|Re: [jetty-users] Problem reading POST body with embedded Jetty 12.0.x
Hello Simone,Thanks for this. I looked at your code but have trouble to really relate it to my use case which is basically a servlet doPost that tries to read the POST body synchronously. I do understand your point about exhausting the request body and will try to use your code to improve on mine. I always thought the container would pickup on me closing the InputStream and would take care of this but obviously that is not the case.
BUT:This is not an intermittent issue. The post handling code has been in place since about 2012 and even predates our move to Jetty (version 6 at the time). It has always worked flawlessly in Jetty <= 11.x. Now with 12.0.x it fails 100% of the time. To reproduce I will startup the server on my laptop, hit it with the curl command line POST and it blocks, always. So in that scenario the post is the absolute first request the server handles.
Using HTTP 1.1 I was able to execute the same curl POST at least 30 times in a row without any issues. Using Jetty 11 (and versions before it) and http/2 it ihas been in daily production use on about 15 different servers and has never caused any issues (this is part of a daily backup/restore/mirror mechanism).
I don't mind sharing code but the code is quite obfuscated. The application consists of 1 servlet instance and uses its own hierarchy of handling/delegating objects implementing a Servlet-like interface. The POST handlers in question are quite deeply embedded in that structure. The only thing that happens along the way to the request before being handled in the endpoint (if that is a proper name for it) is calling methods like getRequestURL, getQueryString, getServletPath and getSession(false) to disect the request and allow proper routing through the structure.
The handler code is: /* Code inside the handlePost method of the Handler object.The request ends up here after being inspected thoroughly while passing through the application structure.
*/ val in = request.getInputStream val bin = new BufferedInputStream(in) val zip = new ZipInputStream(bin) FileScriptContainer.importBackend(cache,root,scriptRepos,importOptions,importListener,zip) zip.closeunfortunately the importBackend call does a LOT. It expands many entries directly to files but for others its creates databases and tables and populates the tables with records all depending on the type of ZIP entry. Basically it has a while loop at the top that goes through the entries, inspects them and passes them on to the proper handling methods. The method returns when the entries are exhausted.
I am convinced there is something in my setup that is causing this. Maybe my embedding code is wrong. Maybe I do not have the right JAR files on the classpath. Any pointers that could help me locate the problem would be helpful.
Cheers, Silvio On 12-09-2023 20:25, Simone Bordet wrote:
Silvio,On Mon, Sep 11, 2023 at 2:16 PM Silvio Bierman via jetty-users <jetty-users@xxxxxxxxxxx> wrote:It appears that all handling of POST requests with ZIP-content as payload in our application is broken with Jetty 12 (I tried both 12.0.0 and 12.0.1). We use an embedded Jetty-12 with ee10 and http/2. Using Jetty 11 the code works as expected. We post a ZIP-file from the command line using Curl to the application. The handling code wraps request.getInputStream in a BufferedInputStream wrapped in a ZipInputStream and starts reading ZipEntry objects with getNextEntry until this returns null. With Jetty 12 this code only manages to read the first part of the POST-body and then blocks indefinitely. This is not a multi-part request, the ZIP-content is simply used as the request payload.I have written a test case similar to what you describe, as it passes cleanly, although careful coding is necessary. The test case is here: https://github.com/eclipse/jetty.project/pull/10502/files#diff-0016119d5f34ccf50bb7920bead0bf5e175027028bb45bcc212bb52ba0996f23 The careful coding is necessary because reading until getNextEntry() returns null is not enough. You must also read from the request InputStream until you read -1 (this is line 65 in the test). This guarantees that Jetty knows that all the content has been consumed, and it does not fail the request because not all the content has been read. Without the read until -1, the tests randomly fail, more often for HTTP/2, but definitely also for HTTP/1.1, both in Jetty 12 and in Jetty 10/11. At this point, you have to show us your code. Please file an issue and post your code there, as GitHub is better for this. From the Jetty point of view, with the test I linked, seems that everything is correct, provided the careful coding is present.
Back to the top