Skip to content

Commit 34c9c34

Browse files
committed
Add support for multipart POST requests
1 parent e027fc5 commit 34c9c34

File tree

5 files changed

+49
-10
lines changed

5 files changed

+49
-10
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,6 @@ The are a few important components this package provides:
2727
to define which "domain model" views and which mutations you are going to expose.
2828
* GraphQLServlet as an entry point servlet. Use `bindQueryProvider`/`bindMutationProvider` or automatically wire
2929
them in OSGi.
30+
31+
Both GET and POST are supported. In POST, plain request body with a JSON is supported, as well as a multipart with a part
32+
called 'graphql'.

build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ dependencies {
106106

107107
// Servlet
108108
compile 'javax.servlet:javax.servlet-api:3.1.0'
109+
// Multipart support
110+
compile 'commons-fileupload:commons-fileupload:1.3.1'
109111

110112
// GraphQL
111113
compile 'com.graphql-java:graphql-java:2.0.0'

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
version = 0.5.2
1+
version = 0.6.0

src/main/java/graphql/servlet/GraphQLContext.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,15 @@
1818
import lombok.NonNull;
1919
import lombok.RequiredArgsConstructor;
2020
import lombok.Setter;
21+
import org.apache.commons.fileupload.FileItemIterator;
22+
import org.apache.commons.fileupload.FileItemStream;
23+
import org.apache.commons.fileupload.servlet.ServletFileUpload;
2124

2225
import javax.security.auth.Subject;
2326
import javax.servlet.http.HttpServletRequest;
2427
import javax.servlet.http.HttpServletResponse;
28+
import java.util.HashMap;
29+
import java.util.Map;
2530
import java.util.Optional;
2631

2732
@RequiredArgsConstructor
@@ -32,4 +37,7 @@ public class GraphQLContext {
3237
private Optional<HttpServletResponse> response;
3338
@Getter @Setter
3439
private Optional<Subject> subject = Optional.empty();
40+
41+
@Getter @Setter
42+
private Optional<FileItemIterator> files = Optional.empty();
3543
}

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

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
import lombok.Setter;
2626
import lombok.SneakyThrows;
2727
import lombok.extern.slf4j.Slf4j;
28+
import org.apache.commons.fileupload.FileItemIterator;
29+
import org.apache.commons.fileupload.FileItemStream;
30+
import org.apache.commons.fileupload.FileUploadException;
31+
import org.apache.commons.fileupload.servlet.ServletFileUpload;
2832
import org.osgi.service.component.annotations.Component;
2933
import org.osgi.service.component.annotations.Reference;
3034
import org.osgi.service.component.annotations.ReferenceCardinality;
@@ -37,11 +41,10 @@
3741
import javax.servlet.http.HttpServletRequest;
3842
import javax.servlet.http.HttpServletResponse;
3943
import java.io.IOException;
44+
import java.io.InputStream;
4045
import java.io.InputStreamReader;
4146
import java.security.AccessController;
4247
import java.security.PrivilegedAction;
43-
import java.security.PrivilegedActionException;
44-
import java.security.PrivilegedExceptionAction;
4548
import java.util.*;
4649
import java.util.stream.Collectors;
4750

@@ -164,26 +167,49 @@ public static class Request {
164167

165168
@Override
166169
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
170+
GraphQLContext context = createContext(Optional.of(req), Optional.of(resp));
167171
if (req.getPathInfo().contentEquals("/schema.json")) {
168-
query(CharStreams.toString(new InputStreamReader(getClass().getResourceAsStream("introspectionQuery"))), new HashMap<>(), schema, req, resp);
172+
query(CharStreams.toString(new InputStreamReader(getClass().getResourceAsStream("introspectionQuery"))), new HashMap<>(), schema, req, resp, context);
169173
} else {
170-
query(req.getParameter("q"), new HashMap<>(), readOnlySchema, req, resp);
174+
query(req.getParameter("q"), new HashMap<>(), readOnlySchema, req, resp, context);
171175
}
172176
}
173177

174178
@Override
175179
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
176-
Request request = new ObjectMapper().readValue(req.getInputStream(), Request.class);
177-
query(request.query, request.variables, schema, req, resp);
180+
GraphQLContext context = createContext(Optional.of(req), Optional.of(resp));
181+
InputStream inputStream = null;
182+
if (ServletFileUpload.isMultipartContent(req)) {
183+
ServletFileUpload upload = new ServletFileUpload();
184+
try {
185+
FileItemIterator it = upload.getItemIterator(req);
186+
context.setFiles(Optional.of(it));
187+
while (inputStream == null && it.hasNext()) {
188+
FileItemStream stream = it.next();
189+
if (stream.getFieldName().contentEquals("graphql")) {
190+
inputStream = stream.openStream();
191+
}
192+
}
193+
if (inputStream == null) {
194+
throw new ServletException("no query found");
195+
}
196+
} catch (FileUploadException e) {
197+
throw new ServletException("no query found");
198+
}
199+
} else {
200+
// this is not a multipart request
201+
inputStream = req.getInputStream();
202+
}
203+
Request request = new ObjectMapper().readValue(inputStream, Request.class);
204+
query(request.query, request.variables, schema, req, resp, context);
178205
}
179206

180-
private void query(String query, Map<String, Object> variables, GraphQLSchema schema, HttpServletRequest req, HttpServletResponse resp) throws IOException {
181-
GraphQLContext context = createContext(Optional.of(req), Optional.of(resp));
207+
private void query(String query, Map<String, Object> variables, GraphQLSchema schema, HttpServletRequest req, HttpServletResponse resp, GraphQLContext context) throws IOException {
182208
if (Subject.getSubject(AccessController.getContext()) == null && context.getSubject().isPresent()) {
183209
Subject.doAs(context.getSubject().get(), new PrivilegedAction<Void>() {
184210
@Override @SneakyThrows
185211
public Void run() {
186-
query(query, variables, schema, req, resp);
212+
query(query, variables, schema, req, resp, context);
187213
return null;
188214
}
189215
});

0 commit comments

Comments
 (0)