comparison src/http/ngx_http_request_body.c @ 7692:0f7f1a509113

Request body: allowed large reads on chunk boundaries. If some additional data from a pipelined request happens to be read into the body buffer, we copy it to r->header_in or allocate an additional large client header buffer for it.
author Maxim Dounin <mdounin@mdounin.ru>
date Thu, 06 Aug 2020 05:02:55 +0300
parents 08ff2e10ae92
children f5a2af0e7079
comparison
equal deleted inserted replaced
7691:08ff2e10ae92 7692:0f7f1a509113
10 #include <ngx_http.h> 10 #include <ngx_http.h>
11 11
12 12
13 static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r); 13 static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r);
14 static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r); 14 static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
15 static ngx_int_t ngx_http_copy_pipelined_header(ngx_http_request_t *r,
16 ngx_buf_t *buf);
15 static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r); 17 static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r);
16 static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r); 18 static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r);
17 static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r, 19 static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r,
18 ngx_buf_t *b); 20 ngx_buf_t *b);
19 static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r); 21 static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r);
377 379
378 return NGX_AGAIN; 380 return NGX_AGAIN;
379 } 381 }
380 } 382 }
381 383
384 if (ngx_http_copy_pipelined_header(r, rb->buf) != NGX_OK) {
385 return NGX_HTTP_INTERNAL_SERVER_ERROR;
386 }
387
382 if (c->read->timer_set) { 388 if (c->read->timer_set) {
383 ngx_del_timer(c->read); 389 ngx_del_timer(c->read);
384 } 390 }
385 391
386 if (!r->request_body_no_buffering) { 392 if (!r->request_body_no_buffering) {
387 r->read_event_handler = ngx_http_block_reading; 393 r->read_event_handler = ngx_http_block_reading;
388 rb->post_handler(r); 394 rb->post_handler(r);
389 } 395 }
396
397 return NGX_OK;
398 }
399
400
401 static ngx_int_t
402 ngx_http_copy_pipelined_header(ngx_http_request_t *r, ngx_buf_t *buf)
403 {
404 size_t n;
405 ngx_buf_t *b;
406 ngx_chain_t *cl;
407 ngx_http_connection_t *hc;
408 ngx_http_core_srv_conf_t *cscf;
409
410 b = r->header_in;
411 n = buf->last - buf->pos;
412
413 if (buf == b || n == 0) {
414 return NGX_OK;
415 }
416
417 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
418 "http body pipelined header: %uz", n);
419
420 /*
421 * if there is a pipelined request in the client body buffer,
422 * copy it to the r->header_in buffer if there is enough room,
423 * or allocate a large client header buffer
424 */
425
426 if (n > (size_t) (b->end - b->last)) {
427
428 hc = r->http_connection;
429
430 if (hc->free) {
431 cl = hc->free;
432 hc->free = cl->next;
433
434 b = cl->buf;
435
436 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
437 "http large header free: %p %uz",
438 b->pos, b->end - b->last);
439
440 } else {
441 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
442
443 b = ngx_create_temp_buf(r->connection->pool,
444 cscf->large_client_header_buffers.size);
445 if (b == NULL) {
446 return NGX_ERROR;
447 }
448
449 cl = ngx_alloc_chain_link(r->connection->pool);
450 if (cl == NULL) {
451 return NGX_ERROR;
452 }
453
454 cl->buf = b;
455
456 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
457 "http large header alloc: %p %uz",
458 b->pos, b->end - b->last);
459 }
460
461 cl->next = hc->busy;
462 hc->busy = cl;
463 hc->nbusy++;
464
465 r->header_in = b;
466
467 if (n > (size_t) (b->end - b->last)) {
468 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
469 "too large pipelined header after reading body");
470 return NGX_ERROR;
471 }
472 }
473
474 ngx_memcpy(b->last, buf->pos, n);
475
476 b->last += n;
477 r->request_length -= n;
390 478
391 return NGX_OK; 479 return NGX_OK;
392 } 480 }
393 481
394 482
635 723
636 b.temporary = 1; 724 b.temporary = 1;
637 725
638 for ( ;; ) { 726 for ( ;; ) {
639 if (r->headers_in.content_length_n == 0) { 727 if (r->headers_in.content_length_n == 0) {
640 r->read_event_handler = ngx_http_block_reading; 728 break;
641 return NGX_OK;
642 } 729 }
643 730
644 if (!r->connection->read->ready) { 731 if (!r->connection->read->ready) {
645 return NGX_AGAIN; 732 return NGX_AGAIN;
646 } 733 }
670 757
671 if (rc != NGX_OK) { 758 if (rc != NGX_OK) {
672 return rc; 759 return rc;
673 } 760 }
674 } 761 }
762
763 if (ngx_http_copy_pipelined_header(r, &b) != NGX_OK) {
764 return NGX_HTTP_INTERNAL_SERVER_ERROR;
765 }
766
767 r->read_event_handler = ngx_http_block_reading;
768
769 return NGX_OK;
675 } 770 }
676 771
677 772
678 static ngx_int_t 773 static ngx_int_t
679 ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b) 774 ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b)
680 { 775 {
681 size_t size; 776 size_t size;
682 ngx_int_t rc; 777 ngx_int_t rc;
683 ngx_http_request_body_t *rb; 778 ngx_http_request_body_t *rb;
779 ngx_http_core_srv_conf_t *cscf;
684 780
685 if (r->headers_in.chunked) { 781 if (r->headers_in.chunked) {
686 782
687 rb = r->request_body; 783 rb = r->request_body;
688 784
733 829
734 if (rc == NGX_AGAIN) { 830 if (rc == NGX_AGAIN) {
735 831
736 /* set amount of data we want to see next time */ 832 /* set amount of data we want to see next time */
737 833
738 r->headers_in.content_length_n = rb->chunked->length; 834 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
835
836 r->headers_in.content_length_n = ngx_max(rb->chunked->length,
837 (off_t) cscf->large_client_header_buffers.size);
739 break; 838 break;
740 } 839 }
741 840
742 /* invalid */ 841 /* invalid */
743 842
901 ngx_int_t rc; 1000 ngx_int_t rc;
902 ngx_buf_t *b; 1001 ngx_buf_t *b;
903 ngx_chain_t *cl, *out, *tl, **ll; 1002 ngx_chain_t *cl, *out, *tl, **ll;
904 ngx_http_request_body_t *rb; 1003 ngx_http_request_body_t *rb;
905 ngx_http_core_loc_conf_t *clcf; 1004 ngx_http_core_loc_conf_t *clcf;
1005 ngx_http_core_srv_conf_t *cscf;
906 1006
907 rb = r->request_body; 1007 rb = r->request_body;
908 1008
909 if (rb->rest == -1) { 1009 if (rb->rest == -1) {
910 1010
914 rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t)); 1014 rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
915 if (rb->chunked == NULL) { 1015 if (rb->chunked == NULL) {
916 return NGX_HTTP_INTERNAL_SERVER_ERROR; 1016 return NGX_HTTP_INTERNAL_SERVER_ERROR;
917 } 1017 }
918 1018
1019 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
1020
919 r->headers_in.content_length_n = 0; 1021 r->headers_in.content_length_n = 0;
920 rb->rest = 3; 1022 rb->rest = cscf->large_client_header_buffers.size;
921 } 1023 }
922 1024
923 out = NULL; 1025 out = NULL;
924 ll = &out; 1026 ll = &out;
925 1027
1022 1124
1023 if (rc == NGX_AGAIN) { 1125 if (rc == NGX_AGAIN) {
1024 1126
1025 /* set rb->rest, amount of data we want to see next time */ 1127 /* set rb->rest, amount of data we want to see next time */
1026 1128
1027 rb->rest = rb->chunked->length; 1129 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
1130
1131 rb->rest = ngx_max(rb->chunked->length,
1132 (off_t) cscf->large_client_header_buffers.size);
1028 1133
1029 break; 1134 break;
1030 } 1135 }
1031 1136
1032 /* invalid */ 1137 /* invalid */