src/http/modules/ngx_http_rewrite_module.c - nginx source code

Global variables defined

Data types defined

Functions 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. typedef struct {
  9.     ngx_array_t  *codes;        /* uintptr_t */

  10.     ngx_uint_t    stack_size;

  11.     ngx_flag_t    log;
  12.     ngx_flag_t    uninitialized_variable_warn;
  13. } ngx_http_rewrite_loc_conf_t;


  14. static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf);
  15. static char *ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf,
  16.     void *parent, void *child);
  17. static ngx_int_t ngx_http_rewrite_init(ngx_conf_t *cf);
  18. static char *ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
  19. static char *ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd,
  20.     void *conf);
  21. static char *ngx_http_rewrite_break(ngx_conf_t *cf, ngx_command_t *cmd,
  22.     void *conf);
  23. static char *ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd,
  24.     void *conf);
  25. static char * ngx_http_rewrite_if_condition(ngx_conf_t *cf,
  26.     ngx_http_rewrite_loc_conf_t *lcf);
  27. static char *ngx_http_rewrite_variable(ngx_conf_t *cf,
  28.     ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value);
  29. static char *ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd,
  30.     void *conf);
  31. static char * ngx_http_rewrite_value(ngx_conf_t *cf,
  32.     ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value);


  33. static ngx_command_t  ngx_http_rewrite_commands[] = {

  34.     { ngx_string("rewrite"),
  35.       NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
  36.                        |NGX_CONF_TAKE23,
  37.       ngx_http_rewrite,
  38.       NGX_HTTP_LOC_CONF_OFFSET,
  39.       0,
  40.       NULL },

  41.     { ngx_string("return"),
  42.       NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
  43.                        |NGX_CONF_TAKE12,
  44.       ngx_http_rewrite_return,
  45.       NGX_HTTP_LOC_CONF_OFFSET,
  46.       0,
  47.       NULL },

  48.     { ngx_string("break"),
  49.       NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
  50.                        |NGX_CONF_NOARGS,
  51.       ngx_http_rewrite_break,
  52.       NGX_HTTP_LOC_CONF_OFFSET,
  53.       0,
  54.       NULL },

  55.     { ngx_string("if"),
  56.       NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_1MORE,
  57.       ngx_http_rewrite_if,
  58.       NGX_HTTP_LOC_CONF_OFFSET,
  59.       0,
  60.       NULL },

  61.     { ngx_string("set"),
  62.       NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
  63.                        |NGX_CONF_TAKE2,
  64.       ngx_http_rewrite_set,
  65.       NGX_HTTP_LOC_CONF_OFFSET,
  66.       0,
  67.       NULL },

  68.     { ngx_string("rewrite_log"),
  69.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF
  70.                         |NGX_HTTP_LIF_CONF|NGX_CONF_FLAG,
  71.       ngx_conf_set_flag_slot,
  72.       NGX_HTTP_LOC_CONF_OFFSET,
  73.       offsetof(ngx_http_rewrite_loc_conf_t, log),
  74.       NULL },

  75.     { ngx_string("uninitialized_variable_warn"),
  76.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF
  77.                         |NGX_HTTP_LIF_CONF|NGX_CONF_FLAG,
  78.       ngx_conf_set_flag_slot,
  79.       NGX_HTTP_LOC_CONF_OFFSET,
  80.       offsetof(ngx_http_rewrite_loc_conf_t, uninitialized_variable_warn),
  81.       NULL },

  82.       ngx_null_command
  83. };


  84. static ngx_http_module_t  ngx_http_rewrite_module_ctx = {
  85.     NULL,                                  /* preconfiguration */
  86.     ngx_http_rewrite_init,                 /* postconfiguration */

  87.     NULL,                                  /* create main configuration */
  88.     NULL,                                  /* init main configuration */

  89.     NULL,                                  /* create server configuration */
  90.     NULL,                                  /* merge server configuration */

  91.     ngx_http_rewrite_create_loc_conf,      /* create location configuration */
  92.     ngx_http_rewrite_merge_loc_conf        /* merge location configuration */
  93. };


  94. ngx_module_t  ngx_http_rewrite_module = {
  95.     NGX_MODULE_V1,
  96.     &ngx_http_rewrite_module_ctx,          /* module context */
  97.     ngx_http_rewrite_commands,             /* module directives */
  98.     NGX_HTTP_MODULE,                       /* module type */
  99.     NULL,                                  /* init master */
  100.     NULL,                                  /* init module */
  101.     NULL,                                  /* init process */
  102.     NULL,                                  /* init thread */
  103.     NULL,                                  /* exit thread */
  104.     NULL,                                  /* exit process */
  105.     NULL,                                  /* exit master */
  106.     NGX_MODULE_V1_PADDING
  107. };


  108. static ngx_int_t
  109. ngx_http_rewrite_handler(ngx_http_request_t *r)
  110. {
  111.     ngx_int_t                     index;
  112.     ngx_http_script_code_pt       code;
  113.     ngx_http_script_engine_t     *e;
  114.     ngx_http_core_srv_conf_t     *cscf;
  115.     ngx_http_core_main_conf_t    *cmcf;
  116.     ngx_http_rewrite_loc_conf_t  *rlcf;

  117.     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
  118.     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
  119.     index = cmcf->phase_engine.location_rewrite_index;

  120.     if (r->phase_handler == index && r->loc_conf == cscf->ctx->loc_conf) {
  121.         /* skipping location rewrite phase for server null location */
  122.         return NGX_DECLINED;
  123.     }

  124.     rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);

  125.     if (rlcf->codes == NULL) {
  126.         return NGX_DECLINED;
  127.     }

  128.     e = ngx_pcalloc(r->pool, sizeof(ngx_http_script_engine_t));
  129.     if (e == NULL) {
  130.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  131.     }

  132.     e->sp = ngx_pcalloc(r->pool,
  133.                         rlcf->stack_size * sizeof(ngx_http_variable_value_t));
  134.     if (e->sp == NULL) {
  135.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  136.     }

  137.     e->ip = rlcf->codes->elts;
  138.     e->request = r;
  139.     e->quote = 1;
  140.     e->log = rlcf->log;
  141.     e->status = NGX_DECLINED;

  142.     while (*(uintptr_t *) e->ip) {
  143.         code = *(ngx_http_script_code_pt *) e->ip;
  144.         code(e);
  145.     }

  146.     return e->status;
  147. }


  148. static ngx_int_t
  149. ngx_http_rewrite_var(ngx_http_request_t *r, ngx_http_variable_value_t *v,
  150.     uintptr_t data)
  151. {
  152.     ngx_http_variable_t          *var;
  153.     ngx_http_core_main_conf_t    *cmcf;
  154.     ngx_http_rewrite_loc_conf_t  *rlcf;

  155.     rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);

  156.     if (rlcf->uninitialized_variable_warn == 0) {
  157.         *v = ngx_http_variable_null_value;
  158.         return NGX_OK;
  159.     }

  160.     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);

  161.     var = cmcf->variables.elts;

  162.     /*
  163.      * the ngx_http_rewrite_module sets variables directly in r->variables,
  164.      * and they should be handled by ngx_http_get_indexed_variable(),
  165.      * so the handler is called only if the variable is not initialized
  166.      */

  167.     ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
  168.                   "using uninitialized \"%V\" variable", &var[data].name);

  169.     *v = ngx_http_variable_null_value;

  170.     return NGX_OK;
  171. }


  172. static void *
  173. ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf)
  174. {
  175.     ngx_http_rewrite_loc_conf_t  *conf;

  176.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_rewrite_loc_conf_t));
  177.     if (conf == NULL) {
  178.         return NULL;
  179.     }

  180.     conf->stack_size = NGX_CONF_UNSET_UINT;
  181.     conf->log = NGX_CONF_UNSET;
  182.     conf->uninitialized_variable_warn = NGX_CONF_UNSET;

  183.     return conf;
  184. }


  185. static char *
  186. ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  187. {
  188.     ngx_http_rewrite_loc_conf_t *prev = parent;
  189.     ngx_http_rewrite_loc_conf_t *conf = child;

  190.     uintptr_t  *code;

  191.     ngx_conf_merge_value(conf->log, prev->log, 0);
  192.     ngx_conf_merge_value(conf->uninitialized_variable_warn,
  193.                          prev->uninitialized_variable_warn, 1);
  194.     ngx_conf_merge_uint_value(conf->stack_size, prev->stack_size, 10);

  195.     if (conf->codes == NULL) {
  196.         return NGX_CONF_OK;
  197.     }

  198.     if (conf->codes == prev->codes) {
  199.         return NGX_CONF_OK;
  200.     }

  201.     code = ngx_array_push_n(conf->codes, sizeof(uintptr_t));
  202.     if (code == NULL) {
  203.         return NGX_CONF_ERROR;
  204.     }

  205.     *code = (uintptr_t) NULL;

  206.     return NGX_CONF_OK;
  207. }


  208. static ngx_int_t
  209. ngx_http_rewrite_init(ngx_conf_t *cf)
  210. {
  211.     ngx_http_handler_pt        *h;
  212.     ngx_http_core_main_conf_t  *cmcf;

  213.     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

  214.     h = ngx_array_push(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers);
  215.     if (h == NULL) {
  216.         return NGX_ERROR;
  217.     }

  218.     *h = ngx_http_rewrite_handler;

  219.     h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
  220.     if (h == NULL) {
  221.         return NGX_ERROR;
  222.     }

  223.     *h = ngx_http_rewrite_handler;

  224.     return NGX_OK;
  225. }


  226. static char *
  227. ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  228. {
  229.     ngx_http_rewrite_loc_conf_t  *lcf = conf;

  230.     ngx_str_t                         *value;
  231.     ngx_uint_t                         last;
  232.     ngx_regex_compile_t                rc;
  233.     ngx_http_script_code_pt           *code;
  234.     ngx_http_script_compile_t          sc;
  235.     ngx_http_script_regex_code_t      *regex;
  236.     ngx_http_script_regex_end_code_t  *regex_end;
  237.     u_char                             errstr[NGX_MAX_CONF_ERRSTR];

  238.     regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
  239.                                        sizeof(ngx_http_script_regex_code_t));
  240.     if (regex == NULL) {
  241.         return NGX_CONF_ERROR;
  242.     }

  243.     ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));

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

  245.     if (value[2].len == 0) {
  246.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty replacement");
  247.         return NGX_CONF_ERROR;
  248.     }

  249.     ngx_memzero(&rc, sizeof(ngx_regex_compile_t));

  250.     rc.pattern = value[1];
  251.     rc.err.len = NGX_MAX_CONF_ERRSTR;
  252.     rc.err.data = errstr;

  253.     /* TODO: NGX_REGEX_CASELESS */

  254.     regex->regex = ngx_http_regex_compile(cf, &rc);
  255.     if (regex->regex == NULL) {
  256.         return NGX_CONF_ERROR;
  257.     }

  258.     regex->code = ngx_http_script_regex_start_code;
  259.     regex->uri = 1;
  260.     regex->name = value[1];

  261.     if (value[2].data[value[2].len - 1] == '?') {

  262.         /* the last "?" drops the original arguments */
  263.         value[2].len--;

  264.     } else {
  265.         regex->add_args = 1;
  266.     }

  267.     last = 0;

  268.     if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0
  269.         || ngx_strncmp(value[2].data, "https://", sizeof("https://") - 1) == 0
  270.         || ngx_strncmp(value[2].data, "$scheme", sizeof("$scheme") - 1) == 0)
  271.     {
  272.         regex->status = NGX_HTTP_MOVED_TEMPORARILY;
  273.         regex->redirect = 1;
  274.         last = 1;
  275.     }

  276.     if (cf->args->nelts == 4) {
  277.         if (ngx_strcmp(value[3].data, "last") == 0) {
  278.             last = 1;

  279.         } else if (ngx_strcmp(value[3].data, "break") == 0) {
  280.             regex->break_cycle = 1;
  281.             last = 1;

  282.         } else if (ngx_strcmp(value[3].data, "redirect") == 0) {
  283.             regex->status = NGX_HTTP_MOVED_TEMPORARILY;
  284.             regex->redirect = 1;
  285.             last = 1;

  286.         } else if (ngx_strcmp(value[3].data, "permanent") == 0) {
  287.             regex->status = NGX_HTTP_MOVED_PERMANENTLY;
  288.             regex->redirect = 1;
  289.             last = 1;

  290.         } else {
  291.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  292.                                "invalid parameter \"%V\"", &value[3]);
  293.             return NGX_CONF_ERROR;
  294.         }
  295.     }

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

  297.     sc.cf = cf;
  298.     sc.source = &value[2];
  299.     sc.lengths = &regex->lengths;
  300.     sc.values = &lcf->codes;
  301.     sc.variables = ngx_http_script_variables_count(&value[2]);
  302.     sc.main = regex;
  303.     sc.complete_lengths = 1;
  304.     sc.compile_args = !regex->redirect;

  305.     if (ngx_http_script_compile(&sc) != NGX_OK) {
  306.         return NGX_CONF_ERROR;
  307.     }

  308.     regex = sc.main;

  309.     regex->size = sc.size;
  310.     regex->args = sc.args;

  311.     if (sc.variables == 0 && !sc.dup_capture) {
  312.         regex->lengths = NULL;
  313.     }

  314.     regex_end = ngx_http_script_add_code(lcf->codes,
  315.                                       sizeof(ngx_http_script_regex_end_code_t),
  316.                                       &regex);
  317.     if (regex_end == NULL) {
  318.         return NGX_CONF_ERROR;
  319.     }

  320.     regex_end->code = ngx_http_script_regex_end_code;
  321.     regex_end->uri = regex->uri;
  322.     regex_end->args = regex->args;
  323.     regex_end->add_args = regex->add_args;
  324.     regex_end->redirect = regex->redirect;

  325.     if (last) {
  326.         code = ngx_http_script_add_code(lcf->codes, sizeof(uintptr_t), &regex);
  327.         if (code == NULL) {
  328.             return NGX_CONF_ERROR;
  329.         }

  330.         *code = NULL;
  331.     }

  332.     regex->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
  333.                                               - (u_char *) regex;

  334.     return NGX_CONF_OK;
  335. }


  336. static char *
  337. ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  338. {
  339.     ngx_http_rewrite_loc_conf_t  *lcf = conf;

  340.     u_char                            *p;
  341.     ngx_str_t                         *value, *v;
  342.     ngx_http_script_return_code_t     *ret;
  343.     ngx_http_compile_complex_value_t   ccv;

  344.     ret = ngx_http_script_start_code(cf->pool, &lcf->codes,
  345.                                      sizeof(ngx_http_script_return_code_t));
  346.     if (ret == NULL) {
  347.         return NGX_CONF_ERROR;
  348.     }

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

  350.     ngx_memzero(ret, sizeof(ngx_http_script_return_code_t));

  351.     ret->code = ngx_http_script_return_code;

  352.     p = value[1].data;

  353.     ret->status = ngx_atoi(p, value[1].len);

  354.     if (ret->status == (uintptr_t) NGX_ERROR) {

  355.         if (cf->args->nelts == 2
  356.             && (ngx_strncmp(p, "http://", sizeof("http://") - 1) == 0
  357.                 || ngx_strncmp(p, "https://", sizeof("https://") - 1) == 0
  358.                 || ngx_strncmp(p, "$scheme", sizeof("$scheme") - 1) == 0))
  359.         {
  360.             ret->status = NGX_HTTP_MOVED_TEMPORARILY;
  361.             v = &value[1];

  362.         } else {
  363.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  364.                                "invalid return code \"%V\"", &value[1]);
  365.             return NGX_CONF_ERROR;
  366.         }

  367.     } else {

  368.         if (ret->status > 999) {
  369.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  370.                                "invalid return code \"%V\"", &value[1]);
  371.             return NGX_CONF_ERROR;
  372.         }

  373.         if (cf->args->nelts == 2) {
  374.             ngx_str_set(&ret->text.value, "");
  375.             return NGX_CONF_OK;
  376.         }

  377.         v = &value[2];
  378.     }

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

  380.     ccv.cf = cf;
  381.     ccv.value = v;
  382.     ccv.complex_value = &ret->text;

  383.     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  384.         return NGX_CONF_ERROR;
  385.     }

  386.     return NGX_CONF_OK;
  387. }


  388. static char *
  389. ngx_http_rewrite_break(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  390. {
  391.     ngx_http_rewrite_loc_conf_t *lcf = conf;

  392.     ngx_http_script_code_pt  *code;

  393.     code = ngx_http_script_start_code(cf->pool, &lcf->codes, sizeof(uintptr_t));
  394.     if (code == NULL) {
  395.         return NGX_CONF_ERROR;
  396.     }

  397.     *code = ngx_http_script_break_code;

  398.     return NGX_CONF_OK;
  399. }


  400. static char *
  401. ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  402. {
  403.     ngx_http_rewrite_loc_conf_t  *lcf = conf;

  404.     void                         *mconf;
  405.     char                         *rv;
  406.     u_char                       *elts;
  407.     ngx_uint_t                    i;
  408.     ngx_conf_t                    save;
  409.     ngx_http_module_t            *module;
  410.     ngx_http_conf_ctx_t          *ctx, *pctx;
  411.     ngx_http_core_loc_conf_t     *clcf, *pclcf;
  412.     ngx_http_script_if_code_t    *if_code;
  413.     ngx_http_rewrite_loc_conf_t  *nlcf;

  414.     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
  415.     if (ctx == NULL) {
  416.         return NGX_CONF_ERROR;
  417.     }

  418.     pctx = cf->ctx;
  419.     ctx->main_conf = pctx->main_conf;
  420.     ctx->srv_conf = pctx->srv_conf;

  421.     ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
  422.     if (ctx->loc_conf == NULL) {
  423.         return NGX_CONF_ERROR;
  424.     }

  425.     for (i = 0; cf->cycle->modules[i]; i++) {
  426.         if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {
  427.             continue;
  428.         }

  429.         module = cf->cycle->modules[i]->ctx;

  430.         if (module->create_loc_conf) {

  431.             mconf = module->create_loc_conf(cf);
  432.             if (mconf == NULL) {
  433.                 return NGX_CONF_ERROR;
  434.             }

  435.             ctx->loc_conf[cf->cycle->modules[i]->ctx_index] = mconf;
  436.         }
  437.     }

  438.     pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];

  439.     clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
  440.     clcf->loc_conf = ctx->loc_conf;
  441.     clcf->name = pclcf->name;
  442.     clcf->noname = 1;

  443.     if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {
  444.         return NGX_CONF_ERROR;
  445.     }

  446.     if (ngx_http_rewrite_if_condition(cf, lcf) != NGX_CONF_OK) {
  447.         return NGX_CONF_ERROR;
  448.     }

  449.     if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_script_if_code_t));
  450.     if (if_code == NULL) {
  451.         return NGX_CONF_ERROR;
  452.     }

  453.     if_code->code = ngx_http_script_if_code;

  454.     elts = lcf->codes->elts;


  455.     /* the inner directives must be compiled to the same code array */

  456.     nlcf = ctx->loc_conf[ngx_http_rewrite_module.ctx_index];
  457.     nlcf->codes = lcf->codes;


  458.     save = *cf;
  459.     cf->ctx = ctx;

  460.     if (cf->cmd_type == NGX_HTTP_SRV_CONF) {
  461.         if_code->loc_conf = NULL;
  462.         cf->cmd_type = NGX_HTTP_SIF_CONF;

  463.     } else {
  464.         if_code->loc_conf = ctx->loc_conf;
  465.         cf->cmd_type = NGX_HTTP_LIF_CONF;
  466.     }

  467.     rv = ngx_conf_parse(cf, NULL);

  468.     *cf = save;

  469.     if (rv != NGX_CONF_OK) {
  470.         return rv;
  471.     }


  472.     if (elts != lcf->codes->elts) {
  473.         if_code = (ngx_http_script_if_code_t *)
  474.                    ((u_char *) if_code + ((u_char *) lcf->codes->elts - elts));
  475.     }

  476.     if_code->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
  477.                                                 - (u_char *) if_code;

  478.     /* the code array belong to parent block */

  479.     nlcf->codes = NULL;

  480.     return NGX_CONF_OK;
  481. }


  482. static char *
  483. ngx_http_rewrite_if_condition(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf)
  484. {
  485.     u_char                        *p;
  486.     size_t                         len;
  487.     ngx_str_t                     *value;
  488.     ngx_uint_t                     cur, last;
  489.     ngx_regex_compile_t            rc;
  490.     ngx_http_script_code_pt       *code;
  491.     ngx_http_script_file_code_t   *fop;
  492.     ngx_http_script_regex_code_t  *regex;
  493.     u_char                         errstr[NGX_MAX_CONF_ERRSTR];

  494.     value = cf->args->elts;
  495.     last = cf->args->nelts - 1;

  496.     if (value[1].len < 1 || value[1].data[0] != '(') {
  497.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  498.                            "invalid condition \"%V\"", &value[1]);
  499.         return NGX_CONF_ERROR;
  500.     }

  501.     if (value[1].len == 1) {
  502.         cur = 2;

  503.     } else {
  504.         cur = 1;
  505.         value[1].len--;
  506.         value[1].data++;
  507.     }

  508.     if (value[last].len < 1 || value[last].data[value[last].len - 1] != ')') {
  509.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  510.                            "invalid condition \"%V\"", &value[last]);
  511.         return NGX_CONF_ERROR;
  512.     }

  513.     if (value[last].len == 1) {
  514.         last--;

  515.     } else {
  516.         value[last].len--;
  517.         value[last].data[value[last].len] = '\0';
  518.     }

  519.     len = value[cur].len;
  520.     p = value[cur].data;

  521.     if (len > 1 && p[0] == '$') {

  522.         if (cur != last && cur + 2 != last) {
  523.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  524.                                "invalid condition \"%V\"", &value[cur]);
  525.             return NGX_CONF_ERROR;
  526.         }

  527.         if (ngx_http_rewrite_variable(cf, lcf, &value[cur]) != NGX_CONF_OK) {
  528.             return NGX_CONF_ERROR;
  529.         }

  530.         if (cur == last) {
  531.             return NGX_CONF_OK;
  532.         }

  533.         cur++;

  534.         len = value[cur].len;
  535.         p = value[cur].data;

  536.         if (len == 1 && p[0] == '=') {

  537.             if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
  538.                 return NGX_CONF_ERROR;
  539.             }

  540.             code = ngx_http_script_start_code(cf->pool, &lcf->codes,
  541.                                               sizeof(uintptr_t));
  542.             if (code == NULL) {
  543.                 return NGX_CONF_ERROR;
  544.             }

  545.             *code = ngx_http_script_equal_code;

  546.             return NGX_CONF_OK;
  547.         }

  548.         if (len == 2 && p[0] == '!' && p[1] == '=') {

  549.             if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
  550.                 return NGX_CONF_ERROR;
  551.             }

  552.             code = ngx_http_script_start_code(cf->pool, &lcf->codes,
  553.                                               sizeof(uintptr_t));
  554.             if (code == NULL) {
  555.                 return NGX_CONF_ERROR;
  556.             }

  557.             *code = ngx_http_script_not_equal_code;
  558.             return NGX_CONF_OK;
  559.         }

  560.         if ((len == 1 && p[0] == '~')
  561.             || (len == 2 && p[0] == '~' && p[1] == '*')
  562.             || (len == 2 && p[0] == '!' && p[1] == '~')
  563.             || (len == 3 && p[0] == '!' && p[1] == '~' && p[2] == '*'))
  564.         {
  565.             regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
  566.                                          sizeof(ngx_http_script_regex_code_t));
  567.             if (regex == NULL) {
  568.                 return NGX_CONF_ERROR;
  569.             }

  570.             ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));

  571.             ngx_memzero(&rc, sizeof(ngx_regex_compile_t));

  572.             rc.pattern = value[last];
  573.             rc.options = (p[len - 1] == '*') ? NGX_REGEX_CASELESS : 0;
  574.             rc.err.len = NGX_MAX_CONF_ERRSTR;
  575.             rc.err.data = errstr;

  576.             regex->regex = ngx_http_regex_compile(cf, &rc);
  577.             if (regex->regex == NULL) {
  578.                 return NGX_CONF_ERROR;
  579.             }

  580.             regex->code = ngx_http_script_regex_start_code;
  581.             regex->next = sizeof(ngx_http_script_regex_code_t);
  582.             regex->test = 1;
  583.             if (p[0] == '!') {
  584.                 regex->negative_test = 1;
  585.             }
  586.             regex->name = value[last];

  587.             return NGX_CONF_OK;
  588.         }

  589.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  590.                            "unexpected \"%V\" in condition", &value[cur]);
  591.         return NGX_CONF_ERROR;

  592.     } else if ((len == 2 && p[0] == '-')
  593.                || (len == 3 && p[0] == '!' && p[1] == '-'))
  594.     {
  595.         if (cur + 1 != last) {
  596.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  597.                                "invalid condition \"%V\"", &value[cur]);
  598.             return NGX_CONF_ERROR;
  599.         }

  600.         value[last].data[value[last].len] = '\0';
  601.         value[last].len++;

  602.         if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
  603.             return NGX_CONF_ERROR;
  604.         }

  605.         fop = ngx_http_script_start_code(cf->pool, &lcf->codes,
  606.                                           sizeof(ngx_http_script_file_code_t));
  607.         if (fop == NULL) {
  608.             return NGX_CONF_ERROR;
  609.         }

  610.         fop->code = ngx_http_script_file_code;

  611.         if (p[1] == 'f') {
  612.             fop->op = ngx_http_script_file_plain;
  613.             return NGX_CONF_OK;
  614.         }

  615.         if (p[1] == 'd') {
  616.             fop->op = ngx_http_script_file_dir;
  617.             return NGX_CONF_OK;
  618.         }

  619.         if (p[1] == 'e') {
  620.             fop->op = ngx_http_script_file_exists;
  621.             return NGX_CONF_OK;
  622.         }

  623.         if (p[1] == 'x') {
  624.             fop->op = ngx_http_script_file_exec;
  625.             return NGX_CONF_OK;
  626.         }

  627.         if (p[0] == '!') {
  628.             if (p[2] == 'f') {
  629.                 fop->op = ngx_http_script_file_not_plain;
  630.                 return NGX_CONF_OK;
  631.             }

  632.             if (p[2] == 'd') {
  633.                 fop->op = ngx_http_script_file_not_dir;
  634.                 return NGX_CONF_OK;
  635.             }

  636.             if (p[2] == 'e') {
  637.                 fop->op = ngx_http_script_file_not_exists;
  638.                 return NGX_CONF_OK;
  639.             }

  640.             if (p[2] == 'x') {
  641.                 fop->op = ngx_http_script_file_not_exec;
  642.                 return NGX_CONF_OK;
  643.             }
  644.         }

  645.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  646.                            "invalid condition \"%V\"", &value[cur]);
  647.         return NGX_CONF_ERROR;
  648.     }

  649.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  650.                        "invalid condition \"%V\"", &value[cur]);

  651.     return NGX_CONF_ERROR;
  652. }


  653. static char *
  654. ngx_http_rewrite_variable(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf,
  655.     ngx_str_t *value)
  656. {
  657.     ngx_int_t                    index;
  658.     ngx_http_script_var_code_t  *var_code;

  659.     value->len--;
  660.     value->data++;

  661.     index = ngx_http_get_variable_index(cf, value);

  662.     if (index == NGX_ERROR) {
  663.         return NGX_CONF_ERROR;
  664.     }

  665.     var_code = ngx_http_script_start_code(cf->pool, &lcf->codes,
  666.                                           sizeof(ngx_http_script_var_code_t));
  667.     if (var_code == NULL) {
  668.         return NGX_CONF_ERROR;
  669.     }

  670.     var_code->code = ngx_http_script_var_code;
  671.     var_code->index = index;

  672.     return NGX_CONF_OK;
  673. }


  674. static char *
  675. ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  676. {
  677.     ngx_http_rewrite_loc_conf_t  *lcf = conf;

  678.     ngx_int_t                            index;
  679.     ngx_str_t                           *value;
  680.     ngx_http_variable_t                 *v;
  681.     ngx_http_script_var_code_t          *vcode;
  682.     ngx_http_script_var_handler_code_t  *vhcode;

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

  684.     if (value[1].data[0] != '$') {
  685.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  686.                            "invalid variable name \"%V\"", &value[1]);
  687.         return NGX_CONF_ERROR;
  688.     }

  689.     value[1].len--;
  690.     value[1].data++;

  691.     v = ngx_http_add_variable(cf, &value[1],
  692.                               NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_WEAK);
  693.     if (v == NULL) {
  694.         return NGX_CONF_ERROR;
  695.     }

  696.     index = ngx_http_get_variable_index(cf, &value[1]);
  697.     if (index == NGX_ERROR) {
  698.         return NGX_CONF_ERROR;
  699.     }

  700.     if (v->get_handler == NULL) {
  701.         v->get_handler = ngx_http_rewrite_var;
  702.         v->data = index;
  703.     }

  704.     if (ngx_http_rewrite_value(cf, lcf, &value[2]) != NGX_CONF_OK) {
  705.         return NGX_CONF_ERROR;
  706.     }

  707.     if (v->set_handler) {
  708.         vhcode = ngx_http_script_start_code(cf->pool, &lcf->codes,
  709.                                    sizeof(ngx_http_script_var_handler_code_t));
  710.         if (vhcode == NULL) {
  711.             return NGX_CONF_ERROR;
  712.         }

  713.         vhcode->code = ngx_http_script_var_set_handler_code;
  714.         vhcode->handler = v->set_handler;
  715.         vhcode->data = v->data;

  716.         return NGX_CONF_OK;
  717.     }

  718.     vcode = ngx_http_script_start_code(cf->pool, &lcf->codes,
  719.                                        sizeof(ngx_http_script_var_code_t));
  720.     if (vcode == NULL) {
  721.         return NGX_CONF_ERROR;
  722.     }

  723.     vcode->code = ngx_http_script_set_var_code;
  724.     vcode->index = (uintptr_t) index;

  725.     return NGX_CONF_OK;
  726. }


  727. static char *
  728. ngx_http_rewrite_value(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf,
  729.     ngx_str_t *value)
  730. {
  731.     ngx_int_t                              n;
  732.     ngx_http_script_compile_t              sc;
  733.     ngx_http_script_value_code_t          *val;
  734.     ngx_http_script_complex_value_code_t  *complex;

  735.     n = ngx_http_script_variables_count(value);

  736.     if (n == 0) {
  737.         val = ngx_http_script_start_code(cf->pool, &lcf->codes,
  738.                                          sizeof(ngx_http_script_value_code_t));
  739.         if (val == NULL) {
  740.             return NGX_CONF_ERROR;
  741.         }

  742.         n = ngx_atoi(value->data, value->len);

  743.         if (n == NGX_ERROR) {
  744.             n = 0;
  745.         }

  746.         val->code = ngx_http_script_value_code;
  747.         val->value = (uintptr_t) n;
  748.         val->text_len = (uintptr_t) value->len;
  749.         val->text_data = (uintptr_t) value->data;

  750.         return NGX_CONF_OK;
  751.     }

  752.     complex = ngx_http_script_start_code(cf->pool, &lcf->codes,
  753.                                  sizeof(ngx_http_script_complex_value_code_t));
  754.     if (complex == NULL) {
  755.         return NGX_CONF_ERROR;
  756.     }

  757.     complex->code = ngx_http_script_complex_value_code;
  758.     complex->lengths = NULL;

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

  760.     sc.cf = cf;
  761.     sc.source = value;
  762.     sc.lengths = &complex->lengths;
  763.     sc.values = &lcf->codes;
  764.     sc.variables = n;
  765.     sc.complete_lengths = 1;

  766.     if (ngx_http_script_compile(&sc) != NGX_OK) {
  767.         return NGX_CONF_ERROR;
  768.     }

  769.     return NGX_CONF_OK;
  770. }