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