Skip to content

Commit 67d160b

Browse files
committed
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.)
1 parent 2a70921 commit 67d160b

File tree

3 files changed

+182
-26
lines changed

3 files changed

+182
-26
lines changed

src/http/ngx_http_request.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,8 @@ typedef struct {
302302
ngx_chain_t *busy;
303303
ngx_http_chunked_t *chunked;
304304
ngx_http_client_body_handler_pt post_handler;
305+
unsigned filter_need_buffering:1;
306+
unsigned last_sent:1;
305307
unsigned last_saved:1;
306308
} ngx_http_request_body_t;
307309

src/http/ngx_http_request_body.c

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
6969
* rb->busy = NULL;
7070
* rb->chunked = NULL;
7171
* rb->received = 0;
72+
* rb->filter_need_buffering = 0;
73+
* rb->last_sent = 0;
7274
* rb->last_saved = 0;
7375
*/
7476

@@ -147,7 +149,7 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
147149
}
148150
}
149151

150-
if (rb->rest == 0) {
152+
if (rb->rest == 0 && rb->last_saved) {
151153
/* the whole request body was pre-read */
152154
r->request_body_no_buffering = 0;
153155
post_handler(r);
@@ -175,6 +177,10 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
175177
size += preread;
176178
}
177179

180+
if (size == 0) {
181+
size++;
182+
}
183+
178184
} else {
179185
size = clcf->client_body_buffer_size;
180186
}
@@ -273,19 +279,25 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
273279
size_t size;
274280
ssize_t n;
275281
ngx_int_t rc;
282+
ngx_uint_t flush;
276283
ngx_chain_t out;
277284
ngx_connection_t *c;
278285
ngx_http_request_body_t *rb;
279286
ngx_http_core_loc_conf_t *clcf;
280287

281288
c = r->connection;
282289
rb = r->request_body;
290+
flush = 1;
283291

284292
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
285293
"http read client request body");
286294

287295
for ( ;; ) {
288296
for ( ;; ) {
297+
if (rb->rest == 0) {
298+
break;
299+
}
300+
289301
if (rb->buf->last == rb->buf->end) {
290302

291303
/* update chains */
@@ -309,12 +321,25 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
309321
return NGX_AGAIN;
310322
}
311323

324+
if (rb->filter_need_buffering) {
325+
clcf = ngx_http_get_module_loc_conf(r,
326+
ngx_http_core_module);
327+
ngx_add_timer(c->read, clcf->client_body_timeout);
328+
329+
if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
330+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
331+
}
332+
333+
return NGX_AGAIN;
334+
}
335+
312336
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
313337
"busy buffers after request body flush");
314338

315339
return NGX_HTTP_INTERNAL_SERVER_ERROR;
316340
}
317341

342+
flush = 0;
318343
rb->buf->pos = rb->buf->start;
319344
rb->buf->last = rb->buf->start;
320345
}
@@ -326,6 +351,10 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
326351
size = (size_t) rest;
327352
}
328353

354+
if (size == 0) {
355+
break;
356+
}
357+
329358
n = c->recv(c, rb->buf->last, size);
330359

331360
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)
350379

351380
/* pass buffer to request body filter chain */
352381

382+
flush = 0;
353383
out.buf = rb->buf;
354384
out.next = NULL;
355385

@@ -371,11 +401,19 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
371401
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
372402
"http client request body rest %O", rb->rest);
373403

374-
if (rb->rest == 0) {
404+
if (flush) {
405+
rc = ngx_http_request_body_filter(r, NULL);
406+
407+
if (rc != NGX_OK) {
408+
return rc;
409+
}
410+
}
411+
412+
if (rb->rest == 0 && rb->last_saved) {
375413
break;
376414
}
377415

378-
if (!c->read->ready) {
416+
if (!c->read->ready || rb->rest == 0) {
379417

380418
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
381419
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)
12801318
return NGX_OK;
12811319
}
12821320

1283-
/* rb->rest == 0 */
1321+
if (!rb->last_saved) {
1322+
return NGX_OK;
1323+
}
12841324

12851325
if (rb->temp_file || r->request_body_in_file_only) {
12861326

0 commit comments

Comments
 (0)