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 }