From 020d2d0b27f4e4d28326675b803b137b0798c886 Mon Sep 17 00:00:00 2001 From: Troy Benson Date: Sat, 26 Oct 2024 14:35:12 +0000 Subject: [PATCH] fix: http servers closijng after non-fatal errors --- Cargo.lock | 1 + foundations/Cargo.toml | 5 ++++- foundations/src/http/server/stream/mod.rs | 12 ++++++++++++ foundations/src/http/server/stream/tcp.rs | 15 +++++++++++++-- foundations/src/http/server/stream/tls.rs | 15 +++++++++++++-- 5 files changed, 43 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36408c9b8..fec805208 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3963,6 +3963,7 @@ dependencies = [ "hyper 1.5.0", "hyper-util", "itertools 0.13.0", + "libc", "matchers", "minijinja", "num_cpus", diff --git a/foundations/Cargo.toml b/foundations/Cargo.toml index 83f19e7ff..b3b2f0d85 100644 --- a/foundations/Cargo.toml +++ b/foundations/Cargo.toml @@ -67,6 +67,8 @@ thiserror = { version = "1", optional = true } http-body = { version = "1", optional = true } socket2 = { version = "0.5", optional = true } +libc = { version = "0.2", optional = true } + [features] context = [ @@ -203,7 +205,8 @@ http = [ "futures", "context", "socket2", - "tracing" + "tracing", + "libc" ] http-tls = [ diff --git a/foundations/src/http/server/stream/mod.rs b/foundations/src/http/server/stream/mod.rs index 6b53e207b..56a857d89 100644 --- a/foundations/src/http/server/stream/mod.rs +++ b/foundations/src/http/server/stream/mod.rs @@ -177,3 +177,15 @@ impl ActiveRequestsGuard { Self(active_requests) } } + +fn is_fatal_tcp_error(err: &std::io::Error) -> bool { + matches!( + err.raw_os_error(), + Some(libc::EFAULT) + | Some(libc::EINVAL) + | Some(libc::ENFILE) + | Some(libc::EMFILE) + | Some(libc::ENOBUFS) + | Some(libc::ENOMEM) + ) +} diff --git a/foundations/src/http/server/stream/tcp.rs b/foundations/src/http/server/stream/tcp.rs index e59631c5f..0d8eb5a8c 100644 --- a/foundations/src/http/server/stream/tcp.rs +++ b/foundations/src/http/server/stream/tcp.rs @@ -15,7 +15,7 @@ use tracing::Instrument; use super::{Backend, IncomingConnection, MakeService, ServiceHandler, SocketKind}; use crate::context::ContextFutExt; -use crate::http::server::stream::{jitter, ActiveRequestsGuard}; +use crate::http::server::stream::{is_fatal_tcp_error, jitter, ActiveRequestsGuard}; #[cfg(feature = "runtime")] use crate::runtime::spawn; #[cfg(feature = "opentelemetry")] @@ -83,10 +83,21 @@ impl Backend for TcpBackend { tracing::trace!("waiting for incoming connection"); - let Some((connection, addr)) = self.listener.accept().with_context(&ctx).await.transpose()? else { + let Some(stream) = self.listener.accept().with_context(&ctx).await else { break; }; + let (connection, addr) = match stream { + Ok((connection, addr)) => (connection, addr), + Err(err) if is_fatal_tcp_error(&err) => { + return Err(err.into()); + } + Err(err) => { + tracing::error!(err = %err, "failed to accept connection"); + continue; + } + }; + let span = tracing::trace_span!("connection", remote_addr = %addr); let _guard = span.enter(); diff --git a/foundations/src/http/server/stream/tls.rs b/foundations/src/http/server/stream/tls.rs index 365121e63..8a7d2b387 100644 --- a/foundations/src/http/server/stream/tls.rs +++ b/foundations/src/http/server/stream/tls.rs @@ -16,7 +16,7 @@ use tracing::Instrument; use super::{Backend, IncomingConnection, MakeService, ServiceHandler, SocketKind}; use crate::context::ContextFutExt; -use crate::http::server::stream::{jitter, ActiveRequestsGuard}; +use crate::http::server::stream::{is_fatal_tcp_error, jitter, ActiveRequestsGuard}; #[cfg(feature = "runtime")] use crate::runtime::spawn; #[cfg(feature = "opentelemetry")] @@ -91,10 +91,21 @@ impl Backend for TlsBackend { tracing::trace!("waiting for incoming connection"); - let Some((connection, addr)) = self.listener.accept().with_context(&ctx).await.transpose()? else { + let Some(stream) = self.listener.accept().with_context(&ctx).await else { break; }; + let (connection, addr) = match stream { + Ok((connection, addr)) => (connection, addr), + Err(err) if is_fatal_tcp_error(&err) => { + return Err(err.into()); + } + Err(err) => { + tracing::error!(err = %err, "failed to accept connection"); + continue; + } + }; + let span = tracing::trace_span!("connection", remote_addr = %addr); let _guard = span.enter();