nginx upload client_max_body_size issue
Asked Answered
T

3

122

I'm running nginx/ruby-on-rails and I have a simple multipart form to upload files. Everything works fine until I decide to restrict the maximum size of files I want uploaded. To do that, I set the nginx client_max_body_size to 1m (1MB) and expect a HTTP 413 (Request Entity Too Large) status in response when that rule breaks.

The problem is that when I upload a 1.2 MB file, instead of displaying the HTTP 413 error page, the browser hangs a bit and then dies with a "Connection was reset while the page was loading" message.

I've tried just about every option there is that nginx offers, nothing seems to work. Does anyone have any ideas about this?

Here's my nginx.conf:

worker_processes  1;
timer_resolution  1000ms;
events {
    worker_connections  1024;
}

http {
    passenger_root /the_passenger_root;
    passenger_ruby /the_ruby;

    include       mime.types;
    default_type  application/octet-stream;

    sendfile           on;
    keepalive_timeout  65;

    server {
      listen 80;
      server_name www.x.com;
      client_max_body_size 1M;
      passenger_use_global_queue on;
      root /the_root;
      passenger_enabled on;

      error_page 404 /404.html;
      error_page 413 /413.html;    
    }    
}

Thanks.


**Edit**

Environment/UA: Windows XP/Firefox 3.6.13

Teresetereshkova answered 9/2, 2011 at 15:46 Comment(0)
P
133

nginx "fails fast" when the client informs it that it's going to send a body larger than the client_max_body_size by sending a 413 response and closing the connection.

Most clients don't read responses until the entire request body is sent. Because nginx closes the connection, the client sends data to the closed socket, causing a TCP RST.

If your HTTP client supports it, the best way to handle this is to send an Expect: 100-Continue header. Nginx supports this correctly as of 1.2.7, and will reply with a 413 Request Entity Too Large response rather than 100 Continue if Content-Length exceeds the maximum body size.

Proliferate answered 16/11, 2012 at 21:9 Comment(8)
Oh, I should point out that this answer assumes that the client is sending Content-Length rather than doing Transfer-Encoding: chunked.Proliferate
The nginx author posted a patch to fix this on the mailing list: nginx.2469901.n2.nabble.com/… No word whether it will be added to the 1.2.x stable branch, though.Proliferate
Thanks, that actually explains a lot. Certainly looks like Expect is the way to go for large requests.Teresetereshkova
Updated my answer to note that the patch I mentioned earlier was committed and incorporated into the 1.2.7 release.Proliferate
Just to save the time of looking for a nice syntax (like I spent): request.setHeader(HttpHeaders.EXPECT, CONTINUE); with import org.apache.http.HttpHeaders; and import static org.jboss.netty.handler.codec.http.HttpHeaders.Values.CONTINUE;Tuning
make sure to check and included configs such as sites-enabled. Any setting in there will override the this parameter in the main configThermion
I set client max body size value but still have the problem! any idea? I'm using Rails.Jeffryjeffy
+1 for explaining that "nginx 'fails fast' when the client informs it that it's going to send a body larger than the client_max_body_size ..." That sentence helped me understand why my chunked requests were still being rejected by the server, something that was not explained by the related resources I saw elsewhere online.Fredricfredrick
G
49

Does your upload die at the very end? 99% before crashing? Client body and buffers are key because nginx must buffer incoming data. The body configs (data of the request body) specify how nginx handles the bulk flow of binary data from multi-part-form clients into your app's logic.

The clean setting frees up memory and consumption limits by instructing nginx to store incoming buffer in a file and then clean this file later from disk by deleting it.

Set body_in_file_only to clean and adjust buffers for the client_max_body_size. The original question's config already had sendfile on, increase timeouts too. I use the settings below to fix this, appropriate across your local config, server, & http contexts.

client_body_in_file_only clean;
client_body_buffer_size 32K;

client_max_body_size 300M;

sendfile on;
send_timeout 300s;
Gastrin answered 23/1, 2013 at 8:52 Comment(5)
Even if this does result in nginx returning a proper HTTP 413, UA will still end up sending the entirety of request body, will it not? In that case I think it's worth trying the approach @joe-shaw suggested.Teresetereshkova
@Teresetereshkova when it looks we got 99% upload complete before NGINX "fail fast," I agree with you. In this case, all signs are positive surrounding the request object, i.e. diagnosis is that internal server application logic is fine--whatever runs behind Nginx. So while it's likely the request has been well formed, our need is then to consider why NGINX chokes on response. client_max_body_size should be the first config option we look at, then consider the buffers, because with a large enough upload the correct solution depends on how much memory our server can handle as well.Gastrin
@Bent Cardan. This approach seemed to be the better one and I tried it. But I'm still getting a 413 error after about 20 seconds for a 4mb file. My upspeeds cannot manage 4 MB in 20secs so it is happening after data has been flowing for quite a bit. Thoughts?Anthony
I have added the changes in nginx.conf file _client_max_body_size 300M; sendfile on;send_timeout 300s; _ Its working perfectly for me ThanksMobcap
Solution works for me on openshift php7 nginx.Yeeyegg
F
7

From the documentation:

It is necessary to keep in mind that the browsers do not know how to correctly show this error.

I suspect this is what's happening, if you inspect the HTTP to-and-fro using tools such as Firebug or Live HTTP Headers (both Firefox extensions) you'll be able to see what's really going on.

Foxe answered 9/2, 2011 at 17:21 Comment(4)
I've come across that here, too: forum.nginx.org/read.php?2,2620 Where the nginx author says people could try changing lingering_time/lingering_timeout - both of which had no effect in my case. Besides, I just don't see how there could be a persistent timeout issue when I'm uploading 1.2MB file with a 1MB limit easily having a steady 5Mbps connection. I've sniffed the response and it does send the 413 page with "Connection: close" header, but the connection doesn't seem to close.Teresetereshkova
I guess I just have a hard time believing that even though there is a perfectly valid 413 HTTP status, it doesn't fire in browsers. I've googled a lot of places where people can't get rid of that page, and I never even saw it.Teresetereshkova
If you disable passenger, does it close the connection?Overboard
Well, I compared the responses with and without passenger. When everything runs normally and I upload a file several times larger (~14MB) than my 1MB restriction I get 413 response multiple times (because client keeps sending chunks) and the final "Connection reset" does look like a timeout. Without passenger I get one 413 instant response and all progress stops, but I still see "Connection reset" page, not my static 413.html or anything that implies "Entity Too Large"Teresetereshkova

© 2022 - 2024 — McMap. All rights reserved.