summaryrefslogtreecommitdiffhomepage
path: root/src/http/ngx_http_request_body.c
diff options
context:
space:
mode:
authorMaxim Dounin <mdounin@mdounin.ru>2021-08-29 22:22:02 +0300
committerMaxim Dounin <mdounin@mdounin.ru>2021-08-29 22:22:02 +0300
commit67d160bf25e02ba6679bb6c3b9cbdfeb29b759de (patch)
treeff76312fe9cba7e3c339e71a053c1888d1bdab45 /src/http/ngx_http_request_body.c
parent2a709213800fd3fd2809881374eb110562b53c08 (diff)
downloadnginx-67d160bf25e02ba6679bb6c3b9cbdfeb29b759de.tar.gz
nginx-67d160bf25e02ba6679bb6c3b9cbdfeb29b759de.tar.bz2
Request body: reading body buffering in filters.
If a filter wants to buffer the request body during reading (for example, to check an external scanner), it can now do so. To make it possible, the code now checks rb->last_saved (introduced in the previous change) along with rb->rest == 0. Since in HTTP/2 this requires flow control to avoid overflowing the request body buffer, so filters which need buffering have to set the rb->filter_need_buffering flag on the first filter call. (Note that each filter is expected to call the next filter, so all filters will be able set the flag if needed.)
Diffstat (limited to 'src/http/ngx_http_request_body.c')
-rw-r--r--src/http/ngx_http_request_body.c48
1 files changed, 44 insertions, 4 deletions
diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c
index 4a31db0bc..89a4c7492 100644
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -69,6 +69,8 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
* rb->busy = NULL;
* rb->chunked = NULL;
* rb->received = 0;
+ * rb->filter_need_buffering = 0;
+ * rb->last_sent = 0;
* rb->last_saved = 0;
*/
@@ -147,7 +149,7 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
}
}
- if (rb->rest == 0) {
+ if (rb->rest == 0 && rb->last_saved) {
/* the whole request body was pre-read */
r->request_body_no_buffering = 0;
post_handler(r);
@@ -175,6 +177,10 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
size += preread;
}
+ if (size == 0) {
+ size++;
+ }
+
} else {
size = clcf->client_body_buffer_size;
}
@@ -273,6 +279,7 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
size_t size;
ssize_t n;
ngx_int_t rc;
+ ngx_uint_t flush;
ngx_chain_t out;
ngx_connection_t *c;
ngx_http_request_body_t *rb;
@@ -280,12 +287,17 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
c = r->connection;
rb = r->request_body;
+ flush = 1;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http read client request body");
for ( ;; ) {
for ( ;; ) {
+ if (rb->rest == 0) {
+ break;
+ }
+
if (rb->buf->last == rb->buf->end) {
/* update chains */
@@ -309,12 +321,25 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
return NGX_AGAIN;
}
+ if (rb->filter_need_buffering) {
+ clcf = ngx_http_get_module_loc_conf(r,
+ ngx_http_core_module);
+ ngx_add_timer(c->read, clcf->client_body_timeout);
+
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ return NGX_AGAIN;
+ }
+
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
"busy buffers after request body flush");
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
+ flush = 0;
rb->buf->pos = rb->buf->start;
rb->buf->last = rb->buf->start;
}
@@ -326,6 +351,10 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
size = (size_t) rest;
}
+ if (size == 0) {
+ break;
+ }
+
n = c->recv(c, rb->buf->last, size);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
@@ -350,6 +379,7 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
/* pass buffer to request body filter chain */
+ flush = 0;
out.buf = rb->buf;
out.next = NULL;
@@ -371,11 +401,19 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http client request body rest %O", rb->rest);
- if (rb->rest == 0) {
+ if (flush) {
+ rc = ngx_http_request_body_filter(r, NULL);
+
+ if (rc != NGX_OK) {
+ return rc;
+ }
+ }
+
+ if (rb->rest == 0 && rb->last_saved) {
break;
}
- if (!c->read->ready) {
+ if (!c->read->ready || rb->rest == 0) {
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
ngx_add_timer(c->read, clcf->client_body_timeout);
@@ -1280,7 +1318,9 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
return NGX_OK;
}
- /* rb->rest == 0 */
+ if (!rb->last_saved) {
+ return NGX_OK;
+ }
if (rb->temp_file || r->request_body_in_file_only) {