views:

329

answers:

3

I have form with file upload. The files to be uploaded actually are pictures and videos, so they can be quite big. I have logic which based on headers and first 1KB can determine if the rest will be processed or immediately rejected. In the later case I'd like to redirect client to error page without having to wait for upload to finish.

The case is, that just sending response before POST is complete doesn't seem to work. The redirect gets ignored and if I close connection, browser complains with "Connection reset by peer" error.

So the question is: is it even possible to do that in pure HTTP (without JavaScript on client-side), and if so, how?

+3  A: 

Have a look at django ticket #10850 - "Impossible to stop a large file upload mid-stream". Doesn't solve the problem, but at least it should help you understand it.

sdolan
As far as I can see, they're talking either of stopping the processing on server side or of reseting the connection, neither is good option for me, because neither allows immediate redirect.
vartec
I think the bug report at least answers your question of whether or not it's possible to do it with pure HTTP, but maybe I'm just not being clever enough :).Is Javascript not an option, or are you just trying to avoid using it if you don't have to?
sdolan
It's required to work on wide range of mobile devices, actually excluding iPhone, BB and Android, which get native apps. So assumption is, that having JS is not guaranteed.
vartec
So what I would do is:1. Get a regular POST solution in place waits for the upload to finish, analyzes it, then return the appropriate success/failure message.2. Layer on some AJAX that will terminate the upload if it's bad, and show an appropriate success/error message.3. When you feel the value add of having a pure HTTP solution is worth the week or so you'll spend implementing it correctly, then go deep on building that (and post your findings here!). SpliFF has demonstrated that it should be at least possible in some browsers, it'll take a lot of research and testing to prove it.
sdolan
+11  A: 

The HTTP/1.1 protocol does allow for this, just in a really bizarre and messed up way. You need to apply the following 3 step proceedure:

  1. Immediately (abruptly) close the connection, store a server-side flag for the client session
  2. Use the flag to detect an attempt to resend the same form data, the spec recommends the client to do this automatically
  3. Send an error status with a redirect (like 302 Temporarily Moved)

This SHOULD work because as outlined below the client is expected to retry a connection at least once after being cut off unexpectedly. On the retry attempt(s) it is expected to only send the headers, then wait and watch for an error response and abort sending the body if it gets one.

http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html

8.2.4 Client Behavior if Server Prematurely Closes Connection

If an HTTP/1.1 client sends a request which includes a request body, but which does not include an Expect request-header field with the "100-continue" expectation, and if the client is not directly connected to an HTTP/1.1 origin server, and if the client sees the connection close before receiving any status from the server, the client SHOULD retry the request. If the client does retry this request, it MAY use the following "binary exponential backoff" algorithm to be assured of obtaining a reliable response:

  1. Initiate a new connection to the server

  2. Transmit the request-headers

  3. Initialize a variable R to the estimated round-trip time to the
     server (e.g., based on the time it took to establish the
     connection), or to a constant value of 5 seconds if the round-
     trip time is not available.

  4. Compute T = R * (2**N), where N is the number of previous
     retries of this request.

  5. Wait either for an error response from the server, or for T
     seconds (whichever comes first)

  6. If no error response is received, after T seconds transmit the
     body of the request.

  7. If client sees that the connection is closed prematurely,
     repeat from step 1 until the request is accepted, an error
     response is received, or the user becomes impatient and
     terminates the retry process.

If at any point an error status is received, the client

  - SHOULD NOT continue and

  - SHOULD close the connection if it has not completed sending the
    request message.

Gotchas:

  1. That's what the spec says browswers SHOULD do. Who knows what browsers ACTUALLY do in this case? Not me. You'll need to run some tests.
  2. The spec makes a specific mention that this behaviour only applies "if the client is not directly connected to an HTTP/1.1 origin server". That seems a really bizarre requirement which in practice means you may need to fake your server response headers to pretend you're a proxy or HTTP/1.0 server.
  3. Certain intermediary protocols like fast-cgi may not activate your script until the request is complete. In this event you'll actually need a real low-level socket server.
  4. This whole process is messy and convoluted and may not even work. You'd be better off using AJAX in my opinion. Still, you did ask if it could be done without JS.
SpliFF
I must say, this answer is quite helpful. Nevertheless, I doubt that I'll even try to implement that, as the service I have is generally stateless and behind non-sticky load-balancer.
vartec
A: 
  1. use PCEL uploadprogress extension if you use apache
  2. create an file to poll meta via Ajax, and return trueor false based on your condition, you could also get the temp_name file and check for the 1kb meta.
  3. the ajax call need to be binded with an function which uses HTML meta-refresh headers to redirect or stay until the uploads done.


Checkout the uploadprogress examples.

openprojdevel