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