Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.11 ]​[ nginx-1.14.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 
0012 
0013 typedef struct {
0014     ngx_array_t  *codes;        /* uintptr_t */
0015 
0016     ngx_uint_t    stack_size;
0017 
0018     ngx_flag_t    log;
0019     ngx_flag_t    uninitialized_variable_warn;
0020 } ngx_http_rewrite_loc_conf_t;
0021 
0022 
0023 static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf);
0024 static char *ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf,
0025     void *parent, void *child);
0026 static ngx_int_t ngx_http_rewrite_init(ngx_conf_t *cf);
0027 static char *ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
0028 static char *ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd,
0029     void *conf);
0030 static char *ngx_http_rewrite_break(ngx_conf_t *cf, ngx_command_t *cmd,
0031     void *conf);
0032 static char *ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd,
0033     void *conf);
0034 static char * ngx_http_rewrite_if_condition(ngx_conf_t *cf,
0035     ngx_http_rewrite_loc_conf_t *lcf);
0036 static char *ngx_http_rewrite_variable(ngx_conf_t *cf,
0037     ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value);
0038 static char *ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd,
0039     void *conf);
0040 static char * ngx_http_rewrite_value(ngx_conf_t *cf,
0041     ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value);
0042 
0043 
0044 static ngx_command_t  ngx_http_rewrite_commands[] = {
0045 
0046     { ngx_string("rewrite"),
0047       NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
0048                        |NGX_CONF_TAKE23,
0049       ngx_http_rewrite,
0050       NGX_HTTP_LOC_CONF_OFFSET,
0051       0,
0052       NULL },
0053 
0054     { ngx_string("return"),
0055       NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
0056                        |NGX_CONF_TAKE12,
0057       ngx_http_rewrite_return,
0058       NGX_HTTP_LOC_CONF_OFFSET,
0059       0,
0060       NULL },
0061 
0062     { ngx_string("break"),
0063       NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
0064                        |NGX_CONF_NOARGS,
0065       ngx_http_rewrite_break,
0066       NGX_HTTP_LOC_CONF_OFFSET,
0067       0,
0068       NULL },
0069 
0070     { ngx_string("if"),
0071       NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_1MORE,
0072       ngx_http_rewrite_if,
0073       NGX_HTTP_LOC_CONF_OFFSET,
0074       0,
0075       NULL },
0076 
0077     { ngx_string("set"),
0078       NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
0079                        |NGX_CONF_TAKE2,
0080       ngx_http_rewrite_set,
0081       NGX_HTTP_LOC_CONF_OFFSET,
0082       0,
0083       NULL },
0084 
0085     { ngx_string("rewrite_log"),
0086       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF
0087                         |NGX_HTTP_LIF_CONF|NGX_CONF_FLAG,
0088       ngx_conf_set_flag_slot,
0089       NGX_HTTP_LOC_CONF_OFFSET,
0090       offsetof(ngx_http_rewrite_loc_conf_t, log),
0091       NULL },
0092 
0093     { ngx_string("uninitialized_variable_warn"),
0094       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF
0095                         |NGX_HTTP_LIF_CONF|NGX_CONF_FLAG,
0096       ngx_conf_set_flag_slot,
0097       NGX_HTTP_LOC_CONF_OFFSET,
0098       offsetof(ngx_http_rewrite_loc_conf_t, uninitialized_variable_warn),
0099       NULL },
0100 
0101       ngx_null_command
0102 };
0103 
0104 
0105 static ngx_http_module_t  ngx_http_rewrite_module_ctx = {
0106     NULL,                                  /* preconfiguration */
0107     ngx_http_rewrite_init,                 /* postconfiguration */
0108 
0109     NULL,                                  /* create main configuration */
0110     NULL,                                  /* init main configuration */
0111 
0112     NULL,                                  /* create server configuration */
0113     NULL,                                  /* merge server configuration */
0114 
0115     ngx_http_rewrite_create_loc_conf,      /* create location configuration */
0116     ngx_http_rewrite_merge_loc_conf        /* merge location configuration */
0117 };
0118 
0119 
0120 ngx_module_t  ngx_http_rewrite_module = {
0121     NGX_MODULE_V1,
0122     &ngx_http_rewrite_module_ctx,          /* module context */
0123     ngx_http_rewrite_commands,             /* module directives */
0124     NGX_HTTP_MODULE,                       /* module type */
0125     NULL,                                  /* init master */
0126     NULL,                                  /* init module */
0127     NULL,                                  /* init process */
0128     NULL,                                  /* init thread */
0129     NULL,                                  /* exit thread */
0130     NULL,                                  /* exit process */
0131     NULL,                                  /* exit master */
0132     NGX_MODULE_V1_PADDING
0133 };
0134 
0135 
0136 static ngx_int_t
0137 ngx_http_rewrite_handler(ngx_http_request_t *r)
0138 {
0139     ngx_int_t                     index;
0140     ngx_http_script_code_pt       code;
0141     ngx_http_script_engine_t     *e;
0142     ngx_http_core_srv_conf_t     *cscf;
0143     ngx_http_core_main_conf_t    *cmcf;
0144     ngx_http_rewrite_loc_conf_t  *rlcf;
0145 
0146     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
0147     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
0148     index = cmcf->phase_engine.location_rewrite_index;
0149 
0150     if (r->phase_handler == index && r->loc_conf == cscf->ctx->loc_conf) {
0151         /* skipping location rewrite phase for server null location */
0152         return NGX_DECLINED;
0153     }
0154 
0155     rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
0156 
0157     if (rlcf->codes == NULL) {
0158         return NGX_DECLINED;
0159     }
0160 
0161     e = ngx_pcalloc(r->pool, sizeof(ngx_http_script_engine_t));
0162     if (e == NULL) {
0163         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0164     }
0165 
0166     e->sp = ngx_pcalloc(r->pool,
0167                         rlcf->stack_size * sizeof(ngx_http_variable_value_t));
0168     if (e->sp == NULL) {
0169         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0170     }
0171 
0172     e->ip = rlcf->codes->elts;
0173     e->request = r;
0174     e->quote = 1;
0175     e->log = rlcf->log;
0176     e->status = NGX_DECLINED;
0177 
0178     while (*(uintptr_t *) e->ip) {
0179         code = *(ngx_http_script_code_pt *) e->ip;
0180         code(e);
0181     }
0182 
0183     return e->status;
0184 }
0185 
0186 
0187 static ngx_int_t
0188 ngx_http_rewrite_var(ngx_http_request_t *r, ngx_http_variable_value_t *v,
0189     uintptr_t data)
0190 {
0191     ngx_http_variable_t          *var;
0192     ngx_http_core_main_conf_t    *cmcf;
0193     ngx_http_rewrite_loc_conf_t  *rlcf;
0194 
0195     rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
0196 
0197     if (rlcf->uninitialized_variable_warn == 0) {
0198         *v = ngx_http_variable_null_value;
0199         return NGX_OK;
0200     }
0201 
0202     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
0203 
0204     var = cmcf->variables.elts;
0205 
0206     /*
0207      * the ngx_http_rewrite_module sets variables directly in r->variables,
0208      * and they should be handled by ngx_http_get_indexed_variable(),
0209      * so the handler is called only if the variable is not initialized
0210      */
0211 
0212     ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
0213                   "using uninitialized \"%V\" variable", &var[data].name);
0214 
0215     *v = ngx_http_variable_null_value;
0216 
0217     return NGX_OK;
0218 }
0219 
0220 
0221 static void *
0222 ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf)
0223 {
0224     ngx_http_rewrite_loc_conf_t  *conf;
0225 
0226     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_rewrite_loc_conf_t));
0227     if (conf == NULL) {
0228         return NULL;
0229     }
0230 
0231     conf->stack_size = NGX_CONF_UNSET_UINT;
0232     conf->log = NGX_CONF_UNSET;
0233     conf->uninitialized_variable_warn = NGX_CONF_UNSET;
0234 
0235     return conf;
0236 }
0237 
0238 
0239 static char *
0240 ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
0241 {
0242     ngx_http_rewrite_loc_conf_t *prev = parent;
0243     ngx_http_rewrite_loc_conf_t *conf = child;
0244 
0245     uintptr_t  *code;
0246 
0247     ngx_conf_merge_value(conf->log, prev->log, 0);
0248     ngx_conf_merge_value(conf->uninitialized_variable_warn,
0249                          prev->uninitialized_variable_warn, 1);
0250     ngx_conf_merge_uint_value(conf->stack_size, prev->stack_size, 10);
0251 
0252     if (conf->codes == NULL) {
0253         return NGX_CONF_OK;
0254     }
0255 
0256     if (conf->codes == prev->codes) {
0257         return NGX_CONF_OK;
0258     }
0259 
0260     code = ngx_array_push_n(conf->codes, sizeof(uintptr_t));
0261     if (code == NULL) {
0262         return NGX_CONF_ERROR;
0263     }
0264 
0265     *code = (uintptr_t) NULL;
0266 
0267     return NGX_CONF_OK;
0268 }
0269 
0270 
0271 static ngx_int_t
0272 ngx_http_rewrite_init(ngx_conf_t *cf)
0273 {
0274     ngx_http_handler_pt        *h;
0275     ngx_http_core_main_conf_t  *cmcf;
0276 
0277     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
0278 
0279     h = ngx_array_push(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers);
0280     if (h == NULL) {
0281         return NGX_ERROR;
0282     }
0283 
0284     *h = ngx_http_rewrite_handler;
0285 
0286     h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
0287     if (h == NULL) {
0288         return NGX_ERROR;
0289     }
0290 
0291     *h = ngx_http_rewrite_handler;
0292 
0293     return NGX_OK;
0294 }
0295 
0296 
0297 static char *
0298 ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0299 {
0300     ngx_http_rewrite_loc_conf_t  *lcf = conf;
0301 
0302     ngx_str_t                         *value;
0303     ngx_uint_t                         last;
0304     ngx_regex_compile_t                rc;
0305     ngx_http_script_code_pt           *code;
0306     ngx_http_script_compile_t          sc;
0307     ngx_http_script_regex_code_t      *regex;
0308     ngx_http_script_regex_end_code_t  *regex_end;
0309     u_char                             errstr[NGX_MAX_CONF_ERRSTR];
0310 
0311     regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
0312                                        sizeof(ngx_http_script_regex_code_t));
0313     if (regex == NULL) {
0314         return NGX_CONF_ERROR;
0315     }
0316 
0317     ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));
0318 
0319     value = cf->args->elts;
0320 
0321     ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
0322 
0323     rc.pattern = value[1];
0324     rc.err.len = NGX_MAX_CONF_ERRSTR;
0325     rc.err.data = errstr;
0326 
0327     /* TODO: NGX_REGEX_CASELESS */
0328 
0329     regex->regex = ngx_http_regex_compile(cf, &rc);
0330     if (regex->regex == NULL) {
0331         return NGX_CONF_ERROR;
0332     }
0333 
0334     regex->code = ngx_http_script_regex_start_code;
0335     regex->uri = 1;
0336     regex->name = value[1];
0337 
0338     if (value[2].data[value[2].len - 1] == '?') {
0339 
0340         /* the last "?" drops the original arguments */
0341         value[2].len--;
0342 
0343     } else {
0344         regex->add_args = 1;
0345     }
0346 
0347     last = 0;
0348 
0349     if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0
0350         || ngx_strncmp(value[2].data, "https://", sizeof("https://") - 1) == 0
0351         || ngx_strncmp(value[2].data, "$scheme", sizeof("$scheme") - 1) == 0)
0352     {
0353         regex->status = NGX_HTTP_MOVED_TEMPORARILY;
0354         regex->redirect = 1;
0355         last = 1;
0356     }
0357 
0358     if (cf->args->nelts == 4) {
0359         if (ngx_strcmp(value[3].data, "last") == 0) {
0360             last = 1;
0361 
0362         } else if (ngx_strcmp(value[3].data, "break") == 0) {
0363             regex->break_cycle = 1;
0364             last = 1;
0365 
0366         } else if (ngx_strcmp(value[3].data, "redirect") == 0) {
0367             regex->status = NGX_HTTP_MOVED_TEMPORARILY;
0368             regex->redirect = 1;
0369             last = 1;
0370 
0371         } else if (ngx_strcmp(value[3].data, "permanent") == 0) {
0372             regex->status = NGX_HTTP_MOVED_PERMANENTLY;
0373             regex->redirect = 1;
0374             last = 1;
0375 
0376         } else {
0377             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0378                                "invalid parameter \"%V\"", &value[3]);
0379             return NGX_CONF_ERROR;
0380         }
0381     }
0382 
0383     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
0384 
0385     sc.cf = cf;
0386     sc.source = &value[2];
0387     sc.lengths = &regex->lengths;
0388     sc.values = &lcf->codes;
0389     sc.variables = ngx_http_script_variables_count(&value[2]);
0390     sc.main = regex;
0391     sc.complete_lengths = 1;
0392     sc.compile_args = !regex->redirect;
0393 
0394     if (ngx_http_script_compile(&sc) != NGX_OK) {
0395         return NGX_CONF_ERROR;
0396     }
0397 
0398     regex = sc.main;
0399 
0400     regex->size = sc.size;
0401     regex->args = sc.args;
0402 
0403     if (sc.variables == 0 && !sc.dup_capture) {
0404         regex->lengths = NULL;
0405     }
0406 
0407     regex_end = ngx_http_script_add_code(lcf->codes,
0408                                       sizeof(ngx_http_script_regex_end_code_t),
0409                                       &regex);
0410     if (regex_end == NULL) {
0411         return NGX_CONF_ERROR;
0412     }
0413 
0414     regex_end->code = ngx_http_script_regex_end_code;
0415     regex_end->uri = regex->uri;
0416     regex_end->args = regex->args;
0417     regex_end->add_args = regex->add_args;
0418     regex_end->redirect = regex->redirect;
0419 
0420     if (last) {
0421         code = ngx_http_script_add_code(lcf->codes, sizeof(uintptr_t), &regex);
0422         if (code == NULL) {
0423             return NGX_CONF_ERROR;
0424         }
0425 
0426         *code = NULL;
0427     }
0428 
0429     regex->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
0430                                               - (u_char *) regex;
0431 
0432     return NGX_CONF_OK;
0433 }
0434 
0435 
0436 static char *
0437 ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0438 {
0439     ngx_http_rewrite_loc_conf_t  *lcf = conf;
0440 
0441     u_char                            *p;
0442     ngx_str_t                         *value, *v;
0443     ngx_http_script_return_code_t     *ret;
0444     ngx_http_compile_complex_value_t   ccv;
0445 
0446     ret = ngx_http_script_start_code(cf->pool, &lcf->codes,
0447                                      sizeof(ngx_http_script_return_code_t));
0448     if (ret == NULL) {
0449         return NGX_CONF_ERROR;
0450     }
0451 
0452     value = cf->args->elts;
0453 
0454     ngx_memzero(ret, sizeof(ngx_http_script_return_code_t));
0455 
0456     ret->code = ngx_http_script_return_code;
0457 
0458     p = value[1].data;
0459 
0460     ret->status = ngx_atoi(p, value[1].len);
0461 
0462     if (ret->status == (uintptr_t) NGX_ERROR) {
0463 
0464         if (cf->args->nelts == 2
0465             && (ngx_strncmp(p, "http://", sizeof("http://") - 1) == 0
0466                 || ngx_strncmp(p, "https://", sizeof("https://") - 1) == 0
0467                 || ngx_strncmp(p, "$scheme", sizeof("$scheme") - 1) == 0))
0468         {
0469             ret->status = NGX_HTTP_MOVED_TEMPORARILY;
0470             v = &value[1];
0471 
0472         } else {
0473             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0474                                "invalid return code \"%V\"", &value[1]);
0475             return NGX_CONF_ERROR;
0476         }
0477 
0478     } else {
0479 
0480         if (ret->status > 999) {
0481             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0482                                "invalid return code \"%V\"", &value[1]);
0483             return NGX_CONF_ERROR;
0484         }
0485 
0486         if (cf->args->nelts == 2) {
0487             return NGX_CONF_OK;
0488         }
0489 
0490         v = &value[2];
0491     }
0492 
0493     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
0494 
0495     ccv.cf = cf;
0496     ccv.value = v;
0497     ccv.complex_value = &ret->text;
0498 
0499     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
0500         return NGX_CONF_ERROR;
0501     }
0502 
0503     return NGX_CONF_OK;
0504 }
0505 
0506 
0507 static char *
0508 ngx_http_rewrite_break(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0509 {
0510     ngx_http_rewrite_loc_conf_t *lcf = conf;
0511 
0512     ngx_http_script_code_pt  *code;
0513 
0514     code = ngx_http_script_start_code(cf->pool, &lcf->codes, sizeof(uintptr_t));
0515     if (code == NULL) {
0516         return NGX_CONF_ERROR;
0517     }
0518 
0519     *code = ngx_http_script_break_code;
0520 
0521     return NGX_CONF_OK;
0522 }
0523 
0524 
0525 static char *
0526 ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0527 {
0528     ngx_http_rewrite_loc_conf_t  *lcf = conf;
0529 
0530     void                         *mconf;
0531     char                         *rv;
0532     u_char                       *elts;
0533     ngx_uint_t                    i;
0534     ngx_conf_t                    save;
0535     ngx_http_module_t            *module;
0536     ngx_http_conf_ctx_t          *ctx, *pctx;
0537     ngx_http_core_loc_conf_t     *clcf, *pclcf;
0538     ngx_http_script_if_code_t    *if_code;
0539     ngx_http_rewrite_loc_conf_t  *nlcf;
0540 
0541     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
0542     if (ctx == NULL) {
0543         return NGX_CONF_ERROR;
0544     }
0545 
0546     pctx = cf->ctx;
0547     ctx->main_conf = pctx->main_conf;
0548     ctx->srv_conf = pctx->srv_conf;
0549 
0550     ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
0551     if (ctx->loc_conf == NULL) {
0552         return NGX_CONF_ERROR;
0553     }
0554 
0555     for (i = 0; cf->cycle->modules[i]; i++) {
0556         if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {
0557             continue;
0558         }
0559 
0560         module = cf->cycle->modules[i]->ctx;
0561 
0562         if (module->create_loc_conf) {
0563 
0564             mconf = module->create_loc_conf(cf);
0565             if (mconf == NULL) {
0566                 return NGX_CONF_ERROR;
0567             }
0568 
0569             ctx->loc_conf[cf->cycle->modules[i]->ctx_index] = mconf;
0570         }
0571     }
0572 
0573     pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
0574 
0575     clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
0576     clcf->loc_conf = ctx->loc_conf;
0577     clcf->name = pclcf->name;
0578     clcf->noname = 1;
0579 
0580     if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {
0581         return NGX_CONF_ERROR;
0582     }
0583 
0584     if (ngx_http_rewrite_if_condition(cf, lcf) != NGX_CONF_OK) {
0585         return NGX_CONF_ERROR;
0586     }
0587 
0588     if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_script_if_code_t));
0589     if (if_code == NULL) {
0590         return NGX_CONF_ERROR;
0591     }
0592 
0593     if_code->code = ngx_http_script_if_code;
0594 
0595     elts = lcf->codes->elts;
0596 
0597 
0598     /* the inner directives must be compiled to the same code array */
0599 
0600     nlcf = ctx->loc_conf[ngx_http_rewrite_module.ctx_index];
0601     nlcf->codes = lcf->codes;
0602 
0603 
0604     save = *cf;
0605     cf->ctx = ctx;
0606 
0607     if (cf->cmd_type == NGX_HTTP_SRV_CONF) {
0608         if_code->loc_conf = NULL;
0609         cf->cmd_type = NGX_HTTP_SIF_CONF;
0610 
0611     } else {
0612         if_code->loc_conf = ctx->loc_conf;
0613         cf->cmd_type = NGX_HTTP_LIF_CONF;
0614     }
0615 
0616     rv = ngx_conf_parse(cf, NULL);
0617 
0618     *cf = save;
0619 
0620     if (rv != NGX_CONF_OK) {
0621         return rv;
0622     }
0623 
0624 
0625     if (elts != lcf->codes->elts) {
0626         if_code = (ngx_http_script_if_code_t *)
0627                    ((u_char *) if_code + ((u_char *) lcf->codes->elts - elts));
0628     }
0629 
0630     if_code->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
0631                                                 - (u_char *) if_code;
0632 
0633     /* the code array belong to parent block */
0634 
0635     nlcf->codes = NULL;
0636 
0637     return NGX_CONF_OK;
0638 }
0639 
0640 
0641 static char *
0642 ngx_http_rewrite_if_condition(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf)
0643 {
0644     u_char                        *p;
0645     size_t                         len;
0646     ngx_str_t                     *value;
0647     ngx_uint_t                     cur, last;
0648     ngx_regex_compile_t            rc;
0649     ngx_http_script_code_pt       *code;
0650     ngx_http_script_file_code_t   *fop;
0651     ngx_http_script_regex_code_t  *regex;
0652     u_char                         errstr[NGX_MAX_CONF_ERRSTR];
0653 
0654     value = cf->args->elts;
0655     last = cf->args->nelts - 1;
0656 
0657     if (value[1].len < 1 || value[1].data[0] != '(') {
0658         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0659                            "invalid condition \"%V\"", &value[1]);
0660         return NGX_CONF_ERROR;
0661     }
0662 
0663     if (value[1].len == 1) {
0664         cur = 2;
0665 
0666     } else {
0667         cur = 1;
0668         value[1].len--;
0669         value[1].data++;
0670     }
0671 
0672     if (value[last].len < 1 || value[last].data[value[last].len - 1] != ')') {
0673         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0674                            "invalid condition \"%V\"", &value[last]);
0675         return NGX_CONF_ERROR;
0676     }
0677 
0678     if (value[last].len == 1) {
0679         last--;
0680 
0681     } else {
0682         value[last].len--;
0683         value[last].data[value[last].len] = '\0';
0684     }
0685 
0686     len = value[cur].len;
0687     p = value[cur].data;
0688 
0689     if (len > 1 && p[0] == '$') {
0690 
0691         if (cur != last && cur + 2 != last) {
0692             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0693                                "invalid condition \"%V\"", &value[cur]);
0694             return NGX_CONF_ERROR;
0695         }
0696 
0697         if (ngx_http_rewrite_variable(cf, lcf, &value[cur]) != NGX_CONF_OK) {
0698             return NGX_CONF_ERROR;
0699         }
0700 
0701         if (cur == last) {
0702             return NGX_CONF_OK;
0703         }
0704 
0705         cur++;
0706 
0707         len = value[cur].len;
0708         p = value[cur].data;
0709 
0710         if (len == 1 && p[0] == '=') {
0711 
0712             if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
0713                 return NGX_CONF_ERROR;
0714             }
0715 
0716             code = ngx_http_script_start_code(cf->pool, &lcf->codes,
0717                                               sizeof(uintptr_t));
0718             if (code == NULL) {
0719                 return NGX_CONF_ERROR;
0720             }
0721 
0722             *code = ngx_http_script_equal_code;
0723 
0724             return NGX_CONF_OK;
0725         }
0726 
0727         if (len == 2 && p[0] == '!' && p[1] == '=') {
0728 
0729             if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
0730                 return NGX_CONF_ERROR;
0731             }
0732 
0733             code = ngx_http_script_start_code(cf->pool, &lcf->codes,
0734                                               sizeof(uintptr_t));
0735             if (code == NULL) {
0736                 return NGX_CONF_ERROR;
0737             }
0738 
0739             *code = ngx_http_script_not_equal_code;
0740             return NGX_CONF_OK;
0741         }
0742 
0743         if ((len == 1 && p[0] == '~')
0744             || (len == 2 && p[0] == '~' && p[1] == '*')
0745             || (len == 2 && p[0] == '!' && p[1] == '~')
0746             || (len == 3 && p[0] == '!' && p[1] == '~' && p[2] == '*'))
0747         {
0748             regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
0749                                          sizeof(ngx_http_script_regex_code_t));
0750             if (regex == NULL) {
0751                 return NGX_CONF_ERROR;
0752             }
0753 
0754             ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));
0755 
0756             ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
0757 
0758             rc.pattern = value[last];
0759             rc.options = (p[len - 1] == '*') ? NGX_REGEX_CASELESS : 0;
0760             rc.err.len = NGX_MAX_CONF_ERRSTR;
0761             rc.err.data = errstr;
0762 
0763             regex->regex = ngx_http_regex_compile(cf, &rc);
0764             if (regex->regex == NULL) {
0765                 return NGX_CONF_ERROR;
0766             }
0767 
0768             regex->code = ngx_http_script_regex_start_code;
0769             regex->next = sizeof(ngx_http_script_regex_code_t);
0770             regex->test = 1;
0771             if (p[0] == '!') {
0772                 regex->negative_test = 1;
0773             }
0774             regex->name = value[last];
0775 
0776             return NGX_CONF_OK;
0777         }
0778 
0779         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0780                            "unexpected \"%V\" in condition", &value[cur]);
0781         return NGX_CONF_ERROR;
0782 
0783     } else if ((len == 2 && p[0] == '-')
0784                || (len == 3 && p[0] == '!' && p[1] == '-'))
0785     {
0786         if (cur + 1 != last) {
0787             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0788                                "invalid condition \"%V\"", &value[cur]);
0789             return NGX_CONF_ERROR;
0790         }
0791 
0792         value[last].data[value[last].len] = '\0';
0793         value[last].len++;
0794 
0795         if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
0796             return NGX_CONF_ERROR;
0797         }
0798 
0799         fop = ngx_http_script_start_code(cf->pool, &lcf->codes,
0800                                           sizeof(ngx_http_script_file_code_t));
0801         if (fop == NULL) {
0802             return NGX_CONF_ERROR;
0803         }
0804 
0805         fop->code = ngx_http_script_file_code;
0806 
0807         if (p[1] == 'f') {
0808             fop->op = ngx_http_script_file_plain;
0809             return NGX_CONF_OK;
0810         }
0811 
0812         if (p[1] == 'd') {
0813             fop->op = ngx_http_script_file_dir;
0814             return NGX_CONF_OK;
0815         }
0816 
0817         if (p[1] == 'e') {
0818             fop->op = ngx_http_script_file_exists;
0819             return NGX_CONF_OK;
0820         }
0821 
0822         if (p[1] == 'x') {
0823             fop->op = ngx_http_script_file_exec;
0824             return NGX_CONF_OK;
0825         }
0826 
0827         if (p[0] == '!') {
0828             if (p[2] == 'f') {
0829                 fop->op = ngx_http_script_file_not_plain;
0830                 return NGX_CONF_OK;
0831             }
0832 
0833             if (p[2] == 'd') {
0834                 fop->op = ngx_http_script_file_not_dir;
0835                 return NGX_CONF_OK;
0836             }
0837 
0838             if (p[2] == 'e') {
0839                 fop->op = ngx_http_script_file_not_exists;
0840                 return NGX_CONF_OK;
0841             }
0842 
0843             if (p[2] == 'x') {
0844                 fop->op = ngx_http_script_file_not_exec;
0845                 return NGX_CONF_OK;
0846             }
0847         }
0848 
0849         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0850                            "invalid condition \"%V\"", &value[cur]);
0851         return NGX_CONF_ERROR;
0852     }
0853 
0854     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0855                        "invalid condition \"%V\"", &value[cur]);
0856 
0857     return NGX_CONF_ERROR;
0858 }
0859 
0860 
0861 static char *
0862 ngx_http_rewrite_variable(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf,
0863     ngx_str_t *value)
0864 {
0865     ngx_int_t                    index;
0866     ngx_http_script_var_code_t  *var_code;
0867 
0868     value->len--;
0869     value->data++;
0870 
0871     index = ngx_http_get_variable_index(cf, value);
0872 
0873     if (index == NGX_ERROR) {
0874         return NGX_CONF_ERROR;
0875     }
0876 
0877     var_code = ngx_http_script_start_code(cf->pool, &lcf->codes,
0878                                           sizeof(ngx_http_script_var_code_t));
0879     if (var_code == NULL) {
0880         return NGX_CONF_ERROR;
0881     }
0882 
0883     var_code->code = ngx_http_script_var_code;
0884     var_code->index = index;
0885 
0886     return NGX_CONF_OK;
0887 }
0888 
0889 
0890 static char *
0891 ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0892 {
0893     ngx_http_rewrite_loc_conf_t  *lcf = conf;
0894 
0895     ngx_int_t                            index;
0896     ngx_str_t                           *value;
0897     ngx_http_variable_t                 *v;
0898     ngx_http_script_var_code_t          *vcode;
0899     ngx_http_script_var_handler_code_t  *vhcode;
0900 
0901     value = cf->args->elts;
0902 
0903     if (value[1].data[0] != '$') {
0904         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0905                            "invalid variable name \"%V\"", &value[1]);
0906         return NGX_CONF_ERROR;
0907     }
0908 
0909     value[1].len--;
0910     value[1].data++;
0911 
0912     v = ngx_http_add_variable(cf, &value[1],
0913                               NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_WEAK);
0914     if (v == NULL) {
0915         return NGX_CONF_ERROR;
0916     }
0917 
0918     index = ngx_http_get_variable_index(cf, &value[1]);
0919     if (index == NGX_ERROR) {
0920         return NGX_CONF_ERROR;
0921     }
0922 
0923     if (v->get_handler == NULL) {
0924         v->get_handler = ngx_http_rewrite_var;
0925         v->data = index;
0926     }
0927 
0928     if (ngx_http_rewrite_value(cf, lcf, &value[2]) != NGX_CONF_OK) {
0929         return NGX_CONF_ERROR;
0930     }
0931 
0932     if (v->set_handler) {
0933         vhcode = ngx_http_script_start_code(cf->pool, &lcf->codes,
0934                                    sizeof(ngx_http_script_var_handler_code_t));
0935         if (vhcode == NULL) {
0936             return NGX_CONF_ERROR;
0937         }
0938 
0939         vhcode->code = ngx_http_script_var_set_handler_code;
0940         vhcode->handler = v->set_handler;
0941         vhcode->data = v->data;
0942 
0943         return NGX_CONF_OK;
0944     }
0945 
0946     vcode = ngx_http_script_start_code(cf->pool, &lcf->codes,
0947                                        sizeof(ngx_http_script_var_code_t));
0948     if (vcode == NULL) {
0949         return NGX_CONF_ERROR;
0950     }
0951 
0952     vcode->code = ngx_http_script_set_var_code;
0953     vcode->index = (uintptr_t) index;
0954 
0955     return NGX_CONF_OK;
0956 }
0957 
0958 
0959 static char *
0960 ngx_http_rewrite_value(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf,
0961     ngx_str_t *value)
0962 {
0963     ngx_int_t                              n;
0964     ngx_http_script_compile_t              sc;
0965     ngx_http_script_value_code_t          *val;
0966     ngx_http_script_complex_value_code_t  *complex;
0967 
0968     n = ngx_http_script_variables_count(value);
0969 
0970     if (n == 0) {
0971         val = ngx_http_script_start_code(cf->pool, &lcf->codes,
0972                                          sizeof(ngx_http_script_value_code_t));
0973         if (val == NULL) {
0974             return NGX_CONF_ERROR;
0975         }
0976 
0977         n = ngx_atoi(value->data, value->len);
0978 
0979         if (n == NGX_ERROR) {
0980             n = 0;
0981         }
0982 
0983         val->code = ngx_http_script_value_code;
0984         val->value = (uintptr_t) n;
0985         val->text_len = (uintptr_t) value->len;
0986         val->text_data = (uintptr_t) value->data;
0987 
0988         return NGX_CONF_OK;
0989     }
0990 
0991     complex = ngx_http_script_start_code(cf->pool, &lcf->codes,
0992                                  sizeof(ngx_http_script_complex_value_code_t));
0993     if (complex == NULL) {
0994         return NGX_CONF_ERROR;
0995     }
0996 
0997     complex->code = ngx_http_script_complex_value_code;
0998     complex->lengths = NULL;
0999 
1000     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1001 
1002     sc.cf = cf;
1003     sc.source = value;
1004     sc.lengths = &complex->lengths;
1005     sc.values = &lcf->codes;
1006     sc.variables = n;
1007     sc.complete_lengths = 1;
1008 
1009     if (ngx_http_script_compile(&sc) != NGX_OK) {
1010         return NGX_CONF_ERROR;
1011     }
1012 
1013     return NGX_CONF_OK;
1014 }