1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-11-30 10:42:55 +01:00

add ContentLength typed header (#2490)

This commit is contained in:
Rob Ede 2023-07-22 03:16:01 +01:00 committed by GitHub
parent 8cdbab3416
commit 6a0ea51b15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 67 additions and 9 deletions

View File

@ -8,6 +8,7 @@
- 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. - Add missing constructors on `HttpResponse` for several status codes.
- Add `http::header::ContentLength` typed header.
### Changed ### Changed

View File

@ -48,12 +48,15 @@ crate::http::header::common_header! {
(Allow, header::ALLOW) => (Method)* (Allow, header::ALLOW) => (Method)*
test_parse_and_format { test_parse_and_format {
// From the RFC // from the RFC
crate::http::header::common_header_test!( crate::http::header::common_header_test!(
test1, test1,
[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
// other tests
crate::http::header::common_header_test!( crate::http::header::common_header_test!(
test2, test2,
[b"OPTIONS, GET, PUT, POST, DELETE, HEAD, TRACE, CONNECT, PATCH"], [b"OPTIONS, GET, PUT, POST, DELETE, HEAD, TRACE, CONNECT, PATCH"],
@ -67,6 +70,7 @@ crate::http::header::common_header! {
Method::TRACE, Method::TRACE,
Method::CONNECT, Method::CONNECT,
Method::PATCH]))); Method::PATCH])));
crate::http::header::common_header_test!( crate::http::header::common_header_test!(
test3, test3,
[b""], [b""],

View File

@ -0,0 +1,56 @@
use super::common_header;
use crate::http::header;
common_header! {
/// `Content-Length` header, defined in [RFC 7230 §3.3.2].
///
/// The Content-Length
///
/// # ABNF
///
/// ```plain
/// Content-Length = 1*DIGIT
/// ```
///
/// # Example Values
///
/// - `0`
/// - `3495`
///
/// # Examples
///
/// ```
/// use actix_web::{http::header::ContentLength, HttpResponse};
///
/// let res_empty = HttpResponse::Ok()
/// .insert_header(ContentLength(0));
///
/// let res_fake_cl = HttpResponse::Ok()
/// .insert_header(ContentLength(3_495));
/// ```
///
/// [RFC 7230 §3.3.2]: https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
(ContentLength, header::CONTENT_LENGTH) => [usize]
test_parse_and_format {
common_header_test!(no_header, [b""; 0], None);
common_header_test!(empty_header, [b""; 1], None);
common_header_test!(zero, [b"0"], Some(ContentLength(0)));
common_header_test!(one, [b"1"], Some(ContentLength(1)));
common_header_test!(one_two_three, [b"123"], Some(ContentLength(123)));
common_header_test!(
thirty_two_power_plus_one,
[b"4294967297"],
Some(ContentLength(4_294_967_297))
);
common_header_test!(
sixty_four_power_minus_one,
[b"18446744073709551615"],
Some(ContentLength(18_446_744_073_709_551_615))
);
common_header_test!(invalid1, [b"123,567"], None);
common_header_test!(invalid2, [b"123_567"], None);
}
}

View File

@ -67,7 +67,6 @@ crate::http::header::common_header! {
crate::http::header::common_header_test!(test_bytes_many_dashes, crate::http::header::common_header_test!(test_bytes_many_dashes,
[b"bytes 1-2-3/500"], [b"bytes 1-2-3/500"],
None::<ContentRange>); None::<ContentRange>);
} }
} }

View File

@ -24,6 +24,7 @@ mod allow;
mod cache_control; mod cache_control;
mod content_disposition; mod content_disposition;
mod content_language; mod content_language;
mod content_length;
mod content_range; mod content_range;
mod content_type; mod content_type;
mod date; mod date;
@ -53,6 +54,7 @@ pub use self::{
cache_control::{CacheControl, CacheDirective}, cache_control::{CacheControl, CacheDirective},
content_disposition::{ContentDisposition, DispositionParam, DispositionType}, content_disposition::{ContentDisposition, DispositionParam, DispositionType},
content_language::ContentLanguage, content_language::ContentLanguage,
content_length::ContentLength,
content_range::{ContentRange, ContentRangeSpec}, content_range::{ContentRange, ContentRangeSpec},
content_type::ContentType, content_type::ContentType,
date::Date, date::Date,

View File

@ -21,7 +21,7 @@ use crate::{
body::EitherBody, body::EitherBody,
error::{Error, JsonPayloadError}, error::{Error, JsonPayloadError},
extract::FromRequest, extract::FromRequest,
http::header::CONTENT_LENGTH, http::header::{ContentLength, Header as _},
request::HttpRequest, request::HttpRequest,
web, HttpMessage, HttpResponse, Responder, web, HttpMessage, HttpResponse, Responder,
}; };
@ -342,11 +342,7 @@ impl<T: DeserializeOwned> JsonBody<T> {
return JsonBody::Error(Some(JsonPayloadError::ContentType)); return JsonBody::Error(Some(JsonPayloadError::ContentType));
} }
let length = req let length = ContentLength::parse(req).ok().map(|x| x.0);
.headers()
.get(&CONTENT_LENGTH)
.and_then(|l| l.to_str().ok())
.and_then(|s| s.parse::<usize>().ok());
// Notice the content-length is not checked against limit of json config here. // Notice the content-length is not checked against limit of json config here.
// As the internal usage always call JsonBody::limit after JsonBody::new. // As the internal usage always call JsonBody::limit after JsonBody::new.