Mercurial > hg > nginx
annotate src/http/modules/ngx_http_sub_filter_module.c @ 5204:a64c8a5da336
PCRE: retain input pattern for all regular expressions.
Previously, input pattern was kept only for regular expressions
with named captures, which resulted in error log entries without
input pattern for PCRE errors that occured while processing
regular expressions without them.
Signed-off-by: Piotr Sikora <piotr@cloudflare.com>
author | Piotr Sikora <piotr@cloudflare.com> |
---|---|
date | Thu, 02 May 2013 03:26:36 -0700 |
parents | 4251e72b8bb4 |
children | 4c1a604b0285 |
rev | line source |
---|---|
1172 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4412 | 4 * Copyright (C) Nginx, Inc. |
1172 | 5 */ |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_http.h> | |
11 | |
12 | |
13 typedef struct { | |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
14 ngx_str_t match; |
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
15 ngx_http_complex_value_t value; |
1172 | 16 |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
17 ngx_hash_t types; |
1172 | 18 |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
19 ngx_flag_t once; |
2166
723df5089c05
use hash in gzip_types, ssi_types, and sub_filter_types
Igor Sysoev <igor@sysoev.ru>
parents:
2135
diff
changeset
|
20 |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
21 ngx_array_t *types_keys; |
1172 | 22 } ngx_http_sub_loc_conf_t; |
23 | |
24 | |
25 typedef enum { | |
26 sub_start_state = 0, | |
27 sub_match_state, | |
28 } ngx_http_sub_state_e; | |
29 | |
30 | |
31 typedef struct { | |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
32 ngx_str_t match; |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
33 ngx_str_t saved; |
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
34 ngx_str_t looked; |
1172 | 35 |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
36 ngx_uint_t once; /* unsigned once:1 */ |
1172 | 37 |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
38 ngx_buf_t *buf; |
1172 | 39 |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
40 u_char *pos; |
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
41 u_char *copy_start; |
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
42 u_char *copy_end; |
1172 | 43 |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
44 ngx_chain_t *in; |
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
45 ngx_chain_t *out; |
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
46 ngx_chain_t **last_out; |
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
47 ngx_chain_t *busy; |
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
48 ngx_chain_t *free; |
1172 | 49 |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
50 ngx_str_t sub; |
1172 | 51 |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
52 ngx_uint_t state; |
1172 | 53 } ngx_http_sub_ctx_t; |
54 | |
55 | |
56 static ngx_int_t ngx_http_sub_output(ngx_http_request_t *r, | |
57 ngx_http_sub_ctx_t *ctx); | |
58 static ngx_int_t ngx_http_sub_parse(ngx_http_request_t *r, | |
59 ngx_http_sub_ctx_t *ctx); | |
60 | |
61 static char * ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, | |
62 void *conf); | |
63 static void *ngx_http_sub_create_conf(ngx_conf_t *cf); | |
64 static char *ngx_http_sub_merge_conf(ngx_conf_t *cf, | |
65 void *parent, void *child); | |
66 static ngx_int_t ngx_http_sub_filter_init(ngx_conf_t *cf); | |
67 | |
68 | |
69 static ngx_command_t ngx_http_sub_filter_commands[] = { | |
70 | |
71 { ngx_string("sub_filter"), | |
72 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, | |
73 ngx_http_sub_filter, | |
74 NGX_HTTP_LOC_CONF_OFFSET, | |
75 0, | |
76 NULL }, | |
77 | |
78 { ngx_string("sub_filter_types"), | |
79 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, | |
2166
723df5089c05
use hash in gzip_types, ssi_types, and sub_filter_types
Igor Sysoev <igor@sysoev.ru>
parents:
2135
diff
changeset
|
80 ngx_http_types_slot, |
1172 | 81 NGX_HTTP_LOC_CONF_OFFSET, |
2166
723df5089c05
use hash in gzip_types, ssi_types, and sub_filter_types
Igor Sysoev <igor@sysoev.ru>
parents:
2135
diff
changeset
|
82 offsetof(ngx_http_sub_loc_conf_t, types_keys), |
723df5089c05
use hash in gzip_types, ssi_types, and sub_filter_types
Igor Sysoev <igor@sysoev.ru>
parents:
2135
diff
changeset
|
83 &ngx_http_html_default_types[0] }, |
1172 | 84 |
85 { ngx_string("sub_filter_once"), | |
86 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
87 ngx_conf_set_flag_slot, | |
88 NGX_HTTP_LOC_CONF_OFFSET, | |
89 offsetof(ngx_http_sub_loc_conf_t, once), | |
90 NULL }, | |
91 | |
92 ngx_null_command | |
93 }; | |
94 | |
95 | |
96 static ngx_http_module_t ngx_http_sub_filter_module_ctx = { | |
97 NULL, /* preconfiguration */ | |
98 ngx_http_sub_filter_init, /* postconfiguration */ | |
99 | |
100 NULL, /* create main configuration */ | |
101 NULL, /* init main configuration */ | |
102 | |
103 NULL, /* create server configuration */ | |
104 NULL, /* merge server configuration */ | |
105 | |
106 ngx_http_sub_create_conf, /* create location configuration */ | |
107 ngx_http_sub_merge_conf /* merge location configuration */ | |
108 }; | |
109 | |
110 | |
111 ngx_module_t ngx_http_sub_filter_module = { | |
112 NGX_MODULE_V1, | |
113 &ngx_http_sub_filter_module_ctx, /* module context */ | |
114 ngx_http_sub_filter_commands, /* module directives */ | |
115 NGX_HTTP_MODULE, /* module type */ | |
116 NULL, /* init master */ | |
117 NULL, /* init module */ | |
118 NULL, /* init process */ | |
119 NULL, /* init thread */ | |
120 NULL, /* exit thread */ | |
121 NULL, /* exit process */ | |
122 NULL, /* exit master */ | |
123 NGX_MODULE_V1_PADDING | |
124 }; | |
125 | |
126 | |
127 static ngx_http_output_header_filter_pt ngx_http_next_header_filter; | |
128 static ngx_http_output_body_filter_pt ngx_http_next_body_filter; | |
129 | |
130 | |
131 static ngx_int_t | |
132 ngx_http_sub_header_filter(ngx_http_request_t *r) | |
133 { | |
134 ngx_http_sub_ctx_t *ctx; | |
135 ngx_http_sub_loc_conf_t *slcf; | |
136 | |
137 slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module); | |
138 | |
139 if (slcf->match.len == 0 | |
2166
723df5089c05
use hash in gzip_types, ssi_types, and sub_filter_types
Igor Sysoev <igor@sysoev.ru>
parents:
2135
diff
changeset
|
140 || r->headers_out.content_length_n == 0 |
723df5089c05
use hash in gzip_types, ssi_types, and sub_filter_types
Igor Sysoev <igor@sysoev.ru>
parents:
2135
diff
changeset
|
141 || ngx_http_test_content_type(r, &slcf->types) == NULL) |
1172 | 142 { |
143 return ngx_http_next_header_filter(r); | |
144 } | |
145 | |
146 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_sub_ctx_t)); | |
147 if (ctx == NULL) { | |
148 return NGX_ERROR; | |
149 } | |
150 | |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
151 ctx->saved.data = ngx_pnalloc(r->pool, slcf->match.len); |
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
152 if (ctx->saved.data == NULL) { |
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
153 return NGX_ERROR; |
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
154 } |
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
155 |
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
156 ctx->looked.data = ngx_pnalloc(r->pool, slcf->match.len); |
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
157 if (ctx->looked.data == NULL) { |
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
158 return NGX_ERROR; |
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
159 } |
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
160 |
1172 | 161 ngx_http_set_ctx(r, ctx, ngx_http_sub_filter_module); |
162 | |
163 ctx->match = slcf->match; | |
164 ctx->last_out = &ctx->out; | |
165 | |
166 r->filter_need_in_memory = 1; | |
167 | |
168 if (r == r->main) { | |
169 ngx_http_clear_content_length(r); | |
170 ngx_http_clear_last_modified(r); | |
4746
4a18bf1833a9
Entity tags: clear on entity changes.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4412
diff
changeset
|
171 ngx_http_clear_etag(r); |
1172 | 172 } |
173 | |
174 return ngx_http_next_header_filter(r); | |
175 } | |
176 | |
177 | |
178 static ngx_int_t | |
179 ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) | |
180 { | |
181 ngx_int_t rc; | |
182 ngx_buf_t *b; | |
183 ngx_chain_t *cl; | |
184 ngx_http_sub_ctx_t *ctx; | |
185 ngx_http_sub_loc_conf_t *slcf; | |
186 | |
187 ctx = ngx_http_get_module_ctx(r, ngx_http_sub_filter_module); | |
188 | |
189 if (ctx == NULL) { | |
190 return ngx_http_next_body_filter(r, in); | |
191 } | |
192 | |
193 if ((in == NULL | |
194 && ctx->buf == NULL | |
195 && ctx->in == NULL | |
196 && ctx->busy == NULL)) | |
197 { | |
198 return ngx_http_next_body_filter(r, in); | |
199 } | |
200 | |
201 if (ctx->once && (ctx->buf == NULL || ctx->in == NULL)) { | |
202 | |
203 if (ctx->busy) { | |
204 if (ngx_http_sub_output(r, ctx) == NGX_ERROR) { | |
205 return NGX_ERROR; | |
206 } | |
207 } | |
208 | |
209 return ngx_http_next_body_filter(r, in); | |
210 } | |
211 | |
212 /* add the incoming chain to the chain ctx->in */ | |
213 | |
214 if (in) { | |
2536
a6d6d762c554
small optimization: " == NGX_ERROR" > " != NGX_OK"
Igor Sysoev <igor@sysoev.ru>
parents:
2414
diff
changeset
|
215 if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { |
1172 | 216 return NGX_ERROR; |
217 } | |
218 } | |
219 | |
220 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
221 "http sub filter \"%V\"", &r->uri); | |
222 | |
223 while (ctx->in || ctx->buf) { | |
224 | |
3642 | 225 if (ctx->buf == NULL) { |
1172 | 226 ctx->buf = ctx->in->buf; |
227 ctx->in = ctx->in->next; | |
228 ctx->pos = ctx->buf->pos; | |
229 } | |
230 | |
231 if (ctx->state == sub_start_state) { | |
232 ctx->copy_start = ctx->pos; | |
233 ctx->copy_end = ctx->pos; | |
234 } | |
235 | |
236 b = NULL; | |
237 | |
238 while (ctx->pos < ctx->buf->last) { | |
239 | |
240 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
241 "saved: \"%V\" state: %d", &ctx->saved, ctx->state); |
1172 | 242 |
243 rc = ngx_http_sub_parse(r, ctx); | |
244 | |
245 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
246 "parse: %d, looked: \"%V\" %p-%p", |
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
247 rc, &ctx->looked, ctx->copy_start, ctx->copy_end); |
1172 | 248 |
249 if (rc == NGX_ERROR) { | |
250 return rc; | |
251 } | |
252 | |
253 if (ctx->copy_start != ctx->copy_end) { | |
254 | |
255 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
256 "saved: \"%V\"", &ctx->saved); |
1172 | 257 |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
258 if (ctx->saved.len) { |
1172 | 259 |
260 if (ctx->free) { | |
261 cl = ctx->free; | |
262 ctx->free = ctx->free->next; | |
263 b = cl->buf; | |
264 ngx_memzero(b, sizeof(ngx_buf_t)); | |
265 | |
266 } else { | |
267 b = ngx_calloc_buf(r->pool); | |
268 if (b == NULL) { | |
269 return NGX_ERROR; | |
270 } | |
271 | |
272 cl = ngx_alloc_chain_link(r->pool); | |
273 if (cl == NULL) { | |
274 return NGX_ERROR; | |
275 } | |
276 | |
277 cl->buf = b; | |
278 } | |
279 | |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
280 b->pos = ngx_pnalloc(r->pool, ctx->saved.len); |
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
281 if (b->pos == NULL) { |
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
282 return NGX_ERROR; |
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
283 } |
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
284 |
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
285 ngx_memcpy(b->pos, ctx->saved.data, ctx->saved.len); |
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
286 b->last = b->pos + ctx->saved.len; |
1172 | 287 b->memory = 1; |
288 | |
289 *ctx->last_out = cl; | |
290 ctx->last_out = &cl->next; | |
291 | |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
292 ctx->saved.len = 0; |
1172 | 293 } |
294 | |
295 if (ctx->free) { | |
296 cl = ctx->free; | |
297 ctx->free = ctx->free->next; | |
298 b = cl->buf; | |
299 | |
300 } else { | |
301 b = ngx_alloc_buf(r->pool); | |
302 if (b == NULL) { | |
303 return NGX_ERROR; | |
304 } | |
305 | |
306 cl = ngx_alloc_chain_link(r->pool); | |
307 if (cl == NULL) { | |
308 return NGX_ERROR; | |
309 } | |
310 | |
311 cl->buf = b; | |
312 } | |
313 | |
314 ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t)); | |
315 | |
316 b->pos = ctx->copy_start; | |
317 b->last = ctx->copy_end; | |
318 b->shadow = NULL; | |
319 b->last_buf = 0; | |
320 b->recycled = 0; | |
321 | |
322 if (b->in_file) { | |
2079
333ef9e18a59
fix error when response parsed by sub filter, then by SSI filter
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
323 b->file_last = b->file_pos + (b->last - ctx->buf->pos); |
333ef9e18a59
fix error when response parsed by sub filter, then by SSI filter
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
324 b->file_pos += b->pos - ctx->buf->pos; |
1172 | 325 } |
326 | |
327 cl->next = NULL; | |
328 *ctx->last_out = cl; | |
329 ctx->last_out = &cl->next; | |
330 } | |
331 | |
332 if (ctx->state == sub_start_state) { | |
333 ctx->copy_start = ctx->pos; | |
334 ctx->copy_end = ctx->pos; | |
335 | |
336 } else { | |
337 ctx->copy_start = NULL; | |
338 ctx->copy_end = NULL; | |
339 } | |
340 | |
341 if (rc == NGX_AGAIN) { | |
342 continue; | |
343 } | |
344 | |
345 | |
346 /* rc == NGX_OK */ | |
347 | |
348 b = ngx_calloc_buf(r->pool); | |
349 if (b == NULL) { | |
350 return NGX_ERROR; | |
351 } | |
352 | |
353 cl = ngx_alloc_chain_link(r->pool); | |
354 if (cl == NULL) { | |
355 return NGX_ERROR; | |
356 } | |
357 | |
358 slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module); | |
359 | |
360 if (ctx->sub.data == NULL) { | |
361 | |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
362 if (ngx_http_complex_value(r, &slcf->value, &ctx->sub) |
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
363 != NGX_OK) |
1172 | 364 { |
365 return NGX_ERROR; | |
366 } | |
367 } | |
368 | |
1555
76fe59c6fafb
fix empty string replacement in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
1172
diff
changeset
|
369 if (ctx->sub.len) { |
76fe59c6fafb
fix empty string replacement in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
1172
diff
changeset
|
370 b->memory = 1; |
76fe59c6fafb
fix empty string replacement in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
1172
diff
changeset
|
371 b->pos = ctx->sub.data; |
76fe59c6fafb
fix empty string replacement in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
1172
diff
changeset
|
372 b->last = ctx->sub.data + ctx->sub.len; |
76fe59c6fafb
fix empty string replacement in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
1172
diff
changeset
|
373 |
76fe59c6fafb
fix empty string replacement in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
1172
diff
changeset
|
374 } else { |
76fe59c6fafb
fix empty string replacement in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
1172
diff
changeset
|
375 b->sync = 1; |
76fe59c6fafb
fix empty string replacement in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
1172
diff
changeset
|
376 } |
1172 | 377 |
378 cl->buf = b; | |
379 cl->next = NULL; | |
380 *ctx->last_out = cl; | |
381 ctx->last_out = &cl->next; | |
382 | |
383 ctx->once = slcf->once; | |
384 | |
385 continue; | |
386 } | |
387 | |
388 if (ctx->buf->last_buf || ngx_buf_in_memory(ctx->buf)) { | |
389 if (b == NULL) { | |
390 if (ctx->free) { | |
391 cl = ctx->free; | |
392 ctx->free = ctx->free->next; | |
393 b = cl->buf; | |
394 ngx_memzero(b, sizeof(ngx_buf_t)); | |
395 | |
396 } else { | |
397 b = ngx_calloc_buf(r->pool); | |
398 if (b == NULL) { | |
399 return NGX_ERROR; | |
400 } | |
401 | |
402 cl = ngx_alloc_chain_link(r->pool); | |
403 if (cl == NULL) { | |
404 return NGX_ERROR; | |
405 } | |
406 | |
407 cl->buf = b; | |
408 } | |
409 | |
410 b->sync = 1; | |
411 | |
412 cl->next = NULL; | |
413 *ctx->last_out = cl; | |
414 ctx->last_out = &cl->next; | |
415 } | |
416 | |
417 b->last_buf = ctx->buf->last_buf; | |
418 b->shadow = ctx->buf; | |
419 | |
420 b->recycled = ctx->buf->recycled; | |
421 } | |
422 | |
423 ctx->buf = NULL; | |
424 | |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
425 ctx->saved.len = ctx->looked.len; |
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
426 ngx_memcpy(ctx->saved.data, ctx->looked.data, ctx->looked.len); |
1172 | 427 } |
428 | |
429 if (ctx->out == NULL && ctx->busy == NULL) { | |
430 return NGX_OK; | |
431 } | |
432 | |
433 return ngx_http_sub_output(r, ctx); | |
434 } | |
435 | |
436 | |
437 static ngx_int_t | |
438 ngx_http_sub_output(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) | |
439 { | |
440 ngx_int_t rc; | |
441 ngx_buf_t *b; | |
442 ngx_chain_t *cl; | |
443 | |
444 #if 1 | |
445 b = NULL; | |
446 for (cl = ctx->out; cl; cl = cl->next) { | |
447 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
448 "sub out: %p %p", cl->buf, cl->buf->pos); | |
449 if (cl->buf == b) { | |
450 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
451 "the same buf was used in sub"); | |
452 ngx_debug_point(); | |
453 return NGX_ERROR; | |
454 } | |
455 b = cl->buf; | |
456 } | |
457 #endif | |
458 | |
459 rc = ngx_http_next_body_filter(r, ctx->out); | |
460 | |
461 if (ctx->busy == NULL) { | |
462 ctx->busy = ctx->out; | |
463 | |
464 } else { | |
465 for (cl = ctx->busy; cl->next; cl = cl->next) { /* void */ } | |
466 cl->next = ctx->out; | |
467 } | |
468 | |
469 ctx->out = NULL; | |
470 ctx->last_out = &ctx->out; | |
471 | |
472 while (ctx->busy) { | |
473 | |
474 cl = ctx->busy; | |
475 b = cl->buf; | |
476 | |
477 if (ngx_buf_size(b) != 0) { | |
478 break; | |
479 } | |
480 | |
481 if (b->shadow) { | |
482 b->shadow->pos = b->shadow->last; | |
483 } | |
484 | |
485 ctx->busy = cl->next; | |
486 | |
487 if (ngx_buf_in_memory(b) || b->in_file) { | |
488 /* add data bufs only to the free buf chain */ | |
489 | |
490 cl->next = ctx->free; | |
491 ctx->free = cl; | |
492 } | |
493 } | |
494 | |
495 if (ctx->in || ctx->buf) { | |
496 r->buffered |= NGX_HTTP_SUB_BUFFERED; | |
497 | |
498 } else { | |
499 r->buffered &= ~NGX_HTTP_SUB_BUFFERED; | |
500 } | |
501 | |
502 return rc; | |
503 } | |
504 | |
505 | |
506 static ngx_int_t | |
507 ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) | |
508 { | |
509 u_char *p, *last, *copy_end, ch, match; | |
510 size_t looked; | |
511 ngx_http_sub_state_e state; | |
512 | |
513 if (ctx->once) { | |
514 ctx->copy_start = ctx->pos; | |
515 ctx->copy_end = ctx->buf->last; | |
516 ctx->pos = ctx->buf->last; | |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
517 ctx->looked.len = 0; |
1172 | 518 |
519 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "once"); | |
520 | |
521 return NGX_AGAIN; | |
522 } | |
523 | |
524 state = ctx->state; | |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
525 looked = ctx->looked.len; |
1172 | 526 last = ctx->buf->last; |
527 copy_end = ctx->copy_end; | |
528 | |
529 for (p = ctx->pos; p < last; p++) { | |
530 | |
531 ch = *p; | |
532 ch = ngx_tolower(ch); | |
533 | |
534 if (state == sub_start_state) { | |
535 | |
536 /* the tight loop */ | |
537 | |
538 match = ctx->match.data[0]; | |
539 | |
540 for ( ;; ) { | |
541 if (ch == match) { | |
542 copy_end = p; | |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
543 ctx->looked.data[0] = *p; |
1172 | 544 looked = 1; |
545 state = sub_match_state; | |
546 | |
547 goto match_started; | |
548 } | |
549 | |
550 if (++p == last) { | |
551 break; | |
552 } | |
553 | |
554 ch = *p; | |
555 ch = ngx_tolower(ch); | |
556 } | |
557 | |
1557
9d094e581587
*) add sub_filter parser fix similar to r1261 in SSI parser
Igor Sysoev <igor@sysoev.ru>
parents:
1555
diff
changeset
|
558 ctx->state = state; |
1172 | 559 ctx->pos = p; |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
560 ctx->looked.len = looked; |
1172 | 561 ctx->copy_end = p; |
562 | |
563 if (ctx->copy_start == NULL) { | |
564 ctx->copy_start = ctx->buf->pos; | |
565 } | |
566 | |
567 return NGX_AGAIN; | |
568 | |
569 match_started: | |
570 | |
571 continue; | |
572 } | |
573 | |
574 /* state == sub_match_state */ | |
575 | |
576 if (ch == ctx->match.data[looked]) { | |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
577 ctx->looked.data[looked] = *p; |
1172 | 578 looked++; |
579 | |
580 if (looked == ctx->match.len) { | |
1557
9d094e581587
*) add sub_filter parser fix similar to r1261 in SSI parser
Igor Sysoev <igor@sysoev.ru>
parents:
1555
diff
changeset
|
581 if ((size_t) (p - ctx->pos) < looked) { |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
582 ctx->saved.len = 0; |
1557
9d094e581587
*) add sub_filter parser fix similar to r1261 in SSI parser
Igor Sysoev <igor@sysoev.ru>
parents:
1555
diff
changeset
|
583 } |
9d094e581587
*) add sub_filter parser fix similar to r1261 in SSI parser
Igor Sysoev <igor@sysoev.ru>
parents:
1555
diff
changeset
|
584 |
1172 | 585 ctx->state = sub_start_state; |
586 ctx->pos = p + 1; | |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
587 ctx->looked.len = 0; |
1172 | 588 ctx->copy_end = copy_end; |
589 | |
590 if (ctx->copy_start == NULL && copy_end) { | |
591 ctx->copy_start = ctx->buf->pos; | |
592 } | |
593 | |
594 return NGX_OK; | |
595 } | |
596 | |
597 } else if (ch == ctx->match.data[0]) { | |
598 copy_end = p; | |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
599 ctx->looked.data[0] = *p; |
1172 | 600 looked = 1; |
601 | |
602 } else { | |
603 copy_end = p; | |
604 looked = 0; | |
605 state = sub_start_state; | |
606 } | |
607 } | |
608 | |
609 ctx->state = state; | |
610 ctx->pos = p; | |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
611 ctx->looked.len = looked; |
1172 | 612 |
613 ctx->copy_end = (state == sub_start_state) ? p : copy_end; | |
614 | |
615 if (ctx->copy_start == NULL && ctx->copy_end) { | |
616 ctx->copy_start = ctx->buf->pos; | |
617 } | |
618 | |
619 return NGX_AGAIN; | |
620 } | |
621 | |
622 | |
623 static char * | |
624 ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
625 { | |
626 ngx_http_sub_loc_conf_t *slcf = conf; | |
627 | |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
628 ngx_str_t *value; |
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
629 ngx_http_compile_complex_value_t ccv; |
1172 | 630 |
4947
4251e72b8bb4
Allow the complex value to be defined as an empty string.
Ruslan Ermilov <ru@nginx.com>
parents:
4746
diff
changeset
|
631 if (slcf->match.data) { |
1172 | 632 return "is duplicate"; |
633 } | |
634 | |
635 value = cf->args->elts; | |
636 | |
2135 | 637 ngx_strlow(value[1].data, value[1].data, value[1].len); |
1172 | 638 |
2135 | 639 slcf->match = value[1]; |
1172 | 640 |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
641 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); |
1172 | 642 |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
643 ccv.cf = cf; |
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
644 ccv.value = &value[2]; |
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
645 ccv.complex_value = &slcf->value; |
1172 | 646 |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
647 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { |
1172 | 648 return NGX_CONF_ERROR; |
649 } | |
650 | |
651 return NGX_CONF_OK; | |
652 } | |
653 | |
654 | |
655 static void * | |
656 ngx_http_sub_create_conf(ngx_conf_t *cf) | |
657 { | |
658 ngx_http_sub_loc_conf_t *slcf; | |
659 | |
660 slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_sub_loc_conf_t)); | |
661 if (slcf == NULL) { | |
2912
c7d57b539248
return NULL instead of NGX_CONF_ERROR on a create conf failure
Igor Sysoev <igor@sysoev.ru>
parents:
2588
diff
changeset
|
662 return NULL; |
1172 | 663 } |
664 | |
665 /* | |
666 * set by ngx_pcalloc(): | |
667 * | |
2166
723df5089c05
use hash in gzip_types, ssi_types, and sub_filter_types
Igor Sysoev <igor@sysoev.ru>
parents:
2135
diff
changeset
|
668 * conf->match = { 0, NULL }; |
723df5089c05
use hash in gzip_types, ssi_types, and sub_filter_types
Igor Sysoev <igor@sysoev.ru>
parents:
2135
diff
changeset
|
669 * conf->sub = { 0, NULL }; |
1172 | 670 * conf->sub_lengths = NULL; |
671 * conf->sub_values = NULL; | |
2166
723df5089c05
use hash in gzip_types, ssi_types, and sub_filter_types
Igor Sysoev <igor@sysoev.ru>
parents:
2135
diff
changeset
|
672 * conf->types = { NULL }; |
723df5089c05
use hash in gzip_types, ssi_types, and sub_filter_types
Igor Sysoev <igor@sysoev.ru>
parents:
2135
diff
changeset
|
673 * conf->types_keys = NULL; |
1172 | 674 */ |
675 | |
676 slcf->once = NGX_CONF_UNSET; | |
677 | |
678 return slcf; | |
679 } | |
680 | |
681 | |
682 static char * | |
683 ngx_http_sub_merge_conf(ngx_conf_t *cf, void *parent, void *child) | |
684 { | |
685 ngx_http_sub_loc_conf_t *prev = parent; | |
686 ngx_http_sub_loc_conf_t *conf = child; | |
687 | |
688 ngx_conf_merge_value(conf->once, prev->once, 1); | |
689 ngx_conf_merge_str_value(conf->match, prev->match, ""); | |
690 | |
4947
4251e72b8bb4
Allow the complex value to be defined as an empty string.
Ruslan Ermilov <ru@nginx.com>
parents:
4746
diff
changeset
|
691 if (conf->value.value.data == NULL) { |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
692 conf->value = prev->value; |
1172 | 693 } |
694 | |
3372
6b8e5c882e47
support "*" in gzip_types, ssi_types, etc
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
695 if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types, |
6b8e5c882e47
support "*" in gzip_types, ssi_types, etc
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
696 &prev->types_keys, &prev->types, |
2166
723df5089c05
use hash in gzip_types, ssi_types, and sub_filter_types
Igor Sysoev <igor@sysoev.ru>
parents:
2135
diff
changeset
|
697 ngx_http_html_default_types) |
723df5089c05
use hash in gzip_types, ssi_types, and sub_filter_types
Igor Sysoev <igor@sysoev.ru>
parents:
2135
diff
changeset
|
698 != NGX_OK) |
723df5089c05
use hash in gzip_types, ssi_types, and sub_filter_types
Igor Sysoev <igor@sysoev.ru>
parents:
2135
diff
changeset
|
699 { |
723df5089c05
use hash in gzip_types, ssi_types, and sub_filter_types
Igor Sysoev <igor@sysoev.ru>
parents:
2135
diff
changeset
|
700 return NGX_CONF_ERROR; |
1172 | 701 } |
702 | |
703 return NGX_CONF_OK; | |
704 } | |
705 | |
706 | |
707 static ngx_int_t | |
708 ngx_http_sub_filter_init(ngx_conf_t *cf) | |
709 { | |
710 ngx_http_next_header_filter = ngx_http_top_header_filter; | |
711 ngx_http_top_header_filter = ngx_http_sub_header_filter; | |
712 | |
713 ngx_http_next_body_filter = ngx_http_top_body_filter; | |
714 ngx_http_top_body_filter = ngx_http_sub_body_filter; | |
715 | |
716 return NGX_OK; | |
717 } |