I have implemented a servlet that has the following properties:
1) asyncSupported = true
2) @MultipartConfig
3) Uses a ReadListener to upload a file without blocking
The problem I have is that in the ReadListener the parts have disappeared. Obviously invoking request.getInputStream() in the Servlet causes request.getParts() in the ReadListener to return an empty list.
I found out that in the class io.undertow.servlet.spec.HttpServletRequestImpl the flag readStarted controls whether parts may be read or not. Obviously it is not possible to get the parts once you have called getInputStream(). I can't find the place in the spec where this is forbidden.
What I don't understand here is that this source code works using glassfish, but not using Wildfly 18 (with undertow). Can someone tell me why this is so? And maybe offer an alternative implementation.
@WebServlet(urlPatterns = { "/noblock" }, asyncSupported = true)
@MultipartConfig(maxFileSize = 1024 * 1024 * 10, maxRequestSize = 1024 * 1024 * 30)
public class AsyncServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private Logger log = Logger.getLogger(AsyncServlet.class.getName());
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
log.finest("doPost Start");
AsyncContext asyncContext = request.startAsync();
ServletInputStream input = request.getInputStream();
input.setReadListener(new ExampleReadListener(asyncContext));
PrintWriter writer = response.getWriter();
writer.println("Non blocking Servlet completed");
writer.flush();
log.finest("doPost End");
}
}
public class ExampleReadListener implements ReadListener {
private Logger log = Logger.getLogger(ExampleReadListener.class.getName());
private AsyncContext asyncContext;
public ExampleReadListener(AsyncContext pAsyncContext) {
this.asyncContext = pAsyncContext;
}
@Override
public void onAllDataRead() throws IOException {
log.finest("onAllDataRead started");
try {
asyncContext.getResponse().getWriter().write("\n All data has been read!");
} catch (Exception e) {
e.printStackTrace();
}
asyncContext.complete();
log.finest("onAllDataRead ended");
}
@Override
public void onDataAvailable() throws IOException {
log.finest("onDataAvailable started");
HttpServletRequest request = (HttpServletRequest) asyncContext.getRequest();
ServletInputStream input = null;
Collection<Part> parts = null;
try {
asyncContext.getResponse().getWriter().write("Some data available!\n");
parts = request.getParts();
log.finest("Parts = " + parts);
input = request.getInputStream();
} catch (Exception e) {
e.printStackTrace();
}
int length = -1;
byte buffer[] = new byte[1024];
while (input.isReady() && (length = input.read(buffer)) != -1) {
String data = new String(buffer, 0, length);
asyncContext.getResponse().getWriter().write(data);
}
log.finest("onDataAvailable ended");
}
@Override
public void onError(Throwable arg0) {
log.finest("onError started");
asyncContext.complete();
log.finest("onError ended");
}
}