From 73bff4e98c372ce04b006370c0b0d2af29ea8718 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Wed, 4 Aug 2021 13:52:35 -0700 Subject: [PATCH] feat(client): expose http09 and http1 options on `client::conn::Builder` (#2611) These options are currently available on the high-level builder only. Along the way, rename the setters to follow the public API conventions and add docs. Closes #2461 --- src/client/client.rs | 12 ++++----- src/client/conn.rs | 61 +++++++++++++++++++++++++++++++++++++++----- src/ffi/client.rs | 2 +- 3 files changed, 62 insertions(+), 13 deletions(-) diff --git a/src/client/client.rs b/src/client/client.rs index f94d4154b8..e1d5914aba 100644 --- a/src/client/client.rs +++ b/src/client/client.rs @@ -971,7 +971,7 @@ impl Builder { /// /// Default is an adaptive read buffer. pub fn http1_read_buf_exact_size(&mut self, sz: usize) -> &mut Self { - self.conn_builder.h1_read_buf_exact_size(Some(sz)); + self.conn_builder.http1_read_buf_exact_size(Some(sz)); self } @@ -987,7 +987,7 @@ impl Builder { #[cfg(feature = "http1")] #[cfg_attr(docsrs, doc(cfg(feature = "http1")))] pub fn http1_max_buf_size(&mut self, max: usize) -> &mut Self { - self.conn_builder.h1_max_buf_size(max); + self.conn_builder.http1_max_buf_size(max); self } @@ -1012,7 +1012,7 @@ impl Builder { /// [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); + .http1_allow_spaces_after_header_name_in_responses(val); self } @@ -1023,7 +1023,7 @@ impl Builder { /// /// Default is false. pub fn http1_title_case_headers(&mut self, val: bool) -> &mut Self { - self.conn_builder.h1_title_case_headers(val); + self.conn_builder.http1_title_case_headers(val); self } @@ -1034,7 +1034,7 @@ impl Builder { /// /// Default is false. pub fn http1_preserve_header_case(&mut self, val: bool) -> &mut Self { - self.conn_builder.h1_preserve_header_case(val); + self.conn_builder.http1_preserve_header_case(val); self } @@ -1042,7 +1042,7 @@ impl Builder { /// /// Default is false. pub fn http09_responses(&mut self, val: bool) -> &mut Self { - self.conn_builder.h09_responses(val); + self.conn_builder.http09_responses(val); self } diff --git a/src/client/conn.rs b/src/client/conn.rs index c557ee29c2..c40452038e 100644 --- a/src/client/conn.rs +++ b/src/client/conn.rs @@ -550,12 +550,34 @@ impl Builder { self } - pub(super) fn h09_responses(&mut self, enabled: bool) -> &mut Builder { + /// Set whether HTTP/0.9 responses should be tolerated. + /// + /// Default is false. + pub fn http09_responses(&mut self, enabled: bool) -> &mut Builder { self.h09_responses = enabled; self } - pub(crate) fn h1_allow_spaces_after_header_name_in_responses( + /// 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, enabled: bool, ) -> &mut Builder { @@ -564,24 +586,51 @@ impl Builder { self } - pub(super) fn h1_title_case_headers(&mut self, enabled: bool) -> &mut Builder { + /// Set whether HTTP/1 connections will write header names as title case at + /// the socket level. + /// + /// Note that this setting does not affect HTTP/2. + /// + /// Default is false. + pub fn http1_title_case_headers(&mut self, enabled: bool) -> &mut Builder { self.h1_title_case_headers = enabled; self } - pub(crate) fn h1_preserve_header_case(&mut self, enabled: bool) -> &mut Builder { + /// Set whether HTTP/1 connections will write header names as provided + /// at the socket level. + /// + /// Note that this setting does not affect HTTP/2. + /// + /// Default is false. + pub fn http1_preserve_header_case(&mut self, enabled: bool) -> &mut Builder { self.h1_preserve_header_case = enabled; self } - pub(super) fn h1_read_buf_exact_size(&mut self, sz: Option) -> &mut Builder { + /// Sets the exact size of the read buffer to *always* use. + /// + /// Note that setting this option unsets the `http1_max_buf_size` option. + /// + /// Default is an adaptive read buffer. + pub fn http1_read_buf_exact_size(&mut self, sz: Option) -> &mut Builder { self.h1_read_buf_exact_size = sz; self.h1_max_buf_size = None; self } + /// Set the maximum buffer size for the connection. + /// + /// Default is ~400kb. + /// + /// Note that setting this option unsets the `http1_read_exact_buf_size` option. + /// + /// # Panics + /// + /// The minimum value allowed is 8192. This method panics if the passed `max` is less than the minimum. #[cfg(feature = "http1")] - pub(super) fn h1_max_buf_size(&mut self, max: usize) -> &mut Self { + #[cfg_attr(docsrs, doc(cfg(feature = "http1")))] + pub fn http1_max_buf_size(&mut self, max: usize) -> &mut Self { assert!( max >= proto::h1::MINIMUM_MAX_BUFFER_SIZE, "the max_buf_size cannot be smaller than the minimum that h1 specifies." diff --git a/src/ffi/client.rs b/src/ffi/client.rs index 6fa8862ddd..2e73e6695a 100644 --- a/src/ffi/client.rs +++ b/src/ffi/client.rs @@ -107,7 +107,7 @@ ffi_fn! { /// Creates a new set of HTTP clientconn options to be used in a handshake. fn hyper_clientconn_options_new() -> *mut hyper_clientconn_options { let mut builder = conn::Builder::new(); - builder.h1_preserve_header_case(true); + builder.http1_preserve_header_case(true); Box::into_raw(Box::new(hyper_clientconn_options { builder,