[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
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.close
unfortunately 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.