Merge branch 'master' into payload-read-helpers

This commit is contained in:
Rob Ede 2023-07-22 01:39:14 +01:00 committed by GitHub
commit d1854b316e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 265 additions and 211 deletions

View File

@ -12,7 +12,7 @@ pub use self::{decoder::Decoder, encoder::Encoder};
/// Special-purpose writer for streaming (de-)compression. /// Special-purpose writer for streaming (de-)compression.
/// ///
/// Pre-allocates 8KiB of capacity. /// Pre-allocates 8KiB of capacity.
pub(self) struct Writer { struct Writer {
buf: BytesMut, buf: BytesMut,
} }

View File

@ -50,7 +50,7 @@ mod tests {
#[test] #[test]
fn test_apply_mask() { fn test_apply_mask() {
let mask = [0x6d, 0xb6, 0xb2, 0x80]; let mask = [0x6d, 0xb6, 0xb2, 0x80];
let unmasked = vec![ let unmasked = [
0xf3, 0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x82, 0xff, 0xfe, 0x00, 0x17, 0x74, 0xf9, 0xf3, 0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x82, 0xff, 0xfe, 0x00, 0x17, 0x74, 0xf9,
0x12, 0x03, 0x12, 0x03,
]; ];

View File

@ -1,5 +1,3 @@
#![allow(clippy::uninlined_format_args)]
use std::{ use std::{
convert::Infallible, convert::Infallible,
io::{Read, Write}, io::{Read, Write},
@ -139,7 +137,7 @@ async fn expect_continue_h1() {
#[actix_rt::test] #[actix_rt::test]
async fn chunked_payload() { async fn chunked_payload() {
let chunk_sizes = vec![32768, 32, 32768]; let chunk_sizes = [32768, 32, 32768];
let total_size: usize = chunk_sizes.iter().sum(); let total_size: usize = chunk_sizes.iter().sum();
let mut srv = test_server(|| { let mut srv = test_server(|| {
@ -402,7 +400,7 @@ async fn content_length() {
let mut srv = test_server(|| { let mut srv = test_server(|| {
HttpService::build() HttpService::build()
.h1(|req: Request| { .h1(|req: Request| {
let indx: usize = req.uri().path()[1..].parse().unwrap(); let idx: usize = req.uri().path()[1..].parse().unwrap();
let statuses = [ let statuses = [
StatusCode::NO_CONTENT, StatusCode::NO_CONTENT,
StatusCode::CONTINUE, StatusCode::CONTINUE,
@ -411,7 +409,7 @@ async fn content_length() {
StatusCode::OK, StatusCode::OK,
StatusCode::NOT_FOUND, StatusCode::NOT_FOUND,
]; ];
ok::<_, Infallible>(Response::new(statuses[indx])) ok::<_, Infallible>(Response::new(statuses[idx]))
}) })
.tcp() .tcp()
}) })

View File

@ -2,6 +2,7 @@
## Unreleased ## Unreleased
- Update `syn` dependency to `2`.
- Minimum supported Rust version (MSRV) is now 1.65 due to transitive `time` dependency. - Minimum supported Rust version (MSRV) is now 1.65 due to transitive `time` dependency.
## 0.6.0 - 2023-02-26 ## 0.6.0 - 2023-02-26

View File

@ -17,11 +17,11 @@ all-features = true
proc-macro = true proc-macro = true
[dependencies] [dependencies]
darling = "0.14" darling = "0.20"
parse-size = "1" parse-size = "1"
proc-macro2 = "1" proc-macro2 = "1"
quote = "1" quote = "1"
syn = "1" syn = "2"
[dev-dependencies] [dev-dependencies]
actix-multipart = "0.6" actix-multipart = "0.6"

View File

@ -252,7 +252,7 @@ impl ResourceDef {
/// Multi-pattern resources can be constructed by providing a slice (or vec) of patterns. /// Multi-pattern resources can be constructed by providing a slice (or vec) of patterns.
/// ///
/// # Panics /// # Panics
/// Panics if path pattern is malformed. /// Panics if any path patterns are malformed.
/// ///
/// # Examples /// # Examples
/// ``` /// ```
@ -838,6 +838,7 @@ impl ResourceDef {
fn construct<T: IntoPatterns>(paths: T, is_prefix: bool) -> Self { fn construct<T: IntoPatterns>(paths: T, is_prefix: bool) -> Self {
let patterns = paths.patterns(); let patterns = paths.patterns();
let (pat_type, segments) = match &patterns { let (pat_type, segments) = match &patterns {
Patterns::Single(pattern) => ResourceDef::parse(pattern, is_prefix, false), Patterns::Single(pattern) => ResourceDef::parse(pattern, is_prefix, false),
@ -1528,7 +1529,12 @@ mod tests {
assert!(!resource.resource_path_from_iter(&mut s, &mut ["item"].iter())); assert!(!resource.resource_path_from_iter(&mut s, &mut ["item"].iter()));
let mut s = String::new(); let mut s = String::new();
assert!(resource.resource_path_from_iter(&mut s, &mut vec!["item", "item2"].iter()));
assert!(resource.resource_path_from_iter(
&mut s,
#[allow(clippy::useless_vec)]
&mut vec!["item", "item2"].iter()
));
assert_eq!(s, "/user/item/item2/"); assert_eq!(s, "/user/item/item2/");
} }

View File

@ -2,6 +2,7 @@
## Unreleased - 2023-xx-xx ## Unreleased - 2023-xx-xx
- Update `syn` dependency to `2`.
- Minimum supported Rust version (MSRV) is now 1.65 due to transitive `time` dependency. - Minimum supported Rust version (MSRV) is now 1.65 due to transitive `time` dependency.
## 4.2.0 - 2023-02-26 ## 4.2.0 - 2023-02-26

View File

@ -18,10 +18,10 @@ proc-macro = true
actix-router = "0.5" actix-router = "0.5"
proc-macro2 = "1" proc-macro2 = "1"
quote = "1" quote = "1"
syn = { version = "1", features = ["full", "extra-traits"] } syn = { version = "2", features = ["full", "extra-traits"] }
[dev-dependencies] [dev-dependencies]
actix-macros = "0.2.3" actix-macros = "0.2.4"
actix-rt = "2.2" actix-rt = "2.2"
actix-test = "0.1" actix-test = "0.1"
actix-utils = "3" actix-utils = "3"

View File

@ -4,7 +4,54 @@ use actix_router::ResourceDef;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use proc_macro2::{Span, TokenStream as TokenStream2}; use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::{quote, ToTokens, TokenStreamExt}; use quote::{quote, ToTokens, TokenStreamExt};
use syn::{parse_macro_input, AttributeArgs, Ident, LitStr, Meta, NestedMeta, Path}; use syn::{punctuated::Punctuated, Ident, LitStr, Path, Token};
#[derive(Debug)]
pub struct RouteArgs {
path: syn::LitStr,
options: Punctuated<syn::MetaNameValue, Token![,]>,
}
impl syn::parse::Parse for RouteArgs {
fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
// path to match: "/foo"
let path = input.parse::<syn::LitStr>().map_err(|mut err| {
err.combine(syn::Error::new(
err.span(),
r#"invalid service definition, expected #[<method>("<path>")]"#,
));
err
})?;
// verify that path pattern is valid
let _ = ResourceDef::new(path.value());
// if there's no comma, assume that no options are provided
if !input.peek(Token![,]) {
return Ok(Self {
path,
options: Punctuated::new(),
});
}
// advance past comma separator
input.parse::<Token![,]>()?;
// if next char is a literal, assume that it is a string and show multi-path error
if input.cursor().literal().is_some() {
return Err(syn::Error::new(
Span::call_site(),
r#"Multiple paths specified! There should be only one."#,
));
}
// zero or more options: name = "foo"
let options = input.parse_terminated(syn::MetaNameValue::parse, Token![,])?;
Ok(Self { path, options })
}
}
macro_rules! standard_method_type { macro_rules! standard_method_type {
( (
@ -182,70 +229,54 @@ struct Args {
} }
impl Args { impl Args {
fn new(args: AttributeArgs, method: Option<MethodType>) -> syn::Result<Self> { fn new(args: RouteArgs, method: Option<MethodType>) -> syn::Result<Self> {
let mut path = None;
let mut resource_name = None; let mut resource_name = None;
let mut guards = Vec::new(); let mut guards = Vec::new();
let mut wrappers = Vec::new(); let mut wrappers = Vec::new();
let mut methods = HashSet::new(); let mut methods = HashSet::new();
if args.is_empty() {
return Err(syn::Error::new(
Span::call_site(),
format!(
r#"invalid service definition, expected #[{}("<path>")]"#,
method
.map_or("route", |it| it.as_str())
.to_ascii_lowercase()
),
));
}
let is_route_macro = method.is_none(); let is_route_macro = method.is_none();
if let Some(method) = method { if let Some(method) = method {
methods.insert(MethodTypeExt::Standard(method)); methods.insert(MethodTypeExt::Standard(method));
} }
for arg in args { for nv in args.options {
match arg {
NestedMeta::Lit(syn::Lit::Str(lit)) => match path {
None => {
let _ = ResourceDef::new(lit.value());
path = Some(lit);
}
_ => {
return Err(syn::Error::new_spanned(
lit,
"Multiple paths specified! Should be only one!",
));
}
},
NestedMeta::Meta(syn::Meta::NameValue(nv)) => {
if nv.path.is_ident("name") { if nv.path.is_ident("name") {
if let syn::Lit::Str(lit) = nv.lit { if let syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(lit),
..
}) = nv.value
{
resource_name = Some(lit); resource_name = Some(lit);
} else { } else {
return Err(syn::Error::new_spanned( return Err(syn::Error::new_spanned(
nv.lit, nv.value,
"Attribute name expects literal string!", "Attribute name expects literal string!",
)); ));
} }
} else if nv.path.is_ident("guard") { } else if nv.path.is_ident("guard") {
if let syn::Lit::Str(lit) = nv.lit { if let syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(lit),
..
}) = nv.value
{
guards.push(lit.parse::<Path>()?); guards.push(lit.parse::<Path>()?);
} else { } else {
return Err(syn::Error::new_spanned( return Err(syn::Error::new_spanned(
nv.lit, nv.value,
"Attribute guard expects literal string!", "Attribute guard expects literal string!",
)); ));
} }
} else if nv.path.is_ident("wrap") { } else if nv.path.is_ident("wrap") {
if let syn::Lit::Str(lit) = nv.lit { if let syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(lit),
..
}) = nv.value
{
wrappers.push(lit.parse()?); wrappers.push(lit.parse()?);
} else { } else {
return Err(syn::Error::new_spanned( return Err(syn::Error::new_spanned(
nv.lit, nv.value,
"Attribute wrap expects type", "Attribute wrap expects type",
)); ));
} }
@ -255,19 +286,20 @@ impl Args {
&nv, &nv,
"HTTP method forbidden here. To handle multiple methods, use `route` instead", "HTTP method forbidden here. To handle multiple methods, use `route` instead",
)); ));
} else if let syn::Lit::Str(ref lit) = nv.lit { } else if let syn::Expr::Lit(syn::ExprLit {
if !methods.insert(MethodTypeExt::try_from(lit)?) { lit: syn::Lit::Str(lit),
..
}) = nv.value.clone()
{
if !methods.insert(MethodTypeExt::try_from(&lit)?) {
return Err(syn::Error::new_spanned( return Err(syn::Error::new_spanned(
&nv.lit, nv.value,
format!( format!("HTTP method defined more than once: `{}`", lit.value()),
"HTTP method defined more than once: `{}`",
lit.value()
),
)); ));
} }
} else { } else {
return Err(syn::Error::new_spanned( return Err(syn::Error::new_spanned(
nv.lit, nv.value,
"Attribute method expects literal string!", "Attribute method expects literal string!",
)); ));
} }
@ -279,14 +311,8 @@ impl Args {
} }
} }
arg => {
return Err(syn::Error::new_spanned(arg, "Unknown attribute."));
}
}
}
Ok(Args { Ok(Args {
path: path.unwrap(), path: args.path,
resource_name, resource_name,
guards, guards,
wrappers, wrappers,
@ -312,11 +338,7 @@ pub struct Route {
} }
impl Route { impl Route {
pub fn new( pub fn new(args: RouteArgs, ast: syn::ItemFn, method: Option<MethodType>) -> syn::Result<Self> {
args: AttributeArgs,
ast: syn::ItemFn,
method: Option<MethodType>,
) -> syn::Result<Self> {
let name = ast.sig.ident.clone(); let name = ast.sig.ident.clone();
// Try and pull out the doc comments so that we can reapply them to the generated struct. // Try and pull out the doc comments so that we can reapply them to the generated struct.
@ -324,7 +346,7 @@ impl Route {
let doc_attributes = ast let doc_attributes = ast
.attrs .attrs
.iter() .iter()
.filter(|attr| attr.path.is_ident("doc")) .filter(|attr| attr.path().is_ident("doc"))
.cloned() .cloned()
.collect(); .collect();
@ -360,7 +382,7 @@ impl Route {
let doc_attributes = ast let doc_attributes = ast
.attrs .attrs
.iter() .iter()
.filter(|attr| attr.path.is_ident("doc")) .filter(|attr| attr.path().is_ident("doc"))
.cloned() .cloned()
.collect(); .collect();
@ -455,7 +477,11 @@ pub(crate) fn with_method(
args: TokenStream, args: TokenStream,
input: TokenStream, input: TokenStream,
) -> TokenStream { ) -> TokenStream {
let args = parse_macro_input!(args as syn::AttributeArgs); let args = match syn::parse(args) {
Ok(args) => args,
// on parse error, make IDEs happy; see fn docs
Err(err) => return input_and_compile_error(input, err),
};
let ast = match syn::parse::<syn::ItemFn>(input.clone()) { let ast = match syn::parse::<syn::ItemFn>(input.clone()) {
Ok(ast) => ast, Ok(ast) => ast,
@ -480,7 +506,7 @@ pub(crate) fn with_methods(input: TokenStream) -> TokenStream {
let (methods, others) = ast let (methods, others) = ast
.attrs .attrs
.into_iter() .into_iter()
.map(|attr| match MethodType::from_path(&attr.path) { .map(|attr| match MethodType::from_path(attr.path()) {
Ok(method) => Ok((method, attr)), Ok(method) => Ok((method, attr)),
Err(_) => Err(attr), Err(_) => Err(attr),
}) })
@ -492,13 +518,8 @@ pub(crate) fn with_methods(input: TokenStream) -> TokenStream {
.into_iter() .into_iter()
.map(Result::unwrap) .map(Result::unwrap)
.map(|(method, attr)| { .map(|(method, attr)| {
attr.parse_meta().and_then(|args| { attr.parse_args()
if let Meta::List(args) = args { .and_then(|args| Args::new(args, Some(method)))
Args::new(args.nested.into_iter().collect(), Some(method))
} else {
Err(syn::Error::new_spanned(attr, "Invalid input for macro"))
}
})
}) })
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()
{ {

View File

@ -1,4 +1,4 @@
error: invalid service definition, expected #[get("<path>")] error: unexpected end of input, expected string literal
--> tests/trybuild/routes-missing-args-fail.rs:4:1 --> tests/trybuild/routes-missing-args-fail.rs:4:1
| |
4 | #[get] 4 | #[get]
@ -6,11 +6,19 @@ error: invalid service definition, expected #[get("<path>")]
| |
= note: this error originates in the attribute macro `get` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the attribute macro `get` (in Nightly builds, run with -Z macro-backtrace for more info)
error: Invalid input for macro error: invalid service definition, expected #[<method>("<path>")]
--> tests/trybuild/routes-missing-args-fail.rs:4:1 --> tests/trybuild/routes-missing-args-fail.rs:4:1
| |
4 | #[get] 4 | #[get]
| ^^^^^^ | ^^^^^^
|
= note: this error originates in the attribute macro `get` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected attribute arguments in parentheses: #[get(...)]
--> tests/trybuild/routes-missing-args-fail.rs:4:3
|
4 | #[get]
| ^^^
error[E0277]: the trait bound `fn() -> impl std::future::Future<Output = String> {index}: HttpServiceFactory` is not satisfied error[E0277]: the trait bound `fn() -> impl std::future::Future<Output = String> {index}: HttpServiceFactory` is not satisfied
--> tests/trybuild/routes-missing-args-fail.rs:13:55 --> tests/trybuild/routes-missing-args-fail.rs:13:55

View File

@ -1,26 +1,42 @@
error: Unknown attribute. error: expected `=`
--> $DIR/simple-fail.rs:3:15 --> $DIR/simple-fail.rs:3:1
| |
3 | #[get("/one", other)] 3 | #[get("/one", other)]
| ^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the attribute macro `get` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected identifier or literal error: expected string literal
--> $DIR/simple-fail.rs:8:8 --> $DIR/simple-fail.rs:8:8
| |
8 | #[post(/two)] 8 | #[post(/two)]
| ^ | ^
error: Unknown attribute. error: invalid service definition, expected #[<method>("<path>")]
--> $DIR/simple-fail.rs:8:8
|
8 | #[post(/two)]
| ^
error: expected string literal
--> $DIR/simple-fail.rs:15:9 --> $DIR/simple-fail.rs:15:9
| |
15 | #[patch(PATCH_PATH)] 15 | #[patch(PATCH_PATH)]
| ^^^^^^^^^^ | ^^^^^^^^^^
error: Multiple paths specified! Should be only one! error: invalid service definition, expected #[<method>("<path>")]
--> $DIR/simple-fail.rs:20:19 --> $DIR/simple-fail.rs:15:9
|
15 | #[patch(PATCH_PATH)]
| ^^^^^^^^^^
error: Multiple paths specified! There should be only one.
--> $DIR/simple-fail.rs:20:1
| |
20 | #[delete("/four", "/five")] 20 | #[delete("/four", "/five")]
| ^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the attribute macro `delete` (in Nightly builds, run with -Z macro-backtrace for more info)
error: HTTP method forbidden here. To handle multiple methods, use `route` instead error: HTTP method forbidden here. To handle multiple methods, use `route` instead
--> $DIR/simple-fail.rs:25:19 --> $DIR/simple-fail.rs:25:19

View File

@ -7,6 +7,7 @@
- Add `HttpServer::{bind, listen}_auto_h2c()` method behind new `http2` crate feature. - Add `HttpServer::{bind, listen}_auto_h2c()` method behind new `http2` crate feature.
- Add `Resource::{get, post, etc...}` methods for more concisely adding routes that don't need additional guards. - Add `Resource::{get, post, etc...}` methods for more concisely adding routes that don't need additional guards.
- Add `web::Payload::to_bytes[_limited]()` helper methods. - Add `web::Payload::to_bytes[_limited]()` helper methods.
- Add missing constructors on `HttpResponse` for several status codes.
### Changed ### Changed

View File

@ -78,7 +78,7 @@ common_header! {
// Tests from the RFC // Tests from the RFC
crate::http::header::common_header_test!( crate::http::header::common_header_test!(
test1, test1,
vec![b"audio/*; q=0.2, audio/basic"], [b"audio/*; q=0.2, audio/basic"],
Some(Accept(vec![ Some(Accept(vec![
QualityItem::new("audio/*".parse().unwrap(), q(0.2)), QualityItem::new("audio/*".parse().unwrap(), q(0.2)),
QualityItem::max("audio/basic".parse().unwrap()), QualityItem::max("audio/basic".parse().unwrap()),
@ -86,7 +86,7 @@ common_header! {
crate::http::header::common_header_test!( crate::http::header::common_header_test!(
test2, test2,
vec![b"text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c"], [b"text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c"],
Some(Accept(vec![ Some(Accept(vec![
QualityItem::new(mime::TEXT_PLAIN, q(0.5)), QualityItem::new(mime::TEXT_PLAIN, q(0.5)),
QualityItem::max(mime::TEXT_HTML), QualityItem::max(mime::TEXT_HTML),
@ -99,13 +99,13 @@ common_header! {
// Custom tests // Custom tests
crate::http::header::common_header_test!( crate::http::header::common_header_test!(
test3, test3,
vec![b"text/plain; charset=utf-8"], [b"text/plain; charset=utf-8"],
Some(Accept(vec![ Some(Accept(vec![
QualityItem::max(mime::TEXT_PLAIN_UTF_8), QualityItem::max(mime::TEXT_PLAIN_UTF_8),
]))); ])));
crate::http::header::common_header_test!( crate::http::header::common_header_test!(
test4, test4,
vec![b"text/plain; charset=utf-8; q=0.5"], [b"text/plain; charset=utf-8; q=0.5"],
Some(Accept(vec![ Some(Accept(vec![
QualityItem::new(mime::TEXT_PLAIN_UTF_8, q(0.5)), QualityItem::new(mime::TEXT_PLAIN_UTF_8, q(0.5)),
]))); ])));

View File

@ -57,6 +57,6 @@ common_header! {
test_parse_and_format { test_parse_and_format {
// Test case from RFC // Test case from RFC
common_header_test!(test1, vec![b"iso-8859-5, unicode-1-1;q=0.8"]); common_header_test!(test1, [b"iso-8859-5, unicode-1-1;q=0.8"]);
} }
} }

View File

@ -50,31 +50,31 @@ common_header! {
(AcceptEncoding, header::ACCEPT_ENCODING) => (QualityItem<Preference<Encoding>>)* (AcceptEncoding, header::ACCEPT_ENCODING) => (QualityItem<Preference<Encoding>>)*
test_parse_and_format { test_parse_and_format {
common_header_test!(no_headers, vec![b""; 0], Some(AcceptEncoding(vec![]))); common_header_test!(no_headers, [b""; 0], Some(AcceptEncoding(vec![])));
common_header_test!(empty_header, vec![b""; 1], Some(AcceptEncoding(vec![]))); common_header_test!(empty_header, [b""; 1], Some(AcceptEncoding(vec![])));
common_header_test!( common_header_test!(
order_of_appearance, order_of_appearance,
vec![b"br, gzip"], [b"br, gzip"],
Some(AcceptEncoding(vec![ Some(AcceptEncoding(vec![
QualityItem::max(Preference::Specific(Encoding::brotli())), QualityItem::max(Preference::Specific(Encoding::brotli())),
QualityItem::max(Preference::Specific(Encoding::gzip())), QualityItem::max(Preference::Specific(Encoding::gzip())),
])) ]))
); );
common_header_test!(any, vec![b"*"], Some(AcceptEncoding(vec![ common_header_test!(any, [b"*"], Some(AcceptEncoding(vec![
QualityItem::max(Preference::Any), QualityItem::max(Preference::Any),
]))); ])));
// Note: Removed quality 1 from gzip // Note: Removed quality 1 from gzip
common_header_test!(implicit_quality, vec![b"gzip, identity; q=0.5, *;q=0"]); common_header_test!(implicit_quality, [b"gzip, identity; q=0.5, *;q=0"]);
// Note: Removed quality 1 from gzip // Note: Removed quality 1 from gzip
common_header_test!(implicit_quality_out_of_order, vec![b"compress;q=0.5, gzip"]); common_header_test!(implicit_quality_out_of_order, [b"compress;q=0.5, gzip"]);
common_header_test!( common_header_test!(
only_gzip_no_identity, only_gzip_no_identity,
vec![b"gzip, *; q=0"], [b"gzip, *; q=0"],
Some(AcceptEncoding(vec![ Some(AcceptEncoding(vec![
QualityItem::max(Preference::Specific(Encoding::gzip())), QualityItem::max(Preference::Specific(Encoding::gzip())),
QualityItem::zero(Preference::Any), QualityItem::zero(Preference::Any),

View File

@ -58,19 +58,19 @@ common_header! {
(AcceptLanguage, header::ACCEPT_LANGUAGE) => (QualityItem<Preference<LanguageTag>>)* (AcceptLanguage, header::ACCEPT_LANGUAGE) => (QualityItem<Preference<LanguageTag>>)*
test_parse_and_format { test_parse_and_format {
common_header_test!(no_headers, vec![b""; 0], Some(AcceptLanguage(vec![]))); common_header_test!(no_headers, [b""; 0], Some(AcceptLanguage(vec![])));
common_header_test!(empty_header, vec![b""; 1], Some(AcceptLanguage(vec![]))); common_header_test!(empty_header, [b""; 1], Some(AcceptLanguage(vec![])));
common_header_test!( common_header_test!(
example_from_rfc, example_from_rfc,
vec![b"da, en-gb;q=0.8, en;q=0.7"] [b"da, en-gb;q=0.8, en;q=0.7"]
); );
common_header_test!( common_header_test!(
not_ordered_by_weight, not_ordered_by_weight,
vec![b"en-US, en; q=0.5, fr"], [b"en-US, en; q=0.5, fr"],
Some(AcceptLanguage(vec![ Some(AcceptLanguage(vec![
QualityItem::max("en-US".parse().unwrap()), QualityItem::max("en-US".parse().unwrap()),
QualityItem::new("en".parse().unwrap(), q(0.5)), QualityItem::new("en".parse().unwrap(), q(0.5)),
@ -80,7 +80,7 @@ common_header! {
common_header_test!( common_header_test!(
has_wildcard, has_wildcard,
vec![b"fr-CH, fr; q=0.9, en; q=0.8, de; q=0.7, *; q=0.5"], [b"fr-CH, fr; q=0.9, en; q=0.8, de; q=0.7, *; q=0.5"],
Some(AcceptLanguage(vec![ Some(AcceptLanguage(vec![
QualityItem::max("fr-CH".parse().unwrap()), QualityItem::max("fr-CH".parse().unwrap()),
QualityItem::new("fr".parse().unwrap(), q(0.9)), QualityItem::new("fr".parse().unwrap(), q(0.9)),
@ -137,7 +137,7 @@ impl AcceptLanguage {
b.quality.cmp(&a.quality) b.quality.cmp(&a.quality)
}); });
types.into_iter().map(|qitem| qitem.item).collect() types.into_iter().map(|q_item| q_item.item).collect()
} }
} }

View File

@ -51,12 +51,12 @@ crate::http::header::common_header! {
// From the RFC // From the RFC
crate::http::header::common_header_test!( crate::http::header::common_header_test!(
test1, test1,
vec![b"GET, HEAD, PUT"], [b"GET, HEAD, PUT"],
Some(HeaderField(vec![Method::GET, Method::HEAD, Method::PUT]))); Some(HeaderField(vec![Method::GET, Method::HEAD, Method::PUT])));
// Own tests // Own tests
crate::http::header::common_header_test!( crate::http::header::common_header_test!(
test2, test2,
vec![b"OPTIONS, GET, PUT, POST, DELETE, HEAD, TRACE, CONNECT, PATCH"], [b"OPTIONS, GET, PUT, POST, DELETE, HEAD, TRACE, CONNECT, PATCH"],
Some(HeaderField(vec![ Some(HeaderField(vec![
Method::OPTIONS, Method::OPTIONS,
Method::GET, Method::GET,
@ -69,7 +69,7 @@ crate::http::header::common_header! {
Method::PATCH]))); Method::PATCH])));
crate::http::header::common_header_test!( crate::http::header::common_header_test!(
test3, test3,
vec![b""], [b""],
Some(HeaderField(Vec::<Method>::new()))); Some(HeaderField(Vec::<Method>::new())));
} }
} }

View File

@ -47,13 +47,13 @@ common_header! {
(CacheControl, header::CACHE_CONTROL) => (CacheDirective)+ (CacheControl, header::CACHE_CONTROL) => (CacheDirective)+
test_parse_and_format { test_parse_and_format {
common_header_test!(no_headers, vec![b""; 0], None); common_header_test!(no_headers, [b""; 0], None);
common_header_test!(empty_header, vec![b""; 1], None); common_header_test!(empty_header, [b""; 1], None);
common_header_test!(bad_syntax, vec![b"foo="], None); common_header_test!(bad_syntax, [b"foo="], None);
common_header_test!( common_header_test!(
multiple_headers, multiple_headers,
vec![&b"no-cache"[..], &b"private"[..]], [&b"no-cache"[..], &b"private"[..]],
Some(CacheControl(vec![ Some(CacheControl(vec![
CacheDirective::NoCache, CacheDirective::NoCache,
CacheDirective::Private, CacheDirective::Private,
@ -62,7 +62,7 @@ common_header! {
common_header_test!( common_header_test!(
argument, argument,
vec![b"max-age=100, private"], [b"max-age=100, private"],
Some(CacheControl(vec![ Some(CacheControl(vec![
CacheDirective::MaxAge(100), CacheDirective::MaxAge(100),
CacheDirective::Private, CacheDirective::Private,
@ -71,7 +71,7 @@ common_header! {
common_header_test!( common_header_test!(
extension, extension,
vec![b"foo, bar=baz"], [b"foo, bar=baz"],
Some(CacheControl(vec![ Some(CacheControl(vec![
CacheDirective::Extension("foo".to_owned(), None), CacheDirective::Extension("foo".to_owned(), None),
CacheDirective::Extension("bar".to_owned(), Some("baz".to_owned())), CacheDirective::Extension("bar".to_owned(), Some("baz".to_owned())),

View File

@ -48,7 +48,7 @@ common_header! {
(ContentLanguage, CONTENT_LANGUAGE) => (QualityItem<LanguageTag>)+ (ContentLanguage, CONTENT_LANGUAGE) => (QualityItem<LanguageTag>)+
test_parse_and_format { test_parse_and_format {
crate::http::header::common_header_test!(test1, vec![b"da"]); crate::http::header::common_header_test!(test1, [b"da"]);
crate::http::header::common_header_test!(test2, vec![b"mi, en"]); crate::http::header::common_header_test!(test2, [b"mi, en"]);
} }
} }

View File

@ -13,59 +13,59 @@ crate::http::header::common_header! {
test_parse_and_format { test_parse_and_format {
crate::http::header::common_header_test!(test_bytes, crate::http::header::common_header_test!(test_bytes,
vec![b"bytes 0-499/500"], [b"bytes 0-499/500"],
Some(ContentRange(ContentRangeSpec::Bytes { Some(ContentRange(ContentRangeSpec::Bytes {
range: Some((0, 499)), range: Some((0, 499)),
instance_length: Some(500) instance_length: Some(500)
}))); })));
crate::http::header::common_header_test!(test_bytes_unknown_len, crate::http::header::common_header_test!(test_bytes_unknown_len,
vec![b"bytes 0-499/*"], [b"bytes 0-499/*"],
Some(ContentRange(ContentRangeSpec::Bytes { Some(ContentRange(ContentRangeSpec::Bytes {
range: Some((0, 499)), range: Some((0, 499)),
instance_length: None instance_length: None
}))); })));
crate::http::header::common_header_test!(test_bytes_unknown_range, crate::http::header::common_header_test!(test_bytes_unknown_range,
vec![b"bytes */500"], [b"bytes */500"],
Some(ContentRange(ContentRangeSpec::Bytes { Some(ContentRange(ContentRangeSpec::Bytes {
range: None, range: None,
instance_length: Some(500) instance_length: Some(500)
}))); })));
crate::http::header::common_header_test!(test_unregistered, crate::http::header::common_header_test!(test_unregistered,
vec![b"seconds 1-2"], [b"seconds 1-2"],
Some(ContentRange(ContentRangeSpec::Unregistered { Some(ContentRange(ContentRangeSpec::Unregistered {
unit: "seconds".to_owned(), unit: "seconds".to_owned(),
resp: "1-2".to_owned() resp: "1-2".to_owned()
}))); })));
crate::http::header::common_header_test!(test_no_len, crate::http::header::common_header_test!(test_no_len,
vec![b"bytes 0-499"], [b"bytes 0-499"],
None::<ContentRange>); None::<ContentRange>);
crate::http::header::common_header_test!(test_only_unit, crate::http::header::common_header_test!(test_only_unit,
vec![b"bytes"], [b"bytes"],
None::<ContentRange>); None::<ContentRange>);
crate::http::header::common_header_test!(test_end_less_than_start, crate::http::header::common_header_test!(test_end_less_than_start,
vec![b"bytes 499-0/500"], [b"bytes 499-0/500"],
None::<ContentRange>); None::<ContentRange>);
crate::http::header::common_header_test!(test_blank, crate::http::header::common_header_test!(test_blank,
vec![b""], [b""],
None::<ContentRange>); None::<ContentRange>);
crate::http::header::common_header_test!(test_bytes_many_spaces, crate::http::header::common_header_test!(test_bytes_many_spaces,
vec![b"bytes 1-2/500 3"], [b"bytes 1-2/500 3"],
None::<ContentRange>); None::<ContentRange>);
crate::http::header::common_header_test!(test_bytes_many_slashes, crate::http::header::common_header_test!(test_bytes_many_slashes,
vec![b"bytes 1-2/500/600"], [b"bytes 1-2/500/600"],
None::<ContentRange>); None::<ContentRange>);
crate::http::header::common_header_test!(test_bytes_many_dashes, crate::http::header::common_header_test!(test_bytes_many_dashes,
vec![b"bytes 1-2-3/500"], [b"bytes 1-2-3/500"],
None::<ContentRange>); None::<ContentRange>);
} }
@ -113,21 +113,13 @@ pub enum ContentRangeSpec {
}, },
} }
fn split_in_two(s: &str, separator: char) -> Option<(&str, &str)> {
let mut iter = s.splitn(2, separator);
match (iter.next(), iter.next()) {
(Some(a), Some(b)) => Some((a, b)),
_ => None,
}
}
impl FromStr for ContentRangeSpec { impl FromStr for ContentRangeSpec {
type Err = ParseError; type Err = ParseError;
fn from_str(s: &str) -> Result<Self, ParseError> { fn from_str(s: &str) -> Result<Self, ParseError> {
let res = match split_in_two(s, ' ') { let res = match s.split_once(' ') {
Some(("bytes", resp)) => { Some(("bytes", resp)) => {
let (range, instance_length) = split_in_two(resp, '/').ok_or(ParseError::Header)?; let (range, instance_length) = resp.split_once('/').ok_or(ParseError::Header)?;
let instance_length = if instance_length == "*" { let instance_length = if instance_length == "*" {
None None
@ -139,7 +131,7 @@ impl FromStr for ContentRangeSpec {
None None
} else { } else {
let (first_byte, last_byte) = let (first_byte, last_byte) =
split_in_two(range, '-').ok_or(ParseError::Header)?; range.split_once('-').ok_or(ParseError::Header)?;
let first_byte = first_byte.parse().map_err(|_| ParseError::Header)?; let first_byte = first_byte.parse().map_err(|_| ParseError::Header)?;
let last_byte = last_byte.parse().map_err(|_| ParseError::Header)?; let last_byte = last_byte.parse().map_err(|_| ParseError::Header)?;
if last_byte < first_byte { if last_byte < first_byte {

View File

@ -45,11 +45,11 @@ crate::http::header::common_header! {
test_parse_and_format { test_parse_and_format {
crate::http::header::common_header_test!( crate::http::header::common_header_test!(
test_text_html, test_text_html,
vec![b"text/html"], [b"text/html"],
Some(HeaderField(mime::TEXT_HTML))); Some(HeaderField(mime::TEXT_HTML)));
crate::http::header::common_header_test!( crate::http::header::common_header_test!(
test_image_star, test_image_star,
vec![b"image/*"], [b"image/*"],
Some(HeaderField(mime::IMAGE_STAR))); Some(HeaderField(mime::IMAGE_STAR)));
} }

View File

@ -32,7 +32,7 @@ crate::http::header::common_header! {
(Date, DATE) => [HttpDate] (Date, DATE) => [HttpDate]
test_parse_and_format { test_parse_and_format {
crate::http::header::common_header_test!(test1, vec![b"Tue, 15 Nov 1994 08:12:31 GMT"]); crate::http::header::common_header_test!(test1, [b"Tue, 15 Nov 1994 08:12:31 GMT"]);
} }
} }

View File

@ -49,50 +49,50 @@ crate::http::header::common_header! {
test_parse_and_format { test_parse_and_format {
// From the RFC // From the RFC
crate::http::header::common_header_test!(test1, crate::http::header::common_header_test!(test1,
vec![b"\"xyzzy\""], [b"\"xyzzy\""],
Some(ETag(EntityTag::new_strong("xyzzy".to_owned())))); Some(ETag(EntityTag::new_strong("xyzzy".to_owned()))));
crate::http::header::common_header_test!(test2, crate::http::header::common_header_test!(test2,
vec![b"W/\"xyzzy\""], [b"W/\"xyzzy\""],
Some(ETag(EntityTag::new_weak("xyzzy".to_owned())))); Some(ETag(EntityTag::new_weak("xyzzy".to_owned()))));
crate::http::header::common_header_test!(test3, crate::http::header::common_header_test!(test3,
vec![b"\"\""], [b"\"\""],
Some(ETag(EntityTag::new_strong("".to_owned())))); Some(ETag(EntityTag::new_strong("".to_owned()))));
// Own tests // Own tests
crate::http::header::common_header_test!(test4, crate::http::header::common_header_test!(test4,
vec![b"\"foobar\""], [b"\"foobar\""],
Some(ETag(EntityTag::new_strong("foobar".to_owned())))); Some(ETag(EntityTag::new_strong("foobar".to_owned()))));
crate::http::header::common_header_test!(test5, crate::http::header::common_header_test!(test5,
vec![b"\"\""], [b"\"\""],
Some(ETag(EntityTag::new_strong("".to_owned())))); Some(ETag(EntityTag::new_strong("".to_owned()))));
crate::http::header::common_header_test!(test6, crate::http::header::common_header_test!(test6,
vec![b"W/\"weak-etag\""], [b"W/\"weak-etag\""],
Some(ETag(EntityTag::new_weak("weak-etag".to_owned())))); Some(ETag(EntityTag::new_weak("weak-etag".to_owned()))));
crate::http::header::common_header_test!(test7, crate::http::header::common_header_test!(test7,
vec![b"W/\"\x65\x62\""], [b"W/\"\x65\x62\""],
Some(ETag(EntityTag::new_weak("\u{0065}\u{0062}".to_owned())))); Some(ETag(EntityTag::new_weak("\u{0065}\u{0062}".to_owned()))));
crate::http::header::common_header_test!(test8, crate::http::header::common_header_test!(test8,
vec![b"W/\"\""], [b"W/\"\""],
Some(ETag(EntityTag::new_weak("".to_owned())))); Some(ETag(EntityTag::new_weak("".to_owned()))));
crate::http::header::common_header_test!(test9, crate::http::header::common_header_test!(test9,
vec![b"no-dquotes"], [b"no-dquotes"],
None::<ETag>); None::<ETag>);
crate::http::header::common_header_test!(test10, crate::http::header::common_header_test!(test10,
vec![b"w/\"the-first-w-is-case-sensitive\""], [b"w/\"the-first-w-is-case-sensitive\""],
None::<ETag>); None::<ETag>);
crate::http::header::common_header_test!(test11, crate::http::header::common_header_test!(test11,
vec![b""], [b""],
None::<ETag>); None::<ETag>);
crate::http::header::common_header_test!(test12, crate::http::header::common_header_test!(test12,
vec![b"\"unmatched-dquotes1"], [b"\"unmatched-dquotes1"],
None::<ETag>); None::<ETag>);
crate::http::header::common_header_test!(test13, crate::http::header::common_header_test!(test13,
vec![b"unmatched-dquotes2\""], [b"unmatched-dquotes2\""],
None::<ETag>); None::<ETag>);
crate::http::header::common_header_test!(test14, crate::http::header::common_header_test!(test14,
vec![b"matched-\"dquotes\""], [b"matched-\"dquotes\""],
None::<ETag>); None::<ETag>);
crate::http::header::common_header_test!(test15, crate::http::header::common_header_test!(test15,
vec![b"\""], [b"\""],
None::<ETag>); None::<ETag>);
} }
} }

View File

@ -36,6 +36,6 @@ crate::http::header::common_header! {
test_parse_and_format { test_parse_and_format {
// Test case from RFC // Test case from RFC
crate::http::header::common_header_test!(test1, vec![b"Thu, 01 Dec 1994 16:00:00 GMT"]); crate::http::header::common_header_test!(test1, [b"Thu, 01 Dec 1994 16:00:00 GMT"]);
} }
} }

View File

@ -52,17 +52,17 @@ common_header! {
test_parse_and_format { test_parse_and_format {
crate::http::header::common_header_test!( crate::http::header::common_header_test!(
test1, test1,
vec![b"\"xyzzy\""], [b"\"xyzzy\""],
Some(HeaderField::Items( Some(HeaderField::Items(
vec![EntityTag::new_strong("xyzzy".to_owned())]))); vec![EntityTag::new_strong("xyzzy".to_owned())])));
crate::http::header::common_header_test!( crate::http::header::common_header_test!(
test2, test2,
vec![b"\"xyzzy\", \"r2d2xxxx\", \"c3piozzzz\""], [b"\"xyzzy\", \"r2d2xxxx\", \"c3piozzzz\""],
Some(HeaderField::Items( Some(HeaderField::Items(
vec![EntityTag::new_strong("xyzzy".to_owned()), vec![EntityTag::new_strong("xyzzy".to_owned()),
EntityTag::new_strong("r2d2xxxx".to_owned()), EntityTag::new_strong("r2d2xxxx".to_owned()),
EntityTag::new_strong("c3piozzzz".to_owned())]))); EntityTag::new_strong("c3piozzzz".to_owned())])));
crate::http::header::common_header_test!(test3, vec![b"*"], Some(IfMatch::Any)); crate::http::header::common_header_test!(test3, [b"*"], Some(IfMatch::Any));
} }
} }

View File

@ -35,6 +35,6 @@ crate::http::header::common_header! {
test_parse_and_format { test_parse_and_format {
// Test case from RFC // Test case from RFC
crate::http::header::common_header_test!(test1, vec![b"Sat, 29 Oct 1994 19:43:31 GMT"]); crate::http::header::common_header_test!(test1, [b"Sat, 29 Oct 1994 19:43:31 GMT"]);
} }
} }

View File

@ -52,11 +52,11 @@ crate::http::header::common_header! {
(IfNoneMatch, IF_NONE_MATCH) => {Any / (EntityTag)+} (IfNoneMatch, IF_NONE_MATCH) => {Any / (EntityTag)+}
test_parse_and_format { test_parse_and_format {
crate::http::header::common_header_test!(test1, vec![b"\"xyzzy\""]); crate::http::header::common_header_test!(test1, [b"\"xyzzy\""]);
crate::http::header::common_header_test!(test2, vec![b"W/\"xyzzy\""]); crate::http::header::common_header_test!(test2, [b"W/\"xyzzy\""]);
crate::http::header::common_header_test!(test3, vec![b"\"xyzzy\", \"r2d2xxxx\", \"c3piozzzz\""]); crate::http::header::common_header_test!(test3, [b"\"xyzzy\", \"r2d2xxxx\", \"c3piozzzz\""]);
crate::http::header::common_header_test!(test4, vec![b"W/\"xyzzy\", W/\"r2d2xxxx\", W/\"c3piozzzz\""]); crate::http::header::common_header_test!(test4, [b"W/\"xyzzy\", W/\"r2d2xxxx\", W/\"c3piozzzz\""]);
crate::http::header::common_header_test!(test5, vec![b"*"]); crate::http::header::common_header_test!(test5, [b"*"]);
} }
} }

View File

@ -111,7 +111,7 @@ mod test_parse_and_format {
use super::IfRange as HeaderField; use super::IfRange as HeaderField;
use crate::http::header::*; use crate::http::header::*;
crate::http::header::common_header_test!(test1, vec![b"Sat, 29 Oct 1994 19:43:31 GMT"]); crate::http::header::common_header_test!(test1, [b"Sat, 29 Oct 1994 19:43:31 GMT"]);
crate::http::header::common_header_test!(test2, vec![b"\"abc\""]); crate::http::header::common_header_test!(test2, [b"\"abc\""]);
crate::http::header::common_header_test!(test3, vec![b"this-is-invalid"], None::<IfRange>); crate::http::header::common_header_test!(test3, [b"this-is-invalid"], None::<IfRange>);
} }

View File

@ -35,6 +35,6 @@ crate::http::header::common_header! {
test_parse_and_format { test_parse_and_format {
// Test case from RFC // Test case from RFC
crate::http::header::common_header_test!(test1, vec![b"Sat, 29 Oct 1994 19:43:31 GMT"]); crate::http::header::common_header_test!(test1, [b"Sat, 29 Oct 1994 19:43:31 GMT"]);
} }
} }

View File

@ -34,6 +34,6 @@ crate::http::header::common_header! {
test_parse_and_format { test_parse_and_format {
// Test case from RFC // Test case from RFC
crate::http::header::common_header_test!(test1, vec![b"Sat, 29 Oct 1994 19:43:31 GMT"]); crate::http::header::common_header_test!(test1, [b"Sat, 29 Oct 1994 19:43:31 GMT"]);
} }
} }

View File

@ -25,12 +25,12 @@ impl HttpResponse {
NonAuthoritativeInformation, NonAuthoritativeInformation,
StatusCode::NON_AUTHORITATIVE_INFORMATION StatusCode::NON_AUTHORITATIVE_INFORMATION
); );
static_resp!(NoContent, StatusCode::NO_CONTENT); static_resp!(NoContent, StatusCode::NO_CONTENT);
static_resp!(ResetContent, StatusCode::RESET_CONTENT); static_resp!(ResetContent, StatusCode::RESET_CONTENT);
static_resp!(PartialContent, StatusCode::PARTIAL_CONTENT); static_resp!(PartialContent, StatusCode::PARTIAL_CONTENT);
static_resp!(MultiStatus, StatusCode::MULTI_STATUS); static_resp!(MultiStatus, StatusCode::MULTI_STATUS);
static_resp!(AlreadyReported, StatusCode::ALREADY_REPORTED); static_resp!(AlreadyReported, StatusCode::ALREADY_REPORTED);
static_resp!(ImUsed, StatusCode::IM_USED);
static_resp!(MultipleChoices, StatusCode::MULTIPLE_CHOICES); static_resp!(MultipleChoices, StatusCode::MULTIPLE_CHOICES);
static_resp!(MovedPermanently, StatusCode::MOVED_PERMANENTLY); static_resp!(MovedPermanently, StatusCode::MOVED_PERMANENTLY);
@ -42,10 +42,10 @@ impl HttpResponse {
static_resp!(PermanentRedirect, StatusCode::PERMANENT_REDIRECT); static_resp!(PermanentRedirect, StatusCode::PERMANENT_REDIRECT);
static_resp!(BadRequest, StatusCode::BAD_REQUEST); static_resp!(BadRequest, StatusCode::BAD_REQUEST);
static_resp!(NotFound, StatusCode::NOT_FOUND);
static_resp!(Unauthorized, StatusCode::UNAUTHORIZED); static_resp!(Unauthorized, StatusCode::UNAUTHORIZED);
static_resp!(PaymentRequired, StatusCode::PAYMENT_REQUIRED); static_resp!(PaymentRequired, StatusCode::PAYMENT_REQUIRED);
static_resp!(Forbidden, StatusCode::FORBIDDEN); static_resp!(Forbidden, StatusCode::FORBIDDEN);
static_resp!(NotFound, StatusCode::NOT_FOUND);
static_resp!(MethodNotAllowed, StatusCode::METHOD_NOT_ALLOWED); static_resp!(MethodNotAllowed, StatusCode::METHOD_NOT_ALLOWED);
static_resp!(NotAcceptable, StatusCode::NOT_ACCEPTABLE); static_resp!(NotAcceptable, StatusCode::NOT_ACCEPTABLE);
static_resp!( static_resp!(
@ -57,13 +57,18 @@ impl HttpResponse {
static_resp!(Gone, StatusCode::GONE); static_resp!(Gone, StatusCode::GONE);
static_resp!(LengthRequired, StatusCode::LENGTH_REQUIRED); static_resp!(LengthRequired, StatusCode::LENGTH_REQUIRED);
static_resp!(PreconditionFailed, StatusCode::PRECONDITION_FAILED); static_resp!(PreconditionFailed, StatusCode::PRECONDITION_FAILED);
static_resp!(PreconditionRequired, StatusCode::PRECONDITION_REQUIRED);
static_resp!(PayloadTooLarge, StatusCode::PAYLOAD_TOO_LARGE); static_resp!(PayloadTooLarge, StatusCode::PAYLOAD_TOO_LARGE);
static_resp!(UriTooLong, StatusCode::URI_TOO_LONG); static_resp!(UriTooLong, StatusCode::URI_TOO_LONG);
static_resp!(UnsupportedMediaType, StatusCode::UNSUPPORTED_MEDIA_TYPE); static_resp!(UnsupportedMediaType, StatusCode::UNSUPPORTED_MEDIA_TYPE);
static_resp!(RangeNotSatisfiable, StatusCode::RANGE_NOT_SATISFIABLE); static_resp!(RangeNotSatisfiable, StatusCode::RANGE_NOT_SATISFIABLE);
static_resp!(ExpectationFailed, StatusCode::EXPECTATION_FAILED); static_resp!(ExpectationFailed, StatusCode::EXPECTATION_FAILED);
static_resp!(ImATeapot, StatusCode::IM_A_TEAPOT);
static_resp!(MisdirectedRequest, StatusCode::MISDIRECTED_REQUEST);
static_resp!(UnprocessableEntity, StatusCode::UNPROCESSABLE_ENTITY); static_resp!(UnprocessableEntity, StatusCode::UNPROCESSABLE_ENTITY);
static_resp!(Locked, StatusCode::LOCKED);
static_resp!(FailedDependency, StatusCode::FAILED_DEPENDENCY);
static_resp!(UpgradeRequired, StatusCode::UPGRADE_REQUIRED);
static_resp!(PreconditionRequired, StatusCode::PRECONDITION_REQUIRED);
static_resp!(TooManyRequests, StatusCode::TOO_MANY_REQUESTS); static_resp!(TooManyRequests, StatusCode::TOO_MANY_REQUESTS);
static_resp!( static_resp!(
RequestHeaderFieldsTooLarge, RequestHeaderFieldsTooLarge,
@ -83,6 +88,11 @@ impl HttpResponse {
static_resp!(VariantAlsoNegotiates, StatusCode::VARIANT_ALSO_NEGOTIATES); static_resp!(VariantAlsoNegotiates, StatusCode::VARIANT_ALSO_NEGOTIATES);
static_resp!(InsufficientStorage, StatusCode::INSUFFICIENT_STORAGE); static_resp!(InsufficientStorage, StatusCode::INSUFFICIENT_STORAGE);
static_resp!(LoopDetected, StatusCode::LOOP_DETECTED); static_resp!(LoopDetected, StatusCode::LOOP_DETECTED);
static_resp!(NotExtended, StatusCode::NOT_EXTENDED);
static_resp!(
NetworkAuthenticationRequired,
StatusCode::NETWORK_AUTHENTICATION_REQUIRED
);
} }
#[cfg(test)] #[cfg(test)]