1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11
12
13 static ngx_int_t ngx_http_script_init_arrays(ngx_http_script_compile_t *sc);
14 static ngx_int_t ngx_http_script_done(ngx_http_script_compile_t *sc);
15 static ngx_int_t ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc,
16 ngx_str_t *value, ngx_uint_t last);
17 static ngx_int_t ngx_http_script_add_var_code(ngx_http_script_compile_t *sc,
18 ngx_str_t *name);
19 static ngx_int_t ngx_http_script_add_args_code(ngx_http_script_compile_t *sc);
20 #if (NGX_PCRE)
21 static ngx_int_t ngx_http_script_add_capture_code(ngx_http_script_compile_t *sc,
22 ngx_uint_t n);
23 #endif
24 static ngx_int_t
25 ngx_http_script_add_full_name_code(ngx_http_script_compile_t *sc);
26 static size_t ngx_http_script_full_name_len_code(ngx_http_script_engine_t *e);
27 static void ngx_http_script_full_name_code(ngx_http_script_engine_t *e);
28
29
30 #define ngx_http_script_exit (u_char *) &ngx_http_script_exit_code
31
32 static uintptr_t ngx_http_script_exit_code = (uintptr_t) NULL;
33
34
35 void
ngx_http_script_flush_complex_value(ngx_http_request_t * r,ngx_http_complex_value_t * val)36 ngx_http_script_flush_complex_value(ngx_http_request_t *r,
37 ngx_http_complex_value_t *val)
38 {
39 ngx_uint_t *index;
40
41 index = val->flushes;
42
43 if (index) {
44 while (*index != (ngx_uint_t) -1) {
45
46 if (r->variables[*index].no_cacheable) {
47 r->variables[*index].valid = 0;
48 r->variables[*index].not_found = 0;
49 }
50
51 index++;
52 }
53 }
54 }
55
56
57 ngx_int_t
ngx_http_complex_value(ngx_http_request_t * r,ngx_http_complex_value_t * val,ngx_str_t * value)58 ngx_http_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val,
59 ngx_str_t *value)
60 {
61 size_t len;
62 ngx_http_script_code_pt code;
63 ngx_http_script_len_code_pt lcode;
64 ngx_http_script_engine_t e;
65
66 if (val->lengths == NULL) {
67 *value = val->value;
68 return NGX_OK;
69 }
70
71 ngx_http_script_flush_complex_value(r, val);
72
73 ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
74
75 e.ip = val->lengths;
76 e.request = r;
77 e.flushed = 1;
78
79 len = 0;
80
81 while (*(uintptr_t *) e.ip) {
82 lcode = *(ngx_http_script_len_code_pt *) e.ip;
83 len += lcode(&e);
84 }
85
86 value->len = len;
87 value->data = ngx_pnalloc(r->pool, len);
88 if (value->data == NULL) {
89 return NGX_ERROR;
90 }
91
92 e.ip = val->values;
93 e.pos = value->data;
94 e.buf = *value;
95
96 while (*(uintptr_t *) e.ip) {
97 code = *(ngx_http_script_code_pt *) e.ip;
98 code((ngx_http_script_engine_t *) &e);
99 }
100
101 *value = e.buf;
102
103 return NGX_OK;
104 }
105
106
107 size_t
ngx_http_complex_value_size(ngx_http_request_t * r,ngx_http_complex_value_t * val,size_t default_value)108 ngx_http_complex_value_size(ngx_http_request_t *r,
109 ngx_http_complex_value_t *val, size_t default_value)
110 {
111 size_t size;
112 ngx_str_t value;
113
114 if (val == NULL) {
115 return default_value;
116 }
117
118 if (val->lengths == NULL) {
119 return val->u.size;
120 }
121
122 if (ngx_http_complex_value(r, val, &value) != NGX_OK) {
123 return default_value;
124 }
125
126 size = ngx_parse_size(&value);
127
128 if (size == (size_t) NGX_ERROR) {
129 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
130 "invalid size \"%V\"", &value);
131 return default_value;
132 }
133
134 return size;
135 }
136
137
138 ngx_int_t
ngx_http_compile_complex_value(ngx_http_compile_complex_value_t * ccv)139 ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv)
140 {
141 ngx_str_t *v;
142 ngx_uint_t i, n, nv, nc;
143 ngx_array_t flushes, lengths, values, *pf, *pl, *pv;
144 ngx_http_script_compile_t sc;
145
146 v = ccv->value;
147
148 nv = 0;
149 nc = 0;
150
151 for (i = 0; i < v->len; i++) {
152 if (v->data[i] == '$') {
153 if (v->data[i + 1] >= '1' && v->data[i + 1] <= '9') {
154 nc++;
155
156 } else {
157 nv++;
158 }
159 }
160 }
161
162 if ((v->len == 0 || v->data[0] != '$')
163 && (ccv->conf_prefix || ccv->root_prefix))
164 {
165 if (ngx_conf_full_name(ccv->cf->cycle, v, ccv->conf_prefix) != NGX_OK) {
166 return NGX_ERROR;
167 }
168
169 ccv->conf_prefix = 0;
170 ccv->root_prefix = 0;
171 }
172
173 ccv->complex_value->value = *v;
174 ccv->complex_value->flushes = NULL;
175 ccv->complex_value->lengths = NULL;
176 ccv->complex_value->values = NULL;
177
178 if (nv == 0 && nc == 0) {
179 return NGX_OK;
180 }
181
182 n = nv + 1;
183
184 if (ngx_array_init(&flushes, ccv->cf->pool, n, sizeof(ngx_uint_t))
185 != NGX_OK)
186 {
187 return NGX_ERROR;
188 }
189
190 n = nv * (2 * sizeof(ngx_http_script_copy_code_t)
191 + sizeof(ngx_http_script_var_code_t))
192 + sizeof(uintptr_t);
193
194 if (ngx_array_init(&lengths, ccv->cf->pool, n, 1) != NGX_OK) {
195 return NGX_ERROR;
196 }
197
198 n = (nv * (2 * sizeof(ngx_http_script_copy_code_t)
199 + sizeof(ngx_http_script_var_code_t))
200 + sizeof(uintptr_t)
201 + v->len
202 + sizeof(uintptr_t) - 1)
203 & ~(sizeof(uintptr_t) - 1);
204
205 if (ngx_array_init(&values, ccv->cf->pool, n, 1) != NGX_OK) {
206 return NGX_ERROR;
207 }
208
209 pf = &flushes;
210 pl = &lengths;
211 pv = &values;
212
213 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
214
215 sc.cf = ccv->cf;
216 sc.source = v;
217 sc.flushes = &pf;
218 sc.lengths = &pl;
219 sc.values = &pv;
220 sc.complete_lengths = 1;
221 sc.complete_values = 1;
222 sc.zero = ccv->zero;
223 sc.conf_prefix = ccv->conf_prefix;
224 sc.root_prefix = ccv->root_prefix;
225
226 if (ngx_http_script_compile(&sc) != NGX_OK) {
227 return NGX_ERROR;
228 }
229
230 if (flushes.nelts) {
231 ccv->complex_value->flushes = flushes.elts;
232 ccv->complex_value->flushes[flushes.nelts] = (ngx_uint_t) -1;
233 }
234
235 ccv->complex_value->lengths = lengths.elts;
236 ccv->complex_value->values = values.elts;
237
238 return NGX_OK;
239 }
240
241
242 char *
ngx_http_set_complex_value_slot(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)243 ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
244 {
245 char *p = conf;
246
247 ngx_str_t *value;
248 ngx_http_complex_value_t **cv;
249 ngx_http_compile_complex_value_t ccv;
250
251 cv = (ngx_http_complex_value_t **) (p + cmd->offset);
252
253 if (*cv != NULL) {
254 return "is duplicate";
255 }
256
257 *cv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
258 if (*cv == NULL) {
259 return NGX_CONF_ERROR;
260 }
261
262 value = cf->args->elts;
263
264 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
265
266 ccv.cf = cf;
267 ccv.value = &value[1];
268 ccv.complex_value = *cv;
269
270 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
271 return NGX_CONF_ERROR;
272 }
273
274 return NGX_CONF_OK;
275 }
276
277
278 char *
ngx_http_set_complex_value_size_slot(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)279 ngx_http_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd,
280 void *conf)
281 {
282 char *p = conf;
283
284 char *rv;
285 ngx_http_complex_value_t *cv;
286
287 rv = ngx_http_set_complex_value_slot(cf, cmd, conf);
288
289 if (rv != NGX_CONF_OK) {
290 return rv;
291 }
292
293 cv = *(ngx_http_complex_value_t **) (p + cmd->offset);
294
295 if (cv->lengths) {
296 return NGX_CONF_OK;
297 }
298
299 cv->u.size = ngx_parse_size(&cv->value);
300 if (cv->u.size == (size_t) NGX_ERROR) {
301 return "invalid value";
302 }
303
304 return NGX_CONF_OK;
305 }
306
307
308 ngx_int_t
ngx_http_test_predicates(ngx_http_request_t * r,ngx_array_t * predicates)309 ngx_http_test_predicates(ngx_http_request_t *r, ngx_array_t *predicates)
310 {
311 ngx_str_t val;
312 ngx_uint_t i;
313 ngx_http_complex_value_t *cv;
314
315 if (predicates == NULL) {
316 return NGX_OK;
317 }
318
319 cv = predicates->elts;
320
321 for (i = 0; i < predicates->nelts; i++) {
322 if (ngx_http_complex_value(r, &cv[i], &val) != NGX_OK) {
323 return NGX_ERROR;
324 }
325
326 if (val.len && (val.len != 1 || val.data[0] != '0')) {
327 return NGX_DECLINED;
328 }
329 }
330
331 return NGX_OK;
332 }
333
334
335 ngx_int_t
ngx_http_test_required_predicates(ngx_http_request_t * r,ngx_array_t * predicates)336 ngx_http_test_required_predicates(ngx_http_request_t *r,
337 ngx_array_t *predicates)
338 {
339 ngx_str_t val;
340 ngx_uint_t i;
341 ngx_http_complex_value_t *cv;
342
343 if (predicates == NULL) {
344 return NGX_OK;
345 }
346
347 cv = predicates->elts;
348
349 for (i = 0; i < predicates->nelts; i++) {
350 if (ngx_http_complex_value(r, &cv[i], &val) != NGX_OK) {
351 return NGX_ERROR;
352 }
353
354 if (val.len == 0 || (val.len == 1 && val.data[0] == '0')) {
355 return NGX_DECLINED;
356 }
357 }
358
359 return NGX_OK;
360 }
361
362
363 char *
ngx_http_set_predicate_slot(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)364 ngx_http_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
365 {
366 char *p = conf;
367
368 ngx_str_t *value;
369 ngx_uint_t i;
370 ngx_array_t **a;
371 ngx_http_complex_value_t *cv;
372 ngx_http_compile_complex_value_t ccv;
373
374 a = (ngx_array_t **) (p + cmd->offset);
375
376 if (*a == NGX_CONF_UNSET_PTR) {
377 *a = ngx_array_create(cf->pool, 1, sizeof(ngx_http_complex_value_t));
378 if (*a == NULL) {
379 return NGX_CONF_ERROR;
380 }
381 }
382
383 value = cf->args->elts;
384
385 for (i = 1; i < cf->args->nelts; i++) {
386 cv = ngx_array_push(*a);
387 if (cv == NULL) {
388 return NGX_CONF_ERROR;
389 }
390
391 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
392
393 ccv.cf = cf;
394 ccv.value = &value[i];
395 ccv.complex_value = cv;
396
397 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
398 return NGX_CONF_ERROR;
399 }
400 }
401
402 return NGX_CONF_OK;
403 }
404
405
406 ngx_uint_t
ngx_http_script_variables_count(ngx_str_t * value)407 ngx_http_script_variables_count(ngx_str_t *value)
408 {
409 ngx_uint_t i, n;
410
411 for (n = 0, i = 0; i < value->len; i++) {
412 if (value->data[i] == '$') {
413 n++;
414 }
415 }
416
417 return n;
418 }
419
420
421 ngx_int_t
ngx_http_script_compile(ngx_http_script_compile_t * sc)422 ngx_http_script_compile(ngx_http_script_compile_t *sc)
423 {
424 u_char ch;
425 ngx_str_t name;
426 ngx_uint_t i, bracket;
427
428 if (ngx_http_script_init_arrays(sc) != NGX_OK) {
429 return NGX_ERROR;
430 }
431
432 for (i = 0; i < sc->source->len; /* void */ ) {
433
434 name.len = 0;
435
436 if (sc->source->data[i] == '$') {
437
438 if (++i == sc->source->len) {
439 goto invalid_variable;
440 }
441
442 if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') {
443 #if (NGX_PCRE)
444 ngx_uint_t n;
445
446 n = sc->source->data[i] - '0';
447
448 if (sc->captures_mask & ((ngx_uint_t) 1 << n)) {
449 sc->dup_capture = 1;
450 }
451
452 sc->captures_mask |= (ngx_uint_t) 1 << n;
453
454 if (ngx_http_script_add_capture_code(sc, n) != NGX_OK) {
455 return NGX_ERROR;
456 }
457
458 i++;
459
460 continue;
461 #else
462 ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0,
463 "using variable \"$%c\" requires "
464 "PCRE library", sc->source->data[i]);
465 return NGX_ERROR;
466 #endif
467 }
468
469 if (sc->source->data[i] == '{') {
470 bracket = 1;
471
472 if (++i == sc->source->len) {
473 goto invalid_variable;
474 }
475
476 name.data = &sc->source->data[i];
477
478 } else {
479 bracket = 0;
480 name.data = &sc->source->data[i];
481 }
482
483 for ( /* void */ ; i < sc->source->len; i++, name.len++) {
484 ch = sc->source->data[i];
485
486 if (ch == '}' && bracket) {
487 i++;
488 bracket = 0;
489 break;
490 }
491
492 if ((ch >= 'A' && ch <= 'Z')
493 || (ch >= 'a' && ch <= 'z')
494 || (ch >= '0' && ch <= '9')
495 || ch == '_')
496 {
497 continue;
498 }
499
500 break;
501 }
502
503 if (bracket) {
504 ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0,
505 "the closing bracket in \"%V\" "
506 "variable is missing", &name);
507 return NGX_ERROR;
508 }
509
510 if (name.len == 0) {
511 goto invalid_variable;
512 }
513
514 sc->variables++;
515
516 if (ngx_http_script_add_var_code(sc, &name) != NGX_OK) {
517 return NGX_ERROR;
518 }
519
520 continue;
521 }
522
523 if (sc->source->data[i] == '?' && sc->compile_args) {
524 sc->args = 1;
525 sc->compile_args = 0;
526
527 if (ngx_http_script_add_args_code(sc) != NGX_OK) {
528 return NGX_ERROR;
529 }
530
531 i++;
532
533 continue;
534 }
535
536 name.data = &sc->source->data[i];
537
538 while (i < sc->source->len) {
539
540 if (sc->source->data[i] == '$') {
541 break;
542 }
543
544 if (sc->source->data[i] == '?') {
545
546 sc->args = 1;
547
548 if (sc->compile_args) {
549 break;
550 }
551 }
552
553 i++;
554 name.len++;
555 }
556
557 sc->size += name.len;
558
559 if (ngx_http_script_add_copy_code(sc, &name, (i == sc->source->len))
560 != NGX_OK)
561 {
562 return NGX_ERROR;
563 }
564 }
565
566 return ngx_http_script_done(sc);
567
568 invalid_variable:
569
570 ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, "invalid variable name");
571
572 return NGX_ERROR;
573 }
574
575
576 u_char *
ngx_http_script_run(ngx_http_request_t * r,ngx_str_t * value,void * code_lengths,size_t len,void * code_values)577 ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value,
578 void *code_lengths, size_t len, void *code_values)
579 {
580 ngx_uint_t i;
581 ngx_http_script_code_pt code;
582 ngx_http_script_len_code_pt lcode;
583 ngx_http_script_engine_t e;
584 ngx_http_core_main_conf_t *cmcf;
585
586 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
587
588 for (i = 0; i < cmcf->variables.nelts; i++) {
589 if (r->variables[i].no_cacheable) {
590 r->variables[i].valid = 0;
591 r->variables[i].not_found = 0;
592 }
593 }
594
595 ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
596
597 e.ip = code_lengths;
598 e.request = r;
599 e.flushed = 1;
600
601 while (*(uintptr_t *) e.ip) {
602 lcode = *(ngx_http_script_len_code_pt *) e.ip;
603 len += lcode(&e);
604 }
605
606
607 value->len = len;
608 value->data = ngx_pnalloc(r->pool, len);
609 if (value->data == NULL) {
610 return NULL;
611 }
612
613 e.ip = code_values;
614 e.pos = value->data;
615
616 while (*(uintptr_t *) e.ip) {
617 code = *(ngx_http_script_code_pt *) e.ip;
618 code((ngx_http_script_engine_t *) &e);
619 }
620
621 return e.pos;
622 }
623
624
625 void
ngx_http_script_flush_no_cacheable_variables(ngx_http_request_t * r,ngx_array_t * indices)626 ngx_http_script_flush_no_cacheable_variables(ngx_http_request_t *r,
627 ngx_array_t *indices)
628 {
629 ngx_uint_t n, *index;
630
631 if (indices) {
632 index = indices->elts;
633 for (n = 0; n < indices->nelts; n++) {
634 if (r->variables[index[n]].no_cacheable) {
635 r->variables[index[n]].valid = 0;
636 r->variables[index[n]].not_found = 0;
637 }
638 }
639 }
640 }
641
642
643 static ngx_int_t
ngx_http_script_init_arrays(ngx_http_script_compile_t * sc)644 ngx_http_script_init_arrays(ngx_http_script_compile_t *sc)
645 {
646 ngx_uint_t n;
647
648 if (sc->flushes && *sc->flushes == NULL) {
649 n = sc->variables ? sc->variables : 1;
650 *sc->flushes = ngx_array_create(sc->cf->pool, n, sizeof(ngx_uint_t));
651 if (*sc->flushes == NULL) {
652 return NGX_ERROR;
653 }
654 }
655
656 if (*sc->lengths == NULL) {
657 n = sc->variables * (2 * sizeof(ngx_http_script_copy_code_t)
658 + sizeof(ngx_http_script_var_code_t))
659 + sizeof(uintptr_t);
660
661 *sc->lengths = ngx_array_create(sc->cf->pool, n, 1);
662 if (*sc->lengths == NULL) {
663 return NGX_ERROR;
664 }
665 }
666
667 if (*sc->values == NULL) {
668 n = (sc->variables * (2 * sizeof(ngx_http_script_copy_code_t)
669 + sizeof(ngx_http_script_var_code_t))
670 + sizeof(uintptr_t)
671 + sc->source->len
672 + sizeof(uintptr_t) - 1)
673 & ~(sizeof(uintptr_t) - 1);
674
675 *sc->values = ngx_array_create(sc->cf->pool, n, 1);
676 if (*sc->values == NULL) {
677 return NGX_ERROR;
678 }
679 }
680
681 sc->variables = 0;
682
683 return NGX_OK;
684 }
685
686
687 static ngx_int_t
ngx_http_script_done(ngx_http_script_compile_t * sc)688 ngx_http_script_done(ngx_http_script_compile_t *sc)
689 {
690 ngx_str_t zero;
691 uintptr_t *code;
692
693 if (sc->zero) {
694
695 zero.len = 1;
696 zero.data = (u_char *) "\0";
697
698 if (ngx_http_script_add_copy_code(sc, &zero, 0) != NGX_OK) {
699 return NGX_ERROR;
700 }
701 }
702
703 if (sc->conf_prefix || sc->root_prefix) {
704 if (ngx_http_script_add_full_name_code(sc) != NGX_OK) {
705 return NGX_ERROR;
706 }
707 }
708
709 if (sc->complete_lengths) {
710 code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL);
711 if (code == NULL) {
712 return NGX_ERROR;
713 }
714
715 *code = (uintptr_t) NULL;
716 }
717
718 if (sc->complete_values) {
719 code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t),
720 &sc->main);
721 if (code == NULL) {
722 return NGX_ERROR;
723 }
724
725 *code = (uintptr_t) NULL;
726 }
727
728 return NGX_OK;
729 }
730
731
732 void *
ngx_http_script_start_code(ngx_pool_t * pool,ngx_array_t ** codes,size_t size)733 ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size)
734 {
735 if (*codes == NULL) {
736 *codes = ngx_array_create(pool, 256, 1);
737 if (*codes == NULL) {
738 return NULL;
739 }
740 }
741
742 return ngx_array_push_n(*codes, size);
743 }
744
745
746 void *
ngx_http_script_add_code(ngx_array_t * codes,size_t size,void * code)747 ngx_http_script_add_code(ngx_array_t *codes, size_t size, void *code)
748 {
749 u_char *elts, **p;
750 void *new;
751
752 elts = codes->elts;
753
754 new = ngx_array_push_n(codes, size);
755 if (new == NULL) {
756 return NULL;
757 }
758
759 if (code) {
760 if (elts != codes->elts) {
761 p = code;
762 *p += (u_char *) codes->elts - elts;
763 }
764 }
765
766 return new;
767 }
768
769
770 static ngx_int_t
ngx_http_script_add_copy_code(ngx_http_script_compile_t * sc,ngx_str_t * value,ngx_uint_t last)771 ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc, ngx_str_t *value,
772 ngx_uint_t last)
773 {
774 u_char *p;
775 size_t size, len, zero;
776 ngx_http_script_copy_code_t *code;
777
778 zero = (sc->zero && last);
779 len = value->len + zero;
780
781 code = ngx_http_script_add_code(*sc->lengths,
782 sizeof(ngx_http_script_copy_code_t), NULL);
783 if (code == NULL) {
784 return NGX_ERROR;
785 }
786
787 code->code = (ngx_http_script_code_pt) (void *)
788 ngx_http_script_copy_len_code;
789 code->len = len;
790
791 size = (sizeof(ngx_http_script_copy_code_t) + len + sizeof(uintptr_t) - 1)
792 & ~(sizeof(uintptr_t) - 1);
793
794 code = ngx_http_script_add_code(*sc->values, size, &sc->main);
795 if (code == NULL) {
796 return NGX_ERROR;
797 }
798
799 code->code = ngx_http_script_copy_code;
800 code->len = len;
801
802 p = ngx_cpymem((u_char *) code + sizeof(ngx_http_script_copy_code_t),
803 value->data, value->len);
804
805 if (zero) {
806 *p = '\0';
807 sc->zero = 0;
808 }
809
810 return NGX_OK;
811 }
812
813
814 size_t
ngx_http_script_copy_len_code(ngx_http_script_engine_t * e)815 ngx_http_script_copy_len_code(ngx_http_script_engine_t *e)
816 {
817 ngx_http_script_copy_code_t *code;
818
819 code = (ngx_http_script_copy_code_t *) e->ip;
820
821 e->ip += sizeof(ngx_http_script_copy_code_t);
822
823 return code->len;
824 }
825
826
827 void
ngx_http_script_copy_code(ngx_http_script_engine_t * e)828 ngx_http_script_copy_code(ngx_http_script_engine_t *e)
829 {
830 u_char *p;
831 ngx_http_script_copy_code_t *code;
832
833 code = (ngx_http_script_copy_code_t *) e->ip;
834
835 p = e->pos;
836
837 if (!e->skip) {
838 e->pos = ngx_copy(p, e->ip + sizeof(ngx_http_script_copy_code_t),
839 code->len);
840 }
841
842 e->ip += sizeof(ngx_http_script_copy_code_t)
843 + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));
844
845 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
846 "http script copy: \"%*s\"", e->pos - p, p);
847 }
848
849
850 static ngx_int_t
ngx_http_script_add_var_code(ngx_http_script_compile_t * sc,ngx_str_t * name)851 ngx_http_script_add_var_code(ngx_http_script_compile_t *sc, ngx_str_t *name)
852 {
853 ngx_int_t index, *p;
854 ngx_http_script_var_code_t *code;
855
856 index = ngx_http_get_variable_index(sc->cf, name);
857
858 if (index == NGX_ERROR) {
859 return NGX_ERROR;
860 }
861
862 if (sc->flushes) {
863 p = ngx_array_push(*sc->flushes);
864 if (p == NULL) {
865 return NGX_ERROR;
866 }
867
868 *p = index;
869 }
870
871 code = ngx_http_script_add_code(*sc->lengths,
872 sizeof(ngx_http_script_var_code_t), NULL);
873 if (code == NULL) {
874 return NGX_ERROR;
875 }
876
877 code->code = (ngx_http_script_code_pt) (void *)
878 ngx_http_script_copy_var_len_code;
879 code->index = (uintptr_t) index;
880
881 code = ngx_http_script_add_code(*sc->values,
882 sizeof(ngx_http_script_var_code_t),
883 &sc->main);
884 if (code == NULL) {
885 return NGX_ERROR;
886 }
887
888 code->code = ngx_http_script_copy_var_code;
889 code->index = (uintptr_t) index;
890
891 return NGX_OK;
892 }
893
894
895 size_t
ngx_http_script_copy_var_len_code(ngx_http_script_engine_t * e)896 ngx_http_script_copy_var_len_code(ngx_http_script_engine_t *e)
897 {
898 ngx_http_variable_value_t *value;
899 ngx_http_script_var_code_t *code;
900
901 code = (ngx_http_script_var_code_t *) e->ip;
902
903 e->ip += sizeof(ngx_http_script_var_code_t);
904
905 if (e->flushed) {
906 value = ngx_http_get_indexed_variable(e->request, code->index);
907
908 } else {
909 value = ngx_http_get_flushed_variable(e->request, code->index);
910 }
911
912 if (value && !value->not_found) {
913 return value->len;
914 }
915
916 return 0;
917 }
918
919
920 void
ngx_http_script_copy_var_code(ngx_http_script_engine_t * e)921 ngx_http_script_copy_var_code(ngx_http_script_engine_t *e)
922 {
923 u_char *p;
924 ngx_http_variable_value_t *value;
925 ngx_http_script_var_code_t *code;
926
927 code = (ngx_http_script_var_code_t *) e->ip;
928
929 e->ip += sizeof(ngx_http_script_var_code_t);
930
931 if (!e->skip) {
932
933 if (e->flushed) {
934 value = ngx_http_get_indexed_variable(e->request, code->index);
935
936 } else {
937 value = ngx_http_get_flushed_variable(e->request, code->index);
938 }
939
940 if (value && !value->not_found) {
941 p = e->pos;
942 e->pos = ngx_copy(p, value->data, value->len);
943
944 ngx_log_debug2(NGX_LOG_DEBUG_HTTP,
945 e->request->connection->log, 0,
946 "http script var: \"%*s\"", e->pos - p, p);
947 }
948 }
949 }
950
951
952 static ngx_int_t
ngx_http_script_add_args_code(ngx_http_script_compile_t * sc)953 ngx_http_script_add_args_code(ngx_http_script_compile_t *sc)
954 {
955 uintptr_t *code;
956
957 code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL);
958 if (code == NULL) {
959 return NGX_ERROR;
960 }
961
962 *code = (uintptr_t) ngx_http_script_mark_args_code;
963
964 code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t), &sc->main);
965 if (code == NULL) {
966 return NGX_ERROR;
967 }
968
969 *code = (uintptr_t) ngx_http_script_start_args_code;
970
971 return NGX_OK;
972 }
973
974
975 size_t
ngx_http_script_mark_args_code(ngx_http_script_engine_t * e)976 ngx_http_script_mark_args_code(ngx_http_script_engine_t *e)
977 {
978 e->is_args = 1;
979 e->ip += sizeof(uintptr_t);
980
981 return 1;
982 }
983
984
985 void
ngx_http_script_start_args_code(ngx_http_script_engine_t * e)986 ngx_http_script_start_args_code(ngx_http_script_engine_t *e)
987 {
988 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
989 "http script args");
990
991 e->is_args = 1;
992 e->args = e->pos;
993 e->ip += sizeof(uintptr_t);
994 }
995
996
997 #if (NGX_PCRE)
998
999 void
ngx_http_script_regex_start_code(ngx_http_script_engine_t * e)1000 ngx_http_script_regex_start_code(ngx_http_script_engine_t *e)
1001 {
1002 size_t len;
1003 ngx_int_t rc;
1004 ngx_uint_t n;
1005 ngx_http_request_t *r;
1006 ngx_http_script_engine_t le;
1007 ngx_http_script_len_code_pt lcode;
1008 ngx_http_script_regex_code_t *code;
1009
1010 code = (ngx_http_script_regex_code_t *) e->ip;
1011
1012 r = e->request;
1013
1014 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1015 "http script regex: \"%V\"", &code->name);
1016
1017 if (code->uri) {
1018 e->line = r->uri;
1019 } else {
1020 e->sp--;
1021 e->line.len = e->sp->len;
1022 e->line.data = e->sp->data;
1023 }
1024
1025 rc = ngx_http_regex_exec(r, code->regex, &e->line);
1026
1027 if (rc == NGX_DECLINED) {
1028 if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
1029 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
1030 "\"%V\" does not match \"%V\"",
1031 &code->name, &e->line);
1032 }
1033
1034 r->ncaptures = 0;
1035
1036 if (code->test) {
1037 if (code->negative_test) {
1038 e->sp->len = 1;
1039 e->sp->data = (u_char *) "1";
1040
1041 } else {
1042 e->sp->len = 0;
1043 e->sp->data = (u_char *) "";
1044 }
1045
1046 e->sp++;
1047
1048 e->ip += sizeof(ngx_http_script_regex_code_t);
1049 return;
1050 }
1051
1052 e->ip += code->next;
1053 return;
1054 }
1055
1056 if (rc == NGX_ERROR) {
1057 e->ip = ngx_http_script_exit;
1058 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1059 return;
1060 }
1061
1062 if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
1063 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
1064 "\"%V\" matches \"%V\"", &code->name, &e->line);
1065 }
1066
1067 if (code->test) {
1068 if (code->negative_test) {
1069 e->sp->len = 0;
1070 e->sp->data = (u_char *) "";
1071
1072 } else {
1073 e->sp->len = 1;
1074 e->sp->data = (u_char *) "1";
1075 }
1076
1077 e->sp++;
1078
1079 e->ip += sizeof(ngx_http_script_regex_code_t);
1080 return;
1081 }
1082
1083 if (code->status) {
1084 e->status = code->status;
1085
1086 if (!code->redirect) {
1087 e->ip = ngx_http_script_exit;
1088 return;
1089 }
1090 }
1091
1092 if (code->uri) {
1093 r->internal = 1;
1094 r->valid_unparsed_uri = 0;
1095
1096 if (code->break_cycle) {
1097 r->valid_location = 0;
1098 r->uri_changed = 0;
1099
1100 } else {
1101 r->uri_changed = 1;
1102 }
1103 }
1104
1105 if (code->lengths == NULL) {
1106 e->buf.len = code->size;
1107
1108 if (code->uri) {
1109 if (r->ncaptures && (r->quoted_uri || r->plus_in_uri)) {
1110 e->buf.len += 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len,
1111 NGX_ESCAPE_ARGS);
1112 }
1113 }
1114
1115 for (n = 2; n < r->ncaptures; n += 2) {
1116 e->buf.len += r->captures[n + 1] - r->captures[n];
1117 }
1118
1119 } else {
1120 ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
1121
1122 le.ip = code->lengths->elts;
1123 le.line = e->line;
1124 le.request = r;
1125 le.quote = code->redirect;
1126
1127 len = 0;
1128
1129 while (*(uintptr_t *) le.ip) {
1130 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1131 len += lcode(&le);
1132 }
1133
1134 e->buf.len = len;
1135 }
1136
1137 if (code->add_args && r->args.len) {
1138 e->buf.len += r->args.len + 1;
1139 }
1140
1141 e->buf.data = ngx_pnalloc(r->pool, e->buf.len);
1142 if (e->buf.data == NULL) {
1143 e->ip = ngx_http_script_exit;
1144 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1145 return;
1146 }
1147
1148 e->quote = code->redirect;
1149
1150 e->pos = e->buf.data;
1151
1152 e->ip += sizeof(ngx_http_script_regex_code_t);
1153 }
1154
1155
1156 void
ngx_http_script_regex_end_code(ngx_http_script_engine_t * e)1157 ngx_http_script_regex_end_code(ngx_http_script_engine_t *e)
1158 {
1159 u_char *dst, *src;
1160 ngx_http_request_t *r;
1161 ngx_http_script_regex_end_code_t *code;
1162
1163 code = (ngx_http_script_regex_end_code_t *) e->ip;
1164
1165 r = e->request;
1166
1167 e->quote = 0;
1168
1169 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1170 "http script regex end");
1171
1172 if (code->redirect) {
1173
1174 dst = e->buf.data;
1175 src = e->buf.data;
1176
1177 ngx_unescape_uri(&dst, &src, e->pos - e->buf.data,
1178 NGX_UNESCAPE_REDIRECT);
1179
1180 if (src < e->pos) {
1181 dst = ngx_movemem(dst, src, e->pos - src);
1182 }
1183
1184 e->pos = dst;
1185
1186 if (code->add_args && r->args.len) {
1187 *e->pos++ = (u_char) (code->args ? '&' : '?');
1188 e->pos = ngx_copy(e->pos, r->args.data, r->args.len);
1189 }
1190
1191 e->buf.len = e->pos - e->buf.data;
1192
1193 if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
1194 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
1195 "rewritten redirect: \"%V\"", &e->buf);
1196 }
1197
1198 ngx_http_clear_location(r);
1199
1200 r->headers_out.location = ngx_list_push(&r->headers_out.headers);
1201 if (r->headers_out.location == NULL) {
1202 e->ip = ngx_http_script_exit;
1203 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1204 return;
1205 }
1206
1207 r->headers_out.location->hash = 1;
1208 ngx_str_set(&r->headers_out.location->key, "Location");
1209 r->headers_out.location->value = e->buf;
1210
1211 e->ip += sizeof(ngx_http_script_regex_end_code_t);
1212 return;
1213 }
1214
1215 if (e->args) {
1216 e->buf.len = e->args - e->buf.data;
1217
1218 if (code->add_args && r->args.len) {
1219 *e->pos++ = '&';
1220 e->pos = ngx_copy(e->pos, r->args.data, r->args.len);
1221 }
1222
1223 r->args.len = e->pos - e->args;
1224 r->args.data = e->args;
1225
1226 e->args = NULL;
1227
1228 } else {
1229 e->buf.len = e->pos - e->buf.data;
1230
1231 if (!code->add_args) {
1232 r->args.len = 0;
1233 }
1234 }
1235
1236 if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
1237 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
1238 "rewritten data: \"%V\", args: \"%V\"",
1239 &e->buf, &r->args);
1240 }
1241
1242 if (code->uri) {
1243 r->uri = e->buf;
1244
1245 if (r->uri.len == 0) {
1246 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1247 "the rewritten URI has a zero length");
1248 e->ip = ngx_http_script_exit;
1249 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1250 return;
1251 }
1252
1253 ngx_http_set_exten(r);
1254 }
1255
1256 e->ip += sizeof(ngx_http_script_regex_end_code_t);
1257 }
1258
1259
1260 static ngx_int_t
ngx_http_script_add_capture_code(ngx_http_script_compile_t * sc,ngx_uint_t n)1261 ngx_http_script_add_capture_code(ngx_http_script_compile_t *sc, ngx_uint_t n)
1262 {
1263 ngx_http_script_copy_capture_code_t *code;
1264
1265 code = ngx_http_script_add_code(*sc->lengths,
1266 sizeof(ngx_http_script_copy_capture_code_t),
1267 NULL);
1268 if (code == NULL) {
1269 return NGX_ERROR;
1270 }
1271
1272 code->code = (ngx_http_script_code_pt) (void *)
1273 ngx_http_script_copy_capture_len_code;
1274 code->n = 2 * n;
1275
1276
1277 code = ngx_http_script_add_code(*sc->values,
1278 sizeof(ngx_http_script_copy_capture_code_t),
1279 &sc->main);
1280 if (code == NULL) {
1281 return NGX_ERROR;
1282 }
1283
1284 code->code = ngx_http_script_copy_capture_code;
1285 code->n = 2 * n;
1286
1287 if (sc->ncaptures < n) {
1288 sc->ncaptures = n;
1289 }
1290
1291 return NGX_OK;
1292 }
1293
1294
1295 size_t
ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t * e)1296 ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e)
1297 {
1298 int *cap;
1299 u_char *p;
1300 ngx_uint_t n;
1301 ngx_http_request_t *r;
1302 ngx_http_script_copy_capture_code_t *code;
1303
1304 r = e->request;
1305
1306 code = (ngx_http_script_copy_capture_code_t *) e->ip;
1307
1308 e->ip += sizeof(ngx_http_script_copy_capture_code_t);
1309
1310 n = code->n;
1311
1312 if (n < r->ncaptures) {
1313
1314 cap = r->captures;
1315
1316 if ((e->is_args || e->quote)
1317 && (e->request->quoted_uri || e->request->plus_in_uri))
1318 {
1319 p = r->captures_data;
1320
1321 return cap[n + 1] - cap[n]
1322 + 2 * ngx_escape_uri(NULL, &p[cap[n]], cap[n + 1] - cap[n],
1323 NGX_ESCAPE_ARGS);
1324 } else {
1325 return cap[n + 1] - cap[n];
1326 }
1327 }
1328
1329 return 0;
1330 }
1331
1332
1333 void
ngx_http_script_copy_capture_code(ngx_http_script_engine_t * e)1334 ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e)
1335 {
1336 int *cap;
1337 u_char *p, *pos;
1338 ngx_uint_t n;
1339 ngx_http_request_t *r;
1340 ngx_http_script_copy_capture_code_t *code;
1341
1342 r = e->request;
1343
1344 code = (ngx_http_script_copy_capture_code_t *) e->ip;
1345
1346 e->ip += sizeof(ngx_http_script_copy_capture_code_t);
1347
1348 n = code->n;
1349
1350 pos = e->pos;
1351
1352 if (n < r->ncaptures) {
1353
1354 cap = r->captures;
1355 p = r->captures_data;
1356
1357 if ((e->is_args || e->quote)
1358 && (e->request->quoted_uri || e->request->plus_in_uri))
1359 {
1360 e->pos = (u_char *) ngx_escape_uri(pos, &p[cap[n]],
1361 cap[n + 1] - cap[n],
1362 NGX_ESCAPE_ARGS);
1363 } else {
1364 e->pos = ngx_copy(pos, &p[cap[n]], cap[n + 1] - cap[n]);
1365 }
1366 }
1367
1368 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1369 "http script capture: \"%*s\"", e->pos - pos, pos);
1370 }
1371
1372 #endif
1373
1374
1375 static ngx_int_t
ngx_http_script_add_full_name_code(ngx_http_script_compile_t * sc)1376 ngx_http_script_add_full_name_code(ngx_http_script_compile_t *sc)
1377 {
1378 ngx_http_script_full_name_code_t *code;
1379
1380 code = ngx_http_script_add_code(*sc->lengths,
1381 sizeof(ngx_http_script_full_name_code_t),
1382 NULL);
1383 if (code == NULL) {
1384 return NGX_ERROR;
1385 }
1386
1387 code->code = (ngx_http_script_code_pt) (void *)
1388 ngx_http_script_full_name_len_code;
1389 code->conf_prefix = sc->conf_prefix;
1390
1391 code = ngx_http_script_add_code(*sc->values,
1392 sizeof(ngx_http_script_full_name_code_t),
1393 &sc->main);
1394 if (code == NULL) {
1395 return NGX_ERROR;
1396 }
1397
1398 code->code = ngx_http_script_full_name_code;
1399 code->conf_prefix = sc->conf_prefix;
1400
1401 return NGX_OK;
1402 }
1403
1404
1405 static size_t
ngx_http_script_full_name_len_code(ngx_http_script_engine_t * e)1406 ngx_http_script_full_name_len_code(ngx_http_script_engine_t *e)
1407 {
1408 ngx_http_script_full_name_code_t *code;
1409
1410 code = (ngx_http_script_full_name_code_t *) e->ip;
1411
1412 e->ip += sizeof(ngx_http_script_full_name_code_t);
1413
1414 return code->conf_prefix ? ngx_cycle->conf_prefix.len:
1415 ngx_cycle->prefix.len;
1416 }
1417
1418
1419 static void
ngx_http_script_full_name_code(ngx_http_script_engine_t * e)1420 ngx_http_script_full_name_code(ngx_http_script_engine_t *e)
1421 {
1422 ngx_http_script_full_name_code_t *code;
1423
1424 ngx_str_t value, *prefix;
1425
1426 code = (ngx_http_script_full_name_code_t *) e->ip;
1427
1428 value.data = e->buf.data;
1429 value.len = e->pos - e->buf.data;
1430
1431 prefix = code->conf_prefix ? (ngx_str_t *) &ngx_cycle->conf_prefix:
1432 (ngx_str_t *) &ngx_cycle->prefix;
1433
1434 if (ngx_get_full_name(e->request->pool, prefix, &value) != NGX_OK) {
1435 e->ip = ngx_http_script_exit;
1436 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1437 return;
1438 }
1439
1440 e->buf = value;
1441
1442 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1443 "http script fullname: \"%V\"", &value);
1444
1445 e->ip += sizeof(ngx_http_script_full_name_code_t);
1446 }
1447
1448
1449 void
ngx_http_script_return_code(ngx_http_script_engine_t * e)1450 ngx_http_script_return_code(ngx_http_script_engine_t *e)
1451 {
1452 ngx_http_script_return_code_t *code;
1453
1454 code = (ngx_http_script_return_code_t *) e->ip;
1455
1456 if (code->status < NGX_HTTP_BAD_REQUEST
1457 || code->text.value.len
1458 || code->text.lengths)
1459 {
1460 e->status = ngx_http_send_response(e->request, code->status, NULL,
1461 &code->text);
1462 } else {
1463 e->status = code->status;
1464 }
1465
1466 e->ip = ngx_http_script_exit;
1467 }
1468
1469
1470 void
ngx_http_script_break_code(ngx_http_script_engine_t * e)1471 ngx_http_script_break_code(ngx_http_script_engine_t *e)
1472 {
1473 ngx_http_request_t *r;
1474
1475 r = e->request;
1476
1477 if (r->uri_changed) {
1478 r->valid_location = 0;
1479 r->uri_changed = 0;
1480 }
1481
1482 e->ip = ngx_http_script_exit;
1483 }
1484
1485
1486 void
ngx_http_script_if_code(ngx_http_script_engine_t * e)1487 ngx_http_script_if_code(ngx_http_script_engine_t *e)
1488 {
1489 ngx_http_script_if_code_t *code;
1490
1491 code = (ngx_http_script_if_code_t *) e->ip;
1492
1493 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1494 "http script if");
1495
1496 e->sp--;
1497
1498 if (e->sp->len && (e->sp->len != 1 || e->sp->data[0] != '0')) {
1499 if (code->loc_conf) {
1500 e->request->loc_conf = code->loc_conf;
1501 ngx_http_update_location_config(e->request);
1502 }
1503
1504 e->ip += sizeof(ngx_http_script_if_code_t);
1505 return;
1506 }
1507
1508 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1509 "http script if: false");
1510
1511 e->ip += code->next;
1512 }
1513
1514
1515 void
ngx_http_script_equal_code(ngx_http_script_engine_t * e)1516 ngx_http_script_equal_code(ngx_http_script_engine_t *e)
1517 {
1518 ngx_http_variable_value_t *val, *res;
1519
1520 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1521 "http script equal");
1522
1523 e->sp--;
1524 val = e->sp;
1525 res = e->sp - 1;
1526
1527 e->ip += sizeof(uintptr_t);
1528
1529 if (val->len == res->len
1530 && ngx_strncmp(val->data, res->data, res->len) == 0)
1531 {
1532 *res = ngx_http_variable_true_value;
1533 return;
1534 }
1535
1536 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1537 "http script equal: no");
1538
1539 *res = ngx_http_variable_null_value;
1540 }
1541
1542
1543 void
ngx_http_script_not_equal_code(ngx_http_script_engine_t * e)1544 ngx_http_script_not_equal_code(ngx_http_script_engine_t *e)
1545 {
1546 ngx_http_variable_value_t *val, *res;
1547
1548 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1549 "http script not equal");
1550
1551 e->sp--;
1552 val = e->sp;
1553 res = e->sp - 1;
1554
1555 e->ip += sizeof(uintptr_t);
1556
1557 if (val->len == res->len
1558 && ngx_strncmp(val->data, res->data, res->len) == 0)
1559 {
1560 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1561 "http script not equal: no");
1562
1563 *res = ngx_http_variable_null_value;
1564 return;
1565 }
1566
1567 *res = ngx_http_variable_true_value;
1568 }
1569
1570
1571 void
ngx_http_script_file_code(ngx_http_script_engine_t * e)1572 ngx_http_script_file_code(ngx_http_script_engine_t *e)
1573 {
1574 ngx_str_t path;
1575 ngx_http_request_t *r;
1576 ngx_open_file_info_t of;
1577 ngx_http_core_loc_conf_t *clcf;
1578 ngx_http_variable_value_t *value;
1579 ngx_http_script_file_code_t *code;
1580
1581 value = e->sp - 1;
1582
1583 code = (ngx_http_script_file_code_t *) e->ip;
1584 e->ip += sizeof(ngx_http_script_file_code_t);
1585
1586 path.len = value->len - 1;
1587 path.data = value->data;
1588
1589 r = e->request;
1590
1591 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1592 "http script file op %p \"%V\"", (void *) code->op, &path);
1593
1594 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1595
1596 ngx_memzero(&of, sizeof(ngx_open_file_info_t));
1597
1598 of.read_ahead = clcf->read_ahead;
1599 of.directio = clcf->directio;
1600 of.valid = clcf->open_file_cache_valid;
1601 of.min_uses = clcf->open_file_cache_min_uses;
1602 of.test_only = 1;
1603 of.errors = clcf->open_file_cache_errors;
1604 of.events = clcf->open_file_cache_events;
1605
1606 if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
1607 e->ip = ngx_http_script_exit;
1608 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1609 return;
1610 }
1611
1612 if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
1613 != NGX_OK)
1614 {
1615 if (of.err == 0) {
1616 e->ip = ngx_http_script_exit;
1617 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1618 return;
1619 }
1620
1621 if (of.err != NGX_ENOENT
1622 && of.err != NGX_ENOTDIR
1623 && of.err != NGX_ENAMETOOLONG)
1624 {
1625 ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
1626 "%s \"%s\" failed", of.failed, value->data);
1627 }
1628
1629 switch (code->op) {
1630
1631 case ngx_http_script_file_plain:
1632 case ngx_http_script_file_dir:
1633 case ngx_http_script_file_exists:
1634 case ngx_http_script_file_exec:
1635 goto false_value;
1636
1637 case ngx_http_script_file_not_plain:
1638 case ngx_http_script_file_not_dir:
1639 case ngx_http_script_file_not_exists:
1640 case ngx_http_script_file_not_exec:
1641 goto true_value;
1642 }
1643
1644 goto false_value;
1645 }
1646
1647 switch (code->op) {
1648 case ngx_http_script_file_plain:
1649 if (of.is_file) {
1650 goto true_value;
1651 }
1652 goto false_value;
1653
1654 case ngx_http_script_file_not_plain:
1655 if (of.is_file) {
1656 goto false_value;
1657 }
1658 goto true_value;
1659
1660 case ngx_http_script_file_dir:
1661 if (of.is_dir) {
1662 goto true_value;
1663 }
1664 goto false_value;
1665
1666 case ngx_http_script_file_not_dir:
1667 if (of.is_dir) {
1668 goto false_value;
1669 }
1670 goto true_value;
1671
1672 case ngx_http_script_file_exists:
1673 if (of.is_file || of.is_dir || of.is_link) {
1674 goto true_value;
1675 }
1676 goto false_value;
1677
1678 case ngx_http_script_file_not_exists:
1679 if (of.is_file || of.is_dir || of.is_link) {
1680 goto false_value;
1681 }
1682 goto true_value;
1683
1684 case ngx_http_script_file_exec:
1685 if (of.is_exec) {
1686 goto true_value;
1687 }
1688 goto false_value;
1689
1690 case ngx_http_script_file_not_exec:
1691 if (of.is_exec) {
1692 goto false_value;
1693 }
1694 goto true_value;
1695 }
1696
1697 false_value:
1698
1699 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1700 "http script file op false");
1701
1702 *value = ngx_http_variable_null_value;
1703 return;
1704
1705 true_value:
1706
1707 *value = ngx_http_variable_true_value;
1708 return;
1709 }
1710
1711
1712 void
ngx_http_script_complex_value_code(ngx_http_script_engine_t * e)1713 ngx_http_script_complex_value_code(ngx_http_script_engine_t *e)
1714 {
1715 size_t len;
1716 ngx_http_script_engine_t le;
1717 ngx_http_script_len_code_pt lcode;
1718 ngx_http_script_complex_value_code_t *code;
1719
1720 code = (ngx_http_script_complex_value_code_t *) e->ip;
1721
1722 e->ip += sizeof(ngx_http_script_complex_value_code_t);
1723
1724 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1725 "http script complex value");
1726
1727 ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
1728
1729 le.ip = code->lengths->elts;
1730 le.line = e->line;
1731 le.request = e->request;
1732 le.quote = e->quote;
1733
1734 for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {
1735 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1736 }
1737
1738 e->buf.len = len;
1739 e->buf.data = ngx_pnalloc(e->request->pool, len);
1740 if (e->buf.data == NULL) {
1741 e->ip = ngx_http_script_exit;
1742 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1743 return;
1744 }
1745
1746 e->pos = e->buf.data;
1747
1748 e->sp->len = e->buf.len;
1749 e->sp->data = e->buf.data;
1750 e->sp++;
1751 }
1752
1753
1754 void
ngx_http_script_value_code(ngx_http_script_engine_t * e)1755 ngx_http_script_value_code(ngx_http_script_engine_t *e)
1756 {
1757 ngx_http_script_value_code_t *code;
1758
1759 code = (ngx_http_script_value_code_t *) e->ip;
1760
1761 e->ip += sizeof(ngx_http_script_value_code_t);
1762
1763 e->sp->len = code->text_len;
1764 e->sp->data = (u_char *) code->text_data;
1765
1766 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1767 "http script value: \"%v\"", e->sp);
1768
1769 e->sp++;
1770 }
1771
1772
1773 void
ngx_http_script_set_var_code(ngx_http_script_engine_t * e)1774 ngx_http_script_set_var_code(ngx_http_script_engine_t *e)
1775 {
1776 ngx_http_request_t *r;
1777 ngx_http_script_var_code_t *code;
1778
1779 code = (ngx_http_script_var_code_t *) e->ip;
1780
1781 e->ip += sizeof(ngx_http_script_var_code_t);
1782
1783 r = e->request;
1784
1785 e->sp--;
1786
1787 r->variables[code->index].len = e->sp->len;
1788 r->variables[code->index].valid = 1;
1789 r->variables[code->index].no_cacheable = 0;
1790 r->variables[code->index].not_found = 0;
1791 r->variables[code->index].data = e->sp->data;
1792
1793 #if (NGX_DEBUG)
1794 {
1795 ngx_http_variable_t *v;
1796 ngx_http_core_main_conf_t *cmcf;
1797
1798 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
1799
1800 v = cmcf->variables.elts;
1801
1802 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1803 "http script set $%V", &v[code->index].name);
1804 }
1805 #endif
1806 }
1807
1808
1809 void
ngx_http_script_var_set_handler_code(ngx_http_script_engine_t * e)1810 ngx_http_script_var_set_handler_code(ngx_http_script_engine_t *e)
1811 {
1812 ngx_http_script_var_handler_code_t *code;
1813
1814 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1815 "http script set var handler");
1816
1817 code = (ngx_http_script_var_handler_code_t *) e->ip;
1818
1819 e->ip += sizeof(ngx_http_script_var_handler_code_t);
1820
1821 e->sp--;
1822
1823 code->handler(e->request, e->sp, code->data);
1824 }
1825
1826
1827 void
ngx_http_script_var_code(ngx_http_script_engine_t * e)1828 ngx_http_script_var_code(ngx_http_script_engine_t *e)
1829 {
1830 ngx_http_variable_value_t *value;
1831 ngx_http_script_var_code_t *code;
1832
1833 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1834 "http script var");
1835
1836 code = (ngx_http_script_var_code_t *) e->ip;
1837
1838 e->ip += sizeof(ngx_http_script_var_code_t);
1839
1840 value = ngx_http_get_flushed_variable(e->request, code->index);
1841
1842 if (value && !value->not_found) {
1843 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1844 "http script var: \"%v\"", value);
1845
1846 *e->sp = *value;
1847 e->sp++;
1848
1849 return;
1850 }
1851
1852 *e->sp = ngx_http_variable_null_value;
1853 e->sp++;
1854 }
1855
1856
1857 void
ngx_http_script_nop_code(ngx_http_script_engine_t * e)1858 ngx_http_script_nop_code(ngx_http_script_engine_t *e)
1859 {
1860 e->ip += sizeof(uintptr_t);
1861 }
1862