[PATCH] Make ngx_http_upstream provide a way to expose errors after sending out the response header

agentzh agentzh at gmail.com
Mon Sep 10 05:03:24 UTC 2012


Hello!

According to the current implementation of ngx_http_upstream, there is
almost no way for 3rd-party output body filters and "post_subrequest"
handlers (in the subrequest context) to know if there's any errors
while ngx_http_upstream is processing the upstream response body after
the response header is sent out (in both the buffered and non-buffered
modes).

For example, if

1. a read-timeout happens in the middle of the process of reading the
upstream response body,
2. or the upstream connection is closed prematurely in the same situation,

then ngx_http_upstream will just happily finalize the current request
with the status code 0 (i.e., NGX_OK). This issue already affects at
least our ngx_srcache and ngx_lua modules (originally reported by
Bryan Alger).

Here attaches a patch that makes ngx_http_upstream set
r->headers_out.status to a new error status code to notify the outside
world if there is a problem. Comments will be highly appreciated as
always :)

Thanks!
-agentzh

--- nginx-1.2.3/src/http/ngx_http_upstream.c	2012-08-06 10:34:08.000000000 -0700
+++ nginx-1.2.3-patched/src/http/ngx_http_upstream.c	2012-09-09
21:58:04.727761891 -0700
@@ -2383,7 +2383,7 @@

     if (c->read->timedout) {
         ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
-        ngx_http_upstream_finalize_request(r, u, 0);
+        ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT);
         return;
     }

@@ -2430,13 +2430,17 @@
             if (u->busy_bufs == NULL) {

                 if (u->length == 0
-                    || upstream->read->eof
-                    || upstream->read->error)
+                    || (upstream->read->eof &&
u->headers_in.content_length_n == -1))
                 {
                     ngx_http_upstream_finalize_request(r, u, 0);
                     return;
                 }

+                if (upstream->read->eof || upstream->read->error) {
+                    ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_BAD_GATEWAY);
+                    return;
+                }
+
                 b->pos = b->start;
                 b->last = b->start;
             }
@@ -2710,7 +2714,16 @@
 #if 0
             ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
 #endif
-            ngx_http_upstream_finalize_request(r, u, 0);
+
+            if (p->upstream_done
+                || (p->upstream_eof && u->headers_in.content_length_n == -1))
+            {
+                ngx_http_upstream_finalize_request(r, u, 0);
+
+            } else {
+                ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY);
+            }
+
             return;
         }
     }
@@ -3073,6 +3086,13 @@
         && rc != NGX_HTTP_REQUEST_TIME_OUT
         && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE))
     {
+        if (rc == NGX_ERROR) {
+            r->headers_out.status = NGX_HTTP_INTERNAL_SERVER_ERROR;
+
+        } else {
+            r->headers_out.status = rc;
+        }
+
         rc = 0;
     }
-------------- next part --------------
A non-text attachment was scrubbed...
Name: nginx-1.2.3-nonbuffered-upstream-truncation.patch
Type: application/octet-stream
Size: 2021 bytes
Desc: not available
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20120909/2b608a54/attachment.obj>


More information about the nginx-devel mailing list