Search code examples
postrequestundertow

Reading a POST request in Undertow without consuming it


In Undertow I have two handlers, that are chained:

  1. The first handler reads the request and then calls calls the second handler via next.handleRequest(exchange);
  2. The second handler is a proxy handler which send the request to and external server where it is processed.

My problem is the first handler which reads the request. The request headers are no big deal but getting the body data of POST requests is a problem.

Existing solutions as shown in the question How to properly read POST request body in a Handler? consume the request body su that the handler chaining does not work anymore.

How can I read the request body data without consuming it or altering the request in a way that the handler chain does not work afterwards?


Solution

  • I found the problem, in the end it was a missing call to ByteBuffer.flip().

    If someone ever needs such an POST data reader, one can use the following simplified implementation of an AbstractStreamSourceConduit that is able to read the incoming POST data without consuming it:

        exchange.addRequestWrapper(new ConduitWrapper<StreamSourceConduit>() {
    
            @Override
            public StreamSourceConduit wrap(ConduitFactory<StreamSourceConduit> factory, HttpServerExchange exchange) {
                StreamSourceConduit source = factory.create();
                return new AbstractStreamSourceConduit<StreamSourceConduit>(source) {
    
                    ByteArrayOutputStream bout = new ByteArrayOutputStream(8192);
    
                    @Override
                    public int read(ByteBuffer dst) throws IOException {
                        int x = super.read(dst);
                        if (x >= 0) {
                            ByteBuffer dup = dst.duplicate();
                            dup.flip();
                            byte[] data = new byte[x];
                            dup.get(data);
                            bout.write(data);
                        } else {
                            // end of stream reached
                            byte[] data = bout.toByteArray();
                            // ... to something with data
                        }
                        return x;
                    }
    
                };
            }
        });