From c6742cff8e8b41f987c0fd8341913d93fd31ea42 Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Wed, 23 Jul 2008 16:18:37 +0000 Subject: split ngx_http_range_filter_module --- src/http/modules/ngx_http_range_filter_module.c | 332 +++++++++++++++--------- 1 file changed, 210 insertions(+), 122 deletions(-) (limited to 'src') diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index e2137f299..8f5ff7976 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -58,6 +58,20 @@ typedef struct { } 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_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_filter_ctx_t *ctx); +static ngx_int_t ngx_http_range_test_overlapped(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in); +static ngx_int_t ngx_http_range_singlepart_body(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in); +static ngx_int_t ngx_http_range_multipart_body(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in); +static ngx_int_t ngx_http_range_not_satisfiable(ngx_http_request_t *r); + static ngx_int_t ngx_http_range_header_filter_init(ngx_conf_t *cf); static ngx_int_t ngx_http_range_body_filter_init(ngx_conf_t *cf); @@ -131,15 +145,8 @@ static ngx_http_output_body_filter_pt ngx_http_next_body_filter; static ngx_int_t ngx_http_range_header_filter(ngx_http_request_t *r) { - u_char *p; - size_t len; - off_t start, end; time_t if_range; ngx_int_t rc; - ngx_uint_t suffix, i; - ngx_atomic_uint_t boundary; - ngx_table_elt_t *content_range; - ngx_http_range_t *range; ngx_http_range_filter_ctx_t *ctx; if (r->http_version < NGX_HTTP_VERSION_10 @@ -185,8 +192,54 @@ ngx_http_range_header_filter(ngx_http_request_t *r) return NGX_ERROR; } - rc = 0; - range = NULL; + rc = ngx_http_range_parse(r, ctx); + + if (rc == NGX_OK) { + + ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); + + r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; + + if (ctx->ranges.nelts == 1) { + return ngx_http_range_singlepart_header(r, ctx); + } + + return ngx_http_range_multipart_header(r, ctx); + } + + if (rc == NGX_HTTP_RANGE_NOT_SATISFIABLE) { + return ngx_http_range_not_satisfiable(r); + } + + /* rc == NGX_ERROR */ + + return rc; + +next_filter: + + r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); + if (r->headers_out.accept_ranges == NULL) { + return NGX_ERROR; + } + + r->headers_out.accept_ranges->hash = 1; + r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1; + r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges"; + r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1; + r->headers_out.accept_ranges->value.data = (u_char *) "bytes"; + + return ngx_http_next_header_filter(r); +} + + +ngx_int_t +ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx) +{ + u_char *p; + off_t start, end; + ngx_uint_t suffix; + ngx_http_range_t *range; + p = r->headers_in.range->value.data + 6; for ( ;; ) { @@ -198,8 +251,7 @@ ngx_http_range_header_filter(ngx_http_request_t *r) if (*p != '-') { if (*p < '0' || *p > '9') { - rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; - break; + return NGX_HTTP_RANGE_NOT_SATISFIABLE; } while (*p >= '0' && *p <= '9') { @@ -209,13 +261,11 @@ ngx_http_range_header_filter(ngx_http_request_t *r) while (*p == ' ') { p++; } if (*p++ != '-') { - rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; - break; + return NGX_HTTP_RANGE_NOT_SATISFIABLE; } if (start >= r->headers_out.content_length_n) { - rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; - break; + return NGX_HTTP_RANGE_NOT_SATISFIABLE; } while (*p == ' ') { p++; } @@ -230,7 +280,7 @@ ngx_http_range_header_filter(ngx_http_request_t *r) range->end = r->headers_out.content_length_n; if (*p++ != ',') { - break; + return NGX_OK; } continue; @@ -242,8 +292,7 @@ ngx_http_range_header_filter(ngx_http_request_t *r) } if (*p < '0' || *p > '9') { - rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; - break; + return NGX_HTTP_RANGE_NOT_SATISFIABLE; } while (*p >= '0' && *p <= '9') { @@ -253,8 +302,7 @@ ngx_http_range_header_filter(ngx_http_request_t *r) while (*p == ' ') { p++; } if (*p != ',' && *p != '\0') { - rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; - break; + return NGX_HTTP_RANGE_NOT_SATISFIABLE; } if (suffix) { @@ -263,8 +311,7 @@ ngx_http_range_header_filter(ngx_http_request_t *r) } if (start > end) { - rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; - break; + return NGX_HTTP_RANGE_NOT_SATISFIABLE; } range = ngx_array_push(&ctx->ranges); @@ -286,84 +333,65 @@ ngx_http_range_header_filter(ngx_http_request_t *r) } if (*p++ != ',') { - break; + return NGX_OK; } } +} - if (rc) { - - /* rc == NGX_HTTP_RANGE_NOT_SATISFIABLE */ - - r->headers_out.status = rc; - - content_range = ngx_list_push(&r->headers_out.headers); - if (content_range == NULL) { - return NGX_ERROR; - } - - r->headers_out.content_range = content_range; - - content_range->hash = 1; - content_range->key.len = sizeof("Content-Range") - 1; - content_range->key.data = (u_char *) "Content-Range"; - - content_range->value.data = ngx_pnalloc(r->pool, - sizeof("bytes */") - 1 + NGX_OFF_T_LEN); - if (content_range->value.data == NULL) { - return NGX_ERROR; - } - - content_range->value.len = ngx_sprintf(content_range->value.data, - "bytes */%O", - r->headers_out.content_length_n) - - content_range->value.data; - ngx_http_clear_content_length(r); +static ngx_int_t +ngx_http_range_singlepart_header(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx) +{ + ngx_table_elt_t *content_range; + ngx_http_range_t *range; - return rc; + content_range = ngx_list_push(&r->headers_out.headers); + if (content_range == NULL) { + return NGX_ERROR; } - ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); - - r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; + r->headers_out.content_range = content_range; - if (ctx->ranges.nelts == 1) { + content_range->hash = 1; + content_range->key.len = sizeof("Content-Range") - 1; + content_range->key.data = (u_char *) "Content-Range"; - content_range = ngx_list_push(&r->headers_out.headers); - if (content_range == NULL) { - return NGX_ERROR; - } - - r->headers_out.content_range = content_range; + content_range->value.data = ngx_pnalloc(r->pool, + sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN); + if (content_range->value.data == NULL) { + return NGX_ERROR; + } - content_range->hash = 1; - content_range->key.len = sizeof("Content-Range") - 1; - content_range->key.data = (u_char *) "Content-Range"; + /* "Content-Range: bytes SSSS-EEEE/TTTT" header */ - content_range->value.data = - ngx_pnalloc(r->pool, sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN); - if (content_range->value.data == NULL) { - return NGX_ERROR; - } + range = ctx->ranges.elts; - /* "Content-Range: bytes SSSS-EEEE/TTTT" header */ + content_range->value.len = ngx_sprintf(content_range->value.data, + "bytes %O-%O/%O", + range->start, range->end - 1, + r->headers_out.content_length_n) + - content_range->value.data; - content_range->value.len = ngx_sprintf(content_range->value.data, - "bytes %O-%O/%O", - range->start, range->end - 1, - r->headers_out.content_length_n) - - content_range->value.data; + r->headers_out.content_length_n = range->end - range->start; - r->headers_out.content_length_n = range->end - range->start; + if (r->headers_out.content_length) { + r->headers_out.content_length->hash = 0; + r->headers_out.content_length = NULL; + } - if (r->headers_out.content_length) { - r->headers_out.content_length->hash = 0; - r->headers_out.content_length = NULL; - } + return ngx_http_next_header_filter(r); +} - return ngx_http_next_header_filter(r); - } +static ngx_int_t +ngx_http_range_multipart_header(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx) +{ + size_t len; + ngx_uint_t i; + ngx_http_range_t *range; + ngx_atomic_uint_t boundary; /* TODO: what if no content_type ?? */ @@ -465,32 +493,47 @@ ngx_http_range_header_filter(ngx_http_request_t *r) } return ngx_http_next_header_filter(r); +} -next_filter: - r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); - if (r->headers_out.accept_ranges == NULL) { +static ngx_int_t +ngx_http_range_not_satisfiable(ngx_http_request_t *r) +{ + ngx_table_elt_t *content_range; + + r->headers_out.status = NGX_HTTP_RANGE_NOT_SATISFIABLE; + + content_range = ngx_list_push(&r->headers_out.headers); + if (content_range == NULL) { return NGX_ERROR; } - r->headers_out.accept_ranges->hash = 1; - r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1; - r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges"; - r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1; - r->headers_out.accept_ranges->value.data = (u_char *) "bytes"; + r->headers_out.content_range = content_range; - return ngx_http_next_header_filter(r); + content_range->hash = 1; + content_range->key.len = sizeof("Content-Range") - 1; + content_range->key.data = (u_char *) "Content-Range"; + + content_range->value.data = ngx_pnalloc(r->pool, + sizeof("bytes */") - 1 + NGX_OFF_T_LEN); + if (content_range->value.data == NULL) { + return NGX_ERROR; + } + + content_range->value.len = ngx_sprintf(content_range->value.data, + "bytes */%O", + r->headers_out.content_length_n) + - content_range->value.data; + + ngx_http_clear_content_length(r); + + return NGX_HTTP_RANGE_NOT_SATISFIABLE; } static ngx_int_t ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { - off_t start, last; - ngx_buf_t *b, *buf; - ngx_uint_t i; - ngx_chain_t *out, *hcl, *rcl, *dcl, **ll; - ngx_http_range_t *range; ngx_http_range_filter_ctx_t *ctx; if (in == NULL) { @@ -503,17 +546,42 @@ ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in) return ngx_http_next_body_filter(r, in); } - buf = in->buf; - if (ngx_buf_special(in->buf)) { return ngx_http_next_body_filter(r, in); } + if (ngx_http_range_test_overlapped(r, ctx, in) != NGX_OK) { + return NGX_ERROR; + } + + if (ctx->ranges.nelts == 1) { + + /* + * the optimized version for the responses + * that are passed in the single buffer + */ + + return ngx_http_range_singlepart_body(r, ctx, in); + } + + return ngx_http_range_multipart_body(r, ctx, in); +} + + +static ngx_int_t +ngx_http_range_test_overlapped(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) +{ + off_t start, last; + ngx_buf_t *buf; + ngx_uint_t i; + ngx_http_range_t *range; + if (ctx->offset) { goto overlapped; } - range = ctx->ranges.elts; + buf = in->buf; if (!buf->last_buf) { @@ -526,6 +594,7 @@ ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in) last = buf->last - buf->start + ctx->offset; } + range = ctx->ranges.elts; for (i = 0; i < ctx->ranges.nelts; i++) { if (start > range[i].start || last < range[i].end) { goto overlapped; @@ -533,29 +602,55 @@ ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in) } } - /* - * the optimized version for the responses - * that are passed in the single buffer - */ - ctx->offset = ngx_buf_size(buf); - if (ctx->ranges.nelts == 1) { + return NGX_OK; - if (buf->in_file) { - buf->file_pos = range->start; - buf->file_last = range->end; - } +overlapped: - if (ngx_buf_in_memory(buf)) { - buf->pos = buf->start + (size_t) range->start; - buf->last = buf->start + (size_t) range->end; - } + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "range in overlapped buffers"); - return ngx_http_next_body_filter(r, in); + return NGX_ERROR; +} + + +static ngx_int_t +ngx_http_range_singlepart_body(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) +{ + ngx_buf_t *buf; + ngx_http_range_t *range; + + buf = in->buf; + range = ctx->ranges.elts; + + if (buf->in_file) { + buf->file_pos = range->start; + buf->file_last = range->end; } + if (ngx_buf_in_memory(buf)) { + buf->pos = buf->start + (size_t) range->start; + buf->last = buf->start + (size_t) range->end; + } + + return ngx_http_next_body_filter(r, in); +} + + +static ngx_int_t +ngx_http_range_multipart_body(ngx_http_request_t *r, + ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) +{ + ngx_buf_t *b, *buf; + ngx_uint_t i; + ngx_chain_t *out, *hcl, *rcl, *dcl, **ll; + ngx_http_range_t *range; + ll = &out; + buf = in->buf; + range = ctx->ranges.elts; for (i = 0; i < ctx->ranges.nelts; i++) { @@ -671,13 +766,6 @@ ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in) *ll = hcl; return ngx_http_next_body_filter(r, out); - -overlapped: - - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "range in overlapped buffers"); - - return NGX_ERROR; } -- cgit v1.2.3