]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Merge r233493 from trunk:
authorJoe Orton <jorton@apache.org>
Tue, 23 Aug 2005 08:36:16 +0000 (08:36 +0000)
committerJoe Orton <jorton@apache.org>
Tue, 23 Aug 2005 08:36:16 +0000 (08:36 +0000)
* 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

CHANGES
STATUS
modules/http/http_protocol.c

diff --git a/CHANGES b/CHANGES
index b3d06bcdce19a738cd5a759364ed24ce0f36ba27..a8c5e5aaf07672fba7970dd8f0e60f2936bc81be 100644 (file)
--- 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 ab717769d1ba216faf52c7a894180e9ab379bc52..28feda0f2f4b67364c6ea450aef9896b9e8a07e7 100644 (file)
--- 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: <Location> bug and Cookie support
         Patch is at
         http://marc.theaimsgroup.com/?l=apache-httpd-dev&m=112365629308138&q=p4
index 052af13cf6f03cf536dd4f8e8125664bd670de85..849ddfb1eab94214c27600687053ef785e62f2d4 100644 (file)
@@ -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);