nginx 0.8.26
[nginx.git] / src / http / ngx_http_script.c
blobaa03df00752016f8d603013592189c68661a2a38
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 ngx_uint_t
215 ngx_http_script_variables_count(ngx_str_t *value)
217 ngx_uint_t i, n;
219 for (n = 0, i = 0; i < value->len; i++) {
220 if (value->data[i] == '$') {
221 n++;
225 return n;
229 ngx_int_t
230 ngx_http_script_compile(ngx_http_script_compile_t *sc)
232 u_char ch;
233 ngx_str_t name;
234 ngx_uint_t i, bracket;
236 if (ngx_http_script_init_arrays(sc) != NGX_OK) {
237 return NGX_ERROR;
240 for (i = 0; i < sc->source->len; /* void */ ) {
242 name.len = 0;
244 if (sc->source->data[i] == '$') {
246 if (++i == sc->source->len) {
247 goto invalid_variable;
250 #if (NGX_PCRE)
252 ngx_uint_t n;
254 if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') {
256 n = sc->source->data[i] - '0';
258 if (sc->captures_mask & (1 << n)) {
259 sc->dup_capture = 1;
262 sc->captures_mask |= 1 << n;
264 if (ngx_http_script_add_capture_code(sc, n) != NGX_OK) {
265 return NGX_ERROR;
268 i++;
270 continue;
273 #endif
275 if (sc->source->data[i] == '{') {
276 bracket = 1;
278 if (++i == sc->source->len) {
279 goto invalid_variable;
282 name.data = &sc->source->data[i];
284 } else {
285 bracket = 0;
286 name.data = &sc->source->data[i];
289 for ( /* void */ ; i < sc->source->len; i++, name.len++) {
290 ch = sc->source->data[i];
292 if (ch == '}' && bracket) {
293 i++;
294 bracket = 0;
295 break;
298 if ((ch >= 'A' && ch <= 'Z')
299 || (ch >= 'a' && ch <= 'z')
300 || (ch >= '0' && ch <= '9')
301 || ch == '_')
303 continue;
306 break;
309 if (bracket) {
310 ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0,
311 "the closing bracket in \"%V\" "
312 "variable is missing", &name);
313 return NGX_ERROR;
316 if (name.len == 0) {
317 goto invalid_variable;
320 sc->variables++;
322 if (ngx_http_script_add_var_code(sc, &name) != NGX_OK) {
323 return NGX_ERROR;
326 continue;
329 if (sc->source->data[i] == '?' && sc->compile_args) {
330 sc->args = 1;
331 sc->compile_args = 0;
333 if (ngx_http_script_add_args_code(sc) != NGX_OK) {
334 return NGX_ERROR;
337 i++;
339 continue;
342 name.data = &sc->source->data[i];
344 while (i < sc->source->len) {
346 if (sc->source->data[i] == '$') {
347 break;
350 if (sc->source->data[i] == '?') {
352 sc->args = 1;
354 if (sc->compile_args) {
355 break;
359 i++;
360 name.len++;
363 sc->size += name.len;
365 if (ngx_http_script_add_copy_code(sc, &name, (i == sc->source->len))
366 != NGX_OK)
368 return NGX_ERROR;
372 return ngx_http_script_done(sc);
374 invalid_variable:
376 ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, "invalid variable name");
378 return NGX_ERROR;
382 u_char *
383 ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value,
384 void *code_lengths, size_t len, void *code_values)
386 ngx_uint_t i;
387 ngx_http_script_code_pt code;
388 ngx_http_script_len_code_pt lcode;
389 ngx_http_script_engine_t e;
390 ngx_http_core_main_conf_t *cmcf;
392 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
394 for (i = 0; i < cmcf->variables.nelts; i++) {
395 if (r->variables[i].no_cacheable) {
396 r->variables[i].valid = 0;
397 r->variables[i].not_found = 0;
401 ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
403 e.ip = code_lengths;
404 e.request = r;
405 e.flushed = 1;
407 while (*(uintptr_t *) e.ip) {
408 lcode = *(ngx_http_script_len_code_pt *) e.ip;
409 len += lcode(&e);
413 value->len = len;
414 value->data = ngx_pnalloc(r->pool, len);
415 if (value->data == NULL) {
416 return NULL;
419 e.ip = code_values;
420 e.pos = value->data;
422 while (*(uintptr_t *) e.ip) {
423 code = *(ngx_http_script_code_pt *) e.ip;
424 code((ngx_http_script_engine_t *) &e);
427 return e.pos;
431 void
432 ngx_http_script_flush_no_cacheable_variables(ngx_http_request_t *r,
433 ngx_array_t *indices)
435 ngx_uint_t n, *index;
437 if (indices) {
438 index = indices->elts;
439 for (n = 0; n < indices->nelts; n++) {
440 if (r->variables[index[n]].no_cacheable) {
441 r->variables[index[n]].valid = 0;
442 r->variables[index[n]].not_found = 0;
449 static ngx_int_t
450 ngx_http_script_init_arrays(ngx_http_script_compile_t *sc)
452 ngx_uint_t n;
454 if (sc->flushes && *sc->flushes == NULL) {
455 n = sc->variables ? sc->variables : 1;
456 *sc->flushes = ngx_array_create(sc->cf->pool, n, sizeof(ngx_uint_t));
457 if (*sc->flushes == NULL) {
458 return NGX_ERROR;
462 if (*sc->lengths == NULL) {
463 n = sc->variables * (2 * sizeof(ngx_http_script_copy_code_t)
464 + sizeof(ngx_http_script_var_code_t))
465 + sizeof(uintptr_t);
467 *sc->lengths = ngx_array_create(sc->cf->pool, n, 1);
468 if (*sc->lengths == NULL) {
469 return NGX_ERROR;
473 if (*sc->values == NULL) {
474 n = (sc->variables * (2 * sizeof(ngx_http_script_copy_code_t)
475 + sizeof(ngx_http_script_var_code_t))
476 + sizeof(uintptr_t)
477 + sc->source->len
478 + sizeof(uintptr_t) - 1)
479 & ~(sizeof(uintptr_t) - 1);
481 *sc->values = ngx_array_create(sc->cf->pool, n, 1);
482 if (*sc->values == NULL) {
483 return NGX_ERROR;
487 sc->variables = 0;
489 return NGX_OK;
493 static ngx_int_t
494 ngx_http_script_done(ngx_http_script_compile_t *sc)
496 ngx_str_t zero;
497 uintptr_t *code;
499 if (sc->zero) {
501 zero.len = 1;
502 zero.data = (u_char *) "\0";
504 if (ngx_http_script_add_copy_code(sc, &zero, 0) != NGX_OK) {
505 return NGX_ERROR;
509 if (sc->conf_prefix || sc->root_prefix) {
510 if (ngx_http_script_add_full_name_code(sc) != NGX_OK) {
511 return NGX_ERROR;
515 if (sc->complete_lengths) {
516 code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL);
517 if (code == NULL) {
518 return NGX_ERROR;
521 *code = (uintptr_t) NULL;
524 if (sc->complete_values) {
525 code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t),
526 &sc->main);
527 if (code == NULL) {
528 return NGX_ERROR;
531 *code = (uintptr_t) NULL;
534 return NGX_OK;
538 void *
539 ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size)
541 if (*codes == NULL) {
542 *codes = ngx_array_create(pool, 256, 1);
543 if (*codes == NULL) {
544 return NULL;
548 return ngx_array_push_n(*codes, size);
552 void *
553 ngx_http_script_add_code(ngx_array_t *codes, size_t size, void *code)
555 u_char *elts, **p;
556 void *new;
558 elts = codes->elts;
560 new = ngx_array_push_n(codes, size);
561 if (new == NULL) {
562 return NULL;
565 if (code) {
566 if (elts != codes->elts) {
567 p = code;
568 *p += (u_char *) codes->elts - elts;
572 return new;
576 static ngx_int_t
577 ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc, ngx_str_t *value,
578 ngx_uint_t last)
580 u_char *p;
581 size_t size, len, zero;
582 ngx_http_script_copy_code_t *code;
584 zero = (sc->zero && last);
585 len = value->len + zero;
587 code = ngx_http_script_add_code(*sc->lengths,
588 sizeof(ngx_http_script_copy_code_t), NULL);
589 if (code == NULL) {
590 return NGX_ERROR;
593 code->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
594 code->len = len;
596 size = (sizeof(ngx_http_script_copy_code_t) + len + sizeof(uintptr_t) - 1)
597 & ~(sizeof(uintptr_t) - 1);
599 code = ngx_http_script_add_code(*sc->values, size, &sc->main);
600 if (code == NULL) {
601 return NGX_ERROR;
604 code->code = ngx_http_script_copy_code;
605 code->len = len;
607 p = ngx_cpymem((u_char *) code + sizeof(ngx_http_script_copy_code_t),
608 value->data, value->len);
610 if (zero) {
611 *p = '\0';
612 sc->zero = 0;
615 return NGX_OK;
619 size_t
620 ngx_http_script_copy_len_code(ngx_http_script_engine_t *e)
622 ngx_http_script_copy_code_t *code;
624 code = (ngx_http_script_copy_code_t *) e->ip;
626 e->ip += sizeof(ngx_http_script_copy_code_t);
628 return code->len;
632 void
633 ngx_http_script_copy_code(ngx_http_script_engine_t *e)
635 u_char *p;
636 ngx_http_script_copy_code_t *code;
638 code = (ngx_http_script_copy_code_t *) e->ip;
640 p = e->pos;
642 if (!e->skip) {
643 e->pos = ngx_copy(p, e->ip + sizeof(ngx_http_script_copy_code_t),
644 code->len);
647 e->ip += sizeof(ngx_http_script_copy_code_t)
648 + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));
650 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
651 "http script copy: \"%*s\"", e->pos - p, p);
655 static ngx_int_t
656 ngx_http_script_add_var_code(ngx_http_script_compile_t *sc, ngx_str_t *name)
658 ngx_int_t index, *p;
659 ngx_http_script_var_code_t *code;
661 index = ngx_http_get_variable_index(sc->cf, name);
663 if (index == NGX_ERROR) {
664 return NGX_ERROR;
667 if (sc->flushes) {
668 p = ngx_array_push(*sc->flushes);
669 if (p == NULL) {
670 return NGX_ERROR;
673 *p = index;
676 code = ngx_http_script_add_code(*sc->lengths,
677 sizeof(ngx_http_script_var_code_t), NULL);
678 if (code == NULL) {
679 return NGX_ERROR;
682 code->code = (ngx_http_script_code_pt) ngx_http_script_copy_var_len_code;
683 code->index = (uintptr_t) index;
685 code = ngx_http_script_add_code(*sc->values,
686 sizeof(ngx_http_script_var_code_t),
687 &sc->main);
688 if (code == NULL) {
689 return NGX_ERROR;
692 code->code = ngx_http_script_copy_var_code;
693 code->index = (uintptr_t) index;
695 return NGX_OK;
699 size_t
700 ngx_http_script_copy_var_len_code(ngx_http_script_engine_t *e)
702 ngx_http_variable_value_t *value;
703 ngx_http_script_var_code_t *code;
705 code = (ngx_http_script_var_code_t *) e->ip;
707 e->ip += sizeof(ngx_http_script_var_code_t);
709 if (e->flushed) {
710 value = ngx_http_get_indexed_variable(e->request, code->index);
712 } else {
713 value = ngx_http_get_flushed_variable(e->request, code->index);
716 if (value && !value->not_found) {
717 return value->len;
720 return 0;
724 void
725 ngx_http_script_copy_var_code(ngx_http_script_engine_t *e)
727 u_char *p;
728 ngx_http_variable_value_t *value;
729 ngx_http_script_var_code_t *code;
731 code = (ngx_http_script_var_code_t *) e->ip;
733 e->ip += sizeof(ngx_http_script_var_code_t);
735 if (!e->skip) {
737 if (e->flushed) {
738 value = ngx_http_get_indexed_variable(e->request, code->index);
740 } else {
741 value = ngx_http_get_flushed_variable(e->request, code->index);
744 if (value && !value->not_found) {
745 p = e->pos;
746 e->pos = ngx_copy(p, value->data, value->len);
748 ngx_log_debug2(NGX_LOG_DEBUG_HTTP,
749 e->request->connection->log, 0,
750 "http script var: \"%*s\"", e->pos - p, p);
756 static ngx_int_t
757 ngx_http_script_add_args_code(ngx_http_script_compile_t *sc)
759 uintptr_t *code;
761 code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL);
762 if (code == NULL) {
763 return NGX_ERROR;
766 *code = (uintptr_t) ngx_http_script_mark_args_code;
768 code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t), &sc->main);
769 if (code == NULL) {
770 return NGX_ERROR;
773 *code = (uintptr_t) ngx_http_script_start_args_code;
775 return NGX_OK;
779 size_t
780 ngx_http_script_mark_args_code(ngx_http_script_engine_t *e)
782 e->is_args = 1;
783 e->ip += sizeof(uintptr_t);
785 return 1;
789 void
790 ngx_http_script_start_args_code(ngx_http_script_engine_t *e)
792 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
793 "http script args");
795 e->is_args = 1;
796 e->args = e->pos;
797 e->ip += sizeof(uintptr_t);
801 #if (NGX_PCRE)
803 void
804 ngx_http_script_regex_start_code(ngx_http_script_engine_t *e)
806 size_t len;
807 ngx_int_t rc;
808 ngx_uint_t n;
809 ngx_http_request_t *r;
810 ngx_http_script_engine_t le;
811 ngx_http_script_len_code_pt lcode;
812 ngx_http_script_regex_code_t *code;
814 code = (ngx_http_script_regex_code_t *) e->ip;
816 r = e->request;
818 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
819 "http script regex: \"%V\"", &code->name);
821 if (code->uri) {
822 e->line = r->uri;
823 } else {
824 e->sp--;
825 e->line.len = e->sp->len;
826 e->line.data = e->sp->data;
829 rc = ngx_http_regex_exec(r, code->regex, &e->line);
831 if (rc == NGX_DECLINED) {
832 if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
833 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
834 "\"%V\" does not match \"%V\"",
835 &code->name, &e->line);
838 r->ncaptures = 0;
840 if (code->test) {
841 if (code->negative_test) {
842 e->sp->len = 1;
843 e->sp->data = (u_char *) "1";
845 } else {
846 e->sp->len = 0;
847 e->sp->data = (u_char *) "";
850 e->sp++;
852 e->ip += sizeof(ngx_http_script_regex_code_t);
853 return;
856 e->ip += code->next;
857 return;
860 if (rc == NGX_ERROR) {
861 e->ip = ngx_http_script_exit;
862 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
863 return;
866 if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
867 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
868 "\"%V\" matches \"%V\"", &code->name, &e->line);
871 if (code->test) {
872 if (code->negative_test) {
873 e->sp->len = 0;
874 e->sp->data = (u_char *) "";
876 } else {
877 e->sp->len = 1;
878 e->sp->data = (u_char *) "1";
881 e->sp++;
883 e->ip += sizeof(ngx_http_script_regex_code_t);
884 return;
887 if (code->status) {
888 e->status = code->status;
890 if (!code->redirect) {
891 e->ip = ngx_http_script_exit;
892 return;
896 if (code->uri) {
897 r->internal = 1;
898 r->valid_unparsed_uri = 0;
900 if (code->break_cycle) {
901 r->valid_location = 0;
902 r->uri_changed = 0;
904 } else {
905 r->uri_changed = 1;
909 if (code->lengths == NULL) {
910 e->buf.len = code->size;
912 if (code->uri) {
913 if (r->ncaptures && (r->quoted_uri || r->plus_in_uri)) {
914 e->buf.len += 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len,
915 NGX_ESCAPE_ARGS);
919 for (n = 2; n < r->ncaptures; n += 2) {
920 e->buf.len += r->captures[n + 1] - r->captures[n];
923 } else {
924 ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
926 le.ip = code->lengths->elts;
927 le.line = e->line;
928 le.request = r;
929 le.quote = code->redirect;
931 len = 0;
933 while (*(uintptr_t *) le.ip) {
934 lcode = *(ngx_http_script_len_code_pt *) le.ip;
935 len += lcode(&le);
938 e->buf.len = len;
939 e->is_args = le.is_args;
942 if (code->add_args && r->args.len) {
943 e->buf.len += r->args.len + 1;
946 e->buf.data = ngx_pnalloc(r->pool, e->buf.len);
947 if (e->buf.data == NULL) {
948 e->ip = ngx_http_script_exit;
949 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
950 return;
953 e->quote = code->redirect;
955 e->pos = e->buf.data;
957 e->ip += sizeof(ngx_http_script_regex_code_t);
961 void
962 ngx_http_script_regex_end_code(ngx_http_script_engine_t *e)
964 u_char *dst, *src;
965 ngx_http_request_t *r;
966 ngx_http_script_regex_end_code_t *code;
968 code = (ngx_http_script_regex_end_code_t *) e->ip;
970 r = e->request;
972 e->quote = 0;
974 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
975 "http script regex end");
977 if (code->redirect) {
979 dst = e->buf.data;
980 src = e->buf.data;
982 ngx_unescape_uri(&dst, &src, e->pos - e->buf.data,
983 NGX_UNESCAPE_REDIRECT);
985 if (src < e->pos) {
986 dst = ngx_copy(dst, src, e->pos - src);
989 e->pos = dst;
991 if (code->add_args && r->args.len) {
992 *e->pos++ = (u_char) (code->args ? '&' : '?');
993 e->pos = ngx_copy(e->pos, r->args.data, r->args.len);
996 e->buf.len = e->pos - e->buf.data;
998 if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
999 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
1000 "rewritten redirect: \"%V\"", &e->buf);
1003 r->headers_out.location = ngx_list_push(&r->headers_out.headers);
1004 if (r->headers_out.location == NULL) {
1005 e->ip = ngx_http_script_exit;
1006 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1007 return;
1010 r->headers_out.location->hash = 1;
1011 r->headers_out.location->key.len = sizeof("Location") - 1;
1012 r->headers_out.location->key.data = (u_char *) "Location";
1013 r->headers_out.location->value = e->buf;
1015 e->ip += sizeof(ngx_http_script_regex_end_code_t);
1016 return;
1019 if (e->args) {
1020 e->buf.len = e->args - e->buf.data;
1022 if (code->add_args && r->args.len) {
1023 *e->pos++ = '&';
1024 e->pos = ngx_copy(e->pos, r->args.data, r->args.len);
1027 r->args.len = e->pos - e->args;
1028 r->args.data = e->args;
1030 e->args = NULL;
1032 } else {
1033 e->buf.len = e->pos - e->buf.data;
1035 if (!code->add_args) {
1036 r->args.len = 0;
1040 if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
1041 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
1042 "rewritten data: \"%V\", args: \"%V\"",
1043 &e->buf, &r->args);
1046 if (code->uri) {
1047 r->uri = e->buf;
1049 if (r->uri.len == 0) {
1050 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1051 "the rewritten URI has a zero length");
1052 e->ip = ngx_http_script_exit;
1053 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1054 return;
1057 ngx_http_set_exten(r);
1060 e->ip += sizeof(ngx_http_script_regex_end_code_t);
1064 static ngx_int_t
1065 ngx_http_script_add_capture_code(ngx_http_script_compile_t *sc, ngx_uint_t n)
1067 ngx_http_script_copy_capture_code_t *code;
1069 code = ngx_http_script_add_code(*sc->lengths,
1070 sizeof(ngx_http_script_copy_capture_code_t),
1071 NULL);
1072 if (code == NULL) {
1073 return NGX_ERROR;
1076 code->code = (ngx_http_script_code_pt)
1077 ngx_http_script_copy_capture_len_code;
1078 code->n = 2 * n;
1081 code = ngx_http_script_add_code(*sc->values,
1082 sizeof(ngx_http_script_copy_capture_code_t),
1083 &sc->main);
1084 if (code == NULL) {
1085 return NGX_ERROR;
1088 code->code = ngx_http_script_copy_capture_code;
1089 code->n = 2 * n;
1091 if (sc->ncaptures < n) {
1092 sc->ncaptures = n;
1095 return NGX_OK;
1099 size_t
1100 ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e)
1102 int *cap;
1103 u_char *p;
1104 ngx_uint_t n;
1105 ngx_http_request_t *r;
1106 ngx_http_script_copy_capture_code_t *code;
1108 r = e->request;
1110 code = (ngx_http_script_copy_capture_code_t *) e->ip;
1112 e->ip += sizeof(ngx_http_script_copy_capture_code_t);
1114 n = code->n;
1116 if (n < r->ncaptures) {
1118 cap = r->captures;
1120 if ((e->is_args || e->quote)
1121 && (e->request->quoted_uri || e->request->plus_in_uri))
1123 p = r->captures_data;
1125 return cap[n + 1] - cap[n]
1126 + 2 * ngx_escape_uri(NULL, &p[cap[n]], cap[n + 1] - cap[n],
1127 NGX_ESCAPE_ARGS);
1128 } else {
1129 return cap[n + 1] - cap[n];
1133 return 0;
1137 void
1138 ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e)
1140 int *cap;
1141 u_char *p, *pos;
1142 ngx_uint_t n;
1143 ngx_http_request_t *r;
1144 ngx_http_script_copy_capture_code_t *code;
1146 r = e->request;
1148 code = (ngx_http_script_copy_capture_code_t *) e->ip;
1150 e->ip += sizeof(ngx_http_script_copy_capture_code_t);
1152 n = code->n;
1154 pos = e->pos;
1156 if (n < r->ncaptures) {
1158 cap = r->captures;
1159 p = r->captures_data;
1161 if ((e->is_args || e->quote)
1162 && (e->request->quoted_uri || e->request->plus_in_uri))
1164 e->pos = (u_char *) ngx_escape_uri(pos, &p[cap[n]],
1165 cap[n + 1] - cap[n],
1166 NGX_ESCAPE_ARGS);
1167 } else {
1168 e->pos = ngx_copy(pos, &p[cap[n]], cap[n + 1] - cap[n]);
1172 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1173 "http script capture: \"%*s\"", e->pos - pos, pos);
1176 #endif
1179 static ngx_int_t
1180 ngx_http_script_add_full_name_code(ngx_http_script_compile_t *sc)
1182 ngx_http_script_full_name_code_t *code;
1184 code = ngx_http_script_add_code(*sc->lengths,
1185 sizeof(ngx_http_script_full_name_code_t),
1186 NULL);
1187 if (code == NULL) {
1188 return NGX_ERROR;
1191 code->code = (ngx_http_script_code_pt) ngx_http_script_full_name_len_code;
1192 code->conf_prefix = sc->conf_prefix;
1194 code = ngx_http_script_add_code(*sc->values,
1195 sizeof(ngx_http_script_full_name_code_t),
1196 &sc->main);
1197 if (code == NULL) {
1198 return NGX_ERROR;
1201 code->code = ngx_http_script_full_name_code;
1202 code->conf_prefix = sc->conf_prefix;
1204 return NGX_OK;
1208 static size_t
1209 ngx_http_script_full_name_len_code(ngx_http_script_engine_t *e)
1211 ngx_http_script_full_name_code_t *code;
1213 code = (ngx_http_script_full_name_code_t *) e->ip;
1215 e->ip += sizeof(ngx_http_script_full_name_code_t);
1217 return code->conf_prefix ? ngx_cycle->conf_prefix.len:
1218 ngx_cycle->prefix.len;
1222 static void
1223 ngx_http_script_full_name_code(ngx_http_script_engine_t *e)
1225 ngx_http_script_full_name_code_t *code;
1227 ngx_str_t value;
1229 code = (ngx_http_script_full_name_code_t *) e->ip;
1231 value.data = e->buf.data;
1232 value.len = e->pos - e->buf.data;
1234 if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &value, code->conf_prefix)
1235 != NGX_OK)
1237 e->ip = ngx_http_script_exit;
1238 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1239 return;
1242 e->buf = value;
1244 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1245 "http script fullname: \"%V\"", &value);
1247 e->ip += sizeof(ngx_http_script_full_name_code_t);
1251 void
1252 ngx_http_script_return_code(ngx_http_script_engine_t *e)
1254 ngx_http_script_return_code_t *code;
1256 code = (ngx_http_script_return_code_t *) e->ip;
1258 e->status = code->status;
1260 if (code->status == NGX_HTTP_NO_CONTENT) {
1261 e->request->header_only = 1;
1262 e->request->zero_body = 1;
1265 e->ip += sizeof(ngx_http_script_return_code_t) - sizeof(uintptr_t);
1269 void
1270 ngx_http_script_break_code(ngx_http_script_engine_t *e)
1272 e->request->uri_changed = 0;
1274 e->ip = ngx_http_script_exit;
1278 void
1279 ngx_http_script_if_code(ngx_http_script_engine_t *e)
1281 ngx_http_script_if_code_t *code;
1283 code = (ngx_http_script_if_code_t *) e->ip;
1285 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1286 "http script if");
1288 e->sp--;
1290 if (e->sp->len && e->sp->data[0] != '0') {
1291 if (code->loc_conf) {
1292 e->request->loc_conf = code->loc_conf;
1293 ngx_http_update_location_config(e->request);
1296 e->ip += sizeof(ngx_http_script_if_code_t);
1297 return;
1300 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1301 "http script if: false");
1303 e->ip += code->next;
1307 void
1308 ngx_http_script_equal_code(ngx_http_script_engine_t *e)
1310 ngx_http_variable_value_t *val, *res;
1312 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1313 "http script equal");
1315 e->sp--;
1316 val = e->sp;
1317 res = e->sp - 1;
1319 e->ip += sizeof(uintptr_t);
1321 if (val->len == res->len
1322 && ngx_strncmp(val->data, res->data, res->len) == 0)
1324 *res = ngx_http_variable_true_value;
1325 return;
1328 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1329 "http script equal: no");
1331 *res = ngx_http_variable_null_value;
1335 void
1336 ngx_http_script_not_equal_code(ngx_http_script_engine_t *e)
1338 ngx_http_variable_value_t *val, *res;
1340 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1341 "http script not equal");
1343 e->sp--;
1344 val = e->sp;
1345 res = e->sp - 1;
1347 e->ip += sizeof(uintptr_t);
1349 if (val->len == res->len
1350 && ngx_strncmp(val->data, res->data, res->len) == 0)
1352 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1353 "http script not equal: no");
1355 *res = ngx_http_variable_null_value;
1356 return;
1359 *res = ngx_http_variable_true_value;
1363 void
1364 ngx_http_script_file_code(ngx_http_script_engine_t *e)
1366 ngx_str_t path;
1367 ngx_http_request_t *r;
1368 ngx_open_file_info_t of;
1369 ngx_http_core_loc_conf_t *clcf;
1370 ngx_http_variable_value_t *value;
1371 ngx_http_script_file_code_t *code;
1373 value = e->sp - 1;
1375 code = (ngx_http_script_file_code_t *) e->ip;
1376 e->ip += sizeof(ngx_http_script_file_code_t);
1378 path.len = value->len - 1;
1379 path.data = value->data;
1381 r = e->request;
1383 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1384 "http script file op %p \"%V\"", code->op, &path);
1386 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1388 ngx_memzero(&of, sizeof(ngx_open_file_info_t));
1390 of.read_ahead = clcf->read_ahead;
1391 of.directio = clcf->directio;
1392 of.valid = clcf->open_file_cache_valid;
1393 of.min_uses = clcf->open_file_cache_min_uses;
1394 of.test_only = 1;
1395 of.errors = clcf->open_file_cache_errors;
1396 of.events = clcf->open_file_cache_events;
1398 if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
1399 != NGX_OK)
1401 if (of.err != NGX_ENOENT
1402 && of.err != NGX_ENOTDIR
1403 && of.err != NGX_ENAMETOOLONG)
1405 ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
1406 "%s \"%s\" failed", of.failed, value->data);
1409 switch (code->op) {
1411 case ngx_http_script_file_plain:
1412 case ngx_http_script_file_dir:
1413 case ngx_http_script_file_exists:
1414 case ngx_http_script_file_exec:
1415 goto false_value;
1417 case ngx_http_script_file_not_plain:
1418 case ngx_http_script_file_not_dir:
1419 case ngx_http_script_file_not_exists:
1420 case ngx_http_script_file_not_exec:
1421 goto true_value;
1424 goto false_value;
1427 switch (code->op) {
1428 case ngx_http_script_file_plain:
1429 if (of.is_file) {
1430 goto true_value;
1432 goto false_value;
1434 case ngx_http_script_file_not_plain:
1435 if (of.is_file) {
1436 goto false_value;
1438 goto true_value;
1440 case ngx_http_script_file_dir:
1441 if (of.is_dir) {
1442 goto true_value;
1444 goto false_value;
1446 case ngx_http_script_file_not_dir:
1447 if (of.is_dir) {
1448 goto false_value;
1450 goto true_value;
1452 case ngx_http_script_file_exists:
1453 if (of.is_file || of.is_dir || of.is_link) {
1454 goto true_value;
1456 goto false_value;
1458 case ngx_http_script_file_not_exists:
1459 if (of.is_file || of.is_dir || of.is_link) {
1460 goto false_value;
1462 goto true_value;
1464 case ngx_http_script_file_exec:
1465 if (of.is_exec) {
1466 goto true_value;
1468 goto false_value;
1470 case ngx_http_script_file_not_exec:
1471 if (of.is_exec) {
1472 goto false_value;
1474 goto true_value;
1477 false_value:
1479 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1480 "http script file op false");
1482 *value = ngx_http_variable_null_value;
1483 return;
1485 true_value:
1487 *value = ngx_http_variable_true_value;
1488 return;
1492 void
1493 ngx_http_script_complex_value_code(ngx_http_script_engine_t *e)
1495 size_t len;
1496 ngx_http_script_engine_t le;
1497 ngx_http_script_len_code_pt lcode;
1498 ngx_http_script_complex_value_code_t *code;
1500 code = (ngx_http_script_complex_value_code_t *) e->ip;
1502 e->ip += sizeof(ngx_http_script_complex_value_code_t);
1504 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1505 "http script complex value");
1507 ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
1509 le.ip = code->lengths->elts;
1510 le.line = e->line;
1511 le.request = e->request;
1512 le.quote = e->quote;
1514 for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {
1515 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1518 e->buf.len = len;
1519 e->buf.data = ngx_pnalloc(e->request->pool, len);
1520 if (e->buf.data == NULL) {
1521 e->ip = ngx_http_script_exit;
1522 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1523 return;
1526 e->pos = e->buf.data;
1528 e->sp->len = e->buf.len;
1529 e->sp->data = e->buf.data;
1530 e->sp++;
1534 void
1535 ngx_http_script_value_code(ngx_http_script_engine_t *e)
1537 ngx_http_script_value_code_t *code;
1539 code = (ngx_http_script_value_code_t *) e->ip;
1541 e->ip += sizeof(ngx_http_script_value_code_t);
1543 e->sp->len = code->text_len;
1544 e->sp->data = (u_char *) code->text_data;
1546 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1547 "http script value: \"%v\"", e->sp);
1549 e->sp++;
1553 void
1554 ngx_http_script_set_var_code(ngx_http_script_engine_t *e)
1556 ngx_http_request_t *r;
1557 ngx_http_script_var_code_t *code;
1559 code = (ngx_http_script_var_code_t *) e->ip;
1561 e->ip += sizeof(ngx_http_script_var_code_t);
1563 r = e->request;
1565 e->sp--;
1567 r->variables[code->index].len = e->sp->len;
1568 r->variables[code->index].valid = 1;
1569 r->variables[code->index].no_cacheable = 0;
1570 r->variables[code->index].not_found = 0;
1571 r->variables[code->index].data = e->sp->data;
1573 #if (NGX_DEBUG)
1575 ngx_http_variable_t *v;
1576 ngx_http_core_main_conf_t *cmcf;
1578 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
1580 v = cmcf->variables.elts;
1582 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1583 "http script set $%V", &v[code->index].name);
1585 #endif
1589 void
1590 ngx_http_script_var_set_handler_code(ngx_http_script_engine_t *e)
1592 ngx_http_script_var_handler_code_t *code;
1594 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1595 "http script set var handler");
1597 code = (ngx_http_script_var_handler_code_t *) e->ip;
1599 e->ip += sizeof(ngx_http_script_var_handler_code_t);
1601 e->sp--;
1603 code->handler(e->request, e->sp, code->data);
1607 void
1608 ngx_http_script_var_code(ngx_http_script_engine_t *e)
1610 ngx_http_variable_value_t *value;
1611 ngx_http_script_var_code_t *code;
1613 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1614 "http script var");
1616 code = (ngx_http_script_var_code_t *) e->ip;
1618 e->ip += sizeof(ngx_http_script_var_code_t);
1620 value = ngx_http_get_flushed_variable(e->request, code->index);
1622 if (value && !value->not_found) {
1623 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
1624 "http script var: \"%v\"", value);
1626 *e->sp = *value;
1627 e->sp++;
1629 return;
1632 *e->sp = ngx_http_variable_null_value;
1633 e->sp++;
1637 void
1638 ngx_http_script_nop_code(ngx_http_script_engine_t *e)
1640 e->ip += sizeof(uintptr_t);