Mercurial > hg > nginx
annotate src/http/ngx_http_script.c @ 647:95d7da23ea53 release-0.3.45
nginx-0.3.45-RELEASE import
*) Feature: the "ssl_verify_client", "ssl_verify_depth", and
"ssl_client_certificate" directives.
*) Change: the $request_method variable now returns the main request
method.
*) Change: the ° symbol codes were changed in koi-win conversion
table.
*) Feature: the euro and N symbols were added to koi-win conversion
table.
*) Bugfix: if nginx distributed the requests among several backends and
some backend failed, then requests intended for this backend was
directed to one live backend only instead of being distributed among
the rest.
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Sat, 06 May 2006 16:28:56 +0000 |
parents | 5e8fb59c18c1 |
children | 7cbef16c71a1 |
rev | line source |
---|---|
441
da8c5707af39
nginx-0.1.0-2004-09-28-12:34:51 import; set copyright and remove unused files
Igor Sysoev <igor@sysoev.ru>
parents:
99
diff
changeset
|
1 |
da8c5707af39
nginx-0.1.0-2004-09-28-12:34:51 import; set copyright and remove unused files
Igor Sysoev <igor@sysoev.ru>
parents:
99
diff
changeset
|
2 /* |
444
42d11f017717
nginx-0.1.0-2004-09-29-20:00:49 import; remove years from copyright
Igor Sysoev <igor@sysoev.ru>
parents:
441
diff
changeset
|
3 * Copyright (C) Igor Sysoev |
441
da8c5707af39
nginx-0.1.0-2004-09-28-12:34:51 import; set copyright and remove unused files
Igor Sysoev <igor@sysoev.ru>
parents:
99
diff
changeset
|
4 */ |
da8c5707af39
nginx-0.1.0-2004-09-28-12:34:51 import; set copyright and remove unused files
Igor Sysoev <igor@sysoev.ru>
parents:
99
diff
changeset
|
5 |
99
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
6 |
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
7 #include <ngx_config.h> |
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
8 #include <ngx_core.h> |
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
9 #include <ngx_http.h> |
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
10 |
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
11 |
509 | 12 #define ngx_http_script_exit (u_char *) &ngx_http_script_exit_code |
13 | |
14 static uintptr_t ngx_http_script_exit_code = (uintptr_t) NULL; | |
15 | |
16 | |
17 ngx_uint_t | |
18 ngx_http_script_variables_count(ngx_str_t *value) | |
99
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
19 { |
509 | 20 ngx_uint_t i, n; |
507 | 21 |
509 | 22 for (n = 0, i = 0; i < value->len; i++) { |
23 if (value->data[i] == '$') { | |
24 n++; | |
25 } | |
507 | 26 } |
27 | |
509 | 28 return n; |
29 } | |
30 | |
31 | |
32 ngx_int_t | |
33 ngx_http_script_compile(ngx_http_script_compile_t *sc) | |
34 { | |
35 u_char ch; | |
36 size_t size; | |
573 | 37 ngx_int_t index, *p; |
509 | 38 ngx_str_t name; |
39 uintptr_t *code; | |
40 ngx_uint_t i, n, bracket; | |
41 ngx_http_script_var_code_t *var_code; | |
42 ngx_http_script_copy_code_t *copy; | |
43 ngx_http_script_copy_capture_code_t *copy_capture; | |
44 | |
573 | 45 if (sc->flushes && *sc->flushes == NULL) { |
46 n = sc->variables ? sc->variables : 1; | |
47 *sc->flushes = ngx_array_create(sc->cf->pool, n, sizeof(ngx_uint_t)); | |
48 if (*sc->flushes == NULL) { | |
49 return NGX_ERROR; | |
50 } | |
51 } | |
52 | |
53 | |
509 | 54 if (*sc->lengths == NULL) { |
55 n = sc->variables * (2 * sizeof(ngx_http_script_copy_code_t) | |
56 + sizeof(ngx_http_script_var_code_t)) | |
57 + sizeof(uintptr_t); | |
58 | |
59 *sc->lengths = ngx_array_create(sc->cf->pool, n, 1); | |
60 if (*sc->lengths == NULL) { | |
61 return NGX_ERROR; | |
62 } | |
63 } | |
64 | |
65 | |
66 if (*sc->values == NULL) { | |
67 n = (sc->variables * (2 * sizeof(ngx_http_script_copy_code_t) | |
68 + sizeof(ngx_http_script_var_code_t)) | |
69 + sizeof(uintptr_t) | |
70 + sc->source->len | |
71 + sizeof(uintptr_t) - 1) | |
72 & ~(sizeof(uintptr_t) - 1); | |
73 | |
74 *sc->values = ngx_array_create(sc->cf->pool, n, 1); | |
75 if (*sc->values == NULL) { | |
507 | 76 return NGX_ERROR; |
77 } | |
78 } | |
79 | |
509 | 80 sc->variables = 0; |
81 | |
82 for (i = 0; i < sc->source->len; /* void */ ) { | |
83 | |
84 name.len = 0; | |
85 | |
86 if (sc->source->data[i] == '$') { | |
87 | |
88 if (++i == sc->source->len) { | |
89 goto invalid_variable; | |
90 } | |
91 | |
92 if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') { | |
93 | |
641 | 94 n = sc->source->data[i] - '0'; |
95 | |
96 if (sc->captures_mask & (1 << n)) { | |
97 sc->dup_capture = 1; | |
98 } | |
99 | |
100 sc->captures_mask |= 1 << n; | |
101 | |
509 | 102 copy_capture = ngx_http_script_add_code(*sc->lengths, |
103 sizeof(ngx_http_script_copy_capture_code_t), | |
104 NULL); | |
105 if (copy_capture == NULL) { | |
106 return NGX_ERROR; | |
107 } | |
108 | |
109 copy_capture->code = (ngx_http_script_code_pt) | |
110 ngx_http_script_copy_capture_len_code; | |
641 | 111 copy_capture->n = 2 * n; |
112 | |
509 | 113 |
114 copy_capture = ngx_http_script_add_code(*sc->values, | |
115 sizeof(ngx_http_script_copy_capture_code_t), | |
116 &sc->main); | |
117 if (copy_capture == NULL) { | |
118 return NGX_ERROR; | |
119 } | |
120 | |
121 copy_capture->code = ngx_http_script_copy_capture_code; | |
641 | 122 copy_capture->n = 2 * n; |
509 | 123 |
641 | 124 if (sc->ncaptures < n) { |
125 sc->ncaptures = n; | |
509 | 126 } |
127 | |
128 i++; | |
129 | |
130 continue; | |
131 } | |
132 | |
133 if (sc->source->data[i] == '{') { | |
134 bracket = 1; | |
135 | |
136 if (++i == sc->source->len) { | |
137 goto invalid_variable; | |
138 } | |
139 | |
140 name.data = &sc->source->data[i]; | |
141 | |
142 } else { | |
143 bracket = 0; | |
144 name.data = &sc->source->data[i]; | |
145 } | |
146 | |
147 for ( /* void */ ; i < sc->source->len; i++, name.len++) { | |
148 ch = sc->source->data[i]; | |
507 | 149 |
509 | 150 if (ch == '}' && bracket) { |
151 i++; | |
152 bracket = 0; | |
153 break; | |
154 } | |
155 | |
156 if ((ch >= 'A' && ch <= 'Z') | |
157 || (ch >= 'a' && ch <= 'z') | |
158 || (ch >= '0' && ch <= '9') | |
159 || ch == '_') | |
160 { | |
161 continue; | |
162 } | |
163 | |
164 break; | |
165 } | |
166 | |
167 if (bracket) { | |
168 ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, | |
169 "the closing bracket in \"%V\" " | |
170 "variable is missing", &name); | |
507 | 171 return NGX_ERROR; |
172 } | |
173 | |
509 | 174 if (name.len == 0) { |
175 goto invalid_variable; | |
176 } | |
507 | 177 |
509 | 178 sc->variables++; |
507 | 179 |
509 | 180 index = ngx_http_get_variable_index(sc->cf, &name); |
181 | |
182 if (index == NGX_ERROR) { | |
507 | 183 return NGX_ERROR; |
184 } | |
99
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
185 |
573 | 186 if (sc->flushes) { |
187 p = ngx_array_push(*sc->flushes); | |
188 if (p == NULL) { | |
189 return NGX_ERROR; | |
190 } | |
191 | |
192 *p = index; | |
193 } | |
194 | |
509 | 195 var_code = ngx_http_script_add_code(*sc->lengths, |
196 sizeof(ngx_http_script_var_code_t), | |
197 NULL); | |
507 | 198 if (var_code == NULL) { |
199 return NGX_ERROR; | |
200 } | |
201 | |
202 var_code->code = (ngx_http_script_code_pt) | |
509 | 203 ngx_http_script_copy_var_len_code; |
204 var_code->index = (uintptr_t) index; | |
507 | 205 |
206 | |
509 | 207 var_code = ngx_http_script_add_code(*sc->values, |
208 sizeof(ngx_http_script_var_code_t), | |
209 &sc->main); | |
507 | 210 if (var_code == NULL) { |
211 return NGX_ERROR; | |
212 } | |
213 | |
509 | 214 var_code->code = ngx_http_script_copy_var_code; |
215 var_code->index = (uintptr_t) index; | |
216 | |
217 continue; | |
218 } | |
507 | 219 |
509 | 220 if (sc->source->data[i] == '?' && sc->compile_args) { |
221 sc->args = 1; | |
222 sc->compile_args = 0; | |
99
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
223 |
509 | 224 code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t), |
225 &sc->main); | |
226 if (code == NULL) { | |
507 | 227 return NGX_ERROR; |
228 } | |
229 | |
509 | 230 *code = (uintptr_t) ngx_http_script_start_args_code; |
231 | |
232 i++; | |
233 | |
507 | 234 continue; |
235 } | |
236 | |
509 | 237 name.data = &sc->source->data[i]; |
238 | |
239 while (i < sc->source->len | |
240 && sc->source->data[i] != '$' | |
241 && !(sc->source->data[i] == '?' && sc->compile_args)) | |
242 { | |
243 i++; | |
244 name.len++; | |
245 } | |
246 | |
247 sc->size += name.len; | |
248 | |
249 copy = ngx_http_script_add_code(*sc->lengths, | |
250 sizeof(ngx_http_script_copy_code_t), | |
251 NULL); | |
252 if (copy == NULL) { | |
507 | 253 return NGX_ERROR; |
254 } | |
509 | 255 |
256 copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code; | |
257 copy->len = name.len; | |
258 | |
259 size = (sizeof(ngx_http_script_copy_code_t) + name.len | |
260 + sizeof(uintptr_t) - 1) | |
261 & ~(sizeof(uintptr_t) - 1); | |
99
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
262 |
509 | 263 copy = ngx_http_script_add_code(*sc->values, size, &sc->main); |
264 if (copy == NULL) { | |
265 return NGX_ERROR; | |
266 } | |
267 | |
268 copy->code = ngx_http_script_copy_code; | |
269 copy->len = name.len; | |
270 | |
271 ngx_memcpy((u_char *) copy + sizeof(ngx_http_script_copy_code_t), | |
272 name.data, name.len); | |
507 | 273 } |
274 | |
509 | 275 if (sc->complete_lengths) { |
276 code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL); | |
277 if (code == NULL) { | |
278 return NGX_ERROR; | |
279 } | |
507 | 280 |
509 | 281 *code = (uintptr_t) NULL; |
507 | 282 } |
283 | |
509 | 284 if (sc->complete_values) { |
285 code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t), | |
286 &sc->main); | |
287 if (code == NULL) { | |
288 return NGX_ERROR; | |
289 } | |
290 | |
291 *code = (uintptr_t) NULL; | |
292 } | |
507 | 293 |
294 return NGX_OK; | |
509 | 295 |
296 invalid_variable: | |
297 | |
298 ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, "invalid variable name"); | |
299 | |
300 return NGX_ERROR; | |
99
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
301 } |
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
302 |
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
303 |
623 | 304 u_char * |
305 ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value, | |
306 void *code_lengths, size_t len, void *code_values) | |
307 { | |
308 ngx_http_script_code_pt code; | |
309 ngx_http_script_len_code_pt lcode; | |
310 ngx_http_script_engine_t e; | |
311 | |
312 ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); | |
313 | |
314 e.ip = code_lengths; | |
315 e.request = r; | |
316 e.flushed = 1; | |
317 | |
318 while (*(uintptr_t *) e.ip) { | |
319 lcode = *(ngx_http_script_len_code_pt *) e.ip; | |
320 len += lcode(&e); | |
321 } | |
322 | |
323 | |
324 value->len = len; | |
325 value->data = ngx_palloc(r->pool, len); | |
326 if (value->data == NULL) { | |
327 return NULL; | |
328 } | |
329 | |
330 e.ip = code_values; | |
331 e.pos = value->data; | |
332 | |
333 while (*(uintptr_t *) e.ip) { | |
334 code = *(ngx_http_script_code_pt *) e.ip; | |
335 code((ngx_http_script_engine_t *) &e); | |
336 } | |
337 | |
338 return e.pos; | |
339 } | |
340 | |
341 | |
573 | 342 void |
343 ngx_http_script_flush_no_cachable_variables(ngx_http_request_t *r, | |
344 ngx_array_t *indices) | |
345 { | |
346 ngx_uint_t n, *index; | |
347 | |
348 if (indices) { | |
349 index = indices->elts; | |
350 for (n = 0; n < indices->nelts; n++) { | |
351 if (r->variables[index[n]].no_cachable) { | |
352 r->variables[index[n]].valid = 0; | |
353 r->variables[index[n]].not_found = 0; | |
354 } | |
355 } | |
356 } | |
357 } | |
358 | |
359 | |
509 | 360 void * |
507 | 361 ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size) |
479 | 362 { |
507 | 363 if (*codes == NULL) { |
364 *codes = ngx_array_create(pool, 256, 1); | |
365 if (*codes == NULL) { | |
366 return NULL; | |
367 } | |
368 } | |
99
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
369 |
507 | 370 return ngx_array_push_n(*codes, size); |
371 } | |
372 | |
509 | 373 |
374 void * | |
375 ngx_http_script_add_code(ngx_array_t *codes, size_t size, void *code) | |
376 { | |
377 u_char *elts, **p; | |
378 void *new; | |
379 | |
380 elts = codes->elts; | |
381 | |
382 new = ngx_array_push_n(codes, size); | |
383 if (new == NULL) { | |
384 return NGX_CONF_ERROR; | |
385 } | |
386 | |
387 if (code) { | |
388 if (elts != codes->elts) { | |
389 p = code; | |
390 *p += (u_char *) codes->elts - elts; | |
391 } | |
392 } | |
393 | |
394 return new; | |
395 } | |
507 | 396 |
479 | 397 |
507 | 398 size_t |
509 | 399 ngx_http_script_copy_len_code(ngx_http_script_engine_t *e) |
507 | 400 { |
401 ngx_http_script_copy_code_t *code; | |
479 | 402 |
509 | 403 code = (ngx_http_script_copy_code_t *) e->ip; |
507 | 404 |
509 | 405 e->ip += sizeof(ngx_http_script_copy_code_t); |
507 | 406 |
407 return code->len; | |
99
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
408 } |
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
409 |
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
410 |
507 | 411 void |
509 | 412 ngx_http_script_copy_code(ngx_http_script_engine_t *e) |
99
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
413 { |
507 | 414 ngx_http_script_copy_code_t *code; |
415 | |
509 | 416 code = (ngx_http_script_copy_code_t *) e->ip; |
417 | |
418 if (!e->skip) { | |
573 | 419 e->pos = ngx_copy(e->pos, e->ip + sizeof(ngx_http_script_copy_code_t), |
420 code->len); | |
509 | 421 } |
507 | 422 |
509 | 423 e->ip += sizeof(ngx_http_script_copy_code_t) |
424 + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1)); | |
507 | 425 |
509 | 426 if (e->log) { |
427 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, | |
428 "http script copy: \"%V\"", &e->buf); | |
429 } | |
99
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
430 } |
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
431 |
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
432 |
507 | 433 size_t |
509 | 434 ngx_http_script_copy_var_len_code(ngx_http_script_engine_t *e) |
99
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
435 { |
507 | 436 ngx_http_variable_value_t *value; |
437 ngx_http_script_var_code_t *code; | |
438 | |
509 | 439 code = (ngx_http_script_var_code_t *) e->ip; |
507 | 440 |
509 | 441 e->ip += sizeof(ngx_http_script_var_code_t); |
507 | 442 |
573 | 443 if (e->flushed) { |
444 value = ngx_http_get_indexed_variable(e->request, code->index); | |
507 | 445 |
573 | 446 } else { |
447 value = ngx_http_get_flushed_variable(e->request, code->index); | |
448 } | |
449 | |
450 if (value && !value->not_found) { | |
451 return value->len; | |
507 | 452 } |
453 | |
553 | 454 return 0; |
99
a059e1aa65d4
nginx-0.0.1-2003-06-02-19:24:30 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
455 } |
479 | 456 |
457 | |
507 | 458 void |
509 | 459 ngx_http_script_copy_var_code(ngx_http_script_engine_t *e) |
479 | 460 { |
507 | 461 ngx_http_variable_value_t *value; |
462 ngx_http_script_var_code_t *code; | |
463 | |
509 | 464 code = (ngx_http_script_var_code_t *) e->ip; |
465 | |
466 e->ip += sizeof(ngx_http_script_var_code_t); | |
467 | |
468 if (!e->skip) { | |
573 | 469 |
470 if (e->flushed) { | |
471 value = ngx_http_get_indexed_variable(e->request, code->index); | |
509 | 472 |
573 | 473 } else { |
474 value = ngx_http_get_flushed_variable(e->request, code->index); | |
475 } | |
476 | |
477 if (value && !value->not_found) { | |
478 e->pos = ngx_copy(e->pos, value->data, value->len); | |
509 | 479 |
553 | 480 if (e->log) { |
481 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, | |
482 e->request->connection->log, 0, | |
483 "http script var: \"%V\"", &e->buf); | |
484 } | |
509 | 485 } |
486 } | |
487 } | |
488 | |
489 | |
490 size_t | |
491 ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e) | |
492 { | |
493 ngx_http_script_copy_capture_code_t *code; | |
494 | |
495 code = (ngx_http_script_copy_capture_code_t *) e->ip; | |
496 | |
497 e->ip += sizeof(ngx_http_script_copy_capture_code_t); | |
498 | |
515 | 499 if (code->n < e->ncaptures) { |
500 if ((e->args || e->quote) | |
501 && (e->request->quoted_uri || e->request->plus_in_uri)) | |
502 { | |
503 return e->captures[code->n + 1] - e->captures[code->n] | |
504 + ngx_escape_uri(NULL, | |
505 &e->line.data[e->captures[code->n]], | |
509 | 506 e->captures[code->n + 1] - e->captures[code->n], |
507 NGX_ESCAPE_ARGS); | |
515 | 508 } else { |
509 return e->captures[code->n + 1] - e->captures[code->n]; | |
510 } | |
509 | 511 } |
515 | 512 |
513 return 0; | |
509 | 514 } |
515 | |
516 | |
517 void | |
518 ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e) | |
519 { | |
520 ngx_http_script_copy_capture_code_t *code; | |
521 | |
522 code = (ngx_http_script_copy_capture_code_t *) e->ip; | |
523 | |
524 e->ip += sizeof(ngx_http_script_copy_capture_code_t); | |
507 | 525 |
515 | 526 if (code->n < e->ncaptures) { |
527 if ((e->args || e->quote) | |
528 && (e->request->quoted_uri || e->request->plus_in_uri)) | |
529 { | |
530 e->pos = (u_char *) ngx_escape_uri(e->pos, | |
531 &e->line.data[e->captures[code->n]], | |
509 | 532 e->captures[code->n + 1] - e->captures[code->n], |
533 NGX_ESCAPE_ARGS); | |
515 | 534 } else { |
573 | 535 e->pos = ngx_copy(e->pos, |
536 &e->line.data[e->captures[code->n]], | |
537 e->captures[code->n + 1] - e->captures[code->n]); | |
515 | 538 } |
509 | 539 } |
540 | |
541 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, | |
542 "http script capture: \"%V\"", &e->buf); | |
543 } | |
544 | |
545 | |
546 void | |
547 ngx_http_script_start_args_code(ngx_http_script_engine_t *e) | |
548 { | |
549 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, | |
550 "http script args"); | |
577 | 551 |
509 | 552 e->args = e->pos; |
553 e->ip += sizeof(uintptr_t); | |
554 } | |
555 | |
556 | |
517 | 557 |
558 #if (NGX_PCRE) | |
559 | |
509 | 560 void |
561 ngx_http_script_regex_start_code(ngx_http_script_engine_t *e) | |
562 { | |
563 size_t len; | |
564 ngx_int_t rc; | |
565 ngx_uint_t n; | |
566 ngx_http_request_t *r; | |
567 ngx_http_script_engine_t le; | |
568 ngx_http_script_len_code_pt lcode; | |
569 ngx_http_script_regex_code_t *code; | |
570 | |
571 code = (ngx_http_script_regex_code_t *) e->ip; | |
572 | |
573 r = e->request; | |
574 | |
575 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
576 "http script regex: \"%V\"", &code->name); | |
577 | |
578 if (code->uri) { | |
515 | 579 e->line = r->uri; |
509 | 580 } else { |
581 e->sp--; | |
573 | 582 e->line.len = e->sp->len; |
583 e->line.data = e->sp->data; | |
509 | 584 } |
507 | 585 |
515 | 586 rc = ngx_regex_exec(code->regex, &e->line, e->captures, code->ncaptures); |
509 | 587 |
588 if (rc == NGX_REGEX_NO_MATCHED) { | |
589 if (e->log) { | |
590 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, | |
515 | 591 "\"%V\" does not match \"%V\"", |
592 &code->name, &e->line); | |
509 | 593 } |
594 | |
515 | 595 e->ncaptures = 0; |
596 | |
509 | 597 if (code->test) { |
631 | 598 if (code->negative_test) { |
599 e->sp->len = 1; | |
600 e->sp->data = (u_char *) "1"; | |
601 | |
602 } else { | |
603 e->sp->len = 0; | |
604 e->sp->data = (u_char *) ""; | |
605 } | |
606 | |
509 | 607 e->sp++; |
608 | |
609 e->ip += sizeof(ngx_http_script_regex_code_t); | |
610 return; | |
611 } | |
612 | |
613 e->ip += code->next; | |
614 return; | |
615 } | |
616 | |
617 if (rc < 0) { | |
618 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
619 ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"", | |
515 | 620 rc, &e->line, &code->name); |
509 | 621 |
622 e->ip = ngx_http_script_exit; | |
623 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; | |
624 return; | |
625 } | |
626 | |
627 if (e->log) { | |
628 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, | |
515 | 629 "\"%V\" matches \"%V\"", &code->name, &e->line); |
509 | 630 } |
631 | |
515 | 632 e->ncaptures = code->ncaptures; |
633 | |
509 | 634 if (code->test) { |
631 | 635 if (code->negative_test) { |
636 e->sp->len = 0; | |
637 e->sp->data = (u_char *) ""; | |
638 | |
639 } else { | |
640 e->sp->len = 1; | |
641 e->sp->data = (u_char *) "1"; | |
642 } | |
643 | |
509 | 644 e->sp++; |
645 | |
646 e->ip += sizeof(ngx_http_script_regex_code_t); | |
647 return; | |
648 } | |
649 | |
650 if (code->status) { | |
651 e->status = code->status; | |
507 | 652 |
509 | 653 if (!code->redirect) { |
654 e->ip = ngx_http_script_exit; | |
655 return; | |
656 } | |
657 } | |
658 | |
659 if (code->uri) { | |
660 r->internal = 1; | |
661 r->valid_unparsed_uri = 0; | |
662 | |
663 if (code->break_cycle) { | |
664 r->valid_location = 0; | |
527 | 665 r->uri_changed = 0; |
509 | 666 |
667 } else { | |
668 r->uri_changed = 1; | |
669 } | |
670 } | |
671 | |
672 if (code->lengths == NULL) { | |
673 e->buf.len = code->size; | |
674 | |
675 if (code->uri) { | |
676 if (rc && (r->quoted_uri || r->plus_in_uri)) { | |
677 e->buf.len += 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, | |
678 NGX_ESCAPE_ARGS); | |
679 } | |
680 } | |
681 | |
682 for (n = 1; n < (ngx_uint_t) rc; n++) { | |
683 e->buf.len += e->captures[2 * n + 1] - e->captures[2 * n]; | |
684 } | |
685 | |
686 } else { | |
687 ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); | |
688 | |
689 le.ip = code->lengths->elts; | |
690 le.request = r; | |
691 le.captures = e->captures; | |
515 | 692 le.ncaptures = e->ncaptures; |
509 | 693 |
694 len = 1; /* reserve 1 byte for possible "?" */ | |
695 | |
696 while (*(uintptr_t *) le.ip) { | |
697 lcode = *(ngx_http_script_len_code_pt *) le.ip; | |
698 len += lcode(&le); | |
699 } | |
700 | |
701 e->buf.len = len; | |
702 } | |
703 | |
515 | 704 if (code->add_args && r->args.len) { |
509 | 705 e->buf.len += r->args.len + 1; |
706 } | |
707 | |
708 e->buf.data = ngx_palloc(r->pool, e->buf.len); | |
709 if (e->buf.data == NULL) { | |
710 e->ip = ngx_http_script_exit; | |
711 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; | |
507 | 712 return; |
713 } | |
714 | |
509 | 715 e->quote = code->redirect; |
716 | |
717 e->pos = e->buf.data; | |
718 | |
719 e->ip += sizeof(ngx_http_script_regex_code_t); | |
720 } | |
721 | |
722 | |
723 void | |
724 ngx_http_script_regex_end_code(ngx_http_script_engine_t *e) | |
725 { | |
577 | 726 u_char *dst, *src; |
509 | 727 ngx_http_request_t *r; |
728 ngx_http_script_regex_end_code_t *code; | |
729 | |
730 code = (ngx_http_script_regex_end_code_t *) e->ip; | |
731 | |
732 r = e->request; | |
733 | |
734 e->quote = 0; | |
735 | |
736 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
737 "http script regex end"); | |
738 | |
739 if (code->redirect) { | |
740 | |
577 | 741 dst = e->buf.data; |
742 src = e->buf.data; | |
743 | |
601 | 744 ngx_unescape_uri(&dst, &src, e->pos - e->buf.data, NGX_UNESCAPE_URI); |
577 | 745 |
746 if (src < e->pos) { | |
747 dst = ngx_copy(dst, src, e->pos - src); | |
748 } | |
749 | |
750 e->pos = dst; | |
751 | |
752 if (code->add_args && r->args.len) { | |
509 | 753 *e->pos++ = (u_char) (code->args ? '&' : '?'); |
573 | 754 e->pos = ngx_copy(e->pos, r->args.data, r->args.len); |
509 | 755 } |
756 | |
757 e->buf.len = e->pos - e->buf.data; | |
758 | |
759 if (e->log) { | |
760 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, | |
761 "rewritten redirect: \"%V\"", &e->buf); | |
762 } | |
763 | |
764 r->headers_out.location = ngx_list_push(&r->headers_out.headers); | |
765 if (r->headers_out.location == NULL) { | |
766 e->ip = ngx_http_script_exit; | |
767 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; | |
768 return; | |
769 } | |
770 | |
577 | 771 r->headers_out.location->hash = 1; |
509 | 772 r->headers_out.location->key.len = sizeof("Location") - 1; |
773 r->headers_out.location->key.data = (u_char *) "Location"; | |
774 r->headers_out.location->value = e->buf; | |
775 | |
776 e->ip += sizeof(ngx_http_script_regex_end_code_t); | |
777 return; | |
778 } | |
779 | |
577 | 780 if (e->args) { |
509 | 781 e->buf.len = e->args - e->buf.data; |
782 | |
783 if (code->add_args && r->args.len) { | |
784 *e->pos++ = '&'; | |
573 | 785 e->pos = ngx_copy(e->pos, r->args.data, r->args.len); |
509 | 786 } |
787 | |
788 r->args.len = e->pos - e->args; | |
789 r->args.data = e->args; | |
790 | |
791 e->args = NULL; | |
792 | |
793 } else { | |
794 e->buf.len = e->pos - e->buf.data; | |
795 } | |
796 | |
797 if (e->log) { | |
798 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, | |
799 "rewritten data: \"%V\", args: \"%V\"", | |
800 &e->buf, &r->args); | |
801 } | |
802 | |
803 if (code->uri) { | |
804 r->uri = e->buf; | |
805 | |
535 | 806 if (r->uri.len == 0) { |
807 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
808 "the rewritten URI has a zero length"); | |
809 e->ip = ngx_http_script_exit; | |
810 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; | |
811 return; | |
812 } | |
813 | |
509 | 814 if (ngx_http_set_exten(r) != NGX_OK) { |
815 e->ip = ngx_http_script_exit; | |
816 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; | |
817 return; | |
818 } | |
819 } | |
820 | |
821 e->ip += sizeof(ngx_http_script_regex_end_code_t); | |
822 } | |
823 | |
517 | 824 #endif |
825 | |
509 | 826 |
827 void | |
828 ngx_http_script_return_code(ngx_http_script_engine_t *e) | |
577 | 829 { |
509 | 830 ngx_http_script_return_code_t *code; |
577 | 831 |
509 | 832 code = (ngx_http_script_return_code_t *) e->ip; |
833 | |
834 e->status = code->status; | |
835 | |
836 e->ip += sizeof(ngx_http_script_return_code_t) - sizeof(uintptr_t); | |
479 | 837 } |
509 | 838 |
839 | |
840 void | |
527 | 841 ngx_http_script_break_code(ngx_http_script_engine_t *e) |
842 { | |
843 e->request->uri_changed = 0; | |
844 | |
845 e->ip = ngx_http_script_exit; | |
846 } | |
847 | |
848 | |
849 void | |
509 | 850 ngx_http_script_if_code(ngx_http_script_engine_t *e) |
851 { | |
852 ngx_http_script_if_code_t *code; | |
853 | |
854 code = (ngx_http_script_if_code_t *) e->ip; | |
855 | |
856 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, | |
857 "http script if"); | |
858 | |
859 e->sp--; | |
860 | |
573 | 861 if (e->sp->len && e->sp->data[0] != '0') { |
509 | 862 if (code->loc_conf) { |
863 e->request->loc_conf = code->loc_conf; | |
535 | 864 ngx_http_update_location_config(e->request); |
509 | 865 } |
866 | |
867 e->ip += sizeof(ngx_http_script_if_code_t); | |
868 return; | |
869 } | |
870 | |
871 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, | |
577 | 872 "http script if: false"); |
509 | 873 |
874 e->ip += code->next; | |
875 } | |
876 | |
877 | |
878 void | |
577 | 879 ngx_http_script_equal_code(ngx_http_script_engine_t *e) |
880 { | |
881 ngx_http_variable_value_t *val, *res; | |
882 | |
883 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, | |
884 "http script equal"); | |
885 | |
886 e->sp--; | |
887 val = e->sp; | |
888 res = e->sp - 1; | |
889 | |
890 e->ip += sizeof(uintptr_t); | |
891 | |
892 if (val->len == res->len && ngx_strncmp(val->data, res->data, res->len) | |
893 == 0) | |
894 { | |
895 *res = ngx_http_variable_true_value; | |
896 return; | |
897 } | |
898 | |
899 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, | |
900 "http script equal: no"); | |
901 | |
902 *res = ngx_http_variable_null_value; | |
903 } | |
904 | |
905 | |
906 void | |
907 ngx_http_script_not_equal_code(ngx_http_script_engine_t *e) | |
908 { | |
909 ngx_http_variable_value_t *val, *res; | |
910 | |
911 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, | |
912 "http script not equal"); | |
913 | |
914 e->sp--; | |
915 val = e->sp; | |
916 res = e->sp - 1; | |
917 | |
918 e->ip += sizeof(uintptr_t); | |
919 | |
920 if (val->len == res->len && ngx_strncmp(val->data, res->data, res->len) | |
921 == 0) | |
922 { | |
923 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, | |
924 "http script not equal: no"); | |
925 | |
926 *res = ngx_http_variable_null_value; | |
927 return; | |
928 } | |
929 | |
930 *res = ngx_http_variable_true_value; | |
931 } | |
932 | |
933 | |
934 void | |
631 | 935 ngx_http_script_file_code(ngx_http_script_engine_t *e) |
936 { | |
937 ngx_err_t err; | |
938 ngx_file_info_t fi; | |
939 ngx_http_variable_value_t *value; | |
940 ngx_http_script_file_code_t *code; | |
941 | |
942 value = e->sp - 1; | |
943 | |
944 code = (ngx_http_script_file_code_t *) e->ip; | |
945 e->ip += sizeof(ngx_http_script_file_code_t); | |
946 | |
947 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, | |
948 "http script file op %p", code->op); | |
949 | |
950 if (ngx_file_info(value->data, &fi) == -1) { | |
951 err = ngx_errno; | |
952 | |
953 if (err != NGX_ENOENT && err != NGX_ENOTDIR) { | |
954 ngx_log_error(NGX_LOG_CRIT, e->request->connection->log, err, | |
955 ngx_file_info_n " \"%s\" failed", value->data); | |
956 } | |
957 | |
958 switch (code->op) { | |
959 case ngx_http_script_file_plain: | |
960 goto false; | |
961 case ngx_http_script_file_not_plain: | |
962 goto true; | |
963 } | |
964 | |
965 goto false; | |
966 } | |
967 | |
968 switch (code->op) { | |
969 case ngx_http_script_file_plain: | |
970 if (ngx_is_file(&fi)) { | |
971 goto true; | |
972 } | |
973 goto false; | |
974 | |
975 case ngx_http_script_file_not_plain: | |
976 if (ngx_is_file(&fi)) { | |
977 goto false; | |
978 } | |
979 goto true; | |
980 } | |
981 | |
982 false: | |
983 | |
984 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, | |
985 "http script file op false"); | |
986 | |
987 *value = ngx_http_variable_null_value; | |
988 return; | |
989 | |
990 true: | |
991 | |
992 *value = ngx_http_variable_true_value; | |
993 return; | |
994 } | |
995 | |
996 | |
997 void | |
515 | 998 ngx_http_script_complex_value_code(ngx_http_script_engine_t *e) |
999 { | |
1000 size_t len; | |
1001 ngx_http_script_engine_t le; | |
1002 ngx_http_script_len_code_pt lcode; | |
1003 ngx_http_script_complex_value_code_t *code; | |
1004 | |
1005 code = (ngx_http_script_complex_value_code_t *) e->ip; | |
1006 | |
1007 e->ip += sizeof(ngx_http_script_complex_value_code_t); | |
1008 | |
1009 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, | |
1010 "http script complex value"); | |
1011 | |
1012 ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); | |
1013 | |
1014 le.ip = code->lengths->elts; | |
1015 le.request = e->request; | |
1016 le.captures = e->captures; | |
1017 le.ncaptures = e->ncaptures; | |
1018 | |
1019 for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) { | |
1020 lcode = *(ngx_http_script_len_code_pt *) le.ip; | |
1021 } | |
1022 | |
1023 e->buf.len = len; | |
1024 e->buf.data = ngx_palloc(e->request->pool, len); | |
1025 if (e->buf.data == NULL) { | |
1026 e->ip = ngx_http_script_exit; | |
1027 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; | |
1028 return; | |
1029 } | |
1030 | |
1031 e->pos = e->buf.data; | |
1032 | |
577 | 1033 e->sp->len = e->buf.len; |
573 | 1034 e->sp->data = e->buf.data; |
515 | 1035 e->sp++; |
1036 } | |
1037 | |
1038 | |
1039 void | |
509 | 1040 ngx_http_script_value_code(ngx_http_script_engine_t *e) |
1041 { | |
1042 ngx_http_script_value_code_t *code; | |
1043 | |
1044 code = (ngx_http_script_value_code_t *) e->ip; | |
1045 | |
1046 e->ip += sizeof(ngx_http_script_value_code_t); | |
1047 | |
573 | 1048 e->sp->len = code->text_len; |
1049 e->sp->data = (u_char *) code->text_data; | |
577 | 1050 |
1051 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, | |
1052 "http script value: \"%V\"", e->sp); | |
1053 | |
509 | 1054 e->sp++; |
1055 } | |
1056 | |
1057 | |
1058 void | |
1059 ngx_http_script_set_var_code(ngx_http_script_engine_t *e) | |
1060 { | |
1061 ngx_http_request_t *r; | |
1062 ngx_http_script_var_code_t *code; | |
1063 | |
1064 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, | |
1065 "http script set var"); | |
1066 | |
1067 code = (ngx_http_script_var_code_t *) e->ip; | |
1068 | |
1069 e->ip += sizeof(ngx_http_script_var_code_t); | |
1070 | |
1071 r = e->request; | |
1072 | |
1073 e->sp--; | |
1074 | |
573 | 1075 r->variables[code->index].len = e->sp->len; |
1076 r->variables[code->index].valid = 1; | |
1077 r->variables[code->index].no_cachable = 0; | |
1078 r->variables[code->index].not_found = 0; | |
1079 r->variables[code->index].data = e->sp->data; | |
509 | 1080 } |
1081 | |
1082 | |
1083 void | |
637 | 1084 ngx_http_script_var_set_handler_code(ngx_http_script_engine_t *e) |
1085 { | |
1086 ngx_http_script_var_handler_code_t *code; | |
1087 | |
1088 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, | |
1089 "http script set var handler"); | |
1090 | |
1091 code = (ngx_http_script_var_handler_code_t *) e->ip; | |
1092 | |
1093 e->ip += sizeof(ngx_http_script_var_handler_code_t); | |
1094 | |
1095 e->sp--; | |
1096 | |
1097 code->handler(e->request, e->sp, code->data); | |
1098 } | |
1099 | |
1100 | |
1101 void | |
509 | 1102 ngx_http_script_var_code(ngx_http_script_engine_t *e) |
1103 { | |
1104 ngx_http_variable_value_t *value; | |
1105 ngx_http_script_var_code_t *code; | |
1106 | |
1107 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, | |
1108 "http script var"); | |
1109 | |
1110 code = (ngx_http_script_var_code_t *) e->ip; | |
1111 | |
1112 e->ip += sizeof(ngx_http_script_var_code_t); | |
1113 | |
573 | 1114 value = ngx_http_get_flushed_variable(e->request, code->index); |
509 | 1115 |
573 | 1116 if (value && !value->not_found) { |
1117 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, | |
1118 "http script var: \"%V\"", value); | |
1119 | |
553 | 1120 *e->sp = *value; |
509 | 1121 e->sp++; |
1122 | |
1123 return; | |
1124 } | |
1125 | |
577 | 1126 *e->sp = ngx_http_variable_null_value; |
509 | 1127 e->sp++; |
1128 } | |
1129 | |
1130 | |
1131 void | |
1132 ngx_http_script_nop_code(ngx_http_script_engine_t *e) | |
1133 { | |
1134 e->ip += sizeof(uintptr_t); | |
1135 } |