Mercurial > hg > nginx
comparison src/http/ngx_http_request_body.c @ 9261:f798ecafec05
Request body: error_page 413 handling with HTTP/2 and HTTP/3.
When the client_max_body_size limit in ngx_http_core_find_config_phase()
is hit, nginx calls the ngx_http_discard_request_body() function, which
normally sets the r->discard_body flag while discarding the body, and then
reduces the r->headers_in.content_length_n field to 0 when the body is
completely discarded. As such, the client_max_body_size check is skipped
if the request is redirected to an error page, and this makes it possible
to use "error_page 413" without additional settings.
This only works with HTTP/1.x though. The HTTP/2 and HTTP/3 request body
discarding code paths failed to set r->discard_body or reset
r->headers_in.content_length_n, so configuring "error_page 413" did notwork
without additionally clearing the client_max_body_size limit in the
location with error page.
Fix is to set r->headers_in.content_length_n to 0 in the HTTP/2 and HTTP/3
request body discarding code paths (if there is a body). This is essentially
what happens with HTTP/1.x when the body is completely discarded, and makes
it possible to use "error_page 413" with HTTP/2 and HTTP/3 without additional
settings.
Additionally, r->discard_body flag is also set. For HTTP/2, it is not needed,
but serves as an optimization. For HTTP/3, it ensures that the request body
cannot be read after it was discarded, thus bypassing the client_max_body_size
limit.
Further, the r->discard_body flag is now always set after the request body
is discarded (and not cleared once it is fully discarded). While the body
is being discarded, the new r->discarding_body flag is now used. This
slightly optimizes existing code paths in ngx_http_read_client_request_body()
and ngx_http_discard_request_body(), and also makes it easier to only set
ngx_http_discarded_request_body_handler() for HTTP/1.x.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Sat, 27 Apr 2024 18:22:38 +0300 |
parents | ac5635650bc6 |
children | 388a801e9bb9 |
comparison
equal
deleted
inserted
replaced
9260:ac5635650bc6 | 9261:f798ecafec05 |
---|---|
680 "http set discard body"); | 680 "http set discard body"); |
681 | 681 |
682 #if (NGX_HTTP_V2) | 682 #if (NGX_HTTP_V2) |
683 if (r->stream) { | 683 if (r->stream) { |
684 r->stream->skip_data = 1; | 684 r->stream->skip_data = 1; |
685 | |
686 if (r->headers_in.content_length_n > 0 || r->headers_in.chunked) { | |
687 r->headers_in.content_length_n = 0; | |
688 r->discard_body = 1; | |
689 } | |
690 | |
685 return NGX_OK; | 691 return NGX_OK; |
686 } | 692 } |
687 #endif | 693 #endif |
688 | 694 |
689 #if (NGX_HTTP_V3) | 695 #if (NGX_HTTP_V3) |
690 if (r->http_version == NGX_HTTP_VERSION_30) { | 696 if (r->http_version == NGX_HTTP_VERSION_30) { |
697 | |
698 if (r->headers_in.content_length_n > 0 || r->headers_in.chunked) { | |
699 r->headers_in.content_length_n = 0; | |
700 r->discard_body = 1; | |
701 } | |
702 | |
691 return NGX_OK; | 703 return NGX_OK; |
692 } | 704 } |
693 #endif | 705 #endif |
694 | 706 |
695 if (ngx_http_test_expect(r) != NGX_OK) { | 707 if (ngx_http_test_expect(r) != NGX_OK) { |
704 | 716 |
705 if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) { | 717 if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) { |
706 return NGX_OK; | 718 return NGX_OK; |
707 } | 719 } |
708 | 720 |
721 r->discard_body = 1; | |
722 | |
709 size = r->header_in->last - r->header_in->pos; | 723 size = r->header_in->last - r->header_in->pos; |
710 | 724 |
711 if (size || r->headers_in.chunked) { | 725 if (size || r->headers_in.chunked) { |
712 rc = ngx_http_discard_request_body_filter(r, r->header_in); | 726 rc = ngx_http_discard_request_body_filter(r, r->header_in); |
713 | 727 |
738 if (ngx_handle_read_event(rev, 0) != NGX_OK) { | 752 if (ngx_handle_read_event(rev, 0) != NGX_OK) { |
739 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 753 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
740 } | 754 } |
741 | 755 |
742 r->count++; | 756 r->count++; |
743 r->discard_body = 1; | 757 r->discarding_body = 1; |
744 | 758 |
745 return NGX_OK; | 759 return NGX_OK; |
746 } | 760 } |
747 | 761 |
748 | 762 |
767 | 781 |
768 if (r->lingering_time) { | 782 if (r->lingering_time) { |
769 timer = (ngx_msec_t) r->lingering_time - (ngx_msec_t) ngx_time(); | 783 timer = (ngx_msec_t) r->lingering_time - (ngx_msec_t) ngx_time(); |
770 | 784 |
771 if ((ngx_msec_int_t) timer <= 0) { | 785 if ((ngx_msec_int_t) timer <= 0) { |
772 r->discard_body = 0; | 786 r->discarding_body = 0; |
773 r->lingering_close = 0; | 787 r->lingering_close = 0; |
774 ngx_http_finalize_request(r, NGX_ERROR); | 788 ngx_http_finalize_request(r, NGX_ERROR); |
775 return; | 789 return; |
776 } | 790 } |
777 | 791 |
780 } | 794 } |
781 | 795 |
782 rc = ngx_http_read_discarded_request_body(r); | 796 rc = ngx_http_read_discarded_request_body(r); |
783 | 797 |
784 if (rc == NGX_OK) { | 798 if (rc == NGX_OK) { |
785 r->discard_body = 0; | 799 r->discarding_body = 0; |
786 r->lingering_close = 0; | 800 r->lingering_close = 0; |
787 r->lingering_time = 0; | 801 r->lingering_time = 0; |
788 ngx_http_finalize_request(r, NGX_DONE); | 802 ngx_http_finalize_request(r, NGX_DONE); |
789 return; | 803 return; |
790 } | 804 } |