3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
12 #define ngx_http_script_exit (u_char *) &ngx_http_script_exit_code
14 static uintptr_t ngx_http_script_exit_code
= (uintptr_t) NULL
;
18 ngx_http_script_variables_count(ngx_str_t
*value
)
22 for (n
= 0, i
= 0; i
< value
->len
; i
++) {
23 if (value
->data
[i
] == '$') {
33 ngx_http_script_compile(ngx_http_script_compile_t
*sc
)
40 ngx_uint_t i
, n
, bracket
;
41 ngx_http_script_var_code_t
*var_code
;
42 ngx_http_script_copy_code_t
*copy
;
43 ngx_http_script_copy_capture_code_t
*copy_capture
;
45 if (*sc
->lengths
== NULL
) {
46 n
= sc
->variables
* (2 * sizeof(ngx_http_script_copy_code_t
)
47 + sizeof(ngx_http_script_var_code_t
))
50 *sc
->lengths
= ngx_array_create(sc
->cf
->pool
, n
, 1);
51 if (*sc
->lengths
== NULL
) {
57 if (*sc
->values
== NULL
) {
58 n
= (sc
->variables
* (2 * sizeof(ngx_http_script_copy_code_t
)
59 + sizeof(ngx_http_script_var_code_t
))
62 + sizeof(uintptr_t) - 1)
63 & ~(sizeof(uintptr_t) - 1);
65 *sc
->values
= ngx_array_create(sc
->cf
->pool
, n
, 1);
66 if (*sc
->values
== NULL
) {
73 for (i
= 0; i
< sc
->source
->len
; /* void */ ) {
77 if (sc
->source
->data
[i
] == '$') {
79 if (++i
== sc
->source
->len
) {
80 goto invalid_variable
;
83 if (sc
->source
->data
[i
] >= '1' && sc
->source
->data
[i
] <= '9') {
85 copy_capture
= ngx_http_script_add_code(*sc
->lengths
,
86 sizeof(ngx_http_script_copy_capture_code_t
),
88 if (copy_capture
== NULL
) {
92 copy_capture
->code
= (ngx_http_script_code_pt
)
93 ngx_http_script_copy_capture_len_code
;
94 copy_capture
->n
= 2 * (sc
->source
->data
[i
] - '0');
96 copy_capture
= ngx_http_script_add_code(*sc
->values
,
97 sizeof(ngx_http_script_copy_capture_code_t
),
99 if (copy_capture
== NULL
) {
103 copy_capture
->code
= ngx_http_script_copy_capture_code
;
104 copy_capture
->n
= sc
->source
->data
[i
] - '0';
106 if (sc
->ncaptures
< copy_capture
->n
) {
107 sc
->ncaptures
= copy_capture
->n
;
110 copy_capture
->n
*= 2;
117 if (sc
->source
->data
[i
] == '{') {
120 if (++i
== sc
->source
->len
) {
121 goto invalid_variable
;
124 name
.data
= &sc
->source
->data
[i
];
128 name
.data
= &sc
->source
->data
[i
];
131 for ( /* void */ ; i
< sc
->source
->len
; i
++, name
.len
++) {
132 ch
= sc
->source
->data
[i
];
134 if (ch
== '}' && bracket
) {
140 if ((ch
>= 'A' && ch
<= 'Z')
141 || (ch
>= 'a' && ch
<= 'z')
142 || (ch
>= '0' && ch
<= '9')
152 ngx_conf_log_error(NGX_LOG_EMERG
, sc
->cf
, 0,
153 "the closing bracket in \"%V\" "
154 "variable is missing", &name
);
159 goto invalid_variable
;
164 index
= ngx_http_get_variable_index(sc
->cf
, &name
);
166 if (index
== NGX_ERROR
) {
170 var_code
= ngx_http_script_add_code(*sc
->lengths
,
171 sizeof(ngx_http_script_var_code_t
),
173 if (var_code
== NULL
) {
177 var_code
->code
= (ngx_http_script_code_pt
)
178 ngx_http_script_copy_var_len_code
;
179 var_code
->index
= (uintptr_t) index
;
182 var_code
= ngx_http_script_add_code(*sc
->values
,
183 sizeof(ngx_http_script_var_code_t
),
185 if (var_code
== NULL
) {
189 var_code
->code
= ngx_http_script_copy_var_code
;
190 var_code
->index
= (uintptr_t) index
;
195 if (sc
->source
->data
[i
] == '?' && sc
->compile_args
) {
197 sc
->compile_args
= 0;
199 code
= ngx_http_script_add_code(*sc
->values
, sizeof(uintptr_t),
205 *code
= (uintptr_t) ngx_http_script_start_args_code
;
212 name
.data
= &sc
->source
->data
[i
];
214 while (i
< sc
->source
->len
215 && sc
->source
->data
[i
] != '$'
216 && !(sc
->source
->data
[i
] == '?' && sc
->compile_args
))
222 sc
->size
+= name
.len
;
224 copy
= ngx_http_script_add_code(*sc
->lengths
,
225 sizeof(ngx_http_script_copy_code_t
),
231 copy
->code
= (ngx_http_script_code_pt
) ngx_http_script_copy_len_code
;
232 copy
->len
= name
.len
;
234 size
= (sizeof(ngx_http_script_copy_code_t
) + name
.len
235 + sizeof(uintptr_t) - 1)
236 & ~(sizeof(uintptr_t) - 1);
238 copy
= ngx_http_script_add_code(*sc
->values
, size
, &sc
->main
);
243 copy
->code
= ngx_http_script_copy_code
;
244 copy
->len
= name
.len
;
246 ngx_memcpy((u_char
*) copy
+ sizeof(ngx_http_script_copy_code_t
),
247 name
.data
, name
.len
);
250 if (sc
->complete_lengths
) {
251 code
= ngx_http_script_add_code(*sc
->lengths
, sizeof(uintptr_t), NULL
);
256 *code
= (uintptr_t) NULL
;
259 if (sc
->complete_values
) {
260 code
= ngx_http_script_add_code(*sc
->values
, sizeof(uintptr_t),
266 *code
= (uintptr_t) NULL
;
273 ngx_conf_log_error(NGX_LOG_EMERG
, sc
->cf
, 0, "invalid variable name");
280 ngx_http_script_start_code(ngx_pool_t
*pool
, ngx_array_t
**codes
, size_t size
)
282 if (*codes
== NULL
) {
283 *codes
= ngx_array_create(pool
, 256, 1);
284 if (*codes
== NULL
) {
289 return ngx_array_push_n(*codes
, size
);
294 ngx_http_script_add_code(ngx_array_t
*codes
, size_t size
, void *code
)
301 new = ngx_array_push_n(codes
, size
);
303 return NGX_CONF_ERROR
;
307 if (elts
!= codes
->elts
) {
309 *p
+= (u_char
*) codes
->elts
- elts
;
318 ngx_http_script_copy_len_code(ngx_http_script_engine_t
*e
)
320 ngx_http_script_copy_code_t
*code
;
322 code
= (ngx_http_script_copy_code_t
*) e
->ip
;
324 e
->ip
+= sizeof(ngx_http_script_copy_code_t
);
331 ngx_http_script_copy_code(ngx_http_script_engine_t
*e
)
333 ngx_http_script_copy_code_t
*code
;
335 code
= (ngx_http_script_copy_code_t
*) e
->ip
;
338 e
->pos
= ngx_cpymem(e
->pos
, e
->ip
+ sizeof(ngx_http_script_copy_code_t
),
342 e
->ip
+= sizeof(ngx_http_script_copy_code_t
)
343 + ((code
->len
+ sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));
346 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, e
->request
->connection
->log
, 0,
347 "http script copy: \"%V\"", &e
->buf
);
353 ngx_http_script_copy_var_len_code(ngx_http_script_engine_t
*e
)
355 ngx_http_variable_value_t
*value
;
356 ngx_http_script_var_code_t
*code
;
358 code
= (ngx_http_script_var_code_t
*) e
->ip
;
360 e
->ip
+= sizeof(ngx_http_script_var_code_t
);
362 value
= ngx_http_get_indexed_variable(e
->request
, code
->index
);
364 if (value
== NULL
|| value
== NGX_HTTP_VAR_NOT_FOUND
) {
368 return value
->text
.len
;
373 ngx_http_script_copy_var_code(ngx_http_script_engine_t
*e
)
375 ngx_http_variable_value_t
*value
;
376 ngx_http_script_var_code_t
*code
;
378 code
= (ngx_http_script_var_code_t
*) e
->ip
;
380 e
->ip
+= sizeof(ngx_http_script_var_code_t
);
383 value
= ngx_http_get_indexed_variable(e
->request
, code
->index
);
385 if (value
== NULL
|| value
== NGX_HTTP_VAR_NOT_FOUND
) {
389 e
->pos
= ngx_cpymem(e
->pos
, value
->text
.data
, value
->text
.len
);
392 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, e
->request
->connection
->log
, 0,
393 "http script var: \"%V\"", &e
->buf
);
400 ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t
*e
)
402 ngx_http_script_copy_capture_code_t
*code
;
404 code
= (ngx_http_script_copy_capture_code_t
*) e
->ip
;
406 e
->ip
+= sizeof(ngx_http_script_copy_capture_code_t
);
408 if (code
->n
< e
->ncaptures
) {
409 if ((e
->args
|| e
->quote
)
410 && (e
->request
->quoted_uri
|| e
->request
->plus_in_uri
))
412 return e
->captures
[code
->n
+ 1] - e
->captures
[code
->n
]
413 + ngx_escape_uri(NULL
,
414 &e
->line
.data
[e
->captures
[code
->n
]],
415 e
->captures
[code
->n
+ 1] - e
->captures
[code
->n
],
418 return e
->captures
[code
->n
+ 1] - e
->captures
[code
->n
];
427 ngx_http_script_copy_capture_code(ngx_http_script_engine_t
*e
)
429 ngx_http_script_copy_capture_code_t
*code
;
431 code
= (ngx_http_script_copy_capture_code_t
*) e
->ip
;
433 e
->ip
+= sizeof(ngx_http_script_copy_capture_code_t
);
435 if (code
->n
< e
->ncaptures
) {
436 if ((e
->args
|| e
->quote
)
437 && (e
->request
->quoted_uri
|| e
->request
->plus_in_uri
))
439 e
->pos
= (u_char
*) ngx_escape_uri(e
->pos
,
440 &e
->line
.data
[e
->captures
[code
->n
]],
441 e
->captures
[code
->n
+ 1] - e
->captures
[code
->n
],
444 e
->pos
= ngx_cpymem(e
->pos
,
445 &e
->line
.data
[e
->captures
[code
->n
]],
446 e
->captures
[code
->n
+ 1] - e
->captures
[code
->n
]);
450 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, e
->request
->connection
->log
, 0,
451 "http script capture: \"%V\"", &e
->buf
);
456 ngx_http_script_start_args_code(ngx_http_script_engine_t
*e
)
458 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, e
->request
->connection
->log
, 0,
462 e
->ip
+= sizeof(uintptr_t);
470 ngx_http_script_regex_start_code(ngx_http_script_engine_t
*e
)
475 ngx_http_request_t
*r
;
476 ngx_http_script_engine_t le
;
477 ngx_http_script_len_code_pt lcode
;
478 ngx_http_script_regex_code_t
*code
;
480 code
= (ngx_http_script_regex_code_t
*) e
->ip
;
484 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
485 "http script regex: \"%V\"", &code
->name
);
491 e
->line
= e
->sp
->text
;
494 rc
= ngx_regex_exec(code
->regex
, &e
->line
, e
->captures
, code
->ncaptures
);
496 if (rc
== NGX_REGEX_NO_MATCHED
) {
498 ngx_log_error(NGX_LOG_NOTICE
, r
->connection
->log
, 0,
499 "\"%V\" does not match \"%V\"",
500 &code
->name
, &e
->line
);
508 e
->sp
->text
.data
= (u_char
*) "";
511 e
->ip
+= sizeof(ngx_http_script_regex_code_t
);
520 ngx_log_error(NGX_LOG_ALERT
, r
->connection
->log
, 0,
521 ngx_regex_exec_n
" failed: %d on \"%V\" using \"%V\"",
522 rc
, &e
->line
, &code
->name
);
524 e
->ip
= ngx_http_script_exit
;
525 e
->status
= NGX_HTTP_INTERNAL_SERVER_ERROR
;
530 ngx_log_error(NGX_LOG_NOTICE
, r
->connection
->log
, 0,
531 "\"%V\" matches \"%V\"", &code
->name
, &e
->line
);
534 e
->ncaptures
= code
->ncaptures
;
539 e
->sp
->text
.data
= (u_char
*) "1";
542 e
->ip
+= sizeof(ngx_http_script_regex_code_t
);
547 e
->status
= code
->status
;
549 if (!code
->redirect
) {
550 e
->ip
= ngx_http_script_exit
;
557 r
->valid_unparsed_uri
= 0;
559 if (code
->break_cycle
) {
560 r
->valid_location
= 0;
568 if (code
->lengths
== NULL
) {
569 e
->buf
.len
= code
->size
;
572 if (rc
&& (r
->quoted_uri
|| r
->plus_in_uri
)) {
573 e
->buf
.len
+= 2 * ngx_escape_uri(NULL
, r
->uri
.data
, r
->uri
.len
,
578 for (n
= 1; n
< (ngx_uint_t
) rc
; n
++) {
579 e
->buf
.len
+= e
->captures
[2 * n
+ 1] - e
->captures
[2 * n
];
583 ngx_memzero(&le
, sizeof(ngx_http_script_engine_t
));
585 le
.ip
= code
->lengths
->elts
;
587 le
.captures
= e
->captures
;
588 le
.ncaptures
= e
->ncaptures
;
590 len
= 1; /* reserve 1 byte for possible "?" */
592 while (*(uintptr_t *) le
.ip
) {
593 lcode
= *(ngx_http_script_len_code_pt
*) le
.ip
;
600 if (code
->add_args
&& r
->args
.len
) {
601 e
->buf
.len
+= r
->args
.len
+ 1;
604 e
->buf
.data
= ngx_palloc(r
->pool
, e
->buf
.len
);
605 if (e
->buf
.data
== NULL
) {
606 e
->ip
= ngx_http_script_exit
;
607 e
->status
= NGX_HTTP_INTERNAL_SERVER_ERROR
;
611 e
->quote
= code
->redirect
;
613 e
->pos
= e
->buf
.data
;
615 e
->ip
+= sizeof(ngx_http_script_regex_code_t
);
620 ngx_http_script_regex_end_code(ngx_http_script_engine_t
*e
)
622 ngx_http_request_t
*r
;
623 ngx_http_script_regex_end_code_t
*code
;
625 code
= (ngx_http_script_regex_end_code_t
*) e
->ip
;
631 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
632 "http script regex end");
634 if (code
->redirect
) {
636 if (code
->add_args
&& r
->args
.len
) {
637 *e
->pos
++ = (u_char
) (code
->args
? '&' : '?');
638 e
->pos
= ngx_cpymem(e
->pos
, r
->args
.data
, r
->args
.len
);
641 e
->buf
.len
= e
->pos
- e
->buf
.data
;
644 ngx_log_error(NGX_LOG_NOTICE
, r
->connection
->log
, 0,
645 "rewritten redirect: \"%V\"", &e
->buf
);
648 r
->headers_out
.location
= ngx_list_push(&r
->headers_out
.headers
);
649 if (r
->headers_out
.location
== NULL
) {
650 e
->ip
= ngx_http_script_exit
;
651 e
->status
= NGX_HTTP_INTERNAL_SERVER_ERROR
;
655 r
->headers_out
.location
->hash
= 1;
656 r
->headers_out
.location
->key
.len
= sizeof("Location") - 1;
657 r
->headers_out
.location
->key
.data
= (u_char
*) "Location";
658 r
->headers_out
.location
->value
= e
->buf
;
660 e
->ip
+= sizeof(ngx_http_script_regex_end_code_t
);
665 e
->buf
.len
= e
->args
- e
->buf
.data
;
667 if (code
->add_args
&& r
->args
.len
) {
669 e
->pos
= ngx_cpymem(e
->pos
, r
->args
.data
, r
->args
.len
);
672 r
->args
.len
= e
->pos
- e
->args
;
673 r
->args
.data
= e
->args
;
678 e
->buf
.len
= e
->pos
- e
->buf
.data
;
682 ngx_log_error(NGX_LOG_NOTICE
, r
->connection
->log
, 0,
683 "rewritten data: \"%V\", args: \"%V\"",
690 if (ngx_http_set_exten(r
) != NGX_OK
) {
691 e
->ip
= ngx_http_script_exit
;
692 e
->status
= NGX_HTTP_INTERNAL_SERVER_ERROR
;
697 e
->ip
+= sizeof(ngx_http_script_regex_end_code_t
);
704 ngx_http_script_return_code(ngx_http_script_engine_t
*e
)
706 ngx_http_script_return_code_t
*code
;
708 code
= (ngx_http_script_return_code_t
*) e
->ip
;
710 e
->status
= code
->status
;
712 e
->ip
+= sizeof(ngx_http_script_return_code_t
) - sizeof(uintptr_t);
717 ngx_http_script_break_code(ngx_http_script_engine_t
*e
)
719 e
->request
->uri_changed
= 0;
721 e
->ip
= ngx_http_script_exit
;
726 ngx_http_script_if_code(ngx_http_script_engine_t
*e
)
728 ngx_http_script_if_code_t
*code
;
730 code
= (ngx_http_script_if_code_t
*) e
->ip
;
732 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, e
->request
->connection
->log
, 0,
738 if (code
->loc_conf
) {
739 e
->request
->loc_conf
= code
->loc_conf
;
742 e
->ip
+= sizeof(ngx_http_script_if_code_t
);
746 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, e
->request
->connection
->log
, 0,
747 "http script if false");
754 ngx_http_script_complex_value_code(ngx_http_script_engine_t
*e
)
757 ngx_http_script_engine_t le
;
758 ngx_http_script_len_code_pt lcode
;
759 ngx_http_script_complex_value_code_t
*code
;
761 code
= (ngx_http_script_complex_value_code_t
*) e
->ip
;
763 e
->ip
+= sizeof(ngx_http_script_complex_value_code_t
);
765 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, e
->request
->connection
->log
, 0,
766 "http script complex value");
768 ngx_memzero(&le
, sizeof(ngx_http_script_engine_t
));
770 le
.ip
= code
->lengths
->elts
;
771 le
.request
= e
->request
;
772 le
.captures
= e
->captures
;
773 le
.ncaptures
= e
->ncaptures
;
775 for (len
= 0; *(uintptr_t *) le
.ip
; len
+= lcode(&le
)) {
776 lcode
= *(ngx_http_script_len_code_pt
*) le
.ip
;
780 e
->buf
.data
= ngx_palloc(e
->request
->pool
, len
);
781 if (e
->buf
.data
== NULL
) {
782 e
->ip
= ngx_http_script_exit
;
783 e
->status
= NGX_HTTP_INTERNAL_SERVER_ERROR
;
787 e
->pos
= e
->buf
.data
;
790 e
->sp
->text
= e
->buf
;
796 ngx_http_script_value_code(ngx_http_script_engine_t
*e
)
798 ngx_http_script_value_code_t
*code
;
800 code
= (ngx_http_script_value_code_t
*) e
->ip
;
802 e
->ip
+= sizeof(ngx_http_script_value_code_t
);
804 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, e
->request
->connection
->log
, 0,
805 "http script value");
807 e
->sp
->value
= (ngx_uint_t
) code
->value
;
808 e
->sp
->text
.len
= (size_t) code
->text_len
;
809 e
->sp
->text
.data
= (u_char
*) code
->text_data
;
815 ngx_http_script_set_var_code(ngx_http_script_engine_t
*e
)
817 ngx_http_request_t
*r
;
818 ngx_http_variable_value_t
*value
;
819 ngx_http_core_main_conf_t
*cmcf
;
820 ngx_http_script_var_code_t
*code
;
822 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, e
->request
->connection
->log
, 0,
823 "http script set var");
825 code
= (ngx_http_script_var_code_t
*) e
->ip
;
827 e
->ip
+= sizeof(ngx_http_script_var_code_t
);
831 if (r
->variables
== NULL
) {
832 cmcf
= ngx_http_get_module_main_conf(r
, ngx_http_core_module
);
834 r
->variables
= ngx_pcalloc(r
->pool
, cmcf
->variables
.nelts
835 * sizeof(ngx_http_variable_value_t
*));
836 if (r
->variables
== NULL
) {
837 e
->ip
= ngx_http_script_exit
;
838 e
->status
= NGX_HTTP_INTERNAL_SERVER_ERROR
;
843 value
= ngx_palloc(r
->pool
, sizeof(ngx_http_variable_value_t
));
845 e
->ip
= ngx_http_script_exit
;
846 e
->status
= NGX_HTTP_INTERNAL_SERVER_ERROR
;
854 r
->variables
[code
->index
] = value
;
859 ngx_http_script_var_code(ngx_http_script_engine_t
*e
)
861 ngx_http_variable_value_t
*value
;
862 ngx_http_script_var_code_t
*code
;
864 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, e
->request
->connection
->log
, 0,
867 code
= (ngx_http_script_var_code_t
*) e
->ip
;
869 e
->ip
+= sizeof(ngx_http_script_var_code_t
);
871 value
= ngx_http_get_indexed_variable(e
->request
, code
->index
);
873 if (value
== NULL
|| value
== NGX_HTTP_VAR_NOT_FOUND
) {
876 e
->sp
->text
.data
= (u_char
*) "";
882 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, e
->request
->connection
->log
, 0,
883 "http script var: %ui, \"%V\"", value
->value
, &value
->text
);
891 ngx_http_script_nop_code(ngx_http_script_engine_t
*e
)
893 e
->ip
+= sizeof(uintptr_t);