mirror of
https://github.com/fafhrd91/actix-web
synced 2025-06-25 06:39:22 +02:00
response header rework (#1869)
This commit is contained in:
@ -1,6 +1,17 @@
|
||||
# Changes
|
||||
|
||||
## Unreleased - 2021-xx-xx
|
||||
### Added
|
||||
* `ClientRequest::insert_header` method which allows using typed headers. [#1869]
|
||||
* `ClientRequest::append_header` method which allows using typed headers. [#1869]
|
||||
|
||||
### Removed
|
||||
* `ClientRequest::set`; use `ClientRequest::insert_header`. [#1869]
|
||||
* `ClientRequest::set_header`; use `ClientRequest::insert_header`. [#1869]
|
||||
* `ClientRequest::set_header_if_none`; use `ClientRequest::insert_header_if_none`. [#1869]
|
||||
* `ClientRequest::header`; use `ClientRequest::append_header`. [#1869]
|
||||
|
||||
[#1869]: https://github.com/actix/actix-web/pull/1869
|
||||
|
||||
|
||||
## 3.0.0-beta.1 - 2021-01-07
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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()),
|
||||
},
|
||||
|
@ -7,7 +7,7 @@
|
||||
//! # async fn main() -> Result<(), awc::error::SendRequestError> {
|
||||
//! let mut client = awc::Client::default();
|
||||
//! let response = client.get("http://www.rust-lang.org") // <- Create request builder
|
||||
//! .header("User-Agent", "Actix-web")
|
||||
//! .insert_header(("User-Agent", "Actix-web"))
|
||||
//! .send() // <- Send http request
|
||||
//! .await?;
|
||||
//!
|
||||
@ -134,7 +134,7 @@ use self::connect::{Connect, ConnectorWrapper};
|
||||
/// let mut client = Client::default();
|
||||
///
|
||||
/// let res = client.get("http://www.rust-lang.org") // <- Create request builder
|
||||
/// .header("User-Agent", "Actix-web")
|
||||
/// .insert_header(("User-Agent", "Actix-web"))
|
||||
/// .send() // <- Send http request
|
||||
/// .await; // <- send request and wait for response
|
||||
///
|
||||
@ -182,8 +182,8 @@ impl Client {
|
||||
{
|
||||
let mut req = ClientRequest::new(method, url, self.0.clone());
|
||||
|
||||
for (key, value) in self.0.headers.iter() {
|
||||
req = req.set_header_if_none(key.clone(), value.clone());
|
||||
for header in self.0.headers.iter() {
|
||||
req = req.insert_header_if_none(header);
|
||||
}
|
||||
req
|
||||
}
|
||||
@ -198,8 +198,8 @@ impl Client {
|
||||
<Uri as TryFrom<U>>::Error: Into<HttpError>,
|
||||
{
|
||||
let mut req = self.request(head.method.clone(), url);
|
||||
for (key, value) in head.headers.iter() {
|
||||
req = req.set_header_if_none(key.clone(), value.clone());
|
||||
for header in head.headers.iter() {
|
||||
req = req.insert_header_if_none(header);
|
||||
}
|
||||
req
|
||||
}
|
||||
|
@ -9,10 +9,10 @@ use serde::Serialize;
|
||||
|
||||
use actix_http::body::Body;
|
||||
use actix_http::cookie::{Cookie, CookieJar};
|
||||
use actix_http::http::header::{self, Header, IntoHeaderValue};
|
||||
use actix_http::http::header::{self, IntoHeaderPair};
|
||||
use actix_http::http::{
|
||||
uri, ConnectionType, Error as HttpError, HeaderMap, HeaderName, HeaderValue, Method,
|
||||
Uri, Version,
|
||||
uri, ConnectionType, Error as HttpError, HeaderMap, HeaderValue, Method, Uri,
|
||||
Version,
|
||||
};
|
||||
use actix_http::{Error, RequestHead};
|
||||
|
||||
@ -37,13 +37,11 @@ cfg_if::cfg_if! {
|
||||
/// builder-like pattern.
|
||||
///
|
||||
/// ```rust
|
||||
/// use actix_rt::System;
|
||||
///
|
||||
/// #[actix_rt::main]
|
||||
/// async fn main() {
|
||||
/// let response = awc::Client::new()
|
||||
/// .get("http://www.rust-lang.org") // <- Create request builder
|
||||
/// .header("User-Agent", "Actix-web")
|
||||
/// .insert_header(("User-Agent", "Actix-web"))
|
||||
/// .send() // <- Send http request
|
||||
/// .await;
|
||||
///
|
||||
@ -143,110 +141,71 @@ impl ClientRequest {
|
||||
&self.head.peer_addr
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Returns request's headers.
|
||||
#[inline]
|
||||
pub fn headers(&self) -> &HeaderMap {
|
||||
&self.head.headers
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Returns request's mutable headers.
|
||||
#[inline]
|
||||
pub fn headers_mut(&mut self) -> &mut HeaderMap {
|
||||
&mut self.head.headers
|
||||
}
|
||||
|
||||
/// Set a header.
|
||||
///
|
||||
/// ```rust
|
||||
/// fn main() {
|
||||
/// # actix_rt::System::new("test").block_on(futures_util::future::lazy(|_| {
|
||||
/// let req = awc::Client::new()
|
||||
/// .get("http://www.rust-lang.org")
|
||||
/// .set(awc::http::header::Date::now())
|
||||
/// .set(awc::http::header::ContentType(mime::TEXT_HTML));
|
||||
/// # Ok::<_, ()>(())
|
||||
/// # }));
|
||||
/// }
|
||||
/// ```
|
||||
pub fn set<H: Header>(mut self, hdr: H) -> Self {
|
||||
match hdr.try_into() {
|
||||
Ok(value) => {
|
||||
self.head.headers.insert(H::name(), value);
|
||||
}
|
||||
Err(e) => self.err = Some(e.into()),
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Append a header.
|
||||
///
|
||||
/// Header gets appended to existing header.
|
||||
/// To override header use `set_header()` method.
|
||||
///
|
||||
/// ```rust
|
||||
/// use awc::{http, Client};
|
||||
///
|
||||
/// fn main() {
|
||||
/// # actix_rt::System::new("test").block_on(async {
|
||||
/// let req = Client::new()
|
||||
/// .get("http://www.rust-lang.org")
|
||||
/// .header("X-TEST", "value")
|
||||
/// .header(http::header::CONTENT_TYPE, "application/json");
|
||||
/// # Ok::<_, ()>(())
|
||||
/// # });
|
||||
/// }
|
||||
/// ```
|
||||
pub fn header<K, V>(mut self, key: K, value: V) -> Self
|
||||
/// Insert a header, replacing any that were set with an equivalent field name.
|
||||
pub fn insert_header<H>(mut self, header: H) -> Self
|
||||
where
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
H: IntoHeaderPair,
|
||||
{
|
||||
match HeaderName::try_from(key) {
|
||||
Ok(key) => match value.try_into() {
|
||||
Ok(value) => self.head.headers.append(key, value),
|
||||
Err(e) => self.err = Some(e.into()),
|
||||
},
|
||||
match header.try_into_header_pair() {
|
||||
Ok((key, value)) => self.head.headers.insert(key, value),
|
||||
Err(e) => self.err = Some(e.into()),
|
||||
}
|
||||
self
|
||||
}
|
||||
};
|
||||
|
||||
/// Insert a header, replaces existing header.
|
||||
pub fn set_header<K, V>(mut self, key: K, value: V) -> Self
|
||||
where
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
{
|
||||
match HeaderName::try_from(key) {
|
||||
Ok(key) => match value.try_into() {
|
||||
Ok(value) => self.head.headers.insert(key, value),
|
||||
Err(e) => self.err = Some(e.into()),
|
||||
},
|
||||
Err(e) => self.err = Some(e.into()),
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Insert a header only if it is not yet set.
|
||||
pub fn set_header_if_none<K, V>(mut self, key: K, value: V) -> Self
|
||||
pub fn insert_header_if_none<H>(mut self, header: H) -> Self
|
||||
where
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
H: IntoHeaderPair,
|
||||
{
|
||||
match HeaderName::try_from(key) {
|
||||
Ok(key) => {
|
||||
match header.try_into_header_pair() {
|
||||
Ok((key, value)) => {
|
||||
if !self.head.headers.contains_key(&key) {
|
||||
match value.try_into() {
|
||||
Ok(value) => self.head.headers.insert(key, value),
|
||||
Err(e) => self.err = Some(e.into()),
|
||||
}
|
||||
self.head.headers.insert(key, value);
|
||||
}
|
||||
}
|
||||
Err(e) => self.err = Some(e.into()),
|
||||
}
|
||||
};
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Append a header, keeping any that were set with an equivalent field name.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[actix_rt::main]
|
||||
/// # async fn main() {
|
||||
/// # use awc::Client;
|
||||
/// use awc::http::header::ContentType;
|
||||
///
|
||||
/// Client::new()
|
||||
/// .get("http://www.rust-lang.org")
|
||||
/// .insert_header(("X-TEST", "value"))
|
||||
/// .insert_header(ContentType(mime::APPLICATION_JSON));
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn append_header<H>(mut self, header: H) -> Self
|
||||
where
|
||||
H: IntoHeaderPair,
|
||||
{
|
||||
match header.try_into_header_pair() {
|
||||
Ok((key, value)) => self.head.headers.append(key, value),
|
||||
Err(e) => self.err = Some(e.into()),
|
||||
};
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
@ -282,7 +241,7 @@ impl ClientRequest {
|
||||
/// Set content length
|
||||
#[inline]
|
||||
pub fn content_length(self, len: u64) -> Self {
|
||||
self.header(header::CONTENT_LENGTH, len)
|
||||
self.append_header((header::CONTENT_LENGTH, len))
|
||||
}
|
||||
|
||||
/// Set HTTP basic authorization header
|
||||
@ -294,10 +253,10 @@ impl ClientRequest {
|
||||
Some(password) => format!("{}:{}", username, password),
|
||||
None => format!("{}:", username),
|
||||
};
|
||||
self.header(
|
||||
self.append_header((
|
||||
header::AUTHORIZATION,
|
||||
format!("Basic {}", base64::encode(&auth)),
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
/// Set HTTP bearer authentication header
|
||||
@ -305,7 +264,7 @@ impl ClientRequest {
|
||||
where
|
||||
T: fmt::Display,
|
||||
{
|
||||
self.header(header::AUTHORIZATION, format!("Bearer {}", token))
|
||||
self.append_header((header::AUTHORIZATION, format!("Bearer {}", token)))
|
||||
}
|
||||
|
||||
/// Set a cookie
|
||||
@ -557,12 +516,15 @@ impl ClientRequest {
|
||||
.unwrap_or(true);
|
||||
|
||||
if https {
|
||||
slf = slf.set_header_if_none(header::ACCEPT_ENCODING, HTTPS_ENCODING)
|
||||
slf =
|
||||
slf.insert_header_if_none((header::ACCEPT_ENCODING, HTTPS_ENCODING))
|
||||
} else {
|
||||
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
|
||||
{
|
||||
slf =
|
||||
slf.set_header_if_none(header::ACCEPT_ENCODING, "gzip, deflate")
|
||||
slf = slf.insert_header_if_none((
|
||||
header::ACCEPT_ENCODING,
|
||||
"gzip, deflate",
|
||||
))
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -595,7 +557,7 @@ mod tests {
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_debug() {
|
||||
let request = Client::new().get("/").header("x-test", "111");
|
||||
let request = Client::new().get("/").append_header(("x-test", "111"));
|
||||
let repr = format!("{:?}", request);
|
||||
assert!(repr.contains("ClientRequest"));
|
||||
assert!(repr.contains("x-test"));
|
||||
@ -606,18 +568,18 @@ mod tests {
|
||||
let req = Client::new()
|
||||
.put("/")
|
||||
.version(Version::HTTP_2)
|
||||
.set(header::Date(SystemTime::now().into()))
|
||||
.insert_header(header::Date(SystemTime::now().into()))
|
||||
.content_type("plain/text")
|
||||
.header(header::SERVER, "awc");
|
||||
.append_header((header::SERVER, "awc"));
|
||||
|
||||
let req = if let Some(val) = Some("server") {
|
||||
req.header(header::USER_AGENT, val)
|
||||
req.append_header((header::USER_AGENT, val))
|
||||
} else {
|
||||
req
|
||||
};
|
||||
|
||||
let req = if let Some(_val) = Option::<&str>::None {
|
||||
req.header(header::ALLOW, "1")
|
||||
req.append_header((header::ALLOW, "1"))
|
||||
} else {
|
||||
req
|
||||
};
|
||||
@ -660,7 +622,7 @@ mod tests {
|
||||
.header(header::CONTENT_TYPE, "111")
|
||||
.finish()
|
||||
.get("/")
|
||||
.set_header(header::CONTENT_TYPE, "222");
|
||||
.insert_header((header::CONTENT_TYPE, "222"));
|
||||
|
||||
assert_eq!(
|
||||
req.head
|
||||
|
@ -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)
|
||||
|
@ -45,7 +45,7 @@ impl TestResponse {
|
||||
|
||||
/// Set a header
|
||||
pub fn set<H: Header>(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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ async fn test_simple() {
|
||||
.service(web::resource("/").route(web::to(|| HttpResponse::Ok().body(STR))))
|
||||
});
|
||||
|
||||
let request = srv.get("/").header("x-test", "111").send();
|
||||
let request = srv.get("/").insert_header(("x-test", "111")).send();
|
||||
let mut response = request.await.unwrap();
|
||||
assert!(response.status().is_success());
|
||||
|
||||
@ -82,7 +82,7 @@ async fn test_json() {
|
||||
|
||||
let request = srv
|
||||
.get("/")
|
||||
.header("x-test", "111")
|
||||
.insert_header(("x-test", "111"))
|
||||
.send_json(&"TEST".to_string());
|
||||
let response = request.await.unwrap();
|
||||
assert!(response.status().is_success());
|
||||
@ -99,7 +99,10 @@ async fn test_form() {
|
||||
let mut data = HashMap::new();
|
||||
let _ = data.insert("key".to_string(), "TEST".to_string());
|
||||
|
||||
let request = srv.get("/").header("x-test", "111").send_form(&data);
|
||||
let request = srv
|
||||
.get("/")
|
||||
.append_header(("x-test", "111"))
|
||||
.send_form(&data);
|
||||
let response = request.await.unwrap();
|
||||
assert!(response.status().is_success());
|
||||
}
|
||||
@ -438,7 +441,7 @@ async fn test_client_gzip_encoding() {
|
||||
let data = e.finish().unwrap();
|
||||
|
||||
HttpResponse::Ok()
|
||||
.header("content-encoding", "gzip")
|
||||
.insert_header(("content-encoding", "gzip"))
|
||||
.body(data)
|
||||
})))
|
||||
});
|
||||
@ -461,7 +464,7 @@ async fn test_client_gzip_encoding_large() {
|
||||
let data = e.finish().unwrap();
|
||||
|
||||
HttpResponse::Ok()
|
||||
.header("content-encoding", "gzip")
|
||||
.insert_header(("content-encoding", "gzip"))
|
||||
.body(data)
|
||||
})))
|
||||
});
|
||||
@ -489,7 +492,7 @@ async fn test_client_gzip_encoding_large_random() {
|
||||
e.write_all(&data).unwrap();
|
||||
let data = e.finish().unwrap();
|
||||
HttpResponse::Ok()
|
||||
.header("content-encoding", "gzip")
|
||||
.insert_header(("content-encoding", "gzip"))
|
||||
.body(data)
|
||||
})))
|
||||
});
|
||||
@ -511,7 +514,7 @@ async fn test_client_brotli_encoding() {
|
||||
e.write_all(&data).unwrap();
|
||||
let data = e.finish().unwrap();
|
||||
HttpResponse::Ok()
|
||||
.header("content-encoding", "br")
|
||||
.insert_header(("content-encoding", "br"))
|
||||
.body(data)
|
||||
})))
|
||||
});
|
||||
@ -539,7 +542,7 @@ async fn test_client_brotli_encoding_large_random() {
|
||||
e.write_all(&data).unwrap();
|
||||
let data = e.finish().unwrap();
|
||||
HttpResponse::Ok()
|
||||
.header("content-encoding", "br")
|
||||
.insert_header(("content-encoding", "br"))
|
||||
.body(data)
|
||||
})))
|
||||
});
|
||||
|
Reference in New Issue
Block a user