From 33a385c6b677cce4ece2843c11ac78711fd5b898 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Tue, 6 Mar 2018 10:37:40 -0800 Subject: [PATCH] feat(client): add `Config::set_host` option If set to false, the `Client` will no longer automatically set the `Host` header if absent. --- src/client/mod.rs | 22 ++++++++++++- tests/client.rs | 78 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 98 insertions(+), 2 deletions(-) diff --git a/src/client/mod.rs b/src/client/mod.rs index 3fcd9e7a..eb614c08 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -46,6 +46,7 @@ pub struct Client { h1_writev: bool, pool: Pool>, retry_canceled_requests: bool, + set_host: bool, } impl Client { @@ -101,6 +102,7 @@ impl Client { h1_writev: config.h1_writev, pool: Pool::new(config.keep_alive, config.keep_alive_timeout), retry_canceled_requests: config.retry_canceled_requests, + set_host: config.set_host, } } } @@ -147,7 +149,7 @@ where C: Connect, )))); } }; - if !req.headers().has::() { + if self.set_host && !req.headers().has::() { let host = Host::new( domain.host().expect("authority implies host").to_owned(), domain.port(), @@ -289,6 +291,7 @@ impl Clone for Client { h1_writev: self.h1_writev, pool: self.pool.clone(), retry_canceled_requests: self.retry_canceled_requests, + set_host: self.set_host, } } } @@ -413,6 +416,7 @@ pub struct Config { //TODO: make use of max_idle config max_idle: usize, retry_canceled_requests: bool, + set_host: bool, } /// Phantom type used to signal that `Config` should create a `HttpConnector`. @@ -429,6 +433,7 @@ impl Default for Config { h1_writev: true, max_idle: 5, retry_canceled_requests: true, + set_host: true, } } } @@ -453,6 +458,7 @@ impl Config { h1_writev: self.h1_writev, max_idle: self.max_idle, retry_canceled_requests: self.retry_canceled_requests, + set_host: self.set_host, } } @@ -467,6 +473,7 @@ impl Config { h1_writev: self.h1_writev, max_idle: self.max_idle, retry_canceled_requests: self.retry_canceled_requests, + set_host: self.set_host, } } @@ -521,6 +528,18 @@ impl Config { self } + /// Set whether to automatically add the `Host` header to requests. + /// + /// If true, and a request does not include a `Host` header, one will be + /// added automatically, derived from the authority of the `Uri`. + /// + /// Default is `true`. + #[inline] + pub fn set_host(mut self, val: bool) -> Config { + self.set_host = val; + self + } + #[doc(hidden)] #[deprecated(since="0.11.11", note="no_proto is always enabled")] pub fn no_proto(self) -> Config { @@ -573,6 +592,7 @@ impl fmt::Debug for Config { .field("keep_alive_timeout", &self.keep_alive_timeout) .field("http1_writev", &self.h1_writev) .field("max_idle", &self.max_idle) + .field("set_host", &self.set_host) .finish() } } diff --git a/tests/client.rs b/tests/client.rs index 6b39acad..5dff660c 100644 --- a/tests/client.rs +++ b/tests/client.rs @@ -45,6 +45,45 @@ macro_rules! test { headers: [ $($response_headers:expr,)* ], body: $response_body:expr, ) => ( + test! { + name: $name, + server: + expected: $server_expected, + reply: $server_reply, + client: + set_host: true, + request: + method: $client_method, + url: $client_url, + headers: [ $($request_headers,)* ], + body: $request_body, + proxy: $request_proxy, + + response: + status: $client_status, + headers: [ $($response_headers,)* ], + body: $response_body, + } + ); + ( + name: $name:ident, + server: + expected: $server_expected:expr, + reply: $server_reply:expr, + client: + set_host: $set_host:expr, + request: + method: $client_method:ident, + url: $client_url:expr, + headers: [ $($request_headers:expr,)* ], + body: $request_body:expr, + proxy: $request_proxy:expr, + + response: + status: $client_status:ident, + headers: [ $($response_headers:expr,)* ], + body: $response_body:expr, + ) => ( #[test] fn $name() { #![allow(unused)] @@ -60,6 +99,7 @@ macro_rules! test { expected: $server_expected, reply: $server_reply, client: + set_host: $set_host, request: method: $client_method, url: $client_url, @@ -111,6 +151,7 @@ macro_rules! test { expected: $server_expected, reply: $server_reply, client: + set_host: true, request: method: $client_method, url: $client_url, @@ -132,6 +173,7 @@ macro_rules! test { expected: $server_expected:expr, reply: $server_reply:expr, client: + set_host: $set_host:expr, request: method: $client_method:ident, url: $client_url:expr, @@ -142,7 +184,12 @@ macro_rules! test { let server = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = server.local_addr().unwrap(); let mut core = $core; - let client = client(&core.handle()); + + let mut config = Client::configure(); + if !$set_host { + config = config.set_host(false); + } + let client = config.build(&core.handle()); let mut req = Request::new(Method::$client_method, format!($client_url, addr=addr).parse().unwrap()); $( req.headers_mut().set($request_headers); @@ -545,6 +592,35 @@ test! { } +test! { + name: client_set_host_false, + + server: + // {addr} is here because format! requires it to exist in the string + expected: "\ + GET /no-host/{addr} HTTP/1.1\r\n\ + \r\n\ + ", + reply: "\ + HTTP/1.1 200 OK\r\n\ + Content-Length: 0\r\n\ + \r\n\ + ", + + client: + set_host: false, + request: + method: Get, + url: "http://{addr}/no-host/{addr}", + headers: [], + body: None, + proxy: false, + response: + status: Ok, + headers: [], + body: None, +} + #[test] fn client_keep_alive() { let server = TcpListener::bind("127.0.0.1:0").unwrap();