Mercurial > hg > nginx-mail
comparison src/http/modules/ngx_http_ssi_filter_module.c @ 50:72eb30262aac NGINX_0_1_25
nginx 0.1.25
*) Bugfix: nginx did run on Linux parisc.
*) Feature: nginx now does not start under FreeBSD if the sysctl
kern.ipc.somaxconn value is too big.
*) Bugfix: if a request was internally redirected by the
ngx_http_index_module module to the ngx_http_proxy_module or
ngx_http_fastcgi_module modules, then the index file was not closed
after request completion.
*) Feature: the "proxy_pass" can be used in location with regular
expression.
*) Feature: the ngx_http_rewrite_filter_module module supports the
condition like "if ($HTTP_USER_AGENT ~ MSIE)".
*) Bugfix: nginx started too slow if the large number of addresses and
text values were used in the "geo" directive.
*) Change: a variable name must be declared as "$name" in the "geo"
directive. The previous variant without "$" is still supported, but
will be removed soon.
*) Feature: the "%{VARIABLE}v" logging parameter.
*) Feature: the "set $name value" directive.
*) Bugfix: gcc 4.0 compatibility.
*) Feature: the --with-openssl-opt=OPTIONS autoconfiguration directive.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Sat, 19 Mar 2005 00:00:00 +0300 |
parents | src/http/modules/ngx_http_ssi_filter.c@6cfc63e68377 |
children | b55cbf18157e |
comparison
equal
deleted
inserted
replaced
49:93dabbc9efb9 | 50:72eb30262aac |
---|---|
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 #define NGX_HTTP_SSI_MAX_PARAMS 16 | |
12 | |
13 #define NGX_HTTP_SSI_COMMAND_LEN 31 | |
14 #define NGX_HTTP_SSI_PARAM_LEN 31 | |
15 #define NGX_HTTP_SSI_PARAMS_N 4 | |
16 | |
17 #define NGX_HTTP_SSI_ERROR 1 | |
18 | |
19 | |
20 typedef struct { | |
21 ngx_flag_t enable; | |
22 ngx_flag_t silent_errors; | |
23 | |
24 size_t min_file_chunk; | |
25 size_t value_len; | |
26 } ngx_http_ssi_conf_t; | |
27 | |
28 | |
29 typedef struct { | |
30 ngx_buf_t *buf; | |
31 | |
32 u_char *pos; | |
33 u_char *copy_start; | |
34 u_char *copy_end; | |
35 | |
36 ngx_str_t command; | |
37 ngx_array_t params; | |
38 ngx_table_elt_t *param; | |
39 ngx_table_elt_t params_array[NGX_HTTP_SSI_PARAMS_N]; | |
40 | |
41 ngx_chain_t *in; | |
42 ngx_chain_t *out; | |
43 ngx_chain_t **last_out; | |
44 ngx_chain_t *busy; | |
45 ngx_chain_t *free; | |
46 | |
47 ngx_uint_t state; | |
48 ngx_uint_t saved_state; | |
49 size_t saved; | |
50 size_t looked; | |
51 | |
52 size_t value_len; | |
53 } ngx_http_ssi_ctx_t; | |
54 | |
55 | |
56 typedef ngx_int_t (*ngx_http_ssi_command_pt) (ngx_http_request_t *r, | |
57 ngx_http_ssi_ctx_t *ctx, ngx_str_t **); | |
58 | |
59 | |
60 typedef struct { | |
61 ngx_str_t name; | |
62 ngx_uint_t index; | |
63 | |
64 ngx_uint_t mandatory; | |
65 } ngx_http_ssi_param_t; | |
66 | |
67 | |
68 typedef struct { | |
69 ngx_str_t name; | |
70 ngx_http_ssi_command_pt handler; | |
71 ngx_http_ssi_param_t *params; | |
72 | |
73 ngx_uint_t flush; /* unsigned flush:1; */ | |
74 } ngx_http_ssi_command_t; | |
75 | |
76 | |
77 typedef enum { | |
78 ssi_start_state = 0, | |
79 ssi_tag_state, | |
80 ssi_comment0_state, | |
81 ssi_comment1_state, | |
82 ssi_sharp_state, | |
83 ssi_precommand_state, | |
84 ssi_command_state, | |
85 ssi_preparam_state, | |
86 ssi_param_state, | |
87 ssi_preequal_state, | |
88 ssi_prevalue_state, | |
89 ssi_double_quoted_value_state, | |
90 ssi_quoted_value_state, | |
91 ssi_quoted_symbol_state, | |
92 ssi_postparam_state, | |
93 ssi_comment_end0_state, | |
94 ssi_comment_end1_state, | |
95 ssi_error_state, | |
96 ssi_error_end0_state, | |
97 ssi_error_end1_state | |
98 } ngx_http_ssi_state_e; | |
99 | |
100 | |
101 static ngx_int_t ngx_http_ssi_parse(ngx_http_request_t *r, | |
102 ngx_http_ssi_ctx_t *ctx); | |
103 | |
104 static ngx_int_t ngx_http_ssi_echo(ngx_http_request_t *r, | |
105 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); | |
106 | |
107 static void *ngx_http_ssi_create_conf(ngx_conf_t *cf); | |
108 static char *ngx_http_ssi_merge_conf(ngx_conf_t *cf, | |
109 void *parent, void *child); | |
110 static ngx_int_t ngx_http_ssi_filter_init(ngx_cycle_t *cycle); | |
111 | |
112 | |
113 static ngx_command_t ngx_http_ssi_filter_commands[] = { | |
114 | |
115 { ngx_string("ssi"), | |
116 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
117 ngx_conf_set_flag_slot, | |
118 NGX_HTTP_LOC_CONF_OFFSET, | |
119 offsetof(ngx_http_ssi_conf_t, enable), | |
120 NULL }, | |
121 | |
122 { ngx_string("ssi_silent_errors"), | |
123 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
124 ngx_conf_set_flag_slot, | |
125 NGX_HTTP_LOC_CONF_OFFSET, | |
126 offsetof(ngx_http_ssi_conf_t, silent_errors), | |
127 NULL }, | |
128 | |
129 { ngx_string("ssi_min_file_chunk"), | |
130 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
131 ngx_conf_set_size_slot, | |
132 NGX_HTTP_LOC_CONF_OFFSET, | |
133 offsetof(ngx_http_ssi_conf_t, min_file_chunk), | |
134 NULL }, | |
135 | |
136 ngx_null_command | |
137 }; | |
138 | |
139 | |
140 | |
141 static ngx_http_module_t ngx_http_ssi_filter_module_ctx = { | |
142 NULL, /* pre conf */ | |
143 | |
144 NULL, /* create main configuration */ | |
145 NULL, /* init main configuration */ | |
146 | |
147 NULL, /* create server configuration */ | |
148 NULL, /* merge server configuration */ | |
149 | |
150 ngx_http_ssi_create_conf, /* create location configuration */ | |
151 ngx_http_ssi_merge_conf /* merge location configuration */ | |
152 }; | |
153 | |
154 | |
155 ngx_module_t ngx_http_ssi_filter_module = { | |
156 NGX_MODULE, | |
157 &ngx_http_ssi_filter_module_ctx, /* module context */ | |
158 ngx_http_ssi_filter_commands, /* module directives */ | |
159 NGX_HTTP_MODULE, /* module type */ | |
160 ngx_http_ssi_filter_init, /* init module */ | |
161 NULL /* init process */ | |
162 }; | |
163 | |
164 | |
165 static ngx_int_t (*ngx_http_next_header_filter) (ngx_http_request_t *r); | |
166 static ngx_int_t (*ngx_http_next_body_filter) (ngx_http_request_t *r, | |
167 ngx_chain_t *in); | |
168 | |
169 | |
170 static u_char ngx_http_ssi_string[] = "<!--"; | |
171 static u_char ngx_http_ssi_error_string[] = | |
172 "[an error occurred while processing the directive]"; | |
173 | |
174 static ngx_str_t ngx_http_ssi_none = ngx_string("(none)"); | |
175 | |
176 | |
177 #define NGX_HTTP_SSI_ECHO_VAR 0 | |
178 #define NGX_HTTP_SSI_ECHO_DEFAULT 1 | |
179 | |
180 static ngx_http_ssi_param_t ngx_http_ssi_echo_params[] = { | |
181 { ngx_string("var"), NGX_HTTP_SSI_ECHO_VAR, 1 }, | |
182 { ngx_string("default"), NGX_HTTP_SSI_ECHO_DEFAULT, 0 }, | |
183 { ngx_null_string, 0, 0 } | |
184 }; | |
185 | |
186 | |
187 static ngx_http_ssi_command_t ngx_http_ssi_commands[] = { | |
188 { ngx_string("echo"), ngx_http_ssi_echo, ngx_http_ssi_echo_params, 0 }, | |
189 { ngx_null_string, NULL, NULL, 0 } | |
190 }; | |
191 | |
192 | |
193 static ngx_int_t | |
194 ngx_http_ssi_header_filter(ngx_http_request_t *r) | |
195 { | |
196 ngx_http_ssi_ctx_t *ctx; | |
197 ngx_http_ssi_conf_t *conf; | |
198 | |
199 conf = ngx_http_get_module_loc_conf(r, ngx_http_ssi_filter_module); | |
200 | |
201 if (!conf->enable) { | |
202 return ngx_http_next_header_filter(r); | |
203 } | |
204 | |
205 /* TODO: "text/html" -> custom types */ | |
206 | |
207 if (r->headers_out.content_type | |
208 && ngx_strncasecmp(r->headers_out.content_type->value.data, | |
209 "text/html", 5) != 0) | |
210 { | |
211 return ngx_http_next_header_filter(r); | |
212 } | |
213 | |
214 | |
215 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_ssi_ctx_t)); | |
216 if (ctx == NULL) { | |
217 return NGX_ERROR; | |
218 } | |
219 | |
220 ngx_http_set_ctx(r, ctx, ngx_http_ssi_filter_module); | |
221 | |
222 | |
223 ctx->value_len = conf->value_len; | |
224 ctx->last_out = &ctx->out; | |
225 | |
226 ctx->params.elts = ctx->params_array; | |
227 ctx->params.size = sizeof(ngx_table_elt_t); | |
228 ctx->params.nalloc = NGX_HTTP_SSI_PARAMS_N; | |
229 ctx->params.pool = r->pool; | |
230 | |
231 r->headers_out.content_length_n = -1; | |
232 if (r->headers_out.content_length) { | |
233 r->headers_out.content_length->key.len = 0; | |
234 r->headers_out.content_length = NULL; | |
235 } | |
236 | |
237 r->headers_out.last_modified_time = -1; | |
238 if (r->headers_out.last_modified) { | |
239 r->headers_out.last_modified->key.len = 0; | |
240 r->headers_out.last_modified = NULL; | |
241 } | |
242 | |
243 r->filter_need_in_memory = 1; | |
244 r->filter_ssi_need_in_memory = 1; | |
245 | |
246 return ngx_http_next_header_filter(r); | |
247 } | |
248 | |
249 | |
250 static ngx_int_t | |
251 ngx_http_ssi_body_filter(ngx_http_request_t *r, ngx_chain_t *in) | |
252 { | |
253 ngx_int_t rc; | |
254 ngx_uint_t i; | |
255 ngx_buf_t *b; | |
256 ngx_chain_t *cl; | |
257 ngx_table_elt_t *param; | |
258 ngx_http_ssi_ctx_t *ctx; | |
259 ngx_http_ssi_conf_t *conf; | |
260 ngx_http_ssi_param_t *prm; | |
261 ngx_http_ssi_command_t *cmd; | |
262 ngx_str_t *params[NGX_HTTP_SSI_MAX_PARAMS]; | |
263 | |
264 ctx = ngx_http_get_module_ctx(r, ngx_http_ssi_filter_module); | |
265 | |
266 if (ctx == NULL || (in == NULL && ctx->in == NULL && ctx->busy == NULL)) { | |
267 return ngx_http_next_body_filter(r, in); | |
268 } | |
269 | |
270 /* add the incoming chain to the chain ctx->in */ | |
271 | |
272 if (in) { | |
273 if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) { | |
274 return NGX_ERROR; | |
275 } | |
276 } | |
277 | |
278 conf = ngx_http_get_module_loc_conf(r, ngx_http_ssi_filter_module); | |
279 | |
280 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
281 "http ssi filter"); | |
282 | |
283 while (ctx->in || ctx->buf) { | |
284 | |
285 if (ctx->buf == NULL ){ | |
286 ctx->buf = ctx->in->buf; | |
287 ctx->in = ctx->in->next; | |
288 ctx->pos = ctx->buf->pos; | |
289 } | |
290 | |
291 if (ctx->state == ssi_start_state) { | |
292 ctx->copy_start = ctx->pos; | |
293 ctx->copy_end = ctx->pos; | |
294 } | |
295 | |
296 b = NULL; | |
297 | |
298 while (ctx->pos < ctx->buf->last) { | |
299 | |
300 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
301 "saved: %d state: %d", ctx->saved, ctx->state); | |
302 | |
303 rc = ngx_http_ssi_parse(r, ctx); | |
304 | |
305 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
306 "parse: %d, looked: %d %p-%p", | |
307 rc, ctx->looked, ctx->copy_start, ctx->copy_end); | |
308 | |
309 if (rc == NGX_ERROR) { | |
310 return rc; | |
311 } | |
312 | |
313 if (ctx->copy_start != ctx->copy_end) { | |
314 | |
315 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
316 "saved: %d", ctx->saved); | |
317 | |
318 if (ctx->saved) { | |
319 | |
320 if (ctx->free) { | |
321 cl = ctx->free; | |
322 ctx->free = ctx->free->next; | |
323 b = cl->buf; | |
324 ngx_memzero(b, sizeof(ngx_buf_t)); | |
325 | |
326 } else { | |
327 b = ngx_calloc_buf(r->pool); | |
328 if (b == NULL) { | |
329 return NGX_ERROR; | |
330 } | |
331 | |
332 cl = ngx_alloc_chain_link(r->pool); | |
333 if (cl == NULL) { | |
334 return NGX_ERROR; | |
335 } | |
336 | |
337 cl->buf = b; | |
338 } | |
339 | |
340 b->memory = 1; | |
341 b->pos = ngx_http_ssi_string; | |
342 b->last = ngx_http_ssi_string + ctx->saved; | |
343 | |
344 *ctx->last_out = cl; | |
345 ctx->last_out = &cl->next; | |
346 | |
347 ctx->saved = 0; | |
348 } | |
349 | |
350 if (ctx->free) { | |
351 cl = ctx->free; | |
352 ctx->free = ctx->free->next; | |
353 b = cl->buf; | |
354 | |
355 } else { | |
356 b = ngx_alloc_buf(r->pool); | |
357 if (b == NULL) { | |
358 return NGX_ERROR; | |
359 } | |
360 | |
361 cl = ngx_alloc_chain_link(r->pool); | |
362 if (cl == NULL) { | |
363 return NGX_ERROR; | |
364 } | |
365 | |
366 cl->buf = b; | |
367 } | |
368 | |
369 ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t)); | |
370 | |
371 b->last_buf = 0; | |
372 b->recycled = 0; | |
373 b->pos = ctx->copy_start; | |
374 b->last = ctx->copy_end; | |
375 | |
376 if (b->in_file) { | |
377 | |
378 if (conf->min_file_chunk < (size_t) (b->last - b->pos)) { | |
379 b->file_last = b->file_pos + (b->last - b->start); | |
380 b->file_pos += b->pos - b->start; | |
381 | |
382 } else { | |
383 b->in_file = 0; | |
384 } | |
385 } | |
386 | |
387 cl->next = NULL; | |
388 *ctx->last_out = cl; | |
389 ctx->last_out = &cl->next; | |
390 } | |
391 | |
392 if (ctx->state == ssi_start_state) { | |
393 ctx->copy_start = ctx->pos; | |
394 ctx->copy_end = ctx->pos; | |
395 | |
396 } else { | |
397 ctx->copy_start = NULL; | |
398 ctx->copy_end = NULL; | |
399 } | |
400 | |
401 if (rc == NGX_AGAIN) { | |
402 continue; | |
403 } | |
404 | |
405 | |
406 if (rc == NGX_OK) { | |
407 | |
408 for (cmd = ngx_http_ssi_commands; cmd->handler; cmd++) { | |
409 if (cmd->name.len == 0) { | |
410 cmd = (ngx_http_ssi_command_t *) cmd->handler; | |
411 } | |
412 | |
413 if (cmd->name.len != ctx->command.len | |
414 || ngx_strncmp(cmd->name.data, ctx->command.data, | |
415 ctx->command.len) != 0) | |
416 { | |
417 continue; | |
418 } | |
419 | |
420 break; | |
421 } | |
422 | |
423 if (cmd->name.len == 0) { | |
424 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
425 "invalid SSI command: \"%V\"", &ctx->command); | |
426 goto ssi_error; | |
427 } | |
428 | |
429 ngx_memzero(params, | |
430 NGX_HTTP_SSI_MAX_PARAMS * sizeof(ngx_str_t *)); | |
431 | |
432 param = ctx->params.elts; | |
433 | |
434 | |
435 for (i = 0; i < ctx->params.nelts; i++) { | |
436 | |
437 for (prm = cmd->params; prm->name.len; prm++) { | |
438 | |
439 if (param[i].key.len != prm->name.len | |
440 || ngx_strncmp(param[i].key.data, prm->name.data, | |
441 prm->name.len) != 0) | |
442 { | |
443 continue; | |
444 } | |
445 | |
446 if (params[prm->index]) { | |
447 ngx_log_error(NGX_LOG_ERR, | |
448 r->connection->log, 0, | |
449 "duplicate \"%V\" parameter " | |
450 "in \"%V\" SSI command", | |
451 ¶m[i].key, &ctx->command); | |
452 | |
453 goto ssi_error; | |
454 } | |
455 | |
456 params[prm->index] = ¶m[i].value; | |
457 | |
458 break; | |
459 } | |
460 | |
461 if (prm->name.len == 0) { | |
462 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
463 "invalid parameter name: \"%V\" " | |
464 "in \"%V\" SSI command", | |
465 ¶m[i].key, &ctx->command); | |
466 | |
467 goto ssi_error; | |
468 } | |
469 } | |
470 | |
471 for (prm = cmd->params; prm->name.len; prm++) { | |
472 if (prm->mandatory && params[prm->index] == 0) { | |
473 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
474 "mandatory \"%V\" parameter is absent " | |
475 "in \"%V\" SSI command", | |
476 &prm->name, &ctx->command); | |
477 | |
478 goto ssi_error; | |
479 } | |
480 } | |
481 | |
482 if (cmd->handler(r, ctx, params) == NGX_OK) { | |
483 continue; | |
484 } | |
485 } | |
486 | |
487 | |
488 /* rc == NGX_HTTP_SSI_ERROR */ | |
489 | |
490 ssi_error: | |
491 | |
492 if (conf->silent_errors) { | |
493 continue; | |
494 } | |
495 | |
496 if (ctx->free) { | |
497 cl = ctx->free; | |
498 ctx->free = ctx->free->next; | |
499 b = cl->buf; | |
500 ngx_memzero(b, sizeof(ngx_buf_t)); | |
501 | |
502 } else { | |
503 b = ngx_calloc_buf(r->pool); | |
504 if (b == NULL) { | |
505 return NGX_ERROR; | |
506 } | |
507 | |
508 cl = ngx_alloc_chain_link(r->pool); | |
509 if (cl == NULL) { | |
510 return NGX_ERROR; | |
511 } | |
512 | |
513 cl->buf = b; | |
514 } | |
515 | |
516 b->memory = 1; | |
517 b->pos = ngx_http_ssi_error_string; | |
518 b->last = ngx_http_ssi_error_string | |
519 + sizeof(ngx_http_ssi_error_string) - 1; | |
520 | |
521 cl->next = NULL; | |
522 *ctx->last_out = cl; | |
523 ctx->last_out = &cl->next; | |
524 | |
525 continue; | |
526 } | |
527 | |
528 if (ctx->buf->recycled || ctx->buf->last_buf) { | |
529 if (b == NULL) { | |
530 | |
531 if (ctx->free) { | |
532 cl = ctx->free; | |
533 ctx->free = ctx->free->next; | |
534 b = cl->buf; | |
535 ngx_memzero(b, sizeof(ngx_buf_t)); | |
536 | |
537 } else { | |
538 b = ngx_calloc_buf(r->pool); | |
539 if (b == NULL) { | |
540 return NGX_ERROR; | |
541 } | |
542 | |
543 cl = ngx_alloc_chain_link(r->pool); | |
544 if (cl == NULL) { | |
545 return NGX_ERROR; | |
546 } | |
547 | |
548 cl->buf = b; | |
549 } | |
550 | |
551 cl->next = NULL; | |
552 *ctx->last_out = cl; | |
553 ctx->last_out = &cl->next; | |
554 } | |
555 | |
556 b->last_buf = ctx->buf->last_buf; | |
557 b->flush = ctx->buf->recycled; | |
558 b->shadow = ctx->buf; | |
559 } | |
560 | |
561 ctx->buf = NULL; | |
562 | |
563 ctx->saved = ctx->looked; | |
564 } | |
565 | |
566 if (ctx->out == NULL && ctx->busy == NULL) { | |
567 return NGX_OK; | |
568 } | |
569 | |
570 rc = ngx_http_next_body_filter(r, ctx->out); | |
571 | |
572 if (ctx->busy == NULL) { | |
573 ctx->busy = ctx->out; | |
574 | |
575 } else { | |
576 for (cl = ctx->busy; cl->next; cl = cl->next) { /* void */ } | |
577 cl->next = ctx->out; | |
578 } | |
579 | |
580 ctx->out = NULL; | |
581 ctx->last_out = &ctx->out; | |
582 | |
583 while (ctx->busy) { | |
584 | |
585 b = ctx->busy->buf; | |
586 | |
587 if (ngx_buf_size(b) != 0) { | |
588 break; | |
589 } | |
590 | |
591 #if (NGX_HAVE_WRITE_ZEROCOPY) | |
592 if (b->zerocopy_busy) { | |
593 break; | |
594 } | |
595 #endif | |
596 | |
597 if (b->shadow) { | |
598 b->shadow->pos = b->shadow->last; | |
599 } | |
600 | |
601 cl = ctx->busy; | |
602 ctx->busy = cl->next; | |
603 cl->next = ctx->free; | |
604 ctx->free = cl; | |
605 } | |
606 | |
607 return rc; | |
608 } | |
609 | |
610 | |
611 static ngx_int_t | |
612 ngx_http_ssi_parse(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx) | |
613 { | |
614 u_char *p, *last, *copy_end, ch; | |
615 size_t looked; | |
616 ngx_http_ssi_state_e state; | |
617 | |
618 state = ctx->state; | |
619 looked = ctx->looked; | |
620 last = ctx->buf->last; | |
621 copy_end = ctx->copy_end; | |
622 | |
623 for (p = ctx->pos; p < last; p++) { | |
624 | |
625 ch = *p; | |
626 | |
627 if (state == ssi_start_state) { | |
628 | |
629 /* the tight loop */ | |
630 | |
631 for ( ;; ) { | |
632 if (ch == '<') { | |
633 copy_end = p; | |
634 looked = 1; | |
635 state = ssi_tag_state; | |
636 | |
637 goto tag_started; | |
638 } | |
639 | |
640 if (++p == last) { | |
641 break; | |
642 } | |
643 | |
644 ch = *p; | |
645 } | |
646 | |
647 ctx->pos = p; | |
648 ctx->looked = looked; | |
649 ctx->copy_end = p; | |
650 | |
651 if (ctx->copy_start == NULL) { | |
652 ctx->copy_start = ctx->buf->pos; | |
653 } | |
654 | |
655 return NGX_AGAIN; | |
656 | |
657 tag_started: | |
658 | |
659 continue; | |
660 } | |
661 | |
662 switch (state) { | |
663 | |
664 case ssi_start_state: | |
665 break; | |
666 | |
667 case ssi_tag_state: | |
668 switch (ch) { | |
669 case '!': | |
670 looked = 2; | |
671 state = ssi_comment0_state; | |
672 break; | |
673 | |
674 case '<': | |
675 copy_end = p; | |
676 break; | |
677 | |
678 default: | |
679 copy_end = p; | |
680 looked = 0; | |
681 state = ssi_start_state; | |
682 break; | |
683 } | |
684 | |
685 break; | |
686 | |
687 case ssi_comment0_state: | |
688 switch (ch) { | |
689 case '-': | |
690 looked = 3; | |
691 state = ssi_comment1_state; | |
692 break; | |
693 | |
694 case '<': | |
695 copy_end = p; | |
696 looked = 1; | |
697 state = ssi_tag_state; | |
698 break; | |
699 | |
700 default: | |
701 copy_end = p; | |
702 looked = 0; | |
703 state = ssi_start_state; | |
704 break; | |
705 } | |
706 | |
707 break; | |
708 | |
709 case ssi_comment1_state: | |
710 switch (ch) { | |
711 case '-': | |
712 looked = 4; | |
713 state = ssi_sharp_state; | |
714 break; | |
715 | |
716 case '<': | |
717 copy_end = p; | |
718 looked = 1; | |
719 state = ssi_tag_state; | |
720 break; | |
721 | |
722 default: | |
723 copy_end = p; | |
724 looked = 0; | |
725 state = ssi_start_state; | |
726 break; | |
727 } | |
728 | |
729 break; | |
730 | |
731 case ssi_sharp_state: | |
732 switch (ch) { | |
733 case '#': | |
734 if (ctx->copy_start) { | |
735 ctx->saved = 0; | |
736 } | |
737 looked = 0; | |
738 state = ssi_precommand_state; | |
739 break; | |
740 | |
741 case '<': | |
742 copy_end = p; | |
743 looked = 1; | |
744 state = ssi_tag_state; | |
745 break; | |
746 | |
747 default: | |
748 copy_end = p; | |
749 looked = 0; | |
750 state = ssi_start_state; | |
751 break; | |
752 } | |
753 | |
754 break; | |
755 | |
756 case ssi_precommand_state: | |
757 switch (ch) { | |
758 case ' ': | |
759 case CR: | |
760 case LF: | |
761 case '\t': | |
762 break; | |
763 | |
764 default: | |
765 ctx->command.len = 1; | |
766 ctx->command.data = ngx_palloc(r->pool, | |
767 NGX_HTTP_SSI_COMMAND_LEN + 1); | |
768 if (ctx->command.data == NULL) { | |
769 return NGX_ERROR; | |
770 } | |
771 | |
772 ctx->command.data[0] = ch; | |
773 ctx->params.nelts = 0; | |
774 state = ssi_command_state; | |
775 break; | |
776 } | |
777 | |
778 break; | |
779 | |
780 case ssi_command_state: | |
781 switch (ch) { | |
782 case ' ': | |
783 case CR: | |
784 case LF: | |
785 case '\t': | |
786 state = ssi_preparam_state; | |
787 break; | |
788 | |
789 case '-': | |
790 state = ssi_comment_end0_state; | |
791 break; | |
792 | |
793 default: | |
794 ctx->command.data[ctx->command.len++] = ch; | |
795 | |
796 if (ctx->command.len == NGX_HTTP_SSI_COMMAND_LEN) { | |
797 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
798 "the \"%V\" SSI command is too long", | |
799 &ctx->command); | |
800 | |
801 state = ssi_error_state; | |
802 break; | |
803 } | |
804 } | |
805 | |
806 break; | |
807 | |
808 case ssi_preparam_state: | |
809 switch (ch) { | |
810 case ' ': | |
811 case CR: | |
812 case LF: | |
813 case '\t': | |
814 break; | |
815 | |
816 case '-': | |
817 state = ssi_comment_end0_state; | |
818 break; | |
819 | |
820 default: | |
821 ctx->param = ngx_array_push(&ctx->params); | |
822 if (ctx->param == NULL) { | |
823 return NGX_ERROR; | |
824 } | |
825 | |
826 ctx->param->key.len = 1; | |
827 ctx->param->key.data = ngx_palloc(r->pool, | |
828 NGX_HTTP_SSI_PARAM_LEN + 1); | |
829 if (ctx->param->key.data == NULL) { | |
830 return NGX_ERROR; | |
831 } | |
832 | |
833 ctx->param->key.data[0] = ch; | |
834 | |
835 ctx->param->value.len = 0; | |
836 ctx->param->value.data = ngx_palloc(r->pool, | |
837 ctx->value_len + 1); | |
838 if (ctx->param->value.data == NULL) { | |
839 return NGX_ERROR; | |
840 } | |
841 | |
842 state = ssi_param_state; | |
843 break; | |
844 } | |
845 | |
846 break; | |
847 | |
848 case ssi_param_state: | |
849 switch (ch) { | |
850 case ' ': | |
851 case CR: | |
852 case LF: | |
853 case '\t': | |
854 state = ssi_preequal_state; | |
855 break; | |
856 | |
857 case '=': | |
858 state = ssi_prevalue_state; | |
859 break; | |
860 | |
861 case '-': | |
862 state = ssi_error_end0_state; | |
863 | |
864 ctx->param->key.data[ctx->param->key.len++] = ch; | |
865 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
866 "invalid \"%V\" parameter in \"%V\" SSI command", | |
867 &ctx->param->key, &ctx->command); | |
868 break; | |
869 | |
870 default: | |
871 ctx->param->key.data[ctx->param->key.len++] = ch; | |
872 | |
873 if (ctx->param->key.len == NGX_HTTP_SSI_PARAM_LEN) { | |
874 state = ssi_error_state; | |
875 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
876 "too long \"%V\" parameter in " | |
877 "\"%V\" SSI command", | |
878 &ctx->param->key, &ctx->command); | |
879 break; | |
880 } | |
881 } | |
882 | |
883 break; | |
884 | |
885 case ssi_preequal_state: | |
886 switch (ch) { | |
887 case ' ': | |
888 case CR: | |
889 case LF: | |
890 case '\t': | |
891 break; | |
892 | |
893 case '=': | |
894 state = ssi_prevalue_state; | |
895 break; | |
896 | |
897 default: | |
898 if (ch == '-') { | |
899 state = ssi_error_end0_state; | |
900 } else { | |
901 state = ssi_error_state; | |
902 } | |
903 | |
904 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
905 "unexpected \"%c\" symbol after \"%V\" " | |
906 "parameter in \"%V\" SSI command", | |
907 ch, &ctx->param->key, &ctx->command); | |
908 break; | |
909 } | |
910 | |
911 break; | |
912 | |
913 case ssi_prevalue_state: | |
914 switch (ch) { | |
915 case ' ': | |
916 case CR: | |
917 case LF: | |
918 case '\t': | |
919 break; | |
920 | |
921 case '"': | |
922 state = ssi_double_quoted_value_state; | |
923 break; | |
924 | |
925 case '\'': | |
926 state = ssi_quoted_value_state; | |
927 break; | |
928 | |
929 default: | |
930 if (ch == '-') { | |
931 state = ssi_error_end0_state; | |
932 } else { | |
933 state = ssi_error_state; | |
934 } | |
935 | |
936 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
937 "unexpected \"%c\" symbol before value of " | |
938 "\"%V\" parameter in \"%V\" SSI command", | |
939 ch, &ctx->param->key, &ctx->command); | |
940 break; | |
941 } | |
942 | |
943 break; | |
944 | |
945 case ssi_double_quoted_value_state: | |
946 switch (ch) { | |
947 case '\\': | |
948 ctx->saved_state = ssi_double_quoted_value_state; | |
949 state = ssi_quoted_symbol_state; | |
950 break; | |
951 | |
952 case '"': | |
953 state = ssi_postparam_state; | |
954 break; | |
955 | |
956 default: | |
957 ctx->param->value.data[ctx->param->value.len++] = ch; | |
958 | |
959 if (ctx->param->value.len == ctx->value_len) { | |
960 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
961 "too long \"%V\" value of \"%V\" parameter " | |
962 "in \"%V\" SSI command", | |
963 &ctx->param->value, &ctx->param->key, | |
964 &ctx->command); | |
965 state = ssi_error_state; | |
966 break; | |
967 } | |
968 } | |
969 | |
970 break; | |
971 | |
972 case ssi_quoted_value_state: | |
973 switch (ch) { | |
974 case '\\': | |
975 ctx->saved_state = ssi_quoted_value_state; | |
976 state = ssi_quoted_symbol_state; | |
977 break; | |
978 | |
979 case '\'': | |
980 state = ssi_postparam_state; | |
981 break; | |
982 | |
983 default: | |
984 ctx->param->value.data[ctx->param->value.len++] = ch; | |
985 | |
986 if (ctx->param->value.len == ctx->value_len) { | |
987 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
988 "too long \"%V\" value of \"%V\" parameter " | |
989 "in \"%V\" SSI command", | |
990 &ctx->param->value, &ctx->param->key, | |
991 &ctx->command); | |
992 state = ssi_error_state; | |
993 break; | |
994 } | |
995 } | |
996 | |
997 break; | |
998 | |
999 case ssi_quoted_symbol_state: | |
1000 ctx->param->value.data[ctx->param->value.len++] = ch; | |
1001 | |
1002 if (ctx->param->value.len == ctx->value_len) { | |
1003 if (ctx->param->value.len == ctx->value_len) { | |
1004 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1005 "too long \"%V\" value of \"%V\" parameter " | |
1006 "in \"%V\" SSI command", | |
1007 &ctx->param->value, &ctx->param->key, | |
1008 &ctx->command); | |
1009 state = ssi_error_state; | |
1010 break; | |
1011 } | |
1012 } | |
1013 | |
1014 state = ctx->saved_state; | |
1015 break; | |
1016 | |
1017 case ssi_postparam_state: | |
1018 switch (ch) { | |
1019 case ' ': | |
1020 case CR: | |
1021 case LF: | |
1022 case '\t': | |
1023 state = ssi_preparam_state; | |
1024 break; | |
1025 | |
1026 case '-': | |
1027 state = ssi_comment_end0_state; | |
1028 break; | |
1029 | |
1030 default: | |
1031 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1032 "unexpected \"%c\" symbol after \"%V\" value " | |
1033 "of \"%V\" parameter in \"%V\" SSI command", | |
1034 ch, &ctx->param->value, &ctx->param->key, | |
1035 &ctx->command); | |
1036 state = ssi_error_state; | |
1037 break; | |
1038 } | |
1039 | |
1040 break; | |
1041 | |
1042 case ssi_comment_end0_state: | |
1043 switch (ch) { | |
1044 case '-': | |
1045 state = ssi_comment_end1_state; | |
1046 break; | |
1047 | |
1048 default: | |
1049 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1050 "unexpected \"%c\" symbol in \"%V\" SSI command", | |
1051 ch, &ctx->command); | |
1052 state = ssi_error_state; | |
1053 break; | |
1054 } | |
1055 | |
1056 break; | |
1057 | |
1058 case ssi_comment_end1_state: | |
1059 switch (ch) { | |
1060 case '>': | |
1061 ctx->state = ssi_start_state; | |
1062 ctx->pos = p + 1; | |
1063 ctx->looked = looked; | |
1064 ctx->copy_end = copy_end; | |
1065 | |
1066 if (ctx->copy_start == NULL && copy_end) { | |
1067 ctx->copy_start = ctx->buf->pos; | |
1068 } | |
1069 | |
1070 return NGX_OK; | |
1071 | |
1072 default: | |
1073 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1074 "unexpected \"%c\" symbol in \"%V\" SSI command", | |
1075 ch, &ctx->command); | |
1076 state = ssi_error_state; | |
1077 break; | |
1078 } | |
1079 | |
1080 break; | |
1081 | |
1082 case ssi_error_state: | |
1083 switch (ch) { | |
1084 case '-': | |
1085 state = ssi_error_end0_state; | |
1086 break; | |
1087 | |
1088 default: | |
1089 break; | |
1090 } | |
1091 | |
1092 break; | |
1093 | |
1094 case ssi_error_end0_state: | |
1095 switch (ch) { | |
1096 case '-': | |
1097 state = ssi_error_end1_state; | |
1098 break; | |
1099 | |
1100 default: | |
1101 state = ssi_error_state; | |
1102 break; | |
1103 } | |
1104 | |
1105 break; | |
1106 | |
1107 case ssi_error_end1_state: | |
1108 switch (ch) { | |
1109 case '>': | |
1110 ctx->state = ssi_start_state; | |
1111 ctx->pos = p + 1; | |
1112 ctx->looked = looked; | |
1113 ctx->copy_end = copy_end; | |
1114 | |
1115 if (ctx->copy_start == NULL && copy_end) { | |
1116 ctx->copy_start = ctx->buf->pos; | |
1117 } | |
1118 | |
1119 return NGX_HTTP_SSI_ERROR; | |
1120 | |
1121 default: | |
1122 state = ssi_error_state; | |
1123 break; | |
1124 } | |
1125 | |
1126 break; | |
1127 } | |
1128 } | |
1129 | |
1130 ctx->state = state; | |
1131 ctx->pos = p; | |
1132 ctx->looked = looked; | |
1133 | |
1134 ctx->copy_end = (state == ssi_start_state) ? p : copy_end; | |
1135 | |
1136 if (ctx->copy_start == NULL && ctx->copy_end) { | |
1137 ctx->copy_start = ctx->buf->pos; | |
1138 } | |
1139 | |
1140 return NGX_AGAIN; | |
1141 } | |
1142 | |
1143 | |
1144 static ngx_int_t | |
1145 ngx_http_ssi_echo(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, | |
1146 ngx_str_t **params) | |
1147 { | |
1148 ngx_uint_t i; | |
1149 ngx_buf_t *b; | |
1150 ngx_str_t *var, *value; | |
1151 ngx_chain_t *cl; | |
1152 ngx_http_variable_value_t *vv; | |
1153 | |
1154 var = params[NGX_HTTP_SSI_ECHO_VAR]; | |
1155 | |
1156 for (i = 0; i < var->len; i++) { | |
1157 var->data[i] = ngx_toupper(var->data[i]); | |
1158 } | |
1159 | |
1160 vv = ngx_http_get_variable(r, var); | |
1161 | |
1162 if (vv == NULL) { | |
1163 return NGX_HTTP_SSI_ERROR; | |
1164 } | |
1165 | |
1166 if (vv == NGX_HTTP_VARIABLE_NOT_FOUND) { | |
1167 value = params[NGX_HTTP_SSI_ECHO_DEFAULT]; | |
1168 | |
1169 if (value == NULL) { | |
1170 value = &ngx_http_ssi_none; | |
1171 | |
1172 } else if (value->len == 0) { | |
1173 return NGX_OK; | |
1174 } | |
1175 | |
1176 } else { | |
1177 value = &vv->text; | |
1178 | |
1179 if (value->len == 0) { | |
1180 return NGX_OK; | |
1181 } | |
1182 } | |
1183 | |
1184 b = ngx_calloc_buf(r->pool); | |
1185 if (b == NULL) { | |
1186 return NGX_HTTP_SSI_ERROR; | |
1187 } | |
1188 | |
1189 cl = ngx_alloc_chain_link(r->pool); | |
1190 if (cl == NULL) { | |
1191 return NGX_HTTP_SSI_ERROR; | |
1192 } | |
1193 | |
1194 b->memory = 1; | |
1195 b->pos = value->data; | |
1196 b->last = value->data + value->len; | |
1197 | |
1198 cl->buf = b; | |
1199 cl->next = NULL; | |
1200 *ctx->last_out = cl; | |
1201 ctx->last_out = &cl->next; | |
1202 | |
1203 return NGX_OK; | |
1204 } | |
1205 | |
1206 | |
1207 static void * | |
1208 ngx_http_ssi_create_conf(ngx_conf_t *cf) | |
1209 { | |
1210 ngx_http_ssi_conf_t *conf; | |
1211 | |
1212 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssi_conf_t)); | |
1213 if (conf == NULL) { | |
1214 return NGX_CONF_ERROR; | |
1215 } | |
1216 | |
1217 conf->enable = NGX_CONF_UNSET; | |
1218 conf->silent_errors = NGX_CONF_UNSET; | |
1219 | |
1220 conf->min_file_chunk = NGX_CONF_UNSET_SIZE; | |
1221 conf->value_len = NGX_CONF_UNSET_SIZE; | |
1222 | |
1223 return conf; | |
1224 } | |
1225 | |
1226 | |
1227 static char * | |
1228 ngx_http_ssi_merge_conf(ngx_conf_t *cf, void *parent, void *child) | |
1229 { | |
1230 ngx_http_ssi_conf_t *prev = parent; | |
1231 ngx_http_ssi_conf_t *conf = child; | |
1232 | |
1233 ngx_conf_merge_value(conf->enable, prev->enable, 0); | |
1234 ngx_conf_merge_value(conf->silent_errors, prev->silent_errors, 0); | |
1235 | |
1236 ngx_conf_merge_size_value(conf->min_file_chunk, prev->min_file_chunk, 1024); | |
1237 ngx_conf_merge_size_value(conf->value_len, prev->value_len, 256); | |
1238 | |
1239 return NGX_CONF_OK; | |
1240 } | |
1241 | |
1242 | |
1243 static ngx_int_t | |
1244 ngx_http_ssi_filter_init(ngx_cycle_t *cycle) | |
1245 { | |
1246 ngx_http_next_header_filter = ngx_http_top_header_filter; | |
1247 ngx_http_top_header_filter = ngx_http_ssi_header_filter; | |
1248 | |
1249 ngx_http_next_body_filter = ngx_http_top_body_filter; | |
1250 ngx_http_top_body_filter = ngx_http_ssi_body_filter; | |
1251 | |
1252 return NGX_OK; | |
1253 } |