diff --git a/src/client/conn/http1.rs b/src/client/conn/http1.rs index 43c2564280..d4019a20a1 100644 --- a/src/client/conn/http1.rs +++ b/src/client/conn/http1.rs @@ -430,6 +430,22 @@ impl Builder { self } + /// Set whether HTTP/1 connections will accept spaces before the first + /// header name in responses. + /// + /// This is not allowed by the spec, but some servers send it anyway, and + /// browsers accept it for compatibility. + /// + /// Default is false. + pub fn allow_space_before_first_header_name_in_responses( + &mut self, + enabled: bool, + ) -> &mut Builder { + self.h1_parser_config + .allow_space_before_first_header_name(enabled); + self + } + /// Set whether HTTP/1 connections will silently ignored malformed header lines. /// /// If this is enabled and a header line does not start with a valid header diff --git a/src/proto/h1/role.rs b/src/proto/h1/role.rs index fce1df78af..fa8135ac6f 100644 --- a/src/proto/h1/role.rs +++ b/src/proto/h1/role.rs @@ -1877,6 +1877,58 @@ mod tests { Client::parse(&mut raw, ctx).unwrap_err(); } + const RESPONSE_WITH_SPACE_BEFORE_FIRST_HEADER_NAME: &str = + "HTTP/1.1 200 OK\r\n Space-Before-Header: hello there\r\n\r\n"; + + #[test] + fn test_parse_allow_response_with_space_before_first_header_name() { + use httparse::ParserConfig; + + let _ = pretty_env_logger::try_init(); + let mut raw = BytesMut::from(RESPONSE_WITH_SPACE_BEFORE_FIRST_HEADER_NAME); + let mut h1_parser_config = ParserConfig::default(); + h1_parser_config.allow_space_before_first_header_name(true); + let ctx = ParseContext { + cached_headers: &mut None, + req_method: &mut Some(crate::Method::GET), + h1_parser_config, + h1_max_headers: None, + h1_max_header_size: None, + preserve_header_case: false, + #[cfg(feature = "ffi")] + preserve_header_order: false, + h09_responses: false, + #[cfg(feature = "client")] + on_informational: &mut None, + }; + let msg = Client::parse(&mut raw, ctx).unwrap().unwrap(); + assert_eq!(raw.len(), 0); + assert_eq!(msg.head.subject, crate::StatusCode::OK); + assert_eq!(msg.head.version, crate::Version::HTTP_11); + assert_eq!(msg.head.headers.len(), 1); + assert_eq!(msg.head.headers["Space-Before-Header"], "hello there"); + } + + #[test] + fn test_parse_reject_response_with_space_before_first_header_name() { + let _ = pretty_env_logger::try_init(); + let mut raw = BytesMut::from(RESPONSE_WITH_SPACE_BEFORE_FIRST_HEADER_NAME); + let ctx = ParseContext { + cached_headers: &mut None, + req_method: &mut Some(crate::Method::GET), + h1_parser_config: Default::default(), + h1_max_headers: None, + h1_max_header_size: None, + preserve_header_case: false, + #[cfg(feature = "ffi")] + preserve_header_order: false, + h09_responses: false, + #[cfg(feature = "client")] + on_informational: &mut None, + }; + Client::parse(&mut raw, ctx).unwrap_err(); + } + const REQUEST_WITH_MULTIPLE_SPACES_IN_REQUEST_LINE: &str = "GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n";