Mercurial > hg > nginx
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 |