httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From r..@locus.apache.org
Subject cvs commit: apache-2.0/src/main http_core.c http_protocol.c
Date Wed, 08 Nov 2000 06:24:50 GMT
rbb         00/11/07 22:24:48

  Modified:    src      CHANGES
               src/include http_protocol.h
               src/main http_core.c http_protocol.c
  Log:
  The byte-ranges filter.  This looks like it should work, but the
  Acrobat plug-in doesn't like it for some reason.  This does work better
  than what we currently have, because at least it returns all of the
  requested data.  This basically removes all BUFFs from the byte-range
  code and removes all of the byte-range code from the default-handler.
  
  Byte-ranges are now handled by a filter, which makes sense, and it allows
  us to handle byte-ranges for all requests, not just files.
  
  Revision  Changes    Path
  1.313     +7 -0      apache-2.0/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/CHANGES,v
  retrieving revision 1.312
  retrieving revision 1.313
  diff -u -r1.312 -r1.313
  --- CHANGES	2000/11/07 20:21:00	1.312
  +++ CHANGES	2000/11/08 06:24:44	1.313
  @@ -1,4 +1,11 @@
   Changes with Apache 2.0a8
  +  *) Byteranges have been completely re-written to be a filter.  This
  +     has been tested, and I believe it is working correctly, but it could
  +     doesn't work for the Adobe Acrobat plug-in.  The output almost matches
  +     the output from 1.3, the only difference being that 1.3 includes
  +     a content-length in the response, and this does not.
  +     [Ryan Bloom]
  +
     *) APR read/write functions and bucket read functions now operate
        on unsigned integers, instead of signed ones.  It doesn't make
        any sense to use signed ints, because we return the error codes,
  
  
  
  1.40      +1 -16     apache-2.0/src/include/http_protocol.h
  
  Index: http_protocol.h
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/include/http_protocol.h,v
  retrieving revision 1.39
  retrieving revision 1.40
  diff -u -r1.39 -r1.40
  --- http_protocol.h	2000/11/07 22:40:56	1.39
  +++ http_protocol.h	2000/11/08 06:24:45	1.40
  @@ -103,6 +103,7 @@
    */
   AP_DECLARE(void) ap_send_http_header(request_rec *l);
   
  +AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, ap_bucket_brigade
*b);
   AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, ap_bucket_brigade
*b);
   AP_CORE_DECLARE_NONSTD(apr_status_t) ap_content_length_filter(ap_filter_t *, 
                                                                 ap_bucket_brigade *);
  @@ -435,22 +436,6 @@
   
   /* Sending a byterange */
   
  -/**
  - * Setup the request to send Byte Range requests
  - * @param r the current request
  - * @return 1 if request was setup for byte range requests, 0 otherwise
  - * @deffunc int ap_set_byterange(request_rec *r)
  - */
  -AP_DECLARE(int) ap_set_byterange(request_rec *r);
  -/**
  - * Send one byte range chunk for a byte range request
  - * @param r The current request
  - * @param offset Set to the position it should be after the chunk is sent
  - * @param length Set to the length in should be after the chunk is sent
  - * @deffunc int ap_each_byterange(request_rec *r, apr_off_t *offset, apr_size_t *length)
  - */
  -AP_DECLARE(int) ap_each_byterange(request_rec *r, apr_off_t *offset,
  -				  apr_size_t *length);
   /**
    * Setup the output headers so that the client knows how to authenticate
    * itself the next time, if an authentication request failed.  This function
  
  
  
  1.206     +9 -27     apache-2.0/src/main/http_core.c
  
  Index: http_core.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/main/http_core.c,v
  retrieving revision 1.205
  retrieving revision 1.206
  diff -u -r1.205 -r1.206
  --- http_core.c	2000/11/08 02:46:00	1.205
  +++ http_core.c	2000/11/08 06:24:46	1.206
  @@ -2912,7 +2912,7 @@
   {
       core_dir_config *d =
   	    (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module);
  -    int rangestatus, errstatus;
  +    int errstatus;
       apr_file_t *fd = NULL;
       apr_status_t status;
   #ifdef AP_USE_MMAP_FILES
  @@ -2997,8 +2997,6 @@
                              ap_md5digest(r->pool, fd));
   	}
   
  -	rangestatus = ap_set_byterange(r);
  -
   	ap_send_http_header(r);
   	
   	if (!r->header_only) {
  @@ -3006,18 +3004,7 @@
               apr_off_t  offset = 0;
               apr_size_t nbytes = 0;
   
  -	    if (!rangestatus) {
  -		ap_send_fd(fd, r, offset, length, &nbytes);
  -	    }
  -	    else {
  -		while (ap_each_byterange(r, &offset, &length)) {
  -                    if ((status = ap_send_fd(fd, r, offset, length, &nbytes)) != APR_SUCCESS)
{
  -		        ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
  -				  "error byteserving file: %s", r->filename);
  -			return HTTP_INTERNAL_SERVER_ERROR;
  -		    }
  -		}
  -	    }
  +            ap_send_fd(fd, r, offset, length, &nbytes);
   	}
   
   #ifdef AP_USE_MMAP_FILES
  @@ -3035,20 +3022,10 @@
   			  ap_md5contextTo64(r->pool, &context));
   	}
   
  -	rangestatus = ap_set_byterange(r);
   	ap_send_http_header(r);
   	
   	if (!r->header_only) {
  -	    if (!rangestatus) {
  -		ap_send_mmap(mm, r, 0, r->finfo.size);
  -	    }
  -	    else {
  -		apr_off_t offset;
  -		apr_size_t length;
  -		while (ap_each_byterange(r, &offset, &length)) {
  -		    ap_send_mmap(mm, r, offset, length);
  -		}
  -	    }
  +            ap_send_mmap(mm, r, 0, r->finfo.size);
   	}
       }
   #endif
  @@ -3056,6 +3033,7 @@
       apr_close(fd);
       return OK;
   }
  +
   /*
    * coalesce_filter()
    * This is a simple filter to coalesce many small buckets into one large
  @@ -3563,10 +3541,12 @@
        * filters
        */
       ap_hook_insert_filter(core_insert_filter, NULL, NULL, AP_HOOK_MIDDLE);
  +
       ap_register_input_filter("HTTP_IN", ap_http_filter, AP_FTYPE_CONNECTION);
       ap_register_input_filter("DECHUNK", ap_dechunk_filter, AP_FTYPE_TRANSCODE);
       ap_register_input_filter("CORE_IN", core_input_filter, AP_FTYPE_NETWORK);
  -    ap_register_output_filter("HTTP_HEADER", ap_http_header_filter, AP_FTYPE_HTTP_HEADER);
  +    ap_register_output_filter("HTTP_HEADER", ap_http_header_filter, 
  +                              AP_FTYPE_HTTP_HEADER);
       ap_register_output_filter("CONTENT_LENGTH", ap_content_length_filter, 
                                 AP_FTYPE_HTTP_HEADER);
       ap_register_output_filter("CORE", core_output_filter, AP_FTYPE_NETWORK);
  @@ -3574,6 +3554,8 @@
                                 AP_FTYPE_CONTENT);
       ap_register_output_filter("CHUNK", chunk_filter, AP_FTYPE_TRANSCODE);
       ap_register_output_filter("COALESCE", coalesce_filter, AP_FTYPE_CONNECTION);
  +    ap_register_output_filter("BYTERANGE", ap_byterange_filter, 
  +                              AP_FTYPE_TRANSCODE);
   }
   
   AP_DECLARE_DATA module core_module = {
  
  
  
  1.233     +198 -182  apache-2.0/src/main/http_protocol.c
  
  Index: http_protocol.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/main/http_protocol.c,v
  retrieving revision 1.232
  retrieving revision 1.233
  diff -u -r1.232 -r1.233
  --- http_protocol.c	2000/11/07 22:41:09	1.232
  +++ http_protocol.c	2000/11/08 06:24:47	1.233
  @@ -98,42 +98,6 @@
   	    AP_HOOK_LINK(default_port)
   )
   
  -/* if this is the first error, then log an INFO message and shut down the
  - * connection.
  - */
  -static void check_first_conn_error(const request_rec *r, const char *operation,
  -                                   apr_status_t status)
  -{
  -    if (!r->connection->aborted) {
  -        if (status == 0)
  -            status = ap_berror(r->connection->client);
  -        ap_log_rerror(APLOG_MARK, APLOG_INFO, status, r,
  -                      "client stopped connection before %s completed",
  -                      operation);
  -        r->connection->aborted = 1;
  -    }
  -}
  -
  -static int checked_bputstrs(request_rec *r, ...)
  -{
  -    va_list va;
  -    int n;
  -
  -    if (r->connection->aborted)
  -        return EOF;
  -
  -    va_start(va, r);
  -    n = ap_vbputstrs(r->connection->client, va);
  -    va_end(va);
  -
  -    if (n < 0) {
  -        check_first_conn_error(r, "checked_bputstrs", 0);
  -        return EOF;
  -    }
  -
  -    return n;
  -}
  -
   /*
    * Builds the content-type that should be sent to the client from the
    * content-type specified.  The following rules are followed:
  @@ -215,169 +179,119 @@
       return (*start > 0 || *end < clength - 1);
   }
   
  -/* forward declare */
  -static int internal_byterange(int realreq, apr_off_t *tlength, request_rec *r,
  -                              const char **r_range, apr_off_t *offset,
  -                              apr_size_t *length);
  -
  -AP_DECLARE(int) ap_set_byterange(request_rec *r)
  -{
  -    const char *range;
  -    const char *if_range;
  -    const char *match;
  -    apr_off_t range_start;
  -    apr_off_t range_end;
  -
  -    if (!r->clength || 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.
  -     */
  +typedef struct byterange_ctx {
  +    ap_bucket_brigade *bb;
  +} byterange_ctx;
   
  -    if (!(range = apr_table_get(r->headers_in, "Range")))
  -        range = apr_table_get(r->headers_in, "Request-Range");
  +/* If we are dealing with a file bucket, there are some interesting
  + * optimizations that can be made later, but for now this should work
  + * for all bucket types, and later we should optimize this for
  + * file buckets.
  + */
  +AP_CORE_DECLARE(apr_status_t) ap_byterange_filter(ap_filter_t *f, ap_bucket_brigade *bb)
  +{
  +#define MIN_LENGTH(len1, len2) ((len1 > len2) ? len2 : len1)
  +    request_rec *r = f->r;
  +    byterange_ctx *ctx;
  +    ap_bucket *e;
  +    apr_off_t curr_offset = 0;
  +    apr_size_t curr_length = 0;
  +    ap_bucket_brigade *bsend = ap_brigade_create(r->pool);
  +    long range_start, range_end;
  +    char *range;
  +    char *ts;
  +    char *current;
  +    char *end = apr_pstrcat(r->pool, CRLF "--", r->boundary, "--" CRLF, NULL);
  +    char *bound = apr_pstrcat(r->pool, CRLF "--", r->boundary,
  +                                    CRLF "Content-type: ", 
  +                                    make_content_type(r, r->content_type),
  +                                    CRLF "Content-range: bytes ", 
  +                                    NULL);
   
  -    if (!range || strncasecmp(range, "bytes=", 6)) {
  -        return 0;
  +    ctx = f->ctx;
  +    if (ctx == NULL) {
  +        f->ctx = ctx = apr_pcalloc(r->pool, sizeof(*ctx));
       }
   
  -    /* 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.
  +    /* 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 ((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;
  -    }
  -
  -    if (!ap_strchr_c(range, ',')) {
  -        /* A single range */
  -        if (!parse_byterange(apr_pstrdup(r->pool, range + 6), r->clength,
  -                             &range_start, &range_end))
  -            return 0;
  -
  -        r->byterange = 1;
  -
  -        apr_table_setn(r->headers_out, "Content-Range",
  -                       apr_psprintf(r->pool,
  -                                    "bytes %" APR_OFF_T_FMT "-%" APR_OFF_T_FMT
  -                                    "/%" APR_OFF_T_FMT,
  -                                    range_start, range_end, r->clength));
  -        apr_table_setn(r->headers_out, "Content-Length",
  -                       apr_psprintf(r->pool, "%" APR_OFF_T_FMT,
  -                                    range_end - range_start + 1));
  -    }
  -    else {
  -        /* a multiple range */
  -        const char *r_range = apr_pstrdup(r->pool, range + 6);
  -        apr_off_t tlength = 0;
  -
  -        r->byterange = 2;
  -        r->boundary = apr_psprintf(r->pool, "%qx%lx",
  -				r->request_time, (long) getpid());
  -        while (internal_byterange(0, &tlength, r, &r_range, NULL, NULL))
  -            continue;
  -        apr_table_setn(r->headers_out, "Content-Length",
  -                       apr_psprintf(r->pool, "%" APR_OFF_T_FMT, tlength));
  +    if (!AP_BUCKET_IS_EOS(AP_BRIGADE_LAST(bb))) {
  +        ap_save_brigade(f, &ctx->bb, &bb);
  +        return APR_SUCCESS;
       }
  +    AP_BRIGADE_CONCAT(ctx->bb, bb);
   
  -    r->status = HTTP_PARTIAL_CONTENT;
  -    r->range = range + 6;
  +    bb = ctx->bb;
  +    while ((current = ap_getword(r->pool, &r->range, ',')) &&
  +           parse_byterange(current, r->clength, &range_start, &range_end)) {
  +        const char *str;
  +        apr_size_t n;
  +        char *loc;
   
  -    return 1;
  -}
  +        curr_length = range_end - range_start + 1;
  +        loc = range = apr_pcalloc(r->pool, curr_length + 1);
   
  -AP_DECLARE(int) ap_each_byterange(request_rec *r, apr_off_t *offset,
  -				  apr_size_t *length)
  -{
  -    return internal_byterange(1, NULL, r, &r->range, offset, length);
  -}
  +        e = AP_BRIGADE_FIRST(bb);
  +        curr_offset = 0;
  +        ap_bucket_read(e, &str, &n, AP_NONBLOCK_READ);
  +        while (range_start > (curr_offset + e->length)) {
  +            curr_offset += e->length;
  +            e = AP_BUCKET_NEXT(e);
  +            if (e == AP_BRIGADE_SENTINEL(bb)) {
  +                break;
  +            }
  +        }
  +        if (range_start != curr_offset) {
  +            /* If we get here, then we know that the beginning of this 
  +             * byte-range occurs someplace in the middle of the current bucket
  +             */
   
  -/* If this function is called with realreq=1, it will spit out
  - * the correct headers for a byterange chunk, and set offset and
  - * length to the positions they should be.
  - *
  - * If it is called with realreq=0, it will add to tlength the length
  - * it *would* have used with realreq=1.
  - *
  - * Either case will return 1 if it should be called again, and 0
  - * when done.
  - */
  -static int internal_byterange(int realreq, apr_off_t *tlength, request_rec *r,
  -                              const char **r_range, apr_off_t *offset,
  -                              apr_size_t *length)
  -{
  -    apr_off_t range_start;
  -    apr_off_t range_end;
  -    char *range;
  +            apr_cpystrn(loc, str + (range_start - curr_offset), 
  +                        MIN_LENGTH(curr_length + 1, e->length));
  +            loc += MIN_LENGTH(curr_length + 1, e->length);
  +            curr_length -= MIN_LENGTH(curr_length + 1, e->length);
  +            e = AP_BUCKET_NEXT(e);
  +        }
  +        
  +        do {
  +            if (curr_length == 0) {
  +                break;
  +            }
  +            ap_bucket_read(e, &str, &n, AP_NONBLOCK_READ);
  +            apr_cpystrn(loc, str + (range_start - curr_offset), 
  +                        MIN_LENGTH(curr_length + 1, e->length));
  +            loc += MIN_LENGTH(curr_length + 1, e->length);
  +            curr_length -= MIN_LENGTH(curr_length + 1, e->length);
  +            e = AP_BUCKET_NEXT(e);
  +        } while (e != AP_BRIGADE_SENTINEL(bb));
   
  -    if (!**r_range) {
           if (r->byterange > 1) {
  -            if (realreq) {
  -                /* ### this isn't "content" so we can't use ap_rvputs(), but
  -                 * ### it should be processed by non-processing filters. We
  -                 * ### have no "in-between" APIs yet, so send it to the
  -                 * ### network for now
  -                 */
  -                (void) checked_bputstrs(r, CRLF "--", r->boundary, "--" CRLF,
  -                                        NULL);
  -            }
  -	    else {
  -                *tlength += 4 + strlen(r->boundary) + 4;
  -            }
  -        }
  -        return 0;
  -    }
  +            e = ap_bucket_create_pool(bound, strlen(bound), r->pool);
  +            AP_BRIGADE_INSERT_TAIL(bsend, e);
   
  -    range = ap_getword(r->pool, r_range, ',');
  -    if (!parse_byterange(range, r->clength, &range_start, &range_end)) {
  -        /* Skip this one */
  -        return internal_byterange(realreq, tlength, r, r_range, offset,
  -                                  length);
  +            ts = apr_pcalloc(r->pool, MAX_STRING_LEN);
  +            apr_snprintf(ts, MAX_STRING_LEN, "%ld-%ld/%ld" CRLF CRLF, 
  +                         range_start, range_end, r->clength);
  +            e = ap_bucket_create_pool(ts, strlen(ts), r->pool);
  +            AP_BRIGADE_INSERT_TAIL(bsend, e);
  +        }
  +        
  +        e = ap_bucket_create_pool(range, strlen(range), r->pool);
  +        AP_BRIGADE_INSERT_TAIL(bsend, e);
       }
  -
       if (r->byterange > 1) {
  -        const char *ct = make_content_type(r, r->content_type);
  -        char ts[MAX_STRING_LEN];
  -
  -        apr_snprintf(ts, sizeof(ts),
  -                     "%" APR_OFF_T_FMT "-%" APR_OFF_T_FMT "/%" APR_OFF_T_FMT,
  -                     range_start, range_end, r->clength);
  -        if (realreq)
  -            (void) checked_bputstrs(r, CRLF "--", r->boundary,
  -                                    CRLF "Content-type: ", ct,
  -                                    CRLF "Content-range: bytes ", ts,
  -                                    CRLF CRLF, NULL);
  -        else
  -            *tlength += 4 + strlen(r->boundary) + 16 + strlen(ct) + 23 +
  -                        strlen(ts) + 4;
  +        e = ap_bucket_create_pool(end, strlen(end), r->pool);
  +        AP_BRIGADE_INSERT_TAIL(bsend, e);
       }
  +    e = ap_bucket_create_eos();
  +    AP_BRIGADE_INSERT_TAIL(bsend, e);
   
  -    if (realreq) {
  -        *offset = range_start;
  +    ap_brigade_destroy(bb);
  +    return ap_pass_brigade(f->next, bsend); 
  +}    
   
  -        /* ### we need to change ap_each_byterange() to fix this */
  -        *length = (apr_size_t) (range_end - range_start + 1);
  -    }
  -    else {
  -        *tlength += range_end - range_start + 1;
  -    }
  -    return 1;
  -}
  -
   AP_DECLARE(void) ap_set_content_length(request_rec *r, apr_off_t clength)
   {
       r->clength = clength;
  @@ -2323,6 +2237,95 @@
       return ap_pass_brigade(f->next, b);
   }
   
  +static int ap_set_byterange(request_rec *r)
  +{
  +    const char *range, *if_range, *match;
  +    long range_start, range_end;
  +
  +    if (!r->clength || 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;
  +    }
  +
  +    if (!ap_strchr_c(range, ',')) {
  +        /* A single range */
  +        if (!parse_byterange(apr_pstrdup(r->pool, range + 6), r->clength, &range_start,
&range_end)) {
  +            return 0;
  +        }
  +        apr_table_setn(r->headers_out, "Content-Range",
  +                       apr_psprintf(r->pool,
  +                                    "bytes %" APR_OFF_T_FMT "-%" APR_OFF_T_FMT
  +                                    "/%" APR_OFF_T_FMT,
  +                                    range_start, range_end, r->clength));
  +        apr_table_setn(r->headers_out, "Content-Length",
  +                       apr_psprintf(r->pool, "%" APR_OFF_T_FMT,
  +                                    range_end - range_start + 1));
  +
  +        r->byterange = 1;
  +    }
  +    else {
  +#if 0
  +        const char *temp = apr_pstrdup(r->pool, range + 6);
  +        char *current;
  +        long tlength = 0;
  +#endif
  +        /* a multiple range */
  +
  +        r->byterange = 2;
  +        r->boundary = apr_psprintf(r->pool, "%qx%lx",
  +				r->request_time, (long) getpid());
  +#if 0
  +        /* This computes the content-length for the actual data, but it does
  +         * not add the length of the byte-range headers, so it is an invalid
  +         * content-length.  I am leaving the code here, so that other people
  +         * can see what I have done. rbb
  +         */
  +        while ((current = ap_getword(r->pool, &temp, ',')) &&
  +               parse_byterange(current, r->clength, &range_start, &range_end))
{
  +            tlength += (range_end - range_start + 2);
  +        }
  +        apr_table_setn(r->headers_out, "Content-Length",
  +            apr_psprintf(r->pool, "%ld", tlength));
  +#endif
  +    }
  +
  +    r->status = HTTP_PARTIAL_CONTENT;
  +    r->range = range + 6;
  +
  +    return 1;
  +}
  +
  +
   AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, ap_bucket_brigade
*b)
   {
       int i;
  @@ -2376,12 +2379,18 @@
   /*      ap_add_output_filter("COALESCE", NULL, r, r->connection); */
       }
   
  +    ap_set_byterange(r);
  +
       if (r->byterange > 1) {
           apr_table_setn(r->headers_out, "Content-Type",
   		       apr_pstrcat(r->pool, "multipart",
   				   use_range_x(r) ? "/x-" : "/",
   				   "byteranges; boundary=",
   				   r->boundary, NULL));
  +        /* Remove the content-length until we figure out how to compute
  +         * it correctly.
  +         */
  +        apr_table_unset(r->headers_out, "Content-Length");
       }
       else {
   	apr_table_setn(r->headers_out, "Content-Type",
  @@ -2441,11 +2450,18 @@
       ap_pass_brigade(f->next, b2);
   
       if (r->chunked) {
  -        /* We can't add this filters until we have already sent the headers.
  +        /* We can't add this filter until we have already sent the headers.
            * If we add it before this point, then the headers will be chunked
            * as well, and that is just wrong.
            */
           ap_add_output_filter("CHUNK", NULL, r, r->connection);
  +    }
  +    if (r->byterange) {
  +        /* We can't add this filter until we have already sent the headers.
  +         * If we add it before this point, then the headers will be chunked
  +         * as well, and that is just wrong.
  +         */
  +        ap_add_output_filter("BYTERANGE", NULL, r, r->connection);
       }
   
       /* Don't remove this filter until after we have added the CHUNK filter.
  
  
  

Mime
View raw message