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