nginx 1.1.11
[nginx.git] / src / http / ngx_http_script.c
blob6d81b4435c79c52194627c0f299b4e3d36f5d64d
2 /*
3 * Copyright (C) Igor Sysoev
4 */
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_http.h>
12 static ngx_int_t ngx_http_script_init_arrays(ngx_http_script_compile_t *sc);
13 static ngx_int_t ngx_http_script_done(ngx_http_script_compile_t *sc);
14 static ngx_int_t ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc,
15 ngx_str_t *value, ngx_uint_t last);
16 static ngx_int_t ngx_http_script_add_var_code(ngx_http_script_compile_t *sc,
17 ngx_str_t *name);
18 static ngx_int_t ngx_http_script_add_args_code(ngx_http_script_compile_t *sc);
19 #if (NGX_PCRE)
20 static ngx_int_t ngx_http_script_add_capture_code(ngx_http_script_compile_t *sc,
21 ngx_uint_t n);
22 #endif
23 static ngx_int_t
24 ngx_http_script_add_full_name_code(ngx_http_script_compile_t *sc);
25 static size_t ngx_http_script_full_name_len_code(ngx_http_script_engine_t *e);
26 static void ngx_http_script_full_name_code(ngx_http_script_engine_t *e);
29 #define ngx_http_script_exit (u_char *) &ngx_http_script_exit_code
31 static uintptr_t ngx_http_script_exit_code = (uintptr_t) NULL;
34 void
35 ngx_http_script_flush_complex_value(ngx_http_request_t *r,
36 ngx_http_complex_value_t *val)
38 ngx_uint_t *index;
40 index = val->flushes;
42 if (index) {
43 while (*index != (ngx_uint_t) -1) {
45 if (r->variables[*index].no_cacheable) {
46 r->variables[*index].valid = 0;
47 r->variables[*index].not_found = 0;
50 index++;
56 ngx_int_t
57 ngx_http_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val,
58 ngx_str_t *value)
60 size_t len;
61 ngx_http_script_code_pt code;
62 ngx_http_script_len_code_pt lcode;
63 ngx_http_script_engine_t e;
65 if (val->lengths == NULL) {
66 *value = val->value;
67 return NGX_OK;
70 ngx_http_script_flush_complex_value(r, val);
72 ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
74 e.ip = val->lengths;
75 e.request = r;
76 e.flushed = 1;
78 len = 0;
80 while (*(uintptr_t *) e.ip) {
81 lcode = *(ngx_http_script_len_code_pt *) e.ip;
82 len += lcode(&e);
85 value->len = len;
86 value->data = ngx_pnalloc(r->pool, len);
87 if (value->data == NULL) {
88 return NGX_ERROR;
91 e.ip = val->values;
92 e.pos = value->data;
93 e.buf = *value;
95 while (*(uintptr_t *) e.ip) {
96 code = *(ngx_http_script_code_pt *) e.ip;
97 code((ngx_http_script_engine_t *) &e);
100 *value = e.buf;
102 return NGX_OK;
106 ngx_int_t
107 ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv)
109 ngx_str_t *v;
110 ngx_uint_t i, n, nv, nc;
111 ngx_array_t flushes, lengths, values, *pf, *pl, *pv;
112 ngx_http_script_compile_t sc;
114 v = ccv->value;
116 if (v->len == 0) {
117 ngx_conf_log_error(NGX_LOG_EMERG, ccv->cf, 0, "empty parameter");
118 return NGX_ERROR;
121 nv = 0;
122 nc = 0;
124 for (i = 0; i < v->len; i++) {
125 if (v->data[i] == '$') {
126 if (v->data[i + 1] >= '1' && v->data[i + 1] <= '9') {
127 nc++;
129 } else {
130 nv++;
135 if (v->data[0] != '$' && (ccv->conf_prefix || ccv->root_prefix)) {
137 if (ngx_conf_full_name(ccv->cf->cycle, v, ccv->conf_prefix) != NGX_OK) {
138 return NGX_ERROR;
141 ccv->conf_prefix = 0;
142 ccv->root_prefix = 0;
145 ccv->complex_value->value = *v;
146 ccv->complex_value->flushes = NULL;
147 ccv->complex_value->lengths = NULL;
148 ccv->complex_value->values = NULL;
150 if (nv == 0 && nc == 0) {
151 return NGX_OK;
154 n = nv + 1;
156 if (ngx_array_init(&flushes, ccv->cf->pool, n, sizeof(ngx_uint_t))
157 != NGX_OK)
159 return NGX_ERROR;
162 n = nv * (2 * sizeof(ngx_http_script_copy_code_t)
163 + sizeof(ngx_http_script_var_code_t))
164 + sizeof(uintptr_t);
166 if (ngx_array_init(&lengths, ccv->cf->pool, n, 1) != NGX_OK) {
167 return NGX_ERROR;
170 n = (nv * (2 * sizeof(ngx_http_script_copy_code_t)
171 + sizeof(ngx_http_script_var_code_t))
172 + sizeof(uintptr_t)
173 + v->len
174 + sizeof(uintptr_t) - 1)
175 & ~(sizeof(uintptr_t) - 1);
177 if (ngx_array_init(&values, ccv->cf->pool, n, 1) != NGX_OK) {
178 return NGX_ERROR;
181 pf = &flushes;
182 pl = &lengths;
183 pv = &values;
185 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
187 sc.cf = ccv->cf;
188 sc.source = v;
189 sc.flushes = &pf;
190 sc.lengths = &pl;
191 sc.values = &pv;
192 sc.complete_lengths = 1;
193 sc.complete_values = 1;
194 sc.zero = ccv->zero;
195 sc.conf_prefix = ccv->conf_prefix;
196 sc.root_prefix = ccv->root_prefix;
198 if (ngx_http_script_compile(&sc) != NGX_OK) {
199 return NGX_ERROR;
202 if (flushes.nelts) {
203 ccv->complex_value->flushes = flushes.elts;
204 ccv->complex_value->flushes[flushes.nelts] = (ngx_uint_t) -1;
207 ccv->complex_value->lengths = lengths.elts;
208 ccv->complex_value->values = values.elts;
210 return NGX_OK;
214 char *
215 ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
217 char *p = conf;
219 ngx_str_t *value;
220 ngx_http_complex_value_t **cv;
221 ngx_http_compile_complex_value_t ccv;
223 cv = (ngx_http_complex_value_t **) (p + cmd->offset);
225 if (*cv != NULL) {
226 return "duplicate";
229 *cv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
230 if (*cv == NULL) {
231 return NGX_CONF_ERROR;
234 value = cf->args->elts;
236 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
238 ccv.cf = cf;
239 ccv.value = &value[1];
240 ccv.complex_value = *cv;
242 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
243 return NGX_CONF_ERROR;
246 return NGX_CONF_OK;
250 ngx_int_t
251 ngx_http_test_predicates(ngx_http_request_t *r, ngx_array_t *predicates)
253 ngx_str_t val;
254 ngx_uint_t i;
255 ngx_http_complex_value_t *cv;
257 if (predicates == NULL) {
258 return NGX_OK;
261 cv = predicates->elts;
263 for (i = 0; i < predicates->nelts; i++) {
264 if (ngx_http_complex_value(r, &cv[i], &val) != NGX_OK) {
265 return NGX_ERROR;
268 if (val.len && (val.len != 1 || val.data[0] != '0')) {
269 return NGX_DECLINED;
273 return NGX_OK;
277 char *
278 ngx_http_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
280 char *p = conf;
282 ngx_str_t *value;
283 ngx_uint_t i;
284 ngx_array_t **a;
285 ngx_http_complex_value_t *cv;
286 ngx_http_compile_complex_value_t ccv;
288 a = (ngx_array_t **) (p + cmd->offset);
290 if (*a == NGX_CONF_UNSET_PTR) {
291 *a = ngx_array_create(cf->pool, 1, sizeof(ngx_http_complex_value_t));
292 if (*a == NULL) {
293 return NGX_CONF_ERROR;
297 value = cf->args->elts;
299 for (i = 1; i < cf->args->nelts; i++) {
300 cv = ngx_array_push(*a);
301 if (cv == NULL) {
302 return NGX_CONF_ERROR;
305 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
307 ccv.cf = cf;
308 ccv.value = &value[i];
309 ccv.complex_value = cv;
311 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
312 return NGX_CONF_ERROR;
316 return NGX_CONF_OK;
320 ngx_uint_t
321 ngx_http_script_variables_count(ngx_str_t *value)
323 ngx_uint_t i, n;
325 for (n = 0, i = 0; i < value->len; i++) {
326 if (value->data[i] == '$') {
327 n++;
331 return n;
335 ngx_int_t
336 ngx_http_script_compile(ngx_http_script_compile_t *sc)
338 u_char ch;
339 ngx_str_t name;
340 ngx_uint_t i, bracket;
342 if (ngx_http_script_init_arrays(sc) != NGX_OK) {
343 return NGX_ERROR;
346 for (i = 0; i < sc->source->len; /* void */ ) {
348 name.len = 0;
350 if (sc->source->data[i] == '$') {
352 if (++i == sc->source->len) {
353 goto invalid_variable;
356 #if (NGX_PCRE)
358 ngx_uint_t n;
360 if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') {
362 n = sc->source->data[i] - '0';
364 if (sc->captures_mask & (1 << n)) {
365 sc->dup_capture = 1;
368 sc->captures_mask |= 1 << n;
370 if (ngx_http_script_add_capture_code(sc, n) != NGX_OK) {
371 return NGX_ERROR;
374 i++;
376 continue;
379 #endif
381 if (sc->source->data[i] == '{') {
382 bracket = 1;
384 if (++i == sc->source->len) {
385 goto invalid_variable;
388 name.data = &sc->source->data[i];
390 } else {
391 bracket = 0;
392 name.data = &sc->source->data[i];
395 for ( /* void */ ; i < sc->source->len; i++, name.len++) {
396 ch = sc->source->data[i];
398 if (ch == '}' && bracket) {
399 i++;
400 bracket = 0;
401 break;
404 if ((ch >= 'A' && ch <= 'Z')
405 || (ch >= 'a' && ch <= 'z')
406 || (ch >= '0' && ch <= '9')
407 || ch == '_')
409 continue;
412 break;
415 if (bracket) {
416 ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0,
417 "the closing bracket in \"%V\" "
418 "variable is missing", &name);
419 return NGX_ERROR;
422 if (name.len == 0) {
423 goto invalid_variable;
426 sc->variables++;
428 if (ngx_http_script_add_var_code(sc, &name) != NGX_OK) {
429 return NGX_ERROR;
432 continue;
435 if (sc->source->data[i] == '?' && sc->compile_args) {
436 sc->args = 1;
437 sc->compile_args = 0;
439 if (ngx_http_script_add_args_code(sc) != NGX_OK) {
440 return NGX_ERROR;
443 i++;
445 continue;
448 name.data = &sc->source->data[i];
450 while (i < sc->source->len) {
452 if (sc->source->data[i] == '$') {
453 break;
456 if (sc->source->data[i] == '?') {
458 sc->args = 1;
460 if (sc->compile_args) {
461 break;
465 i++;
466 name.len++;
469 sc->size += name.len;
471 if (ngx_http_script_add_copy_code(sc, &name, (i == sc->source->len))
472 != NGX_OK)
474 return NGX_ERROR;
478 return ngx_http_script_done(sc);
480 invalid_variable:
482 ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, "invalid variable name");
484 return NGX_ERROR;
488 u_char *
489 ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value,
490 void *code_lengths, size_t len, void *code_values)
492 ngx_uint_t i;
493 ngx_http_script_code_pt code;
494 ngx_http_script_len_code_pt lcode;
495 ngx_http_script_engine_t e;
496 ngx_http_core_main_conf_t *cmcf;
498 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
500 for (i = 0; i < cmcf->variables.nelts; i++) {
501 if (r->variables[i].no_cacheable) {
502 r->variables[i].valid = 0;
503 r->variables[i].not_found = 0;
507 ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
509 e.ip = code_lengths;
510 e.request = r;
511 e.flushed = 1;
513 while (*(uintptr_t *) e.ip) {
514 lcode = *(ngx_http_script_len_code_pt *) e.ip;
515 len += lcode(&e);
519 value->len = len;
520 value->data = ngx_pnalloc(r->pool, len);
521 if (value->data == NULL) {
522 return NULL;
525 e.ip = code_values;
526 e.pos = value->data;
528 while (*(uintptr_t *) e.ip) {
529 code = *(ngx_http_script_code_pt *) e.ip;
530 code((ngx_http_script_engine_t *) &e);
533 return e.pos;
537 void
538 ngx_http_script_flush_no_cacheable_variables(ngx_http_request_t *r,
539 ngx_array_t *indices)
541 ngx_uint_t n, *index;
543 if (indices) {
544 index = indices->elts;
545 for (n = 0; n < indices->nelts; n++) {
546 if (r->variables[index[n]].no_cacheable) {
547 r->variables[index[n]].valid = 0;
548 r->variables[index[n]].not_found = 0;
555 static ngx_int_t
556 ngx_http_script_init_arrays(ngx_http_script_compile_t *sc)
558 ngx_uint_t n;
560 if (sc->flushes && *sc->flushes == NULL) {
561 n = sc->variables ? sc->variables : 1;
562 *sc->flushes = ngx_array_create(sc->cf->pool, n, sizeof(ngx_uint_t));
563 if (*sc->flushes == NULL) {
564 return NGX_ERROR;
568 if (*sc->lengths == NULL) {
569 n = sc->variables * (2 * sizeof(ngx_http_script_copy_code_t)
570 + sizeof(ngx_http_script_var_code_t))
571 + sizeof(uintptr_t);
573 *sc->lengths = ngx_array_create(sc->cf->pool, n, 1);
574 if (*sc->lengths == NULL) {
575 return NGX_ERROR;
579 if (*sc->values == NULL) {
580 n = (sc->variables * (2 * sizeof(ngx_http_script_copy_code_t)
581 + sizeof(ngx_http_script_var_code_t))
582 + sizeof(uintptr_t)
583 + sc->source->len
584 + sizeof(uintptr_t) - 1)
585 & ~(sizeof(uintptr_t) - 1);
587 *sc->values = ngx_array_create(sc->cf->pool, n, 1);
588 if (*sc->values == NULL) {
589 return NGX_ERROR;
593 sc->variables = 0;
595 return NGX_OK;
599 static ngx_int_t
600 ngx_http_script_done(ngx_http_script_compile_t *sc)
602 ngx_str_t zero;
603 uintptr_t *code;
605 if (sc->zero) {
607 zero.len = 1;
608 zero.data = (u_char *) "\0";
610 if (ngx_http_script_add_copy_code(sc, &zero, 0) != NGX_OK) {
611 return NGX_ERROR;
615 if (sc->conf_prefix || sc->root_prefix) {
616 if (ngx_http_script_add_full_name_code(sc) != NGX_OK) {
617 return NGX_ERROR;
621 if (sc->complete_lengths) {
622 code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL);
623 if (code == NULL) {
624 return NGX_ERROR;
627 *code = (uintptr_t) NULL;
630 if (sc->complete_values) {
631 code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t),
632 &sc->main);
633 if (code == NULL) {
634 return NGX_ERROR;
637 *code = (uintptr_t) NULL;
640 return NGX_OK;
644 void *
645 ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size)
647 if (*codes == NULL) {
648 *codes = ngx_array_create(pool, 256, 1);
649 if (*codes == NULL) {
650 return NULL;
654 return ngx_array_push_n(*codes, size);
658 void *
659 ngx_http_script_add_code(ngx_array_t *codes, size_t size, void *code)
661 u_char *elts, **p;
662 void *new;
664 elts = codes->elts;
666 new = ngx_array_push_n(codes, size);
667 if (new == NULL) {
668 return NULL;
671 if (code) {
672 if (elts != codes->elts) {
673 p = code;
674 *p += (u_char *) codes->elts - elts;
678 return new;
682 static ngx_int_t
683 ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc, ngx_str_t *value,
684 ngx_uint_t last)
686 u_char *p;
687 size_t size, len, zero;
688 ngx_http_script_copy_code_t *code;
690 zero = (sc->zero && last);
691 len = value->len + zero;
693 code = ngx_http_script_add_code(*sc->lengths,
694 sizeof(ngx_http_script_copy_code_t), NULL);
695 if (code == NULL) {
696 return NGX_ERROR;
699 code->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
700 code->len = len;
702 size = (sizeof(ngx_http_script_copy_code_t) + len + sizeof(uintptr_t) - 1)
703 & ~(sizeof(uintptr_t) - 1);
705 code = ngx_http_script_add_code(*sc->values, size, &sc->main);
706 if (code == NULL) {
707 return NGX_ERROR;
710 code->code = ngx_http_script_copy_code;
711 code->len = len;
713 p = ngx_cpymem((u_char *) code + sizeof(ngx_http_script_copy_code_t),
714 value->data, value->len);
716 if (zero) {
717 *p = '\0';
718 sc->zero = 0;
721 return NGX_OK;
725 size_t
726 ngx_http_script_copy_len_code(ngx_http_script_engine_t *e)
728 ngx_http_script_copy_code_t *code;
730 code = (ngx_http_script_copy_code_t *) e->ip;
732 e->ip += sizeof(ngx_http_script_copy_code_t);
734 return code->len;
738 void
739 ngx_http_script_copy_code(ngx_http_script_engine_t *e)
741 u_char *p;
742 ngx_http_script_copy_code_t *code;
744 code = (ngx_http_script_copy_code_t *) e->ip;
746 p = e->pos;
748 if (!e->skip) {
749 e->pos = ngx_copy(p, e->ip + sizeof(ngx_http_script_copy_code_t),
750 code->len);
753 e->ip += sizeof(ngx_http_script_copy_code_t)
754 + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));
756 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
757 "http script copy: \"%*s\"", e->pos - p, p);
761 static ngx_int_t
762 ngx_http_script_add_var_code(ngx_http_script_compile_t *sc, ngx_str_t *name)
764 ngx_int_t index, *p;
765 ngx_http_script_var_code_t *code;
767 index = ngx_http_get_variable_index(sc->cf, name);
769 if (index == NGX_ERROR) {
770 return NGX_ERROR;
773 if (sc->flushes) {
774 p = ngx_array_push(*sc->flushes);
775 if (p == NULL) {
776 return NGX_ERROR;
779 *p = index;
782 code = ngx_http_script_add_code(*sc->lengths,
783 sizeof(ngx_http_script_var_code_t), NULL);
784 if (code == NULL) {
785 return NGX_ERROR;
788 code->code = (ngx_http_script_code_pt) ngx_http_script_copy_var_len_code;
789 code->index = (uintptr_t) index;
791 code = ngx_http_script_add_code(*sc->values,
792 sizeof(ngx_http_script_var_code_t),
793 &sc->main);
794 if (code == NULL) {
795 return NGX_ERROR;
798 code->code = ngx_http_script_copy_var_code;
799 code->index = (uintptr_t) index;
801 return NGX_OK;
805 size_t
806 ngx_http_script_copy_var_len_code(ngx_http_script_engine_t *e)
808 ngx_http_variable_value_t *value;
809 ngx_http_script_var_code_t *code;
811 code = (ngx_http_script_var_code_t *) e->ip;
813 e->ip += sizeof(ngx_http_script_var_code_t);
815 if (e->flushed) {
816 value = ngx_http_get_indexed_variable(e->request, code->index);
818 } else {
819 value = ngx_http_get_flushed_variable(e->request, code->index);
822 if (value && !value->not_found) {
823 return value->len;
826 return 0;
830 void
831 ngx_http_script_copy_var_code(ngx_http_script_engine_t *e)
833 u_char *p;
834 ngx_http_variable_value_t *value;
835 ngx_http_script_var_code_t *code;
837 code = (ngx_http_script_var_code_t *) e->ip;
839 e->ip += sizeof(ngx_http_script_var_code_t);
841 if (!e->skip) {
843 if (e->flushed) {
844 value = ngx_http_get_indexed_variable(e->request, code->index);
846 } else {
847 value = ngx_http_get_flushed_variable(e->request, code->index);
850 if (value && !value->not_found) {
851 p = e->pos;
852 e->pos = ngx_copy(p, value->data, value->len);
854 ngx_log_debug2(NGX_LOG_DEBUG_HTTP,
855 e->request->connection->log, 0,
856 "http script var: \"%*s\"", e->pos - p, p);
862 static ngx_int_t
863 ngx_http_script_add_args_code(ngx_http_script_compile_t *sc)
865 uintptr_t *code;
867 code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL);
868 if (code == NULL) {
869 return NGX_ERROR;
872 *code = (uintptr_t) ngx_http_script_mark_args_code;
874 code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t), &sc->main);
875 if (code == NULL) {
876 return NGX_ERROR;
879 *code = (uintptr_t) ngx_http_script_start_args_code;
881 return NGX_OK;
885 size_t
886 ngx_http_script_mark_args_code(ngx_http_script_engine_t *e)
888 e->is_args = 1;
889 e->ip += sizeof(uintptr_t);
891 return 1;
895 void
896 ngx_http_script_start_args_code(ngx_http_script_engine_t *e)
898 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
899 "http script args");
901 e->is_args = 1;
902 e->args = e->pos;
903 e->ip += sizeof(uintptr_t);
907 #if (NGX_PCRE)
909 void
910 ngx_http_script_regex_start_code(ngx_http_script_engine_t *e)
912 size_t len;
913 ngx_int_t rc;
914 ngx_uint_t n;
915 ngx_http_request_t *r;
916 ngx_http_script_engine_t le;
917 ngx_http_script_len_code_pt lcode;
918 ngx_http_script_regex_code_t *code;
920 code = (ngx_http_script_regex_code_t *) e->ip;
922 r = e->request;
924 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
925 "http script regex: \"%V\"", &code->name);
927 if (code->uri) {
928 e->line = r->uri;
929 } else {
930 e->sp--;
931 e->line.len = e->sp->len;
932 e->line.data = e->sp->data;
935 rc = ngx_http_regex_exec(r, code->regex, &e->line);
937 if (rc == NGX_DECLINED) {
938 if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
939 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
940 "\"%V\" does not match \"%V\"",
941 &code->name, &e->line);
944 r->ncaptures = 0;
946 if (code->test) {
947 if (code->negative_test) {
948 e->sp->len = 1;
949 e->sp->data = (u_char *) "1";
951 } else {
952 e->sp->len = 0;
953 e->sp->data = (u_char *) "";
956 e->sp++;
958 e->ip += sizeof(ngx_http_script_regex_code_t);
959 return;
962 e->ip += code->next;
963 return;
966 if (rc == NGX_ERROR) {
967 e->ip = ngx_http_script_exit;
968 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
969 return;
972 if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
973 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
974 "\"%V\" matches \"%V\"", &code->name, &e->line);
977 if (code->test) {
978 if (code->negative_test) {
979 e->sp->len = 0;
980 e->sp->data = (u_char *) "";
982 } else {
983 e->sp->len = 1;
984 e->sp->data = (u_char *) "1";
987 e->sp++;
989 e->ip += sizeof(ngx_http_script_regex_code_t);
990 return;
993 if (code->status) {
994 e->status = code->status;
996 if (!code->redirect) {
997 e->ip = ngx_http_script_exit;
998 return;
1002 if (code->uri) {
1003 r->internal = 1;
1004 r->valid_unparsed_uri = 0;
1006 if (code->break_cycle) {
1007 r->valid_location = 0;
1008 r->uri_changed = 0;
1010 } else {
1011 r->uri_changed = 1;
1015 if (code->lengths == NULL) {
1016 e->buf.len = code->size;
1018 if (code->uri) {
1019 if (r->ncaptures && (r->quoted_uri || r->plus_in_uri)) {
1020 e->buf.len += 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len,
1021 NGX_ESCAPE_ARGS);
1025 for (n = 2; n < r->ncaptures; n += 2) {
1026 e->buf.len += r->captures[n + 1] - r->captures[n];
1029 } else {
1030 ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
1032 le.ip = code->lengths->elts;
1033 le.line = e->line;
1034 le.request = r;
1035 le.quote = code->redirect;
1037 len = 0;
1039 while (*(uintptr_t *) le.ip) {
1040 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1041 len += lcode(&le);
1044 e->buf.len = len;
1045 e->is_args = le.is_args;
1048 if (code->add_args && r->args.len) {
1049 e->buf.len += r->args.len + 1;
1052 e->buf.data = ngx_pnalloc(r->pool, e->buf.len);
1053 if (e->buf.data == NULL) {
1054 e->ip = ngx_http_script_exit;
1055 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1056 return;
1059 e->quote = code->redirect;
1061 e->pos = e->buf.data;
1063 e->ip += sizeof(ngx_http_script_regex_code_t);
1067 void
1068 ngx_http_script_regex_end_code(ngx_http_script_engine_t *e)
1070 u_char *dst, *src;
1071 ngx_http_request_t *r;
1072 ngx_http_script_regex_end_code_t *code;
1074 code = (ngx_http_script_regex_end_code_t *) e->ip;
1076 r = e->request;
1078 e->quote = 0;
1080 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1081 "http script regex end");
1083 if (code->redirect) {
1085 dst = e->buf.data;
1086 src = e->buf.data;
1088 ngx_unescape_uri(&dst, &src, e->pos - e->buf.data,
1089 NGX_UNESCAPE_REDIRECT);
1091 if (src < e->pos) {
1092 dst = ngx_movemem(dst, src, e->pos - src);
1095 e->pos = dst;
1097 if (code->add_args && r->args.len) {
1098 *e->pos++ = (u_char) (code->args ? '&' : '?');
1099 e->pos = ngx_copy(e->pos, r->args.data, r->args.len);
1102 e->buf.len = e->pos - e->buf.data;
1104 if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
1105 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
1106 "rewritten redirect: \"%V\"", &e->buf);
1109 ngx_http_clear_location(r);
1111 r->headers_out.location = ngx_list_push(&r->headers_out.headers);
1112 if (r->headers_out.location == NULL) {
1113 e->ip = ngx_http_script_exit;
1114 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1115 return;
1118 r->headers_out.location->hash = 1;
1119 ngx_str_set(&r->headers_out.location->key, "Location");
1120 r->headers_out.location->value = e->buf;
1122 e->ip += sizeof(ngx_http_script_regex_end_code_t);
1123 return;
1126 if (e->args) {
1127 e->buf.len = e->args - e->buf.data;
1129 if (code->add_args && r->args.len) {
1130 *e->pos++ = '&';
1131 e->pos = ngx_copy(e->pos, r->args.data, r->args.len);
1134 r->args.len = e->pos - e->args;
1135 r->args.data = e->args;
1137 e->args = NULL;
1139 } else {
1140 e->buf.len = e->pos - e->buf.data;
1142 if (!code->add_args) {
1143 r->args.len = 0;
1147 if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
1148 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
1149 "rewritten data: \"%V\", args: \"%V\"",
1150 &e->buf, &r->args);
1153 if (code->uri) {
1154 r->uri = e->buf;
1156 if (r->uri.len == 0) {
1157 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1158 "the rewritten URI has a zero length");
1159 e->ip = ngx_http_script_exit;
1160 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1161 return;
1164 ngx_http_set_exten(r);
1167 e->ip += sizeof(ngx_http_script_regex_end_code_t);
1171 static ngx_int_t
1172 ngx_http_script_add_capture_code(ngx_http_script_compile_t *sc, ngx_uint_t n)
1174 ngx_http_script_copy_capture_code_t *code;
1176 code = ngx_http_script_add_code(*sc->lengths,
1177 sizeof(ngx_http_script_copy_capture_code_t),
1178 NULL);
1179 if (code == NULL) {
1180 return NGX_ERROR;
1183 code->code = (ngx_http_script_code_pt)
1184 ngx_http_script_copy_capture_len_code;
1185 code->n = 2 * n;
1188 code = ngx_http_script_add_code(*sc->values,
1189 sizeof(ngx_http_script_copy_capture_code_t),
1190 &sc->main);
1191 if (code == NULL) {
1192 return NGX_ERROR;
1195 code->code = ngx_http_script_copy_capture_code;
1196 code->n = 2 * n;
1198 if (sc->ncaptures < n) {
1199 sc->ncaptures = n;
1202 return NGX_OK;
1206 size_t
1207 ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e)
1209 int *cap;
1210 u_char *p;
1211 ngx_uint_t n;
1212 ngx_http_request_t *r;
1213 ngx_http_script_copy_capture_code_t *code;
1215 r = e->request;
1217 code = (ngx_http_script_copy_capture_code_t *) e->ip;
1219 e->ip += sizeof(ngx_http_script_copy_capture_code_t);
1221 n = code->n;
1223 if (n < r->ncaptures) {
1225 cap = r->captures;
1227 if ((e->is_args || e->quote)
1228 && (e->request->quoted_uri || e->request->plus_in_uri))
1230 p = r->captures_data;
1232 return cap[n + 1] - cap[n]
1233 + 2 * ngx_escape_uri(NULL, &p[cap[n]], cap[n + 1] - cap[n],
1234 NGX_ESCAPE_ARGS);
1235 } else {
1236 return cap[n + 1] - cap[n];
1240 return 0;
1244 void
1245 ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e)
1247 int *cap;
1248 u_char *p, *pos;
1249 ngx_uint_t n;
1250 ngx_http_request_t *r;
1251 ngx_http_script_copy_capture_code_t *code;
1253 r = e->request;
1255 code = (ngx_http_script_copy_capture_code_t *) e->ip;
1257 e->ip += sizeof(ngx_http_script_copy_capture_code_t);
1259 n = code->n;
1261 pos = e->pos;
1263 if (n < r->ncaptures) {
1265 cap = r->captures;
1266 p = r->captures_data;
1268 if ((e->is_args || e->quote)
1269 && (e->request->quoted_uri || e->request->plus_in_uri))
1271 e->pos = (u_char *) ngx_escape_uri(pos, &p[cap[n]],
1272 cap[n + 1] - cap[n],
1273 NGX_ESCAPE_ARGS);
1274 } else {
1275 e->pos = ngx_copy(pos, &p[cap[n]], cap[n + 1] - cap[n]);
1279 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1280 "http script capture: \"%*s\"", e->pos - pos, pos);
1283 #endif
1286 static ngx_int_t
1287 ngx_http_script_add_full_name_code(ngx_http_script_compile_t *sc)
1289 ngx_http_script_full_name_code_t *code;
1291 code = ngx_http_script_add_code(*sc->lengths,
1292 sizeof(ngx_http_script_full_name_code_t),
1293 NULL);
1294 if (code == NULL) {
1295 return NGX_ERROR;
1298 code->code = (ngx_http_script_code_pt) ngx_http_script_full_name_len_code;
1299 code->conf_prefix = sc->conf_prefix;
1301 code = ngx_http_script_add_code(*sc->values,
1302 sizeof(ngx_http_script_full_name_code_t),
1303 &sc->main);
1304 if (code == NULL) {
1305 return NGX_ERROR;
1308 code->code = ngx_http_script_full_name_code;
1309 code->conf_prefix = sc->conf_prefix;
1311 return NGX_OK;
1315 static size_t
1316 ngx_http_script_full_name_len_code(ngx_http_script_engine_t *e)
1318 ngx_http_script_full_name_code_t *code;
1320 code = (ngx_http_script_full_name_code_t *) e->ip;
1322 e->ip += sizeof(ngx_http_script_full_name_code_t);
1324 return code->conf_prefix ? ngx_cycle->conf_prefix.len:
1325 ngx_cycle->prefix.len;
1329 static void
1330 ngx_http_script_full_name_code(ngx_http_script_engine_t *e)
1332 ngx_http_script_full_name_code_t *code;
1334 ngx_str_t value;
1336 code = (ngx_http_script_full_name_code_t *) e->ip;
1338 value.data = e->buf.data;
1339 value.len = e->pos - e->buf.data;
1341 if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &value, code->conf_prefix)
1342 != NGX_OK)
1344 e->ip = ngx_http_script_exit;
1345 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1346 return;
1349 e->buf = value;
1351 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1352 "http script fullname: \"%V\"", &value);
1354 e->ip += sizeof(ngx_http_script_full_name_code_t);
1358 void
1359 ngx_http_script_return_code(ngx_http_script_engine_t *e)
1361 ngx_http_script_return_code_t *code;
1363 code = (ngx_http_script_return_code_t *) e->ip;
1365 if (code->status < NGX_HTTP_BAD_REQUEST
1366 || code->text.value.len
1367 || code->text.lengths)
1369 e->status = ngx_http_send_response(e->request, code->status, NULL,
1370 &code->text);
1371 } else {
1372 e->status = code->status;
1375 e->ip = ngx_http_script_exit;
1379 void
1380 ngx_http_script_break_code(ngx_http_script_engine_t *e)
1382 e->request->uri_changed = 0;
1384 e->ip = ngx_http_script_exit;
1388 void
1389 ngx_http_script_if_code(ngx_http_script_engine_t *e)
1391 ngx_http_script_if_code_t *code;
1393 code = (ngx_http_script_if_code_t *) e->ip;
1395 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1396 "http script if");
1398 e->sp--;
1400 if (e->sp->len && (e->sp->len !=1 || e->sp->data[0] != '0')) {
1401 if (code->loc_conf) {
1402 e->request->loc_conf = code->loc_conf;
1403 ngx_http_update_location_config(e->request);
1406 e->ip += sizeof(ngx_http_script_if_code_t);
1407 return;
1410 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1411 "http script if: false");
1413 e->ip += code->next;
1417 void
1418 ngx_http_script_equal_code(ngx_http_script_engine_t *e)
1420 ngx_http_variable_value_t *val, *res;
1422 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1423 "http script equal");
1425 e->sp--;
1426 val = e->sp;
1427 res = e->sp - 1;
1429 e->ip += sizeof(uintptr_t);
1431 if (val->len == res->len
1432 && ngx_strncmp(val->data, res->data, res->len) == 0)
1434 *res = ngx_http_variable_true_value;
1435 return;
1438 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1439 "http script equal: no");
1441 *res = ngx_http_variable_null_value;
1445 void
1446 ngx_http_script_not_equal_code(ngx_http_script_engine_t *e)
1448 ngx_http_variable_value_t *val, *res;
1450 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1451 "http script not equal");
1453 e->sp--;
1454 val = e->sp;
1455 res = e->sp - 1;
1457 e->ip += sizeof(uintptr_t);
1459 if (val->len == res->len
1460 && ngx_strncmp(val->data, res->data, res->len) == 0)
1462 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1463 "http script not equal: no");
1465 *res = ngx_http_variable_null_value;
1466 return;
1469 *res = ngx_http_variable_true_value;
1473 void
1474 ngx_http_script_file_code(ngx_http_script_engine_t *e)
1476 ngx_str_t path;
1477 ngx_http_request_t *r;
1478 ngx_open_file_info_t of;
1479 ngx_http_core_loc_conf_t *clcf;
1480 ngx_http_variable_value_t *value;
1481 ngx_http_script_file_code_t *code;
1483 value = e->sp - 1;
1485 code = (ngx_http_script_file_code_t *) e->ip;
1486 e->ip += sizeof(ngx_http_script_file_code_t);
1488 path.len = value->len - 1;
1489 path.data = value->data;
1491 r = e->request;
1493 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1494 "http script file op %p \"%V\"", code->op, &path);
1496 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1498 ngx_memzero(&of, sizeof(ngx_open_file_info_t));
1500 of.read_ahead = clcf->read_ahead;
1501 of.directio = clcf->directio;
1502 of.valid = clcf->open_file_cache_valid;
1503 of.min_uses = clcf->open_file_cache_min_uses;
1504 of.test_only = 1;
1505 of.errors = clcf->open_file_cache_errors;
1506 of.events = clcf->open_file_cache_events;
1508 if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
1509 != NGX_OK)
1511 if (of.err != NGX_ENOENT
1512 && of.err != NGX_ENOTDIR
1513 && of.err != NGX_ENAMETOOLONG)
1515 ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
1516 "%s \"%s\" failed", of.failed, value->data);
1519 switch (code->op) {
1521 case ngx_http_script_file_plain:
1522 case ngx_http_script_file_dir:
1523 case ngx_http_script_file_exists:
1524 case ngx_http_script_file_exec:
1525 goto false_value;
1527 case ngx_http_script_file_not_plain:
1528 case ngx_http_script_file_not_dir:
1529 case ngx_http_script_file_not_exists:
1530 case ngx_http_script_file_not_exec:
1531 goto true_value;
1534 goto false_value;
1537 switch (code->op) {
1538 case ngx_http_script_file_plain:
1539 if (of.is_file) {
1540 goto true_value;
1542 goto false_value;
1544 case ngx_http_script_file_not_plain:
1545 if (of.is_file) {
1546 goto false_value;
1548 goto true_value;
1550 case ngx_http_script_file_dir:
1551 if (of.is_dir) {
1552 goto true_value;
1554 goto false_value;
1556 case ngx_http_script_file_not_dir:
1557 if (of.is_dir) {
1558 goto false_value;
1560 goto true_value;
1562 case ngx_http_script_file_exists:
1563 if (of.is_file || of.is_dir || of.is_link) {
1564 goto true_value;
1566 goto false_value;
1568 case ngx_http_script_file_not_exists:
1569 if (of.is_file || of.is_dir || of.is_link) {
1570 goto false_value;
1572 goto true_value;
1574 case ngx_http_script_file_exec:
1575 if (of.is_exec) {
1576 goto true_value;
1578 goto false_value;
1580 case ngx_http_script_file_not_exec:
1581 if (of.is_exec) {
1582 goto false_value;
1584 goto true_value;
1587 false_value:
1589 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1590 "http script file op false");
1592 *value = ngx_http_variable_null_value;
1593 return;
1595 true_value:
1597 *value = ngx_http_variable_true_value;
1598 return;
1602 void
1603 ngx_http_script_complex_value_code(ngx_http_script_engine_t *e)
1605 size_t len;
1606 ngx_http_script_engine_t le;
1607 ngx_http_script_len_code_pt lcode;
1608 ngx_http_script_complex_value_code_t *code;
1610 code = (ngx_http_script_complex_value_code_t *) e->ip;
1612 e->ip += sizeof(ngx_http_script_complex_value_code_t);
1614 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1615 "http script complex value");
1617 ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
1619 le.ip = code->lengths->elts;
1620 le.line = e->line;
1621 le.request = e->request;
1622 le.quote = e->quote;
1624 for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {
1625 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1628 e->buf.len = len;
1629 e->buf.data = ngx_pnalloc(e->request->pool, len);
1630 if (e->buf.data == NULL) {
1631 e->ip = ngx_http_script_exit;
1632 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1633 return;
1636 e->pos = e->buf.data;
1638 e->sp->len = e->buf.len;
1639 e->sp->data = e->buf.data;
1640 e->sp++;
1644 void
1645 ngx_http_script_value_code(ngx_http_script_engine_t *e)
1647 ngx_http_script_value_code_t *code;
1649 code = (ngx_http_script_value_code_t *) e->ip;
1651 e->ip += sizeof(ngx_http_script_value_code_t);
1653 e->sp->len = code->text_len;
1654 e->sp->data = (u_char *) code->text_data;
1656 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1657 "http script value: \"%v\"", e->sp);
1659 e->sp++;
1663 void
1664 ngx_http_script_set_var_code(ngx_http_script_engine_t *e)
1666 ngx_http_request_t *r;
1667 ngx_http_script_var_code_t *code;
1669 code = (ngx_http_script_var_code_t *) e->ip;
1671 e->ip += sizeof(ngx_http_script_var_code_t);
1673 r = e->request;
1675 e->sp--;
1677 r->variables[code->index].len = e->sp->len;
1678 r->variables[code->index].valid = 1;
1679 r->variables[code->index].no_cacheable = 0;
1680 r->variables[code->index].not_found = 0;
1681 r->variables[code->index].data = e->sp->data;
1683 #if (NGX_DEBUG)
1685 ngx_http_variable_t *v;
1686 ngx_http_core_main_conf_t *cmcf;
1688 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
1690 v = cmcf->variables.elts;
1692 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1693 "http script set $%V", &v[code->index].name);
1695 #endif
1699 void
1700 ngx_http_script_var_set_handler_code(ngx_http_script_engine_t *e)
1702 ngx_http_script_var_handler_code_t *code;
1704 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1705 "http script set var handler");
1707 code = (ngx_http_script_var_handler_code_t *) e->ip;
1709 e->ip += sizeof(ngx_http_script_var_handler_code_t);
1711 e->sp--;
1713 code->handler(e->request, e->sp, code->data);
1717 void
1718 ngx_http_script_var_code(ngx_http_script_engine_t *e)
1720 ngx_http_variable_value_t *value;
1721 ngx_http_script_var_code_t *code;
1723 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1724 "http script var");
1726 code = (ngx_http_script_var_code_t *) e->ip;
1728 e->ip += sizeof(ngx_http_script_var_code_t);
1730 value = ngx_http_get_flushed_variable(e->request, code->index);
1732 if (value && !value->not_found) {
1733 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1734 "http script var: \"%v\"", value);
1736 *e->sp = *value;
1737 e->sp++;
1739 return;
1742 *e->sp = ngx_http_variable_null_value;
1743 e->sp++;
1747 void
1748 ngx_http_script_nop_code(ngx_http_script_engine_t *e)
1750 e->ip += sizeof(uintptr_t);