-
Notifications
You must be signed in to change notification settings - Fork 202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
org.takes.Request.body().read() never returns -1 to indicate end of request body #1116
Comments
@golszewski86 many thanks for the report! do you know how to fix this? would be great if you can submit a pull request |
By the way it is even worse, as the content (e.g. POST) is never consumed the next request in a keep alive session will simply fill up the buffers... so additionally to providing a stream that only reads either chunked or content length data, takes should take care that additional data is disposed (unless connection-close is send). |
I now created the following wrapper, maybe worth to add to the library directly?
|
I found another issue, if you ever close the stream (e.g. try with resources) this closes the underlying socket as well :-\ Improved decorator:
|
@laeubi maybe you can help and fix this issue? |
Yes I'll try to came up with a possible fix |
Just as a reference from the Spec: Http 1.0:
Http 1.1:
|
Consider the following example of Takes server and HTTP made to it:
What it does
AtomicBoolean done
value is set totrue
bar
and timeout 5 secondsAtomicBoolean done
totrue
, effectively stopping the serverWhat is the expected result
The expected result would be application logging the following information:
What is the actual result
What happens
The method
java.io.InputStream.read()
, according to the Java documentation, returns next byte from the stream, or -1 if the end of the stream has been reached However, it blocks until more input is available. In case of the Takes framework, the read() method in eventually delegated to the nativejava.net.SocketInputStream.socketRead0(FileDescriptor, byte[], int, int, int)
method which blocks after the request body ("bar" in this case) has been read.Basically this is the correct behavior for a TCP connection, because while the connection remains open the server socket does not know if the client is going to send more data, or when to expect more data. This is why the socket input stream blocks indefinitely (or until defined timeout). However, the client has already sent all the data and is awaiting a response.
After 5 seconds the client decides to close the connection because of the timeout. Then the
java.io.InputStream.read()
method finally returns -1 because now the socket "knows" the end of the stream has been reached. The server then prints "Returning response" and returns HTTP 204 No Content response. However, on the client side the request has already timed out and the client will not process response from the server.What should happen
The TCP socket may not know whether to expect more data coming from the client, but the HTTP protocol features a
Content-Length
header containing information about number of bytes in the request body. Thejava.net.SocketInputStream
is not aware about HTTP protocol, but the Takes framework should be. Theorg.takes.Request.body()
method should return an instance ofInputStream
that is aware of theContent-Length
header value, and itsread()
method returns -1 if the number of bytes equal to theContent-Length
header value has been read.Note this has been implemented in the
org.takes.rq.RqPrint
class, which usesorg.takes.rq.RqChunk
andorg.takes.rq.RqLengthAware
classes to stop reading from the input stream once the expected number of bytes has been received; however,org.takes.http.FtBasic
(or rather the underlyingorg.takes.http.BkBasic
) return aorg.takes.Request
instance with InputStream simply delegating to the native TCP stream.The text was updated successfully, but these errors were encountered: