Fix RequestBuilder::headers to include multiple values
`RequestBuilder::headers` will always overwrite any existing header with the same name, but will now correctly append extra values from the *new* header map. Closes #407
This commit is contained in:
@@ -7,5 +7,5 @@ pub use self::response::{Response, ResponseBuilderExt};
|
|||||||
pub mod body;
|
pub mod body;
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod decoder;
|
pub mod decoder;
|
||||||
mod request;
|
pub(crate) mod request;
|
||||||
mod response;
|
mod response;
|
||||||
|
|||||||
@@ -121,14 +121,13 @@ impl RequestBuilder {
|
|||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a set of Headers to the existing ones on this Request.
|
/// Add a set of Headers to the existing ones on this Request.
|
||||||
///
|
///
|
||||||
/// The headers will be merged in to any already set.
|
/// The headers will be merged in to any already set.
|
||||||
pub fn headers(mut self, headers: ::header::HeaderMap) -> RequestBuilder {
|
pub fn headers(mut self, headers: ::header::HeaderMap) -> RequestBuilder {
|
||||||
if let Ok(ref mut req) = self.request {
|
if let Ok(ref mut req) = self.request {
|
||||||
for (key, value) in headers.iter() {
|
replace_headers(req.headers_mut(), headers);
|
||||||
req.headers_mut().insert(key, value.clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -312,6 +311,33 @@ fn fmt_request_fields<'a, 'b>(f: &'a mut fmt::DebugStruct<'a, 'b>, req: &Request
|
|||||||
.field("headers", &req.headers)
|
.field("headers", &req.headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn replace_headers(dst: &mut HeaderMap, src: HeaderMap) {
|
||||||
|
|
||||||
|
// IntoIter of HeaderMap yields (Option<HeaderName>, 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"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
@@ -379,6 +405,35 @@ mod tests {
|
|||||||
assert_eq!(req.url().query(), Some("foo=bar&qux=three"));
|
assert_eq!(req.url().query(), Some("foo=bar&qux=three"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_replace_headers() {
|
||||||
|
use http::HeaderMap;
|
||||||
|
|
||||||
|
let mut headers = HeaderMap::new();
|
||||||
|
headers.insert("foo", "bar".parse().unwrap());
|
||||||
|
headers.append("foo", "baz".parse().unwrap());
|
||||||
|
|
||||||
|
let client = Client::new();
|
||||||
|
let req = client
|
||||||
|
.get("https://hyper.rs")
|
||||||
|
.header("im-a", "keeper")
|
||||||
|
.header("foo", "pop me")
|
||||||
|
.headers(headers)
|
||||||
|
.build()
|
||||||
|
.expect("request build");
|
||||||
|
|
||||||
|
assert_eq!(req.headers()["im-a"], "keeper");
|
||||||
|
|
||||||
|
let foo = req
|
||||||
|
.headers()
|
||||||
|
.get_all("foo")
|
||||||
|
.iter()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
assert_eq!(foo.len(), 2);
|
||||||
|
assert_eq!(foo[0], "bar");
|
||||||
|
assert_eq!(foo[1], "baz");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
use {body, Method};
|
use {body, Method};
|
||||||
use super::Client;
|
use super::Client;
|
||||||
|
|||||||
@@ -188,9 +188,7 @@ impl RequestBuilder {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn headers(mut self, headers: ::header::HeaderMap) -> RequestBuilder {
|
pub fn headers(mut self, headers: ::header::HeaderMap) -> RequestBuilder {
|
||||||
if let Ok(ref mut req) = self.request {
|
if let Ok(ref mut req) = self.request {
|
||||||
for (key, value) in headers.iter() {
|
async_impl::request::replace_headers(req.headers_mut(), headers);
|
||||||
req.headers_mut().insert(key, value.clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -810,4 +808,33 @@ mod tests {
|
|||||||
let json_data = MyStruct;
|
let json_data = MyStruct;
|
||||||
assert!(r.json(&json_data).build().unwrap_err().is_serialization());
|
assert!(r.json(&json_data).build().unwrap_err().is_serialization());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_replace_headers() {
|
||||||
|
use http::HeaderMap;
|
||||||
|
|
||||||
|
let mut headers = HeaderMap::new();
|
||||||
|
headers.insert("foo", "bar".parse().unwrap());
|
||||||
|
headers.append("foo", "baz".parse().unwrap());
|
||||||
|
|
||||||
|
let client = Client::new();
|
||||||
|
let req = client
|
||||||
|
.get("https://hyper.rs")
|
||||||
|
.header("im-a", "keeper")
|
||||||
|
.header("foo", "pop me")
|
||||||
|
.headers(headers)
|
||||||
|
.build()
|
||||||
|
.expect("request build");
|
||||||
|
|
||||||
|
assert_eq!(req.headers()["im-a"], "keeper");
|
||||||
|
|
||||||
|
let foo = req
|
||||||
|
.headers()
|
||||||
|
.get_all("foo")
|
||||||
|
.iter()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
assert_eq!(foo.len(), 2);
|
||||||
|
assert_eq!(foo[0], "bar");
|
||||||
|
assert_eq!(foo[1], "baz");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user