One Level Up
Top Level
src/http/modules/ngx_http_sub_filter_module.c - nginx-1.7.10
Global variables defined
Data types defined
Functions defined
Source code
- #include <ngx_config.h>
- #include <ngx_core.h>
- #include <ngx_http.h>
- typedef struct {
- ngx_str_t match;
- ngx_http_complex_value_t value;
- ngx_hash_t types;
- ngx_flag_t once;
- ngx_flag_t last_modified;
- ngx_array_t *types_keys;
- } ngx_http_sub_loc_conf_t;
- typedef enum {
- sub_start_state = 0,
- sub_match_state,
- } ngx_http_sub_state_e;
- typedef struct {
- ngx_str_t match;
- ngx_str_t saved;
- ngx_str_t looked;
- ngx_uint_t once;
- ngx_buf_t *buf;
- u_char *pos;
- u_char *copy_start;
- u_char *copy_end;
- ngx_chain_t *in;
- ngx_chain_t *out;
- ngx_chain_t **last_out;
- ngx_chain_t *busy;
- ngx_chain_t *free;
- ngx_str_t sub;
- ngx_uint_t state;
- } ngx_http_sub_ctx_t;
- static ngx_int_t ngx_http_sub_output(ngx_http_request_t *r,
- ngx_http_sub_ctx_t *ctx);
- static ngx_int_t ngx_http_sub_parse(ngx_http_request_t *r,
- ngx_http_sub_ctx_t *ctx);
- static char * ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd,
- void *conf);
- static void *ngx_http_sub_create_conf(ngx_conf_t *cf);
- static char *ngx_http_sub_merge_conf(ngx_conf_t *cf,
- void *parent, void *child);
- static ngx_int_t ngx_http_sub_filter_init(ngx_conf_t *cf);
- static ngx_command_t ngx_http_sub_filter_commands[] = {
- { ngx_string("sub_filter"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
- ngx_http_sub_filter,
- NGX_HTTP_LOC_CONF_OFFSET,
- 0,
- NULL },
- { ngx_string("sub_filter_types"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
- ngx_http_types_slot,
- NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_sub_loc_conf_t, types_keys),
- &ngx_http_html_default_types[0] },
- { ngx_string("sub_filter_once"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
- ngx_conf_set_flag_slot,
- NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_sub_loc_conf_t, once),
- NULL },
- { ngx_string("sub_filter_last_modified"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
- ngx_conf_set_flag_slot,
- NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_sub_loc_conf_t, last_modified),
- NULL },
- ngx_null_command
- };
- static ngx_http_module_t ngx_http_sub_filter_module_ctx = {
- NULL,
- ngx_http_sub_filter_init,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_http_sub_create_conf,
- ngx_http_sub_merge_conf
- };
- ngx_module_t ngx_http_sub_filter_module = {
- NGX_MODULE_V1,
- &ngx_http_sub_filter_module_ctx,
- ngx_http_sub_filter_commands,
- NGX_HTTP_MODULE,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NGX_MODULE_V1_PADDING
- };
- static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
- static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
- static ngx_int_t
- ngx_http_sub_header_filter(ngx_http_request_t *r)
- {
- ngx_http_sub_ctx_t *ctx;
- ngx_http_sub_loc_conf_t *slcf;
- slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module);
- if (slcf->match.len == 0
- || r->headers_out.content_length_n == 0
- || ngx_http_test_content_type(r, &slcf->types) == NULL)
- {
- return ngx_http_next_header_filter(r);
- }
- ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_sub_ctx_t));
- if (ctx == NULL) {
- return NGX_ERROR;
- }
- ctx->saved.data = ngx_pnalloc(r->pool, slcf->match.len);
- if (ctx->saved.data == NULL) {
- return NGX_ERROR;
- }
- ctx->looked.data = ngx_pnalloc(r->pool, slcf->match.len);
- if (ctx->looked.data == NULL) {
- return NGX_ERROR;
- }
- ngx_http_set_ctx(r, ctx, ngx_http_sub_filter_module);
- ctx->match = slcf->match;
- ctx->last_out = &ctx->out;
- r->filter_need_in_memory = 1;
- if (r == r->main) {
- ngx_http_clear_content_length(r);
- if (!slcf->last_modified) {
- ngx_http_clear_last_modified(r);
- ngx_http_clear_etag(r);
- } else {
- ngx_http_weak_etag(r);
- }
- }
- return ngx_http_next_header_filter(r);
- }
- static ngx_int_t
- ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
- {
- ngx_int_t rc;
- ngx_buf_t *b;
- ngx_chain_t *cl;
- ngx_http_sub_ctx_t *ctx;
- ngx_http_sub_loc_conf_t *slcf;
- ctx = ngx_http_get_module_ctx(r, ngx_http_sub_filter_module);
- if (ctx == NULL) {
- return ngx_http_next_body_filter(r, in);
- }
- if ((in == NULL
- && ctx->buf == NULL
- && ctx->in == NULL
- && ctx->busy == NULL))
- {
- return ngx_http_next_body_filter(r, in);
- }
- if (ctx->once && (ctx->buf == NULL || ctx->in == NULL)) {
- if (ctx->busy) {
- if (ngx_http_sub_output(r, ctx) == NGX_ERROR) {
- return NGX_ERROR;
- }
- }
- return ngx_http_next_body_filter(r, in);
- }
-
- if (in) {
- if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {
- return NGX_ERROR;
- }
- }
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "http sub filter \"%V\"", &r->uri);
- while (ctx->in || ctx->buf) {
- if (ctx->buf == NULL) {
- ctx->buf = ctx->in->buf;
- ctx->in = ctx->in->next;
- ctx->pos = ctx->buf->pos;
- }
- if (ctx->state == sub_start_state) {
- ctx->copy_start = ctx->pos;
- ctx->copy_end = ctx->pos;
- }
- b = NULL;
- while (ctx->pos < ctx->buf->last) {
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "saved: \"%V\" state: %d", &ctx->saved, ctx->state);
- rc = ngx_http_sub_parse(r, ctx);
- ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "parse: %d, looked: \"%V\" %p-%p",
- rc, &ctx->looked, ctx->copy_start, ctx->copy_end);
- if (rc == NGX_ERROR) {
- return rc;
- }
- if (ctx->saved.len) {
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "saved: \"%V\"", &ctx->saved);
- cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
- if (cl == NULL) {
- return NGX_ERROR;
- }
- b = cl->buf;
- ngx_memzero(b, sizeof(ngx_buf_t));
- b->pos = ngx_pnalloc(r->pool, ctx->saved.len);
- if (b->pos == NULL) {
- return NGX_ERROR;
- }
- ngx_memcpy(b->pos, ctx->saved.data, ctx->saved.len);
- b->last = b->pos + ctx->saved.len;
- b->memory = 1;
- *ctx->last_out = cl;
- ctx->last_out = &cl->next;
- ctx->saved.len = 0;
- }
- if (ctx->copy_start != ctx->copy_end) {
- cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
- if (cl == NULL) {
- return NGX_ERROR;
- }
- b = cl->buf;
- ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t));
- b->pos = ctx->copy_start;
- b->last = ctx->copy_end;
- b->shadow = NULL;
- b->last_buf = 0;
- b->last_in_chain = 0;
- b->recycled = 0;
- if (b->in_file) {
- b->file_last = b->file_pos + (b->last - ctx->buf->pos);
- b->file_pos += b->pos - ctx->buf->pos;
- }
- *ctx->last_out = cl;
- ctx->last_out = &cl->next;
- }
- if (ctx->state == sub_start_state) {
- ctx->copy_start = ctx->pos;
- ctx->copy_end = ctx->pos;
- } else {
- ctx->copy_start = NULL;
- ctx->copy_end = NULL;
- }
- if (ctx->looked.len > (size_t) (ctx->pos - ctx->buf->pos)) {
- ctx->saved.len = ctx->looked.len - (ctx->pos - ctx->buf->pos);
- ngx_memcpy(ctx->saved.data, ctx->looked.data, ctx->saved.len);
- }
- if (rc == NGX_AGAIN) {
- continue;
- }
-
- cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
- if (cl == NULL) {
- return NGX_ERROR;
- }
- b = cl->buf;
- ngx_memzero(b, sizeof(ngx_buf_t));
- slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module);
- if (ctx->sub.data == NULL) {
- if (ngx_http_complex_value(r, &slcf->value, &ctx->sub)
- != NGX_OK)
- {
- return NGX_ERROR;
- }
- }
- if (ctx->sub.len) {
- b->memory = 1;
- b->pos = ctx->sub.data;
- b->last = ctx->sub.data + ctx->sub.len;
- } else {
- b->sync = 1;
- }
- *ctx->last_out = cl;
- ctx->last_out = &cl->next;
- ctx->once = slcf->once;
- continue;
- }
- if (ctx->looked.len
- && (ctx->buf->last_buf || ctx->buf->last_in_chain))
- {
- cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
- if (cl == NULL) {
- return NGX_ERROR;
- }
- b = cl->buf;
- ngx_memzero(b, sizeof(ngx_buf_t));
- b->pos = ctx->looked.data;
- b->last = b->pos + ctx->looked.len;
- b->memory = 1;
- *ctx->last_out = cl;
- ctx->last_out = &cl->next;
- ctx->looked.len = 0;
- }
- if (ctx->buf->last_buf || ctx->buf->flush || ctx->buf->sync
- || ngx_buf_in_memory(ctx->buf))
- {
- if (b == NULL) {
- cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
- if (cl == NULL) {
- return NGX_ERROR;
- }
- b = cl->buf;
- ngx_memzero(b, sizeof(ngx_buf_t));
- b->sync = 1;
- *ctx->last_out = cl;
- ctx->last_out = &cl->next;
- }
- b->last_buf = ctx->buf->last_buf;
- b->last_in_chain = ctx->buf->last_in_chain;
- b->flush = ctx->buf->flush;
- b->shadow = ctx->buf;
- b->recycled = ctx->buf->recycled;
- }
- ctx->buf = NULL;
- ctx->saved.len = ctx->looked.len;
- ngx_memcpy(ctx->saved.data, ctx->looked.data, ctx->looked.len);
- }
- if (ctx->out == NULL && ctx->busy == NULL) {
- return NGX_OK;
- }
- return ngx_http_sub_output(r, ctx);
- }
- static ngx_int_t
- ngx_http_sub_output(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx)
- {
- ngx_int_t rc;
- ngx_buf_t *b;
- ngx_chain_t *cl;
- #if 1
- b = NULL;
- for (cl = ctx->out; cl; cl = cl->next) {
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "sub out: %p %p", cl->buf, cl->buf->pos);
- if (cl->buf == b) {
- ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
- "the same buf was used in sub");
- ngx_debug_point();
- return NGX_ERROR;
- }
- b = cl->buf;
- }
- #endif
- rc = ngx_http_next_body_filter(r, ctx->out);
- if (ctx->busy == NULL) {
- ctx->busy = ctx->out;
- } else {
- for (cl = ctx->busy; cl->next; cl = cl->next) { }
- cl->next = ctx->out;
- }
- ctx->out = NULL;
- ctx->last_out = &ctx->out;
- while (ctx->busy) {
- cl = ctx->busy;
- b = cl->buf;
- if (ngx_buf_size(b) != 0) {
- break;
- }
- if (b->shadow) {
- b->shadow->pos = b->shadow->last;
- }
- ctx->busy = cl->next;
- if (ngx_buf_in_memory(b) || b->in_file) {
-
- cl->next = ctx->free;
- ctx->free = cl;
- }
- }
- if (ctx->in || ctx->buf) {
- r->buffered |= NGX_HTTP_SUB_BUFFERED;
- } else {
- r->buffered &= ~NGX_HTTP_SUB_BUFFERED;
- }
- return rc;
- }
- static ngx_int_t
- ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx)
- {
- u_char *p, *last, *copy_end, ch, match;
- size_t looked, i;
- ngx_http_sub_state_e state;
- if (ctx->once) {
- ctx->copy_start = ctx->pos;
- ctx->copy_end = ctx->buf->last;
- ctx->pos = ctx->buf->last;
- ctx->looked.len = 0;
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "once");
- return NGX_AGAIN;
- }
- state = ctx->state;
- looked = ctx->looked.len;
- last = ctx->buf->last;
- copy_end = ctx->copy_end;
- for (p = ctx->pos; p < last; p++) {
- ch = *p;
- ch = ngx_tolower(ch);
- if (state == sub_start_state) {
-
- match = ctx->match.data[0];
- for ( ;; ) {
- if (ch == match) {
- if (ctx->match.len == 1) {
- ctx->pos = p + 1;
- ctx->copy_end = p;
- return NGX_OK;
- }
- copy_end = p;
- ctx->looked.data[0] = *p;
- looked = 1;
- state = sub_match_state;
- goto match_started;
- }
- if (++p == last) {
- break;
- }
- ch = *p;
- ch = ngx_tolower(ch);
- }
- ctx->state = state;
- ctx->pos = p;
- ctx->looked.len = looked;
- ctx->copy_end = p;
- if (ctx->copy_start == NULL) {
- ctx->copy_start = ctx->buf->pos;
- }
- return NGX_AGAIN;
- match_started:
- continue;
- }
-
- if (ch == ctx->match.data[looked]) {
- ctx->looked.data[looked] = *p;
- looked++;
- if (looked == ctx->match.len) {
- ctx->state = sub_start_state;
- ctx->pos = p + 1;
- ctx->looked.len = 0;
- ctx->saved.len = 0;
- ctx->copy_end = copy_end;
- if (ctx->copy_start == NULL && copy_end) {
- ctx->copy_start = ctx->buf->pos;
- }
- return NGX_OK;
- }
- } else {
-
- ctx->looked.data[looked] = *p;
- looked++;
- for (i = 1; i < looked; i++) {
- if (ngx_strncasecmp(ctx->looked.data + i,
- ctx->match.data, looked - i)
- == 0)
- {
- break;
- }
- }
- if (i < looked) {
- if (ctx->saved.len > i) {
- ctx->saved.len = i;
- }
- if ((size_t) (p + 1 - ctx->buf->pos) >= looked - i) {
- copy_end = p + 1 - (looked - i);
- }
- ngx_memmove(ctx->looked.data, ctx->looked.data + i, looked - i);
- looked = looked - i;
- } else {
- copy_end = p;
- looked = 0;
- state = sub_start_state;
- }
- if (ctx->saved.len) {
- p++;
- goto out;
- }
- }
- }
- ctx->saved.len = 0;
- out:
- ctx->state = state;
- ctx->pos = p;
- ctx->looked.len = looked;
- ctx->copy_end = (state == sub_start_state) ? p : copy_end;
- if (ctx->copy_start == NULL && ctx->copy_end) {
- ctx->copy_start = ctx->buf->pos;
- }
- return NGX_AGAIN;
- }
- static char *
- ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
- {
- ngx_http_sub_loc_conf_t *slcf = conf;
- ngx_str_t *value;
- ngx_http_compile_complex_value_t ccv;
- if (slcf->match.data) {
- return "is duplicate";
- }
- value = cf->args->elts;
- ngx_strlow(value[1].data, value[1].data, value[1].len);
- slcf->match = value[1];
- ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
- ccv.cf = cf;
- ccv.value = &value[2];
- ccv.complex_value = &slcf->value;
- if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
- return NGX_CONF_ERROR;
- }
- return NGX_CONF_OK;
- }
- static void *
- ngx_http_sub_create_conf(ngx_conf_t *cf)
- {
- ngx_http_sub_loc_conf_t *slcf;
- slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_sub_loc_conf_t));
- if (slcf == NULL) {
- return NULL;
- }
-
- slcf->once = NGX_CONF_UNSET;
- slcf->last_modified = NGX_CONF_UNSET;
- return slcf;
- }
- static char *
- ngx_http_sub_merge_conf(ngx_conf_t *cf, void *parent, void *child)
- {
- ngx_http_sub_loc_conf_t *prev = parent;
- ngx_http_sub_loc_conf_t *conf = child;
- ngx_conf_merge_value(conf->once, prev->once, 1);
- ngx_conf_merge_str_value(conf->match, prev->match, "");
- ngx_conf_merge_value(conf->last_modified, prev->last_modified, 0);
- if (conf->value.value.data == NULL) {
- conf->value = prev->value;
- }
- if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
- &prev->types_keys, &prev->types,
- ngx_http_html_default_types)
- != NGX_OK)
- {
- return NGX_CONF_ERROR;
- }
- return NGX_CONF_OK;
- }
- static ngx_int_t
- ngx_http_sub_filter_init(ngx_conf_t *cf)
- {
- ngx_http_next_header_filter = ngx_http_top_header_filter;
- ngx_http_top_header_filter = ngx_http_sub_header_filter;
- ngx_http_next_body_filter = ngx_http_top_body_filter;
- ngx_http_top_body_filter = ngx_http_sub_body_filter;
- return NGX_OK;
- }
One Level Up
Top Level