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