From 83fa93ccafe1ec5044f2edd118006edf4faa28b2 Mon Sep 17 00:00:00 2001 From: Jason van den Hurk Date: Fri, 7 Aug 2020 00:07:43 +0200 Subject: [PATCH] Make headers method on WASM client for compatibility with async_impl (#991) The replace_headers method had to be moved since the async_impl module is not compiled while compiling to wasm. This caused the replace_headers method to be unavailable. fast_random had to be excluded from the wasm build to prevent dead code warnings in the wasm target. --- src/async_impl/request.rs | 29 +---------------------------- src/blocking/request.rs | 4 ++-- src/lib.rs | 1 + src/util.rs | 30 ++++++++++++++++++++++++++++++ src/wasm/request.rs | 10 ++++++++++ 5 files changed, 44 insertions(+), 30 deletions(-) diff --git a/src/async_impl/request.rs b/src/async_impl/request.rs index ba7f7f3..6c321ea 100644 --- a/src/async_impl/request.rs +++ b/src/async_impl/request.rs @@ -185,7 +185,7 @@ impl RequestBuilder { /// The headers will be merged in to any already set. pub fn headers(mut self, headers: crate::header::HeaderMap) -> RequestBuilder { if let Ok(ref mut req) = self.request { - replace_headers(req.headers_mut(), headers); + crate::util::replace_headers(req.headers_mut(), headers); } self } @@ -467,33 +467,6 @@ fn fmt_request_fields<'a, 'b>( .field("headers", &req.headers) } -pub(crate) fn replace_headers(dst: &mut HeaderMap, src: HeaderMap) { - // IntoIter of HeaderMap yields (Option, HeaderValue). - // The first time a name is yielded, it will be Some(name), and if - // there are more values with the same name, the next yield will be - // None. - // - // TODO: a complex exercise would be to optimize this to only - // require 1 hash/lookup of the key, but doing something fancy - // with header::Entry... - - let mut prev_name = None; - for (key, value) in src { - match key { - Some(key) => { - dst.insert(key.clone(), value); - prev_name = Some(key); - } - None => match prev_name { - Some(ref key) => { - dst.append(key.clone(), value); - } - None => unreachable!("HeaderMap::into_iter yielded None first"), - }, - } - } -} - /// Check the request URL for a "username:password" type authority, and if /// found, remove it from the URL and return it. diff --git a/src/blocking/request.rs b/src/blocking/request.rs index 299e7e2..9dc96b2 100644 --- a/src/blocking/request.rs +++ b/src/blocking/request.rs @@ -228,7 +228,7 @@ impl RequestBuilder { /// ``` pub fn headers(mut self, headers: crate::header::HeaderMap) -> RequestBuilder { if let Ok(ref mut req) = self.request { - async_impl::request::replace_headers(req.headers_mut(), headers); + crate::util::replace_headers(req.headers_mut(), headers); } self } @@ -605,7 +605,7 @@ impl TryFrom> for Request where T:Into { let url = Url::parse(&uri.to_string()) .map_err(crate::error::builder)?; let mut inner = async_impl::Request::new(method, url); - async_impl::request::replace_headers(inner.headers_mut(), headers); + crate::util::replace_headers(inner.headers_mut(), headers); Ok(Request { body: Some(body.into()), inner, diff --git a/src/lib.rs b/src/lib.rs index 43771e3..1b6567a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -306,6 +306,7 @@ if_hyper! { if_wasm! { mod wasm; + mod util; pub use self::wasm::{multipart, Body, Client, ClientBuilder, Request, RequestBuilder, Response}; } diff --git a/src/util.rs b/src/util.rs index 43d809c..81f123a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,4 +1,7 @@ +use crate::header::HeaderMap; + // xor-shift +#[cfg(not(target_arch = "wasm32"))] pub(crate) fn fast_random() -> u64 { use std::cell::Cell; use std::collections::hash_map::RandomState; @@ -33,3 +36,30 @@ pub(crate) fn fast_random() -> u64 { n.0.wrapping_mul(0x2545_f491_4f6c_dd1d) }) } + +pub(crate) fn replace_headers(dst: &mut HeaderMap, src: HeaderMap) { + // IntoIter of HeaderMap yields (Option, HeaderValue). + // The first time a name is yielded, it will be Some(name), and if + // there are more values with the same name, the next yield will be + // None. + // + // TODO: a complex exercise would be to optimize this to only + // require 1 hash/lookup of the key, but doing something fancy + // with header::Entry... + + let mut prev_name = None; + for (key, value) in src { + match key { + Some(key) => { + dst.insert(key.clone(), value); + prev_name = Some(key); + } + None => match prev_name { + Some(ref key) => { + dst.append(key.clone(), value); + } + None => unreachable!("HeaderMap::into_iter yielded None first"), + }, + } + } +} diff --git a/src/wasm/request.rs b/src/wasm/request.rs index cce8747..976ddfa 100644 --- a/src/wasm/request.rs +++ b/src/wasm/request.rs @@ -224,6 +224,16 @@ impl RequestBuilder { self } + /// Add a set of Headers to the existing ones on this Request. + /// + /// The headers will be merged in to any already set. + pub fn headers(mut self, headers: crate::header::HeaderMap) -> RequestBuilder { + if let Ok(ref mut req) = self.request { + crate::util::replace_headers(req.headers_mut(), headers); + } + self + } + /// Disable CORS on fetching the request. /// /// # WASM