comparison src/http/modules/ngx_http_sub_filter_module.c @ 6229:2c045e5b8291

Sub filter: support of variables in the strings to replace.
author Dmitry Volyntsev <xeioex@nginx.com>
date Mon, 17 Aug 2015 17:42:02 +0300
parents b9447fc457b4
children fbbb1c1ce1eb
comparison
equal deleted inserted replaced
6228:b9447fc457b4 6229:2c045e5b8291
9 #include <ngx_core.h> 9 #include <ngx_core.h>
10 #include <ngx_http.h> 10 #include <ngx_http.h>
11 11
12 12
13 typedef struct { 13 typedef struct {
14 ngx_http_complex_value_t match;
15 ngx_http_complex_value_t value;
16 } ngx_http_sub_pair_t;
17
18
19 typedef struct {
14 ngx_str_t match; 20 ngx_str_t match;
15 ngx_http_complex_value_t value; 21 ngx_http_complex_value_t *value;
16 } ngx_http_sub_match_t; 22 } ngx_http_sub_match_t;
17 23
18 24
19 typedef struct { 25 typedef struct {
20 ngx_uint_t min_match_len; 26 ngx_uint_t min_match_len;
24 u_char shift[256]; 30 u_char shift[256];
25 } ngx_http_sub_tables_t; 31 } ngx_http_sub_tables_t;
26 32
27 33
28 typedef struct { 34 typedef struct {
35 ngx_uint_t dynamic; /* unsigned dynamic:1; */
36
37 ngx_array_t *pairs;
38
29 ngx_http_sub_tables_t *tables; 39 ngx_http_sub_tables_t *tables;
30 40
31 ngx_hash_t types; 41 ngx_hash_t types;
32 42
33 ngx_flag_t once; 43 ngx_flag_t once;
59 ngx_str_t *sub; 69 ngx_str_t *sub;
60 ngx_uint_t applied; 70 ngx_uint_t applied;
61 71
62 ngx_int_t offset; 72 ngx_int_t offset;
63 ngx_uint_t index; 73 ngx_uint_t index;
74
75 ngx_http_sub_tables_t *tables;
76 ngx_array_t *matches;
64 } ngx_http_sub_ctx_t; 77 } ngx_http_sub_ctx_t;
65 78
66 79
67 static ngx_uint_t ngx_http_sub_cmp_index; 80 static ngx_uint_t ngx_http_sub_cmp_index;
68 81
153 166
154 167
155 static ngx_int_t 168 static ngx_int_t
156 ngx_http_sub_header_filter(ngx_http_request_t *r) 169 ngx_http_sub_header_filter(ngx_http_request_t *r)
157 { 170 {
158 ngx_http_sub_ctx_t *ctx; 171 ngx_str_t *m;
172 ngx_uint_t i, j, n;
173 ngx_http_sub_ctx_t *ctx;
174 ngx_http_sub_pair_t *pairs;
175 ngx_http_sub_match_t *matches;
159 ngx_http_sub_loc_conf_t *slcf; 176 ngx_http_sub_loc_conf_t *slcf;
160 177
161 slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module); 178 slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module);
162 179
163 if (slcf->matches == NULL 180 if (slcf->pairs == NULL
164 || r->headers_out.content_length_n == 0 181 || r->headers_out.content_length_n == 0
165 || ngx_http_test_content_type(r, &slcf->types) == NULL) 182 || ngx_http_test_content_type(r, &slcf->types) == NULL)
166 { 183 {
167 return ngx_http_next_header_filter(r); 184 return ngx_http_next_header_filter(r);
168 } 185 }
170 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_sub_ctx_t)); 187 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_sub_ctx_t));
171 if (ctx == NULL) { 188 if (ctx == NULL) {
172 return NGX_ERROR; 189 return NGX_ERROR;
173 } 190 }
174 191
175 ctx->saved.data = ngx_pnalloc(r->pool, slcf->tables->max_match_len - 1); 192 if (slcf->dynamic == 0) {
193 ctx->tables = slcf->tables;
194 ctx->matches = slcf->matches;
195
196 } else {
197 pairs = slcf->pairs->elts;
198 n = slcf->pairs->nelts;
199
200 matches = ngx_pcalloc(r->pool, sizeof(ngx_http_sub_match_t) * n);
201 if (matches == NULL) {
202 return NGX_ERROR;
203 }
204
205 j = 0;
206 for (i = 0; i < n; i++) {
207 matches[j].value = &pairs[i].value;
208
209 if (pairs[i].match.lengths == NULL) {
210 matches[j].match = pairs[i].match.value;
211 j++;
212 continue;
213 }
214
215 m = &matches[j].match;
216 if (ngx_http_complex_value(r, &pairs[i].match, m) != NGX_OK) {
217 return NGX_ERROR;
218 }
219
220 if (m->len == 0) {
221 continue;
222 }
223
224 ngx_strlow(m->data, m->data, m->len);
225 j++;
226 }
227
228 if (j == 0) {
229 return ngx_http_next_header_filter(r);
230 }
231
232 ctx->matches = ngx_pnalloc(r->pool, sizeof(ngx_array_t));
233 if (ctx->matches == NULL) {
234 return NGX_ERROR;
235 }
236
237 ctx->matches->elts = matches;
238 ctx->matches->nelts = j;
239
240 ctx->tables = ngx_pnalloc(r->pool, sizeof(ngx_http_sub_tables_t));
241 if (ctx->tables == NULL) {
242 return NGX_ERROR;
243 }
244
245 ngx_http_sub_init_tables(ctx->tables, ctx->matches->elts,
246 ctx->matches->nelts);
247 }
248
249 ngx_http_set_ctx(r, ctx, ngx_http_sub_filter_module);
250
251 ctx->saved.data = ngx_pnalloc(r->pool, ctx->tables->max_match_len - 1);
176 if (ctx->saved.data == NULL) { 252 if (ctx->saved.data == NULL) {
177 return NGX_ERROR; 253 return NGX_ERROR;
178 } 254 }
179 255
180 ctx->looked.data = ngx_pnalloc(r->pool, slcf->tables->max_match_len - 1); 256 ctx->looked.data = ngx_pnalloc(r->pool, ctx->tables->max_match_len - 1);
181 if (ctx->looked.data == NULL) { 257 if (ctx->looked.data == NULL) {
182 return NGX_ERROR; 258 return NGX_ERROR;
183 } 259 }
184 260
185 ngx_http_set_ctx(r, ctx, ngx_http_sub_filter_module); 261 ctx->offset = ctx->tables->min_match_len - 1;
186
187 ctx->offset = slcf->tables->min_match_len - 1;
188 ctx->last_out = &ctx->out; 262 ctx->last_out = &ctx->out;
189 263
190 r->filter_need_in_memory = 1; 264 r->filter_need_in_memory = 1;
191 265
192 if (r == r->main) { 266 if (r == r->main) {
348 422
349 slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module); 423 slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module);
350 424
351 if (ctx->sub == NULL) { 425 if (ctx->sub == NULL) {
352 ctx->sub = ngx_pcalloc(r->pool, sizeof(ngx_str_t) 426 ctx->sub = ngx_pcalloc(r->pool, sizeof(ngx_str_t)
353 * slcf->matches->nelts); 427 * ctx->matches->nelts);
354 if (ctx->sub == NULL) { 428 if (ctx->sub == NULL) {
355 return NGX_ERROR; 429 return NGX_ERROR;
356 } 430 }
357 } 431 }
358 432
359 sub = &ctx->sub[ctx->index]; 433 sub = &ctx->sub[ctx->index];
360 434
361 if (sub->data == NULL) { 435 if (sub->data == NULL) {
362 match = slcf->matches->elts; 436 match = ctx->matches->elts;
363 437
364 if (ngx_http_complex_value(r, &match[ctx->index].value, sub) 438 if (ngx_http_complex_value(r, match[ctx->index].value, sub)
365 != NGX_OK) 439 != NGX_OK)
366 { 440 {
367 return NGX_ERROR; 441 return NGX_ERROR;
368 } 442 }
369 } 443 }
379 453
380 *ctx->last_out = cl; 454 *ctx->last_out = cl;
381 ctx->last_out = &cl->next; 455 ctx->last_out = &cl->next;
382 456
383 ctx->index = 0; 457 ctx->index = 0;
384 ctx->once = slcf->once && (++ctx->applied == slcf->matches->nelts); 458 ctx->once = slcf->once && (++ctx->applied == ctx->matches->nelts);
385 459
386 continue; 460 continue;
387 } 461 }
388 462
389 if (ctx->looked.len 463 if (ctx->looked.len
525 ngx_http_sub_match_t *match; 599 ngx_http_sub_match_t *match;
526 ngx_http_sub_tables_t *tables; 600 ngx_http_sub_tables_t *tables;
527 ngx_http_sub_loc_conf_t *slcf; 601 ngx_http_sub_loc_conf_t *slcf;
528 602
529 slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module); 603 slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module);
530 tables = slcf->tables; 604 tables = ctx->tables;
531 605
532 offset = ctx->offset; 606 offset = ctx->offset;
533 end = ctx->buf->last - ctx->pos; 607 end = ctx->buf->last - ctx->pos;
534 608
535 if (ctx->once) { 609 if (ctx->once) {
552 } 626 }
553 627
554 /* a potential match */ 628 /* a potential match */
555 629
556 start = offset - (ngx_int_t) tables->min_match_len + 1; 630 start = offset - (ngx_int_t) tables->min_match_len + 1;
557 match = slcf->matches->elts; 631 match = ctx->matches->elts;
558 632
559 i = ngx_max(tables->index[c], ctx->index); 633 i = ngx_max(tables->index[c], ctx->index);
560 j = tables->index[c + 1]; 634 j = tables->index[c + 1];
561 635
562 while (i != j) { 636 while (i != j) {
661 ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 735 ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
662 { 736 {
663 ngx_http_sub_loc_conf_t *slcf = conf; 737 ngx_http_sub_loc_conf_t *slcf = conf;
664 738
665 ngx_str_t *value; 739 ngx_str_t *value;
666 ngx_http_sub_match_t *match; 740 ngx_http_sub_pair_t *pair;
667 ngx_http_compile_complex_value_t ccv; 741 ngx_http_compile_complex_value_t ccv;
668 742
669 value = cf->args->elts; 743 value = cf->args->elts;
670 744
671 if (value[1].len == 0) { 745 if (value[1].len == 0) {
672 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty search pattern"); 746 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty search pattern");
673 return NGX_CONF_ERROR; 747 return NGX_CONF_ERROR;
674 } 748 }
675 749
676 if (slcf->matches == NULL) { 750 if (slcf->pairs == NULL) {
677 slcf->matches = ngx_array_create(cf->pool, 1, 751 slcf->pairs = ngx_array_create(cf->pool, 1,
678 sizeof(ngx_http_sub_match_t)); 752 sizeof(ngx_http_sub_pair_t));
679 if (slcf->matches == NULL) { 753 if (slcf->pairs == NULL) {
680 return NGX_CONF_ERROR; 754 return NGX_CONF_ERROR;
681 } 755 }
682 } 756 }
683 757
684 if (slcf->matches->nelts == 255) { 758 if (slcf->pairs->nelts == 255) {
685 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 759 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
686 "number of search patterns exceeds 255"); 760 "number of search patterns exceeds 255");
687 return NGX_CONF_ERROR; 761 return NGX_CONF_ERROR;
688 } 762 }
689 763
690 ngx_strlow(value[1].data, value[1].data, value[1].len); 764 ngx_strlow(value[1].data, value[1].data, value[1].len);
691 765
692 match = ngx_array_push(slcf->matches); 766 pair = ngx_array_push(slcf->pairs);
693 if (match == NULL) { 767 if (pair == NULL) {
694 return NGX_CONF_ERROR; 768 return NGX_CONF_ERROR;
695 } 769 }
696 770
697 match->match = value[1]; 771 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
772
773 ccv.cf = cf;
774 ccv.value = &value[1];
775 ccv.complex_value = &pair->match;
776
777 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
778 return NGX_CONF_ERROR;
779 }
780
781 if (ccv.complex_value->lengths != NULL) {
782 slcf->dynamic = 1;
783
784 } else {
785 ngx_strlow(pair->match.value.data, pair->match.value.data,
786 pair->match.value.len);
787 }
698 788
699 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 789 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
700 790
701 ccv.cf = cf; 791 ccv.cf = cf;
702 ccv.value = &value[2]; 792 ccv.value = &value[2];
703 ccv.complex_value = &match->value; 793 ccv.complex_value = &pair->value;
704 794
705 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 795 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
706 return NGX_CONF_ERROR; 796 return NGX_CONF_ERROR;
707 } 797 }
708 798
721 } 811 }
722 812
723 /* 813 /*
724 * set by ngx_pcalloc(): 814 * set by ngx_pcalloc():
725 * 815 *
816 * conf->dynamic = 0;
817 * conf->pairs = NULL;
726 * conf->tables = NULL; 818 * conf->tables = NULL;
727 * conf->types = { NULL }; 819 * conf->types = { NULL };
728 * conf->types_keys = NULL; 820 * conf->types_keys = NULL;
729 * conf->matches = NULL; 821 * conf->matches = NULL;
730 */ 822 */
737 829
738 830
739 static char * 831 static char *
740 ngx_http_sub_merge_conf(ngx_conf_t *cf, void *parent, void *child) 832 ngx_http_sub_merge_conf(ngx_conf_t *cf, void *parent, void *child)
741 { 833 {
742 ngx_http_sub_loc_conf_t *prev = parent; 834 ngx_uint_t i, n;
743 ngx_http_sub_loc_conf_t *conf = child; 835 ngx_http_sub_pair_t *pairs;
836 ngx_http_sub_match_t *matches;
837 ngx_http_sub_loc_conf_t *prev = parent;
838 ngx_http_sub_loc_conf_t *conf = child;
744 839
745 ngx_conf_merge_value(conf->once, prev->once, 1); 840 ngx_conf_merge_value(conf->once, prev->once, 1);
746 ngx_conf_merge_value(conf->last_modified, prev->last_modified, 0); 841 ngx_conf_merge_value(conf->last_modified, prev->last_modified, 0);
747 842
748 if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types, 843 if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types,
751 != NGX_OK) 846 != NGX_OK)
752 { 847 {
753 return NGX_CONF_ERROR; 848 return NGX_CONF_ERROR;
754 } 849 }
755 850
756 if (conf->matches == NULL) { 851 if (conf->pairs == NULL) {
852 conf->dynamic = prev->dynamic;
853 conf->pairs = prev->pairs;
757 conf->matches = prev->matches; 854 conf->matches = prev->matches;
758 conf->tables = prev->tables; 855 conf->tables = prev->tables;
759 856
760 } else { 857 } else if (conf->dynamic == 0){
858 pairs = conf->pairs->elts;
859 n = conf->pairs->nelts;
860
861 matches = ngx_pnalloc(cf->pool, sizeof(ngx_http_sub_match_t) * n);
862 if (matches == NULL) {
863 return NGX_CONF_ERROR;
864 }
865
866 for (i = 0; i < n; i++) {
867 matches[i].match = pairs[i].match.value;
868 matches[i].value = &pairs[i].value;
869 }
870
871 conf->matches = ngx_pnalloc(cf->pool, sizeof(ngx_array_t));
872 if (conf->matches == NULL) {
873 return NGX_CONF_ERROR;
874 }
875
876 conf->matches->elts = matches;
877 conf->matches->nelts = n;
878
761 conf->tables = ngx_palloc(cf->pool, sizeof(ngx_http_sub_tables_t)); 879 conf->tables = ngx_palloc(cf->pool, sizeof(ngx_http_sub_tables_t));
762 if (conf->tables == NULL) { 880 if (conf->tables == NULL) {
763 return NGX_CONF_ERROR; 881 return NGX_CONF_ERROR;
764 } 882 }
765 883