[PATCH] ngx_http_upstream state machine fixes

agentzh agentzh at gmail.com
Wed Mar 21 13:42:02 UTC 2012


Hello!

I've just found that ngx_http_upstream seems to assume that the
upstream request is already fully sent (i.e., fully flushed into the
socket send buffers) after the first read event on the upstream
connection, and in this case, ngx_http_upstream_send_request_handler
will just silently refuse to re-send the requests on subsequent write
events even if the request has not been fully sent out yet, hence
leading to a hang.

This was observed when doing pipelined requests atop ngx_http_upstream
where the remote server can start sending back response data *before*
all the request data is flushed out (the latter can be trivially
emulated by our mockeagain tool: https://github.com/agentzh/mockeagain
).

I've attached a patch that (hopefully) fixes this issue by introducing
an extra 1-bit "request_all_sent" flag to ngx_http_upstream_t, which
can be set to 1 after ngx_output_chain returns NGX_OK in
ngx_http_upstream_send_request. I know there is already a
"request_sent" flag which indicates whether there is the first attempt
of sending out the request) :)

Feedback will be highly appreciated :)

Thanks!
-agentzh

diff -ur nginx-1.0.11/src/http/ngx_http_upstream.c
nginx-1.0.11-patched/src/http/ngx_http_upstream.c
--- nginx-1.0.11/src/http/ngx_http_upstream.c	2011-12-14
02:34:34.000000000 +0800
+++ nginx-1.0.11-patched/src/http/ngx_http_upstream.c	2012-03-21
21:20:17.333111806 +0800
@@ -1385,6 +1385,8 @@

     /* rc == NGX_OK */

+    u->request_all_sent = 1;
+
     if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
         if (ngx_tcp_push(c->fd) == NGX_ERROR) {
             ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
@@ -1451,7 +1453,7 @@

 #endif

-    if (u->header_sent) {
+    if (u->request_all_sent) {
         u->write_event_handler = ngx_http_upstream_dummy_handler;

         (void) ngx_handle_write_event(c->write, 0);
Only in nginx-1.0.11-patched/src/http: ngx_http_upstream.c~
diff -ur nginx-1.0.11/src/http/ngx_http_upstream.h
nginx-1.0.11-patched/src/http/ngx_http_upstream.h
--- nginx-1.0.11/src/http/ngx_http_upstream.h	2011-11-01
22:18:10.000000000 +0800
+++ nginx-1.0.11-patched/src/http/ngx_http_upstream.h	2012-03-21
21:18:21.041237173 +0800
@@ -313,6 +313,7 @@
     unsigned                         buffering:1;

     unsigned                         request_sent:1;
+    unsigned                         request_all_sent:1;
     unsigned                         header_sent:1;
 };
-------------- next part --------------
A non-text attachment was scrubbed...
Name: nginx-1.0.11-upstream_pipelining.patch
Type: application/octet-stream
Size: 1310 bytes
Desc: not available
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20120321/90a92047/attachment.obj>


More information about the nginx-devel mailing list