} ngx_http_range_filter_ctx_t;
-ngx_int_t ngx_http_range_parse(ngx_http_request_t *r,
- ngx_http_range_filter_ctx_t *ctx);
+static ngx_int_t ngx_http_range_parse(ngx_http_request_t *r,
+ ngx_http_range_filter_ctx_t *ctx, ngx_uint_t ranges);
static ngx_int_t ngx_http_range_singlepart_header(ngx_http_request_t *r,
ngx_http_range_filter_ctx_t *ctx);
static ngx_int_t ngx_http_range_multipart_header(ngx_http_request_t *r,
ngx_http_range_header_filter(ngx_http_request_t *r)
{
time_t if_range;
- ngx_int_t rc;
+ ngx_http_core_loc_conf_t *clcf;
ngx_http_range_filter_ctx_t *ctx;
if (r->http_version < NGX_HTTP_VERSION_10
return ngx_http_next_header_filter(r);
}
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+ if (clcf->max_ranges == 0) {
+ return ngx_http_next_header_filter(r);
+ }
+
if (r->headers_in.range == NULL
|| r->headers_in.range->value.len < 7
|| ngx_strncasecmp(r->headers_in.range->value.data,
return NGX_ERROR;
}
- rc = ngx_http_range_parse(r, ctx);
-
- if (rc == NGX_OK) {
+ switch (ngx_http_range_parse(r, ctx, clcf->max_ranges)) {
+ case NGX_OK:
ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module);
r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT;
}
return ngx_http_range_multipart_header(r, ctx);
- }
- if (rc == NGX_HTTP_RANGE_NOT_SATISFIABLE) {
+ case NGX_HTTP_RANGE_NOT_SATISFIABLE:
return ngx_http_range_not_satisfiable(r);
- }
- /* rc == NGX_ERROR */
+ case NGX_ERROR:
+ return NGX_ERROR;
- return rc;
+ default: /* NGX_DECLINED */
+ break;
+ }
next_filter:
}
-ngx_int_t
-ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx)
+static ngx_int_t
+ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx,
+ ngx_uint_t ranges)
{
u_char *p;
- off_t start, end;
+ off_t start, end, size, content_length;
ngx_uint_t suffix;
ngx_http_range_t *range;
p = r->headers_in.range->value.data + 6;
+ size = 0;
+ content_length = r->headers_out.content_length_n;
for ( ;; ) {
start = 0;
return NGX_HTTP_RANGE_NOT_SATISFIABLE;
}
- if (start >= r->headers_out.content_length_n) {
- return NGX_HTTP_RANGE_NOT_SATISFIABLE;
- }
-
while (*p == ' ') { p++; }
if (*p == ',' || *p == '\0') {
- range = ngx_array_push(&ctx->ranges);
- if (range == NULL) {
- return NGX_ERROR;
- }
-
- range->start = start;
- range->end = r->headers_out.content_length_n;
-
- if (*p++ != ',') {
- return NGX_OK;
- }
-
- continue;
+ end = content_length;
+ goto found;
}
} else {
}
if (suffix) {
- start = r->headers_out.content_length_n - end;
- end = r->headers_out.content_length_n - 1;
+ start = content_length - end;
+ end = content_length - 1;
}
- if (start > end) {
- return NGX_HTTP_RANGE_NOT_SATISFIABLE;
- }
+ if (end >= content_length) {
+ end = content_length;
- range = ngx_array_push(&ctx->ranges);
- if (range == NULL) {
- return NGX_ERROR;
+ } else {
+ end++;
}
- range->start = start;
+ found:
- if (end >= r->headers_out.content_length_n) {
- /*
- * Download Accelerator sends the last byte position
- * that equals to the file length
- */
- range->end = r->headers_out.content_length_n;
+ if (start < end) {
+ range = ngx_array_push(&ctx->ranges);
+ if (range == NULL) {
+ return NGX_ERROR;
+ }
- } else {
- range->end = end + 1;
+ range->start = start;
+ range->end = end;
+
+ size += end - start;
+
+ if (ranges-- == 0) {
+ return NGX_DECLINED;
+ }
}
if (*p++ != ',') {
- return NGX_OK;
+ break;
}
}
+
+ if (ctx->ranges.nelts == 0) {
+ return NGX_HTTP_RANGE_NOT_SATISFIABLE;
+ }
+
+ if (size > content_length) {
+ return NGX_DECLINED;
+ }
+
+ return NGX_OK;
}
offsetof(ngx_http_core_loc_conf_t, if_modified_since),
&ngx_http_core_if_modified_since },
+ { ngx_string("max_ranges"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_core_loc_conf_t, max_ranges),
+ NULL },
+
{ ngx_string("chunked_transfer_encoding"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_flag_slot,
clcf->keepalive_disable = NGX_CONF_UNSET_UINT;
clcf->satisfy = NGX_CONF_UNSET_UINT;
clcf->if_modified_since = NGX_CONF_UNSET_UINT;
+ clcf->max_ranges = NGX_CONF_UNSET_UINT;
clcf->client_body_in_file_only = NGX_CONF_UNSET_UINT;
clcf->client_body_in_single_buffer = NGX_CONF_UNSET;
clcf->internal = NGX_CONF_UNSET;
NGX_HTTP_SATISFY_ALL);
ngx_conf_merge_uint_value(conf->if_modified_since, prev->if_modified_since,
NGX_HTTP_IMS_EXACT);
+ ngx_conf_merge_uint_value(conf->max_ranges, prev->max_ranges,
+ 0x7fffffff);
ngx_conf_merge_uint_value(conf->client_body_in_file_only,
prev->client_body_in_file_only, 0);
ngx_conf_merge_value(conf->client_body_in_single_buffer,