From: Joe Orton Date: Tue, 23 Aug 2005 08:36:16 +0000 (+0000) Subject: Merge r233493 from trunk: X-Git-Tag: 2.0.55~79 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=09a1a2e6e14609564332839c22545d0c7f5c39e4;p=thirdparty%2Fapache%2Fhttpd.git Merge r233493 from trunk: * modules/http/http_protocol.c (ap_byterange_filter): Refuse to byterange any response which may require the consumption of arbitrary amounts of memory. PR: 29962 Reviewed by: jorton, trawick, niq git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.0.x@239378 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index b3d06bcdce1..a8c5e5aaf07 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ -*- coding: utf-8 -*- Changes with Apache 2.0.55 + *) Fix cases where the byterange filter would buffer responses + into memory. PR 29962. [Joe Orton] + *) mod_proxy: Fix over-eager handling of '%' for reverse proxies. PR 15207. [Jim Jagielski] diff --git a/STATUS b/STATUS index ab717769d1b..28feda0f2f4 100644 --- a/STATUS +++ b/STATUS @@ -332,13 +332,6 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: http://svn.apache.org/viewcvs.cgi?rev=193127&view=rev +1: jorton - *) Prevent the byterange filter from buffering responses into - memory; a common cause of "why does httpd eat all my memory". - http://svn.apache.org/viewcvs?rev=188797&view=rev - rediff for 2.0.x: http://people.apache.org/~jorton/ap_byterange.diff - PR: 29962 - +1: jorton, trawick, niq - *) Reverse Proxy fixes: bug and Cookie support Patch is at http://marc.theaimsgroup.com/?l=apache-httpd-dev&m=112365629308138&q=p4 diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c index 052af13cf6f..849ddfb1eab 100644 --- a/modules/http/http_protocol.c +++ b/modules/http/http_protocol.c @@ -2856,18 +2856,35 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, #define MIN_LENGTH(len1, len2) ((len1 > len2) ? len2 : len1) request_rec *r = f->r; conn_rec *c = r->connection; - byterange_ctx *ctx = f->ctx; + byterange_ctx *ctx; apr_bucket *e; apr_bucket_brigade *bsend; apr_off_t range_start; apr_off_t range_end; char *current; - apr_off_t bb_length; apr_off_t clength = 0; apr_status_t rv; int found = 0; - if (!ctx) { + /* Iterate through the brigade until reaching EOS or a bucket with + * unknown length. */ + for (e = APR_BRIGADE_FIRST(bb); + (e != APR_BRIGADE_SENTINEL(bb) && !APR_BUCKET_IS_EOS(e) + && e->length != (apr_size_t)-1); + e = APR_BUCKET_NEXT(e)) { + clength += e->length; + } + + /* Don't attempt to do byte range work if this brigade doesn't + * contain an EOS, or if any of the buckets has an unknown length; + * this avoids the cases where it is expensive to perform + * byteranging (i.e. may require arbitrary amounts of memory). */ + if (!APR_BUCKET_IS_EOS(e) || clength <= 0) { + ap_remove_output_filter(f); + return ap_pass_brigade(f->next, bb); + } + + { int num_ranges = ap_set_byterange(r); /* We have nothing to do, get out of the way. */ @@ -2876,7 +2893,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, return ap_pass_brigade(f->next, bb); } - ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx)); + ctx = apr_pcalloc(r->pool, sizeof(*ctx)); ctx->num_ranges = num_ranges; /* create a brigade in case we never call ap_save_brigade() */ ctx->bb = apr_brigade_create(r->pool, c->bucket_alloc); @@ -2903,29 +2920,6 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, } } - /* We can't actually deal with byte-ranges until we have the whole brigade - * because the byte-ranges can be in any order, and according to the RFC, - * we SHOULD return the data in the same order it was requested. - * - * XXX: We really need to dump all bytes prior to the start of the earliest - * range, and only slurp up to the end of the latest range. By this we - * mean that we should peek-ahead at the lowest first byte of any range, - * and the highest last byte of any range. - */ - if (!APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) { - ap_save_brigade(f, &ctx->bb, &bb, r->pool); - return APR_SUCCESS; - } - - /* Prepend any earlier saved brigades. */ - APR_BRIGADE_PREPEND(bb, ctx->bb); - - /* It is possible that we won't have a content length yet, so we have to - * compute the length before we can actually do the byterange work. - */ - apr_brigade_length(bb, 1, &bb_length); - clength = (apr_off_t)bb_length; - /* this brigade holds what we will be sending */ bsend = apr_brigade_create(r->pool, c->bucket_alloc);