diff --git a/src/proto/h1/conn.rs b/src/proto/h1/conn.rs index 4653210d..a3d6a537 100644 --- a/src/proto/h1/conn.rs +++ b/src/proto/h1/conn.rs @@ -474,7 +474,7 @@ where self.enforce_version(&mut head); let buf = self.io.headers_buf(); - match T::encode( + match super::role::encode_headers::( Encode { head: &mut head, body, diff --git a/src/proto/h1/io.rs b/src/proto/h1/io.rs index 00f4f64f..e68abbb1 100644 --- a/src/proto/h1/io.rs +++ b/src/proto/h1/io.rs @@ -149,7 +149,7 @@ where S: Http1Transaction, { loop { - match S::parse( + match super::role::parse_headers::( &mut self.read_buf, ParseContext { cached_headers: parse_ctx.cached_headers, diff --git a/src/proto/h1/role.rs b/src/proto/h1/role.rs index 46b8b264..ccffb742 100644 --- a/src/proto/h1/role.rs +++ b/src/proto/h1/role.rs @@ -58,6 +58,35 @@ macro_rules! header_value { }}; } +pub(super) fn parse_headers( + bytes: &mut BytesMut, + ctx: ParseContext<'_>, +) -> ParseResult +where + T: Http1Transaction, +{ + // If the buffer is empty, don't bother entering the span, it's just noise. + if bytes.is_empty() { + return Ok(None); + } + + let span = trace_span!("parse_headers"); + let _s = span.enter(); + T::parse(bytes, ctx) +} + +pub(super) fn encode_headers( + enc: Encode<'_, T::Outgoing>, + dst: &mut Vec, +) -> crate::Result +where + T: Http1Transaction, +{ + let span = trace_span!("encode_headers"); + let _s = span.enter(); + T::encode(enc, dst) +} + // There are 2 main roles, Client and Server. pub(crate) enum Client {} @@ -70,9 +99,7 @@ impl Http1Transaction for Server { const LOG: &'static str = "{role=server}"; fn parse(buf: &mut BytesMut, ctx: ParseContext<'_>) -> ParseResult { - if buf.is_empty() { - return Ok(None); - } + debug_assert!(!buf.is_empty(), "parse called with empty buf"); let mut keep_alive; let is_http_11; @@ -614,11 +641,10 @@ impl Http1Transaction for Client { const LOG: &'static str = "{role=client}"; fn parse(buf: &mut BytesMut, ctx: ParseContext<'_>) -> ParseResult { + debug_assert!(!buf.is_empty(), "parse called with empty buf"); + // Loop to skip information status code headers (100 Continue, etc). loop { - if buf.is_empty() { - return Ok(None); - } // Unsafe: see comment in Server Http1Transaction, above. let mut headers_indices: [HeaderIndices; MAX_HEADERS] = unsafe { mem::uninitialized() }; let (len, status, version, headers_len) = { @@ -688,6 +714,12 @@ impl Http1Transaction for Client { wants_upgrade: is_upgrade, })); } + + // Parsing a 1xx response could have consumed the buffer, check if + // it is empty now... + if buf.is_empty() { + return Ok(None); + } } }