From 9d1f75d349dd6ad8451b8d2dbc619561868dba4d Mon Sep 17 00:00:00 2001 From: Marcio Ordonez Date: Sun, 19 Nov 2023 08:22:55 -0300 Subject: [PATCH] fix: content type required flag (#3168) * fix: content type required flag * clarify comments for invalid json mime type * remove pr reference --------- Co-authored-by: Rob Ede --- actix-web/CHANGES.md | 4 ++++ actix-web/src/types/json.rs | 40 +++++++++++++++++++++++++++++-------- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/actix-web/CHANGES.md b/actix-web/CHANGES.md index 50728a839..0079a4120 100644 --- a/actix-web/CHANGES.md +++ b/actix-web/CHANGES.md @@ -6,6 +6,10 @@ - Updated `zstd` dependency to `0.13`. +### Fixed + +- Fix validation of `Json` extractor when `JsonConfig::validate_content_type()` is set to false. + ## 4.4.0 ### Added diff --git a/actix-web/src/types/json.rs b/actix-web/src/types/json.rs index 59c95da4c..6b75c0cfe 100644 --- a/actix-web/src/types/json.rs +++ b/actix-web/src/types/json.rs @@ -328,14 +328,19 @@ impl JsonBody { ctype_required: bool, ) -> Self { // check content-type - let can_parse_json = if let Ok(Some(mime)) = req.mime_type() { - mime.subtype() == mime::JSON - || mime.suffix() == Some(mime::JSON) - || ctype_fn.map_or(false, |predicate| predicate(mime)) - } else { - // if `ctype_required` is false, assume payload is - // json even when content-type header is missing - !ctype_required + let can_parse_json = match (ctype_required, req.mime_type()) { + (true, Ok(Some(mime))) => { + mime.subtype() == mime::JSON + || mime.suffix() == Some(mime::JSON) + || ctype_fn.map_or(false, |predicate| predicate(mime)) + } + + // if content-type is expected but not parsable as mime type, bail + (true, _) => false, + + // if content-type validation is disabled, assume payload is JSON + // even when content-type header is missing or invalid mime type + (false, _) => true, }; if !can_parse_json { @@ -725,6 +730,25 @@ mod tests { assert!(s.is_ok()) } + #[actix_rt::test] + async fn test_json_ignoring_content_type() { + let (req, mut pl) = TestRequest::default() + .insert_header(( + header::CONTENT_LENGTH, + header::HeaderValue::from_static("16"), + )) + .insert_header(( + header::CONTENT_TYPE, + header::HeaderValue::from_static("invalid/value"), + )) + .set_payload(Bytes::from_static(b"{\"name\": \"test\"}")) + .app_data(JsonConfig::default().content_type_required(false)) + .to_http_parts(); + + let s = Json::::from_request(&req, &mut pl).await; + assert!(s.is_ok()); + } + #[actix_rt::test] async fn test_with_config_in_data_wrapper() { let (req, mut pl) = TestRequest::default()