mirror of
https://github.com/fafhrd91/actix-web
synced 2024-11-23 16:21:06 +01:00
move typed headers and implement FromRequest (#2094)
Co-authored-by: Rob Ede <robjtede@icloud.com>
This commit is contained in:
parent
c8ed8dd1a4
commit
50dc13f280
@ -2,6 +2,7 @@
|
||||
|
||||
## Unreleased - 2021-xx-xx
|
||||
### Added
|
||||
* `Header` extractor for extracting common HTTP headers in handlers. [#2094]
|
||||
* Added `TestServer::client_headers` method. [#2097]
|
||||
|
||||
### Fixed
|
||||
@ -17,6 +18,8 @@
|
||||
|
||||
[#2067]: https://github.com/actix/actix-web/pull/2067
|
||||
[#2093]: https://github.com/actix/actix-web/pull/2093
|
||||
[#2094]: https://github.com/actix/actix-web/pull/2094
|
||||
[#2097]: https://github.com/actix/actix-web/pull/2097
|
||||
|
||||
|
||||
## 4.0.0-beta.4 - 2021-03-09
|
||||
|
@ -97,6 +97,8 @@ either = "1.5.3"
|
||||
encoding_rs = "0.8"
|
||||
futures-core = { version = "0.3.7", default-features = false }
|
||||
futures-util = { version = "0.3.7", default-features = false }
|
||||
language-tags = "0.2"
|
||||
once_cell = "1.5"
|
||||
log = "0.4"
|
||||
mime = "0.3"
|
||||
pin-project = "1.0.0"
|
||||
|
@ -10,10 +10,12 @@
|
||||
* `client::Connector` type now only have one generic type for `actix_service::Service`. [#2063]
|
||||
|
||||
### Removed
|
||||
* Common HTTP headers were moved into actix-web. [2094]
|
||||
* `ResponseError` impl for `actix_utils::timeout::TimeoutError`. [#2127]
|
||||
|
||||
[#2063]: https://github.com/actix/actix-web/pull/2063
|
||||
[#2081]: https://github.com/actix/actix-web/pull/2081
|
||||
[#2094]: https://github.com/actix/actix-web/pull/2094
|
||||
[#2127]: https://github.com/actix/actix-web/pull/2127
|
||||
|
||||
|
||||
|
@ -1,9 +1,6 @@
|
||||
//! Typed HTTP headers, pre-defined `HeaderName`s, traits for parsing and conversion, and other
|
||||
//! header utility methods.
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use bytes::{Bytes, BytesMut};
|
||||
use percent_encoding::{AsciiSet, CONTROLS};
|
||||
|
||||
pub use http::header::*;
|
||||
@ -16,11 +13,9 @@ mod into_pair;
|
||||
mod into_value;
|
||||
mod utils;
|
||||
|
||||
mod common;
|
||||
pub(crate) mod map;
|
||||
mod shared;
|
||||
|
||||
pub use self::common::*;
|
||||
#[doc(hidden)]
|
||||
pub use self::shared::*;
|
||||
|
||||
@ -41,34 +36,6 @@ pub trait Header: IntoHeaderValue {
|
||||
fn parse<T: HttpMessage>(msg: &T) -> Result<Self, ParseError>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct Writer {
|
||||
buf: BytesMut,
|
||||
}
|
||||
|
||||
impl Writer {
|
||||
fn new() -> Writer {
|
||||
Writer::default()
|
||||
}
|
||||
|
||||
fn take(&mut self) -> Bytes {
|
||||
self.buf.split().freeze()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for Writer {
|
||||
#[inline]
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
self.buf.extend_from_slice(s.as_bytes());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
|
||||
fmt::write(self, args)
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert `http::HeaderMap` to our `HeaderMap`.
|
||||
impl From<http::HeaderMap> for HeaderMap {
|
||||
fn from(mut map: http::HeaderMap) -> HeaderMap {
|
||||
|
@ -1,15 +1,13 @@
|
||||
//! Originally taken from `hyper::header::shared`.
|
||||
|
||||
mod charset;
|
||||
mod encoding;
|
||||
mod entity;
|
||||
mod content_encoding;
|
||||
mod extended;
|
||||
mod httpdate;
|
||||
mod quality_item;
|
||||
|
||||
pub use self::charset::Charset;
|
||||
pub use self::encoding::Encoding;
|
||||
pub use self::entity::EntityTag;
|
||||
pub use self::content_encoding::ContentEncoding;
|
||||
pub use self::extended::{parse_extended_value, ExtendedValue};
|
||||
pub use self::httpdate::HttpDate;
|
||||
pub use self::quality_item::{q, qitem, Quality, QualityItem};
|
||||
|
@ -193,21 +193,69 @@ where
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::encoding::*;
|
||||
use super::*;
|
||||
|
||||
// copy of encoding from actix-web headers
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum Encoding {
|
||||
Chunked,
|
||||
Brotli,
|
||||
Gzip,
|
||||
Deflate,
|
||||
Compress,
|
||||
Identity,
|
||||
Trailers,
|
||||
EncodingExt(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for Encoding {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use Encoding::*;
|
||||
f.write_str(match *self {
|
||||
Chunked => "chunked",
|
||||
Brotli => "br",
|
||||
Gzip => "gzip",
|
||||
Deflate => "deflate",
|
||||
Compress => "compress",
|
||||
Identity => "identity",
|
||||
Trailers => "trailers",
|
||||
EncodingExt(ref s) => s.as_ref(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl str::FromStr for Encoding {
|
||||
type Err = crate::error::ParseError;
|
||||
fn from_str(s: &str) -> Result<Encoding, crate::error::ParseError> {
|
||||
use Encoding::*;
|
||||
match s {
|
||||
"chunked" => Ok(Chunked),
|
||||
"br" => Ok(Brotli),
|
||||
"deflate" => Ok(Deflate),
|
||||
"gzip" => Ok(Gzip),
|
||||
"compress" => Ok(Compress),
|
||||
"identity" => Ok(Identity),
|
||||
"trailers" => Ok(Trailers),
|
||||
_ => Ok(EncodingExt(s.to_owned())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quality_item_fmt_q_1() {
|
||||
use Encoding::*;
|
||||
let x = qitem(Chunked);
|
||||
assert_eq!(format!("{}", x), "chunked");
|
||||
}
|
||||
#[test]
|
||||
fn test_quality_item_fmt_q_0001() {
|
||||
use Encoding::*;
|
||||
let x = QualityItem::new(Chunked, Quality(1));
|
||||
assert_eq!(format!("{}", x), "chunked; q=0.001");
|
||||
}
|
||||
#[test]
|
||||
fn test_quality_item_fmt_q_05() {
|
||||
use Encoding::*;
|
||||
// Custom value
|
||||
let x = QualityItem {
|
||||
item: EncodingExt("identity".to_owned()),
|
||||
@ -218,6 +266,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_quality_item_fmt_q_0() {
|
||||
use Encoding::*;
|
||||
// Custom value
|
||||
let x = QualityItem {
|
||||
item: EncodingExt("identity".to_owned()),
|
||||
@ -228,6 +277,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_quality_item_from_str1() {
|
||||
use Encoding::*;
|
||||
let x: Result<QualityItem<Encoding>, _> = "chunked".parse();
|
||||
assert_eq!(
|
||||
x.unwrap(),
|
||||
@ -237,8 +287,10 @@ mod tests {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quality_item_from_str2() {
|
||||
use Encoding::*;
|
||||
let x: Result<QualityItem<Encoding>, _> = "chunked; q=1".parse();
|
||||
assert_eq!(
|
||||
x.unwrap(),
|
||||
@ -248,8 +300,10 @@ mod tests {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quality_item_from_str3() {
|
||||
use Encoding::*;
|
||||
let x: Result<QualityItem<Encoding>, _> = "gzip; q=0.5".parse();
|
||||
assert_eq!(
|
||||
x.unwrap(),
|
||||
@ -259,8 +313,10 @@ mod tests {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quality_item_from_str4() {
|
||||
use Encoding::*;
|
||||
let x: Result<QualityItem<Encoding>, _> = "gzip; q=0.273".parse();
|
||||
assert_eq!(
|
||||
x.unwrap(),
|
||||
@ -270,16 +326,19 @@ mod tests {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quality_item_from_str5() {
|
||||
let x: Result<QualityItem<Encoding>, _> = "gzip; q=0.2739999".parse();
|
||||
assert!(x.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quality_item_from_str6() {
|
||||
let x: Result<QualityItem<Encoding>, _> = "gzip; q=2".parse();
|
||||
assert!(x.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quality_item_ordering() {
|
||||
let x: QualityItem<Encoding> = "gzip; q=0.5".parse().ok().unwrap();
|
||||
|
@ -1,7 +1,6 @@
|
||||
use std::{fmt, str::FromStr};
|
||||
|
||||
use http::HeaderValue;
|
||||
|
||||
use super::HeaderValue;
|
||||
use crate::{error::ParseError, header::HTTP_VALUE};
|
||||
|
||||
/// Reads a comma-delimited raw header into a Vec.
|
||||
|
@ -359,10 +359,10 @@ impl ResponseBuilder {
|
||||
///
|
||||
/// ```
|
||||
/// # use actix_http::Response;
|
||||
/// use actix_http::http::header::ContentType;
|
||||
/// use actix_http::http::header;
|
||||
///
|
||||
/// Response::Ok()
|
||||
/// .insert_header(ContentType(mime::APPLICATION_JSON))
|
||||
/// .insert_header((header::CONTENT_TYPE, mime::APPLICATION_JSON))
|
||||
/// .insert_header(("X-TEST", "value"))
|
||||
/// .finish();
|
||||
/// ```
|
||||
@ -386,10 +386,10 @@ impl ResponseBuilder {
|
||||
///
|
||||
/// ```
|
||||
/// # use actix_http::Response;
|
||||
/// use actix_http::http::header::ContentType;
|
||||
/// use actix_http::http::header;
|
||||
///
|
||||
/// Response::Ok()
|
||||
/// .append_header(ContentType(mime::APPLICATION_JSON))
|
||||
/// .append_header((header::CONTENT_TYPE, mime::APPLICATION_JSON))
|
||||
/// .append_header(("X-TEST", "value1"))
|
||||
/// .append_header(("X-TEST", "value2"))
|
||||
/// .finish();
|
||||
@ -682,7 +682,7 @@ impl ResponseBuilder {
|
||||
};
|
||||
|
||||
if !contains {
|
||||
self.insert_header(header::ContentType(mime::APPLICATION_JSON));
|
||||
self.insert_header((header::CONTENT_TYPE, mime::APPLICATION_JSON));
|
||||
}
|
||||
|
||||
self.body(Body::from(body))
|
||||
@ -1133,7 +1133,7 @@ mod tests {
|
||||
#[test]
|
||||
fn response_builder_header_insert_typed() {
|
||||
let mut res = Response::Ok();
|
||||
res.insert_header(header::ContentType(mime::APPLICATION_OCTET_STREAM));
|
||||
res.insert_header((header::CONTENT_TYPE, mime::APPLICATION_OCTET_STREAM));
|
||||
let res = res.finish();
|
||||
|
||||
assert_eq!(
|
||||
@ -1158,8 +1158,8 @@ mod tests {
|
||||
#[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));
|
||||
res.append_header((header::CONTENT_TYPE, mime::APPLICATION_OCTET_STREAM));
|
||||
res.append_header((header::CONTENT_TYPE, mime::APPLICATION_JSON));
|
||||
let res = res.finish();
|
||||
|
||||
let headers: Vec<_> = res.headers().get_all("Content-Type").cloned().collect();
|
||||
|
@ -7,8 +7,10 @@
|
||||
### Changed
|
||||
* `ConnectorService` type is renamed to `BoxConnectorService`. [#2081]
|
||||
* Fix http/https encoding when enabling `compress` feature. [#2116]
|
||||
* Rename `TestResponse::header` to `append_header`, `set` to `insert_header`. `TestResponse` header methods now take `IntoHeaderPair` tuples. [#2094]
|
||||
|
||||
[#2081]: https://github.com/actix/actix-web/pull/2081
|
||||
[#2094]: https://github.com/actix/actix-web/pull/2094
|
||||
[#2114]: https://github.com/actix/actix-web/pull/2114
|
||||
[#2116]: https://github.com/actix/actix-web/pull/2116
|
||||
|
||||
|
@ -189,12 +189,12 @@ impl ClientRequest {
|
||||
/// # #[actix_rt::main]
|
||||
/// # async fn main() {
|
||||
/// # use awc::Client;
|
||||
/// use awc::http::header::ContentType;
|
||||
/// use awc::http::header::CONTENT_TYPE;
|
||||
///
|
||||
/// Client::new()
|
||||
/// .get("http://www.rust-lang.org")
|
||||
/// .insert_header(("X-TEST", "value"))
|
||||
/// .insert_header(ContentType(mime::APPLICATION_JSON));
|
||||
/// .insert_header((CONTENT_TYPE, mime::APPLICATION_JSON));
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn append_header<H>(mut self, header: H) -> Self
|
||||
@ -548,6 +548,8 @@ impl fmt::Debug for ClientRequest {
|
||||
mod tests {
|
||||
use std::time::SystemTime;
|
||||
|
||||
use actix_http::http::header::HttpDate;
|
||||
|
||||
use super::*;
|
||||
use crate::Client;
|
||||
|
||||
@ -564,7 +566,7 @@ mod tests {
|
||||
let req = Client::new()
|
||||
.put("/")
|
||||
.version(Version::HTTP_2)
|
||||
.insert_header(header::Date(SystemTime::now().into()))
|
||||
.insert_header((header::DATE, HttpDate::from(SystemTime::now())))
|
||||
.content_type("plain/text")
|
||||
.append_header((header::SERVER, "awc"));
|
||||
|
||||
|
@ -449,13 +449,13 @@ mod tests {
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_body() {
|
||||
let mut req = TestResponse::with_header(header::CONTENT_LENGTH, "xxxx").finish();
|
||||
let mut req = TestResponse::with_header((header::CONTENT_LENGTH, "xxxx")).finish();
|
||||
match req.body().await.err().unwrap() {
|
||||
PayloadError::UnknownLength => {}
|
||||
_ => unreachable!("error"),
|
||||
}
|
||||
|
||||
let mut req = TestResponse::with_header(header::CONTENT_LENGTH, "10000000").finish();
|
||||
let mut req = TestResponse::with_header((header::CONTENT_LENGTH, "10000000")).finish();
|
||||
match req.body().await.err().unwrap() {
|
||||
PayloadError::Overflow => {}
|
||||
_ => unreachable!("error"),
|
||||
@ -497,23 +497,23 @@ mod tests {
|
||||
assert!(json_eq(json.err().unwrap(), JsonPayloadError::ContentType));
|
||||
|
||||
let mut req = TestResponse::default()
|
||||
.header(
|
||||
.insert_header((
|
||||
header::CONTENT_TYPE,
|
||||
header::HeaderValue::from_static("application/text"),
|
||||
)
|
||||
))
|
||||
.finish();
|
||||
let json = JsonBody::<_, MyObject>::new(&mut req).await;
|
||||
assert!(json_eq(json.err().unwrap(), JsonPayloadError::ContentType));
|
||||
|
||||
let mut req = TestResponse::default()
|
||||
.header(
|
||||
.insert_header((
|
||||
header::CONTENT_TYPE,
|
||||
header::HeaderValue::from_static("application/json"),
|
||||
)
|
||||
.header(
|
||||
))
|
||||
.insert_header((
|
||||
header::CONTENT_LENGTH,
|
||||
header::HeaderValue::from_static("10000"),
|
||||
)
|
||||
))
|
||||
.finish();
|
||||
|
||||
let json = JsonBody::<_, MyObject>::new(&mut req).limit(100).await;
|
||||
@ -523,14 +523,14 @@ mod tests {
|
||||
));
|
||||
|
||||
let mut req = TestResponse::default()
|
||||
.header(
|
||||
.insert_header((
|
||||
header::CONTENT_TYPE,
|
||||
header::HeaderValue::from_static("application/json"),
|
||||
)
|
||||
.header(
|
||||
))
|
||||
.insert_header((
|
||||
header::CONTENT_LENGTH,
|
||||
header::HeaderValue::from_static("16"),
|
||||
)
|
||||
))
|
||||
.set_payload(Bytes::from_static(b"{\"name\": \"test\"}"))
|
||||
.finish();
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
//! Test helpers for actix http client to use during testing.
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use actix_http::http::header::{Header, IntoHeaderValue};
|
||||
use actix_http::http::{Error as HttpError, HeaderName, StatusCode, Version};
|
||||
use actix_http::http::header::IntoHeaderPair;
|
||||
use actix_http::http::{StatusCode, Version};
|
||||
#[cfg(feature = "cookies")]
|
||||
use actix_http::{
|
||||
cookie::{Cookie, CookieJar},
|
||||
@ -34,13 +32,11 @@ impl Default for TestResponse {
|
||||
|
||||
impl TestResponse {
|
||||
/// Create TestResponse and set header
|
||||
pub fn with_header<K, V>(key: K, value: V) -> Self
|
||||
pub fn with_header<H>(header: H) -> Self
|
||||
where
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
H: IntoHeaderPair,
|
||||
{
|
||||
Self::default().header(key, value)
|
||||
Self::default().insert_header(header)
|
||||
}
|
||||
|
||||
/// Set HTTP version of this response
|
||||
@ -49,28 +45,27 @@ impl TestResponse {
|
||||
self
|
||||
}
|
||||
|
||||
/// Set a header
|
||||
pub fn set<H: Header>(mut self, hdr: H) -> Self {
|
||||
if let Ok(value) = hdr.try_into_value() {
|
||||
self.head.headers.append(H::name(), value);
|
||||
/// Insert a header
|
||||
pub fn insert_header<H>(mut self, header: H) -> Self
|
||||
where
|
||||
H: IntoHeaderPair,
|
||||
{
|
||||
if let Ok((key, value)) = header.try_into_header_pair() {
|
||||
self.head.headers.insert(key, value);
|
||||
return self;
|
||||
}
|
||||
panic!("Can not set header");
|
||||
}
|
||||
|
||||
/// Append a header
|
||||
pub fn header<K, V>(mut self, key: K, value: V) -> Self
|
||||
pub fn append_header<H>(mut self, header: H) -> Self
|
||||
where
|
||||
HeaderName: TryFrom<K>,
|
||||
<HeaderName as TryFrom<K>>::Error: Into<HttpError>,
|
||||
V: IntoHeaderValue,
|
||||
H: IntoHeaderPair,
|
||||
{
|
||||
if let Ok(key) = HeaderName::try_from(key) {
|
||||
if let Ok(value) = value.try_into_value() {
|
||||
if let Ok((key, value)) = header.try_into_header_pair() {
|
||||
self.head.headers.append(key, value);
|
||||
return self;
|
||||
}
|
||||
}
|
||||
panic!("Can not create header");
|
||||
}
|
||||
|
||||
@ -115,6 +110,8 @@ impl TestResponse {
|
||||
mod tests {
|
||||
use std::time::SystemTime;
|
||||
|
||||
use actix_http::http::header::HttpDate;
|
||||
|
||||
use super::*;
|
||||
use crate::{cookie, http::header};
|
||||
|
||||
@ -122,7 +119,7 @@ mod tests {
|
||||
fn test_basics() {
|
||||
let res = TestResponse::default()
|
||||
.version(Version::HTTP_2)
|
||||
.set(header::Date(SystemTime::now().into()))
|
||||
.insert_header((header::DATE, HttpDate::from(SystemTime::now())))
|
||||
.cookie(cookie::Cookie::build("name", "value").finish())
|
||||
.finish();
|
||||
assert!(res.headers().contains_key(header::SET_COOKIE));
|
||||
|
@ -2,10 +2,10 @@ use std::cmp::Ordering;
|
||||
|
||||
use mime::Mime;
|
||||
|
||||
use crate::header::{qitem, QualityItem};
|
||||
use super::{qitem, QualityItem};
|
||||
use crate::http::header;
|
||||
|
||||
header! {
|
||||
crate::header! {
|
||||
/// `Accept` header, defined in [RFC7231](http://tools.ietf.org/html/rfc7231#section-5.3.2)
|
||||
///
|
||||
/// The `Accept` header field can be used by user agents to specify
|
||||
@ -33,10 +33,10 @@ header! {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::{Accept, qitem};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{Accept, qitem};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// Accept(vec![
|
||||
/// qitem(mime::TEXT_HTML),
|
||||
@ -45,10 +45,10 @@ header! {
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::{Accept, qitem};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{Accept, qitem};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// Accept(vec![
|
||||
/// qitem(mime::APPLICATION_JSON),
|
||||
@ -57,10 +57,10 @@ header! {
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::{Accept, QualityItem, q, qitem};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{Accept, QualityItem, q, qitem};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// Accept(vec![
|
||||
/// qitem(mime::TEXT_HTML),
|
||||
@ -116,8 +116,8 @@ header! {
|
||||
|
||||
#[test]
|
||||
fn test_fuzzing1() {
|
||||
use crate::test::TestRequest;
|
||||
let req = TestRequest::default().insert_header((crate::header::ACCEPT, "chunk#;e")).finish();
|
||||
use actix_http::test::TestRequest;
|
||||
let req = TestRequest::default().insert_header((crate::http::header::ACCEPT, "chunk#;e")).finish();
|
||||
let header = Accept::parse(&req);
|
||||
assert!(header.is_ok());
|
||||
}
|
||||
@ -213,7 +213,7 @@ impl Accept {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::header::q;
|
||||
use crate::http::header::q;
|
||||
|
||||
#[test]
|
||||
fn test_mime_precedence() {
|
@ -1,6 +1,6 @@
|
||||
use crate::header::{Charset, QualityItem, ACCEPT_CHARSET};
|
||||
use super::{Charset, QualityItem, ACCEPT_CHARSET};
|
||||
|
||||
header! {
|
||||
crate::header! {
|
||||
/// `Accept-Charset` header, defined in
|
||||
/// [RFC7231](http://tools.ietf.org/html/rfc7231#section-5.3.3)
|
||||
///
|
||||
@ -22,20 +22,20 @@ header! {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::{AcceptCharset, Charset, qitem};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{AcceptCharset, Charset, qitem};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// AcceptCharset(vec![qitem(Charset::Us_Ascii)])
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::{AcceptCharset, Charset, q, QualityItem};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{AcceptCharset, Charset, q, QualityItem};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// AcceptCharset(vec![
|
||||
/// QualityItem::new(Charset::Us_Ascii, q(900)),
|
||||
@ -45,10 +45,10 @@ header! {
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::{AcceptCharset, Charset, qitem};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{AcceptCharset, Charset, qitem};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// AcceptCharset(vec![qitem(Charset::Ext("utf-8".to_owned()))])
|
||||
/// );
|
@ -26,18 +26,20 @@ header! {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use hyper::header::{Headers, AcceptEncoding, Encoding, qitem};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{AcceptEncoding, Encoding, qitem};
|
||||
///
|
||||
/// let mut headers = Headers::new();
|
||||
/// headers.set(
|
||||
/// let mut builder = HttpResponse::new();
|
||||
/// builder.insert_header(
|
||||
/// AcceptEncoding(vec![qitem(Encoding::Chunked)])
|
||||
/// );
|
||||
/// ```
|
||||
/// ```
|
||||
/// use hyper::header::{Headers, AcceptEncoding, Encoding, qitem};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{AcceptEncoding, Encoding, qitem};
|
||||
///
|
||||
/// let mut headers = Headers::new();
|
||||
/// headers.set(
|
||||
/// let mut builder = HttpResponse::new();
|
||||
/// builder.insert_header(
|
||||
/// AcceptEncoding(vec![
|
||||
/// qitem(Encoding::Chunked),
|
||||
/// qitem(Encoding::Gzip),
|
||||
@ -46,10 +48,11 @@ header! {
|
||||
/// );
|
||||
/// ```
|
||||
/// ```
|
||||
/// use hyper::header::{Headers, AcceptEncoding, Encoding, QualityItem, q, qitem};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{AcceptEncoding, Encoding, QualityItem, q, qitem};
|
||||
///
|
||||
/// let mut headers = Headers::new();
|
||||
/// headers.set(
|
||||
/// let mut builder = HttpResponse::new();
|
||||
/// builder.insert_header(
|
||||
/// AcceptEncoding(vec![
|
||||
/// qitem(Encoding::Chunked),
|
||||
/// QualityItem::new(Encoding::Gzip, q(600)),
|
@ -1,7 +1,7 @@
|
||||
use crate::header::{QualityItem, ACCEPT_LANGUAGE};
|
||||
use super::{QualityItem, ACCEPT_LANGUAGE};
|
||||
use language_tags::LanguageTag;
|
||||
|
||||
header! {
|
||||
crate::header! {
|
||||
/// `Accept-Language` header, defined in
|
||||
/// [RFC7231](http://tools.ietf.org/html/rfc7231#section-5.3.5)
|
||||
///
|
||||
@ -24,10 +24,10 @@ header! {
|
||||
///
|
||||
/// ```
|
||||
/// use language_tags::langtag;
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::{AcceptLanguage, LanguageTag, qitem};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{AcceptLanguage, LanguageTag, qitem};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// let mut langtag: LanguageTag = Default::default();
|
||||
/// langtag.language = Some("en".to_owned());
|
||||
/// langtag.region = Some("US".to_owned());
|
||||
@ -40,10 +40,10 @@ header! {
|
||||
///
|
||||
/// ```
|
||||
/// use language_tags::langtag;
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::{AcceptLanguage, QualityItem, q, qitem};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{AcceptLanguage, QualityItem, q, qitem};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// AcceptLanguage(vec![
|
||||
/// qitem(langtag!(da)),
|
@ -1,7 +1,7 @@
|
||||
use http::header;
|
||||
use http::Method;
|
||||
use actix_http::http::Method;
|
||||
use crate::http::header;
|
||||
|
||||
header! {
|
||||
crate::header! {
|
||||
/// `Allow` header, defined in [RFC7231](http://tools.ietf.org/html/rfc7231#section-7.4.1)
|
||||
///
|
||||
/// The `Allow` header field lists the set of methods advertised as
|
||||
@ -23,20 +23,20 @@ header! {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::{header::Allow, Method};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::{header::Allow, Method};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// Allow(vec![Method::GET])
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::{header::Allow, Method};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::{header::Allow, Method};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// Allow(vec![
|
||||
/// Method::GET,
|
@ -1,12 +1,12 @@
|
||||
use std::fmt::{self, Write};
|
||||
use std::str::FromStr;
|
||||
|
||||
use http::header;
|
||||
|
||||
use crate::header::{
|
||||
use super::{
|
||||
fmt_comma_delimited, from_comma_delimited, Header, IntoHeaderValue, Writer,
|
||||
};
|
||||
|
||||
use crate::http::header;
|
||||
|
||||
/// `Cache-Control` header, defined in [RFC7234](https://tools.ietf.org/html/rfc7234#section-5.2)
|
||||
///
|
||||
/// The `Cache-Control` header field is used to specify directives for
|
||||
@ -29,18 +29,18 @@ use crate::header::{
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::{CacheControl, CacheDirective};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{CacheControl, CacheDirective};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(CacheControl(vec![CacheDirective::MaxAge(86400u32)]));
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::{CacheControl, CacheDirective};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{CacheControl, CacheDirective};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(CacheControl(vec![
|
||||
/// CacheDirective::NoCache,
|
||||
/// CacheDirective::Private,
|
||||
@ -191,8 +191,8 @@ impl FromStr for CacheDirective {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::header::Header;
|
||||
use crate::test::TestRequest;
|
||||
use crate::http::header::Header;
|
||||
use actix_http::test::TestRequest;
|
||||
|
||||
#[test]
|
||||
fn test_parse_multiple_headers() {
|
@ -10,7 +10,8 @@ use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use std::fmt::{self, Write};
|
||||
|
||||
use crate::header::{self, ExtendedValue, Header, IntoHeaderValue, Writer};
|
||||
use crate::http::header;
|
||||
use super::{ExtendedValue, Header, IntoHeaderValue, Writer};
|
||||
|
||||
/// Split at the index of the first `needle` if it exists or at the end.
|
||||
fn split_once(haystack: &str, needle: char) -> (&str, &str) {
|
||||
@ -63,7 +64,7 @@ impl<'a> From<&'a str> for DispositionType {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use actix_http::http::header::DispositionParam;
|
||||
/// use actix_web::http::header::DispositionParam;
|
||||
///
|
||||
/// let param = DispositionParam::Filename(String::from("sample.txt"));
|
||||
/// assert!(param.is_filename());
|
||||
@ -240,7 +241,7 @@ impl DispositionParam {
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use actix_http::http::header::{
|
||||
/// use actix_web::http::header::{
|
||||
/// Charset, ContentDisposition, DispositionParam, DispositionType,
|
||||
/// ExtendedValue,
|
||||
/// };
|
||||
@ -554,8 +555,8 @@ impl fmt::Display for ContentDisposition {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{ContentDisposition, DispositionParam, DispositionType};
|
||||
use crate::header::shared::Charset;
|
||||
use crate::header::{ExtendedValue, HeaderValue};
|
||||
use crate::http::header::Charset;
|
||||
use crate::http::header::{ExtendedValue, HeaderValue};
|
||||
|
||||
#[test]
|
||||
fn test_from_raw_basic() {
|
@ -1,7 +1,7 @@
|
||||
use crate::header::{QualityItem, CONTENT_LANGUAGE};
|
||||
use super::{QualityItem, CONTENT_LANGUAGE};
|
||||
use language_tags::LanguageTag;
|
||||
|
||||
header! {
|
||||
crate::header! {
|
||||
/// `Content-Language` header, defined in
|
||||
/// [RFC7231](https://tools.ietf.org/html/rfc7231#section-3.1.3.2)
|
||||
///
|
||||
@ -25,10 +25,10 @@ header! {
|
||||
///
|
||||
/// ```
|
||||
/// use language_tags::langtag;
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::{ContentLanguage, qitem};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{ContentLanguage, qitem};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// ContentLanguage(vec![
|
||||
/// qitem(langtag!(en)),
|
||||
@ -38,10 +38,10 @@ header! {
|
||||
///
|
||||
/// ```
|
||||
/// use language_tags::langtag;
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::{ContentLanguage, qitem};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{ContentLanguage, qitem};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// ContentLanguage(vec![
|
||||
/// qitem(langtag!(da)),
|
@ -2,11 +2,11 @@ use std::fmt::{self, Display, Write};
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::error::ParseError;
|
||||
use crate::header::{
|
||||
use super::{
|
||||
HeaderValue, IntoHeaderValue, InvalidHeaderValue, Writer, CONTENT_RANGE,
|
||||
};
|
||||
|
||||
header! {
|
||||
crate::header! {
|
||||
/// `Content-Range` header, defined in
|
||||
/// [RFC7233](http://tools.ietf.org/html/rfc7233#section-4.2)
|
||||
(ContentRange, CONTENT_RANGE) => [ContentRangeSpec]
|
@ -1,7 +1,7 @@
|
||||
use crate::header::CONTENT_TYPE;
|
||||
use super::CONTENT_TYPE;
|
||||
use mime::Mime;
|
||||
|
||||
header! {
|
||||
crate::header! {
|
||||
/// `Content-Type` header, defined in
|
||||
/// [RFC7231](http://tools.ietf.org/html/rfc7231#section-3.1.1.5)
|
||||
///
|
||||
@ -31,20 +31,20 @@ header! {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::ContentType;
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::ContentType;
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// ContentType::json()
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::ContentType;
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::ContentType;
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// ContentType(mime::TEXT_HTML)
|
||||
/// );
|
@ -1,7 +1,7 @@
|
||||
use crate::header::{HttpDate, DATE};
|
||||
use super::{HttpDate, DATE};
|
||||
use std::time::SystemTime;
|
||||
|
||||
header! {
|
||||
crate::header! {
|
||||
/// `Date` header, defined in [RFC7231](http://tools.ietf.org/html/rfc7231#section-7.1.1.2)
|
||||
///
|
||||
/// The `Date` header field represents the date and time at which the
|
||||
@ -21,10 +21,10 @@ header! {
|
||||
///
|
||||
/// ```
|
||||
/// use std::time::SystemTime;
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::Date;
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::Date;
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// Date(SystemTime::now().into())
|
||||
/// );
|
@ -1,7 +1,7 @@
|
||||
use std::fmt::{self, Display, Write};
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::header::{HeaderValue, IntoHeaderValue, InvalidHeaderValue, Writer};
|
||||
use super::{HeaderValue, IntoHeaderValue, InvalidHeaderValue, Writer};
|
||||
|
||||
/// check that each char in the slice is either:
|
||||
/// 1. `%x21`, or
|
@ -1,6 +1,6 @@
|
||||
use crate::header::{EntityTag, ETAG};
|
||||
use super::{EntityTag, ETAG};
|
||||
|
||||
header! {
|
||||
crate::header! {
|
||||
/// `ETag` header, defined in [RFC7232](http://tools.ietf.org/html/rfc7232#section-2.3)
|
||||
///
|
||||
/// The `ETag` header field in a response provides the current entity-tag
|
||||
@ -28,20 +28,20 @@ header! {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::{ETag, EntityTag};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{ETag, EntityTag};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// ETag(EntityTag::new(false, "xyzzy".to_owned()))
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::{ETag, EntityTag};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{ETag, EntityTag};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// ETag(EntityTag::new(true, "xyzzy".to_owned()))
|
||||
/// );
|
@ -1,6 +1,6 @@
|
||||
use crate::header::{HttpDate, EXPIRES};
|
||||
use super::{HttpDate, EXPIRES};
|
||||
|
||||
header! {
|
||||
crate::header! {
|
||||
/// `Expires` header, defined in [RFC7234](http://tools.ietf.org/html/rfc7234#section-5.3)
|
||||
///
|
||||
/// The `Expires` header field gives the date/time after which the
|
||||
@ -23,10 +23,10 @@ header! {
|
||||
///
|
||||
/// ```
|
||||
/// use std::time::{SystemTime, Duration};
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::Expires;
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::Expires;
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// let expiration = SystemTime::now() + Duration::from_secs(60 * 60 * 24);
|
||||
/// builder.insert_header(
|
||||
/// Expires(expiration.into())
|
@ -1,6 +1,6 @@
|
||||
use crate::header::{EntityTag, IF_MATCH};
|
||||
use super::{EntityTag, IF_MATCH};
|
||||
|
||||
header! {
|
||||
crate::header! {
|
||||
/// `If-Match` header, defined in
|
||||
/// [RFC7232](https://tools.ietf.org/html/rfc7232#section-3.1)
|
||||
///
|
||||
@ -30,18 +30,18 @@ header! {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::IfMatch;
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::IfMatch;
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(IfMatch::Any);
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::{IfMatch, EntityTag};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{IfMatch, EntityTag};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// IfMatch::Items(vec![
|
||||
/// EntityTag::new(false, "xyzzy".to_owned()),
|
@ -1,6 +1,6 @@
|
||||
use crate::header::{HttpDate, IF_MODIFIED_SINCE};
|
||||
use super::{HttpDate, IF_MODIFIED_SINCE};
|
||||
|
||||
header! {
|
||||
crate::header! {
|
||||
/// `If-Modified-Since` header, defined in
|
||||
/// [RFC7232](http://tools.ietf.org/html/rfc7232#section-3.3)
|
||||
///
|
||||
@ -23,10 +23,10 @@ header! {
|
||||
///
|
||||
/// ```
|
||||
/// use std::time::{SystemTime, Duration};
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::IfModifiedSince;
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::IfModifiedSince;
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// let modified = SystemTime::now() - Duration::from_secs(60 * 60 * 24);
|
||||
/// builder.insert_header(
|
||||
/// IfModifiedSince(modified.into())
|
@ -1,6 +1,6 @@
|
||||
use crate::header::{EntityTag, IF_NONE_MATCH};
|
||||
use super::{EntityTag, IF_NONE_MATCH};
|
||||
|
||||
header! {
|
||||
crate::header! {
|
||||
/// `If-None-Match` header, defined in
|
||||
/// [RFC7232](https://tools.ietf.org/html/rfc7232#section-3.2)
|
||||
///
|
||||
@ -32,18 +32,18 @@ header! {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::IfNoneMatch;
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::IfNoneMatch;
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(IfNoneMatch::Any);
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::{IfNoneMatch, EntityTag};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{IfNoneMatch, EntityTag};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// IfNoneMatch::Items(vec![
|
||||
/// EntityTag::new(false, "xyzzy".to_owned()),
|
||||
@ -66,8 +66,8 @@ header! {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::IfNoneMatch;
|
||||
use crate::header::{EntityTag, Header, IF_NONE_MATCH};
|
||||
use crate::test::TestRequest;
|
||||
use crate::http::header::{EntityTag, Header, IF_NONE_MATCH};
|
||||
use actix_http::test::TestRequest;
|
||||
|
||||
#[test]
|
||||
fn test_if_none_match() {
|
@ -1,8 +1,9 @@
|
||||
use std::fmt::{self, Display, Write};
|
||||
|
||||
use crate::http::header;
|
||||
use crate::error::ParseError;
|
||||
use crate::header::{
|
||||
self, from_one_raw_str, EntityTag, Header, HeaderName, HeaderValue, HttpDate,
|
||||
use super::{
|
||||
from_one_raw_str, EntityTag, Header, HeaderName, HeaderValue, HttpDate,
|
||||
IntoHeaderValue, InvalidHeaderValue, Writer,
|
||||
};
|
||||
use crate::HttpMessage;
|
||||
@ -36,10 +37,10 @@ use crate::HttpMessage;
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::{EntityTag, IfRange};
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::{EntityTag, IfRange};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// IfRange::EntityTag(
|
||||
/// EntityTag::new(false, "abc".to_owned())
|
||||
@ -49,9 +50,9 @@ use crate::HttpMessage;
|
||||
///
|
||||
/// ```
|
||||
/// use std::time::{Duration, SystemTime};
|
||||
/// use actix_http::{http::header::IfRange, Response};
|
||||
/// use actix_web::{http::header::IfRange, HttpResponse};
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// let fetched = SystemTime::now() - Duration::from_secs(60 * 60 * 24);
|
||||
/// builder.insert_header(
|
||||
/// IfRange::Date(fetched.into())
|
||||
@ -111,7 +112,7 @@ impl IntoHeaderValue for IfRange {
|
||||
#[cfg(test)]
|
||||
mod test_if_range {
|
||||
use super::IfRange as HeaderField;
|
||||
use crate::header::*;
|
||||
use crate::http::header::*;
|
||||
use std::str;
|
||||
|
||||
test_header!(test1, vec![b"Sat, 29 Oct 1994 19:43:31 GMT"]);
|
@ -1,6 +1,6 @@
|
||||
use crate::header::{HttpDate, IF_UNMODIFIED_SINCE};
|
||||
use super::{HttpDate, IF_UNMODIFIED_SINCE};
|
||||
|
||||
header! {
|
||||
crate::header! {
|
||||
/// `If-Unmodified-Since` header, defined in
|
||||
/// [RFC7232](http://tools.ietf.org/html/rfc7232#section-3.4)
|
||||
///
|
||||
@ -24,10 +24,10 @@ header! {
|
||||
///
|
||||
/// ```
|
||||
/// use std::time::{SystemTime, Duration};
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::IfUnmodifiedSince;
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::IfUnmodifiedSince;
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// let modified = SystemTime::now() - Duration::from_secs(60 * 60 * 24);
|
||||
/// builder.insert_header(
|
||||
/// IfUnmodifiedSince(modified.into())
|
@ -1,6 +1,6 @@
|
||||
use crate::header::{HttpDate, LAST_MODIFIED};
|
||||
use super::{HttpDate, LAST_MODIFIED};
|
||||
|
||||
header! {
|
||||
crate::header! {
|
||||
/// `Last-Modified` header, defined in
|
||||
/// [RFC7232](http://tools.ietf.org/html/rfc7232#section-2.2)
|
||||
///
|
||||
@ -23,10 +23,10 @@ header! {
|
||||
///
|
||||
/// ```
|
||||
/// use std::time::{SystemTime, Duration};
|
||||
/// use actix_http::Response;
|
||||
/// use actix_http::http::header::LastModified;
|
||||
/// use actix_web::HttpResponse;
|
||||
/// use actix_web::http::header::LastModified;
|
||||
///
|
||||
/// let mut builder = Response::Ok();
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// let modified = SystemTime::now() - Duration::from_secs(60 * 60 * 24);
|
||||
/// builder.insert_header(
|
||||
/// LastModified(modified.into())
|
@ -7,6 +7,10 @@
|
||||
//! is used, such as `ContentType(pub Mime)`.
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
|
||||
use std::fmt;
|
||||
use bytes::{BytesMut, Bytes};
|
||||
|
||||
pub use actix_http::http::header::*;
|
||||
pub use self::accept_charset::AcceptCharset;
|
||||
//pub use self::accept_encoding::AcceptEncoding;
|
||||
pub use self::accept::Accept;
|
||||
@ -18,7 +22,6 @@ pub use self::content_disposition::{
|
||||
};
|
||||
pub use self::content_language::ContentLanguage;
|
||||
pub use self::content_range::{ContentRange, ContentRangeSpec};
|
||||
pub use self::content_encoding::{ContentEncoding};
|
||||
pub use self::content_type::ContentType;
|
||||
pub use self::date::Date;
|
||||
pub use self::etag::ETag;
|
||||
@ -29,7 +32,39 @@ pub use self::if_none_match::IfNoneMatch;
|
||||
pub use self::if_range::IfRange;
|
||||
pub use self::if_unmodified_since::IfUnmodifiedSince;
|
||||
pub use self::last_modified::LastModified;
|
||||
pub use self::encoding::Encoding;
|
||||
pub use self::entity::EntityTag;
|
||||
//pub use self::range::{Range, ByteRangeSpec};
|
||||
pub(crate) use actix_http::http::header::{fmt_comma_delimited, from_comma_delimited, from_one_raw_str};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct Writer {
|
||||
buf: BytesMut,
|
||||
}
|
||||
|
||||
impl Writer {
|
||||
pub fn new() -> Writer {
|
||||
Writer::default()
|
||||
}
|
||||
|
||||
pub fn take(&mut self) -> Bytes {
|
||||
self.buf.split().freeze()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for Writer {
|
||||
#[inline]
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
self.buf.extend_from_slice(s.as_bytes());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
|
||||
fmt::write(self, args)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
@ -61,9 +96,9 @@ macro_rules! __hyper__tm {
|
||||
#[cfg(test)]
|
||||
mod $tm{
|
||||
use std::str;
|
||||
use http::Method;
|
||||
use actix_http::http::Method;
|
||||
use mime::*;
|
||||
use $crate::header::*;
|
||||
use $crate::http::header::*;
|
||||
use super::$id as HeaderField;
|
||||
$($tf)*
|
||||
}
|
||||
@ -77,8 +112,7 @@ macro_rules! test_header {
|
||||
($id:ident, $raw:expr) => {
|
||||
#[test]
|
||||
fn $id() {
|
||||
use super::*;
|
||||
use $crate::test;
|
||||
use actix_http::test;
|
||||
|
||||
let raw = $raw;
|
||||
let a: Vec<Vec<u8>> = raw.iter().map(|x| x.to_vec()).collect();
|
||||
@ -106,7 +140,7 @@ macro_rules! test_header {
|
||||
($id:ident, $raw:expr, $typed:expr) => {
|
||||
#[test]
|
||||
fn $id() {
|
||||
use $crate::test;
|
||||
use actix_http::test;
|
||||
|
||||
let a: Vec<Vec<u8>> = $raw.iter().map(|x| x.to_vec()).collect();
|
||||
let mut req = test::TestRequest::default();
|
||||
@ -134,6 +168,7 @@ macro_rules! test_header {
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! header {
|
||||
// $a:meta: Attributes associated with the header item (usually docs)
|
||||
@ -341,7 +376,6 @@ mod allow;
|
||||
mod cache_control;
|
||||
mod content_disposition;
|
||||
mod content_language;
|
||||
mod content_encoding;
|
||||
mod content_range;
|
||||
mod content_type;
|
||||
mod date;
|
||||
@ -353,3 +387,5 @@ mod if_none_match;
|
||||
mod if_range;
|
||||
mod if_unmodified_since;
|
||||
mod last_modified;
|
||||
mod encoding;
|
||||
mod entity;
|
@ -1,8 +1,8 @@
|
||||
use std::fmt::{self, Display};
|
||||
use std::str::FromStr;
|
||||
|
||||
use header::parsing::from_one_raw_str;
|
||||
use header::{Header, Raw};
|
||||
use super::parsing::from_one_raw_str;
|
||||
use super::{Header, Raw};
|
||||
|
||||
/// `Range` header, defined in [RFC7233](https://tools.ietf.org/html/rfc7233#section-3.1)
|
||||
///
|
2
src/http/mod.rs
Normal file
2
src/http/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod header;
|
||||
pub use actix_http::http::*;
|
@ -84,6 +84,7 @@ pub mod error;
|
||||
mod extract;
|
||||
pub mod guard;
|
||||
mod handler;
|
||||
pub mod http;
|
||||
mod info;
|
||||
pub mod middleware;
|
||||
mod request;
|
||||
@ -102,7 +103,7 @@ pub mod web;
|
||||
#[cfg(feature = "cookies")]
|
||||
pub use actix_http::cookie;
|
||||
pub use actix_http::Response as HttpResponse;
|
||||
pub use actix_http::{body, http, Error, HttpMessage, ResponseError, Result};
|
||||
pub use actix_http::{body, Error, HttpMessage, ResponseError, Result};
|
||||
pub use actix_rt as rt;
|
||||
pub use actix_web_codegen::*;
|
||||
|
||||
|
22
src/test.rs
22
src/test.rs
@ -8,8 +8,7 @@ use std::{fmt, net, thread, time};
|
||||
use actix_codec::{AsyncRead, AsyncWrite, Framed};
|
||||
#[cfg(feature = "cookies")]
|
||||
use actix_http::cookie::Cookie;
|
||||
use actix_http::http::header::{ContentType, HeaderMap, IntoHeaderPair};
|
||||
use actix_http::http::{Method, StatusCode, Uri, Version};
|
||||
use actix_http::http::{HeaderMap, Method, StatusCode, Uri, Version};
|
||||
use actix_http::test::TestRequest as HttpTestRequest;
|
||||
use actix_http::{ws, Extensions, HttpService, Request};
|
||||
use actix_router::{Path, ResourceDef, Url};
|
||||
@ -31,6 +30,7 @@ use crate::app_service::AppInitServiceState;
|
||||
use crate::config::AppConfig;
|
||||
use crate::data::Data;
|
||||
use crate::dev::{Body, MessageBody, Payload, Server};
|
||||
use crate::http::header::{ContentType, IntoHeaderPair};
|
||||
use crate::rmap::ResourceMap;
|
||||
use crate::service::{ServiceRequest, ServiceResponse};
|
||||
use crate::{Error, HttpRequest, HttpResponse};
|
||||
@ -162,7 +162,7 @@ where
|
||||
let mut resp = app
|
||||
.call(req)
|
||||
.await
|
||||
.unwrap_or_else(|_| panic!("read_response failed at application call"));
|
||||
.unwrap_or_else(|e| panic!("read_response failed at application call: {}", e));
|
||||
|
||||
let mut body = resp.take_body();
|
||||
let mut bytes = BytesMut::new();
|
||||
@ -254,8 +254,12 @@ where
|
||||
{
|
||||
let body = read_body(res).await;
|
||||
|
||||
serde_json::from_slice(&body)
|
||||
.unwrap_or_else(|e| panic!("read_response_json failed during deserialization: {}", e))
|
||||
serde_json::from_slice(&body).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"read_response_json failed during deserialization of body: {:?}, {}",
|
||||
body, e
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn load_stream<S>(mut stream: S) -> Result<Bytes, Error>
|
||||
@ -311,8 +315,12 @@ where
|
||||
{
|
||||
let body = read_response(app, req).await;
|
||||
|
||||
serde_json::from_slice(&body)
|
||||
.unwrap_or_else(|_| panic!("read_response_json failed during deserialization"))
|
||||
serde_json::from_slice(&body).unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"read_response_json failed during deserialization of body: {:?}",
|
||||
body
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Test `Request` builder.
|
||||
|
112
src/types/header.rs
Normal file
112
src/types/header.rs
Normal file
@ -0,0 +1,112 @@
|
||||
//! For header extractor helper documentation, see [`Header`](crate::types::Header).
|
||||
|
||||
use std::{fmt, ops};
|
||||
|
||||
use actix_utils::future::{err, ok, Ready};
|
||||
|
||||
use crate::{
|
||||
dev::Payload, error::ParseError, extract::FromRequest, http::header::Header as ParseHeader,
|
||||
HttpRequest,
|
||||
};
|
||||
|
||||
/// Extract typed headers from the request.
|
||||
///
|
||||
/// To extract a header, the inner type `T` must implement the
|
||||
/// [`Header`](crate::http::header::Header) trait.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use actix_web::{get, web, http::header};
|
||||
///
|
||||
/// #[get("/")]
|
||||
/// async fn index(date: web::Header<header::Date>) -> String {
|
||||
/// format!("Request was sent at {}", date.to_string())
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Header<T>(pub T);
|
||||
|
||||
impl<T> Header<T> {
|
||||
/// Unwrap into the inner `T` value.
|
||||
pub fn into_inner(self) -> T {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ops::Deref for Header<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ops::DerefMut for Header<T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for Header<T>
|
||||
where
|
||||
T: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Header: {:?}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Display for Header<T>
|
||||
where
|
||||
T: fmt::Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromRequest for Header<T>
|
||||
where
|
||||
T: ParseHeader,
|
||||
{
|
||||
type Error = ParseError;
|
||||
type Future = Ready<Result<Self, Self::Error>>;
|
||||
type Config = ();
|
||||
|
||||
#[inline]
|
||||
fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
|
||||
match ParseHeader::parse(req) {
|
||||
Ok(header) => ok(Header(header)),
|
||||
Err(e) => err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::{header, Method};
|
||||
use crate::test::TestRequest;
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_header_extract() {
|
||||
let (req, mut pl) = TestRequest::default()
|
||||
.insert_header((header::CONTENT_TYPE, mime::APPLICATION_JSON))
|
||||
.insert_header((header::ALLOW, header::Allow(vec![Method::GET])))
|
||||
.to_http_parts();
|
||||
|
||||
let s = Header::<header::ContentType>::from_request(&req, &mut pl)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(s.into_inner().0, mime::APPLICATION_JSON);
|
||||
|
||||
let s = Header::<header::Allow>::from_request(&req, &mut pl)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(s.into_inner().0, vec![Method::GET]);
|
||||
|
||||
assert!(Header::<header::Date>::from_request(&req, &mut pl)
|
||||
.await
|
||||
.is_err());
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
// TODO: review visibility
|
||||
mod either;
|
||||
pub(crate) mod form;
|
||||
mod header;
|
||||
pub(crate) mod json;
|
||||
mod path;
|
||||
pub(crate) mod payload;
|
||||
@ -11,6 +12,7 @@ pub(crate) mod readlines;
|
||||
|
||||
pub use self::either::{Either, EitherExtractError};
|
||||
pub use self::form::{Form, FormConfig};
|
||||
pub use self::header::Header;
|
||||
pub use self::json::{Json, JsonConfig};
|
||||
pub use self::path::{Path, PathConfig};
|
||||
pub use self::payload::{Payload, PayloadConfig};
|
||||
|
Loading…
Reference in New Issue
Block a user