[nginx] Request body: handling of body after unbuffered reading.

Maxim Dounin mdounin at mdounin.ru
Sat Apr 27 15:56:47 UTC 2024


details:   http://freenginx.org/hg/nginx/rev/ac5635650bc6
branches:  
changeset: 9260:ac5635650bc6
user:      Maxim Dounin <mdounin at mdounin.ru>
date:      Sat Apr 27 18:22:07 2024 +0300
description:
Request body: handling of body after unbuffered reading.

As long as unbuffered reading of the request body was used, and an attempt
to read the request body is made again, such as when redirecting the request
to an error page, the request body is now cleared to make sure it can be
used safely.

Further, the r->reading_body flag, if it is still set, is cleared (along with
disabling keepalive and enabling lingering close), so the code which uses
the request body, such as when proxying, is not confused and doesn't try
to use "Transfer-Encoding: chunked".

Note that this change makes the workaround for HTTP/2 issues with unbuffered
proxying and error pages, as introduced in 7561:9f1f9d6e056a, ineffective
(since r->reading_body now cleared along with r->reading_body_no_buffering).
Though the workaround is anyway not needed after 7924:d9e009b39596, hence
it is removed.

This makes it safer to use complex processing of error pages with unbuffered
proxying.

diffstat:

 src/http/ngx_http_request.h      |   1 +
 src/http/ngx_http_request_body.c |  14 ++++++++++++++
 src/http/v2/ngx_http_v2.c        |   7 -------
 3 files changed, 15 insertions(+), 7 deletions(-)

diffs (66 lines):

diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -305,6 +305,7 @@ typedef struct {
     ngx_chain_t                      *busy;
     ngx_http_chunked_t               *chunked;
     ngx_http_client_body_handler_pt   post_handler;
+    unsigned                          no_buffering:1;
     unsigned                          filter_need_buffering:1;
     unsigned                          last_sent:1;
     unsigned                          last_saved:1;
diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -44,6 +44,18 @@ ngx_http_read_client_request_body(ngx_ht
 
     if (r != r->main || r->request_body || r->discard_body) {
         r->request_body_no_buffering = 0;
+
+        if (r->request_body && r->request_body->no_buffering) {
+            r->headers_in.content_length_n = 0;
+            r->request_body->bufs = NULL;
+
+            if (r->reading_body) {
+                r->reading_body = 0;
+                r->keepalive = 0;
+                r->lingering_close = 1;
+            }
+        }
+
         post_handler(r);
         return NGX_OK;
     }
@@ -72,6 +84,7 @@ ngx_http_read_client_request_body(ngx_ht
      *     rb->busy = NULL;
      *     rb->chunked = NULL;
      *     rb->received = 0;
+     *     rb->no_buffering = 0;
      *     rb->filter_need_buffering = 0;
      *     rb->last_sent = 0;
      *     rb->last_saved = 0;
@@ -220,6 +233,7 @@ done:
         } else {
             /* rc == NGX_AGAIN */
             r->reading_body = 1;
+            r->request_body->no_buffering = 1;
         }
 
         r->read_event_handler = ngx_http_block_reading;
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -1078,13 +1078,6 @@ ngx_http_v2_state_read_data(ngx_http_v2_
     r = stream->request;
     fc = r->connection;
 
-    if (r->reading_body && !r->request_body_no_buffering) {
-        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
-                       "skipping http2 DATA frame");
-
-        return ngx_http_v2_state_skip_padded(h2c, pos, end);
-    }
-
     if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
                        "skipping http2 DATA frame");



More information about the nginx-devel mailing list