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,