Mercurial > hg > nginx-ranges
view src/http/ngx_http_postpone_filter_module.c @ 391:1d9bef53cd8e
Range filter: late_ranges functionality.
Add one more filtering point after postpone filter. This allows to serve
range capable replies with subrequests. It's not as efficient as range
filtering for static data (i.e. doesn't save us from reading data from
disk if some filter needs them in memory), but it may save some network
bandwidth for us and for our users.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 21 Jul 2008 05:33:01 +0400 |
parents | 12defd37f578 |
children | cdd5890b5538 b4f69f2ef02c |
line wrap: on
line source
/* * Copyright (C) Igor Sysoev */ #include <ngx_config.h> #include <ngx_core.h> #include <ngx_http.h> static ngx_int_t ngx_http_postpone_filter_output_postponed_request(ngx_http_request_t *r); static ngx_int_t ngx_http_postpone_filter_init(ngx_conf_t *cf); static ngx_http_module_t ngx_http_postpone_filter_module_ctx = { NULL, /* preconfiguration */ ngx_http_postpone_filter_init, /* postconfiguration */ 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_postpone_filter_module = { NGX_MODULE_V1, &ngx_http_postpone_filter_module_ctx, /* module context */ NULL, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ NULL, /* exit master */ NGX_MODULE_V1_PADDING }; static ngx_http_output_body_filter_pt ngx_http_next_filter; static ngx_int_t ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_int_t rc; ngx_chain_t *out; ngx_http_postponed_request_t *pr, **ppr; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http postpone filter \"%V?%V\" %p", &r->uri, &r->args, in); if (r != r->connection->data || (r->postponed && in)) { if (r->postponed) { for (pr = r->postponed; pr->next; pr = pr->next) { /* void */ } ppr = pr->request ? &pr->next : NULL; } else { ppr = &r->postponed; #if (NGX_SUPPRESS_WARN) pr = NULL; #endif } if (ppr) { pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t)); if (pr == NULL) { return NGX_ERROR; } *ppr = pr; pr->request = NULL; pr->out = NULL; pr->next = NULL; } if (ngx_chain_add_copy(r->pool, &pr->out, in) == NGX_ERROR) { return NGX_ERROR; } #if 1 { ngx_chain_t *cl; ngx_buf_t *b = NULL; for (cl = pr->out; cl; cl = cl->next) { if (cl->buf == b) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "the same buf was used in postponed %p %p", b, b->pos); ngx_debug_point(); return NGX_ERROR; } b = cl->buf; } } #endif if (r != r->connection->data || r->postponed->request) { return NGX_AGAIN; } } if (r->postponed) { out = r->postponed->out; if (out) { r->postponed = r->postponed->next; } } else { out = in; } rc = NGX_OK; if (out || (r->connection->buffered & (NGX_HTTP_LOWLEVEL_BUFFERED|NGX_LOWLEVEL_BUFFERED))) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http postpone filter out \"%V?%V\"", &r->uri, &r->args); if (!(out && out->next == NULL && ngx_buf_sync_only(out->buf))) { rc = ngx_http_next_filter(r->main, out); if (rc == NGX_ERROR) { /* NGX_ERROR may be returned by any filter */ r->connection->error = 1; } } } if (r->postponed == NULL) { return rc; } rc = ngx_http_postpone_filter_output_postponed_request(r); if (rc == NGX_ERROR) { /* NGX_ERROR may be returned by any filter */ r->connection->error = 1; } return rc; } static ngx_int_t ngx_http_postpone_filter_output_postponed_request(ngx_http_request_t *r) { ngx_int_t rc; ngx_chain_t *out; ngx_http_log_ctx_t *ctx; ngx_http_postponed_request_t *pr; for ( ;; ) { pr = r->postponed; if (pr == NULL) { break; } if (pr->request) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http postpone filter handle \"%V?%V\"", &pr->request->uri, &pr->request->args); ctx = r->connection->log->data; ctx->current_request = pr->request; if (!pr->request->done) { r->connection->data = pr->request; return NGX_AGAIN; } rc = ngx_http_postpone_filter_output_postponed_request(pr->request); if (rc == NGX_AGAIN || rc == NGX_ERROR) { return rc; } r->postponed = r->postponed->next; pr = r->postponed; } if (pr == NULL) { break; } out = pr->out; if (out) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http postpone filter out postponed \"%V?%V\"", &r->uri, &r->args); if (!(out && out->next == NULL && ngx_buf_sync_only(out->buf))) { if (ngx_http_next_filter(r->main, out) == NGX_ERROR) { return NGX_ERROR; } } } r->postponed = r->postponed->next; } if (r->out) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http postpone filter out again \"%V?%V\"", &r->uri, &r->args); r->connection->data = r; return NGX_AGAIN; } return NGX_OK; } static ngx_int_t ngx_http_postpone_filter_init(ngx_conf_t *cf) { ngx_http_next_filter = ngx_http_top_body_filter; ngx_http_top_body_filter = ngx_http_postpone_filter; return NGX_OK; }