61
61
static char * ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd,
63
static char *ngx_http_sub_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
64
63
static void *ngx_http_sub_create_conf(ngx_conf_t *cf);
65
64
static char *ngx_http_sub_merge_conf(ngx_conf_t *cf,
66
65
void *parent, void *child);
79
78
{ ngx_string("sub_filter_types"),
80
79
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
82
81
NGX_HTTP_LOC_CONF_OFFSET,
82
offsetof(ngx_http_sub_loc_conf_t, types_keys),
83
&ngx_http_html_default_types[0] },
86
85
{ ngx_string("sub_filter_once"),
87
86
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
133
132
ngx_http_sub_header_filter(ngx_http_request_t *r)
137
134
ngx_http_sub_ctx_t *ctx;
138
135
ngx_http_sub_loc_conf_t *slcf;
140
137
slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module);
142
139
if (slcf->match.len == 0
143
|| r->headers_out.content_type.len == 0
144
|| r->headers_out.content_length_n == 0)
140
|| r->headers_out.content_length_n == 0
141
|| ngx_http_test_content_type(r, &slcf->types) == NULL)
146
143
return ngx_http_next_header_filter(r);
149
type = slcf->types->elts;
150
for (i = 0; i < slcf->types->nelts; i++) {
151
if (r->headers_out.content_type.len >= type[i].len
152
&& ngx_strncasecmp(r->headers_out.content_type.data,
153
type[i].data, type[i].len) == 0)
159
return ngx_http_next_header_filter(r);
163
146
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_sub_ctx_t));
164
147
if (ctx == NULL) {
165
148
return NGX_ERROR;
151
ctx->saved.data = ngx_pnalloc(r->pool, slcf->match.len);
152
if (ctx->saved.data == NULL) {
156
ctx->looked.data = ngx_pnalloc(r->pool, slcf->match.len);
157
if (ctx->looked.data == NULL) {
168
161
ngx_http_set_ctx(r, ctx, ngx_http_sub_filter_module);
170
163
ctx->match = slcf->match;
171
164
ctx->last_out = &ctx->out;
172
ctx->sub = slcf->sub;
174
166
r->filter_need_in_memory = 1;
176
168
if (r == r->main) {
177
169
ngx_http_clear_content_length(r);
178
170
ngx_http_clear_last_modified(r);
171
ngx_http_clear_etag(r);
181
174
return ngx_http_next_header_filter(r);
219
212
/* add the incoming chain to the chain ctx->in */
222
if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) {
215
if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {
223
216
return NGX_ERROR;
245
238
while (ctx->pos < ctx->buf->last) {
247
240
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
248
"saved: %d state: %d", ctx->saved, ctx->state);
241
"saved: \"%V\" state: %d", &ctx->saved, ctx->state);
250
243
rc = ngx_http_sub_parse(r, ctx);
252
245
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
253
"parse: %d, looked: %d %p-%p",
254
rc, ctx->looked, ctx->copy_start, ctx->copy_end);
246
"parse: %d, looked: \"%V\" %p-%p",
247
rc, &ctx->looked, ctx->copy_start, ctx->copy_end);
256
249
if (rc == NGX_ERROR) {
260
253
if (ctx->copy_start != ctx->copy_end) {
262
255
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
263
"saved: %d", ctx->saved);
256
"saved: \"%V\"", &ctx->saved);
258
if (ctx->saved.len) {
280
b->pos = ngx_pnalloc(r->pool, ctx->saved.len);
281
if (b->pos == NULL) {
285
ngx_memcpy(b->pos, ctx->saved.data, ctx->saved.len);
286
b->last = b->pos + ctx->saved.len;
288
b->pos = ctx->match.data;
289
b->last = ctx->match.data + ctx->saved;
291
289
*ctx->last_out = cl;
292
290
ctx->last_out = &cl->next;
362
360
if (ctx->sub.data == NULL) {
364
if (ngx_http_script_run(r, &ctx->sub, slcf->sub_lengths->elts,
365
0, slcf->sub_values->elts)
362
if (ngx_http_complex_value(r, &slcf->value, &ctx->sub)
368
365
return NGX_ERROR;
428
ctx->saved = ctx->looked;
425
ctx->saved.len = ctx->looked.len;
426
ngx_memcpy(ctx->saved.data, ctx->looked.data, ctx->looked.len);
431
429
if (ctx->out == NULL && ctx->busy == NULL) {
522
514
ctx->copy_start = ctx->pos;
523
515
ctx->copy_end = ctx->buf->last;
524
516
ctx->pos = ctx->buf->last;
527
519
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "once");
581
574
/* state == sub_match_state */
583
576
if (ch == ctx->match.data[looked]) {
577
ctx->looked.data[looked] = *p;
586
580
if (looked == ctx->match.len) {
587
581
if ((size_t) (p - ctx->pos) < looked) {
591
585
ctx->state = sub_start_state;
592
586
ctx->pos = p + 1;
594
588
ctx->copy_end = copy_end;
596
590
if (ctx->copy_start == NULL && copy_end) {
631
626
ngx_http_sub_loc_conf_t *slcf = conf;
636
ngx_http_script_compile_t sc;
629
ngx_http_compile_complex_value_t ccv;
638
if (slcf->match.len) {
631
if (slcf->match.data) {
639
632
return "is duplicate";
642
635
value = cf->args->elts;
637
ngx_strlow(value[1].data, value[1].data, value[1].len);
644
639
slcf->match = value[1];
646
for (i = 0; i < value[1].len; i++) {
647
value[1].data[i] = ngx_tolower(value[1].data[i]);
650
n = ngx_http_script_variables_count(&value[2]);
653
slcf->sub = value[2];
657
ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
660
sc.source = &value[2];
661
sc.lengths = &slcf->sub_lengths;
662
sc.values = &slcf->sub_values;
664
sc.complete_lengths = 1;
665
sc.complete_values = 1;
667
if (ngx_http_script_compile(&sc) != NGX_OK) {
641
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
644
ccv.value = &value[2];
645
ccv.complex_value = &slcf->value;
647
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
668
648
return NGX_CONF_ERROR;
676
ngx_http_sub_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
678
ngx_http_sub_loc_conf_t *slcf = conf;
680
ngx_str_t *value, *type;
683
if (slcf->types == NULL) {
684
slcf->types = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
685
if (slcf->types == NULL) {
686
return NGX_CONF_ERROR;
689
type = ngx_array_push(slcf->types);
691
return NGX_CONF_ERROR;
694
type->len = sizeof("text/html") - 1;
695
type->data = (u_char *) "text/html";
698
value = cf->args->elts;
700
for (i = 1; i < cf->args->nelts; i++) {
702
if (ngx_strcmp(value[i].data, "text/html") == 0) {
706
type = ngx_array_push(slcf->types);
708
return NGX_CONF_ERROR;
711
type->len = value[i].len;
713
type->data = ngx_palloc(cf->pool, type->len + 1);
714
if (type->data == NULL) {
715
return NGX_CONF_ERROR;
718
ngx_cpystrn(type->data, value[i].data, type->len + 1);
726
656
ngx_http_sub_create_conf(ngx_conf_t *cf)
730
660
slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_sub_loc_conf_t));
731
661
if (slcf == NULL) {
732
return NGX_CONF_ERROR;
736
666
* set by ngx_pcalloc():
738
* conf->match.len = 0;
739
* conf->match.data = NULL;
741
* conf->sub.data = NULL;
668
* conf->match = { 0, NULL };
669
* conf->sub = { 0, NULL };
742
670
* conf->sub_lengths = NULL;
743
671
* conf->sub_values = NULL;
744
* conf->types = NULL;
672
* conf->types = { NULL };
673
* conf->types_keys = NULL;
747
676
slcf->once = NGX_CONF_UNSET;
756
685
ngx_http_sub_loc_conf_t *prev = parent;
757
686
ngx_http_sub_loc_conf_t *conf = child;
761
688
ngx_conf_merge_value(conf->once, prev->once, 1);
762
689
ngx_conf_merge_str_value(conf->match, prev->match, "");
764
if (conf->sub.data == NULL && conf->sub_lengths == NULL) {
765
conf->sub = prev->sub;
766
conf->sub_lengths = prev->sub_lengths;
767
conf->sub_values = prev->sub_values;
691
if (conf->value.value.data == NULL) {
692
conf->value = prev->value;
770
if (conf->types == NULL) {
771
if (prev->types == NULL) {
772
conf->types = ngx_array_create(cf->pool, 1, sizeof(ngx_str_t));
773
if (conf->types == NULL) {
774
return NGX_CONF_ERROR;
777
type = ngx_array_push(conf->types);
779
return NGX_CONF_ERROR;
782
type->len = sizeof("text/html") - 1;
783
type->data = (u_char *) "text/html";
786
conf->types = prev->types;
695
if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
696
&prev->types_keys, &prev->types,
697
ngx_http_html_default_types)
700
return NGX_CONF_ERROR;
790
703
return NGX_CONF_OK;