Repository: quarkusio/quarkus
Issue: GraphQL handler blows up if request contains newline breaks

## Describe the bug
When an incoming GraphQL query contains newline characters, the JSON parser that parses it blows up.

### Expected behavior
Request with newlines is parsed, the newlines ignored

### Actual behavior
The request processing blows up on something like
```
javax.json.stream.JsonParsingException: Unexpected char 10 at (line no=1, column no=19, offset=18)
```
where the "char 10" is a newline character


Changed files:
extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLExecutionHandler.java
extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/GraphQLTest.java

diff --git a/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/GraphQLTest.java b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/GraphQLTest.java
index eeb0b5b1c11..cb5b0ae464c 100644
--- a/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/GraphQLTest.java
+++ b/extensions/smallrye-graphql/deployment/src/test/java/io/quarkus/smallrye/graphql/deployment/GraphQLTest.java
@@ -152,6 +152,28 @@ public void testGenerics() {
                         "{\\"data\\":{\\"generics\\":{\\"message\\":\\"I know it\\"}}}"));
     }
 
+    /**
+     * Send a query in JSON that contains raw unescaped line breaks and tabs inside the "query" string,
+     * which technically is forbidden by the JSON spec, but we want to seamlessly support
+     * queries from Java text blocks, for example, which preserve line breaks and tab characters.
+     */
+    @Test
+    public void testQueryWithNewlinesAndTabs() {
+        String foosRequest = "{\\"query\\": \\"query myquery { \\n generics { \\n \\t message } } \\"}";
+
+        RestAssured.given().when()
+                .accept(MEDIATYPE_JSON)
+                .contentType(MEDIATYPE_JSON)
+                .body(foosRequest)
+                .post("/graphql")
+                .then()
+                .assertThat()
+                .statusCode(200)
+                .and()
+                .body(CoreMatchers.containsString(
+                        "{\\"data\\":{\\"generics\\":{\\"message\\":\\"I know it\\"}}}"));
+    }
+
     @Test
     public void testContext() {
         String query = getPayload("{context}");
diff --git a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLExecutionHandler.java b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLExecutionHandler.java
index 215dec4994b..99af8227e95 100644
--- a/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLExecutionHandler.java
+++ b/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLExecutionHandler.java
@@ -118,7 +118,7 @@ private void handleGet(HttpServerResponse response, RoutingContext ctx) {
     private JsonObject getJsonObjectFromQueryParameters(RoutingContext ctx) throws UnsupportedEncodingException {
         JsonObjectBuilder input = Json.createObjectBuilder();
         // Query
-        String query = readQueryParameter(ctx, QUERY);
+        String query = stripNewlinesAndTabs(readQueryParameter(ctx, QUERY));
         if (query != null && !query.isEmpty()) {
             input.add(QUERY, URLDecoder.decode(query, "UTF8"));
         }
@@ -129,14 +129,14 @@ private JsonObject getJsonObjectFromQueryParameters(RoutingContext ctx) throws U
         }
 
         // Variables
-        String variables = readQueryParameter(ctx, VARIABLES);
+        String variables = stripNewlinesAndTabs(readQueryParameter(ctx, VARIABLES));
         if (variables != null && !variables.isEmpty()) {
             JsonObject jsonObject = toJsonObject(URLDecoder.decode(variables, "UTF8"));
             input.add(VARIABLES, jsonObject);
         }
 
         // Extensions
-        String extensions = readQueryParameter(ctx, EXTENSIONS);
+        String extensions = stripNewlinesAndTabs(readQueryParameter(ctx, EXTENSIONS));
         if (extensions != null && !extensions.isEmpty()) {
             JsonObject jsonObject = toJsonObject(URLDecoder.decode(extensions, "UTF8"));
             input.add(EXTENSIONS, jsonObject);
@@ -148,7 +148,8 @@ private JsonObject getJsonObjectFromQueryParameters(RoutingContext ctx) throws U
     private JsonObject getJsonObjectFromBody(RoutingContext ctx) throws IOException {
 
         String contentType = readContentType(ctx);
-        String body = readBody(ctx);
+        String body = stripNewlinesAndTabs(readBody(ctx));
+
         // If the content type is application/graphql, the query is in the body
         if (contentType != null && contentType.startsWith(APPLICATION_GRAPHQL)) {
             JsonObjectBuilder input = Json.createObjectBuilder();
@@ -188,6 +189,22 @@ private String readQueryParameter(RoutingContext ctx, String parameterName) {
         return null;
     }
 
+    /**
+     * Strip away unescaped tabs and line breaks from the incoming JSON document so that it can be
+     * successfully parsed by a JSON parser.
+     * This does NOT remove properly escaped \\n and \\t inside the document, just the raw characters (ASCII
+     * values 9 and 10). Technically, this is not compliant with the JSON spec,
+     * but we want to seamlessly support queries from Java text blocks, for example,
+     * which preserve line breaks and tab characters.
+     */
+    private String stripNewlinesAndTabs(String input) {
+        if (input == null || input.isEmpty()) {
+            return input;
+        }
+        return input.replaceAll("\\\\n", " ")
+                .replaceAll("\\\\t", " ");
+    }
+
     private boolean hasQueryParameters(RoutingContext ctx) {
         return hasQueryParameter(ctx, QUERY) || hasQueryParameter(ctx, OPERATION_NAME) || hasQueryParameter(ctx, VARIABLES)
                 || hasQueryParameter(ctx, EXTENSIONS);