23

I have a django app hosted via Nginx and uWsgi. In a certain very simple request, I get different behaviour for GET and POST, which should not be the case.

The uWsgi daemon log:

[pid: 32454|app: 0|req: 5/17] 127.0.0.1 () {36 vars in 636 bytes} [Tue Oct 19 11:18:36 2010] POST /buy/76d4f520ae82e1dfd35564aed64a885b/a_2/10/ => generated 80 bytes in 3 msecs (HTTP/1.0 440) 1 headers in 76 bytes (0 async switches on async core 0)
[pid: 32455|app: 0|req: 5/18] 127.0.0.1 () {32 vars in 521 bytes} [Tue Oct 19 11:18:50 2010] GET /buy/76d4f520ae82e1dfd35564aed64a885b/a_2/10/ => generated 80 bytes in 3 msecs (HTTP/1.0 440) 1 headers in 76 bytes (0 async switches on async core 0)

The Nginx accesslog:

127.0.0.1 - - [19/Oct/2010:18:18:36 +0200] "POST /buy/76d4f520ae82e1dfd35564aed64a885b/a_2/10/ HTTP/1.0" 440 0 "-" "curl/7.19.5 (i486-pc-linux-gnu) libcurl/7.19.5 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.15"
127.0.0.1 - - [19/Oct/2010:18:18:50 +0200] "GET /buy/76d4f520ae82e1dfd35564aed64a885b/a_2/10/ HTTP/1.0" 440 80 "-" "curl/7.19.5 (i486-pc-linux-gnu) libcurl/7.19.5 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.15"

The Nginx errorlog:

2010/10/19 18:18:36 [error] 4615#0: *5 readv() failed (104: Connection reset by peer) while reading upstream, client: 127.0.0.1, server: localhost, request: "POST /buy/76d4f520ae82e1dfd35564aed64a885b/a_2/10/ HTTP/1.0", upstream: "uwsgi://unix:sock/uwsgi.sock:", host: "localhost:9201"

In essence, Nginx somewhere loses the response if I use POST, not so if I use GET.

Anybody knows something about that?

Ulf
  • 17,492
  • 5
  • 19
  • 13
  • See also http://stackoverflow.com/questions/7273725/django-error-when-send-emails-thrue-google-apps/7279065 – Joe Shaw Sep 07 '12 at 14:50

4 Answers4

28

Pass --post-buffering 1 to uwsgi

This will automatically buffer all the http body > 1 byte

The problem is raised by the way nginx manages upstream disconnections

Joe Shaw
  • 22,066
  • 16
  • 70
  • 92
roberto
  • 305
  • 3
  • 2
  • 4
    FWIW, @roberto is the author of uwsgi. – Joe Shaw Sep 07 '12 at 14:51
  • This is really the correct answer. It is an option to uwsgi and you probably want to use it conjunction with --limit-post. http://projects.unbit.it/uwsgi/wiki/Doc – Derrick Petzold Sep 21 '12 at 20:11
  • I'm having a similar problem (only it has nothing to do with POSTs). Tried, the post-buffering and also @ehabkost's ForcePostHandler, but no luck. This is driving me nuts, please help!!! http://stackoverflow.com/questions/18667370/django-social-auth-gives-502-error-with-google-openid-but-only-with-a-few-users – Tony Lâmpada Sep 08 '13 at 12:22
  • Never mind! I was able to solve the problem by adding `buffer-size = 8192` to uwsgi. Boy, was that hard to figure out... – Tony Lâmpada Sep 08 '13 at 13:05
  • 8
    Wouldn't that be a big performance issue, though? uWSGI's doc says this will save all HTTP body bigger than the limit specified. Saving the body to disk for every POST request could be an issue. – John Smith Optional Aug 09 '14 at 11:21
5

I hit the same issue, but on my case I can't disable "uwsgi_pass_request_body" as most times (but not always) my app do need the POST data.

This is the workaround I found, while this issue is not fixed in uwsgi: http://permalink.gmane.org/gmane.comp.python.wsgi.uwsgi.general/813

import django.core.handlers.wsgi
class ForcePostHandler(django.core.handlers.wsgi.WSGIHandler):
    """Workaround for: http://lists.unbit.it/pipermail/uwsgi/2011-February/001395.html
    """
    def get_response(self, request):
        request.POST # force reading of POST data
        return super(ForcePostHandler, self).get_response(request)

application = ForcePostHandler()
ehabkost
  • 411
  • 3
  • 5
5

I am facing the same issues. I tried all solutions above, but they were not working. Ignoring the response body in my case is simply not an option.

Apparently it is a bug with nginx and uwsgi when dealing with POST requests whose response is smaller than 4052 bytes

What solved it for me was adding "--pep3333-input" to the parameter list of uwsgi. After that all POSTs are returned correctly.

Versions of nginx/uwsgi I'm using:

$ nginx -V
nginx: nginx version: nginx/0.9.6

$ uwsgi --version
uWSGI 0.9.7
lullis
  • 304
  • 4
  • 7
  • Thanks for the answer. Just adding "--pep3333-input" to uwsgi didn't fix it. I also had to add "--post-buffering 4096" as referenced here: http://comments.gmane.org/gmane.comp.python.wsgi.uwsgi.general/812 – freb Mar 08 '12 at 22:56
  • 1
    According to Roberto, the `--pep3333-input` is now obsolete and doesn't do anything on newer versions of uwsgi. I removed the flag and things are still running correctly. Perhaps you are facing some other issue that you managed to solve with `--post-buffering`? – lullis Mar 10 '12 at 06:20
  • If the issue in the question is the same as the issue I had, the problem was that if your your python code never reads the POST data (in django, this would be accessing request.POST somewhere in your view), then things get screwed up. If you tell UWSGI to buffer the POST data with the --post-buffering 1 parameter as roberto says, then your POST requests won't error no matter what you are doing in your view. – freb Aug 10 '12 at 21:47
1

After a lucky find in further research (http://answerpot.com/showthread.php?577619-Several%20Bugs/Page2) I found something that helped...

Supplying the uwsgi_pass_request_body off; parameter in the Nginx conf resolves this problem...

Ulf
  • 17,492
  • 5
  • 19
  • 13