From 3d48c0504c824699d8542019f26a33325543cf6e Mon Sep 17 00:00:00 2001 From: Marcel Overdijk Date: Fri, 17 May 2019 16:26:20 +0200 Subject: [PATCH] Making content type resolution more robust --- build.gradle | 6 ++-- .../components/GraphQLController.java | 17 ++++++++-- .../components/GraphQLControllerTest.java | 31 +++++++------------ .../servlet/components/GraphQLController.java | 17 ++++++++-- 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/build.gradle b/build.gradle index 38b013f..f7d0c8c 100644 --- a/build.gradle +++ b/build.gradle @@ -40,9 +40,9 @@ subprojects { ext { graphqlJavaVersion = "12.0" - springVersion = "5.1.2.RELEASE" - springBootVersion = "2.1.0.RELEASE" - jacksonVersion = "2.9.6" + springVersion = "5.1.7.RELEASE" + springBootVersion = "2.1.5.RELEASE" + jacksonVersion = "2.9.8" assertJVersion = "3.11.1" } diff --git a/graphql-java-spring-webflux/src/main/java/graphql/spring/web/reactive/components/GraphQLController.java b/graphql-java-spring-webflux/src/main/java/graphql/spring/web/reactive/components/GraphQLController.java index 552129f..4926a59 100644 --- a/graphql-java-spring-webflux/src/main/java/graphql/spring/web/reactive/components/GraphQLController.java +++ b/graphql-java-spring-webflux/src/main/java/graphql/spring/web/reactive/components/GraphQLController.java @@ -9,7 +9,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.MediaType; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; @@ -27,6 +29,9 @@ @Internal public class GraphQLController { + static String APPLICATION_GRAPHQL_VALUE = "application/graphql"; + static MediaType APPLICATION_GRAPHQL = MediaType.parseMediaType(APPLICATION_GRAPHQL_VALUE); + @Autowired GraphQLInvocation graphQLInvocation; @@ -47,6 +52,14 @@ public Object graphqlPOST( @RequestBody(required = false) String body, ServerWebExchange serverWebExchange) { + MediaType mediaType = null; + if (!StringUtils.isEmpty(contentType)) { + try { + mediaType = MediaType.parseMediaType(contentType); + } catch (InvalidMediaTypeException ignore) { + } + } + if (body == null) { body = ""; } @@ -62,7 +75,7 @@ public Object graphqlPOST( // "variables": { "myVariable": "someValue", ... } // } - if (MediaType.APPLICATION_JSON_VALUE.equals(contentType)) { + if (MediaType.APPLICATION_JSON.equalsTypeAndSubtype(mediaType)) { GraphQLRequestBody request = jsonSerializer.deserialize(body, GraphQLRequestBody.class); if (request.getQuery() == null) { request.setQuery(""); @@ -82,7 +95,7 @@ public Object graphqlPOST( // * If the "application/graphql" Content-Type header is present, // treat the HTTP POST body contents as the GraphQL query string. - if ("application/graphql".equals(contentType)) { + if (APPLICATION_GRAPHQL.equalsTypeAndSubtype(mediaType)) { return executeRequest(body, null, null, serverWebExchange); } diff --git a/graphql-java-spring-webflux/src/test/java/graphql/spring/web/reactive/components/GraphQLControllerTest.java b/graphql-java-spring-webflux/src/test/java/graphql/spring/web/reactive/components/GraphQLControllerTest.java index ea57695..c9e08a4 100644 --- a/graphql-java-spring-webflux/src/test/java/graphql/spring/web/reactive/components/GraphQLControllerTest.java +++ b/graphql-java-spring-webflux/src/test/java/graphql/spring/web/reactive/components/GraphQLControllerTest.java @@ -18,7 +18,6 @@ import reactor.core.publisher.Mono; import testconfig.TestAppConfig; -import java.net.URLEncoder; import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -109,9 +108,7 @@ public void testSimplePostRequest() throws Exception { @Test public void testQueryParamPostRequest() throws Exception { String variablesJson = "{\"variable\":\"variableValue\"}"; - String variablesValue = URLEncoder.encode(variablesJson, "UTF-8"); String query = "query myQuery {foo}"; - String queryString = URLEncoder.encode(query, "UTF-8"); String operationName = "myQuery"; ExecutionResultImpl executionResult = ExecutionResultImpl.newExecutionResult() @@ -122,10 +119,10 @@ public void testQueryParamPostRequest() throws Exception { Mockito.when(graphql.executeAsync(captor.capture())).thenReturn(cf); client.post().uri(uriBuilder -> uriBuilder.path("/graphql") - .queryParam("variables", variablesValue) - .queryParam("query", queryString) - .queryParam("operationName", operationName) - .build(variablesJson, queryString)) + .queryParam("variables", "{variables}") + .queryParam("query", "{query}") + .queryParam("operationName", "{operationName}") + .build(variablesJson, query, operationName)) .accept(MediaType.APPLICATION_JSON_UTF8) .exchange() .expectStatus().isOk() @@ -144,7 +141,6 @@ public void testQueryParamPostRequest() throws Exception { @Test public void testSimpleQueryParamPostRequest() throws Exception { String query = "{foo}"; - String queryString = URLEncoder.encode(query, "UTF-8"); ExecutionResultImpl executionResult = ExecutionResultImpl.newExecutionResult() .data("bar") @@ -154,8 +150,8 @@ public void testSimpleQueryParamPostRequest() throws Exception { Mockito.when(graphql.executeAsync(captor.capture())).thenReturn(cf); client.post().uri(uriBuilder -> uriBuilder.path("/graphql") - .queryParam("query", queryString) - .build()) + .queryParam("query", "{query}") + .build(query)) .accept(MediaType.APPLICATION_JSON_UTF8) .exchange() .expectStatus().isOk() @@ -196,9 +192,7 @@ public void testApplicationGraphqlPostRequest() throws Exception { @Test public void testGetRequest() throws Exception { String variablesJson = "{\"variable\":\"variableValue\"}"; - String variablesValue = URLEncoder.encode(variablesJson, "UTF-8"); String query = "query myQuery {foo}"; - String queryString = URLEncoder.encode(query, "UTF-8"); String operationName = "myQuery"; ExecutionResultImpl executionResult = ExecutionResultImpl.newExecutionResult() @@ -209,10 +203,10 @@ public void testGetRequest() throws Exception { Mockito.when(graphql.executeAsync(captor.capture())).thenReturn(cf); client.get().uri(uriBuilder -> uriBuilder.path("/graphql") - .queryParam("variables", variablesValue) - .queryParam("query", queryString) - .queryParam("operationName", operationName) - .build(variablesJson, queryString)) + .queryParam("variables", "{variables}") + .queryParam("query", "{query}") + .queryParam("operationName", "{operationName}") + .build(variablesJson, query, operationName)) .accept(MediaType.APPLICATION_JSON_UTF8) .exchange() .expectStatus().isOk() @@ -231,7 +225,6 @@ public void testGetRequest() throws Exception { @Test public void testSimpleGetRequest() throws Exception { String query = "{foo}"; - String queryString = URLEncoder.encode(query, "UTF-8"); ExecutionResultImpl executionResult = ExecutionResultImpl.newExecutionResult() .data("bar") @@ -241,8 +234,8 @@ public void testSimpleGetRequest() throws Exception { Mockito.when(graphql.executeAsync(captor.capture())).thenReturn(cf); client.get().uri(uriBuilder -> uriBuilder.path("/graphql") - .queryParam("query", queryString) - .build()) + .queryParam("query", "{query}") + .build(query)) .accept(MediaType.APPLICATION_JSON_UTF8) .exchange() .expectStatus().isOk() diff --git a/graphql-java-spring-webmvc/src/main/java/graphql/spring/web/servlet/components/GraphQLController.java b/graphql-java-spring-webmvc/src/main/java/graphql/spring/web/servlet/components/GraphQLController.java index 9935b68..6a66790 100644 --- a/graphql-java-spring-webmvc/src/main/java/graphql/spring/web/servlet/components/GraphQLController.java +++ b/graphql-java-spring-webmvc/src/main/java/graphql/spring/web/servlet/components/GraphQLController.java @@ -9,7 +9,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.MediaType; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; @@ -28,6 +30,9 @@ @Internal public class GraphQLController { + static String APPLICATION_GRAPHQL_VALUE = "application/graphql"; + static MediaType APPLICATION_GRAPHQL = MediaType.parseMediaType(APPLICATION_GRAPHQL_VALUE); + @Autowired GraphQLInvocation graphQLInvocation; @@ -48,6 +53,14 @@ public Object graphqlPOST( @RequestBody(required = false) String body, WebRequest webRequest) throws IOException { + MediaType mediaType = null; + if (!StringUtils.isEmpty(contentType)) { + try { + mediaType = MediaType.parseMediaType(contentType); + } catch (InvalidMediaTypeException ignore) { + } + } + if (body == null) { body = ""; } @@ -63,7 +76,7 @@ public Object graphqlPOST( // "variables": { "myVariable": "someValue", ... } // } - if (MediaType.APPLICATION_JSON_VALUE.equals(contentType)) { + if (MediaType.APPLICATION_JSON.equalsTypeAndSubtype(mediaType)) { GraphQLRequestBody request = jsonSerializer.deserialize(body, GraphQLRequestBody.class); if (request.getQuery() == null) { request.setQuery(""); @@ -83,7 +96,7 @@ public Object graphqlPOST( // * If the "application/graphql" Content-Type header is present, // treat the HTTP POST body contents as the GraphQL query string. - if ("application/graphql".equals(contentType)) { + if (APPLICATION_GRAPHQL.equalsTypeAndSubtype(mediaType)) { return executeRequest(body, null, null, webRequest); }