Mercurial > hg > nginx-vendor-0-7
comparison src/http/modules/ngx_http_ssi_filter_module.c @ 58:b55cbf18157e NGINX_0_1_29
nginx 0.1.29
*) Feature: the ngx_http_ssi_module supports "include virtual" command.
*) Feature: the ngx_http_ssi_module supports the condition command like
'if expr="$NAME"' and "else" and "endif" commands. Only one nested
level is supported.
*) Feature: the ngx_http_ssi_module supports the DATE_LOCAL and
DATE_GMT variables and "config timefmt" command.
*) Feature: the "ssi_ignore_recycled_buffers" directive.
*) Bugfix: the "echo" command did not show the default value for the
empty QUERY_STRING variable.
*) Change: the ngx_http_proxy_module was rewritten.
*) Feature: the "proxy_redirect", "proxy_pass_request_headers",
"proxy_pass_request_body", and "proxy_method" directives.
*) Feature: the "proxy_set_header" directive. The "proxy_x_var" was
canceled and must be replaced with the proxy_set_header directive.
*) Change: the "proxy_preserve_host" is canceled and must be replaced
with the "proxy_set_header Host $host" and the "proxy_redirect off"
directives, the "proxy_set_header Host $host:$proxy_port" directive
and the appropriate proxy_redirect directives.
*) Change: the "proxy_set_x_real_ip" is canceled and must be replaced
with the "proxy_set_header X-Real-IP $remote_addr" directive.
*) Change: the "proxy_add_x_forwarded_for" is canceled and must be
replaced with
the "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for"
directive.
*) Change: the "proxy_set_x_url" is canceled and must be replaced with
the "proxy_set_header X-URL http://$host:$server_port$request_uri"
directive.
*) Feature: the "fastcgi_param" directive.
*) Change: the "fastcgi_root", "fastcgi_set_var" and "fastcgi_params"
directive are canceled and must be replaced with the fastcgi_param
directives.
*) Feature: the "index" directive can use the variables.
*) Feature: the "index" directive can be used at http and server levels.
*) Change: the last index only in the "index" directive can be absolute.
*) Feature: the "rewrite" directive can use the variables.
*) Feature: the "internal" directive.
*) Feature: the CONTENT_LENGTH, CONTENT_TYPE, REMOTE_PORT, SERVER_ADDR,
SERVER_PORT, SERVER_PROTOCOL, DOCUMENT_ROOT, SERVER_NAME,
REQUEST_METHOD, REQUEST_URI, and REMOTE_USER variables.
*) Change: nginx now passes the invalid lines in a client request
headers or a backend response header.
*) Bugfix: if the backend did not transfer response for a long time and
the "send_timeout" was less than "proxy_read_timeout", then nginx
returned the 408 response.
*) Bugfix: the segmentation fault was occurred if the backend sent an
invalid line in response header; bug appeared in 0.1.26.
*) Bugfix: the segmentation fault may occurred in FastCGI fault
tolerance configuration.
*) Bugfix: the "expires" directive did not remove the previous
"Expires" and "Cache-Control" headers.
*) Bugfix: nginx did not take into account trailing dot in "Host"
header line.
*) Bugfix: the ngx_http_auth_module did not work under Linux.
*) Bugfix: the rewrite directive worked incorrectly, if the arguments
were in a request.
*) Bugfix: nginx could not be built on MacOS X.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Thu, 12 May 2005 00:00:00 +0400 |
parents | 72eb30262aac |
children | 0790a8599248 |
comparison
equal
deleted
inserted
replaced
57:5df375c55338 | 58:b55cbf18157e |
---|---|
14 #define NGX_HTTP_SSI_PARAM_LEN 31 | 14 #define NGX_HTTP_SSI_PARAM_LEN 31 |
15 #define NGX_HTTP_SSI_PARAMS_N 4 | 15 #define NGX_HTTP_SSI_PARAMS_N 4 |
16 | 16 |
17 #define NGX_HTTP_SSI_ERROR 1 | 17 #define NGX_HTTP_SSI_ERROR 1 |
18 | 18 |
19 #define NGX_HTTP_SSI_DATE_LEN 2048 | |
20 | |
19 | 21 |
20 typedef struct { | 22 typedef struct { |
21 ngx_flag_t enable; | 23 ngx_flag_t enable; |
22 ngx_flag_t silent_errors; | 24 ngx_flag_t silent_errors; |
25 ngx_flag_t ignore_recycled_buffers; | |
23 | 26 |
24 size_t min_file_chunk; | 27 size_t min_file_chunk; |
25 size_t value_len; | 28 size_t value_len; |
26 } ngx_http_ssi_conf_t; | 29 } ngx_http_ssi_conf_t; |
27 | 30 |
48 ngx_uint_t saved_state; | 51 ngx_uint_t saved_state; |
49 size_t saved; | 52 size_t saved; |
50 size_t looked; | 53 size_t looked; |
51 | 54 |
52 size_t value_len; | 55 size_t value_len; |
56 | |
57 ngx_uint_t output; /* unsigned output:1; */ | |
58 | |
59 ngx_str_t timefmt; | |
53 } ngx_http_ssi_ctx_t; | 60 } ngx_http_ssi_ctx_t; |
54 | 61 |
55 | 62 |
56 typedef ngx_int_t (*ngx_http_ssi_command_pt) (ngx_http_request_t *r, | 63 typedef ngx_int_t (*ngx_http_ssi_command_pt) (ngx_http_request_t *r, |
57 ngx_http_ssi_ctx_t *ctx, ngx_str_t **); | 64 ngx_http_ssi_ctx_t *ctx, ngx_str_t **); |
68 typedef struct { | 75 typedef struct { |
69 ngx_str_t name; | 76 ngx_str_t name; |
70 ngx_http_ssi_command_pt handler; | 77 ngx_http_ssi_command_pt handler; |
71 ngx_http_ssi_param_t *params; | 78 ngx_http_ssi_param_t *params; |
72 | 79 |
73 ngx_uint_t flush; /* unsigned flush:1; */ | 80 unsigned conditional:1; |
81 unsigned flush:1; | |
74 } ngx_http_ssi_command_t; | 82 } ngx_http_ssi_command_t; |
75 | 83 |
76 | 84 |
77 typedef enum { | 85 typedef enum { |
78 ssi_start_state = 0, | 86 ssi_start_state = 0, |
96 ssi_error_end0_state, | 104 ssi_error_end0_state, |
97 ssi_error_end1_state | 105 ssi_error_end1_state |
98 } ngx_http_ssi_state_e; | 106 } ngx_http_ssi_state_e; |
99 | 107 |
100 | 108 |
109 static ngx_int_t ngx_http_ssi_output(ngx_http_request_t *r, | |
110 ngx_http_ssi_ctx_t *ctx); | |
101 static ngx_int_t ngx_http_ssi_parse(ngx_http_request_t *r, | 111 static ngx_int_t ngx_http_ssi_parse(ngx_http_request_t *r, |
102 ngx_http_ssi_ctx_t *ctx); | 112 ngx_http_ssi_ctx_t *ctx); |
103 | 113 |
104 static ngx_int_t ngx_http_ssi_echo(ngx_http_request_t *r, | 114 static ngx_int_t ngx_http_ssi_echo(ngx_http_request_t *r, |
105 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); | 115 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); |
106 | 116 static ngx_int_t ngx_http_ssi_config(ngx_http_request_t *r, |
117 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); | |
118 static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r, | |
119 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); | |
120 static ngx_int_t ngx_http_ssi_if(ngx_http_request_t *r, | |
121 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); | |
122 static ngx_int_t ngx_http_ssi_else(ngx_http_request_t *r, | |
123 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); | |
124 static ngx_int_t ngx_http_ssi_endif(ngx_http_request_t *r, | |
125 ngx_http_ssi_ctx_t *ctx, ngx_str_t **params); | |
126 | |
127 static ngx_http_variable_value_t * | |
128 ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, uintptr_t gmt); | |
129 | |
130 static ngx_int_t ngx_http_ssi_add_variables(ngx_conf_t *cf); | |
107 static void *ngx_http_ssi_create_conf(ngx_conf_t *cf); | 131 static void *ngx_http_ssi_create_conf(ngx_conf_t *cf); |
108 static char *ngx_http_ssi_merge_conf(ngx_conf_t *cf, | 132 static char *ngx_http_ssi_merge_conf(ngx_conf_t *cf, |
109 void *parent, void *child); | 133 void *parent, void *child); |
110 static ngx_int_t ngx_http_ssi_filter_init(ngx_cycle_t *cycle); | 134 static ngx_int_t ngx_http_ssi_filter_init(ngx_cycle_t *cycle); |
111 | 135 |
124 ngx_conf_set_flag_slot, | 148 ngx_conf_set_flag_slot, |
125 NGX_HTTP_LOC_CONF_OFFSET, | 149 NGX_HTTP_LOC_CONF_OFFSET, |
126 offsetof(ngx_http_ssi_conf_t, silent_errors), | 150 offsetof(ngx_http_ssi_conf_t, silent_errors), |
127 NULL }, | 151 NULL }, |
128 | 152 |
153 { ngx_string("ssi_ignore_recycled_buffers"), | |
154 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
155 ngx_conf_set_flag_slot, | |
156 NGX_HTTP_LOC_CONF_OFFSET, | |
157 offsetof(ngx_http_ssi_conf_t, ignore_recycled_buffers), | |
158 NULL }, | |
159 | |
129 { ngx_string("ssi_min_file_chunk"), | 160 { ngx_string("ssi_min_file_chunk"), |
130 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | 161 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, |
131 ngx_conf_set_size_slot, | 162 ngx_conf_set_size_slot, |
132 NGX_HTTP_LOC_CONF_OFFSET, | 163 NGX_HTTP_LOC_CONF_OFFSET, |
133 offsetof(ngx_http_ssi_conf_t, min_file_chunk), | 164 offsetof(ngx_http_ssi_conf_t, min_file_chunk), |
137 }; | 168 }; |
138 | 169 |
139 | 170 |
140 | 171 |
141 static ngx_http_module_t ngx_http_ssi_filter_module_ctx = { | 172 static ngx_http_module_t ngx_http_ssi_filter_module_ctx = { |
142 NULL, /* pre conf */ | 173 ngx_http_ssi_add_variables, /* preconfiguration */ |
174 NULL, /* postconfiguration */ | |
143 | 175 |
144 NULL, /* create main configuration */ | 176 NULL, /* create main configuration */ |
145 NULL, /* init main configuration */ | 177 NULL, /* init main configuration */ |
146 | 178 |
147 NULL, /* create server configuration */ | 179 NULL, /* create server configuration */ |
151 ngx_http_ssi_merge_conf /* merge location configuration */ | 183 ngx_http_ssi_merge_conf /* merge location configuration */ |
152 }; | 184 }; |
153 | 185 |
154 | 186 |
155 ngx_module_t ngx_http_ssi_filter_module = { | 187 ngx_module_t ngx_http_ssi_filter_module = { |
156 NGX_MODULE, | 188 NGX_MODULE_V1, |
157 &ngx_http_ssi_filter_module_ctx, /* module context */ | 189 &ngx_http_ssi_filter_module_ctx, /* module context */ |
158 ngx_http_ssi_filter_commands, /* module directives */ | 190 ngx_http_ssi_filter_commands, /* module directives */ |
159 NGX_HTTP_MODULE, /* module type */ | 191 NGX_HTTP_MODULE, /* module type */ |
160 ngx_http_ssi_filter_init, /* init module */ | 192 ngx_http_ssi_filter_init, /* init module */ |
161 NULL /* init process */ | 193 NULL /* init process */ |
172 "[an error occurred while processing the directive]"; | 204 "[an error occurred while processing the directive]"; |
173 | 205 |
174 static ngx_str_t ngx_http_ssi_none = ngx_string("(none)"); | 206 static ngx_str_t ngx_http_ssi_none = ngx_string("(none)"); |
175 | 207 |
176 | 208 |
177 #define NGX_HTTP_SSI_ECHO_VAR 0 | 209 #define NGX_HTTP_SSI_ECHO_VAR 0 |
178 #define NGX_HTTP_SSI_ECHO_DEFAULT 1 | 210 #define NGX_HTTP_SSI_ECHO_DEFAULT 1 |
211 | |
212 #define NGX_HTTP_SSI_CONFIG_TIMEFMT 0 | |
213 | |
214 #define NGX_HTTP_SSI_INCLUDE_VIRTUAL 0 | |
215 #define NGX_HTTP_SSI_INCLUDE_FILE 1 | |
216 | |
217 #define NGX_HTTP_SSI_IF_EXPR 0 | |
218 | |
179 | 219 |
180 static ngx_http_ssi_param_t ngx_http_ssi_echo_params[] = { | 220 static ngx_http_ssi_param_t ngx_http_ssi_echo_params[] = { |
181 { ngx_string("var"), NGX_HTTP_SSI_ECHO_VAR, 1 }, | 221 { ngx_string("var"), NGX_HTTP_SSI_ECHO_VAR, 1 }, |
182 { ngx_string("default"), NGX_HTTP_SSI_ECHO_DEFAULT, 0 }, | 222 { ngx_string("default"), NGX_HTTP_SSI_ECHO_DEFAULT, 0 }, |
183 { ngx_null_string, 0, 0 } | 223 { ngx_null_string, 0, 0 } |
184 }; | 224 }; |
185 | 225 |
226 static ngx_http_ssi_param_t ngx_http_ssi_include_params[] = { | |
227 { ngx_string("virtual"), NGX_HTTP_SSI_INCLUDE_VIRTUAL, 0 }, | |
228 #if 0 | |
229 { ngx_string("file"), NGX_HTTP_SSI_INCLUDE_FILE, 0 }, | |
230 #endif | |
231 { ngx_null_string, 0, 0 } | |
232 }; | |
233 | |
234 | |
235 static ngx_http_ssi_param_t ngx_http_ssi_config_params[] = { | |
236 { ngx_string("timefmt"), NGX_HTTP_SSI_CONFIG_TIMEFMT, 0 }, | |
237 { ngx_null_string, 0, 0 } | |
238 }; | |
239 | |
240 | |
241 static ngx_http_ssi_param_t ngx_http_ssi_if_params[] = { | |
242 { ngx_string("expr"), NGX_HTTP_SSI_IF_EXPR, 0 }, | |
243 { ngx_null_string, 0, 0 } | |
244 }; | |
245 | |
246 | |
247 static ngx_http_ssi_param_t ngx_http_ssi_no_params[] = { | |
248 { ngx_null_string, 0, 0 } | |
249 }; | |
250 | |
186 | 251 |
187 static ngx_http_ssi_command_t ngx_http_ssi_commands[] = { | 252 static ngx_http_ssi_command_t ngx_http_ssi_commands[] = { |
188 { ngx_string("echo"), ngx_http_ssi_echo, ngx_http_ssi_echo_params, 0 }, | 253 { ngx_string("echo"), ngx_http_ssi_echo, ngx_http_ssi_echo_params, 0, 0 }, |
189 { ngx_null_string, NULL, NULL, 0 } | 254 { ngx_string("config"), ngx_http_ssi_config, |
255 ngx_http_ssi_config_params, 0, 0 }, | |
256 { ngx_string("include"), ngx_http_ssi_include, | |
257 ngx_http_ssi_include_params, 0, 1 }, | |
258 | |
259 { ngx_string("if"), ngx_http_ssi_if, ngx_http_ssi_if_params, 0, 0 }, | |
260 { ngx_string("else"), ngx_http_ssi_else, ngx_http_ssi_no_params, 1, 0 }, | |
261 { ngx_string("endif"), ngx_http_ssi_endif, ngx_http_ssi_no_params, 1, 0 }, | |
262 | |
263 { ngx_null_string, NULL, NULL, 0, 0 } | |
190 }; | 264 }; |
265 | |
266 | |
267 static ngx_http_variable_t ngx_http_ssi_vars[] = { | |
268 | |
269 { ngx_string("date_local"), ngx_http_ssi_date_gmt_local_variable, 0, | |
270 NGX_HTTP_VAR_NOCACHABLE }, | |
271 | |
272 { ngx_string("date_gmt"), ngx_http_ssi_date_gmt_local_variable, 1, | |
273 NGX_HTTP_VAR_NOCACHABLE }, | |
274 | |
275 { ngx_null_string, NULL, 0, 0 } | |
276 }; | |
277 | |
191 | 278 |
192 | 279 |
193 static ngx_int_t | 280 static ngx_int_t |
194 ngx_http_ssi_header_filter(ngx_http_request_t *r) | 281 ngx_http_ssi_header_filter(ngx_http_request_t *r) |
195 { | 282 { |
202 return ngx_http_next_header_filter(r); | 289 return ngx_http_next_header_filter(r); |
203 } | 290 } |
204 | 291 |
205 /* TODO: "text/html" -> custom types */ | 292 /* TODO: "text/html" -> custom types */ |
206 | 293 |
207 if (r->headers_out.content_type | 294 if (r->headers_out.content_type.len == 0 |
208 && ngx_strncasecmp(r->headers_out.content_type->value.data, | 295 || ngx_strncasecmp(r->headers_out.content_type.data, "text/html", 5) |
209 "text/html", 5) != 0) | 296 != 0) |
210 { | 297 { |
211 return ngx_http_next_header_filter(r); | 298 return ngx_http_next_header_filter(r); |
212 } | 299 } |
213 | 300 |
214 | 301 |
220 ngx_http_set_ctx(r, ctx, ngx_http_ssi_filter_module); | 307 ngx_http_set_ctx(r, ctx, ngx_http_ssi_filter_module); |
221 | 308 |
222 | 309 |
223 ctx->value_len = conf->value_len; | 310 ctx->value_len = conf->value_len; |
224 ctx->last_out = &ctx->out; | 311 ctx->last_out = &ctx->out; |
312 | |
313 ctx->output = 1; | |
225 | 314 |
226 ctx->params.elts = ctx->params_array; | 315 ctx->params.elts = ctx->params_array; |
227 ctx->params.size = sizeof(ngx_table_elt_t); | 316 ctx->params.size = sizeof(ngx_table_elt_t); |
228 ctx->params.nalloc = NGX_HTTP_SSI_PARAMS_N; | 317 ctx->params.nalloc = NGX_HTTP_SSI_PARAMS_N; |
229 ctx->params.pool = r->pool; | 318 ctx->params.pool = r->pool; |
230 | 319 |
231 r->headers_out.content_length_n = -1; | 320 ctx->timefmt.len = sizeof("%A, %d-%b-%Y %H:%M:%S %Z") - 1; |
232 if (r->headers_out.content_length) { | 321 ctx->timefmt.data = (u_char *) "%A, %d-%b-%Y %H:%M:%S %Z"; |
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 | 322 |
243 r->filter_need_in_memory = 1; | 323 r->filter_need_in_memory = 1; |
244 r->filter_ssi_need_in_memory = 1; | 324 r->filter_ssi_need_in_memory = 1; |
325 | |
326 if (r->main == NULL) { | |
327 r->headers_out.content_length_n = -1; | |
328 if (r->headers_out.content_length) { | |
329 r->headers_out.content_length->hash = 0; | |
330 r->headers_out.content_length = NULL; | |
331 } | |
332 | |
333 r->headers_out.last_modified_time = -1; | |
334 if (r->headers_out.last_modified) { | |
335 r->headers_out.last_modified->hash = 0; | |
336 r->headers_out.last_modified = NULL; | |
337 } | |
338 } | |
245 | 339 |
246 return ngx_http_next_header_filter(r); | 340 return ngx_http_next_header_filter(r); |
247 } | 341 } |
248 | 342 |
249 | 343 |
275 } | 369 } |
276 } | 370 } |
277 | 371 |
278 conf = ngx_http_get_module_loc_conf(r, ngx_http_ssi_filter_module); | 372 conf = ngx_http_get_module_loc_conf(r, ngx_http_ssi_filter_module); |
279 | 373 |
280 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 374 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
281 "http ssi filter"); | 375 "http ssi filter \"%V\"", &r->uri); |
282 | 376 |
283 while (ctx->in || ctx->buf) { | 377 while (ctx->in || ctx->buf) { |
284 | 378 |
285 if (ctx->buf == NULL ){ | 379 if (ctx->buf == NULL ){ |
286 ctx->buf = ctx->in->buf; | 380 ctx->buf = ctx->in->buf; |
310 return rc; | 404 return rc; |
311 } | 405 } |
312 | 406 |
313 if (ctx->copy_start != ctx->copy_end) { | 407 if (ctx->copy_start != ctx->copy_end) { |
314 | 408 |
315 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 409 if (ctx->output) { |
316 "saved: %d", ctx->saved); | 410 |
317 | 411 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
318 if (ctx->saved) { | 412 "saved: %d", ctx->saved); |
413 | |
414 if (ctx->saved) { | |
415 | |
416 if (ctx->free) { | |
417 cl = ctx->free; | |
418 ctx->free = ctx->free->next; | |
419 b = cl->buf; | |
420 ngx_memzero(b, sizeof(ngx_buf_t)); | |
421 | |
422 } else { | |
423 b = ngx_calloc_buf(r->pool); | |
424 if (b == NULL) { | |
425 return NGX_ERROR; | |
426 } | |
427 | |
428 cl = ngx_alloc_chain_link(r->pool); | |
429 if (cl == NULL) { | |
430 return NGX_ERROR; | |
431 } | |
432 | |
433 cl->buf = b; | |
434 } | |
435 | |
436 b->memory = 1; | |
437 b->pos = ngx_http_ssi_string; | |
438 b->last = ngx_http_ssi_string + ctx->saved; | |
439 | |
440 *ctx->last_out = cl; | |
441 ctx->last_out = &cl->next; | |
442 | |
443 ctx->saved = 0; | |
444 } | |
319 | 445 |
320 if (ctx->free) { | 446 if (ctx->free) { |
321 cl = ctx->free; | 447 cl = ctx->free; |
322 ctx->free = ctx->free->next; | 448 ctx->free = ctx->free->next; |
323 b = cl->buf; | 449 b = cl->buf; |
324 ngx_memzero(b, sizeof(ngx_buf_t)); | |
325 | 450 |
326 } else { | 451 } else { |
327 b = ngx_calloc_buf(r->pool); | 452 b = ngx_alloc_buf(r->pool); |
328 if (b == NULL) { | 453 if (b == NULL) { |
329 return NGX_ERROR; | 454 return NGX_ERROR; |
330 } | 455 } |
331 | 456 |
332 cl = ngx_alloc_chain_link(r->pool); | 457 cl = ngx_alloc_chain_link(r->pool); |
335 } | 460 } |
336 | 461 |
337 cl->buf = b; | 462 cl->buf = b; |
338 } | 463 } |
339 | 464 |
340 b->memory = 1; | 465 ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t)); |
341 b->pos = ngx_http_ssi_string; | 466 |
342 b->last = ngx_http_ssi_string + ctx->saved; | 467 b->last_buf = 0; |
343 | 468 b->recycled = 0; |
469 b->pos = ctx->copy_start; | |
470 b->last = ctx->copy_end; | |
471 | |
472 if (b->in_file) { | |
473 if (conf->min_file_chunk < (size_t) (b->last - b->pos)) | |
474 { | |
475 b->file_last = b->file_pos + (b->last - b->start); | |
476 b->file_pos += b->pos - b->start; | |
477 | |
478 } else { | |
479 b->in_file = 0; | |
480 } | |
481 } | |
482 | |
483 cl->next = NULL; | |
344 *ctx->last_out = cl; | 484 *ctx->last_out = cl; |
345 ctx->last_out = &cl->next; | 485 ctx->last_out = &cl->next; |
346 | 486 |
487 } else { | |
347 ctx->saved = 0; | 488 ctx->saved = 0; |
348 } | 489 } |
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 } | 490 } |
391 | 491 |
392 if (ctx->state == ssi_start_state) { | 492 if (ctx->state == ssi_start_state) { |
393 ctx->copy_start = ctx->pos; | 493 ctx->copy_start = ctx->pos; |
394 ctx->copy_end = ctx->pos; | 494 ctx->copy_end = ctx->pos; |
418 } | 518 } |
419 | 519 |
420 break; | 520 break; |
421 } | 521 } |
422 | 522 |
423 if (cmd->name.len == 0) { | 523 if (cmd->name.len == 0 && ctx->output) { |
424 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | 524 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
425 "invalid SSI command: \"%V\"", &ctx->command); | 525 "invalid SSI command: \"%V\"", &ctx->command); |
426 goto ssi_error; | 526 goto ssi_error; |
527 } | |
528 | |
529 if (!ctx->output && !cmd->conditional) { | |
530 continue; | |
427 } | 531 } |
428 | 532 |
429 ngx_memzero(params, | 533 ngx_memzero(params, |
430 NGX_HTTP_SSI_MAX_PARAMS * sizeof(ngx_str_t *)); | 534 NGX_HTTP_SSI_MAX_PARAMS * sizeof(ngx_str_t *)); |
431 | 535 |
477 | 581 |
478 goto ssi_error; | 582 goto ssi_error; |
479 } | 583 } |
480 } | 584 } |
481 | 585 |
586 if (cmd->flush && ctx->out) { | |
587 rc = ngx_http_ssi_output(r, ctx); | |
588 | |
589 if (rc == NGX_ERROR) { | |
590 return NGX_ERROR; | |
591 } | |
592 } | |
593 | |
482 if (cmd->handler(r, ctx, params) == NGX_OK) { | 594 if (cmd->handler(r, ctx, params) == NGX_OK) { |
483 continue; | 595 continue; |
484 } | 596 } |
485 } | 597 } |
486 | 598 |
523 ctx->last_out = &cl->next; | 635 ctx->last_out = &cl->next; |
524 | 636 |
525 continue; | 637 continue; |
526 } | 638 } |
527 | 639 |
528 if (ctx->buf->recycled || ctx->buf->last_buf) { | 640 if (ctx->buf->last_buf || ctx->buf->recycled) { |
641 | |
529 if (b == NULL) { | 642 if (b == NULL) { |
530 | |
531 if (ctx->free) { | 643 if (ctx->free) { |
532 cl = ctx->free; | 644 cl = ctx->free; |
533 ctx->free = ctx->free->next; | 645 ctx->free = ctx->free->next; |
534 b = cl->buf; | 646 b = cl->buf; |
535 ngx_memzero(b, sizeof(ngx_buf_t)); | 647 ngx_memzero(b, sizeof(ngx_buf_t)); |
546 } | 658 } |
547 | 659 |
548 cl->buf = b; | 660 cl->buf = b; |
549 } | 661 } |
550 | 662 |
663 b->sync = 1; | |
664 | |
551 cl->next = NULL; | 665 cl->next = NULL; |
552 *ctx->last_out = cl; | 666 *ctx->last_out = cl; |
553 ctx->last_out = &cl->next; | 667 ctx->last_out = &cl->next; |
554 } | 668 } |
555 | 669 |
556 b->last_buf = ctx->buf->last_buf; | 670 b->last_buf = ctx->buf->last_buf; |
557 b->flush = ctx->buf->recycled; | |
558 b->shadow = ctx->buf; | 671 b->shadow = ctx->buf; |
672 | |
673 if (conf->ignore_recycled_buffers == 0) { | |
674 b->recycled = ctx->buf->recycled; | |
675 } | |
559 } | 676 } |
560 | 677 |
561 ctx->buf = NULL; | 678 ctx->buf = NULL; |
562 | 679 |
563 ctx->saved = ctx->looked; | 680 ctx->saved = ctx->looked; |
564 } | 681 } |
565 | 682 |
566 if (ctx->out == NULL && ctx->busy == NULL) { | 683 if (ctx->out == NULL && ctx->busy == NULL) { |
567 return NGX_OK; | 684 return NGX_OK; |
568 } | 685 } |
686 | |
687 return ngx_http_ssi_output(r, ctx); | |
688 } | |
689 | |
690 | |
691 static ngx_int_t | |
692 ngx_http_ssi_output(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx) | |
693 { | |
694 ngx_int_t rc; | |
695 ngx_buf_t *b; | |
696 ngx_chain_t *cl; | |
569 | 697 |
570 rc = ngx_http_next_body_filter(r, ctx->out); | 698 rc = ngx_http_next_body_filter(r, ctx->out); |
571 | 699 |
572 if (ctx->busy == NULL) { | 700 if (ctx->busy == NULL) { |
573 ctx->busy = ctx->out; | 701 ctx->busy = ctx->out; |
1152 ngx_http_variable_value_t *vv; | 1280 ngx_http_variable_value_t *vv; |
1153 | 1281 |
1154 var = params[NGX_HTTP_SSI_ECHO_VAR]; | 1282 var = params[NGX_HTTP_SSI_ECHO_VAR]; |
1155 | 1283 |
1156 for (i = 0; i < var->len; i++) { | 1284 for (i = 0; i < var->len; i++) { |
1157 var->data[i] = ngx_toupper(var->data[i]); | 1285 var->data[i] = ngx_tolower(var->data[i]); |
1158 } | 1286 } |
1159 | 1287 |
1160 vv = ngx_http_get_variable(r, var); | 1288 vv = ngx_http_get_variable(r, var); |
1161 | 1289 |
1162 if (vv == NULL) { | 1290 if (vv == NULL) { |
1163 return NGX_HTTP_SSI_ERROR; | 1291 return NGX_HTTP_SSI_ERROR; |
1164 } | 1292 } |
1165 | 1293 |
1166 if (vv == NGX_HTTP_VARIABLE_NOT_FOUND) { | 1294 if (vv == NGX_HTTP_VAR_NOT_FOUND) { |
1167 value = params[NGX_HTTP_SSI_ECHO_DEFAULT]; | 1295 value = params[NGX_HTTP_SSI_ECHO_DEFAULT]; |
1168 | 1296 |
1169 if (value == NULL) { | 1297 if (value == NULL) { |
1170 value = &ngx_http_ssi_none; | 1298 value = &ngx_http_ssi_none; |
1171 | 1299 |
1202 | 1330 |
1203 return NGX_OK; | 1331 return NGX_OK; |
1204 } | 1332 } |
1205 | 1333 |
1206 | 1334 |
1335 static ngx_int_t | |
1336 ngx_http_ssi_config(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, | |
1337 ngx_str_t **params) | |
1338 { | |
1339 ngx_str_t *value; | |
1340 | |
1341 value = params[NGX_HTTP_SSI_CONFIG_TIMEFMT]; | |
1342 | |
1343 if (value) { | |
1344 ctx->timefmt = *value; | |
1345 } | |
1346 | |
1347 return NGX_OK; | |
1348 } | |
1349 | |
1350 | |
1351 static ngx_int_t | |
1352 ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, | |
1353 ngx_str_t **params) | |
1354 { | |
1355 u_char ch, *p, **value; | |
1356 size_t *size, len; | |
1357 ngx_uint_t i, j, n, bracket; | |
1358 ngx_str_t uri, args, name; | |
1359 ngx_array_t lengths, values; | |
1360 ngx_http_variable_value_t *vv; | |
1361 | |
1362 /* TODO: file, virtual vs file */ | |
1363 | |
1364 uri = *params[NGX_HTTP_SSI_INCLUDE_VIRTUAL]; | |
1365 args.len = 0; | |
1366 args.data = NULL; | |
1367 | |
1368 n = ngx_http_script_variables_count(&uri); | |
1369 | |
1370 if (n > 0) { | |
1371 | |
1372 if (ngx_array_init(&lengths, r->pool, 8, sizeof(size_t *)) != NGX_OK) { | |
1373 return NGX_HTTP_SSI_ERROR; | |
1374 } | |
1375 | |
1376 if (ngx_array_init(&values, r->pool, 8, sizeof(u_char *)) != NGX_OK) { | |
1377 return NGX_HTTP_SSI_ERROR; | |
1378 } | |
1379 | |
1380 len = 0; | |
1381 | |
1382 for (i = 0; i < uri.len; /* void */ ) { | |
1383 | |
1384 name.len = 0; | |
1385 | |
1386 if (uri.data[i] == '$') { | |
1387 | |
1388 if (++i == uri.len) { | |
1389 goto invalid_variable; | |
1390 } | |
1391 | |
1392 if (uri.data[i] == '{') { | |
1393 bracket = 1; | |
1394 | |
1395 if (++i == uri.len) { | |
1396 goto invalid_variable; | |
1397 } | |
1398 | |
1399 name.data = &uri.data[i]; | |
1400 | |
1401 } else { | |
1402 bracket = 0; | |
1403 name.data = &uri.data[i]; | |
1404 } | |
1405 | |
1406 for ( /* void */ ; i < uri.len; i++, name.len++) { | |
1407 ch = uri.data[i]; | |
1408 | |
1409 if (ch == '}' && bracket) { | |
1410 i++; | |
1411 bracket = 0; | |
1412 break; | |
1413 } | |
1414 | |
1415 if ((ch >= 'A' && ch <= 'Z') | |
1416 || (ch >= 'a' && ch <= 'z') | |
1417 || (ch >= '0' && ch <= '9') | |
1418 || ch == '_') | |
1419 { | |
1420 continue; | |
1421 } | |
1422 | |
1423 break; | |
1424 } | |
1425 | |
1426 if (bracket) { | |
1427 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1428 "the closing bracket in \"%V\" " | |
1429 "variable is missing", &name); | |
1430 return NGX_HTTP_SSI_ERROR; | |
1431 } | |
1432 | |
1433 if (name.len == 0) { | |
1434 goto invalid_variable; | |
1435 } | |
1436 | |
1437 for (j = 0; j < name.len; j++) { | |
1438 name.data[j] = ngx_tolower(name.data[j]); | |
1439 } | |
1440 | |
1441 vv = ngx_http_get_variable(r, &name); | |
1442 | |
1443 if (vv == NULL) { | |
1444 return NGX_HTTP_SSI_ERROR; | |
1445 } | |
1446 | |
1447 if (vv == NGX_HTTP_VAR_NOT_FOUND) { | |
1448 continue; | |
1449 } | |
1450 | |
1451 name = vv->text; | |
1452 | |
1453 } else { | |
1454 name.data = &uri.data[i]; | |
1455 | |
1456 while (i < uri.len && uri.data[i] != '$') { | |
1457 i++; | |
1458 name.len++; | |
1459 } | |
1460 } | |
1461 | |
1462 len += name.len; | |
1463 | |
1464 size = ngx_array_push(&lengths); | |
1465 if (size == NULL) { | |
1466 return NGX_HTTP_SSI_ERROR; | |
1467 } | |
1468 | |
1469 *size = name.len; | |
1470 | |
1471 value = ngx_array_push(&values); | |
1472 if (value == NULL) { | |
1473 return NGX_HTTP_SSI_ERROR; | |
1474 } | |
1475 | |
1476 *value = name.data; | |
1477 } | |
1478 | |
1479 p = ngx_palloc(r->pool, len); | |
1480 if (p == NULL) { | |
1481 return NGX_HTTP_SSI_ERROR; | |
1482 } | |
1483 | |
1484 uri.len = len; | |
1485 uri.data = p; | |
1486 | |
1487 size = lengths.elts; | |
1488 value = values.elts; | |
1489 | |
1490 for (i = 0; i < values.nelts; i++) { | |
1491 p = ngx_cpymem(p, value[i], size[i]); | |
1492 } | |
1493 } | |
1494 | |
1495 for (i = 0; i < uri.len; i++) { | |
1496 if (uri.data[i] == '?') { | |
1497 args.len = uri.len - i - 1; | |
1498 args.data = &uri.data[i + 1]; | |
1499 uri.len -= args.len + 1; | |
1500 | |
1501 break; | |
1502 } | |
1503 } | |
1504 | |
1505 if (ngx_http_subrequest(r, &uri, &args) != NGX_OK) { | |
1506 return NGX_HTTP_SSI_ERROR; | |
1507 } | |
1508 | |
1509 return NGX_OK; | |
1510 | |
1511 invalid_variable: | |
1512 | |
1513 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1514 "invalid variable name in \"%V\"", &uri); | |
1515 | |
1516 return NGX_ERROR; | |
1517 } | |
1518 | |
1519 | |
1520 static ngx_int_t | |
1521 ngx_http_ssi_if(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, | |
1522 ngx_str_t **params) | |
1523 { | |
1524 ngx_str_t *expr, var; | |
1525 ngx_uint_t i; | |
1526 ngx_http_variable_value_t *vv; | |
1527 | |
1528 expr = params[NGX_HTTP_SSI_IF_EXPR]; | |
1529 | |
1530 if (expr->data[0] != '$') { | |
1531 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1532 "invalid variable name in \"%V\"", expr); | |
1533 return NGX_HTTP_SSI_ERROR; | |
1534 } | |
1535 | |
1536 var.len = expr->len - 1; | |
1537 var.data = expr->data + 1; | |
1538 | |
1539 for (i = 0; i < var.len; i++) { | |
1540 var.data[i] = ngx_tolower(var.data[i]); | |
1541 } | |
1542 | |
1543 vv = ngx_http_get_variable(r, &var); | |
1544 | |
1545 if (vv == NULL) { | |
1546 return NGX_HTTP_SSI_ERROR; | |
1547 } | |
1548 | |
1549 if (vv != NGX_HTTP_VAR_NOT_FOUND && vv->text.len != 0) { | |
1550 ctx->output = 1; | |
1551 | |
1552 } else { | |
1553 ctx->output = 0; | |
1554 } | |
1555 | |
1556 return NGX_OK; | |
1557 } | |
1558 | |
1559 | |
1560 static ngx_int_t | |
1561 ngx_http_ssi_else(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, | |
1562 ngx_str_t **params) | |
1563 { | |
1564 ctx->output = !ctx->output; | |
1565 | |
1566 return NGX_OK; | |
1567 } | |
1568 | |
1569 | |
1570 static ngx_int_t | |
1571 ngx_http_ssi_endif(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, | |
1572 ngx_str_t **params) | |
1573 { | |
1574 ctx->output = 1; | |
1575 | |
1576 return NGX_OK; | |
1577 } | |
1578 | |
1579 | |
1580 static ngx_http_variable_value_t * | |
1581 ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, uintptr_t gmt) | |
1582 { | |
1583 ngx_http_ssi_ctx_t *ctx; | |
1584 ngx_http_variable_value_t *vv; | |
1585 struct tm tm; | |
1586 char buf[NGX_HTTP_SSI_DATE_LEN]; | |
1587 | |
1588 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); | |
1589 if (vv == NULL) { | |
1590 return NULL; | |
1591 } | |
1592 | |
1593 ctx = ngx_http_get_module_ctx(r, ngx_http_ssi_filter_module); | |
1594 | |
1595 if (ctx->timefmt.len == sizeof("%s") - 1 | |
1596 && ctx->timefmt.data[0] == '%' && ctx->timefmt.data[1] == 's') | |
1597 { | |
1598 vv->value = ngx_time() + (gmt ? 0 : ngx_gmtoff); | |
1599 | |
1600 vv->text.data = ngx_palloc(r->pool, NGX_TIME_T_LEN); | |
1601 if (vv->text.data == NULL) { | |
1602 return NULL; | |
1603 } | |
1604 | |
1605 vv->text.len = ngx_sprintf(vv->text.data, "%T", vv->value) | |
1606 - vv->text.data; | |
1607 return vv; | |
1608 } | |
1609 | |
1610 if (gmt) { | |
1611 ngx_libc_gmtime(&tm); | |
1612 } else { | |
1613 ngx_libc_localtime(&tm); | |
1614 } | |
1615 | |
1616 vv->value = ngx_time() + (gmt ? 0 : ngx_gmtoff); | |
1617 | |
1618 vv->text.len = strftime(buf, NGX_HTTP_SSI_DATE_LEN, | |
1619 (char *) ctx->timefmt.data, &tm); | |
1620 if (vv->text.len == 0) { | |
1621 return NULL; | |
1622 } | |
1623 | |
1624 vv->text.data = ngx_palloc(r->pool, vv->text.len); | |
1625 if (vv->text.data == NULL) { | |
1626 return NULL; | |
1627 } | |
1628 | |
1629 ngx_memcpy(vv->text.data, buf, vv->text.len); | |
1630 | |
1631 return vv; | |
1632 } | |
1633 | |
1634 | |
1635 static ngx_int_t | |
1636 ngx_http_ssi_add_variables(ngx_conf_t *cf) | |
1637 { | |
1638 ngx_http_variable_t *var, *v; | |
1639 | |
1640 for (v = ngx_http_ssi_vars; v->name.len; v++) { | |
1641 var = ngx_http_add_variable(cf, &v->name, v->flags); | |
1642 if (var == NULL) { | |
1643 return NGX_ERROR; | |
1644 } | |
1645 | |
1646 var->handler = v->handler; | |
1647 var->data = v->data; | |
1648 } | |
1649 | |
1650 return NGX_OK; | |
1651 } | |
1652 | |
1653 | |
1207 static void * | 1654 static void * |
1208 ngx_http_ssi_create_conf(ngx_conf_t *cf) | 1655 ngx_http_ssi_create_conf(ngx_conf_t *cf) |
1209 { | 1656 { |
1210 ngx_http_ssi_conf_t *conf; | 1657 ngx_http_ssi_conf_t *conf; |
1211 | 1658 |
1214 return NGX_CONF_ERROR; | 1661 return NGX_CONF_ERROR; |
1215 } | 1662 } |
1216 | 1663 |
1217 conf->enable = NGX_CONF_UNSET; | 1664 conf->enable = NGX_CONF_UNSET; |
1218 conf->silent_errors = NGX_CONF_UNSET; | 1665 conf->silent_errors = NGX_CONF_UNSET; |
1666 conf->ignore_recycled_buffers = NGX_CONF_UNSET; | |
1219 | 1667 |
1220 conf->min_file_chunk = NGX_CONF_UNSET_SIZE; | 1668 conf->min_file_chunk = NGX_CONF_UNSET_SIZE; |
1221 conf->value_len = NGX_CONF_UNSET_SIZE; | 1669 conf->value_len = NGX_CONF_UNSET_SIZE; |
1222 | 1670 |
1223 return conf; | 1671 return conf; |
1230 ngx_http_ssi_conf_t *prev = parent; | 1678 ngx_http_ssi_conf_t *prev = parent; |
1231 ngx_http_ssi_conf_t *conf = child; | 1679 ngx_http_ssi_conf_t *conf = child; |
1232 | 1680 |
1233 ngx_conf_merge_value(conf->enable, prev->enable, 0); | 1681 ngx_conf_merge_value(conf->enable, prev->enable, 0); |
1234 ngx_conf_merge_value(conf->silent_errors, prev->silent_errors, 0); | 1682 ngx_conf_merge_value(conf->silent_errors, prev->silent_errors, 0); |
1683 ngx_conf_merge_value(conf->ignore_recycled_buffers, | |
1684 prev->ignore_recycled_buffers, 0); | |
1235 | 1685 |
1236 ngx_conf_merge_size_value(conf->min_file_chunk, prev->min_file_chunk, 1024); | 1686 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); | 1687 ngx_conf_merge_size_value(conf->value_len, prev->value_len, 256); |
1238 | 1688 |
1239 return NGX_CONF_OK; | 1689 return NGX_CONF_OK; |