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