Loading modules/http/byterange_filter.c +229 −221 Changes for modules/http/byterange_filter.c: 229 added lines, 221 removed lines. Original line number Diff line number Diff line Loading @@ -59,10 +59,232 @@ #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); 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; } /* * Here we try to be compatible with clients that want multipart/x-byteranges Loading @@ -80,7 +302,6 @@ 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, Loading Loading @@ -181,11 +402,6 @@ static apr_status_t copy_brigade_range(apr_bucket_brigade *bb, return APR_SUCCESS; } 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) { Loading Loading @@ -230,8 +446,12 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, indexes_t *idx; int i; int original_status; int max_ranges = get_max_ranges(r); int overlaps = 0; int reversals = 0; int max_ranges; core_dir_config *core_conf = ap_get_core_module_config(r->per_dir_config); 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. Loading @@ -255,7 +475,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); num_ranges = ap_set_byterange(r, clength, &indexes, &overlaps, &reversals); /* We have nothing to do, get out of the way. */ if (num_ranges == 0 || (max_ranges >= 0 && num_ranges > max_ranges)) { Loading Loading @@ -381,215 +601,3 @@ 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; } Loading
modules/http/byterange_filter.c +229 −221 Changes for modules/http/byterange_filter.c: 229 added lines, 221 removed lines. Original line number Diff line number Diff line Loading @@ -59,10 +59,232 @@ #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); 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; } /* * Here we try to be compatible with clients that want multipart/x-byteranges Loading @@ -80,7 +302,6 @@ 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, Loading Loading @@ -181,11 +402,6 @@ static apr_status_t copy_brigade_range(apr_bucket_brigade *bb, return APR_SUCCESS; } 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) { Loading Loading @@ -230,8 +446,12 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, indexes_t *idx; int i; int original_status; int max_ranges = get_max_ranges(r); int overlaps = 0; int reversals = 0; int max_ranges; core_dir_config *core_conf = ap_get_core_module_config(r->per_dir_config); 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. Loading @@ -255,7 +475,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); num_ranges = ap_set_byterange(r, clength, &indexes, &overlaps, &reversals); /* We have nothing to do, get out of the way. */ if (num_ranges == 0 || (max_ranges >= 0 && num_ranges > max_ranges)) { Loading Loading @@ -381,215 +601,3 @@ 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; }