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 &param[i].key, &ctx->command);
426
427 goto ssi_error;
428 }
429
430 params[prm->index] = &param[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 &param[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;