2

I know that it is possible for a HTTP client to send the next request on a TCP connection even if it had not received the responses for its previous requests - this is called HTTP pipelining.

However, is it acceptable for a HTTP server to start transferring the response before the request had been received completely? Is there an RFC governing this behaviour?

E.g. imagine a service which receives some data via HTTP POST, does some transformation, and responds with the transformed data. If the transformation can be done in a streaming fashion, then the server can start producing the response body even if the request body is incomplete.

1
  • I don't think that any of the widely used HTTP server supports it
    – LatinSuD
    Jan 5, 2018 at 15:27

3 Answers 3

0

I'd be surprised if the standards explicitly described and blessed such an operation (because it's vanishingly rare you can be sure the partial request you have received contains enough information to start producing a response), but I expect it would work in most cases. Any data you send back in response almost certainly won't be read by the client until its finished sending the request, so it'll sit there in the read buffer until the client starts reading, at which point it'll think, "blimey that was fast!" and start chewing away merrily. It won't realise that the data was ALREADY INSIDE THE BUILDING...

I'm sure there's some odd-ball HTTP client implementation that does weird things with its sending loop such that if it finds the socket to be readable before its finished writing the request it freaks out, but the only way to find those is to try it out and see what breaks. That is, pretty much, how everything is done in HTTP-land anyway -- and how new standard behaviours get made (someone does something insane, which becomes popular enough that everyone else has to adapt, so the IETF WG says "fine, we'll make that behaviour the standard, then").

0

I'll add to @wombie answer that doing so would be quite dangerous.

When an http agent (say a reverse proxy or a load balancer, acting between the browser and the final server) receive a response it usually assume that the query was fully sent and that the next query can be send back.

Most reverse proxy agents would not use pipelines when transferring queries to a final backend. That means even if the browser is trying to do a pipeline of n queries the communication between the reverse proxy and the backend will usually be n individual queries and responses, waiting for each response before sending the next query (could use a keep alive connection, but usually not pipelining).

This behavior greatly reduce the risk of HTTP smuggling, with HTTP requests or responses attacks.

Sending your response before receiving the whole body will facilitate the smuggling attack.

To be more clear, imagine you are sending a single query, with a strange syntax and a big body. This body contents looks like another query with a body. And the body of this query-in-the-body is another third query. But this is just one query with a body.

The reverse proxy has a bug on the strange syntax and does not see the body of the first query. For the proxy it's a pipeline of 2 queries. So it sends this first query, without the body, to the backend.

The backend server has no bug on the strange syntax, so it's waiting for the body. But it sends an early response... we'll start having problems. If you'd wait for the complete body before sending the response the attacks would have stop here.

The reverse has a response, so it thinks it can proceed to the next query, and sends back the pseudo-second-query (which contains a body with an hidden third query) to the backend.

The backend thinks it's just the body of the first query, and does something with it, or not. But for the backend it's not a query. Let's say this body has a size of 20k, and that the backend is waiting for a body of 10k. The last 10k is another query for the backend, a query hidden in the body, and this query will be treated as another one, with a new response.

The proxy will receive a response for the hidden third query, and believe it's a response for the second query.

You may exploit this for cache poisoning. The early response is not enough to build an attack (here you also need a strange syntax on the query where the proxy and the backend will have a different perception of the body size), but it makes exploitations more easy. And, of course, you can find this behavior in the wild.

0

I encountered this situation, when trying to implement a check on maximum file size server side.

For example, in golang, the uploaded file that is posted to the server is not some fully uploaded file in the tmp directory, but a stream of bytes that is possible still busy while processing it. If you want to stop the "flood", you have to communicate this to the client. http.MaxBytesReader for example does this by closing the connection, stop reading, and send a response. But the client is not reading the response as it is still uploading its request body, and it does not expect this flow (right?). I saw that the browser just pushed the data again and again, three times after each other to the server. In the browser console I could not see this, but I could see it server side. The browser console simply reported "an empty response" after a long time of waiting, during which I saw three trials server side (could be browser specific).

In short: you have to fully read the request body, before sending a response to the client.

cf. https://stackoverflow.com/a/43785190/2814957

It's tricky to mimic this edge case: you have to make sure that the request body is large enough, and that the server uses streaming. Otherwise the client has already uploaded everything, and is waiting for the response

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .