feat(client): add option to allow misplaced spaces in HTTP/1 responses (#2506)

This commit is contained in:
Anthony Ramine
2021-04-20 23:17:48 +02:00
committed by GitHub
parent ed2fdb7b6a
commit 11345394d9
7 changed files with 117 additions and 5 deletions

View File

@@ -961,6 +961,31 @@ impl Builder {
self
}
/// Set whether HTTP/1 connections will accept spaces between header names
/// and the colon that follow them in responses.
///
/// You probably don't need this, here is what [RFC 7230 Section 3.2.4.] has
/// to say about it:
///
/// > No whitespace is allowed between the header field-name and colon. In
/// > the past, differences in the handling of such whitespace have led to
/// > security vulnerabilities in request routing and response handling. A
/// > server MUST reject any received request message that contains
/// > whitespace between a header field-name and colon with a response code
/// > of 400 (Bad Request). A proxy MUST remove any such whitespace from a
/// > response message before forwarding the message downstream.
///
/// Note that this setting does not affect HTTP/2.
///
/// Default is false.
///
/// [RFC 7230 Section 3.2.4.]: https://tools.ietf.org/html/rfc7230#section-3.2.4
pub fn http1_allow_spaces_after_header_name_in_responses(&mut self, val: bool) -> &mut Self {
self.conn_builder
.h1_allow_spaces_after_header_name_in_responses(val);
self
}
/// Set whether HTTP/1 connections will write header names as title case at
/// the socket level.
///

View File

@@ -56,6 +56,7 @@ use std::time::Duration;
use bytes::Bytes;
use futures_util::future::{self, Either, FutureExt as _};
use httparse::ParserConfig;
use pin_project::pin_project;
use tokio::io::{AsyncRead, AsyncWrite};
use tower_service::Service;
@@ -123,6 +124,7 @@ where
pub struct Builder {
pub(super) exec: Exec,
h09_responses: bool,
h1_parser_config: ParserConfig,
h1_title_case_headers: bool,
h1_read_buf_exact_size: Option<usize>,
h1_max_buf_size: Option<usize>,
@@ -496,6 +498,7 @@ impl Builder {
exec: Exec::Default,
h09_responses: false,
h1_read_buf_exact_size: None,
h1_parser_config: Default::default(),
h1_title_case_headers: false,
h1_max_buf_size: None,
#[cfg(feature = "http2")]
@@ -521,6 +524,14 @@ impl Builder {
self
}
pub(crate) fn h1_allow_spaces_after_header_name_in_responses(
&mut self,
enabled: bool,
) -> &mut Builder {
self.h1_parser_config.allow_spaces_after_header_name_in_responses(enabled);
self
}
pub(super) fn h1_title_case_headers(&mut self, enabled: bool) -> &mut Builder {
self.h1_title_case_headers = enabled;
self
@@ -704,6 +715,7 @@ impl Builder {
#[cfg(feature = "http1")]
Proto::Http1 => {
let mut conn = proto::Conn::new(io);
conn.set_h1_parser_config(opts.h1_parser_config);
if opts.h1_title_case_headers {
conn.set_title_case_headers();
}