]> granicus.if.org Git - apache/commitdiff
When I initially pulled the BYTERANGE filter into the core, Greg Stein
authorRyan Bloom <rbb@apache.org>
Wed, 11 Apr 2001 23:37:16 +0000 (23:37 +0000)
committerRyan Bloom <rbb@apache.org>
Wed, 11 Apr 2001 23:37:16 +0000 (23:37 +0000)
told me I was wrong.  I was wrong, and Greg was right.  This commit
just moves the byterange filter and its related functions out of the core,
and puts them back in the HTTP specific module.
Submitted by: Greg Stein

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@88815 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
modules/http/http_core.c
modules/http/http_protocol.c
server/core.c
server/protocol.c

diff --git a/CHANGES b/CHANGES
index 80c161fb5ffc53011d08b9529101a91c2fb226c7..70cacf283fca5f6b111032ec182e94eafabbaccf 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,9 @@
 Changes with Apache 2.0.17-dev
 
+  *) Move the byterange filter and all of the supporting functions back
+     to the HTTP module.  The byterange filter turned out to be very
+     HTTP specific, and it belongs in the HTTP module.  [Greg Stein]
+
   *) Make clean, distclean, and extraclean consistently according to the
      Gnu makefile guidelines.  [Justin Erenkrantz <jerenkrantz@ebuilt.com>]
 
index 3983ef05daa4ea060927125b392afadfbc397472..f5948973ab6232eaa5c654851df3445cbe0ba0c6 100644 (file)
@@ -309,6 +309,8 @@ static void register_hooks(apr_pool_t *p)
     ap_register_output_filter("HTTP_HEADER", ap_http_header_filter, 
                               AP_FTYPE_HTTP_HEADER);
     ap_register_output_filter("CHUNK", chunk_filter, AP_FTYPE_TRANSCODE);
+    ap_register_output_filter("BYTERANGE", ap_byterange_filter,
+                              AP_FTYPE_HTTP_HEADER);
 }
 
 AP_DECLARE_DATA module http_module = {
index 1b6196fa7874f63156e3d1b07a7920ddcd4bd3fc..e4d45c8e65fdfe78ad00b514f5cb5aff36a87fbd 100644 (file)
@@ -2032,3 +2032,391 @@ AP_DECLARE(void) ap_clear_method_list(ap_method_list_t *l)
     l->method_list->nelts = 0;
 } 
 
+/*
+ * Construct an entity tag (ETag) from resource information.  If it's a real
+ * file, build in some of the file characteristics.  If the modification time
+ * is newer than (request-time minus 1 second), mark the ETag as weak - it
+ * could be modified again in as short an interval.  We rationalize the
+ * modification time we're given to keep it from being in the future.
+ */
+AP_DECLARE(char *) ap_make_etag(request_rec *r, int force_weak)
+{
+    char *etag;
+    char *weak;
+
+    /*
+     * Make an ETag header out of various pieces of information. We use
+     * the last-modified date and, if we have a real file, the
+     * length and inode number - note that this doesn't have to match
+     * the content-length (i.e. includes), it just has to be unique
+     * for the file.
+     *
+     * If the request was made within a second of the last-modified date,
+     * we send a weak tag instead of a strong one, since it could
+     * be modified again later in the second, and the validation
+     * would be incorrect.
+     */
+    
+    weak = ((r->request_time - r->mtime > APR_USEC_PER_SEC)
+           && !force_weak) ? "" : "W/";
+
+    if (r->finfo.filetype != 0) {
+        etag = apr_psprintf(r->pool,
+                           "%s\"%lx-%lx-%lx\"", weak,
+                           (unsigned long) r->finfo.inode,
+                           (unsigned long) r->finfo.size,
+                           (unsigned long) r->mtime);
+    }
+    else {
+        etag = apr_psprintf(r->pool, "%s\"%lx\"", weak,
+                           (unsigned long) r->mtime);
+    }
+
+    return etag;
+}
+
+AP_DECLARE(void) ap_set_etag(request_rec *r)
+{
+    char *etag;
+    char *variant_etag, *vlv;
+    int vlv_weak;
+
+    if (!r->vlist_validator) {
+        etag = ap_make_etag(r, 0);
+    }
+    else {
+        /* If we have a variant list validator (vlv) due to the
+         * response being negotiated, then we create a structured
+         * entity tag which merges the variant etag with the variant
+         * list validator (vlv).  This merging makes revalidation
+         * somewhat safer, ensures that caches which can deal with
+         * Vary will (eventually) be updated if the set of variants is
+         * changed, and is also a protocol requirement for transparent
+         * content negotiation.
+         */
+
+        /* if the variant list validator is weak, we make the whole
+         * structured etag weak.  If we would not, then clients could
+         * have problems merging range responses if we have different
+         * variants with the same non-globally-unique strong etag.
+         */
+
+        vlv = r->vlist_validator;
+        vlv_weak = (vlv[0] == 'W');
+               
+        variant_etag = ap_make_etag(r, vlv_weak);
+
+        /* merge variant_etag and vlv into a structured etag */
+
+        variant_etag[strlen(variant_etag) - 1] = '\0';
+        if (vlv_weak)
+            vlv += 3;
+        else
+            vlv++;
+        etag = apr_pstrcat(r->pool, variant_etag, ";", vlv, NULL);
+    }
+
+    apr_table_setn(r->headers_out, "ETag", etag);
+}
+
+static int parse_byterange(char *range, apr_off_t clength,
+                           apr_off_t *start, apr_off_t *end)
+{
+    char *dash = strchr(range, '-');
+
+    if (!dash)
+        return 0;
+
+    if ((dash == range)) {
+        /* In the form "-5" */
+        *start = clength - atol(dash + 1);
+        *end = clength - 1;
+    }
+    else {
+        *dash = '\0';
+        dash++;
+        *start = atol(range);
+        if (*dash)
+            *end = atol(dash);
+        else                    /* "5-" */
+            *end = clength - 1;
+    }
+
+    if (*start < 0)
+       *start = 0;
+
+    if (*end >= clength)
+        *end = clength - 1;
+
+    if (*start > *end)
+       return -1;
+
+    return (*start > 0 || *end < clength);
+}
+
+static int ap_set_byterange(request_rec *r);
+
+typedef struct byterange_ctx {
+    apr_bucket_brigade *bb;
+    int num_ranges;
+    const char *orig_ct;
+} byterange_ctx;
+
+/*
+ * Here we try to be compatible with clients that want multipart/x-byteranges
+ * instead of multipart/byteranges (also see above), as per HTTP/1.1. We
+ * look for the Request-Range header (e.g. Netscape 2 and 3) as an indication
+ * that the browser supports an older protocol. We also check User-Agent
+ * for Microsoft Internet Explorer 3, which needs this as well.
+ */
+static int use_range_x(request_rec *r)
+{
+    const char *ua;
+    return (apr_table_get(r->headers_in, "Request-Range") ||
+            ((ua = apr_table_get(r->headers_in, "User-Agent"))
+             && ap_strstr_c(ua, "MSIE 3")));
+}
+
+#define BYTERANGE_FMT "%" APR_OFF_T_FMT "-%" APR_OFF_T_FMT "/%" APR_OFF_T_FMT
+
+AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(
+    ap_filter_t *f,
+    apr_bucket_brigade *bb)
+{
+#define MIN_LENGTH(len1, len2) ((len1 > len2) ? len2 : len1)
+    request_rec *r = f->r;
+    byterange_ctx *ctx = f->ctx;
+    apr_bucket *e;
+    apr_bucket_brigade *bsend;
+    apr_off_t range_start;
+    apr_off_t range_end;
+    char *current;
+    char *bound_head;
+    apr_ssize_t bb_length;
+    apr_off_t clength = 0;
+    apr_status_t rv;
+    int found = 0;
+
+    if (!ctx) {
+        int num_ranges = ap_set_byterange(r);
+        if (num_ranges == -1) {
+            ap_remove_output_filter(f);
+            bsend = apr_brigade_create(r->pool);
+            e = ap_bucket_error_create(HTTP_RANGE_NOT_SATISFIABLE, NULL, r->pool);
+            APR_BRIGADE_INSERT_TAIL(bsend, e);
+            e = apr_bucket_eos_create();
+            APR_BRIGADE_INSERT_TAIL(bsend, e);
+            return ap_pass_brigade(f->next, bsend);
+        }
+        if (num_ranges == 0) {
+            ap_remove_output_filter(f);
+            return ap_pass_brigade(f->next, bb);
+        }
+
+        ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx));
+        ctx->num_ranges = num_ranges;
+
+        if (num_ranges > 1) {
+            ctx->orig_ct = r->content_type;
+            r->content_type = 
+                 apr_pstrcat(r->pool, "multipart", use_range_x(r) ? "/x-" : "/",
+                          "byteranges; boundary=", r->boundary, NULL);
+        }
+
+        /* create a brigade in case we never call ap_save_brigade() */
+        ctx->bb = apr_brigade_create(r->pool);
+    }
+
+    /* 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. 
+     */
+    if (!APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
+        ap_save_brigade(f, &ctx->bb, &bb);
+        return APR_SUCCESS;
+    }
+
+    /* compute this once (it is an invariant) */
+    bound_head = apr_pstrcat(r->pool,
+                             CRLF "--", r->boundary,
+                             CRLF "Content-type: ",
+                             ap_make_content_type(r, ctx->orig_ct),
+                             CRLF "Content-range: bytes ", 
+                             NULL);
+    ap_xlate_proto_to_ascii(bound_head, strlen(bound_head));
+
+    /* If we have a saved brigade from a previous run, concat the passed
+     * brigade with our saved brigade.  Otherwise just continue.  
+     */
+    if (ctx->bb) {
+        APR_BRIGADE_CONCAT(ctx->bb, bb);
+        bb = ctx->bb;
+        ctx->bb = NULL;     /* ### strictly necessary? call brigade_destroy? */
+    }
+
+    /* 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.
+     */
+    (void) 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);
+
+    while ((current = ap_getword(r->pool, &r->range, ',')) &&
+           (rv = parse_byterange(current, clength, &range_start, &range_end))) {
+        apr_bucket *e2;
+        apr_bucket *ec;
+
+        if (rv == -1) {
+            continue;
+        }        
+        else {
+            found = 1;
+        }
+
+        if (ctx->num_ranges > 1) {
+            char *ts;
+
+            e = apr_bucket_pool_create(bound_head,
+                                      strlen(bound_head), r->pool);
+            APR_BRIGADE_INSERT_TAIL(bsend, e);
+
+            ts = apr_psprintf(r->pool, BYTERANGE_FMT CRLF CRLF,
+                              range_start, range_end, clength);
+            ap_xlate_proto_to_ascii(ts, strlen(ts));
+            e = apr_bucket_pool_create(ts, strlen(ts), r->pool);
+            APR_BRIGADE_INSERT_TAIL(bsend, e);
+        }
+        
+        e = apr_brigade_partition(bb, range_start);
+        e2 = apr_brigade_partition(bb, range_end + 1);
+        
+        ec = e;
+        do {
+            apr_bucket *foo;
+            const char *str;
+            apr_size_t len;
+
+            if (apr_bucket_copy(ec, &foo) != APR_SUCCESS) {
+                apr_bucket_read(ec, &str, &len, APR_BLOCK_READ);
+                foo = apr_bucket_heap_create(str, len, 0, NULL);
+            }
+            APR_BRIGADE_INSERT_TAIL(bsend, foo);
+            ec = APR_BUCKET_NEXT(ec);
+        } while (ec != e2);
+    }
+
+    if (found == 0) {
+        ap_remove_output_filter(f);
+        r->status = HTTP_OK;
+        return HTTP_RANGE_NOT_SATISFIABLE;
+    }
+
+    if (ctx->num_ranges > 1) {
+        char *end;
+
+        /* add the final boundary */
+        end = apr_pstrcat(r->pool, CRLF "--", r->boundary, "--" CRLF, NULL);
+        ap_xlate_proto_to_ascii(end, strlen(end));
+        e = apr_bucket_pool_create(end, strlen(end), r->pool);
+        APR_BRIGADE_INSERT_TAIL(bsend, e);
+    }
+
+    e = apr_bucket_eos_create();
+    APR_BRIGADE_INSERT_TAIL(bsend, e);
+
+    /* we're done with the original content */
+    apr_brigade_destroy(bb);
+
+    /* send our multipart output */
+    return ap_pass_brigade(f->next, bsend); 
+}    
+
+static int ap_set_byterange(request_rec *r)
+{
+    const char *range;
+    const char *if_range;
+    const char *match;
+    const char *ct;
+    apr_off_t range_start;
+    apr_off_t range_end;
+    int num_ranges;
+
+    if (r->assbackwards)
+        return 0;
+
+    /* Check for Range request-header (HTTP/1.1) or Request-Range for
+     * backwards-compatibility with second-draft Luotonen/Franks
+     * byte-ranges (e.g. Netscape Navigator 2-3).
+     *
+     * We support this form, with Request-Range, and (farther down) we
+     * send multipart/x-byteranges instead of multipart/byteranges for
+     * Request-Range based requests to work around a bug in Netscape
+     * Navigator 2-3 and MSIE 3.
+     */
+
+    if (!(range = apr_table_get(r->headers_in, "Range")))
+        range = apr_table_get(r->headers_in, "Request-Range");
+
+    if (!range || strncasecmp(range, "bytes=", 6)) {
+        return 0;
+    }
+
+    /* Check the If-Range header for Etag or Date.
+     * Note that this check will return false (as required) if either
+     * of the two etags are weak.
+     */
+    if ((if_range = apr_table_get(r->headers_in, "If-Range"))) {
+        if (if_range[0] == '"') {
+            if (!(match = apr_table_get(r->headers_out, "Etag")) ||
+                (strcmp(if_range, match) != 0))
+                return 0;
+        }
+        else if (!(match = apr_table_get(r->headers_out, "Last-Modified")) ||
+                 (strcmp(if_range, match) != 0))
+            return 0;
+    }
+
+    /* would be nice to pick this up from f->ctx */
+    ct = ap_make_content_type(r, r->content_type);
+
+    if (!ap_strchr_c(range, ',')) {
+        int rv;
+        /* A single range */
+
+        /* rvarse_byterange() modifies the contents, so make a copy */
+        if ((rv = parse_byterange(apr_pstrdup(r->pool, range + 6), r->clength,
+                             &range_start, &range_end)) <= 0) {
+            return rv;
+        }
+        apr_table_setn(r->headers_out, "Content-Range",
+                       apr_psprintf(r->pool, "bytes " BYTERANGE_FMT,
+                                    range_start, range_end, r->clength));
+       apr_table_setn(r->headers_out, "Content-Type", ct);
+
+        num_ranges = 1;
+    }
+    else {
+        /* a multiple range */
+
+        num_ranges = 2;
+
+        /* ### it would be nice if r->boundary was in f->ctx */
+        r->boundary = apr_psprintf(r->pool, "%qx%lx",
+                                   r->request_time, (long) getpid());
+
+        apr_table_setn(r->headers_out, "Content-Type",
+                      apr_pstrcat(r->pool,
+                                   "multipart", use_range_x(r) ? "/x-" : "/",
+                                  "byteranges; boundary=", r->boundary,
+                                   NULL));
+    }
+
+    r->status = HTTP_PARTIAL_CONTENT;
+    r->range = range + 6;
+
+    return num_ranges;
+}
+
index a5b68d0e0284622e3f5f0ad6a96f877294a2af95..7dded2f8b7a1b0cfc0d31401363f79ff00c92ff5 100644 (file)
@@ -3284,8 +3284,6 @@ static void register_hooks(apr_pool_t *p)
     ap_register_input_filter("CORE_IN", core_input_filter, AP_FTYPE_NETWORK);
     ap_register_output_filter("CONTENT_LENGTH", ap_content_length_filter, 
                               AP_FTYPE_HTTP_HEADER);
-    ap_register_output_filter("BYTERANGE", ap_byterange_filter, 
-                              AP_FTYPE_HTTP_HEADER);
     ap_register_output_filter("CORE", core_output_filter, AP_FTYPE_NETWORK);
     ap_register_output_filter("SUBREQ_CORE", ap_sub_req_output_filter, 
                               AP_FTYPE_CONTENT);
index b32f651a86dcbb8462591825c684c7c5ac07e21a..45395faabef96b572ec03601cdea83cbce0d1a0b 100644 (file)
@@ -151,221 +151,6 @@ AP_DECLARE(const char *)ap_make_content_type(request_rec *r, const char *type)
     return type;
 }
 
-static int parse_byterange(char *range, apr_off_t clength,
-                           apr_off_t *start, apr_off_t *end)
-{
-    char *dash = strchr(range, '-');
-
-    if (!dash)
-        return 0;
-
-    if ((dash == range)) {
-        /* In the form "-5" */
-        *start = clength - atol(dash + 1);
-        *end = clength - 1;
-    }
-    else {
-        *dash = '\0';
-        dash++;
-        *start = atol(range);
-        if (*dash)
-            *end = atol(dash);
-        else                    /* "5-" */
-            *end = clength - 1;
-    }
-
-    if (*start < 0)
-       *start = 0;
-
-    if (*end >= clength)
-        *end = clength - 1;
-
-    if (*start > *end)
-       return -1;
-
-    return (*start > 0 || *end < clength);
-}
-
-static int ap_set_byterange(request_rec *r);
-
-typedef struct byterange_ctx {
-    apr_bucket_brigade *bb;
-    int num_ranges;
-    const char *orig_ct;
-} byterange_ctx;
-
-/*
- * Here we try to be compatible with clients that want multipart/x-byteranges
- * instead of multipart/byteranges (also see above), as per HTTP/1.1. We
- * look for the Request-Range header (e.g. Netscape 2 and 3) as an indication
- * that the browser supports an older protocol. We also check User-Agent
- * for Microsoft Internet Explorer 3, which needs this as well.
- */
-static int use_range_x(request_rec *r)
-{
-    const char *ua;
-    return (apr_table_get(r->headers_in, "Request-Range") ||
-            ((ua = apr_table_get(r->headers_in, "User-Agent"))
-             && ap_strstr_c(ua, "MSIE 3")));
-}
-
-#define BYTERANGE_FMT "%" APR_OFF_T_FMT "-%" APR_OFF_T_FMT "/%" APR_OFF_T_FMT
-
-AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(
-    ap_filter_t *f,
-    apr_bucket_brigade *bb)
-{
-#define MIN_LENGTH(len1, len2) ((len1 > len2) ? len2 : len1)
-    request_rec *r = f->r;
-    byterange_ctx *ctx = f->ctx;
-    apr_bucket *e;
-    apr_bucket_brigade *bsend;
-    apr_off_t range_start;
-    apr_off_t range_end;
-    char *current;
-    char *bound_head;
-    apr_ssize_t bb_length;
-    apr_off_t clength = 0;
-    apr_status_t rv;
-    int found = 0;
-
-    if (!ctx) {
-        int num_ranges = ap_set_byterange(r);
-        if (num_ranges == -1) {
-            ap_remove_output_filter(f);
-            bsend = apr_brigade_create(r->pool);
-            e = ap_bucket_error_create(HTTP_RANGE_NOT_SATISFIABLE, NULL, r->pool);
-            APR_BRIGADE_INSERT_TAIL(bsend, e);
-            e = apr_bucket_eos_create();
-            APR_BRIGADE_INSERT_TAIL(bsend, e);
-            return ap_pass_brigade(f->next, bsend);
-        }
-        if (num_ranges == 0) {
-            ap_remove_output_filter(f);
-            return ap_pass_brigade(f->next, bb);
-        }
-
-        ctx = f->ctx = apr_pcalloc(r->pool, sizeof(*ctx));
-        ctx->num_ranges = num_ranges;
-
-        if (num_ranges > 1) {
-            ctx->orig_ct = r->content_type;
-            r->content_type = 
-                 apr_pstrcat(r->pool, "multipart", use_range_x(r) ? "/x-" : "/",
-                          "byteranges; boundary=", r->boundary, NULL);
-        }
-
-        /* create a brigade in case we never call ap_save_brigade() */
-        ctx->bb = apr_brigade_create(r->pool);
-    }
-
-    /* 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. 
-     */
-    if (!APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
-        ap_save_brigade(f, &ctx->bb, &bb);
-        return APR_SUCCESS;
-    }
-
-    /* compute this once (it is an invariant) */
-    bound_head = apr_pstrcat(r->pool,
-                             CRLF "--", r->boundary,
-                             CRLF "Content-type: ",
-                             ap_make_content_type(r, ctx->orig_ct),
-                             CRLF "Content-range: bytes ", 
-                             NULL);
-    ap_xlate_proto_to_ascii(bound_head, strlen(bound_head));
-
-    /* If we have a saved brigade from a previous run, concat the passed
-     * brigade with our saved brigade.  Otherwise just continue.  
-     */
-    if (ctx->bb) {
-        APR_BRIGADE_CONCAT(ctx->bb, bb);
-        bb = ctx->bb;
-        ctx->bb = NULL;     /* ### strictly necessary? call brigade_destroy? */
-    }
-
-    /* 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.
-     */
-    (void) 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);
-
-    while ((current = ap_getword(r->pool, &r->range, ',')) &&
-           (rv = parse_byterange(current, clength, &range_start, &range_end))) {
-        apr_bucket *e2;
-        apr_bucket *ec;
-
-        if (rv == -1) {
-            continue;
-        }        
-        else {
-            found = 1;
-        }
-
-        if (ctx->num_ranges > 1) {
-            char *ts;
-
-            e = apr_bucket_pool_create(bound_head,
-                                      strlen(bound_head), r->pool);
-            APR_BRIGADE_INSERT_TAIL(bsend, e);
-
-            ts = apr_psprintf(r->pool, BYTERANGE_FMT CRLF CRLF,
-                              range_start, range_end, clength);
-            ap_xlate_proto_to_ascii(ts, strlen(ts));
-            e = apr_bucket_pool_create(ts, strlen(ts), r->pool);
-            APR_BRIGADE_INSERT_TAIL(bsend, e);
-        }
-        
-        e = apr_brigade_partition(bb, range_start);
-        e2 = apr_brigade_partition(bb, range_end + 1);
-        
-        ec = e;
-        do {
-            apr_bucket *foo;
-            const char *str;
-            apr_size_t len;
-
-            if (apr_bucket_copy(ec, &foo) != APR_SUCCESS) {
-                apr_bucket_read(ec, &str, &len, APR_BLOCK_READ);
-                foo = apr_bucket_heap_create(str, len, 0, NULL);
-            }
-            APR_BRIGADE_INSERT_TAIL(bsend, foo);
-            ec = APR_BUCKET_NEXT(ec);
-        } while (ec != e2);
-    }
-
-    if (found == 0) {
-        ap_remove_output_filter(f);
-        r->status = HTTP_OK;
-        return HTTP_RANGE_NOT_SATISFIABLE;
-    }
-
-    if (ctx->num_ranges > 1) {
-        char *end;
-
-        /* add the final boundary */
-        end = apr_pstrcat(r->pool, CRLF "--", r->boundary, "--" CRLF, NULL);
-        ap_xlate_proto_to_ascii(end, strlen(end));
-        e = apr_bucket_pool_create(end, strlen(end), r->pool);
-        APR_BRIGADE_INSERT_TAIL(bsend, e);
-    }
-
-    e = apr_bucket_eos_create();
-    APR_BRIGADE_INSERT_TAIL(bsend, e);
-
-    /* we're done with the original content */
-    apr_brigade_destroy(bb);
-
-    /* send our multipart output */
-    return ap_pass_brigade(f->next, bsend); 
-}    
-
 AP_DECLARE(void) ap_set_content_length(request_rec *r, apr_off_t clength)
 {
     r->clength = clength;
@@ -397,93 +182,6 @@ AP_DECLARE(apr_time_t) ap_rationalize_mtime(request_rec *r, apr_time_t mtime)
     return (mtime > now) ? now : mtime;
 }
 
-/*
- * Construct an entity tag (ETag) from resource information.  If it's a real
- * file, build in some of the file characteristics.  If the modification time
- * is newer than (request-time minus 1 second), mark the ETag as weak - it
- * could be modified again in as short an interval.  We rationalize the
- * modification time we're given to keep it from being in the future.
- */
-AP_DECLARE(char *) ap_make_etag(request_rec *r, int force_weak)
-{
-    char *etag;
-    char *weak;
-
-    /*
-     * Make an ETag header out of various pieces of information. We use
-     * the last-modified date and, if we have a real file, the
-     * length and inode number - note that this doesn't have to match
-     * the content-length (i.e. includes), it just has to be unique
-     * for the file.
-     *
-     * If the request was made within a second of the last-modified date,
-     * we send a weak tag instead of a strong one, since it could
-     * be modified again later in the second, and the validation
-     * would be incorrect.
-     */
-    
-    weak = ((r->request_time - r->mtime > APR_USEC_PER_SEC)
-           && !force_weak) ? "" : "W/";
-
-    if (r->finfo.filetype != 0) {
-        etag = apr_psprintf(r->pool,
-                           "%s\"%lx-%lx-%lx\"", weak,
-                           (unsigned long) r->finfo.inode,
-                           (unsigned long) r->finfo.size,
-                           (unsigned long) r->mtime);
-    }
-    else {
-        etag = apr_psprintf(r->pool, "%s\"%lx\"", weak,
-                           (unsigned long) r->mtime);
-    }
-
-    return etag;
-}
-
-AP_DECLARE(void) ap_set_etag(request_rec *r)
-{
-    char *etag;
-    char *variant_etag, *vlv;
-    int vlv_weak;
-
-    if (!r->vlist_validator) {
-        etag = ap_make_etag(r, 0);
-    }
-    else {
-        /* If we have a variant list validator (vlv) due to the
-         * response being negotiated, then we create a structured
-         * entity tag which merges the variant etag with the variant
-         * list validator (vlv).  This merging makes revalidation
-         * somewhat safer, ensures that caches which can deal with
-         * Vary will (eventually) be updated if the set of variants is
-         * changed, and is also a protocol requirement for transparent
-         * content negotiation.
-         */
-
-        /* if the variant list validator is weak, we make the whole
-         * structured etag weak.  If we would not, then clients could
-         * have problems merging range responses if we have different
-         * variants with the same non-globally-unique strong etag.
-         */
-
-        vlv = r->vlist_validator;
-        vlv_weak = (vlv[0] == 'W');
-               
-        variant_etag = ap_make_etag(r, vlv_weak);
-
-        /* merge variant_etag and vlv into a structured etag */
-
-        variant_etag[strlen(variant_etag) - 1] = '\0';
-        if (vlv_weak)
-            vlv += 3;
-        else
-            vlv++;
-        etag = apr_pstrcat(r->pool, variant_etag, ";", vlv, NULL);
-    }
-
-    apr_table_setn(r->headers_out, "ETag", etag);
-}
-
 /* Get a line of protocol input, including any continuation lines
  * caused by MIME folding (or broken clients) if fold != 0, and place it
  * in the buffer s, of size n bytes, without the ending newline.
@@ -1235,92 +933,6 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_content_length_filter(ap_filter_t *f,
     return ap_pass_brigade(f->next, b);
 }
 
-static int ap_set_byterange(request_rec *r)
-{
-    const char *range;
-    const char *if_range;
-    const char *match;
-    const char *ct;
-    apr_off_t range_start;
-    apr_off_t range_end;
-    int num_ranges;
-
-    if (r->assbackwards)
-        return 0;
-
-    /* Check for Range request-header (HTTP/1.1) or Request-Range for
-     * backwards-compatibility with second-draft Luotonen/Franks
-     * byte-ranges (e.g. Netscape Navigator 2-3).
-     *
-     * We support this form, with Request-Range, and (farther down) we
-     * send multipart/x-byteranges instead of multipart/byteranges for
-     * Request-Range based requests to work around a bug in Netscape
-     * Navigator 2-3 and MSIE 3.
-     */
-
-    if (!(range = apr_table_get(r->headers_in, "Range")))
-        range = apr_table_get(r->headers_in, "Request-Range");
-
-    if (!range || strncasecmp(range, "bytes=", 6)) {
-        return 0;
-    }
-
-    /* Check the If-Range header for Etag or Date.
-     * Note that this check will return false (as required) if either
-     * of the two etags are weak.
-     */
-    if ((if_range = apr_table_get(r->headers_in, "If-Range"))) {
-        if (if_range[0] == '"') {
-            if (!(match = apr_table_get(r->headers_out, "Etag")) ||
-                (strcmp(if_range, match) != 0))
-                return 0;
-        }
-        else if (!(match = apr_table_get(r->headers_out, "Last-Modified")) ||
-                 (strcmp(if_range, match) != 0))
-            return 0;
-    }
-
-    /* would be nice to pick this up from f->ctx */
-    ct = ap_make_content_type(r, r->content_type);
-
-    if (!ap_strchr_c(range, ',')) {
-        int rv;
-        /* A single range */
-
-        /* rvarse_byterange() modifies the contents, so make a copy */
-        if ((rv = parse_byterange(apr_pstrdup(r->pool, range + 6), r->clength,
-                             &range_start, &range_end)) <= 0) {
-            return rv;
-        }
-        apr_table_setn(r->headers_out, "Content-Range",
-                       apr_psprintf(r->pool, "bytes " BYTERANGE_FMT,
-                                    range_start, range_end, r->clength));
-       apr_table_setn(r->headers_out, "Content-Type", ct);
-
-        num_ranges = 1;
-    }
-    else {
-        /* a multiple range */
-
-        num_ranges = 2;
-
-        /* ### it would be nice if r->boundary was in f->ctx */
-        r->boundary = apr_psprintf(r->pool, "%qx%lx",
-                                   r->request_time, (long) getpid());
-
-        apr_table_setn(r->headers_out, "Content-Type",
-                      apr_pstrcat(r->pool,
-                                   "multipart", use_range_x(r) ? "/x-" : "/",
-                                  "byteranges; boundary=", r->boundary,
-                                   NULL));
-    }
-
-    r->status = HTTP_PARTIAL_CONTENT;
-    r->range = range + 6;
-
-    return num_ranges;
-}
-
 /*
  * Send the body of a response to the client.
  */