Require POST for GraphQL requests

This commit is contained in:
Koxiaet 2020-10-15 18:42:09 +01:00
parent 2756c2cd5b
commit 5c47f1ec57
5 changed files with 19 additions and 5 deletions

View File

@ -13,11 +13,12 @@ they must all internally use the below functions.
- Conversion from HTTP library's request to `async_graphql::BatchRequest`: - Conversion from HTTP library's request to `async_graphql::BatchRequest`:
1. If the request is a `GET` request: 1. If the request is a `GET` request:
1. Return the request's query parameters deserialized as an `async_graphql::Request`. 1. Return the request's query parameters deserialized as an `async_graphql::Request`.
1. Otherwise: 1. If the request is a `POST` request:
1. Get the request's `Content-Type` header. 1. Get the request's `Content-Type` header.
1. Call `async_graphql::http::receive_batch_body` on the request's body. 1. Call `async_graphql::http::receive_batch_body` on the request's body.
1. Convert `ParseRequestError::PayloadTooLarge` to a 413 Payload Too Large response. 1. Convert `ParseRequestError::PayloadTooLarge` to a 413 Payload Too Large response.
1. Convert all other errors to a 400 Bad Request response. 1. Convert all other errors to a 400 Bad Request response.
1. Otherwise return a 405 Method Not Allowed.
- Conversion from HTTP library's request to `async_graphql::Request`: - Conversion from HTTP library's request to `async_graphql::Request`:
1. Call the above function to convert the request to an `async_graphql::BatchRequest`. 1. Call the above function to convert the request to an `async_graphql::BatchRequest`.
1. Call `BatchRequest::into_single` on the result. 1. Call `BatchRequest::into_single` on the result.

View File

@ -75,7 +75,7 @@ impl FromRequest for BatchRequest {
if req.method() == Method::GET { if req.method() == Method::GET {
let res = serde_urlencoded::from_str(req.query_string()); let res = serde_urlencoded::from_str(req.query_string());
Box::pin(async move { Ok(Self(async_graphql::BatchRequest::Single(res?))) }) Box::pin(async move { Ok(Self(async_graphql::BatchRequest::Single(res?))) })
} else { } else if req.method() == Method::POST {
let content_type = req let content_type = req
.headers() .headers()
.get(http::header::CONTENT_TYPE) .get(http::header::CONTENT_TYPE)
@ -129,6 +129,12 @@ impl FromRequest for BatchRequest {
})?, })?,
)) ))
}) })
} else {
Box::pin(async move {
Err(actix_web::error::ErrorMethodNotAllowed(
"GraphQL only supports GET and POST requests",
))
})
} }
} }
} }

View File

@ -128,7 +128,7 @@ pub async fn receive_batch_request_opts<State: Clone + Send + Sync + 'static>(
) -> tide::Result<async_graphql::BatchRequest> { ) -> tide::Result<async_graphql::BatchRequest> {
if request.method() == Method::Get { if request.method() == Method::Get {
request.query::<async_graphql::Request>().map(Into::into) request.query::<async_graphql::Request>().map(Into::into)
} else { } else if request.method() == Method::Post {
let body = request.take_body(); let body = request.take_body();
let content_type = request let content_type = request
.header(headers::CONTENT_TYPE) .header(headers::CONTENT_TYPE)
@ -146,6 +146,11 @@ pub async fn receive_batch_request_opts<State: Clone + Send + Sync + 'static>(
e, e,
) )
}) })
} else {
Err(tide::Error::from_str(
StatusCode::MethodNotAllowed,
"GraphQL only supports GET and POST requests",
))
} }
} }

View File

@ -38,7 +38,7 @@ where
{ {
warp::any() warp::any()
.and(warp::get().and(warp::query()).map(BatchRequest::Single)) .and(warp::get().and(warp::query()).map(BatchRequest::Single))
.or(warp::any() .or(warp::post()
.and(warp::header::optional::<String>("content-type")) .and(warp::header::optional::<String>("content-type"))
.and(warp::body::stream()) .and(warp::body::stream())
.and_then(move |content_type, body| async move { .and_then(move |content_type, body| async move {

View File

@ -43,7 +43,9 @@ pub async fn receive_batch_body(
if let Some(Ok(boundary)) = content_type.map(multer::parse_boundary) { if let Some(Ok(boundary)) = content_type.map(multer::parse_boundary) {
multipart::receive_batch_multipart(body, boundary, opts).await multipart::receive_batch_multipart(body, boundary, opts).await
} else if let Some(content_type) = content_type.filter(|&ct| ct != "application/json") { } else if let Some(content_type) = content_type.filter(|&ct| ct != "application/json") {
Err(ParseRequestError::UnknownContentType(content_type.to_owned())) Err(ParseRequestError::UnknownContentType(
content_type.to_owned(),
))
} else { } else {
receive_batch_json(body).await receive_batch_json(body).await
} }