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