From: Jim Jagielski Date: Fri, 9 Sep 2011 16:02:21 +0000 (+0000) Subject: Reset X-Git-Tag: 2.3.15~279 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fe74b5b58a8b5666d56299103af78ef269ab5bd2;p=apache Reset git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1167264 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/http/byterange_filter.c b/modules/http/byterange_filter.c index 98d6fa6cff..859f414754 100644 --- a/modules/http/byterange_filter.c +++ b/modules/http/byterange_filter.c @@ -59,232 +59,10 @@ #define AP_DEFAULT_MAX_RANGES 200 #endif -#define MAX_PREALLOC_RANGES 100 - APLOG_USE_MODULE(http); -typedef struct indexes_t { - apr_off_t start; - apr_off_t end; -} indexes_t; - -/* - * returns number of ranges OR -1 if unsatisfiable - */ static int ap_set_byterange(request_rec *r, apr_off_t clength, - apr_array_header_t **indexes, int *overlaps, - int *reversals) -{ - const char *range; - const char *if_range; - const char *match; - const char *ct; - char *cur, **new; - apr_array_header_t *merged; - int num_ranges = 0, unsatisfiable = 0; - apr_off_t ostart = 0, oend = 0, sum_lengths = 0; - int in_merge = 0; - indexes_t *idx; - int ranges = 1; - const char *it; - - *overlaps = 0; - *reversals = 0; - 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) || r->status != HTTP_OK) { - return 0; - } - - /* is content already a single range? */ - if (apr_table_get(r->headers_out, "Content-Range")) { - return 0; - } - - /* is content already a multiple range? */ - if ((ct = apr_table_get(r->headers_out, "Content-Type")) - && (!strncasecmp(ct, "multipart/byteranges", 20) - || !strncasecmp(ct, "multipart/x-byteranges", 22))) { - 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; - } - } - - range += 6; - it = range; - while (*it) { - if (*it++ == ',') { - ranges++; - } - } - it = range; - if (ranges > MAX_PREALLOC_RANGES) { - ranges = MAX_PREALLOC_RANGES; - } - *indexes = apr_array_make(r->pool, ranges, sizeof(indexes_t)); - merged = apr_array_make(r->pool, ranges, sizeof(char *)); - while ((cur = ap_getword(r->pool, &range, ','))) { - char *dash; - char *errp; - apr_off_t number, start, end; - - if (!*cur) - break; - - /* - * Per RFC 2616 14.35.1: If there is at least one syntactically invalid - * byte-range-spec, we must ignore the whole header. - */ - - if (!(dash = strchr(cur, '-'))) { - return 0; - } - - if (dash == cur) { - /* In the form "-5" */ - if (apr_strtoff(&number, dash+1, &errp, 10) || *errp) { - return 0; - } - if (number < 1) { - return 0; - } - start = clength - number; - end = clength - 1; - } - else { - *dash++ = '\0'; - if (apr_strtoff(&number, cur, &errp, 10) || *errp) { - return 0; - } - start = number; - if (*dash) { - if (apr_strtoff(&number, dash, &errp, 10) || *errp) { - return 0; - } - end = number; - if (start > end) { - return 0; - } - } - else { /* "5-" */ - end = clength - 1; - } - } - - if (start < 0) { - start = 0; - } - if (start >= clength) { - unsatisfiable = 1; - continue; - } - if (end >= clength) { - end = clength - 1; - } - - if (!in_merge) { - /* new set */ - ostart = start; - oend = end; - in_merge = 1; - continue; - } - in_merge = 0; - - if (start >= ostart && end <= oend) { - in_merge = 1; - } - - if (start < ostart && end >= ostart-1) { - ostart = start; - (*reversals)++; - in_merge = 1; - } - if (end >= oend && start <= oend+1 ) { - oend = end; - in_merge = 1; - } - - if (in_merge) { - (*overlaps)++; - continue; - } else { - new = (char **)apr_array_push(merged); - *new = apr_psprintf(r->pool, "%" APR_OFF_T_FMT "-%" APR_OFF_T_FMT, - ostart, oend); - idx = (indexes_t *)apr_array_push(*indexes); - idx->start = ostart; - idx->end = oend; - sum_lengths += oend - ostart + 1; - /* new set again */ - in_merge = 1; - ostart = start; - oend = end; - num_ranges++; - } - } - - if (in_merge) { - new = (char **)apr_array_push(merged); - *new = apr_psprintf(r->pool, "%" APR_OFF_T_FMT "-%" APR_OFF_T_FMT, - ostart, oend); - idx = (indexes_t *)apr_array_push(*indexes); - idx->start = ostart; - idx->end = oend; - sum_lengths += oend - ostart + 1; - num_ranges++; - } - else if (num_ranges == 0 && unsatisfiable) { - /* If all ranges are unsatisfiable, we should return 416 */ - return -1; - } - if (sum_lengths >= clength) { - ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, - "Sum of ranges not smaller than file, ignoring."); - return 0; - } - - r->status = HTTP_PARTIAL_CONTENT; - r->range = apr_array_pstrcat(r->pool, merged, ','); - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "Range: %s | %s (%d : %d : %"APR_OFF_T_FMT")", - it, r->range, *overlaps, *reversals, clength); - - return num_ranges; -} + apr_array_header_t **indexes); /* * Here we try to be compatible with clients that want multipart/x-byteranges @@ -302,6 +80,7 @@ static int use_range_x(request_rec *r) } #define BYTERANGE_FMT "%" APR_OFF_T_FMT "-%" APR_OFF_T_FMT "/%" APR_OFF_T_FMT +#define MAX_PREALLOC_RANGES 100 static apr_status_t copy_brigade_range(apr_bucket_brigade *bb, apr_bucket_brigade *bbout, @@ -402,7 +181,12 @@ static apr_status_t copy_brigade_range(apr_bucket_brigade *bb, return APR_SUCCESS; } -static int get_max_ranges(request_rec *r) { +typedef struct indexes_t { + apr_off_t start; + apr_off_t end; +} indexes_t; + +static int get_max_ranges(request_rec *r) { core_dir_config *core_conf = ap_get_core_module_config(r->per_dir_config); if (core_conf->max_ranges >= 0 || core_conf->max_ranges == AP_MAXRANGES_UNLIMITED) { return core_conf->max_ranges; @@ -446,12 +230,8 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, indexes_t *idx; int i; int original_status; - int overlaps = 0; - int reversals = 0; - int max_ranges; - core_dir_config *core_conf = ap_get_core_module_config(r->per_dir_config); + int max_ranges = get_max_ranges(r); - max_ranges = (core_conf->max_ranges == -1 ? DEFAULT_MAX_RANGES : core_conf->max_ranges); /* * Iterate through the brigade until reaching EOS or a bucket with * unknown length. @@ -475,7 +255,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, } original_status = r->status; - num_ranges = ap_set_byterange(r, clength, &indexes, &overlaps, &reversals); + num_ranges = ap_set_byterange(r, clength, &indexes); /* We have nothing to do, get out of the way. */ if (num_ranges == 0 || (max_ranges >= 0 && num_ranges > max_ranges)) { @@ -601,3 +381,215 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, return ap_pass_brigade(f->next, bsend); } +static int ap_set_byterange(request_rec *r, apr_off_t clength, + apr_array_header_t **indexes) +{ + const char *range; + const char *if_range; + const char *match; + const char *ct; + char *cur, **new; + apr_array_header_t *merged; + int num_ranges = 0, unsatisfiable = 0; + apr_off_t ostart = 0, oend = 0, sum_lengths = 0; + int in_merge = 0; + indexes_t *idx; + int overlaps = 0, reversals = 0; + int ranges = 1; + const char *it; + + 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) || r->status != HTTP_OK) { + return 0; + } + + /* is content already a single range? */ + if (apr_table_get(r->headers_out, "Content-Range")) { + return 0; + } + + /* is content already a multiple range? */ + if ((ct = apr_table_get(r->headers_out, "Content-Type")) + && (!strncasecmp(ct, "multipart/byteranges", 20) + || !strncasecmp(ct, "multipart/x-byteranges", 22))) { + 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; + } + } + + range += 6; + it = range; + while (*it) { + if (*it++ == ',') { + ranges++; + } + } + it = range; + if (ranges > MAX_PREALLOC_RANGES) { + ranges = MAX_PREALLOC_RANGES; + } + *indexes = apr_array_make(r->pool, ranges, sizeof(indexes_t)); + merged = apr_array_make(r->pool, ranges, sizeof(char *)); + while ((cur = ap_getword(r->pool, &range, ','))) { + char *dash; + char *errp; + apr_off_t number, start, end; + + if (!*cur) + break; + + /* + * Per RFC 2616 14.35.1: If there is at least one syntactically invalid + * byte-range-spec, we must ignore the whole header. + */ + + if (!(dash = strchr(cur, '-'))) { + return 0; + } + + if (dash == cur) { + /* In the form "-5" */ + if (apr_strtoff(&number, dash+1, &errp, 10) || *errp) { + return 0; + } + if (number < 1) { + return 0; + } + start = clength - number; + end = clength - 1; + } + else { + *dash++ = '\0'; + if (apr_strtoff(&number, cur, &errp, 10) || *errp) { + return 0; + } + start = number; + if (*dash) { + if (apr_strtoff(&number, dash, &errp, 10) || *errp) { + return 0; + } + end = number; + if (start > end) { + return 0; + } + } + else { /* "5-" */ + end = clength - 1; + } + } + + if (start < 0) { + start = 0; + } + if (start >= clength) { + unsatisfiable = 1; + continue; + } + if (end >= clength) { + end = clength - 1; + } + + if (!in_merge) { + /* new set */ + ostart = start; + oend = end; + in_merge = 1; + continue; + } + in_merge = 0; + + if (start >= ostart && end <= oend) { + in_merge = 1; + } + + if (start < ostart && end >= ostart-1) { + ostart = start; + reversals++; + in_merge = 1; + } + if (end >= oend && start <= oend+1 ) { + oend = end; + in_merge = 1; + } + + if (in_merge) { + overlaps++; + continue; + } else { + new = (char **)apr_array_push(merged); + *new = apr_psprintf(r->pool, "%" APR_OFF_T_FMT "-%" APR_OFF_T_FMT, + ostart, oend); + idx = (indexes_t *)apr_array_push(*indexes); + idx->start = ostart; + idx->end = oend; + sum_lengths += oend - ostart + 1; + /* new set again */ + in_merge = 1; + ostart = start; + oend = end; + num_ranges++; + } + } + + if (in_merge) { + new = (char **)apr_array_push(merged); + *new = apr_psprintf(r->pool, "%" APR_OFF_T_FMT "-%" APR_OFF_T_FMT, + ostart, oend); + idx = (indexes_t *)apr_array_push(*indexes); + idx->start = ostart; + idx->end = oend; + sum_lengths += oend - ostart + 1; + num_ranges++; + } + else if (num_ranges == 0 && unsatisfiable) { + /* If all ranges are unsatisfiable, we should return 416 */ + return -1; + } + if (sum_lengths >= clength) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, + "Sum of ranges not smaller than file, ignoring."); + return 0; + } + + r->status = HTTP_PARTIAL_CONTENT; + r->range = apr_array_pstrcat(r->pool, merged, ','); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "Range: %s | %s (%d : %d : %"APR_OFF_T_FMT")", + it, r->range, overlaps, reversals, clength); + + return num_ranges; +}