Mercurial > hg > nginx
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 */ |