2

If a website user submits an HTML form with: (1) a post method; (2) a multipart/form-data enctype; and, (3) a large attached file, can the server upload a posted file, and send a server generated HTTP response before the file upload is completed, without using AJAX?

That's pretty dense. So, I wrote an example to illustrate what I mean. Let's say there is an image upload form with a caption field.

  <form action="upload-with-caption/" method="post" enctype="multipart/form-data">
    <input type="hidden" id="hiddenInfo" name="hiddenInfo" />
    File:     <input type="file" name="imgFile" id="imgFile" /><br />
    Caption:  <input type="text" name="caption" id="caption" />
        <input type="submit" />
  </form>

I want to store the caption in a database table with the the definition:

[files_table]

  • file_id [uniqueidentifier]
  • file_caption [varchar(500)]
  • file_status [int]

Then I want to upload the file to /root/{unique-id}/filename.ext.

file_status is mapped to a C# enum with the following definition:

enum  FileUploadStatus{
    Error = 0,
    Uploading = 1,
    Uploaded = 2
}

When the form submits, if the file is too large to process in 1 second, I want to send the webpage back a response that says it is currently uploading.

Can I do this with a single synchronous HTTP post?

Note: I will obviously want to check for the status updates later using AJAX, but that is not what this question is asking. I am specifically asking if the file can continue to upload after the response is sent.

smartcaveman
  • 41,281
  • 29
  • 127
  • 212

2 Answers2

6

HTTP is a synchronous protocol.
You cannot send a response until you receive the entire request.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • 2
    This is not entirely true. You can certainly send multiple requests before a single response has been received: http pipelining. http://en.wikipedia.org/wiki/HTTP_pipelining I believe you can also send a response once the headers of a request are received, but the request body is still en route. You will only run into trouble if you start sending response bodies, in anticipation of requests that have not arrived yet. – koush Dec 26 '12 at 18:46
  • YES and NO :-) A HTTP server can serve a response (headers and entity) before consuming the whole request entity but only when returning an error. In other words, it is not possible to ask the client to abort the request entity while accepting a non-error response, only an error response. – eskatos Mar 21 '13 at 19:07
  • Likely the scenario is that you can certainly send a response as soon as you know any kind of request was made, even before the headers are received, but the browser will likely just send the entire body before it even tries to read or parse the response. So the entire will will be uploaded, while TCP for the response stalls, and this will continue until the browser starts processing the response after it has sent the entire file. So the JS cannot access the response until the file is sent in its entirety. – DDS Nov 25 '13 at 22:44
0

Looking at the HTTP specifications alone (RFC's 753x), then the answer is Yes (and, the currently accepted answer is wrong). HTML specifically I don't think have anything to add.

The HTTP/1.1 protocol "relies on the order of response arrival to correspond exactly to the order in which requests are made on the same connection" (RFC 7230 §5.6). Timing has nothing to do with it.

Not only does the protocol allow for early responses, but some message semantics from categories 4xx (Client Error) and 5xx (Server Error) actually expects the response to be sent before the request has completed.

Let's take an example. If you intend to send five trillion billion million gigabytes to a web server (let's assume this number fit whatever data types are in use for the Content-Length header), when would you expect to receive a "413 Payload Too Large" response back? As soon as possible or only after a couple of decades when the request transfer completes? Obviously the sooner the better!

2xx (Successful) responses are a bit different. These responses "indicates that the client's request was successfully received, understood, and accepted" (RFC 7231 §6.3). Sending back this type of response early is likely to confuse the client.

Instead, what you probably want to send back as an early response belongs to the 1xx (Informational) category. These are referred to as "interim responses" meant to supersede but not obsolete the final response.

RFC 7231 §6.2:

The 1xx (Informational) class of status code indicates an interim response for communicating connection status or request progress prior to completing the requested action and sending a final response.

RFC 7230 §5.6:

More than one response message per request only occurs when one or more informational responses precede a final response to the same request.

RFC 7231 §5.1.1 has a great example where a client is about to send a "presumably large" message but instead of immediately sending the body after the head, the client includes an Expect: 100-continue header and then goes into a short paus whilst expecting the server to either reject the message or welcoming the client to carry on by means of responding a "100 Continue" interim response. This then potentially avoids the client having to transmit bytes for nothing. Smart!

Finally, I thought long and hard about when would we ever want to send a 2xx (Successful) response back to the client before the request has completed? I can only come up with one single scenario - and this is certainly not a common case, but I am going to have it stated: If the server has consumed enough of the request in order to take action and the server wish to discard the remaining body because the residue is sufficiently large and at the same time of no more use to the server, then respond 202 Accepted and include a "Connection: close" header.

This is obviously not good for connection re-use and could also easily lead to confused clients and so the payoff why we're responding early should be 1) advantageous enough to mitigate the overhead of establishing a new connection, 2) advantageous enough to offset the danger of crashing clients that was not prepared for an early response, and 3) be well documented.

The "Connection: close" header will explicitly instruct the client to stop sending the request (RFC 7230 §6.3). And due to message framing, the connection is dead anyways as there is no way for the communication to resume with a new message exchange pair over the same connection. Technically speaking, the client can cleanly abort a chunked transfer (RFC 7230 §4.1) and thus save the connection, but this is details and not applicable in the general case.

Community
  • 1
  • 1
Martin Andersson
  • 18,072
  • 9
  • 87
  • 115