src/http/modules/ngx_http_rewrite_module.c - nginx-1.7.10

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.     if (e->status < NGX_HTTP_BAD_REQUEST) {
  147.         return e->status;
  148.     }

  149.     if (r->err_status == 0) {
  150.         return e->status;
  151.     }

  152.     return r->err_status;
  153. }


  154. static ngx_int_t
  155. ngx_http_rewrite_var(ngx_http_request_t *r, ngx_http_variable_value_t *v,
  156.     uintptr_t data)
  157. {
  158.     ngx_http_variable_t          *var;
  159.     ngx_http_core_main_conf_t    *cmcf;
  160.     ngx_http_rewrite_loc_conf_t  *rlcf;

  161.     rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);

  162.     if (rlcf->uninitialized_variable_warn == 0) {
  163.         *v = ngx_http_variable_null_value;
  164.         return NGX_OK;
  165.     }

  166.     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);

  167.     var = cmcf->variables.elts;

  168.     /*
  169.      * the ngx_http_rewrite_module sets variables directly in r->variables,
  170.      * and they should be handled by ngx_http_get_indexed_variable(),
  171.      * so the handler is called only if the variable is not initialized
  172.      */

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

  175.     *v = ngx_http_variable_null_value;

  176.     return NGX_OK;
  177. }


  178. static void *
  179. ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf)
  180. {
  181.     ngx_http_rewrite_loc_conf_t  *conf;

  182.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_rewrite_loc_conf_t));
  183.     if (conf == NULL) {
  184.         return NULL;
  185.     }

  186.     conf->stack_size = NGX_CONF_UNSET_UINT;
  187.     conf->log = NGX_CONF_UNSET;
  188.     conf->uninitialized_variable_warn = NGX_CONF_UNSET;

  189.     return conf;
  190. }


  191. static char *
  192. ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  193. {
  194.     ngx_http_rewrite_loc_conf_t *prev = parent;
  195.     ngx_http_rewrite_loc_conf_t *conf = child;

  196.     uintptr_t  *code;

  197.     ngx_conf_merge_value(conf->log, prev->log, 0);
  198.     ngx_conf_merge_value(conf->uninitialized_variable_warn,
  199.                          prev->uninitialized_variable_warn, 1);
  200.     ngx_conf_merge_uint_value(conf->stack_size, prev->stack_size, 10);

  201.     if (conf->codes == NULL) {
  202.         return NGX_CONF_OK;
  203.     }

  204.     if (conf->codes == prev->codes) {
  205.         return NGX_CONF_OK;
  206.     }

  207.     code = ngx_array_push_n(conf->codes, sizeof(uintptr_t));
  208.     if (code == NULL) {
  209.         return NGX_CONF_ERROR;
  210.     }

  211.     *code = (uintptr_t) NULL;

  212.     return NGX_CONF_OK;
  213. }


  214. static ngx_int_t
  215. ngx_http_rewrite_init(ngx_conf_t *cf)
  216. {
  217.     ngx_http_handler_pt        *h;
  218.     ngx_http_core_main_conf_t  *cmcf;

  219.     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

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

  224.     *h = ngx_http_rewrite_handler;

  225.     h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
  226.     if (h == NULL) {
  227.         return NGX_ERROR;
  228.     }

  229.     *h = ngx_http_rewrite_handler;

  230.     return NGX_OK;
  231. }


  232. static char *
  233. ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  234. {
  235.     ngx_http_rewrite_loc_conf_t  *lcf = conf;

  236.     ngx_str_t                         *value;
  237.     ngx_uint_t                         last;
  238.     ngx_regex_compile_t                rc;
  239.     ngx_http_script_code_pt           *code;
  240.     ngx_http_script_compile_t          sc;
  241.     ngx_http_script_regex_code_t      *regex;
  242.     ngx_http_script_regex_end_code_t  *regex_end;
  243.     u_char                             errstr[NGX_MAX_CONF_ERRSTR];

  244.     regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
  245.                                        sizeof(ngx_http_script_regex_code_t));
  246.     if (regex == NULL) {
  247.         return NGX_CONF_ERROR;
  248.     }

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

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

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

  252.     rc.pattern = value[1];
  253.     rc.err.len = NGX_MAX_CONF_ERRSTR;
  254.     rc.err.data = errstr;

  255.     /* TODO: NGX_REGEX_CASELESS */

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

  260.     regex->code = ngx_http_script_regex_start_code;
  261.     regex->uri = 1;
  262.     regex->name = value[1];

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

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

  266.     } else {
  267.         regex->add_args = 1;
  268.     }

  269.     last = 0;

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

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

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

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

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

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

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

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

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

  310.     regex = sc.main;

  311.     regex->size = sc.size;
  312.     regex->args = sc.args;

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

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

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

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

  332.         *code = NULL;
  333.     }

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

  336.     return NGX_CONF_OK;
  337. }


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

  342.     u_char                            *p;
  343.     ngx_str_t                         *value, *v;
  344.     ngx_http_script_return_code_t     *ret;
  345.     ngx_http_compile_complex_value_t   ccv;

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

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

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

  353.     ret->code = ngx_http_script_return_code;

  354.     p = value[1].data;

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

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

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

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

  369.     } else {

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

  375.         if (cf->args->nelts == 2) {
  376.             return NGX_CONF_OK;
  377.         }

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

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

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

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

  387.     return NGX_CONF_OK;
  388. }


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

  393.     ngx_http_script_code_pt  *code;

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

  398.     *code = ngx_http_script_break_code;

  399.     return NGX_CONF_OK;
  400. }


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

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

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

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

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

  426.     for (i = 0; ngx_modules[i]; i++) {
  427.         if (ngx_modules[i]->type != NGX_HTTP_MODULE) {
  428.             continue;
  429.         }

  430.         module = ngx_modules[i]->ctx;

  431.         if (module->create_loc_conf) {

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

  436.             ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf;
  437.         }
  438.     }

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

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

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

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

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

  454.     if_code->code = ngx_http_script_if_code;

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


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

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


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

  461.     if (pclcf->name.len == 0) {
  462.         if_code->loc_conf = NULL;
  463.         cf->cmd_type = NGX_HTTP_SIF_CONF;

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

  468.     rv = ngx_conf_parse(cf, NULL);

  469.     *cf = save;

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


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

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

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

  480.     nlcf->codes = NULL;

  481.     return NGX_CONF_OK;
  482. }


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

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

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

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

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

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

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

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

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

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

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

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

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

  534.         cur++;

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

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

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

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

  546.             *code = ngx_http_script_equal_code;

  547.             return NGX_CONF_OK;
  548.         }

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

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

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

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

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

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

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

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

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

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

  588.             return NGX_CONF_OK;
  589.         }

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

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

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

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

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

  611.         fop->code = ngx_http_script_file_code;

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

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

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

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

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

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

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

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

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

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

  652.     return NGX_CONF_ERROR;
  653. }


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

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

  662.     index = ngx_http_get_variable_index(cf, value);

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

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

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

  673.     return NGX_CONF_OK;
  674. }


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

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

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

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

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

  692.     v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGEABLE);
  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.         && ngx_strncasecmp(value[1].data, (u_char *) "http_", 5) != 0
  702.         && ngx_strncasecmp(value[1].data, (u_char *) "sent_http_", 10) != 0
  703.         && ngx_strncasecmp(value[1].data, (u_char *) "upstream_http_", 14) != 0
  704.         && ngx_strncasecmp(value[1].data, (u_char *) "cookie_", 7) != 0
  705.         && ngx_strncasecmp(value[1].data, (u_char *) "upstream_cookie_", 16)
  706.            != 0
  707.         && ngx_strncasecmp(value[1].data, (u_char *) "arg_", 4) != 0)
  708.     {
  709.         v->get_handler = ngx_http_rewrite_var;
  710.         v->data = index;
  711.     }

  712.     if (ngx_http_rewrite_value(cf, lcf, &value[2]) != NGX_CONF_OK) {
  713.         return NGX_CONF_ERROR;
  714.     }

  715.     if (v->set_handler) {
  716.         vhcode = ngx_http_script_start_code(cf->pool, &lcf->codes,
  717.                                    sizeof(ngx_http_script_var_handler_code_t));
  718.         if (vhcode == NULL) {
  719.             return NGX_CONF_ERROR;
  720.         }

  721.         vhcode->code = ngx_http_script_var_set_handler_code;
  722.         vhcode->handler = v->set_handler;
  723.         vhcode->data = v->data;

  724.         return NGX_CONF_OK;
  725.     }

  726.     vcode = ngx_http_script_start_code(cf->pool, &lcf->codes,
  727.                                        sizeof(ngx_http_script_var_code_t));
  728.     if (vcode == NULL) {
  729.         return NGX_CONF_ERROR;
  730.     }

  731.     vcode->code = ngx_http_script_set_var_code;
  732.     vcode->index = (uintptr_t) index;

  733.     return NGX_CONF_OK;
  734. }


  735. static char *
  736. ngx_http_rewrite_value(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf,
  737.     ngx_str_t *value)
  738. {
  739.     ngx_int_t                              n;
  740.     ngx_http_script_compile_t              sc;
  741.     ngx_http_script_value_code_t          *val;
  742.     ngx_http_script_complex_value_code_t  *complex;

  743.     n = ngx_http_script_variables_count(value);

  744.     if (n == 0) {
  745.         val = ngx_http_script_start_code(cf->pool, &lcf->codes,
  746.                                          sizeof(ngx_http_script_value_code_t));
  747.         if (val == NULL) {
  748.             return NGX_CONF_ERROR;
  749.         }

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

  751.         if (n == NGX_ERROR) {
  752.             n = 0;
  753.         }

  754.         val->code = ngx_http_script_value_code;
  755.         val->value = (uintptr_t) n;
  756.         val->text_len = (uintptr_t) value->len;
  757.         val->text_data = (uintptr_t) value->data;

  758.         return NGX_CONF_OK;
  759.     }

  760.     complex = ngx_http_script_start_code(cf->pool, &lcf->codes,
  761.                                  sizeof(ngx_http_script_complex_value_code_t));
  762.     if (complex == NULL) {
  763.         return NGX_CONF_ERROR;
  764.     }

  765.     complex->code = ngx_http_script_complex_value_code;
  766.     complex->lengths = NULL;

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

  768.     sc.cf = cf;
  769.     sc.source = value;
  770.     sc.lengths = &complex->lengths;
  771.     sc.values = &lcf->codes;
  772.     sc.variables = n;
  773.     sc.complete_lengths = 1;

  774.     if (ngx_http_script_compile(&sc) != NGX_OK) {
  775.         return NGX_CONF_ERROR;
  776.     }

  777.     return NGX_CONF_OK;
  778. }