-
Hello, I have a hyper server that sends data as response to GET requests. The amount of data is 500K (or more). This does not happen with a go http server, which always reads the body to avoid issues with badly behaving clients. Also does not happen with a rust server implemented in rocket. The client in this case is python asyncio based, either aiohttp or httpx. But only under special circumstances. Note that in this case, the size of the body is 0! But still I need to read it away, or I see errors on the client side. I did a tcpdump trace. This showed the following difference between hyper reading the body or not when the error (on the client side) occurs: In the case where the body is read explicitly, I see the connection SYN & ACK, the GET request, a number of packets of various sizes containing the data sent back to the client (some have a PUSH flag). Sometimes the connection is closed by the client (FIN), sometimes it is reused for the next request. The last packet seen is an ACK packet , from client to server, for the last received data. Here is the tcpdump output where the error occurs. The server uses port 10081.
|
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 1 reply
-
The RST is terminating the connection since the request body was not fully read, and the server can't continue to reuse that connection. Hyper is designed to be a low level interface. If you want to always read request bodies, you would need to write that logic in your handler (or use a higher level server API that wraps hyper and does it for you). Rocket is presumably an example of one of those higher level APIs that does so. |
Beta Was this translation helpful? Give feedback.
-
I tested it with another client, same hyper server, not reading the body. Here I do 2 GET requests, and I observe that the connection is reused and the server does not send RST. Also, if I actually read the body, then len() is always 0 (the client does not really send data in this case). Should the server, at TCP level, not send the ACK before sending RST in any case? |
Beta Was this translation helpful? Give feedback.
-
Is one client sending The kernel handles ACKs and RSTs - I don't think there's anything the userspace library can do about that. |
Beta Was this translation helpful? Give feedback.
-
I haven't checked the code, but my hypothesis is that Hyper is going to read from the stream until it sees the end of the headers. If the final read happens to also include the empty chunked body, it detects that it's read the entire request and is willing to keep the connection open. If it doesn't see the empty chunked body in the final read (e.g. because it was sent in a separate TCP packet that hasn't yet been read by the kernel) it will terminate the connection after responding if the handler code does not force it to process the body. |
Beta Was this translation helpful? Give feedback.
-
Thanks for your explanation. In that case, one should always do this and read the body, In hyper this then could lead to an abort of the handling and not properly finish sending the reply. It is no problem to add that to our code. Maybe one of the examples should reflect this? |
Beta Was this translation helpful? Give feedback.
I haven't checked the code, but my hypothesis is that Hyper is going to read from the stream until it sees the end of the headers. If the final read happens to also include the empty chunked body, it detects that it's read the entire request and is willing to keep the connection open. If it doesn't see the empty chunked body in the final read (e.g. because it was sent in a separate TCP packet that hasn't yet been read by the kernel) it will terminate the connection after responding if the handler code does not force it to process the body.