From f5ff40e36b7f2e12cfcce6dc905cf36853d9a6b2 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Mon, 4 Jan 2021 00:31:09 +0000 Subject: [PATCH] implement IntoHeaderPair for all T: Header --- actix-http/Cargo.toml | 1 + actix-http/src/client/h1proto.rs | 2 +- actix-http/src/header/common/cache_control.rs | 2 +- .../src/header/common/content_disposition.rs | 2 +- actix-http/src/header/common/content_range.rs | 2 +- actix-http/src/header/common/content_type.rs | 1 + actix-http/src/header/common/if_range.rs | 2 +- actix-http/src/header/common/mod.rs | 10 ++-- actix-http/src/header/into_pair.rs | 36 +++++++++-- actix-http/src/header/into_value.rs | 20 +++---- actix-http/src/header/map.rs | 34 ++++++----- actix-http/src/header/shared/entity.rs | 2 +- actix-http/src/header/shared/httpdate.rs | 2 +- actix-http/src/lib.rs | 4 +- actix-http/src/response.rs | 59 +++++++++++++++++-- actix-http/src/test.rs | 4 +- awc/src/builder.rs | 2 +- awc/src/frozen.rs | 2 +- awc/src/request.rs | 8 +-- awc/src/sender.rs | 4 +- awc/src/test.rs | 4 +- awc/src/ws.rs | 6 +- src/responder.rs | 21 +++---- 23 files changed, 155 insertions(+), 75 deletions(-) diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index 1a4436f96..af6209248 100644 --- a/actix-http/Cargo.toml +++ b/actix-http/Cargo.toml @@ -75,6 +75,7 @@ regex = "1.3" serde = "1.0" serde_json = "1.0" sha-1 = "0.9" +smallvec = "1.6" slab = "0.4" serde_urlencoded = "0.7" time = { version = "0.2.7", default-features = false, features = ["std"] } diff --git a/actix-http/src/client/h1proto.rs b/actix-http/src/client/h1proto.rs index 758ad8424..24f4207e8 100644 --- a/actix-http/src/client/h1proto.rs +++ b/actix-http/src/client/h1proto.rs @@ -45,7 +45,7 @@ where Some(port) => write!(wrt, "{}:{}", host, port), }; - match wrt.get_mut().split().freeze().try_into() { + match wrt.get_mut().split().freeze().try_into_value() { Ok(value) => match head { RequestHeadType::Owned(ref mut head) => { head.headers.insert(HOST, value) diff --git a/actix-http/src/header/common/cache_control.rs b/actix-http/src/header/common/cache_control.rs index ec94ce4a9..b081355d4 100644 --- a/actix-http/src/header/common/cache_control.rs +++ b/actix-http/src/header/common/cache_control.rs @@ -82,7 +82,7 @@ impl fmt::Display for CacheControl { impl IntoHeaderValue for CacheControl { type Error = header::InvalidHeaderValue; - fn try_into(self) -> Result { + fn try_into_value(self) -> Result { let mut writer = Writer::new(); let _ = write!(&mut writer, "{}", self); header::HeaderValue::from_maybe_shared(writer.take()) diff --git a/actix-http/src/header/common/content_disposition.rs b/actix-http/src/header/common/content_disposition.rs index 4c512acbe..ae4a97902 100644 --- a/actix-http/src/header/common/content_disposition.rs +++ b/actix-http/src/header/common/content_disposition.rs @@ -454,7 +454,7 @@ impl ContentDisposition { impl IntoHeaderValue for ContentDisposition { type Error = header::InvalidHeaderValue; - fn try_into(self) -> Result { + fn try_into_value(self) -> Result { let mut writer = Writer::new(); let _ = write!(&mut writer, "{}", self); header::HeaderValue::from_maybe_shared(writer.take()) diff --git a/actix-http/src/header/common/content_range.rs b/actix-http/src/header/common/content_range.rs index 9a604c641..8b7552377 100644 --- a/actix-http/src/header/common/content_range.rs +++ b/actix-http/src/header/common/content_range.rs @@ -200,7 +200,7 @@ impl Display for ContentRangeSpec { impl IntoHeaderValue for ContentRangeSpec { type Error = InvalidHeaderValue; - fn try_into(self) -> Result { + fn try_into_value(self) -> Result { let mut writer = Writer::new(); let _ = write!(&mut writer, "{}", self); HeaderValue::from_maybe_shared(writer.take()) diff --git a/actix-http/src/header/common/content_type.rs b/actix-http/src/header/common/content_type.rs index a0baa5637..8cb970a78 100644 --- a/actix-http/src/header/common/content_type.rs +++ b/actix-http/src/header/common/content_type.rs @@ -99,6 +99,7 @@ impl ContentType { pub fn form_url_encoded() -> ContentType { ContentType(mime::APPLICATION_WWW_FORM_URLENCODED) } + /// A constructor to easily create a `Content-Type: image/jpeg` header. #[inline] pub fn jpeg() -> ContentType { diff --git a/actix-http/src/header/common/if_range.rs b/actix-http/src/header/common/if_range.rs index f231df60f..222bbe59e 100644 --- a/actix-http/src/header/common/if_range.rs +++ b/actix-http/src/header/common/if_range.rs @@ -98,7 +98,7 @@ impl Display for IfRange { impl IntoHeaderValue for IfRange { type Error = InvalidHeaderValue; - fn try_into(self) -> Result { + fn try_into_value(self) -> Result { let mut writer = Writer::new(); let _ = write!(&mut writer, "{}", self); HeaderValue::from_maybe_shared(writer.take()) diff --git a/actix-http/src/header/common/mod.rs b/actix-http/src/header/common/mod.rs index 3d24a960b..815613fe4 100644 --- a/actix-http/src/header/common/mod.rs +++ b/actix-http/src/header/common/mod.rs @@ -169,7 +169,7 @@ macro_rules! header { impl $crate::http::header::IntoHeaderValue for $id { type Error = $crate::http::header::InvalidHeaderValue; - fn try_into(self) -> Result<$crate::http::header::HeaderValue, Self::Error> { + fn try_into_value(self) -> Result<$crate::http::header::HeaderValue, Self::Error> { use std::fmt::Write; let mut writer = $crate::http::header::Writer::new(); let _ = write!(&mut writer, "{}", self); @@ -205,7 +205,7 @@ macro_rules! header { impl $crate::http::header::IntoHeaderValue for $id { type Error = $crate::http::header::InvalidHeaderValue; - fn try_into(self) -> Result<$crate::http::header::HeaderValue, Self::Error> { + fn try_into_value(self) -> Result<$crate::http::header::HeaderValue, Self::Error> { use std::fmt::Write; let mut writer = $crate::http::header::Writer::new(); let _ = write!(&mut writer, "{}", self); @@ -241,8 +241,8 @@ macro_rules! header { impl $crate::http::header::IntoHeaderValue for $id { type Error = $crate::http::header::InvalidHeaderValue; - fn try_into(self) -> Result<$crate::http::header::HeaderValue, Self::Error> { - self.0.try_into() + fn try_into_value(self) -> Result<$crate::http::header::HeaderValue, Self::Error> { + self.0.try_into_value() } } }; @@ -290,7 +290,7 @@ macro_rules! header { impl $crate::http::header::IntoHeaderValue for $id { type Error = $crate::http::header::InvalidHeaderValue; - fn try_into(self) -> Result<$crate::http::header::HeaderValue, Self::Error> { + fn try_into_value(self) -> Result<$crate::http::header::HeaderValue, Self::Error> { use std::fmt::Write; let mut writer = $crate::http::header::Writer::new(); let _ = write!(&mut writer, "{}", self); diff --git a/actix-http/src/header/into_pair.rs b/actix-http/src/header/into_pair.rs index 7a6dfa041..9dcff688d 100644 --- a/actix-http/src/header/into_pair.rs +++ b/actix-http/src/header/into_pair.rs @@ -3,9 +3,11 @@ use std::convert::{Infallible, TryFrom}; use either::Either; use http::{ header::{HeaderName, InvalidHeaderName, InvalidHeaderValue}, - HeaderValue, + Error as HttpError, HeaderValue, }; +use super::{Header, IntoHeaderValue}; + /// Transforms structures into header K/V pairs for inserting into `HeaderMap`s. pub trait IntoHeaderPair: Sized { type Error; @@ -41,13 +43,28 @@ impl IntoHeaderPair for (&str, HeaderValue) { } } +#[derive(Debug)] +pub enum InvalidHeaderPart { + Name(InvalidHeaderName), + Value(InvalidHeaderValue), +} + +impl From for HttpError { + fn from(part_err: InvalidHeaderPart) -> Self { + match part_err { + InvalidHeaderPart::Name(err) => err.into(), + InvalidHeaderPart::Value(err) => err.into(), + } + } +} + impl IntoHeaderPair for (&str, &str) { - type Error = Either; + type Error = InvalidHeaderPart; fn try_into_header_pair(self) -> Result<(HeaderName, HeaderValue), Self::Error> { let (name, value) = self; - let name = HeaderName::try_from(name).map_err(Either::Left)?; - let value = HeaderValue::try_from(value).map_err(Either::Right)?; + let name = HeaderName::try_from(name).map_err(InvalidHeaderPart::Name)?; + let value = HeaderValue::try_from(value).map_err(InvalidHeaderPart::Value)?; Ok((name, value)) } } @@ -82,3 +99,14 @@ impl IntoHeaderPair for (String, String) { Ok((name, value)) } } + +impl IntoHeaderPair for T +where + T: Header, +{ + type Error = ::Error; + + fn try_into_header_pair(self) -> Result<(HeaderName, HeaderValue), Self::Error> { + Ok((T::name(), self.try_into_value()?)) + } +} diff --git a/actix-http/src/header/into_value.rs b/actix-http/src/header/into_value.rs index 3a7a90284..2e8b75b00 100644 --- a/actix-http/src/header/into_value.rs +++ b/actix-http/src/header/into_value.rs @@ -10,14 +10,14 @@ pub trait IntoHeaderValue: Sized { type Error: Into; /// Try to convert value to a Header pair value. - fn try_into(self) -> Result; + fn try_into_value(self) -> Result; } impl IntoHeaderValue for HeaderValue { type Error = InvalidHeaderValue; #[inline] - fn try_into(self) -> Result { + fn try_into_value(self) -> Result { Ok(self) } } @@ -26,7 +26,7 @@ impl<'a> IntoHeaderValue for &'a str { type Error = InvalidHeaderValue; #[inline] - fn try_into(self) -> Result { + fn try_into_value(self) -> Result { self.parse() } } @@ -35,7 +35,7 @@ impl<'a> IntoHeaderValue for &'a [u8] { type Error = InvalidHeaderValue; #[inline] - fn try_into(self) -> Result { + fn try_into_value(self) -> Result { HeaderValue::from_bytes(self) } } @@ -44,7 +44,7 @@ impl IntoHeaderValue for Bytes { type Error = InvalidHeaderValue; #[inline] - fn try_into(self) -> Result { + fn try_into_value(self) -> Result { HeaderValue::from_maybe_shared(self) } } @@ -53,7 +53,7 @@ impl IntoHeaderValue for Vec { type Error = InvalidHeaderValue; #[inline] - fn try_into(self) -> Result { + fn try_into_value(self) -> Result { HeaderValue::try_from(self) } } @@ -62,7 +62,7 @@ impl IntoHeaderValue for String { type Error = InvalidHeaderValue; #[inline] - fn try_into(self) -> Result { + fn try_into_value(self) -> Result { HeaderValue::try_from(self) } } @@ -71,7 +71,7 @@ impl IntoHeaderValue for usize { type Error = InvalidHeaderValue; #[inline] - fn try_into(self) -> Result { + fn try_into_value(self) -> Result { let s = format!("{}", self); HeaderValue::try_from(s) } @@ -81,7 +81,7 @@ impl IntoHeaderValue for u64 { type Error = InvalidHeaderValue; #[inline] - fn try_into(self) -> Result { + fn try_into_value(self) -> Result { let s = format!("{}", self); HeaderValue::try_from(s) } @@ -91,7 +91,7 @@ impl IntoHeaderValue for Mime { type Error = InvalidHeaderValue; #[inline] - fn try_into(self) -> Result { + fn try_into_value(self) -> Result { HeaderValue::try_from(format!("{}", self)) } } diff --git a/actix-http/src/header/map.rs b/actix-http/src/header/map.rs index 4c99f08fc..107bed0fa 100644 --- a/actix-http/src/header/map.rs +++ b/actix-http/src/header/map.rs @@ -1,12 +1,16 @@ -use std::{collections::hash_map::{self, Entry}, convert::TryFrom}; +use std::{ + collections::hash_map::{self, Entry}, + convert::TryFrom, +}; use ahash::AHashMap; use either::Either; use http::header::{HeaderName, HeaderValue}; +use smallvec::{smallvec, SmallVec}; -/// A set of HTTP headers +/// A multi-map of HTTP headers. /// -/// `HeaderMap` is an multi-map of [`HeaderName`] to values. +/// `HeaderMap` is a "multi-map" of [`HeaderName`] to one or more values. #[derive(Debug, Clone, Default)] pub struct HeaderMap { pub(crate) inner: AHashMap, @@ -15,18 +19,18 @@ pub struct HeaderMap { #[derive(Debug, Clone)] pub(crate) enum Value { One(HeaderValue), - Multi(Vec), + Multi(SmallVec<[HeaderValue; 4]>), } impl Value { - fn get(&self) -> &HeaderValue { + fn first(&self) -> &HeaderValue { match self { Value::One(ref val) => val, Value::Multi(ref val) => &val[0], } } - fn get_mut(&mut self) -> &mut HeaderValue { + fn first_mut(&mut self) -> &mut HeaderValue { match self { Value::One(ref mut val) => val, Value::Multi(ref mut val) => &mut val[0], @@ -36,7 +40,7 @@ impl Value { fn append(&mut self, val: HeaderValue) { match self { Value::One(_) => { - let data = std::mem::replace(self, Value::Multi(vec![val])); + let data = std::mem::replace(self, Value::Multi(smallvec![val])); match data { Value::One(val) => self.append(val), Value::Multi(_) => unreachable!(), @@ -117,7 +121,7 @@ impl HeaderMap { /// is returned. Use `get_all` to get all values associated with a given /// key. Returns `None` if there are no values associated with the key. pub fn get(&self, name: N) -> Option<&HeaderValue> { - self.get2(name).map(|v| v.get()) + self.get2(name).map(|v| v.first()) } fn get2(&self, name: N) -> Option<&Value> { @@ -133,11 +137,11 @@ impl HeaderMap { } } - /// Returns a view of all values associated with a key. + /// Returns an iterator of all values associated with a key. /// - /// The returned view does not incur any allocations and allows iterating - /// the values associated with the key. See [`GetAll`] for more details. - /// Returns `None` if there are no values associated with the key. + /// The returned view does not incur any allocations and allows iterating the values associated + /// with the key. Returns `None` if there are no values associated with the key. Iteration order + /// is not guaranteed to be the same as insertion order. pub fn get_all(&self, name: N) -> GetAll<'_> { GetAll { idx: 0, @@ -152,10 +156,10 @@ impl HeaderMap { /// key. Returns `None` if there are no values associated with the key. pub fn get_mut(&mut self, name: N) -> Option<&mut HeaderValue> { match name.as_name() { - Either::Left(name) => self.inner.get_mut(name).map(|v| v.get_mut()), + Either::Left(name) => self.inner.get_mut(name).map(|v| v.first_mut()), Either::Right(s) => { if let Ok(name) = HeaderName::try_from(s) { - self.inner.get_mut(&name).map(|v| v.get_mut()) + self.inner.get_mut(&name).map(|v| v.first_mut()) } else { None } @@ -336,7 +340,7 @@ impl<'a> IntoIterator for &'a HeaderMap { pub struct Iter<'a> { idx: usize, - current: Option<(&'a HeaderName, &'a Vec)>, + current: Option<(&'a HeaderName, &'a SmallVec<[HeaderValue; 4]>)>, iter: hash_map::Iter<'a, HeaderName, Value>, } diff --git a/actix-http/src/header/shared/entity.rs b/actix-http/src/header/shared/entity.rs index 344cfb864..eb383cd6f 100644 --- a/actix-http/src/header/shared/entity.rs +++ b/actix-http/src/header/shared/entity.rs @@ -161,7 +161,7 @@ impl FromStr for EntityTag { impl IntoHeaderValue for EntityTag { type Error = InvalidHeaderValue; - fn try_into(self) -> Result { + fn try_into_value(self) -> Result { let mut wrt = Writer::new(); write!(wrt, "{}", self).unwrap(); HeaderValue::from_maybe_shared(wrt.take()) diff --git a/actix-http/src/header/shared/httpdate.rs b/actix-http/src/header/shared/httpdate.rs index d6b9d8001..72a225589 100644 --- a/actix-http/src/header/shared/httpdate.rs +++ b/actix-http/src/header/shared/httpdate.rs @@ -48,7 +48,7 @@ impl From for HttpDate { impl IntoHeaderValue for HttpDate { type Error = InvalidHeaderValue; - fn try_into(self) -> Result { + fn try_into_value(self) -> Result { let mut wrt = BytesMut::with_capacity(29).writer(); write!( wrt, diff --git a/actix-http/src/lib.rs b/actix-http/src/lib.rs index e17b7de0a..cc99130eb 100644 --- a/actix-http/src/lib.rs +++ b/actix-http/src/lib.rs @@ -53,7 +53,7 @@ pub use self::response::{Response, ResponseBuilder}; pub use self::service::HttpService; pub mod http { - //! Various HTTP related types + //! Various HTTP related types. // re-exports pub use http::header::{HeaderName, HeaderValue}; @@ -64,7 +64,7 @@ pub mod http { pub use crate::cookie::{Cookie, CookieBuilder}; pub use crate::header::HeaderMap; - /// Various http headers + /// A collection of HTTP headers and helpers. pub mod header { pub use crate::header::*; } diff --git a/actix-http/src/response.rs b/actix-http/src/response.rs index cd1fc1c45..cc5a11e08 100644 --- a/actix-http/src/response.rs +++ b/actix-http/src/response.rs @@ -361,7 +361,7 @@ impl ResponseBuilder { #[doc(hidden)] pub fn set(&mut self, hdr: H) -> &mut Self { if let Some(parts) = parts(&mut self.head, &self.err) { - match hdr.try_into() { + match hdr.try_into_value() { Ok(value) => { parts.headers.append(H::name(), value); } @@ -391,7 +391,7 @@ impl ResponseBuilder { { if let Some(parts) = parts(&mut self.head, &self.err) { match HeaderName::try_from(key) { - Ok(key) => match value.try_into() { + Ok(key) => match value.try_into_value() { Ok(value) => { parts.headers.append(key, value); } @@ -485,8 +485,7 @@ impl ResponseBuilder { parts.set_connection_type(ConnectionType::Upgrade); } - // TODO: fix signature - if let Ok(value) = value.try_into() { + if let Ok(value) = value.try_into_value() { self.insert_header((header::UPGRADE, value)); } @@ -880,6 +879,8 @@ impl From for Response { #[cfg(test)] mod tests { + use serde_json::json; + use super::*; use crate::body::Body; use crate::http::header::{HeaderValue, CONTENT_TYPE, COOKIE, SET_COOKIE}; @@ -1113,4 +1114,54 @@ mod tests { let cookie = resp.cookies().next().unwrap(); assert_eq!((cookie.name(), cookie.value()), ("cookie1", "val100")); } + + #[test] + fn response_builder_header_insert_kv() { + let mut res = Response::Ok(); + res.insert_header(("Content-Type", "application/octet-stream")); + let res = res.finish(); + + assert_eq!( + res.headers().get("Content-Type"), + Some(&HeaderValue::from_static("application/octet-stream")) + ); + } + + #[test] + fn response_builder_header_insert_typed() { + let mut res = Response::Ok(); + res.insert_header(header::ContentType(mime::APPLICATION_OCTET_STREAM)); + let res = res.finish(); + + assert_eq!( + res.headers().get("Content-Type"), + Some(&HeaderValue::from_static("application/octet-stream")) + ); + } + + #[test] + fn response_builder_header_append_kv() { + let mut res = Response::Ok(); + res.append_header(("Content-Type", "application/octet-stream")); + res.append_header(("Content-Type", "application/json")); + let res = res.finish(); + + let headers: Vec<_> = res.headers().get_all("Content-Type").cloned().collect(); + assert_eq!(headers.len(), 2); + assert!(headers.contains(&HeaderValue::from_static("application/octet-stream"))); + assert!(headers.contains(&HeaderValue::from_static("application/json"))); + } + + #[test] + fn response_builder_header_append_typed() { + let mut res = Response::Ok(); + res.append_header(header::ContentType(mime::APPLICATION_OCTET_STREAM)); + res.append_header(header::ContentType(mime::APPLICATION_JSON)); + let res = res.finish(); + + let headers: Vec<_> = res.headers().get_all("Content-Type").cloned().collect(); + assert_eq!(headers.len(), 2); + assert!(headers.contains(&HeaderValue::from_static("application/octet-stream"))); + assert!(headers.contains(&HeaderValue::from_static("application/json"))); + } } diff --git a/actix-http/src/test.rs b/actix-http/src/test.rs index 3f08bb7ee..8761b96cc 100644 --- a/actix-http/src/test.rs +++ b/actix-http/src/test.rs @@ -109,7 +109,7 @@ impl TestRequest { /// Set a header pub fn set(&mut self, hdr: H) -> &mut Self { - if let Ok(value) = hdr.try_into() { + if let Ok(value) = hdr.try_into_value() { parts(&mut self.0).headers.append(H::name(), value); return self; } @@ -124,7 +124,7 @@ impl TestRequest { V: IntoHeaderValue, { if let Ok(key) = HeaderName::try_from(key) { - if let Ok(value) = value.try_into() { + if let Ok(value) = value.try_into_value() { parts(&mut self.0).headers.append(key, value); return self; } diff --git a/awc/src/builder.rs b/awc/src/builder.rs index 6be0112d8..351a493af 100644 --- a/awc/src/builder.rs +++ b/awc/src/builder.rs @@ -133,7 +133,7 @@ impl ClientBuilder { V::Error: fmt::Debug, { match HeaderName::try_from(key) { - Ok(key) => match value.try_into() { + Ok(key) => match value.try_into_value() { Ok(value) => { self.headers.append(key, value); } diff --git a/awc/src/frozen.rs b/awc/src/frozen.rs index f7098863c..878f404c6 100644 --- a/awc/src/frozen.rs +++ b/awc/src/frozen.rs @@ -144,7 +144,7 @@ impl FrozenSendBuilder { V: IntoHeaderValue, { match HeaderName::try_from(key) { - Ok(key) => match value.try_into() { + Ok(key) => match value.try_into_value() { Ok(value) => self.extra_headers.insert(key, value), Err(e) => self.err = Some(e.into()), }, diff --git a/awc/src/request.rs b/awc/src/request.rs index 51c3f5190..4d2c0bdad 100644 --- a/awc/src/request.rs +++ b/awc/src/request.rs @@ -169,7 +169,7 @@ impl ClientRequest { /// } /// ``` pub fn set(mut self, hdr: H) -> Self { - match hdr.try_into() { + match hdr.try_into_value() { Ok(value) => { self.head.headers.insert(H::name(), value); } @@ -203,7 +203,7 @@ impl ClientRequest { V: IntoHeaderValue, { match HeaderName::try_from(key) { - Ok(key) => match value.try_into() { + Ok(key) => match value.try_into_value() { Ok(value) => self.head.headers.append(key, value), Err(e) => self.err = Some(e.into()), }, @@ -220,7 +220,7 @@ impl ClientRequest { V: IntoHeaderValue, { match HeaderName::try_from(key) { - Ok(key) => match value.try_into() { + Ok(key) => match value.try_into_value() { Ok(value) => self.head.headers.insert(key, value), Err(e) => self.err = Some(e.into()), }, @@ -239,7 +239,7 @@ impl ClientRequest { match HeaderName::try_from(key) { Ok(key) => { if !self.head.headers.contains_key(&key) { - match value.try_into() { + match value.try_into_value() { Ok(value) => self.head.headers.insert(key, value), Err(e) => self.err = Some(e.into()), } diff --git a/awc/src/sender.rs b/awc/src/sender.rs index ebf87e23b..9fb821a0e 100644 --- a/awc/src/sender.rs +++ b/awc/src/sender.rs @@ -296,7 +296,7 @@ impl RequestSender { match self { RequestSender::Owned(head) => { if !head.headers.contains_key(&key) { - match value.try_into() { + match value.try_into_value() { Ok(value) => head.headers.insert(key, value), Err(e) => return Err(e.into()), } @@ -306,7 +306,7 @@ impl RequestSender { if !head.headers.contains_key(&key) && !extra_headers.iter().any(|h| h.contains_key(&key)) { - match value.try_into() { + match value.try_into_value() { Ok(v) => { let h = extra_headers.get_or_insert(HeaderMap::new()); h.insert(key, v) diff --git a/awc/src/test.rs b/awc/src/test.rs index 68e5c9dc5..84646b9f7 100644 --- a/awc/src/test.rs +++ b/awc/src/test.rs @@ -45,7 +45,7 @@ impl TestResponse { /// Set a header pub fn set(mut self, hdr: H) -> Self { - if let Ok(value) = hdr.try_into() { + if let Ok(value) = hdr.try_into_value() { self.head.headers.append(H::name(), value); return self; } @@ -60,7 +60,7 @@ impl TestResponse { V: IntoHeaderValue, { if let Ok(key) = HeaderName::try_from(key) { - if let Ok(value) = value.try_into() { + if let Ok(value) = value.try_into_value() { self.head.headers.append(key, value); return self; } diff --git a/awc/src/ws.rs b/awc/src/ws.rs index f747f701f..17086cf2a 100644 --- a/awc/src/ws.rs +++ b/awc/src/ws.rs @@ -170,7 +170,7 @@ impl WebsocketsRequest { V: IntoHeaderValue, { match HeaderName::try_from(key) { - Ok(key) => match value.try_into() { + Ok(key) => match value.try_into_value() { Ok(value) => { self.head.headers.append(key, value); } @@ -189,7 +189,7 @@ impl WebsocketsRequest { V: IntoHeaderValue, { match HeaderName::try_from(key) { - Ok(key) => match value.try_into() { + Ok(key) => match value.try_into_value() { Ok(value) => { self.head.headers.insert(key, value); } @@ -210,7 +210,7 @@ impl WebsocketsRequest { match HeaderName::try_from(key) { Ok(key) => { if !self.head.headers.contains_key(&key) { - match value.try_into() { + match value.try_into_value() { Ok(value) => { self.head.headers.insert(key, value); } diff --git a/src/responder.rs b/src/responder.rs index 9b33ac81a..b7745aa4f 100644 --- a/src/responder.rs +++ b/src/responder.rs @@ -2,7 +2,7 @@ use std::convert::TryFrom; use actix_http::error::InternalError; use actix_http::http::{ - header::IntoHeaderValue, Error as HttpError, HeaderMap, HeaderName, StatusCode, + header::IntoHeaderPair, Error as HttpError, HeaderMap, HeaderName, StatusCode, }; use actix_http::ResponseBuilder; use bytes::{Bytes, BytesMut}; @@ -203,29 +203,24 @@ impl CustomResponder { /// web::Json( /// MyObj{name: "Name".to_string()} /// ) - /// .with_header("x-version", "1.2.3") + /// .with_header(("x-version", "1.2.3")) /// } /// # fn main() {} /// ``` - pub fn with_header(mut self, key: K, value: V) -> Self + pub fn with_header(mut self, header: H) -> Self where - HeaderName: TryFrom, - >::Error: Into, - V: IntoHeaderValue, + H: IntoHeaderPair, + H::Error: Into, { if self.headers.is_none() { self.headers = Some(HeaderMap::new()); } - match HeaderName::try_from(key) { - Ok(key) => match value.try_into() { - Ok(value) => { - self.headers.as_mut().unwrap().append(key, value); - } - Err(e) => self.error = Some(e.into()), - }, + match header.try_into_header_pair() { + Ok((key, value)) => self.headers.as_mut().unwrap().append(key, value), Err(e) => self.error = Some(e.into()), }; + self } }