update changelog

This commit is contained in:
Rob Ede 2021-09-11 16:46:33 +01:00
parent dc85ef09a5
commit 2cfa2d17a5
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
2 changed files with 25 additions and 16 deletions

View File

@ -1,10 +1,14 @@
# Changes # Changes
## Unreleased - 2021-xx-xx ## Unreleased - 2021-xx-xx
### Added
* Option to allow `Json` extractor to work without a `Content-Length` header present. [#2362]
### Changed ### Changed
* Asscociated type `FromRequest::Config` was removed. [#2233] * Asscociated type `FromRequest::Config` was removed. [#2233]
[#2233]: https://github.com/actix/actix-web/pull/2233 [#2233]: https://github.com/actix/actix-web/pull/2233
[#2362]: https://github.com/actix/actix-web/pull/2362
## 4.0.0-beta.9 - 2021-09-09 ## 4.0.0-beta.9 - 2021-09-09
### Added ### Added

View File

@ -127,7 +127,7 @@ impl<T: Serialize> Responder for Json<T> {
} }
/// See [here](#extractor) for example of usage as an extractor. /// See [here](#extractor) for example of usage as an extractor.
impl<T: DeserializeOwned + 'static> FromRequest for Json<T> { impl<T: DeserializeOwned> FromRequest for Json<T> {
type Error = Error; type Error = Error;
type Future = JsonExtractFut<T>; type Future = JsonExtractFut<T>;
@ -136,13 +136,13 @@ impl<T: DeserializeOwned + 'static> FromRequest for Json<T> {
let config = JsonConfig::from_req(req); let config = JsonConfig::from_req(req);
let limit = config.limit; let limit = config.limit;
let content_type_required = config.content_type_required; let ctype_required = config.content_type_required;
let ctype = config.content_type.as_deref(); let ctype_fn = config.content_type.as_deref();
let err_handler = config.err_handler.clone(); let err_handler = config.err_handler.clone();
JsonExtractFut { JsonExtractFut {
req: Some(req.clone()), req: Some(req.clone()),
fut: JsonBody::new(req, payload, ctype, content_type_required).limit(limit), fut: JsonBody::new(req, payload, ctype_fn, ctype_required).limit(limit),
err_handler, err_handler,
} }
} }
@ -157,7 +157,7 @@ pub struct JsonExtractFut<T> {
err_handler: JsonErrorHandler, err_handler: JsonErrorHandler,
} }
impl<T: DeserializeOwned + 'static> Future for JsonExtractFut<T> { impl<T: DeserializeOwned> Future for JsonExtractFut<T> {
type Output = Result<Json<T>, Error>; type Output = Result<Json<T>, Error>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
@ -286,15 +286,18 @@ impl Default for JsonConfig {
/// Future that resolves to some `T` when parsed from a JSON payload. /// Future that resolves to some `T` when parsed from a JSON payload.
/// ///
/// Form can be deserialized from any type `T` that implements [`serde::Deserialize`]. /// Can deserialize any type `T` that implements [`Deserialize`][serde::Deserialize].
/// ///
/// Returns error if: /// Returns error if:
/// - content type is not `application/json` /// - `Content-Type` is not `application/json` when `ctype_required` (passed to [`new`][Self::new])
/// - content length is greater than [limit](JsonBody::limit()) /// is `true`.
/// - `Content-Length` is greater than [limit](JsonBody::limit()).
/// - The payload, when consumed, is not valid JSON.
pub enum JsonBody<T> { pub enum JsonBody<T> {
Error(Option<JsonPayloadError>), Error(Option<JsonPayloadError>),
Body { Body {
limit: usize, limit: usize,
/// Length as reported by `Content-Length` header, if present.
length: Option<usize>, length: Option<usize>,
#[cfg(feature = "__compress")] #[cfg(feature = "__compress")]
payload: Decompress<Payload>, payload: Decompress<Payload>,
@ -313,19 +316,21 @@ impl<T: DeserializeOwned> JsonBody<T> {
pub fn new( pub fn new(
req: &HttpRequest, req: &HttpRequest,
payload: &mut Payload, payload: &mut Payload,
ctype: Option<&(dyn Fn(mime::Mime) -> bool + Send + Sync)>, ctype_fn: Option<&(dyn Fn(mime::Mime) -> bool + Send + Sync)>,
content_type_required: bool, ctype_required: bool,
) -> Self { ) -> Self {
// check content-type // check content-type
let has_valid_content_type = if let Ok(Some(mime)) = req.mime_type() { let can_parse_json = if let Ok(Some(mime)) = req.mime_type() {
mime.subtype() == mime::JSON mime.subtype() == mime::JSON
|| mime.suffix() == Some(mime::JSON) || mime.suffix() == Some(mime::JSON)
|| ctype.map_or(false, |predicate| predicate(mime)) || ctype_fn.map_or(false, |predicate| predicate(mime))
} else { } else {
!content_type_required // if `ctype_required` is false, assume payload is
// json even when content-type header is missing
!ctype_required
}; };
if !has_valid_content_type { if !can_parse_json {
return JsonBody::Error(Some(JsonPayloadError::ContentType)); return JsonBody::Error(Some(JsonPayloadError::ContentType));
} }
@ -335,7 +340,7 @@ impl<T: DeserializeOwned> JsonBody<T> {
.and_then(|l| l.to_str().ok()) .and_then(|l| l.to_str().ok())
.and_then(|s| s.parse::<usize>().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.
// And limit check to return an error variant of JsonBody happens there. // And limit check to return an error variant of JsonBody happens there.
@ -389,7 +394,7 @@ impl<T: DeserializeOwned> JsonBody<T> {
} }
} }
impl<T: DeserializeOwned + 'static> Future for JsonBody<T> { impl<T: DeserializeOwned> Future for JsonBody<T> {
type Output = Result<T, JsonPayloadError>; type Output = Result<T, JsonPayloadError>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {