Skip to content

Commit 062cdce

Browse files
committed
Require multipart content type for multipart requests (fix #76)
1 parent c391c51 commit 062cdce

File tree

3 files changed

+51
-58
lines changed

3 files changed

+51
-58
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ apply plugin: 'biz.aQute.bnd.builder'
7070
apply plugin: 'com.jfrog.bintray'
7171
apply plugin: 'maven-publish'
7272
apply plugin: 'idea'
73+
apply plugin: 'maven'
7374

7475
jar {
7576
manifest {

src/main/java/graphql/servlet/GraphQLServlet.java

Lines changed: 46 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@
33
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
44
import com.fasterxml.jackson.core.JsonParser;
55
import com.fasterxml.jackson.core.type.TypeReference;
6-
import com.fasterxml.jackson.databind.DeserializationContext;
7-
import com.fasterxml.jackson.databind.InjectableValues;
8-
import com.fasterxml.jackson.databind.JsonDeserializer;
9-
import com.fasterxml.jackson.databind.ObjectMapper;
10-
import com.fasterxml.jackson.databind.ObjectReader;
6+
import com.fasterxml.jackson.databind.*;
117
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
128
import com.google.common.io.ByteStreams;
139
import graphql.ExecutionInput;
@@ -29,23 +25,10 @@
2925
import javax.servlet.http.HttpServletRequest;
3026
import javax.servlet.http.HttpServletResponse;
3127
import javax.servlet.http.Part;
32-
import java.io.BufferedInputStream;
33-
import java.io.ByteArrayOutputStream;
34-
import java.io.IOException;
35-
import java.io.InputStream;
36-
import java.io.Writer;
28+
import java.io.*;
3729
import java.security.AccessController;
3830
import java.security.PrivilegedAction;
39-
import java.util.ArrayList;
40-
import java.util.Collection;
41-
import java.util.Collections;
42-
import java.util.HashMap;
43-
import java.util.Iterator;
44-
import java.util.LinkedHashMap;
45-
import java.util.List;
46-
import java.util.Map;
47-
import java.util.Objects;
48-
import java.util.Optional;
31+
import java.util.*;
4932
import java.util.function.BiConsumer;
5033
import java.util.function.Consumer;
5134
import java.util.function.Function;
@@ -64,12 +47,17 @@ public abstract class GraphQLServlet extends HttpServlet implements Servlet, Gra
6447
public static final int STATUS_BAD_REQUEST = 400;
6548

6649
protected abstract GraphQLSchemaProvider getSchemaProvider();
50+
6751
protected abstract GraphQLContext createContext(Optional<HttpServletRequest> request, Optional<HttpServletResponse> response);
52+
6853
protected abstract Object createRootObject(Optional<HttpServletRequest> request, Optional<HttpServletResponse> response);
54+
6955
protected abstract ExecutionStrategyProvider getExecutionStrategyProvider();
56+
7057
protected abstract Instrumentation getInstrumentation();
7158

7259
protected abstract GraphQLErrorHandler getGraphQLErrorHandler();
60+
7361
protected abstract PreparsedDocumentProvider getPreparsedDocumentProvider();
7462

7563
private final LazyObjectMapperBuilder lazyObjectMapperBuilder;
@@ -126,9 +114,8 @@ public GraphQLServlet(ObjectMapperConfigurer objectMapperConfigurer, List<GraphQ
126114
final Object rootObject = createRootObject(Optional.of(request), Optional.of(response));
127115

128116
try {
129-
Collection<Part> parts = request.getParts();
130-
if (!parts.isEmpty()) {
131-
final Map<String, List<Part>> fileItems = parts.stream()
117+
if (request.getContentType().equals("multipart/form-data") && !request.getParts().isEmpty()) {
118+
final Map<String, List<Part>> fileItems = request.getParts().stream()
132119
.collect(Collectors.toMap(
133120
Part::getName,
134121
Collections::singletonList,
@@ -189,18 +176,7 @@ public GraphQLServlet(ObjectMapperConfigurer objectMapperConfigurer, List<GraphQ
189176
response.setStatus(STATUS_BAD_REQUEST);
190177
log.info("Bad POST multipart request: no part named \"graphql\" or \"query\"");
191178
} else {
192-
// this is not a multipart request
193-
InputStream inputStream = request.getInputStream();
194-
195-
if (!inputStream.markSupported()) {
196-
inputStream = new BufferedInputStream(inputStream);
197-
}
198-
199-
if (isBatchedQuery(inputStream)) {
200-
doBatchedQuery(getGraphQLRequestMapper().readValues(inputStream), getSchemaProvider().getSchema(request), context, rootObject, request, response);
201-
} else {
202-
doQuery(getGraphQLRequestMapper().readValue(inputStream), getSchemaProvider().getSchema(request), context, rootObject, request, response);
203-
}
179+
handleNonMultipartRequest(request, response, context, rootObject);
204180
}
205181
} catch (Exception e) {
206182
log.info("Bad POST request: parsing failed", e);
@@ -209,6 +185,21 @@ public GraphQLServlet(ObjectMapperConfigurer objectMapperConfigurer, List<GraphQ
209185
};
210186
}
211187

188+
private void handleNonMultipartRequest(HttpServletRequest request, HttpServletResponse response, GraphQLContext context, Object rootObject) throws Exception {
189+
// this is not a multipart request
190+
InputStream inputStream = request.getInputStream();
191+
192+
if (!inputStream.markSupported()) {
193+
inputStream = new BufferedInputStream(inputStream);
194+
}
195+
196+
if (isBatchedQuery(inputStream)) {
197+
doBatchedQuery(getGraphQLRequestMapper().readValues(inputStream), getSchemaProvider().getSchema(request), context, rootObject, request, response);
198+
} else {
199+
doQuery(getGraphQLRequestMapper().readValue(inputStream), getSchemaProvider().getSchema(request), context, rootObject, request, response);
200+
}
201+
}
202+
212203
protected ObjectMapper getMapper() {
213204
return lazyObjectMapperBuilder.getMapper();
214205
}
@@ -285,12 +276,12 @@ private Optional<Part> getFileItem(Map<String, List<Part>> fileItems, String nam
285276
private GraphQL newGraphQL(GraphQLSchema schema) {
286277
ExecutionStrategyProvider executionStrategyProvider = getExecutionStrategyProvider();
287278
return GraphQL.newGraphQL(schema)
288-
.queryExecutionStrategy(executionStrategyProvider.getQueryExecutionStrategy())
289-
.mutationExecutionStrategy(executionStrategyProvider.getMutationExecutionStrategy())
290-
.subscriptionExecutionStrategy(executionStrategyProvider.getSubscriptionExecutionStrategy())
291-
.instrumentation(getInstrumentation())
292-
.preparsedDocumentProvider(getPreparsedDocumentProvider())
293-
.build();
279+
.queryExecutionStrategy(executionStrategyProvider.getQueryExecutionStrategy())
280+
.mutationExecutionStrategy(executionStrategyProvider.getMutationExecutionStrategy())
281+
.subscriptionExecutionStrategy(executionStrategyProvider.getSubscriptionExecutionStrategy())
282+
.instrumentation(getInstrumentation())
283+
.preparsedDocumentProvider(getPreparsedDocumentProvider())
284+
.build();
294285
}
295286

296287
private void doQuery(GraphQLRequest graphQLRequest, GraphQLSchema schema, GraphQLContext context, Object rootObject, HttpServletRequest httpReq, HttpServletResponse httpRes) throws Exception {
@@ -348,7 +339,7 @@ private void query(String query, String operationName, Map<String, Object> varia
348339
graphQLResponse.setResponse(response);
349340
responseHandler.handle(graphQLResponse);
350341

351-
if(getGraphQLErrorHandler().errorsPresent(errors)) {
342+
if (getGraphQLErrorHandler().errorsPresent(errors)) {
352343
runCallbacks(operationCallbacks, c -> c.onError(context, operationName, query, variables, data, errors, extensions));
353344
} else {
354345
runCallbacks(operationCallbacks, c -> c.onSuccess(context, operationName, query, variables, data, extensions));
@@ -367,7 +358,7 @@ private Map<String, Object> createResultFromDataErrorsAndExtensions(Object data,
367358
result.put("errors", getGraphQLErrorHandler().processErrors(errors));
368359
}
369360

370-
if(extensions != null){
361+
if (extensions != null) {
371362
result.put("extensions", extensions);
372363
}
373364

@@ -380,16 +371,16 @@ private <R> List<R> runListeners(Function<? super GraphQLServletListener, R> act
380371
}
381372

382373
return listeners.stream()
383-
.map(listener -> {
384-
try {
385-
return action.apply(listener);
386-
} catch (Throwable t) {
387-
log.error("Error running listener: {}", listener, t);
388-
return null;
389-
}
390-
})
391-
.filter(Objects::nonNull)
392-
.collect(Collectors.toList());
374+
.map(listener -> {
375+
try {
376+
return action.apply(listener);
377+
} catch (Throwable t) {
378+
log.error("Error running listener: {}", listener, t);
379+
return null;
380+
}
381+
})
382+
.filter(Objects::nonNull)
383+
.collect(Collectors.toList());
393384
}
394385

395386
private <T> void runCallbacks(List<T> callbacks, Consumer<T> action) {
@@ -425,7 +416,8 @@ private static Map<String, Object> deserializeVariablesObject(Object variables,
425416
return genericVariables;
426417
} else if (variables instanceof String) {
427418
try {
428-
return mapper.readValue((String) variables, new TypeReference<Map<String, Object>>() {});
419+
return mapper.readValue((String) variables, new TypeReference<Map<String, Object>>() {
420+
});
429421
} catch (IOException e) {
430422
throw new RuntimeException(e);
431423
}

src/main/java/graphql/servlet/SimpleGraphQLServlet.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,25 +65,25 @@ public SimpleGraphQLServlet(GraphQLSchemaProvider schemaProvider, ExecutionStrat
6565
this.instrumentation = instrumentation;
6666
}
6767

68-
if(errorHandler == null) {
68+
if (errorHandler == null) {
6969
this.errorHandler = new DefaultGraphQLErrorHandler();
7070
} else {
7171
this.errorHandler = errorHandler;
7272
}
7373

74-
if(contextBuilder == null) {
74+
if (contextBuilder == null) {
7575
this.contextBuilder = new DefaultGraphQLContextBuilder();
7676
} else {
7777
this.contextBuilder = contextBuilder;
7878
}
7979

80-
if(rootObjectBuilder == null) {
80+
if (rootObjectBuilder == null) {
8181
this.rootObjectBuilder = new DefaultGraphQLRootObjectBuilder();
8282
} else {
8383
this.rootObjectBuilder = rootObjectBuilder;
8484
}
8585

86-
if(preparsedDocumentProvider == null) {
86+
if (preparsedDocumentProvider == null) {
8787
this.preparsedDocumentProvider = NoOpPreparsedDocumentProvider.INSTANCE;
8888
} else {
8989
this.preparsedDocumentProvider = preparsedDocumentProvider;

0 commit comments

Comments
 (0)