comparison src/http/ngx_http_request_body.c @ 7914:9cf043a5d9ca

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.)
author Maxim Dounin <mdounin@mdounin.ru>
date Sun, 29 Aug 2021 22:22:02 +0300
parents 185c86b830ef
children 97cf8284fd19 fac88e160653
comparison
equal deleted inserted replaced
7913:185c86b830ef 7914:9cf043a5d9ca
67 * rb->buf = NULL; 67 * rb->buf = NULL;
68 * rb->free = NULL; 68 * rb->free = NULL;
69 * rb->busy = NULL; 69 * rb->busy = NULL;
70 * rb->chunked = NULL; 70 * rb->chunked = NULL;
71 * rb->received = 0; 71 * rb->received = 0;
72 * rb->filter_need_buffering = 0;
73 * rb->last_sent = 0;
72 * rb->last_saved = 0; 74 * rb->last_saved = 0;
73 */ 75 */
74 76
75 rb->rest = -1; 77 rb->rest = -1;
76 rb->post_handler = post_handler; 78 rb->post_handler = post_handler;
145 if (rc != NGX_OK) { 147 if (rc != NGX_OK) {
146 goto done; 148 goto done;
147 } 149 }
148 } 150 }
149 151
150 if (rb->rest == 0) { 152 if (rb->rest == 0 && rb->last_saved) {
151 /* the whole request body was pre-read */ 153 /* the whole request body was pre-read */
152 r->request_body_no_buffering = 0; 154 r->request_body_no_buffering = 0;
153 post_handler(r); 155 post_handler(r);
154 return NGX_OK; 156 return NGX_OK;
155 } 157 }
173 175
174 if (r->request_body_in_single_buf) { 176 if (r->request_body_in_single_buf) {
175 size += preread; 177 size += preread;
176 } 178 }
177 179
180 if (size == 0) {
181 size++;
182 }
183
178 } else { 184 } else {
179 size = clcf->client_body_buffer_size; 185 size = clcf->client_body_buffer_size;
180 } 186 }
181 187
182 rb->buf = ngx_create_temp_buf(r->pool, size); 188 rb->buf = ngx_create_temp_buf(r->pool, size);
271 { 277 {
272 off_t rest; 278 off_t rest;
273 size_t size; 279 size_t size;
274 ssize_t n; 280 ssize_t n;
275 ngx_int_t rc; 281 ngx_int_t rc;
282 ngx_uint_t flush;
276 ngx_chain_t out; 283 ngx_chain_t out;
277 ngx_connection_t *c; 284 ngx_connection_t *c;
278 ngx_http_request_body_t *rb; 285 ngx_http_request_body_t *rb;
279 ngx_http_core_loc_conf_t *clcf; 286 ngx_http_core_loc_conf_t *clcf;
280 287
281 c = r->connection; 288 c = r->connection;
282 rb = r->request_body; 289 rb = r->request_body;
290 flush = 1;
283 291
284 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, 292 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
285 "http read client request body"); 293 "http read client request body");
286 294
287 for ( ;; ) { 295 for ( ;; ) {
288 for ( ;; ) { 296 for ( ;; ) {
297 if (rb->rest == 0) {
298 break;
299 }
300
289 if (rb->buf->last == rb->buf->end) { 301 if (rb->buf->last == rb->buf->end) {
290 302
291 /* update chains */ 303 /* update chains */
292 304
293 rc = ngx_http_request_body_filter(r, NULL); 305 rc = ngx_http_request_body_filter(r, NULL);
307 } 319 }
308 320
309 return NGX_AGAIN; 321 return NGX_AGAIN;
310 } 322 }
311 323
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
312 ngx_log_error(NGX_LOG_ALERT, c->log, 0, 336 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
313 "busy buffers after request body flush"); 337 "busy buffers after request body flush");
314 338
315 return NGX_HTTP_INTERNAL_SERVER_ERROR; 339 return NGX_HTTP_INTERNAL_SERVER_ERROR;
316 } 340 }
317 341
342 flush = 0;
318 rb->buf->pos = rb->buf->start; 343 rb->buf->pos = rb->buf->start;
319 rb->buf->last = rb->buf->start; 344 rb->buf->last = rb->buf->start;
320 } 345 }
321 346
322 size = rb->buf->end - rb->buf->last; 347 size = rb->buf->end - rb->buf->last;
323 rest = rb->rest - (rb->buf->last - rb->buf->pos); 348 rest = rb->rest - (rb->buf->last - rb->buf->pos);
324 349
325 if ((off_t) size > rest) { 350 if ((off_t) size > rest) {
326 size = (size_t) rest; 351 size = (size_t) rest;
352 }
353
354 if (size == 0) {
355 break;
327 } 356 }
328 357
329 n = c->recv(c, rb->buf->last, size); 358 n = c->recv(c, rb->buf->last, size);
330 359
331 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, 360 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
348 rb->buf->last += n; 377 rb->buf->last += n;
349 r->request_length += n; 378 r->request_length += n;
350 379
351 /* pass buffer to request body filter chain */ 380 /* pass buffer to request body filter chain */
352 381
382 flush = 0;
353 out.buf = rb->buf; 383 out.buf = rb->buf;
354 out.next = NULL; 384 out.next = NULL;
355 385
356 rc = ngx_http_request_body_filter(r, &out); 386 rc = ngx_http_request_body_filter(r, &out);
357 387
369 } 399 }
370 400
371 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, 401 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
372 "http client request body rest %O", rb->rest); 402 "http client request body rest %O", rb->rest);
373 403
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) {
375 break; 413 break;
376 } 414 }
377 415
378 if (!c->read->ready) { 416 if (!c->read->ready || rb->rest == 0) {
379 417
380 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); 418 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
381 ngx_add_timer(c->read, clcf->client_body_timeout); 419 ngx_add_timer(c->read, clcf->client_body_timeout);
382 420
383 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { 421 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
1278 } 1316 }
1279 1317
1280 return NGX_OK; 1318 return NGX_OK;
1281 } 1319 }
1282 1320
1283 /* rb->rest == 0 */ 1321 if (!rb->last_saved) {
1322 return NGX_OK;
1323 }
1284 1324
1285 if (rb->temp_file || r->request_body_in_file_only) { 1325 if (rb->temp_file || r->request_body_in_file_only) {
1286 1326
1287 if (rb->bufs && rb->bufs->buf->in_file) { 1327 if (rb->bufs && rb->bufs->buf->in_file) {
1288 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, 1328 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,