Mercurial > hg > nginx-quic
annotate src/http/modules/ngx_http_sub_filter_module.c @ 4487:a786c85e8268
Disable symlinks: don't allow creating or truncating a file via a symlink in
the last path component if "if_not_owner" parameter is used.
To prevent race condition we have to open a file before checking its owner and
there's no way to change access flags for already opened file descriptor, so
we disable symlinks for the last path component at all if flags allow creating
or truncating the file.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Tue, 21 Feb 2012 15:04:41 +0000 |
parents | d620f497c50f |
children | 4a18bf1833a9 05beaa2d87b3 |
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); | |
171 } | |
172 | |
173 return ngx_http_next_header_filter(r); | |
174 } | |
175 | |
176 | |
177 static ngx_int_t | |
178 ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) | |
179 { | |
180 ngx_int_t rc; | |
181 ngx_buf_t *b; | |
182 ngx_chain_t *cl; | |
183 ngx_http_sub_ctx_t *ctx; | |
184 ngx_http_sub_loc_conf_t *slcf; | |
185 | |
186 ctx = ngx_http_get_module_ctx(r, ngx_http_sub_filter_module); | |
187 | |
188 if (ctx == NULL) { | |
189 return ngx_http_next_body_filter(r, in); | |
190 } | |
191 | |
192 if ((in == NULL | |
193 && ctx->buf == NULL | |
194 && ctx->in == NULL | |
195 && ctx->busy == NULL)) | |
196 { | |
197 return ngx_http_next_body_filter(r, in); | |
198 } | |
199 | |
200 if (ctx->once && (ctx->buf == NULL || ctx->in == NULL)) { | |
201 | |
202 if (ctx->busy) { | |
203 if (ngx_http_sub_output(r, ctx) == NGX_ERROR) { | |
204 return NGX_ERROR; | |
205 } | |
206 } | |
207 | |
208 return ngx_http_next_body_filter(r, in); | |
209 } | |
210 | |
211 /* add the incoming chain to the chain ctx->in */ | |
212 | |
213 if (in) { | |
2536
a6d6d762c554
small optimization: " == NGX_ERROR" > " != NGX_OK"
Igor Sysoev <igor@sysoev.ru>
parents:
2414
diff
changeset
|
214 if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { |
1172 | 215 return NGX_ERROR; |
216 } | |
217 } | |
218 | |
219 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
220 "http sub filter \"%V\"", &r->uri); | |
221 | |
222 while (ctx->in || ctx->buf) { | |
223 | |
3642 | 224 if (ctx->buf == NULL) { |
1172 | 225 ctx->buf = ctx->in->buf; |
226 ctx->in = ctx->in->next; | |
227 ctx->pos = ctx->buf->pos; | |
228 } | |
229 | |
230 if (ctx->state == sub_start_state) { | |
231 ctx->copy_start = ctx->pos; | |
232 ctx->copy_end = ctx->pos; | |
233 } | |
234 | |
235 b = NULL; | |
236 | |
237 while (ctx->pos < ctx->buf->last) { | |
238 | |
239 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
|
240 "saved: \"%V\" state: %d", &ctx->saved, ctx->state); |
1172 | 241 |
242 rc = ngx_http_sub_parse(r, ctx); | |
243 | |
244 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
|
245 "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
|
246 rc, &ctx->looked, ctx->copy_start, ctx->copy_end); |
1172 | 247 |
248 if (rc == NGX_ERROR) { | |
249 return rc; | |
250 } | |
251 | |
252 if (ctx->copy_start != ctx->copy_end) { | |
253 | |
254 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
|
255 "saved: \"%V\"", &ctx->saved); |
1172 | 256 |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
257 if (ctx->saved.len) { |
1172 | 258 |
259 if (ctx->free) { | |
260 cl = ctx->free; | |
261 ctx->free = ctx->free->next; | |
262 b = cl->buf; | |
263 ngx_memzero(b, sizeof(ngx_buf_t)); | |
264 | |
265 } else { | |
266 b = ngx_calloc_buf(r->pool); | |
267 if (b == NULL) { | |
268 return NGX_ERROR; | |
269 } | |
270 | |
271 cl = ngx_alloc_chain_link(r->pool); | |
272 if (cl == NULL) { | |
273 return NGX_ERROR; | |
274 } | |
275 | |
276 cl->buf = b; | |
277 } | |
278 | |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
279 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
|
280 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
|
281 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
|
282 } |
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 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
|
285 b->last = b->pos + ctx->saved.len; |
1172 | 286 b->memory = 1; |
287 | |
288 *ctx->last_out = cl; | |
289 ctx->last_out = &cl->next; | |
290 | |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
291 ctx->saved.len = 0; |
1172 | 292 } |
293 | |
294 if (ctx->free) { | |
295 cl = ctx->free; | |
296 ctx->free = ctx->free->next; | |
297 b = cl->buf; | |
298 | |
299 } else { | |
300 b = ngx_alloc_buf(r->pool); | |
301 if (b == NULL) { | |
302 return NGX_ERROR; | |
303 } | |
304 | |
305 cl = ngx_alloc_chain_link(r->pool); | |
306 if (cl == NULL) { | |
307 return NGX_ERROR; | |
308 } | |
309 | |
310 cl->buf = b; | |
311 } | |
312 | |
313 ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t)); | |
314 | |
315 b->pos = ctx->copy_start; | |
316 b->last = ctx->copy_end; | |
317 b->shadow = NULL; | |
318 b->last_buf = 0; | |
319 b->recycled = 0; | |
320 | |
321 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
|
322 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
|
323 b->file_pos += b->pos - ctx->buf->pos; |
1172 | 324 } |
325 | |
326 cl->next = NULL; | |
327 *ctx->last_out = cl; | |
328 ctx->last_out = &cl->next; | |
329 } | |
330 | |
331 if (ctx->state == sub_start_state) { | |
332 ctx->copy_start = ctx->pos; | |
333 ctx->copy_end = ctx->pos; | |
334 | |
335 } else { | |
336 ctx->copy_start = NULL; | |
337 ctx->copy_end = NULL; | |
338 } | |
339 | |
340 if (rc == NGX_AGAIN) { | |
341 continue; | |
342 } | |
343 | |
344 | |
345 /* rc == NGX_OK */ | |
346 | |
347 b = ngx_calloc_buf(r->pool); | |
348 if (b == NULL) { | |
349 return NGX_ERROR; | |
350 } | |
351 | |
352 cl = ngx_alloc_chain_link(r->pool); | |
353 if (cl == NULL) { | |
354 return NGX_ERROR; | |
355 } | |
356 | |
357 slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module); | |
358 | |
359 if (ctx->sub.data == NULL) { | |
360 | |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
361 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
|
362 != NGX_OK) |
1172 | 363 { |
364 return NGX_ERROR; | |
365 } | |
366 } | |
367 | |
1555
76fe59c6fafb
fix empty string replacement in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
1172
diff
changeset
|
368 if (ctx->sub.len) { |
76fe59c6fafb
fix empty string replacement in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
1172
diff
changeset
|
369 b->memory = 1; |
76fe59c6fafb
fix empty string replacement in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
1172
diff
changeset
|
370 b->pos = ctx->sub.data; |
76fe59c6fafb
fix empty string replacement in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
1172
diff
changeset
|
371 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
|
372 |
76fe59c6fafb
fix empty string replacement in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
1172
diff
changeset
|
373 } else { |
76fe59c6fafb
fix empty string replacement in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
1172
diff
changeset
|
374 b->sync = 1; |
76fe59c6fafb
fix empty string replacement in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
1172
diff
changeset
|
375 } |
1172 | 376 |
377 cl->buf = b; | |
378 cl->next = NULL; | |
379 *ctx->last_out = cl; | |
380 ctx->last_out = &cl->next; | |
381 | |
382 ctx->once = slcf->once; | |
383 | |
384 continue; | |
385 } | |
386 | |
387 if (ctx->buf->last_buf || ngx_buf_in_memory(ctx->buf)) { | |
388 if (b == NULL) { | |
389 if (ctx->free) { | |
390 cl = ctx->free; | |
391 ctx->free = ctx->free->next; | |
392 b = cl->buf; | |
393 ngx_memzero(b, sizeof(ngx_buf_t)); | |
394 | |
395 } else { | |
396 b = ngx_calloc_buf(r->pool); | |
397 if (b == NULL) { | |
398 return NGX_ERROR; | |
399 } | |
400 | |
401 cl = ngx_alloc_chain_link(r->pool); | |
402 if (cl == NULL) { | |
403 return NGX_ERROR; | |
404 } | |
405 | |
406 cl->buf = b; | |
407 } | |
408 | |
409 b->sync = 1; | |
410 | |
411 cl->next = NULL; | |
412 *ctx->last_out = cl; | |
413 ctx->last_out = &cl->next; | |
414 } | |
415 | |
416 b->last_buf = ctx->buf->last_buf; | |
417 b->shadow = ctx->buf; | |
418 | |
419 b->recycled = ctx->buf->recycled; | |
420 } | |
421 | |
422 ctx->buf = NULL; | |
423 | |
3675
08d7165b6be1
fix case of partially matched patterns on buffer border in sub_filter
Igor Sysoev <igor@sysoev.ru>
parents:
3642
diff
changeset
|
424 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
|
425 ngx_memcpy(ctx->saved.data, ctx->looked.data, ctx->looked.len); |
1172 | 426 } |
427 | |
428 if (ctx->out == NULL && ctx->busy == NULL) { | |
429 return NGX_OK; | |
430 } | |
431 | |
432 return ngx_http_sub_output(r, ctx); | |
433 } | |
434 | |
435 | |
436 static ngx_int_t | |
437 ngx_http_sub_output(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) | |
438 { | |
439 ngx_int_t rc; | |
440 ngx_buf_t *b; | |
441 ngx_chain_t *cl; | |
442 | |
443 #if 1 | |
444 b = NULL; | |
445 for (cl = ctx->out; cl; cl = cl->next) { | |
446 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
447 "sub out: %p %p", cl->buf, cl->buf->pos); | |
448 if (cl->buf == b) { | |
449 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
450 "the same buf was used in sub"); | |
451 ngx_debug_point(); | |
452 return NGX_ERROR; | |
453 } | |
454 b = cl->buf; | |
455 } | |
456 #endif | |
457 | |
458 rc = ngx_http_next_body_filter(r, ctx->out); | |
459 | |
460 if (ctx->busy == NULL) { | |
461 ctx->busy = ctx->out; | |
462 | |
463 } else { | |
464 for (cl = ctx->busy; cl->next; cl = cl->next) { /* void */ } | |
465 cl->next = ctx->out; | |
466 } | |
467 | |
468 ctx->out = NULL; | |
469 ctx->last_out = &ctx->out; | |
470 | |
471 while (ctx->busy) { | |
472 | |
473 cl = ctx->busy; | |
474 b = cl->buf; | |
475 | |
476 if (ngx_buf_size(b) != 0) { | |
477 break; | |
478 } | |
479 | |
480 if (b->shadow) { | |
481 b->shadow->pos = b->shadow->last; | |
482 } | |
483 | |
484 ctx->busy = cl->next; | |
485 | |
486 if (ngx_buf_in_memory(b) || b->in_file) { | |
487 /* add data bufs only to the free buf chain */ | |
488 | |
489 cl->next = ctx->free; | |
490 ctx->free = cl; | |
491 } | |
492 } | |
493 | |
494 if (ctx->in || ctx->buf) { | |
495 r->buffered |= NGX_HTTP_SUB_BUFFERED; | |
496 | |
497 } else { | |
498 r->buffered &= ~NGX_HTTP_SUB_BUFFERED; | |
499 } | |
500 | |
501 return rc; | |
502 } | |
503 | |
504 | |
505 static ngx_int_t | |
506 ngx_http_sub_parse(ngx_http_request_t *r, ngx_http_sub_ctx_t *ctx) | |
507 { | |
508 u_char *p, *last, *copy_end, ch, match; | |
509 size_t looked; | |
510 ngx_http_sub_state_e state; | |
511 | |
512 if (ctx->once) { | |
513 ctx->copy_start = ctx->pos; | |
514 ctx->copy_end = ctx->buf->last; | |
515 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
|
516 ctx->looked.len = 0; |
1172 | 517 |
518 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "once"); | |
519 | |
520 return NGX_AGAIN; | |
521 } | |
522 | |
523 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
|
524 looked = ctx->looked.len; |
1172 | 525 last = ctx->buf->last; |
526 copy_end = ctx->copy_end; | |
527 | |
528 for (p = ctx->pos; p < last; p++) { | |
529 | |
530 ch = *p; | |
531 ch = ngx_tolower(ch); | |
532 | |
533 if (state == sub_start_state) { | |
534 | |
535 /* the tight loop */ | |
536 | |
537 match = ctx->match.data[0]; | |
538 | |
539 for ( ;; ) { | |
540 if (ch == match) { | |
541 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
|
542 ctx->looked.data[0] = *p; |
1172 | 543 looked = 1; |
544 state = sub_match_state; | |
545 | |
546 goto match_started; | |
547 } | |
548 | |
549 if (++p == last) { | |
550 break; | |
551 } | |
552 | |
553 ch = *p; | |
554 ch = ngx_tolower(ch); | |
555 } | |
556 | |
1557
9d094e581587
*) add sub_filter parser fix similar to r1261 in SSI parser
Igor Sysoev <igor@sysoev.ru>
parents:
1555
diff
changeset
|
557 ctx->state = state; |
1172 | 558 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
|
559 ctx->looked.len = looked; |
1172 | 560 ctx->copy_end = p; |
561 | |
562 if (ctx->copy_start == NULL) { | |
563 ctx->copy_start = ctx->buf->pos; | |
564 } | |
565 | |
566 return NGX_AGAIN; | |
567 | |
568 match_started: | |
569 | |
570 continue; | |
571 } | |
572 | |
573 /* state == sub_match_state */ | |
574 | |
575 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
|
576 ctx->looked.data[looked] = *p; |
1172 | 577 looked++; |
578 | |
579 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
|
580 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
|
581 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
|
582 } |
9d094e581587
*) add sub_filter parser fix similar to r1261 in SSI parser
Igor Sysoev <igor@sysoev.ru>
parents:
1555
diff
changeset
|
583 |
1172 | 584 ctx->state = sub_start_state; |
585 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
|
586 ctx->looked.len = 0; |
1172 | 587 ctx->copy_end = copy_end; |
588 | |
589 if (ctx->copy_start == NULL && copy_end) { | |
590 ctx->copy_start = ctx->buf->pos; | |
591 } | |
592 | |
593 return NGX_OK; | |
594 } | |
595 | |
596 } else if (ch == ctx->match.data[0]) { | |
597 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
|
598 ctx->looked.data[0] = *p; |
1172 | 599 looked = 1; |
600 | |
601 } else { | |
602 copy_end = p; | |
603 looked = 0; | |
604 state = sub_start_state; | |
605 } | |
606 } | |
607 | |
608 ctx->state = state; | |
609 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
|
610 ctx->looked.len = looked; |
1172 | 611 |
612 ctx->copy_end = (state == sub_start_state) ? p : copy_end; | |
613 | |
614 if (ctx->copy_start == NULL && ctx->copy_end) { | |
615 ctx->copy_start = ctx->buf->pos; | |
616 } | |
617 | |
618 return NGX_AGAIN; | |
619 } | |
620 | |
621 | |
622 static char * | |
623 ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
624 { | |
625 ngx_http_sub_loc_conf_t *slcf = conf; | |
626 | |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
627 ngx_str_t *value; |
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
628 ngx_http_compile_complex_value_t ccv; |
1172 | 629 |
630 if (slcf->match.len) { | |
631 return "is duplicate"; | |
632 } | |
633 | |
634 value = cf->args->elts; | |
635 | |
2135 | 636 ngx_strlow(value[1].data, value[1].data, value[1].len); |
1172 | 637 |
2135 | 638 slcf->match = value[1]; |
1172 | 639 |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
640 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); |
1172 | 641 |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
642 ccv.cf = cf; |
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
643 ccv.value = &value[2]; |
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
644 ccv.complex_value = &slcf->value; |
1172 | 645 |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
646 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { |
1172 | 647 return NGX_CONF_ERROR; |
648 } | |
649 | |
650 return NGX_CONF_OK; | |
651 } | |
652 | |
653 | |
654 static void * | |
655 ngx_http_sub_create_conf(ngx_conf_t *cf) | |
656 { | |
657 ngx_http_sub_loc_conf_t *slcf; | |
658 | |
659 slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_sub_loc_conf_t)); | |
660 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
|
661 return NULL; |
1172 | 662 } |
663 | |
664 /* | |
665 * set by ngx_pcalloc(): | |
666 * | |
2166
723df5089c05
use hash in gzip_types, ssi_types, and sub_filter_types
Igor Sysoev <igor@sysoev.ru>
parents:
2135
diff
changeset
|
667 * 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
|
668 * conf->sub = { 0, NULL }; |
1172 | 669 * conf->sub_lengths = NULL; |
670 * 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
|
671 * conf->types = { NULL }; |
723df5089c05
use hash in gzip_types, ssi_types, and sub_filter_types
Igor Sysoev <igor@sysoev.ru>
parents:
2135
diff
changeset
|
672 * conf->types_keys = NULL; |
1172 | 673 */ |
674 | |
675 slcf->once = NGX_CONF_UNSET; | |
676 | |
677 return slcf; | |
678 } | |
679 | |
680 | |
681 static char * | |
682 ngx_http_sub_merge_conf(ngx_conf_t *cf, void *parent, void *child) | |
683 { | |
684 ngx_http_sub_loc_conf_t *prev = parent; | |
685 ngx_http_sub_loc_conf_t *conf = child; | |
686 | |
687 ngx_conf_merge_value(conf->once, prev->once, 1); | |
688 ngx_conf_merge_str_value(conf->match, prev->match, ""); | |
689 | |
2588
a6954ce88b80
use complex values in add_header, auth_basic_user_file,
Igor Sysoev <igor@sysoev.ru>
parents:
2536
diff
changeset
|
690 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
|
691 conf->value = prev->value; |
1172 | 692 } |
693 | |
3372
6b8e5c882e47
support "*" in gzip_types, ssi_types, etc
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
694 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
|
695 &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
|
696 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
|
697 != NGX_OK) |
723df5089c05
use hash in gzip_types, ssi_types, and sub_filter_types
Igor Sysoev <igor@sysoev.ru>
parents:
2135
diff
changeset
|
698 { |
723df5089c05
use hash in gzip_types, ssi_types, and sub_filter_types
Igor Sysoev <igor@sysoev.ru>
parents:
2135
diff
changeset
|
699 return NGX_CONF_ERROR; |
1172 | 700 } |
701 | |
702 return NGX_CONF_OK; | |
703 } | |
704 | |
705 | |
706 static ngx_int_t | |
707 ngx_http_sub_filter_init(ngx_conf_t *cf) | |
708 { | |
709 ngx_http_next_header_filter = ngx_http_top_header_filter; | |
710 ngx_http_top_header_filter = ngx_http_sub_header_filter; | |
711 | |
712 ngx_http_next_body_filter = ngx_http_top_body_filter; | |
713 ngx_http_top_body_filter = ngx_http_sub_body_filter; | |
714 | |
715 return NGX_OK; | |
716 } |