Mercurial > hg > nginx-quic
comparison src/http/modules/ngx_http_range_filter_module.c @ 7507:ea05113adbdb
Range filter: fixed loss of incoming chain links.
Filters are not allowed to change incoming chain links, and should allocate
their own links if any modifications are needed. Nevertheless
ngx_http_range_singlepart_body() modified incoming chain links in some
cases, notably at the end of the requested range.
No problems caused by this are currently known, mostly because of
limited number of possible modifications and the position of the range
body filter in the filter chain. Though this behaviour is clearly incorrect
and tests demonstrate that it can at least cause some proxy buffers being
lost when using proxy_force_ranges, leading to less effective handling
of responses.
Fix is to always allocate new chain links in ngx_http_range_singlepart_body().
Links are explicitly freed to ensure constant memory usage with long-lived
requests.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 13 May 2019 22:44:02 +0300 |
parents | a2f5e25d6a28 |
children | c30a20e06c21 |
comparison
equal
deleted
inserted
replaced
7506:ee36940cfb0f | 7507:ea05113adbdb |
---|---|
698 static ngx_int_t | 698 static ngx_int_t |
699 ngx_http_range_singlepart_body(ngx_http_request_t *r, | 699 ngx_http_range_singlepart_body(ngx_http_request_t *r, |
700 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) | 700 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) |
701 { | 701 { |
702 off_t start, last; | 702 off_t start, last; |
703 ngx_int_t rc; | |
703 ngx_buf_t *buf; | 704 ngx_buf_t *buf; |
704 ngx_chain_t *out, *cl, **ll; | 705 ngx_chain_t *out, *cl, *tl, **ll; |
705 ngx_http_range_t *range; | 706 ngx_http_range_t *range; |
706 | 707 |
707 out = NULL; | 708 out = NULL; |
708 ll = &out; | 709 ll = &out; |
709 range = ctx->ranges.elts; | 710 range = ctx->ranges.elts; |
719 | 720 |
720 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 721 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
721 "http range body buf: %O-%O", start, last); | 722 "http range body buf: %O-%O", start, last); |
722 | 723 |
723 if (ngx_buf_special(buf)) { | 724 if (ngx_buf_special(buf)) { |
724 *ll = cl; | 725 |
725 ll = &cl->next; | 726 tl = ngx_alloc_chain_link(r->pool); |
727 if (tl == NULL) { | |
728 return NGX_ERROR; | |
729 } | |
730 | |
731 tl->buf = buf; | |
732 tl->next = NULL; | |
733 | |
734 *ll = tl; | |
735 ll = &tl->next; | |
736 | |
726 continue; | 737 continue; |
727 } | 738 } |
728 | 739 |
729 if (range->end <= start || range->start >= last) { | 740 if (range->end <= start || range->start >= last) { |
730 | 741 |
762 buf->last -= (size_t) (last - range->end); | 773 buf->last -= (size_t) (last - range->end); |
763 } | 774 } |
764 | 775 |
765 buf->last_buf = (r == r->main) ? 1 : 0; | 776 buf->last_buf = (r == r->main) ? 1 : 0; |
766 buf->last_in_chain = 1; | 777 buf->last_in_chain = 1; |
767 *ll = cl; | 778 |
768 cl->next = NULL; | 779 tl = ngx_alloc_chain_link(r->pool); |
769 | 780 if (tl == NULL) { |
770 break; | 781 return NGX_ERROR; |
771 } | 782 } |
772 | 783 |
773 *ll = cl; | 784 tl->buf = buf; |
774 ll = &cl->next; | 785 tl->next = NULL; |
786 | |
787 *ll = tl; | |
788 ll = &tl->next; | |
789 | |
790 continue; | |
791 } | |
792 | |
793 tl = ngx_alloc_chain_link(r->pool); | |
794 if (tl == NULL) { | |
795 return NGX_ERROR; | |
796 } | |
797 | |
798 tl->buf = buf; | |
799 tl->next = NULL; | |
800 | |
801 *ll = tl; | |
802 ll = &tl->next; | |
775 } | 803 } |
776 | 804 |
777 if (out == NULL) { | 805 if (out == NULL) { |
778 return NGX_OK; | 806 return NGX_OK; |
779 } | 807 } |
780 | 808 |
781 return ngx_http_next_body_filter(r, out); | 809 rc = ngx_http_next_body_filter(r, out); |
810 | |
811 while (out) { | |
812 cl = out; | |
813 out = out->next; | |
814 ngx_free_chain(r->pool, cl); | |
815 } | |
816 | |
817 return rc; | |
782 } | 818 } |
783 | 819 |
784 | 820 |
785 static ngx_int_t | 821 static ngx_int_t |
786 ngx_http_range_multipart_body(ngx_http_request_t *r, | 822 ngx_http_range_multipart_body(ngx_http_request_t *r, |