src/http/ngx_http_script.c - nginx-1.31.4 nginx/ @ 8d9666701

Global variables defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>


  8. static ngx_int_t ngx_http_script_init_arrays(ngx_http_script_compile_t *sc);
  9. static ngx_int_t ngx_http_script_done(ngx_http_script_compile_t *sc);
  10. static ngx_int_t ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc,
  11.     ngx_str_t *value, ngx_uint_t last);
  12. static ngx_int_t ngx_http_script_add_var_code(ngx_http_script_compile_t *sc,
  13.     ngx_str_t *name);
  14. static ngx_int_t ngx_http_script_add_args_code(ngx_http_script_compile_t *sc);
  15. #if (NGX_PCRE)
  16. static ngx_int_t ngx_http_script_add_capture_code(ngx_http_script_compile_t *sc,
  17.     ngx_uint_t n);
  18. #endif
  19. static ngx_int_t
  20.     ngx_http_script_add_full_name_code(ngx_http_script_compile_t *sc);
  21. static size_t ngx_http_script_full_name_len_code(ngx_http_script_engine_t *e);
  22. static void ngx_http_script_full_name_code(ngx_http_script_engine_t *e);


  23. #define ngx_http_script_exit  (u_char *) &ngx_http_script_exit_code

  24. static uintptr_t ngx_http_script_exit_code = (uintptr_t) NULL;


  25. void
  26. ngx_http_script_flush_complex_value(ngx_http_request_t *r,
  27.     ngx_http_complex_value_t *val)
  28. {
  29.     ngx_uint_t *index;

  30.     index = val->flushes;

  31.     if (index) {
  32.         while (*index != (ngx_uint_t) -1) {

  33.             if (r->variables[*index].no_cacheable) {
  34.                 r->variables[*index].valid = 0;
  35.                 r->variables[*index].not_found = 0;
  36.             }

  37.             index++;
  38.         }
  39.     }
  40. }


  41. ngx_int_t
  42. ngx_http_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val,
  43.     ngx_str_t *value)
  44. {
  45.     size_t                        len;
  46.     ngx_http_script_code_pt       code;
  47.     ngx_http_script_len_code_pt   lcode;
  48.     ngx_http_script_engine_t      e;

  49.     if (val->lengths == NULL) {
  50.         *value = val->value;
  51.         return NGX_OK;
  52.     }

  53.     ngx_http_script_flush_complex_value(r, val);

  54.     ngx_memzero(&e, sizeof(ngx_http_script_engine_t));

  55.     e.ip = val->lengths;
  56.     e.request = r;
  57.     e.flushed = 1;

  58.     len = 0;

  59.     while (*(uintptr_t *) e.ip) {
  60.         lcode = *(ngx_http_script_len_code_pt *) e.ip;
  61.         len += lcode(&e);
  62.     }

  63.     value->len = len;
  64.     value->data = ngx_pnalloc(r->pool, len);
  65.     if (value->data == NULL) {
  66.         return NGX_ERROR;
  67.     }

  68.     e.ip = val->values;
  69.     e.pos = value->data;
  70.     e.buf = *value;
  71.     e.end = value->data + len;

  72.     while (*(uintptr_t *) e.ip) {
  73.         code = *(ngx_http_script_code_pt *) e.ip;
  74.         code((ngx_http_script_engine_t *) &e);
  75.     }

  76.     if (e.status) {
  77.         return NGX_ERROR;
  78.     }

  79.     value->data = e.buf.data;
  80.     value->len = e.pos - e.buf.data;

  81.     return NGX_OK;
  82. }


  83. size_t
  84. ngx_http_complex_value_size(ngx_http_request_t *r,
  85.     ngx_http_complex_value_t *val, size_t default_value)
  86. {
  87.     size_t     size;
  88.     ngx_str_t  value;

  89.     if (val == NULL) {
  90.         return default_value;
  91.     }

  92.     if (val->lengths == NULL) {
  93.         return val->u.size;
  94.     }

  95.     if (ngx_http_complex_value(r, val, &value) != NGX_OK) {
  96.         return default_value;
  97.     }

  98.     size = ngx_parse_size(&value);

  99.     if (size == (size_t) NGX_ERROR) {
  100.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  101.                       "invalid size \"%V\"", &value);
  102.         return default_value;
  103.     }

  104.     return size;
  105. }


  106. ngx_int_t
  107. ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv)
  108. {
  109.     ngx_str_t                  *v;
  110.     ngx_uint_t                  i, n, nv, nc;
  111.     ngx_array_t                 flushes, lengths, values, *pf, *pl, *pv;
  112.     ngx_http_script_compile_t   sc;

  113.     v = ccv->value;

  114.     nv = 0;
  115.     nc = 0;

  116.     for (i = 0; i < v->len; i++) {
  117.         if (v->data[i] == '$') {
  118.             if (i + 1 < v->len
  119.                 && v->data[i + 1] >= '1' && v->data[i + 1] <= '9')
  120.             {
  121.                 nc++;

  122.             } else {
  123.                 nv++;
  124.             }
  125.         }
  126.     }

  127.     if ((v->len == 0 || v->data[0] != '$')
  128.         && (ccv->conf_prefix || ccv->root_prefix))
  129.     {
  130.         if (ngx_conf_full_name(ccv->cf->cycle, v, ccv->conf_prefix) != NGX_OK) {
  131.             return NGX_ERROR;
  132.         }

  133.         ccv->conf_prefix = 0;
  134.         ccv->root_prefix = 0;
  135.     }

  136.     ccv->complex_value->value = *v;
  137.     ccv->complex_value->flushes = NULL;
  138.     ccv->complex_value->lengths = NULL;
  139.     ccv->complex_value->values = NULL;

  140.     if (nv == 0 && nc == 0) {
  141.         return NGX_OK;
  142.     }

  143.     n = nv + 1;

  144.     if (ngx_array_init(&flushes, ccv->cf->pool, n, sizeof(ngx_uint_t))
  145.         != NGX_OK)
  146.     {
  147.         return NGX_ERROR;
  148.     }

  149.     n = nv * (2 * sizeof(ngx_http_script_copy_code_t)
  150.                   + sizeof(ngx_http_script_var_code_t))
  151.         + sizeof(uintptr_t);

  152.     if (ngx_array_init(&lengths, ccv->cf->pool, n, 1) != NGX_OK) {
  153.         return NGX_ERROR;
  154.     }

  155.     n = (nv * (2 * sizeof(ngx_http_script_copy_code_t)
  156.                    + sizeof(ngx_http_script_var_code_t))
  157.                 + sizeof(uintptr_t)
  158.                 + v->len
  159.                 + sizeof(uintptr_t) - 1)
  160.             & ~(sizeof(uintptr_t) - 1);

  161.     if (ngx_array_init(&values, ccv->cf->pool, n, 1) != NGX_OK) {
  162.         return NGX_ERROR;
  163.     }

  164.     pf = &flushes;
  165.     pl = &lengths;
  166.     pv = &values;

  167.     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

  168.     sc.cf = ccv->cf;
  169.     sc.source = v;
  170.     sc.flushes = &pf;
  171.     sc.lengths = &pl;
  172.     sc.values = &pv;
  173.     sc.complete_lengths = 1;
  174.     sc.complete_values = 1;
  175.     sc.zero = ccv->zero;
  176.     sc.conf_prefix = ccv->conf_prefix;
  177.     sc.root_prefix = ccv->root_prefix;

  178.     if (ngx_http_script_compile(&sc) != NGX_OK) {
  179.         return NGX_ERROR;
  180.     }

  181.     if (flushes.nelts) {
  182.         ccv->complex_value->flushes = flushes.elts;
  183.         ccv->complex_value->flushes[flushes.nelts] = (ngx_uint_t) -1;
  184.     }

  185.     ccv->complex_value->lengths = lengths.elts;
  186.     ccv->complex_value->values = values.elts;

  187.     return NGX_OK;
  188. }


  189. char *
  190. ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  191. {
  192.     char  *p = conf;

  193.     ngx_str_t                          *value;
  194.     ngx_http_complex_value_t          **cv;
  195.     ngx_http_compile_complex_value_t    ccv;

  196.     cv = (ngx_http_complex_value_t **) (p + cmd->offset);

  197.     if (*cv != NGX_CONF_UNSET_PTR && *cv != NULL) {
  198.         return "is duplicate";
  199.     }

  200.     *cv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
  201.     if (*cv == NULL) {
  202.         return NGX_CONF_ERROR;
  203.     }

  204.     value = cf->args->elts;

  205.     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

  206.     ccv.cf = cf;
  207.     ccv.value = &value[1];
  208.     ccv.complex_value = *cv;

  209.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  210.         return NGX_CONF_ERROR;
  211.     }

  212.     return NGX_CONF_OK;
  213. }


  214. char *
  215. ngx_http_set_complex_value_zero_slot(ngx_conf_t *cf, ngx_command_t *cmd,
  216.     void *conf)
  217. {
  218.     char  *p = conf;

  219.     ngx_str_t                          *value;
  220.     ngx_http_complex_value_t          **cv;
  221.     ngx_http_compile_complex_value_t    ccv;

  222.     cv = (ngx_http_complex_value_t **) (p + cmd->offset);

  223.     if (*cv != NGX_CONF_UNSET_PTR) {
  224.         return "is duplicate";
  225.     }

  226.     *cv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
  227.     if (*cv == NULL) {
  228.         return NGX_CONF_ERROR;
  229.     }

  230.     value = cf->args->elts;

  231.     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

  232.     ccv.cf = cf;
  233.     ccv.value = &value[1];
  234.     ccv.complex_value = *cv;
  235.     ccv.zero = 1;

  236.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  237.         return NGX_CONF_ERROR;
  238.     }

  239.     return NGX_CONF_OK;
  240. }


  241. char *
  242. ngx_http_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd,
  243.     void *conf)
  244. {
  245.     char  *p = conf;

  246.     char                      *rv;
  247.     ngx_http_complex_value_t  *cv;

  248.     rv = ngx_http_set_complex_value_slot(cf, cmd, conf);

  249.     if (rv != NGX_CONF_OK) {
  250.         return rv;
  251.     }

  252.     cv = *(ngx_http_complex_value_t **) (p + cmd->offset);

  253.     if (cv->lengths) {
  254.         return NGX_CONF_OK;
  255.     }

  256.     cv->u.size = ngx_parse_size(&cv->value);
  257.     if (cv->u.size == (size_t) NGX_ERROR) {
  258.         return "invalid value";
  259.     }

  260.     return NGX_CONF_OK;
  261. }


  262. ngx_int_t
  263. ngx_http_test_predicates(ngx_http_request_t *r, ngx_array_t *predicates)
  264. {
  265.     ngx_str_t                  val;
  266.     ngx_uint_t                 i;
  267.     ngx_http_complex_value_t  *cv;

  268.     if (predicates == NULL) {
  269.         return NGX_OK;
  270.     }

  271.     cv = predicates->elts;

  272.     for (i = 0; i < predicates->nelts; i++) {
  273.         if (ngx_http_complex_value(r, &cv[i], &val) != NGX_OK) {
  274.             return NGX_ERROR;
  275.         }

  276.         if (val.len && (val.len != 1 || val.data[0] != '0')) {
  277.             return NGX_DECLINED;
  278.         }
  279.     }

  280.     return NGX_OK;
  281. }


  282. ngx_int_t
  283. ngx_http_test_required_predicates(ngx_http_request_t *r,
  284.     ngx_array_t *predicates)
  285. {
  286.     ngx_str_t                  val;
  287.     ngx_uint_t                 i;
  288.     ngx_http_complex_value_t  *cv;

  289.     if (predicates == NULL) {
  290.         return NGX_OK;
  291.     }

  292.     cv = predicates->elts;

  293.     for (i = 0; i < predicates->nelts; i++) {
  294.         if (ngx_http_complex_value(r, &cv[i], &val) != NGX_OK) {
  295.             return NGX_ERROR;
  296.         }

  297.         if (val.len == 0 || (val.len == 1 && val.data[0] == '0')) {
  298.             return NGX_DECLINED;
  299.         }
  300.     }

  301.     return NGX_OK;
  302. }


  303. char *
  304. ngx_http_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  305. {
  306.     char  *p = conf;

  307.     ngx_str_t                          *value;
  308.     ngx_uint_t                          i;
  309.     ngx_array_t                       **a;
  310.     ngx_http_complex_value_t           *cv;
  311.     ngx_http_compile_complex_value_t    ccv;

  312.     a = (ngx_array_t **) (p + cmd->offset);

  313.     if (*a == NGX_CONF_UNSET_PTR) {
  314.         *a = ngx_array_create(cf->pool, 1, sizeof(ngx_http_complex_value_t));
  315.         if (*a == NULL) {
  316.             return NGX_CONF_ERROR;
  317.         }
  318.     }

  319.     value = cf->args->elts;

  320.     for (i = 1; i < cf->args->nelts; i++) {
  321.         cv = ngx_array_push(*a);
  322.         if (cv == NULL) {
  323.             return NGX_CONF_ERROR;
  324.         }

  325.         ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

  326.         ccv.cf = cf;
  327.         ccv.value = &value[i];
  328.         ccv.complex_value = cv;

  329.         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  330.             return NGX_CONF_ERROR;
  331.         }
  332.     }

  333.     return NGX_CONF_OK;
  334. }


  335. ngx_uint_t
  336. ngx_http_script_variables_count(ngx_str_t *value)
  337. {
  338.     ngx_uint_t  i, n;

  339.     for (n = 0, i = 0; i < value->len; i++) {
  340.         if (value->data[i] == '$') {
  341.             n++;
  342.         }
  343.     }

  344.     return n;
  345. }


  346. ngx_int_t
  347. ngx_http_script_compile(ngx_http_script_compile_t *sc)
  348. {
  349.     u_char       ch;
  350.     ngx_str_t    name;
  351.     ngx_uint_t   i, bracket;

  352.     if (ngx_http_script_init_arrays(sc) != NGX_OK) {
  353.         return NGX_ERROR;
  354.     }

  355.     for (i = 0; i < sc->source->len; /* void */ ) {

  356.         name.len = 0;

  357.         if (sc->source->data[i] == '$') {

  358.             if (++i == sc->source->len) {
  359.                 goto invalid_variable;
  360.             }

  361.             if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') {
  362. #if (NGX_PCRE)
  363.                 ngx_uint_t  n;

  364.                 n = sc->source->data[i] - '0';

  365.                 if (sc->captures_mask & ((ngx_uint_t) 1 << n)) {
  366.                     sc->dup_capture = 1;
  367.                 }

  368.                 sc->captures_mask |= (ngx_uint_t) 1 << n;

  369.                 if (ngx_http_script_add_capture_code(sc, n) != NGX_OK) {
  370.                     return NGX_ERROR;
  371.                 }

  372.                 i++;

  373.                 continue;
  374. #else
  375.                 ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0,
  376.                                    "using variable \"$%c\" requires "
  377.                                    "PCRE library", sc->source->data[i]);
  378.                 return NGX_ERROR;
  379. #endif
  380.             }

  381.             if (sc->source->data[i] == '{') {
  382.                 bracket = 1;

  383.                 if (++i == sc->source->len) {
  384.                     goto invalid_variable;
  385.                 }

  386.                 name.data = &sc->source->data[i];

  387.             } else {
  388.                 bracket = 0;
  389.                 name.data = &sc->source->data[i];
  390.             }

  391.             for ( /* void */ ; i < sc->source->len; i++, name.len++) {
  392.                 ch = sc->source->data[i];

  393.                 if (ch == '}' && bracket) {
  394.                     i++;
  395.                     bracket = 0;
  396.                     break;
  397.                 }

  398.                 if ((ch >= 'A' && ch <= 'Z')
  399.                     || (ch >= 'a' && ch <= 'z')
  400.                     || (ch >= '0' && ch <= '9')
  401.                     || ch == '_')
  402.                 {
  403.                     continue;
  404.                 }

  405.                 break;
  406.             }

  407.             if (bracket) {
  408.                 ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0,
  409.                                    "the closing bracket in \"%V\" "
  410.                                    "variable is missing", &name);
  411.                 return NGX_ERROR;
  412.             }

  413.             if (name.len == 0) {
  414.                 goto invalid_variable;
  415.             }

  416.             sc->variables++;

  417.             if (ngx_http_script_add_var_code(sc, &name) != NGX_OK) {
  418.                 return NGX_ERROR;
  419.             }

  420.             continue;
  421.         }

  422.         if (sc->source->data[i] == '?' && sc->compile_args) {
  423.             sc->args = 1;
  424.             sc->compile_args = 0;

  425.             if (ngx_http_script_add_args_code(sc) != NGX_OK) {
  426.                 return NGX_ERROR;
  427.             }

  428.             i++;

  429.             continue;
  430.         }

  431.         name.data = &sc->source->data[i];

  432.         while (i < sc->source->len) {

  433.             if (sc->source->data[i] == '$') {
  434.                 break;
  435.             }

  436.             if (sc->source->data[i] == '?') {

  437.                 sc->args = 1;

  438.                 if (sc->compile_args) {
  439.                     break;
  440.                 }
  441.             }

  442.             i++;
  443.             name.len++;
  444.         }

  445.         sc->size += name.len;

  446.         if (ngx_http_script_add_copy_code(sc, &name, (i == sc->source->len))
  447.             != NGX_OK)
  448.         {
  449.             return NGX_ERROR;
  450.         }
  451.     }

  452.     return ngx_http_script_done(sc);

  453. invalid_variable:

  454.     ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, "invalid variable name");

  455.     return NGX_ERROR;
  456. }


  457. u_char *
  458. ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value,
  459.     void *code_lengths, size_t len, void *code_values)
  460. {
  461.     size_t                        n;
  462.     ngx_uint_t                    i;
  463.     ngx_http_script_code_pt       code;
  464.     ngx_http_script_len_code_pt   lcode;
  465.     ngx_http_script_engine_t      e;
  466.     ngx_http_core_main_conf_t    *cmcf;

  467.     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);

  468.     for (i = 0; i < cmcf->variables.nelts; i++) {
  469.         if (r->variables[i].no_cacheable) {
  470.             r->variables[i].valid = 0;
  471.             r->variables[i].not_found = 0;
  472.         }
  473.     }

  474.     ngx_memzero(&e, sizeof(ngx_http_script_engine_t));

  475.     e.ip = code_lengths;
  476.     e.request = r;
  477.     e.flushed = 1;

  478.     n = len;

  479.     while (*(uintptr_t *) e.ip) {
  480.         lcode = *(ngx_http_script_len_code_pt *) e.ip;
  481.         n += lcode(&e);
  482.     }


  483.     value->len = n;
  484.     value->data = ngx_pnalloc(r->pool, n);
  485.     if (value->data == NULL) {
  486.         return NULL;
  487.     }

  488.     e.ip = code_values;
  489.     e.pos = value->data;
  490.     e.end = value->data + n;

  491.     while (*(uintptr_t *) e.ip) {
  492.         code = *(ngx_http_script_code_pt *) e.ip;
  493.         code((ngx_http_script_engine_t *) &e);
  494.     }

  495.     if (e.status) {
  496.         return NULL;
  497.     }

  498.     value->len = e.pos + len - value->data;

  499.     return e.pos;
  500. }


  501. void
  502. ngx_http_script_flush_no_cacheable_variables(ngx_http_request_t *r,
  503.     ngx_array_t *indices)
  504. {
  505.     ngx_uint_t  n, *index;

  506.     if (indices) {
  507.         index = indices->elts;
  508.         for (n = 0; n < indices->nelts; n++) {
  509.             if (r->variables[index[n]].no_cacheable) {
  510.                 r->variables[index[n]].valid = 0;
  511.                 r->variables[index[n]].not_found = 0;
  512.             }
  513.         }
  514.     }
  515. }


  516. static ngx_int_t
  517. ngx_http_script_init_arrays(ngx_http_script_compile_t *sc)
  518. {
  519.     ngx_uint_t   n;

  520.     if (sc->flushes && *sc->flushes == NULL) {
  521.         n = sc->variables ? sc->variables : 1;
  522.         *sc->flushes = ngx_array_create(sc->cf->pool, n, sizeof(ngx_uint_t));
  523.         if (*sc->flushes == NULL) {
  524.             return NGX_ERROR;
  525.         }
  526.     }

  527.     if (*sc->lengths == NULL) {
  528.         n = sc->variables * (2 * sizeof(ngx_http_script_copy_code_t)
  529.                              + sizeof(ngx_http_script_var_code_t))
  530.             + sizeof(uintptr_t);

  531.         *sc->lengths = ngx_array_create(sc->cf->pool, n, 1);
  532.         if (*sc->lengths == NULL) {
  533.             return NGX_ERROR;
  534.         }
  535.     }

  536.     if (*sc->values == NULL) {
  537.         n = (sc->variables * (2 * sizeof(ngx_http_script_copy_code_t)
  538.                               + sizeof(ngx_http_script_var_code_t))
  539.                 + sizeof(uintptr_t)
  540.                 + sc->source->len
  541.                 + sizeof(uintptr_t) - 1)
  542.             & ~(sizeof(uintptr_t) - 1);

  543.         *sc->values = ngx_array_create(sc->cf->pool, n, 1);
  544.         if (*sc->values == NULL) {
  545.             return NGX_ERROR;
  546.         }
  547.     }

  548.     sc->variables = 0;

  549.     return NGX_OK;
  550. }


  551. static ngx_int_t
  552. ngx_http_script_done(ngx_http_script_compile_t *sc)
  553. {
  554.     ngx_str_t    zero;
  555.     uintptr_t   *code;

  556.     if (sc->zero) {

  557.         zero.len = 1;
  558.         zero.data = (u_char *) "\0";

  559.         if (ngx_http_script_add_copy_code(sc, &zero, 0) != NGX_OK) {
  560.             return NGX_ERROR;
  561.         }
  562.     }

  563.     if (sc->conf_prefix || sc->root_prefix) {
  564.         if (ngx_http_script_add_full_name_code(sc) != NGX_OK) {
  565.             return NGX_ERROR;
  566.         }
  567.     }

  568.     if (sc->complete_lengths) {
  569.         code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL);
  570.         if (code == NULL) {
  571.             return NGX_ERROR;
  572.         }

  573.         *code = (uintptr_t) NULL;
  574.     }

  575.     if (sc->complete_values) {
  576.         code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t),
  577.                                         &sc->main);
  578.         if (code == NULL) {
  579.             return NGX_ERROR;
  580.         }

  581.         *code = (uintptr_t) NULL;
  582.     }

  583.     return NGX_OK;
  584. }


  585. void *
  586. ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size)
  587. {
  588.     if (*codes == NULL) {
  589.         *codes = ngx_array_create(pool, 256, 1);
  590.         if (*codes == NULL) {
  591.             return NULL;
  592.         }
  593.     }

  594.     return ngx_array_push_n(*codes, size);
  595. }


  596. void *
  597. ngx_http_script_add_code(ngx_array_t *codes, size_t size, void *code)
  598. {
  599.     u_char  *elts, **p;
  600.     void    *new;

  601.     elts = codes->elts;

  602.     new = ngx_array_push_n(codes, size);
  603.     if (new == NULL) {
  604.         return NULL;
  605.     }

  606.     if (code) {
  607.         if (elts != codes->elts) {
  608.             p = code;
  609.             *p += (u_char *) codes->elts - elts;
  610.         }
  611.     }

  612.     return new;
  613. }


  614. ngx_int_t
  615. ngx_http_script_check_length(ngx_http_script_engine_t *e, size_t len)
  616. {
  617.     if (e->end == NULL) {
  618.         return NGX_OK;
  619.     }

  620.     if (e->end - e->pos < (ssize_t) len) {
  621.         ngx_log_error(NGX_LOG_ALERT, e->request->connection->log, 0,
  622.                       "no buffer space in script copy");
  623.         e->ip = ngx_http_script_exit;
  624.         e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
  625.         return NGX_ERROR;
  626.     }

  627.     return NGX_OK;
  628. }


  629. static ngx_int_t
  630. ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc, ngx_str_t *value,
  631.     ngx_uint_t last)
  632. {
  633.     u_char                       *p;
  634.     size_t                        size, len, zero;
  635.     ngx_http_script_copy_code_t  *code;

  636.     zero = (sc->zero && last);
  637.     len = value->len + zero;

  638.     code = ngx_http_script_add_code(*sc->lengths,
  639.                                     sizeof(ngx_http_script_copy_code_t), NULL);
  640.     if (code == NULL) {
  641.         return NGX_ERROR;
  642.     }

  643.     code->code = (ngx_http_script_code_pt) (void *)
  644.                                                  ngx_http_script_copy_len_code;
  645.     code->len = len;

  646.     size = (sizeof(ngx_http_script_copy_code_t) + len + sizeof(uintptr_t) - 1)
  647.             & ~(sizeof(uintptr_t) - 1);

  648.     code = ngx_http_script_add_code(*sc->values, size, &sc->main);
  649.     if (code == NULL) {
  650.         return NGX_ERROR;
  651.     }

  652.     code->code = ngx_http_script_copy_code;
  653.     code->len = len;

  654.     p = ngx_cpymem((u_char *) code + sizeof(ngx_http_script_copy_code_t),
  655.                    value->data, value->len);

  656.     if (zero) {
  657.         *p = '\0';
  658.         sc->zero = 0;
  659.     }

  660.     return NGX_OK;
  661. }


  662. size_t
  663. ngx_http_script_copy_len_code(ngx_http_script_engine_t *e)
  664. {
  665.     ngx_http_script_copy_code_t  *code;

  666.     code = (ngx_http_script_copy_code_t *) e->ip;

  667.     e->ip += sizeof(ngx_http_script_copy_code_t);

  668.     return code->len;
  669. }


  670. void
  671. ngx_http_script_copy_code(ngx_http_script_engine_t *e)
  672. {
  673.     u_char                       *p;
  674.     ngx_http_script_copy_code_t  *code;

  675.     code = (ngx_http_script_copy_code_t *) e->ip;

  676.     p = e->pos;

  677.     if (!e->skip) {

  678.         if (ngx_http_script_check_length(e, code->len) != NGX_OK) {
  679.             return;
  680.         }

  681.         e->pos = ngx_copy(p, e->ip + sizeof(ngx_http_script_copy_code_t),
  682.                           code->len);
  683.     }

  684.     e->ip += sizeof(ngx_http_script_copy_code_t)
  685.           + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));

  686.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
  687.                    "http script copy: \"%*s\"", e->pos - p, p);
  688. }


  689. static ngx_int_t
  690. ngx_http_script_add_var_code(ngx_http_script_compile_t *sc, ngx_str_t *name)
  691. {
  692.     ngx_int_t                    index, *p;
  693.     ngx_http_script_var_code_t  *code;

  694.     index = ngx_http_get_variable_index(sc->cf, name);

  695.     if (index == NGX_ERROR) {
  696.         return NGX_ERROR;
  697.     }

  698.     if (sc->flushes) {
  699.         p = ngx_array_push(*sc->flushes);
  700.         if (p == NULL) {
  701.             return NGX_ERROR;
  702.         }

  703.         *p = index;
  704.     }

  705.     code = ngx_http_script_add_code(*sc->lengths,
  706.                                     sizeof(ngx_http_script_var_code_t), NULL);
  707.     if (code == NULL) {
  708.         return NGX_ERROR;
  709.     }

  710.     code->code = (ngx_http_script_code_pt) (void *)
  711.                                              ngx_http_script_copy_var_len_code;
  712.     code->index = (uintptr_t) index;

  713.     code = ngx_http_script_add_code(*sc->values,
  714.                                     sizeof(ngx_http_script_var_code_t),
  715.                                     &sc->main);
  716.     if (code == NULL) {
  717.         return NGX_ERROR;
  718.     }

  719.     code->code = ngx_http_script_copy_var_code;
  720.     code->index = (uintptr_t) index;

  721.     return NGX_OK;
  722. }


  723. size_t
  724. ngx_http_script_copy_var_len_code(ngx_http_script_engine_t *e)
  725. {
  726.     ngx_http_variable_value_t   *value;
  727.     ngx_http_script_var_code_t  *code;

  728.     code = (ngx_http_script_var_code_t *) e->ip;

  729.     e->ip += sizeof(ngx_http_script_var_code_t);

  730.     if (e->flushed) {
  731.         value = ngx_http_get_indexed_variable(e->request, code->index);

  732.     } else {
  733.         value = ngx_http_get_flushed_variable(e->request, code->index);
  734.     }

  735.     if (value && !value->not_found) {
  736.         return value->len;
  737.     }

  738.     return 0;
  739. }


  740. void
  741. ngx_http_script_copy_var_code(ngx_http_script_engine_t *e)
  742. {
  743.     u_char                      *p;
  744.     ngx_http_variable_value_t   *value;
  745.     ngx_http_script_var_code_t  *code;

  746.     code = (ngx_http_script_var_code_t *) e->ip;

  747.     e->ip += sizeof(ngx_http_script_var_code_t);

  748.     if (!e->skip) {

  749.         if (e->flushed) {
  750.             value = ngx_http_get_indexed_variable(e->request, code->index);

  751.         } else {
  752.             value = ngx_http_get_flushed_variable(e->request, code->index);
  753.         }

  754.         if (value && !value->not_found) {

  755.             if (ngx_http_script_check_length(e, value->len) != NGX_OK) {
  756.                 return;
  757.             }

  758.             p = e->pos;
  759.             e->pos = ngx_copy(p, value->data, value->len);

  760.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP,
  761.                            e->request->connection->log, 0,
  762.                            "http script var: \"%*s\"", e->pos - p, p);
  763.         }
  764.     }
  765. }


  766. static ngx_int_t
  767. ngx_http_script_add_args_code(ngx_http_script_compile_t *sc)
  768. {
  769.     uintptr_t   *code;

  770.     code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL);
  771.     if (code == NULL) {
  772.         return NGX_ERROR;
  773.     }

  774.     *code = (uintptr_t) ngx_http_script_mark_args_code;

  775.     code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t), &sc->main);
  776.     if (code == NULL) {
  777.         return NGX_ERROR;
  778.     }

  779.     *code = (uintptr_t) ngx_http_script_start_args_code;

  780.     return NGX_OK;
  781. }


  782. size_t
  783. ngx_http_script_mark_args_code(ngx_http_script_engine_t *e)
  784. {
  785.     e->is_args = 1;
  786.     e->ip += sizeof(uintptr_t);

  787.     return 1;
  788. }


  789. void
  790. ngx_http_script_start_args_code(ngx_http_script_engine_t *e)
  791. {
  792.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
  793.                    "http script args");

  794.     e->is_args = 1;
  795.     e->args = e->pos;
  796.     e->ip += sizeof(uintptr_t);
  797. }


  798. #if (NGX_PCRE)

  799. void
  800. ngx_http_script_regex_start_code(ngx_http_script_engine_t *e)
  801. {
  802.     int                           *cap;
  803.     u_char                        *p;
  804.     size_t                         len;
  805.     ngx_int_t                      rc;
  806.     ngx_uint_t                     n;
  807.     ngx_http_request_t            *r;
  808.     ngx_http_script_engine_t       le;
  809.     ngx_http_script_len_code_pt    lcode;
  810.     ngx_http_script_regex_code_t  *code;

  811.     code = (ngx_http_script_regex_code_t *) e->ip;

  812.     r = e->request;

  813.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  814.                    "http script regex: \"%V\"", &code->name);

  815.     if (code->uri) {
  816.         e->line = r->uri;
  817.     } else {
  818.         e->sp--;
  819.         e->line.len = e->sp->len;
  820.         e->line.data = e->sp->data;
  821.     }

  822.     rc = ngx_http_regex_exec(r, code->regex, &e->line);

  823.     if (rc == NGX_DECLINED) {
  824.         if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
  825.             ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
  826.                           "\"%V\" does not match \"%V\"",
  827.                           &code->name, &e->line);
  828.         }

  829.         r->ncaptures = 0;

  830.         if (code->test) {
  831.             if (code->negative_test) {
  832.                 e->sp->len = 1;
  833.                 e->sp->data = (u_char *) "1";

  834.             } else {
  835.                 e->sp->len = 0;
  836.                 e->sp->data = (u_char *) "";
  837.             }

  838.             e->sp++;

  839.             e->ip += sizeof(ngx_http_script_regex_code_t);
  840.             return;
  841.         }

  842.         e->ip += code->next;
  843.         return;
  844.     }

  845.     if (rc == NGX_ERROR) {
  846.         e->ip = ngx_http_script_exit;
  847.         e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
  848.         return;
  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.                       "\"%V\" matches \"%V\"", &code->name, &e->line);
  853.     }

  854.     if (code->test) {
  855.         if (code->negative_test) {
  856.             e->sp->len = 0;
  857.             e->sp->data = (u_char *) "";

  858.         } else {
  859.             e->sp->len = 1;
  860.             e->sp->data = (u_char *) "1";
  861.         }

  862.         e->sp++;

  863.         e->ip += sizeof(ngx_http_script_regex_code_t);
  864.         return;
  865.     }

  866.     if (code->status) {
  867.         e->status = code->status;

  868.         if (!code->redirect) {
  869.             e->ip = ngx_http_script_exit;
  870.             return;
  871.         }
  872.     }

  873.     if (code->uri) {
  874.         r->internal = 1;
  875.         r->valid_unparsed_uri = 0;

  876.         if (code->break_cycle) {
  877.             r->valid_location = 0;
  878.             r->uri_changed = 0;

  879.         } else {
  880.             r->uri_changed = 1;
  881.         }
  882.     }

  883.     if (code->lengths == NULL) {
  884.         e->buf.len = code->size;

  885.         cap = r->captures;
  886.         p = r->captures_data;

  887.         for (n = 2; n < r->ncaptures; n += 2) {
  888.             e->buf.len += cap[n + 1] - cap[n];

  889.             if (code->uri) {
  890.                 if (r->quoted_uri || r->plus_in_uri) {
  891.                     e->buf.len += 2 * ngx_escape_uri(NULL, &p[cap[n]],
  892.                                                      cap[n + 1] - cap[n],
  893.                                                      NGX_ESCAPE_ARGS);
  894.                 }
  895.             }
  896.         }

  897.     } else {
  898.         ngx_memzero(&le, sizeof(ngx_http_script_engine_t));

  899.         le.ip = code->lengths->elts;
  900.         le.line = e->line;
  901.         le.request = r;
  902.         le.quote = code->redirect;

  903.         len = 0;

  904.         while (*(uintptr_t *) le.ip) {
  905.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  906.             len += lcode(&le);
  907.         }

  908.         e->buf.len = len;
  909.     }

  910.     if (code->add_args && r->args.len) {
  911.         e->buf.len += r->args.len + 1;
  912.     }

  913.     e->buf.data = ngx_pnalloc(r->pool, e->buf.len);
  914.     if (e->buf.data == NULL) {
  915.         e->ip = ngx_http_script_exit;
  916.         e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
  917.         return;
  918.     }

  919.     e->is_args = 0;
  920.     e->quote = code->redirect;

  921.     e->pos = e->buf.data;
  922.     e->end = e->buf.data + e->buf.len;

  923.     e->ip += sizeof(ngx_http_script_regex_code_t);
  924. }


  925. void
  926. ngx_http_script_regex_end_code(ngx_http_script_engine_t *e)
  927. {
  928.     u_char                            *dst, *src;
  929.     ngx_http_request_t                *r;
  930.     ngx_http_script_regex_end_code_t  *code;

  931.     code = (ngx_http_script_regex_end_code_t *) e->ip;

  932.     r = e->request;

  933.     e->is_args = 0;
  934.     e->quote = 0;

  935.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  936.                    "http script regex end");

  937.     if (code->redirect) {

  938.         dst = e->buf.data;
  939.         src = e->buf.data;

  940.         ngx_unescape_uri(&dst, &src, e->pos - e->buf.data,
  941.                          NGX_UNESCAPE_REDIRECT);

  942.         if (src < e->pos) {
  943.             dst = ngx_movemem(dst, src, e->pos - src);
  944.         }

  945.         e->pos = dst;

  946.         if (code->add_args && r->args.len) {

  947.             if (ngx_http_script_check_length(e, r->args.len + 1) != NGX_OK) {
  948.                 return;
  949.             }

  950.             *e->pos++ = (u_char) (code->args ? '&' : '?');
  951.             e->pos = ngx_copy(e->pos, r->args.data, r->args.len);
  952.         }

  953.         e->buf.len = e->pos - e->buf.data;

  954.         if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
  955.             ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
  956.                           "rewritten redirect: \"%V\"", &e->buf);
  957.         }

  958.         ngx_http_clear_location(r);

  959.         r->headers_out.location = ngx_list_push(&r->headers_out.headers);
  960.         if (r->headers_out.location == NULL) {
  961.             e->ip = ngx_http_script_exit;
  962.             e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
  963.             return;
  964.         }

  965.         r->headers_out.location->hash = 1;
  966.         r->headers_out.location->next = NULL;
  967.         ngx_str_set(&r->headers_out.location->key, "Location");
  968.         r->headers_out.location->value = e->buf;

  969.         e->ip += sizeof(ngx_http_script_regex_end_code_t);
  970.         return;
  971.     }

  972.     if (e->args) {
  973.         e->buf.len = e->args - e->buf.data;

  974.         if (code->add_args && r->args.len) {

  975.             if (ngx_http_script_check_length(e, r->args.len + 1) != NGX_OK) {
  976.                 return;
  977.             }

  978.             *e->pos++ = '&';
  979.             e->pos = ngx_copy(e->pos, r->args.data, r->args.len);
  980.         }

  981.         r->args.len = e->pos - e->args;
  982.         r->args.data = e->args;

  983.         e->args = NULL;

  984.     } else {
  985.         e->buf.len = e->pos - e->buf.data;

  986.         if (!code->add_args) {
  987.             r->args.len = 0;
  988.         }
  989.     }

  990.     if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) {
  991.         ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
  992.                       "rewritten data: \"%V\", args: \"%V\"",
  993.                       &e->buf, &r->args);
  994.     }

  995.     if (code->uri) {
  996.         r->uri = e->buf;

  997.         if (r->uri.len == 0) {
  998.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  999.                           "the rewritten URI has a zero length");
  1000.             e->ip = ngx_http_script_exit;
  1001.             e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
  1002.             return;
  1003.         }

  1004.         ngx_http_set_exten(r);
  1005.     }

  1006.     e->ip += sizeof(ngx_http_script_regex_end_code_t);
  1007. }


  1008. static ngx_int_t
  1009. ngx_http_script_add_capture_code(ngx_http_script_compile_t *sc, ngx_uint_t n)
  1010. {
  1011.     ngx_http_script_copy_capture_code_t  *code;

  1012.     code = ngx_http_script_add_code(*sc->lengths,
  1013.                                     sizeof(ngx_http_script_copy_capture_code_t),
  1014.                                     NULL);
  1015.     if (code == NULL) {
  1016.         return NGX_ERROR;
  1017.     }

  1018.     code->code = (ngx_http_script_code_pt) (void *)
  1019.                                          ngx_http_script_copy_capture_len_code;
  1020.     code->n = 2 * n;


  1021.     code = ngx_http_script_add_code(*sc->values,
  1022.                                     sizeof(ngx_http_script_copy_capture_code_t),
  1023.                                     &sc->main);
  1024.     if (code == NULL) {
  1025.         return NGX_ERROR;
  1026.     }

  1027.     code->code = ngx_http_script_copy_capture_code;
  1028.     code->n = 2 * n;

  1029.     if (sc->ncaptures < n) {
  1030.         sc->ncaptures = n;
  1031.     }

  1032.     return NGX_OK;
  1033. }


  1034. size_t
  1035. ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e)
  1036. {
  1037.     int                                  *cap;
  1038.     u_char                               *p;
  1039.     size_t                                len;
  1040.     ngx_uint_t                            n;
  1041.     ngx_http_request_t                   *r;
  1042.     ngx_http_script_copy_capture_code_t  *code;

  1043.     r = e->request;

  1044.     code = (ngx_http_script_copy_capture_code_t *) e->ip;

  1045.     e->ip += sizeof(ngx_http_script_copy_capture_code_t);

  1046.     n = code->n;

  1047.     if (n < r->ncaptures) {

  1048.         cap = r->captures;
  1049.         len = cap[n + 1] - cap[n];

  1050.         if ((e->is_args || e->quote)
  1051.             && (e->request->quoted_uri || e->request->plus_in_uri))
  1052.         {
  1053.             p = r->captures_data + cap[n];

  1054.             return len + 2 * ngx_escape_uri(NULL, p, len, NGX_ESCAPE_ARGS);

  1055.         } else {
  1056.             return len;
  1057.         }
  1058.     }

  1059.     return 0;
  1060. }


  1061. void
  1062. ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e)
  1063. {
  1064.     int                                  *cap;
  1065.     u_char                               *p, *pos;
  1066.     size_t                                len;
  1067.     uintptr_t                             escape;
  1068.     ngx_uint_t                            n;
  1069.     ngx_http_request_t                   *r;
  1070.     ngx_http_script_copy_capture_code_t  *code;

  1071.     r = e->request;

  1072.     code = (ngx_http_script_copy_capture_code_t *) e->ip;

  1073.     e->ip += sizeof(ngx_http_script_copy_capture_code_t);

  1074.     n = code->n;

  1075.     pos = e->pos;

  1076.     if (n < r->ncaptures) {

  1077.         cap = r->captures;
  1078.         len = cap[n + 1] - cap[n];
  1079.         p = r->captures_data + cap[n];

  1080.         if ((e->is_args || e->quote)
  1081.             && (e->request->quoted_uri || e->request->plus_in_uri))
  1082.         {
  1083.             escape = 2 * ngx_escape_uri(NULL, p, len, NGX_ESCAPE_ARGS);

  1084.             if (ngx_http_script_check_length(e, len + escape) != NGX_OK) {
  1085.                 return;
  1086.             }

  1087.             e->pos = (u_char *) ngx_escape_uri(pos, p, len, NGX_ESCAPE_ARGS);

  1088.         } else {

  1089.             if (ngx_http_script_check_length(e, len) != NGX_OK) {
  1090.                 return;
  1091.             }

  1092.             e->pos = ngx_copy(pos, p, len);
  1093.         }
  1094.     }

  1095.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
  1096.                    "http script capture: \"%*s\"", e->pos - pos, pos);
  1097. }

  1098. #endif


  1099. static ngx_int_t
  1100. ngx_http_script_add_full_name_code(ngx_http_script_compile_t *sc)
  1101. {
  1102.     ngx_http_script_full_name_code_t  *code;

  1103.     code = ngx_http_script_add_code(*sc->lengths,
  1104.                                     sizeof(ngx_http_script_full_name_code_t),
  1105.                                     NULL);
  1106.     if (code == NULL) {
  1107.         return NGX_ERROR;
  1108.     }

  1109.     code->code = (ngx_http_script_code_pt) (void *)
  1110.                                             ngx_http_script_full_name_len_code;
  1111.     code->conf_prefix = sc->conf_prefix;

  1112.     code = ngx_http_script_add_code(*sc->values,
  1113.                                     sizeof(ngx_http_script_full_name_code_t),
  1114.                                     &sc->main);
  1115.     if (code == NULL) {
  1116.         return NGX_ERROR;
  1117.     }

  1118.     code->code = ngx_http_script_full_name_code;
  1119.     code->conf_prefix = sc->conf_prefix;

  1120.     return NGX_OK;
  1121. }


  1122. static size_t
  1123. ngx_http_script_full_name_len_code(ngx_http_script_engine_t *e)
  1124. {
  1125.     ngx_http_script_full_name_code_t  *code;

  1126.     code = (ngx_http_script_full_name_code_t *) e->ip;

  1127.     e->ip += sizeof(ngx_http_script_full_name_code_t);

  1128.     return code->conf_prefix ? ngx_cycle->conf_prefix.len:
  1129.                                ngx_cycle->prefix.len;
  1130. }


  1131. static void
  1132. ngx_http_script_full_name_code(ngx_http_script_engine_t *e)
  1133. {
  1134.     ngx_http_script_full_name_code_t  *code;

  1135.     ngx_str_t  value, *prefix;

  1136.     code = (ngx_http_script_full_name_code_t *) e->ip;

  1137.     value.data = e->buf.data;
  1138.     value.len = e->pos - e->buf.data;

  1139.     prefix = code->conf_prefix ? (ngx_str_t *) &ngx_cycle->conf_prefix:
  1140.                                  (ngx_str_t *) &ngx_cycle->prefix;

  1141.     if (ngx_get_full_name(e->request->pool, prefix, &value) != NGX_OK) {
  1142.         e->ip = ngx_http_script_exit;
  1143.         e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
  1144.         return;
  1145.     }

  1146.     e->buf = value;
  1147.     e->pos = value.data + value.len;
  1148.     e->end = e->pos;

  1149.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
  1150.                    "http script fullname: \"%V\"", &value);

  1151.     e->ip += sizeof(ngx_http_script_full_name_code_t);
  1152. }


  1153. void
  1154. ngx_http_script_return_code(ngx_http_script_engine_t *e)
  1155. {
  1156.     ngx_http_script_return_code_t  *code;

  1157.     code = (ngx_http_script_return_code_t *) e->ip;

  1158.     if (code->status < NGX_HTTP_BAD_REQUEST
  1159.         || code->text.value.len
  1160.         || code->text.lengths)
  1161.     {
  1162.         e->status = ngx_http_send_response(e->request, code->status, NULL,
  1163.                                            &code->text);
  1164.     } else {
  1165.         e->status = code->status;
  1166.     }

  1167.     e->ip = ngx_http_script_exit;
  1168. }


  1169. void
  1170. ngx_http_script_break_code(ngx_http_script_engine_t *e)
  1171. {
  1172.     ngx_http_request_t  *r;

  1173.     r = e->request;

  1174.     if (r->uri_changed) {
  1175.         r->valid_location = 0;
  1176.         r->uri_changed = 0;
  1177.     }

  1178.     e->ip = ngx_http_script_exit;
  1179. }


  1180. void
  1181. ngx_http_script_if_code(ngx_http_script_engine_t *e)
  1182. {
  1183.     ngx_http_script_if_code_t  *code;

  1184.     code = (ngx_http_script_if_code_t *) e->ip;

  1185.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
  1186.                    "http script if");

  1187.     e->sp--;

  1188.     if (e->sp->len && (e->sp->len != 1 || e->sp->data[0] != '0')) {
  1189.         if (code->loc_conf) {
  1190.             e->request->loc_conf = code->loc_conf;
  1191.             ngx_http_update_location_config(e->request);
  1192.         }

  1193.         e->ip += sizeof(ngx_http_script_if_code_t);
  1194.         return;
  1195.     }

  1196.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
  1197.                    "http script if: false");

  1198.     e->ip += code->next;
  1199. }


  1200. void
  1201. ngx_http_script_equal_code(ngx_http_script_engine_t *e)
  1202. {
  1203.     ngx_http_variable_value_t  *val, *res;

  1204.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
  1205.                    "http script equal");

  1206.     e->sp--;
  1207.     val = e->sp;
  1208.     res = e->sp - 1;

  1209.     e->ip += sizeof(uintptr_t);

  1210.     if (val->len == res->len
  1211.         && ngx_strncmp(val->data, res->data, res->len) == 0)
  1212.     {
  1213.         *res = ngx_http_variable_true_value;
  1214.         return;
  1215.     }

  1216.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
  1217.                    "http script equal: no");

  1218.     *res = ngx_http_variable_null_value;
  1219. }


  1220. void
  1221. ngx_http_script_not_equal_code(ngx_http_script_engine_t *e)
  1222. {
  1223.     ngx_http_variable_value_t  *val, *res;

  1224.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
  1225.                    "http script not equal");

  1226.     e->sp--;
  1227.     val = e->sp;
  1228.     res = e->sp - 1;

  1229.     e->ip += sizeof(uintptr_t);

  1230.     if (val->len == res->len
  1231.         && ngx_strncmp(val->data, res->data, res->len) == 0)
  1232.     {
  1233.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
  1234.                        "http script not equal: no");

  1235.         *res = ngx_http_variable_null_value;
  1236.         return;
  1237.     }

  1238.     *res = ngx_http_variable_true_value;
  1239. }


  1240. void
  1241. ngx_http_script_file_code(ngx_http_script_engine_t *e)
  1242. {
  1243.     ngx_str_t                     path;
  1244.     ngx_http_request_t           *r;
  1245.     ngx_open_file_info_t          of;
  1246.     ngx_http_core_loc_conf_t     *clcf;
  1247.     ngx_http_variable_value_t    *value;
  1248.     ngx_http_script_file_code_t  *code;

  1249.     value = e->sp - 1;

  1250.     code = (ngx_http_script_file_code_t *) e->ip;
  1251.     e->ip += sizeof(ngx_http_script_file_code_t);

  1252.     path.len = value->len - 1;
  1253.     path.data = value->data;

  1254.     r = e->request;

  1255.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1256.                    "http script file op %p \"%V\"", (void *) code->op, &path);

  1257.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  1258.     ngx_memzero(&of, sizeof(ngx_open_file_info_t));

  1259.     of.read_ahead = clcf->read_ahead;
  1260.     of.directio = clcf->directio;
  1261.     of.valid = clcf->open_file_cache_valid;
  1262.     of.min_uses = clcf->open_file_cache_min_uses;
  1263.     of.test_only = 1;
  1264.     of.errors = clcf->open_file_cache_errors;
  1265.     of.events = clcf->open_file_cache_events;

  1266.     if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
  1267.         e->ip = ngx_http_script_exit;
  1268.         e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
  1269.         return;
  1270.     }

  1271.     if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
  1272.         != NGX_OK)
  1273.     {
  1274.         if (of.err == 0) {
  1275.             e->ip = ngx_http_script_exit;
  1276.             e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
  1277.             return;
  1278.         }

  1279.         if (of.err != NGX_ENOENT
  1280.             && of.err != NGX_ENOTDIR
  1281.             && of.err != NGX_ENAMETOOLONG)
  1282.         {
  1283.             ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
  1284.                           "%s \"%s\" failed", of.failed, value->data);
  1285.         }

  1286.         switch (code->op) {

  1287.         case ngx_http_script_file_plain:
  1288.         case ngx_http_script_file_dir:
  1289.         case ngx_http_script_file_exists:
  1290.         case ngx_http_script_file_exec:
  1291.              goto false_value;

  1292.         case ngx_http_script_file_not_plain:
  1293.         case ngx_http_script_file_not_dir:
  1294.         case ngx_http_script_file_not_exists:
  1295.         case ngx_http_script_file_not_exec:
  1296.              goto true_value;
  1297.         }

  1298.         goto false_value;
  1299.     }

  1300.     switch (code->op) {
  1301.     case ngx_http_script_file_plain:
  1302.         if (of.is_file) {
  1303.              goto true_value;
  1304.         }
  1305.         goto false_value;

  1306.     case ngx_http_script_file_not_plain:
  1307.         if (of.is_file) {
  1308.             goto false_value;
  1309.         }
  1310.         goto true_value;

  1311.     case ngx_http_script_file_dir:
  1312.         if (of.is_dir) {
  1313.              goto true_value;
  1314.         }
  1315.         goto false_value;

  1316.     case ngx_http_script_file_not_dir:
  1317.         if (of.is_dir) {
  1318.             goto false_value;
  1319.         }
  1320.         goto true_value;

  1321.     case ngx_http_script_file_exists:
  1322.         if (of.is_file || of.is_dir || of.is_link) {
  1323.              goto true_value;
  1324.         }
  1325.         goto false_value;

  1326.     case ngx_http_script_file_not_exists:
  1327.         if (of.is_file || of.is_dir || of.is_link) {
  1328.             goto false_value;
  1329.         }
  1330.         goto true_value;

  1331.     case ngx_http_script_file_exec:
  1332.         if (of.is_exec) {
  1333.              goto true_value;
  1334.         }
  1335.         goto false_value;

  1336.     case ngx_http_script_file_not_exec:
  1337.         if (of.is_exec) {
  1338.             goto false_value;
  1339.         }
  1340.         goto true_value;
  1341.     }

  1342. false_value:

  1343.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1344.                    "http script file op false");

  1345.     *value = ngx_http_variable_null_value;
  1346.     return;

  1347. true_value:

  1348.     *value = ngx_http_variable_true_value;
  1349.     return;
  1350. }


  1351. void
  1352. ngx_http_script_complex_value_code(ngx_http_script_engine_t *e)
  1353. {
  1354.     size_t                                 len;
  1355.     ngx_http_script_engine_t               le;
  1356.     ngx_http_script_len_code_pt            lcode;
  1357.     ngx_http_script_complex_value_code_t  *code;

  1358.     code = (ngx_http_script_complex_value_code_t *) e->ip;

  1359.     e->ip += sizeof(ngx_http_script_complex_value_code_t);

  1360.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
  1361.                    "http script complex value");

  1362.     ngx_memzero(&le, sizeof(ngx_http_script_engine_t));

  1363.     le.ip = code->lengths->elts;
  1364.     le.line = e->line;
  1365.     le.request = e->request;
  1366.     le.is_args = e->is_args;
  1367.     le.quote = e->quote;

  1368.     for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {
  1369.         lcode = *(ngx_http_script_len_code_pt *) le.ip;
  1370.     }

  1371.     e->buf.len = len;
  1372.     e->buf.data = ngx_pnalloc(e->request->pool, len);
  1373.     if (e->buf.data == NULL) {
  1374.         e->ip = ngx_http_script_exit;
  1375.         e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
  1376.         return;
  1377.     }

  1378.     e->pos = e->buf.data;
  1379.     e->end = e->buf.data + len;

  1380.     e->sp->len = e->buf.len;
  1381.     e->sp->data = e->buf.data;
  1382.     e->sp++;
  1383. }


  1384. void
  1385. ngx_http_script_complex_value_end_code(ngx_http_script_engine_t *e)
  1386. {
  1387.     ngx_http_variable_value_t  *val;

  1388.     val = e->sp - 1;

  1389.     e->ip += sizeof(ngx_http_script_complex_value_end_code_t);

  1390.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
  1391.                    "http script complex value end");

  1392.     if (val->data == e->buf.data) {
  1393.         val->len = e->pos - e->buf.data;
  1394.     }
  1395. }


  1396. void
  1397. ngx_http_script_value_code(ngx_http_script_engine_t *e)
  1398. {
  1399.     ngx_http_script_value_code_t  *code;

  1400.     code = (ngx_http_script_value_code_t *) e->ip;

  1401.     e->ip += sizeof(ngx_http_script_value_code_t);

  1402.     e->sp->len = code->text_len;
  1403.     e->sp->data = (u_char *) code->text_data;

  1404.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
  1405.                    "http script value: \"%v\"", e->sp);

  1406.     e->sp++;
  1407. }


  1408. void
  1409. ngx_http_script_set_var_code(ngx_http_script_engine_t *e)
  1410. {
  1411.     ngx_http_request_t          *r;
  1412.     ngx_http_script_var_code_t  *code;

  1413.     code = (ngx_http_script_var_code_t *) e->ip;

  1414.     e->ip += sizeof(ngx_http_script_var_code_t);

  1415.     r = e->request;

  1416.     e->sp--;

  1417.     r->variables[code->index].len = e->sp->len;
  1418.     r->variables[code->index].valid = 1;
  1419.     r->variables[code->index].no_cacheable = 0;
  1420.     r->variables[code->index].not_found = 0;
  1421.     r->variables[code->index].data = e->sp->data;

  1422. #if (NGX_DEBUG)
  1423.     {
  1424.     ngx_http_variable_t        *v;
  1425.     ngx_http_core_main_conf_t  *cmcf;

  1426.     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);

  1427.     v = cmcf->variables.elts;

  1428.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
  1429.                    "http script set $%V", &v[code->index].name);
  1430.     }
  1431. #endif
  1432. }


  1433. void
  1434. ngx_http_script_var_set_handler_code(ngx_http_script_engine_t *e)
  1435. {
  1436.     ngx_http_script_var_handler_code_t  *code;

  1437.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
  1438.                    "http script set var handler");

  1439.     code = (ngx_http_script_var_handler_code_t *) e->ip;

  1440.     e->ip += sizeof(ngx_http_script_var_handler_code_t);

  1441.     e->sp--;

  1442.     code->handler(e->request, e->sp, code->data);
  1443. }


  1444. void
  1445. ngx_http_script_var_code(ngx_http_script_engine_t *e)
  1446. {
  1447.     ngx_http_variable_value_t   *value;
  1448.     ngx_http_script_var_code_t  *code;

  1449.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
  1450.                    "http script var");

  1451.     code = (ngx_http_script_var_code_t *) e->ip;

  1452.     e->ip += sizeof(ngx_http_script_var_code_t);

  1453.     value = ngx_http_get_flushed_variable(e->request, code->index);

  1454.     if (value && !value->not_found) {
  1455.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
  1456.                        "http script var: \"%v\"", value);

  1457.         *e->sp = *value;
  1458.         e->sp++;

  1459.         return;
  1460.     }

  1461.     *e->sp = ngx_http_variable_null_value;
  1462.     e->sp++;
  1463. }


  1464. void
  1465. ngx_http_script_nop_code(ngx_http_script_engine_t *e)
  1466. {
  1467.     e->ip += sizeof(uintptr_t);
  1468. }