Skip to content

Commit 3c1a561

Browse files
authored
Fix content-header parsing in juniper_axum (#1289)
* Fix content-header parsing in juniper_axum Check media type using `starts_with` instead of full string matching. Fixes #1288 Signed-off-by: Joe Grund <[email protected]> * Add changelog and tests --------- Signed-off-by: Joe Grund <[email protected]>
1 parent 257bc69 commit 3c1a561

File tree

2 files changed

+49
-11
lines changed

2 files changed

+49
-11
lines changed

juniper_axum/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ All user visible changes to `juniper_axum` crate will be documented in this file
1616

1717
- Building on `wasm32-unknown-unknown` and `wasm32-wasi` targets. ([#1283], [#1282])
1818

19+
### Fixed
20+
21+
- `Content-Type` header reading full value instead of just the media type. ([#1288])
22+
1923
[#1272]: /../../pull/1272
2024
[#1282]: /../../issues/1282
2125
[#1283]: /../../pull/1283

juniper_axum/src/extract.rs

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use axum::{
66
async_trait,
77
body::Body,
88
extract::{FromRequest, FromRequestParts, Query},
9-
http::{HeaderValue, Method, Request, StatusCode},
9+
http::{header, HeaderValue, Method, Request, StatusCode},
1010
response::{IntoResponse as _, Response},
1111
Json, RequestExt as _,
1212
};
@@ -85,7 +85,7 @@ where
8585
async fn from_request(mut req: Request<Body>, state: &State) -> Result<Self, Self::Rejection> {
8686
let content_type = req
8787
.headers()
88-
.get("content-type")
88+
.get(header::CONTENT_TYPE)
8989
.map(HeaderValue::to_str)
9090
.transpose()
9191
.map_err(|_| {
@@ -122,22 +122,24 @@ where
122122
.into_response()
123123
})
124124
}),
125-
(&Method::POST, Some("application/json")) => {
125+
(&Method::POST, Some(x)) if x.starts_with("application/json") => {
126126
Json::<GraphQLBatchRequest<S>>::from_request(req, state)
127127
.await
128128
.map(|req| Self(req.0))
129129
.map_err(|e| {
130130
(StatusCode::BAD_REQUEST, format!("Invalid JSON body: {e}")).into_response()
131131
})
132132
}
133-
(&Method::POST, Some("application/graphql")) => String::from_request(req, state)
134-
.await
135-
.map(|body| {
136-
Self(GraphQLBatchRequest::Single(GraphQLRequest::new(
137-
body, None, None,
138-
)))
139-
})
140-
.map_err(|_| (StatusCode::BAD_REQUEST, "Not valid UTF-8 body").into_response()),
133+
(&Method::POST, Some(x)) if x.starts_with("application/graphql") => {
134+
String::from_request(req, state)
135+
.await
136+
.map(|body| {
137+
Self(GraphQLBatchRequest::Single(GraphQLRequest::new(
138+
body, None, None,
139+
)))
140+
})
141+
.map_err(|_| (StatusCode::BAD_REQUEST, "Not valid UTF-8 body").into_response())
142+
}
141143
(&Method::POST, _) => Err((
142144
StatusCode::UNSUPPORTED_MEDIA_TYPE,
143145
"`Content-Type` header is expected to be either `application/json` or \
@@ -246,6 +248,22 @@ mod juniper_request_tests {
246248
assert_eq!(do_from_request(req).await, expected);
247249
}
248250

251+
#[tokio::test]
252+
async fn from_json_post_request_with_charset() {
253+
let req = Request::post("/")
254+
.header("content-type", "application/json; charset=utf-8")
255+
.body(Body::from(r#"{"query": "{ add(a: 2, b: 3) }"}"#))
256+
.unwrap_or_else(|e| panic!("cannot build `Request`: {e}"));
257+
258+
let expected = JuniperRequest(GraphQLBatchRequest::Single(GraphQLRequest::new(
259+
"{ add(a: 2, b: 3) }".to_string(),
260+
None,
261+
None,
262+
)));
263+
264+
assert_eq!(do_from_request(req).await, expected);
265+
}
266+
249267
#[tokio::test]
250268
async fn from_graphql_post_request() {
251269
let req = Request::post("/")
@@ -262,6 +280,22 @@ mod juniper_request_tests {
262280
assert_eq!(do_from_request(req).await, expected);
263281
}
264282

283+
#[tokio::test]
284+
async fn from_graphql_post_request_with_charset() {
285+
let req = Request::post("/")
286+
.header("content-type", "application/graphql; charset=utf-8")
287+
.body(Body::from(r#"{ add(a: 2, b: 3) }"#))
288+
.unwrap_or_else(|e| panic!("cannot build `Request`: {e}"));
289+
290+
let expected = JuniperRequest(GraphQLBatchRequest::Single(GraphQLRequest::new(
291+
"{ add(a: 2, b: 3) }".to_string(),
292+
None,
293+
None,
294+
)));
295+
296+
assert_eq!(do_from_request(req).await, expected);
297+
}
298+
265299
/// Performs [`JuniperRequest::from_request()`].
266300
async fn do_from_request(req: Request<Body>) -> JuniperRequest {
267301
match JuniperRequest::from_request(req, &()).await {

0 commit comments

Comments
 (0)