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