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.


This the Servlet:
@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");
    }
}


This ist the ReadListener:
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");
    }

}