pub struct HttpHardening {
pub http1_max_headers: usize,
pub http1_max_buf_size: usize,
pub http1_header_read_timeout: Duration,
pub h2_max_concurrent_streams: u32,
pub h2_initial_stream_window: u32,
pub h2_initial_connection_window: u32,
pub h2_max_send_buf_size: usize,
pub request_body_gap: Option<Duration>,
}Expand description
Resolved hardening configuration (see the module docs for the knob table, defaults, and the attack each bound addresses).
Fields§
§http1_max_headers: usizeHTTP/1 max header count per request/section.
http1_max_buf_size: usizeHTTP/1 read-buffer cap, in BYTES.
http1_header_read_timeout: DurationHTTP/1 header-read (slowloris) timeout.
h2_max_concurrent_streams: u32HTTP/2 max concurrent streams (enforced and advertised).
h2_initial_stream_window: u32HTTP/2 initial per-stream flow-control window, in BYTES.
h2_initial_connection_window: u32HTTP/2 initial connection flow-control window, in BYTES.
h2_max_send_buf_size: usizeHTTP/2 per-connection send-buffer cap, in BYTES.
request_body_gap: Option<Duration>Inbound request-body inactivity gap; None disables the wrapper (the body then streams through untouched).
Implementations§
Source§impl HttpHardening
impl HttpHardening
Sourcepub fn from_env() -> Self
pub fn from_env() -> Self
Read the knob set from the environment; invalid or absent values fall back to the documented defaults.
Sourcepub fn apply<E>(&self, builder: &mut Builder<E>)
pub fn apply<E>(&self, builder: &mut Builder<E>)
Apply the connection-level bounds to a hyper-util auto builder (h1 + h2). Used by every serving surface: data-plane listeners and the admin listener share one hardening posture.
Sourcepub fn apply_listener_h2<E>(
&self,
builder: &mut Builder<E>,
config: &Http2ListenerConfig,
)
pub fn apply_listener_h2<E>( &self, builder: &mut Builder<E>, config: &Http2ListenerConfig, )
Apply per-listener HTTP/2 overrides (PERF-11, #244). Called
after apply to override the process-wide h2 defaults with
listener-specific values. Only the fields present in the
config are overridden; absent fields keep the process default.
Sourcepub fn wrap_request_body<B>(&self, body: B) -> InboundBody<B>
pub fn wrap_request_body<B>(&self, body: B) -> InboundBody<B>
Wrap an inbound request body with the inactivity-gap timeout. A thin passthrough when the knob is disabled.
Sourcepub async fn guard_connection<S>(&self, stream: S) -> Option<PrefixedStream<S>>where
S: AsyncRead + AsyncWrite + Unpin,
pub async fn guard_connection<S>(&self, stream: S) -> Option<PrefixedStream<S>>where
S: AsyncRead + AsyncWrite + Unpin,
Pre-parse smuggling guard for one connection (DW-023). Reads ahead just enough of the first request head to apply the CL+TE rejection policy BEFORE hyper normalizes the head away (hyper’s HTTP/1 parser gives Transfer-Encoding precedence and DROPS the Content-Length header, which is desync-safe behind this gateway but erases the evidence an explicit rejection needs). Returns the stream to hand to the connection builder (with the sniffed bytes replayed in front), or None when the connection was rejected and answered.
Behavior:
- Bytes beginning with
PRI(the h2c preface) pass through untouched the moment the first bytes identify it — h2 has its own framing rules (Transfer-Encoding is forbidden there; hyper rejects it) and needs no h1 head sniff. - A first HTTP/1 head carrying BOTH a Content-Length and a
Transfer-Encoding header (any order) is answered with a bare
400 Bad Request+ close and never reaches the dataplane. - A head containing an obs-fold (RFC 7230 3.2.4 obsolete line
folding: any header line starting with SP/HTAB) is likewise
answered
400+ close. Folding can split a header NAME across lines (Transfer-\r\n Encoding: chunked), which the name-anchored CL+TE scan below cannot see — and obs-fold is illegal in HTTP/1.1 requests, which hyper also rejects, so refusing it at the sniff is strictly aligned with the parser, one layer earlier. - The head terminator is the FIRST blank line under either
line-ending convention hyper tolerates (
\r\n\r\nfor RFC-strict clients,\n\nand the mixed forms for bare-LF clients): a legal LF-only client’s body must not be over-buffered into the sniff (spurious 431). - A head exceeding the HTTP/1 read-buffer cap is likewise refused.
- The sniff’s read bound is per-read (
http1_header_read_timeoutapplied to each individual read, see the module docs): a slow starter simply falls through to hyper, whose per-head slowloris timeout governs from there. - Documented limitation: only the FIRST request head on a connection is inspected; later keep-alive requests rely on hyper’s framing itself, which cannot desync behind this gateway (every forwarded request is rebuilt from parsed parts — there is no raw-passthrough path).
Trait Implementations§
Source§impl Clone for HttpHardening
impl Clone for HttpHardening
Source§fn clone(&self) -> HttpHardening
fn clone(&self) -> HttpHardening
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for HttpHardening
impl Debug for HttpHardening
Source§impl Default for HttpHardening
impl Default for HttpHardening
Source§impl PartialEq for HttpHardening
impl PartialEq for HttpHardening
impl Eq for HttpHardening
impl StructuralPartialEq for HttpHardening
Auto Trait Implementations§
impl Freeze for HttpHardening
impl RefUnwindSafe for HttpHardening
impl Send for HttpHardening
impl Sync for HttpHardening
impl Unpin for HttpHardening
impl UnwindSafe for HttpHardening
Blanket Implementations§
§impl<T> AnyExt for T
impl<T> AnyExt for T
§fn downcast_ref<T>(this: &Self) -> Option<&T>where
T: Any,
fn downcast_ref<T>(this: &Self) -> Option<&T>where
T: Any,
T behind reference§fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>where
T: Any,
fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>where
T: Any,
T behind mutable reference§fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>where
T: Any,
fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>where
T: Any,
T behind Rc pointer§fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>where
T: Any,
fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>where
T: Any,
T behind Arc pointer§fn downcast_box<T>(this: Box<Self>) -> Result<Box<T>, Box<Self>>where
T: Any,
fn downcast_box<T>(this: Box<Self>) -> Result<Box<T>, Box<Self>>where
T: Any,
T behind Box pointer§fn downcast_move<T>(this: Self) -> Option<T>
fn downcast_move<T>(this: Self) -> Option<T>
Self to T,
useful only in generic context as a workaround for specializationSource§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T, X> CoerceTo<T> for Xwhere
T: CoerceFrom<X> + ?Sized,
impl<T, X> CoerceTo<T> for Xwhere
T: CoerceFrom<X> + ?Sized,
fn coerce_rc_to(self: Rc<X>) -> Rc<T>
fn coerce_box_to(self: Box<X>) -> Box<T>
fn coerce_ref_to(&self) -> &T
fn coerce_mut_to(&mut self) -> &mut T
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more