diff --git a/auto/modules b/auto/modules index d06631d20..5736a46ba 100644 --- a/auto/modules +++ b/auto/modules @@ -43,7 +43,7 @@ fi HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES \ $HTTP_CHUNKED_FILTER_MODULE \ - $HTTP_RANGE_FILTER_MODULE \ + $HTTP_RANGE_HEADER_FILTER_MODULE \ $HTTP_CHARSET_FILTER_MODULE" HTTP_MODULES="$HTTP_MODULES $HTTP_STATIC_MODULE $HTTP_INDEX_MODULE" @@ -80,6 +80,8 @@ fi modules="$CORE_MODULES $EVENT_MODULES $HTTP_MODULES $HTTP_FILTER_MODULES \ $HTTP_HEADERS_FILTER_MODULE \ + $HTTP_COPY_FILTER_MODULE \ + $HTTP_RANGE_BODY_FILTER_MODULE \ $HTTP_NOT_MODIFIED_FILTER_MODULE" diff --git a/auto/sources b/auto/sources index a4035ca66..cbcc90ed0 100644 --- a/auto/sources +++ b/auto/sources @@ -173,13 +173,16 @@ HTTP_MODULES="ngx_http_module \ HTTP_FILE_CACHE_MODULE=ngx_http_cache_module HTTP_FILTER_MODULES="ngx_http_write_filter_module \ - ngx_http_output_filter_module \ ngx_http_header_filter_module" HTTP_CHUNKED_FILTER_MODULE=ngx_http_chunked_filter_module -HTTP_RANGE_FILTER_MODULE=ngx_http_range_filter_module HTTP_CHARSET_FILTER_MODULE=ngx_http_charset_filter_module HTTP_HEADERS_FILTER_MODULE=ngx_http_headers_filter_module +HTTP_COPY_FILTER_MODULE=ngx_http_copy_filter_module + +HTTP_RANGE_HEADER_FILTER_MODULE=ngx_http_range_header_filter_module +HTTP_RANGE_BODY_FILTER_MODULE=ngx_http_range_body_filter_module + HTTP_NOT_MODIFIED_FILTER_MODULE=ngx_http_not_modified_filter_module HTTP_STATIC_MODULE=ngx_http_static_module @@ -204,7 +207,7 @@ HTTP_SRCS="src/http/ngx_http.c \ src/http/ngx_http_headers.c \ src/http/ngx_http_header_filter.c \ src/http/ngx_http_write_filter.c \ - src/http/ngx_http_output_filter.c \ + src/http/ngx_http_copy_filter.c \ src/http/ngx_http_log_handler.c \ src/http/ngx_http_request_body.c \ src/http/ngx_http_parse_time.c \ diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c index 94e410495..b54cbafa8 100644 --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -81,7 +81,11 @@ int ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in) ctx->hunk = ctx->free->hunk; ctx->free = ctx->free->next; - } else if (ctx->hunks < ctx->bufs.num) { + } else if (out || ctx->hunks == ctx->bufs.num) { + + break; + + } else { size = ctx->bufs.size; @@ -118,9 +122,6 @@ int ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in) ctx->hunk->tag = ctx->tag; ctx->hunk->type |= NGX_HUNK_RECYCLED; ctx->hunks++; - - } else { - break; } } @@ -148,10 +149,6 @@ int ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in) *last_out = cl; last_out = &cl->next; ctx->hunk = NULL; - - if (ctx->free == NULL) { - break; - } } if (out == NULL && last != NGX_NONE) { diff --git a/src/http/modules/ngx_http_range_filter.c b/src/http/modules/ngx_http_range_filter.c index df32acf93..d63f4c8d5 100644 --- a/src/http/modules/ngx_http_range_filter.c +++ b/src/http/modules/ngx_http_range_filter.c @@ -44,10 +44,11 @@ typedef struct { } ngx_http_range_filter_ctx_t; -static ngx_int_t ngx_http_range_filter_init(ngx_cycle_t *cycle); +static ngx_int_t ngx_http_range_header_filter_init(ngx_cycle_t *cycle); +static ngx_int_t ngx_http_range_body_filter_init(ngx_cycle_t *cycle); -static ngx_http_module_t ngx_http_range_filter_module_ctx = { +static ngx_http_module_t ngx_http_range_header_filter_module_ctx = { NULL, /* pre conf */ NULL, /* create main configuration */ @@ -61,12 +62,36 @@ static ngx_http_module_t ngx_http_range_filter_module_ctx = { }; -ngx_module_t ngx_http_range_filter_module = { +ngx_module_t ngx_http_range_header_filter_module = { NGX_MODULE, - &ngx_http_range_filter_module_ctx, /* module context */ + &ngx_http_range_header_filter_module_ctx, /* module context */ NULL, /* module directives */ NGX_HTTP_MODULE, /* module type */ - ngx_http_range_filter_init, /* init module */ + ngx_http_range_header_filter_init, /* init module */ + NULL /* init child */ +}; + + +static ngx_http_module_t ngx_http_range_body_filter_module_ctx = { + NULL, /* pre conf */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL, /* merge location configuration */ +}; + + +ngx_module_t ngx_http_range_body_filter_module = { + NGX_MODULE, + &ngx_http_range_body_filter_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_range_body_filter_init, /* init module */ NULL /* init child */ }; @@ -88,13 +113,18 @@ static ngx_int_t ngx_http_range_header_filter(ngx_http_request_t *r) if (r->http_version < NGX_HTTP_VERSION_10 || r->headers_out.status != NGX_HTTP_OK || r->headers_out.content_length_n == -1 + || !(r->filter & NGX_HTTP_FILTER_ALLOW_RANGES)) +#if 0 /* STUB: we currently support ranges for file hunks only */ || !r->sendfile || r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY +#endif +#if 0 || (r->headers_out.content_encoding && r->headers_out.content_encoding->value.len)) +#endif { return ngx_http_next_header_filter(r); } @@ -294,7 +324,7 @@ static ngx_int_t ngx_http_range_header_filter(ngx_http_request_t *r) } #endif - ngx_http_create_ctx(r, ctx, ngx_http_range_filter_module, + ngx_http_create_ctx(r, ctx, ngx_http_range_body_filter_module, sizeof(ngx_http_range_filter_ctx_t), NGX_ERROR); len = 4 + 10 + 2 + 14 + r->headers_out.content_type->value.len @@ -414,7 +444,7 @@ static ngx_int_t ngx_http_range_body_filter(ngx_http_request_t *r, return ngx_http_next_body_filter(r, in); } - ctx = ngx_http_get_module_ctx(r, ngx_http_range_filter_module); + ctx = ngx_http_get_module_ctx(r, ngx_http_range_body_filter_module); ll = &out; for (i = 0; i < r->headers_out.ranges.nelts; i++) { @@ -483,11 +513,17 @@ static ngx_int_t ngx_http_range_body_filter(ngx_http_request_t *r, } -static ngx_int_t ngx_http_range_filter_init(ngx_cycle_t *cycle) +static ngx_int_t ngx_http_range_header_filter_init(ngx_cycle_t *cycle) { ngx_http_next_header_filter = ngx_http_top_header_filter; ngx_http_top_header_filter = ngx_http_range_header_filter; + return NGX_OK; +} + + +static ngx_int_t ngx_http_range_body_filter_init(ngx_cycle_t *cycle) +{ ngx_http_next_body_filter = ngx_http_top_body_filter; ngx_http_top_body_filter = ngx_http_range_body_filter; diff --git a/src/http/modules/ngx_http_static_handler.c b/src/http/modules/ngx_http_static_handler.c index ae1b8170d..d06113b8a 100644 --- a/src/http/modules/ngx_http_static_handler.c +++ b/src/http/modules/ngx_http_static_handler.c @@ -480,6 +480,7 @@ static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } + r->filter |= NGX_HTTP_FILTER_ALLOW_RANGES; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { diff --git a/src/http/ngx_http_copy_filter.c b/src/http/ngx_http_copy_filter.c new file mode 100644 index 000000000..62485ed72 --- /dev/null +++ b/src/http/ngx_http_copy_filter.c @@ -0,0 +1,127 @@ + +#include +#include +#include + + +typedef struct { + ngx_bufs_t bufs; +} ngx_http_copy_filter_conf_t; + + +static void *ngx_http_copy_filter_create_conf(ngx_conf_t *cf); +static char *ngx_http_copy_filter_merge_conf(ngx_conf_t *cf, + void *parent, void *child); +static ngx_int_t ngx_http_copy_filter_init(ngx_cycle_t *cycle); + + +static ngx_command_t ngx_http_copy_filter_commands[] = { + + {ngx_string("output_buffers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, + ngx_conf_set_bufs_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_copy_filter_conf_t, bufs), + NULL}, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_copy_filter_module_ctx = { + NULL, /* pre conf */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_copy_filter_create_conf, /* create location configuration */ + ngx_http_copy_filter_merge_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_copy_filter_module = { + NGX_MODULE, + &ngx_http_copy_filter_module_ctx, /* module context */ + ngx_http_copy_filter_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_copy_filter_init, /* init module */ + NULL /* init process */ +}; + + +static ngx_http_output_body_filter_pt ngx_http_next_filter; + + +ngx_int_t ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + ngx_output_chain_ctx_t *ctx; + ngx_http_copy_filter_conf_t *conf; + + if (r->connection->write->error) { + return NGX_ERROR; + } + + ctx = ngx_http_get_module_ctx(r->main ? r->main : r, + ngx_http_copy_filter_module); + + if (ctx == NULL) { + conf = ngx_http_get_module_loc_conf(r->main ? r->main : r, + ngx_http_copy_filter_module); + + ngx_http_create_ctx(r, ctx, ngx_http_copy_filter_module, + sizeof(ngx_output_chain_ctx_t), NGX_ERROR); + + ctx->sendfile = r->sendfile; + ctx->need_in_memory = r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY; + ctx->need_in_temp = r->filter & NGX_HTTP_FILTER_NEED_TEMP; + + ctx->pool = r->pool; + ctx->bufs = conf->bufs; + ctx->tag = (ngx_hunk_tag_t) &ngx_http_copy_filter_module; + + ctx->output_filter = (ngx_output_chain_filter_pt) ngx_http_next_filter; + ctx->filter_ctx = r; + + } + + return ngx_output_chain(ctx, in); +} + + +static void *ngx_http_copy_filter_create_conf(ngx_conf_t *cf) +{ + ngx_http_copy_filter_conf_t *conf; + + ngx_test_null(conf, + ngx_palloc(cf->pool, sizeof(ngx_http_copy_filter_conf_t)), + NULL); + + conf->bufs.num = 0; + + return conf; +} + + +static char *ngx_http_copy_filter_merge_conf(ngx_conf_t *cf, + void *parent, void *child) +{ + ngx_http_copy_filter_conf_t *prev = parent; + ngx_http_copy_filter_conf_t *conf = child; + + ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 1, 32768); + + return NULL; +} + + +static ngx_int_t ngx_http_copy_filter_init(ngx_cycle_t *cycle) +{ + ngx_http_next_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_copy_filter; + + return NGX_OK; +} + diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index b7eb95112..b8e1a195d 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -658,6 +658,27 @@ int ngx_http_send_header(ngx_http_request_t *r) } +ngx_int_t ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + ngx_int_t rc; + + if (r->connection->write->error) { + return NGX_ERROR; + } + + rc = ngx_http_top_body_filter(r, in); + + if (rc == NGX_ERROR) { + + /* NGX_ERROR could be returned by any filter */ + + r->connection->write->error = 1; + } + + return rc; +} + + int ngx_http_redirect(ngx_http_request_t *r, int redirect) { /* STUB */ diff --git a/src/http/ngx_http_filter.h b/src/http/ngx_http_filter.h index c8fa8dfe1..d90947f05 100644 --- a/src/http/ngx_http_filter.h +++ b/src/http/ngx_http_filter.h @@ -5,6 +5,7 @@ #define NGX_HTTP_FILTER_NEED_IN_MEMORY 1 #define NGX_HTTP_FILTER_SSI_NEED_IN_MEMORY 2 #define NGX_HTTP_FILTER_NEED_TEMP 4 +#define NGX_HTTP_FILTER_ALLOW_RANGES 8 typedef int (*ngx_http_output_header_filter_pt)(ngx_http_request_t *r); diff --git a/src/http/ngx_http_output_filter.c b/src/http/ngx_http_output_filter.c deleted file mode 100644 index ce226a971..000000000 --- a/src/http/ngx_http_output_filter.c +++ /dev/null @@ -1,125 +0,0 @@ - -#include -#include -#include - - -typedef struct { - ngx_bufs_t bufs; -} ngx_http_output_filter_conf_t; - - -static void *ngx_http_output_filter_create_conf(ngx_conf_t *cf); -static char *ngx_http_output_filter_merge_conf(ngx_conf_t *cf, - void *parent, void *child); - - -static ngx_command_t ngx_http_output_filter_commands[] = { - - {ngx_string("output_buffers"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, - ngx_conf_set_bufs_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_output_filter_conf_t, bufs), - NULL}, - - ngx_null_command -}; - - -static ngx_http_module_t ngx_http_output_filter_module_ctx = { - NULL, /* pre conf */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_output_filter_create_conf, /* create location configuration */ - ngx_http_output_filter_merge_conf /* merge location configuration */ -}; - - -ngx_module_t ngx_http_output_filter_module = { - NGX_MODULE, - &ngx_http_output_filter_module_ctx, /* module context */ - ngx_http_output_filter_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - NULL, /* init module */ - NULL /* init child */ -}; - - - -ngx_int_t ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in) -{ - ngx_int_t rc; - ngx_output_chain_ctx_t *ctx; - ngx_http_output_filter_conf_t *conf; - - if (r->connection->write->error) { - return NGX_ERROR; - } - - ctx = ngx_http_get_module_ctx(r->main ? r->main : r, - ngx_http_output_filter_module); - - if (ctx == NULL) { - conf = ngx_http_get_module_loc_conf(r->main ? r->main : r, - ngx_http_output_filter_module); - - ngx_http_create_ctx(r, ctx, ngx_http_output_filter_module, - sizeof(ngx_output_chain_ctx_t), NGX_ERROR); - - ctx->sendfile = r->sendfile; - ctx->need_in_memory = r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY; - ctx->need_in_temp = r->filter & NGX_HTTP_FILTER_NEED_TEMP; - - ctx->pool = r->pool; - ctx->bufs = conf->bufs; - ctx->tag = (ngx_hunk_tag_t) &ngx_http_output_filter_module; - - ctx->output_filter = (ngx_output_chain_filter_pt) - ngx_http_top_body_filter; - ctx->filter_ctx = r; - - } - - rc = ngx_output_chain(ctx, in); - - if (rc == NGX_ERROR) { - - /* NGX_ERROR could be returned by any filter */ - - r->connection->write->error = 1; - } - - return rc; -} - - -static void *ngx_http_output_filter_create_conf(ngx_conf_t *cf) -{ - ngx_http_output_filter_conf_t *conf; - - ngx_test_null(conf, - ngx_palloc(cf->pool, sizeof(ngx_http_output_filter_conf_t)), - NULL); - - conf->bufs.num = 0; - - return conf; -} - - -static char *ngx_http_output_filter_merge_conf(ngx_conf_t *cf, - void *parent, void *child) -{ - ngx_http_output_filter_conf_t *prev = parent; - ngx_http_output_filter_conf_t *conf = child; - - ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 1, 32768); - - return NULL; -}