Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.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     if (e->status < NGX_HTTP_BAD_REQUEST) {
0184         return e->status;
0185     }
0186 
0187     if (r->err_status == 0) {
0188         return e->status;
0189     }
0190 
0191     return r->err_status;
0192 }
0193 
0194 
0195 static ngx_int_t
0196 ngx_http_rewrite_var(ngx_http_request_t *r, ngx_http_variable_value_t *v,
0197     uintptr_t data)
0198 {
0199     ngx_http_variable_t          *var;
0200     ngx_http_core_main_conf_t    *cmcf;
0201     ngx_http_rewrite_loc_conf_t  *rlcf;
0202 
0203     rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
0204 
0205     if (rlcf->uninitialized_variable_warn == 0) {
0206         *v = ngx_http_variable_null_value;
0207         return NGX_OK;
0208     }
0209 
0210     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
0211 
0212     var = cmcf->variables.elts;
0213 
0214     /*
0215      * the ngx_http_rewrite_module sets variables directly in r->variables,
0216      * and they should be handled by ngx_http_get_indexed_variable(),
0217      * so the handler is called only if the variable is not initialized
0218      */
0219 
0220     ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
0221                   "using uninitialized \"%V\" variable", &var[data].name);
0222 
0223     *v = ngx_http_variable_null_value;
0224 
0225     return NGX_OK;
0226 }
0227 
0228 
0229 static void *
0230 ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf)
0231 {
0232     ngx_http_rewrite_loc_conf_t  *conf;
0233 
0234     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_rewrite_loc_conf_t));
0235     if (conf == NULL) {
0236         return NULL;
0237     }
0238 
0239     conf->stack_size = NGX_CONF_UNSET_UINT;
0240     conf->log = NGX_CONF_UNSET;
0241     conf->uninitialized_variable_warn = NGX_CONF_UNSET;
0242 
0243     return conf;
0244 }
0245 
0246 
0247 static char *
0248 ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
0249 {
0250     ngx_http_rewrite_loc_conf_t *prev = parent;
0251     ngx_http_rewrite_loc_conf_t *conf = child;
0252 
0253     uintptr_t  *code;
0254 
0255     ngx_conf_merge_value(conf->log, prev->log, 0);
0256     ngx_conf_merge_value(conf->uninitialized_variable_warn,
0257                          prev->uninitialized_variable_warn, 1);
0258     ngx_conf_merge_uint_value(conf->stack_size, prev->stack_size, 10);
0259 
0260     if (conf->codes == NULL) {
0261         return NGX_CONF_OK;
0262     }
0263 
0264     if (conf->codes == prev->codes) {
0265         return NGX_CONF_OK;
0266     }
0267 
0268     code = ngx_array_push_n(conf->codes, sizeof(uintptr_t));
0269     if (code == NULL) {
0270         return NGX_CONF_ERROR;
0271     }
0272 
0273     *code = (uintptr_t) NULL;
0274 
0275     return NGX_CONF_OK;
0276 }
0277 
0278 
0279 static ngx_int_t
0280 ngx_http_rewrite_init(ngx_conf_t *cf)
0281 {
0282     ngx_http_handler_pt        *h;
0283     ngx_http_core_main_conf_t  *cmcf;
0284 
0285     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
0286 
0287     h = ngx_array_push(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers);
0288     if (h == NULL) {
0289         return NGX_ERROR;
0290     }
0291 
0292     *h = ngx_http_rewrite_handler;
0293 
0294     h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
0295     if (h == NULL) {
0296         return NGX_ERROR;
0297     }
0298 
0299     *h = ngx_http_rewrite_handler;
0300 
0301     return NGX_OK;
0302 }
0303 
0304 
0305 static char *
0306 ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0307 {
0308     ngx_http_rewrite_loc_conf_t  *lcf = conf;
0309 
0310     ngx_str_t                         *value;
0311     ngx_uint_t                         last;
0312     ngx_regex_compile_t                rc;
0313     ngx_http_script_code_pt           *code;
0314     ngx_http_script_compile_t          sc;
0315     ngx_http_script_regex_code_t      *regex;
0316     ngx_http_script_regex_end_code_t  *regex_end;
0317     u_char                             errstr[NGX_MAX_CONF_ERRSTR];
0318 
0319     regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
0320                                        sizeof(ngx_http_script_regex_code_t));
0321     if (regex == NULL) {
0322         return NGX_CONF_ERROR;
0323     }
0324 
0325     ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));
0326 
0327     value = cf->args->elts;
0328 
0329     ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
0330 
0331     rc.pattern = value[1];
0332     rc.err.len = NGX_MAX_CONF_ERRSTR;
0333     rc.err.data = errstr;
0334 
0335     /* TODO: NGX_REGEX_CASELESS */
0336 
0337     regex->regex = ngx_http_regex_compile(cf, &rc);
0338     if (regex->regex == NULL) {
0339         return NGX_CONF_ERROR;
0340     }
0341 
0342     regex->code = ngx_http_script_regex_start_code;
0343     regex->uri = 1;
0344     regex->name = value[1];
0345 
0346     if (value[2].data[value[2].len - 1] == '?') {
0347 
0348         /* the last "?" drops the original arguments */
0349         value[2].len--;
0350 
0351     } else {
0352         regex->add_args = 1;
0353     }
0354 
0355     last = 0;
0356 
0357     if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0
0358         || ngx_strncmp(value[2].data, "https://", sizeof("https://") - 1) == 0
0359         || ngx_strncmp(value[2].data, "$scheme", sizeof("$scheme") - 1) == 0)
0360     {
0361         regex->status = NGX_HTTP_MOVED_TEMPORARILY;
0362         regex->redirect = 1;
0363         last = 1;
0364     }
0365 
0366     if (cf->args->nelts == 4) {
0367         if (ngx_strcmp(value[3].data, "last") == 0) {
0368             last = 1;
0369 
0370         } else if (ngx_strcmp(value[3].data, "break") == 0) {
0371             regex->break_cycle = 1;
0372             last = 1;
0373 
0374         } else if (ngx_strcmp(value[3].data, "redirect") == 0) {
0375             regex->status = NGX_HTTP_MOVED_TEMPORARILY;
0376             regex->redirect = 1;
0377             last = 1;
0378 
0379         } else if (ngx_strcmp(value[3].data, "permanent") == 0) {
0380             regex->status = NGX_HTTP_MOVED_PERMANENTLY;
0381             regex->redirect = 1;
0382             last = 1;
0383 
0384         } else {
0385             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0386                                "invalid parameter \"%V\"", &value[3]);
0387             return NGX_CONF_ERROR;
0388         }
0389     }
0390 
0391     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
0392 
0393     sc.cf = cf;
0394     sc.source = &value[2];
0395     sc.lengths = &regex->lengths;
0396     sc.values = &lcf->codes;
0397     sc.variables = ngx_http_script_variables_count(&value[2]);
0398     sc.main = regex;
0399     sc.complete_lengths = 1;
0400     sc.compile_args = !regex->redirect;
0401 
0402     if (ngx_http_script_compile(&sc) != NGX_OK) {
0403         return NGX_CONF_ERROR;
0404     }
0405 
0406     regex = sc.main;
0407 
0408     regex->size = sc.size;
0409     regex->args = sc.args;
0410 
0411     if (sc.variables == 0 && !sc.dup_capture) {
0412         regex->lengths = NULL;
0413     }
0414 
0415     regex_end = ngx_http_script_add_code(lcf->codes,
0416                                       sizeof(ngx_http_script_regex_end_code_t),
0417                                       &regex);
0418     if (regex_end == NULL) {
0419         return NGX_CONF_ERROR;
0420     }
0421 
0422     regex_end->code = ngx_http_script_regex_end_code;
0423     regex_end->uri = regex->uri;
0424     regex_end->args = regex->args;
0425     regex_end->add_args = regex->add_args;
0426     regex_end->redirect = regex->redirect;
0427 
0428     if (last) {
0429         code = ngx_http_script_add_code(lcf->codes, sizeof(uintptr_t), &regex);
0430         if (code == NULL) {
0431             return NGX_CONF_ERROR;
0432         }
0433 
0434         *code = NULL;
0435     }
0436 
0437     regex->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
0438                                               - (u_char *) regex;
0439 
0440     return NGX_CONF_OK;
0441 }
0442 
0443 
0444 static char *
0445 ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0446 {
0447     ngx_http_rewrite_loc_conf_t  *lcf = conf;
0448 
0449     u_char                            *p;
0450     ngx_str_t                         *value, *v;
0451     ngx_http_script_return_code_t     *ret;
0452     ngx_http_compile_complex_value_t   ccv;
0453 
0454     ret = ngx_http_script_start_code(cf->pool, &lcf->codes,
0455                                      sizeof(ngx_http_script_return_code_t));
0456     if (ret == NULL) {
0457         return NGX_CONF_ERROR;
0458     }
0459 
0460     value = cf->args->elts;
0461 
0462     ngx_memzero(ret, sizeof(ngx_http_script_return_code_t));
0463 
0464     ret->code = ngx_http_script_return_code;
0465 
0466     p = value[1].data;
0467 
0468     ret->status = ngx_atoi(p, value[1].len);
0469 
0470     if (ret->status == (uintptr_t) NGX_ERROR) {
0471 
0472         if (cf->args->nelts == 2
0473             && (ngx_strncmp(p, "http://", sizeof("http://") - 1) == 0
0474                 || ngx_strncmp(p, "https://", sizeof("https://") - 1) == 0
0475                 || ngx_strncmp(p, "$scheme", sizeof("$scheme") - 1) == 0))
0476         {
0477             ret->status = NGX_HTTP_MOVED_TEMPORARILY;
0478             v = &value[1];
0479 
0480         } else {
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     } else {
0487 
0488         if (ret->status > 999) {
0489             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0490                                "invalid return code \"%V\"", &value[1]);
0491             return NGX_CONF_ERROR;
0492         }
0493 
0494         if (cf->args->nelts == 2) {
0495             return NGX_CONF_OK;
0496         }
0497 
0498         v = &value[2];
0499     }
0500 
0501     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
0502 
0503     ccv.cf = cf;
0504     ccv.value = v;
0505     ccv.complex_value = &ret->text;
0506 
0507     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
0508         return NGX_CONF_ERROR;
0509     }
0510 
0511     return NGX_CONF_OK;
0512 }
0513 
0514 
0515 static char *
0516 ngx_http_rewrite_break(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0517 {
0518     ngx_http_rewrite_loc_conf_t *lcf = conf;
0519 
0520     ngx_http_script_code_pt  *code;
0521 
0522     code = ngx_http_script_start_code(cf->pool, &lcf->codes, sizeof(uintptr_t));
0523     if (code == NULL) {
0524         return NGX_CONF_ERROR;
0525     }
0526 
0527     *code = ngx_http_script_break_code;
0528 
0529     return NGX_CONF_OK;
0530 }
0531 
0532 
0533 static char *
0534 ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0535 {
0536     ngx_http_rewrite_loc_conf_t  *lcf = conf;
0537 
0538     void                         *mconf;
0539     char                         *rv;
0540     u_char                       *elts;
0541     ngx_uint_t                    i;
0542     ngx_conf_t                    save;
0543     ngx_http_module_t            *module;
0544     ngx_http_conf_ctx_t          *ctx, *pctx;
0545     ngx_http_core_loc_conf_t     *clcf, *pclcf;
0546     ngx_http_script_if_code_t    *if_code;
0547     ngx_http_rewrite_loc_conf_t  *nlcf;
0548 
0549     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
0550     if (ctx == NULL) {
0551         return NGX_CONF_ERROR;
0552     }
0553 
0554     pctx = cf->ctx;
0555     ctx->main_conf = pctx->main_conf;
0556     ctx->srv_conf = pctx->srv_conf;
0557 
0558     ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
0559     if (ctx->loc_conf == NULL) {
0560         return NGX_CONF_ERROR;
0561     }
0562 
0563     for (i = 0; cf->cycle->modules[i]; i++) {
0564         if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {
0565             continue;
0566         }
0567 
0568         module = cf->cycle->modules[i]->ctx;
0569 
0570         if (module->create_loc_conf) {
0571 
0572             mconf = module->create_loc_conf(cf);
0573             if (mconf == NULL) {
0574                 return NGX_CONF_ERROR;
0575             }
0576 
0577             ctx->loc_conf[cf->cycle->modules[i]->ctx_index] = mconf;
0578         }
0579     }
0580 
0581     pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
0582 
0583     clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
0584     clcf->loc_conf = ctx->loc_conf;
0585     clcf->name = pclcf->name;
0586     clcf->noname = 1;
0587 
0588     if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {
0589         return NGX_CONF_ERROR;
0590     }
0591 
0592     if (ngx_http_rewrite_if_condition(cf, lcf) != NGX_CONF_OK) {
0593         return NGX_CONF_ERROR;
0594     }
0595 
0596     if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_script_if_code_t));
0597     if (if_code == NULL) {
0598         return NGX_CONF_ERROR;
0599     }
0600 
0601     if_code->code = ngx_http_script_if_code;
0602 
0603     elts = lcf->codes->elts;
0604 
0605 
0606     /* the inner directives must be compiled to the same code array */
0607 
0608     nlcf = ctx->loc_conf[ngx_http_rewrite_module.ctx_index];
0609     nlcf->codes = lcf->codes;
0610 
0611 
0612     save = *cf;
0613     cf->ctx = ctx;
0614 
0615     if (cf->cmd_type == NGX_HTTP_SRV_CONF) {
0616         if_code->loc_conf = NULL;
0617         cf->cmd_type = NGX_HTTP_SIF_CONF;
0618 
0619     } else {
0620         if_code->loc_conf = ctx->loc_conf;
0621         cf->cmd_type = NGX_HTTP_LIF_CONF;
0622     }
0623 
0624     rv = ngx_conf_parse(cf, NULL);
0625 
0626     *cf = save;
0627 
0628     if (rv != NGX_CONF_OK) {
0629         return rv;
0630     }
0631 
0632 
0633     if (elts != lcf->codes->elts) {
0634         if_code = (ngx_http_script_if_code_t *)
0635                    ((u_char *) if_code + ((u_char *) lcf->codes->elts - elts));
0636     }
0637 
0638     if_code->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
0639                                                 - (u_char *) if_code;
0640 
0641     /* the code array belong to parent block */
0642 
0643     nlcf->codes = NULL;
0644 
0645     return NGX_CONF_OK;
0646 }
0647 
0648 
0649 static char *
0650 ngx_http_rewrite_if_condition(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf)
0651 {
0652     u_char                        *p;
0653     size_t                         len;
0654     ngx_str_t                     *value;
0655     ngx_uint_t                     cur, last;
0656     ngx_regex_compile_t            rc;
0657     ngx_http_script_code_pt       *code;
0658     ngx_http_script_file_code_t   *fop;
0659     ngx_http_script_regex_code_t  *regex;
0660     u_char                         errstr[NGX_MAX_CONF_ERRSTR];
0661 
0662     value = cf->args->elts;
0663     last = cf->args->nelts - 1;
0664 
0665     if (value[1].len < 1 || value[1].data[0] != '(') {
0666         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0667                            "invalid condition \"%V\"", &value[1]);
0668         return NGX_CONF_ERROR;
0669     }
0670 
0671     if (value[1].len == 1) {
0672         cur = 2;
0673 
0674     } else {
0675         cur = 1;
0676         value[1].len--;
0677         value[1].data++;
0678     }
0679 
0680     if (value[last].len < 1 || value[last].data[value[last].len - 1] != ')') {
0681         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0682                            "invalid condition \"%V\"", &value[last]);
0683         return NGX_CONF_ERROR;
0684     }
0685 
0686     if (value[last].len == 1) {
0687         last--;
0688 
0689     } else {
0690         value[last].len--;
0691         value[last].data[value[last].len] = '\0';
0692     }
0693 
0694     len = value[cur].len;
0695     p = value[cur].data;
0696 
0697     if (len > 1 && p[0] == '$') {
0698 
0699         if (cur != last && cur + 2 != last) {
0700             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0701                                "invalid condition \"%V\"", &value[cur]);
0702             return NGX_CONF_ERROR;
0703         }
0704 
0705         if (ngx_http_rewrite_variable(cf, lcf, &value[cur]) != NGX_CONF_OK) {
0706             return NGX_CONF_ERROR;
0707         }
0708 
0709         if (cur == last) {
0710             return NGX_CONF_OK;
0711         }
0712 
0713         cur++;
0714 
0715         len = value[cur].len;
0716         p = value[cur].data;
0717 
0718         if (len == 1 && p[0] == '=') {
0719 
0720             if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
0721                 return NGX_CONF_ERROR;
0722             }
0723 
0724             code = ngx_http_script_start_code(cf->pool, &lcf->codes,
0725                                               sizeof(uintptr_t));
0726             if (code == NULL) {
0727                 return NGX_CONF_ERROR;
0728             }
0729 
0730             *code = ngx_http_script_equal_code;
0731 
0732             return NGX_CONF_OK;
0733         }
0734 
0735         if (len == 2 && p[0] == '!' && p[1] == '=') {
0736 
0737             if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
0738                 return NGX_CONF_ERROR;
0739             }
0740 
0741             code = ngx_http_script_start_code(cf->pool, &lcf->codes,
0742                                               sizeof(uintptr_t));
0743             if (code == NULL) {
0744                 return NGX_CONF_ERROR;
0745             }
0746 
0747             *code = ngx_http_script_not_equal_code;
0748             return NGX_CONF_OK;
0749         }
0750 
0751         if ((len == 1 && p[0] == '~')
0752             || (len == 2 && p[0] == '~' && p[1] == '*')
0753             || (len == 2 && p[0] == '!' && p[1] == '~')
0754             || (len == 3 && p[0] == '!' && p[1] == '~' && p[2] == '*'))
0755         {
0756             regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
0757                                          sizeof(ngx_http_script_regex_code_t));
0758             if (regex == NULL) {
0759                 return NGX_CONF_ERROR;
0760             }
0761 
0762             ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));
0763 
0764             ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
0765 
0766             rc.pattern = value[last];
0767             rc.options = (p[len - 1] == '*') ? NGX_REGEX_CASELESS : 0;
0768             rc.err.len = NGX_MAX_CONF_ERRSTR;
0769             rc.err.data = errstr;
0770 
0771             regex->regex = ngx_http_regex_compile(cf, &rc);
0772             if (regex->regex == NULL) {
0773                 return NGX_CONF_ERROR;
0774             }
0775 
0776             regex->code = ngx_http_script_regex_start_code;
0777             regex->next = sizeof(ngx_http_script_regex_code_t);
0778             regex->test = 1;
0779             if (p[0] == '!') {
0780                 regex->negative_test = 1;
0781             }
0782             regex->name = value[last];
0783 
0784             return NGX_CONF_OK;
0785         }
0786 
0787         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0788                            "unexpected \"%V\" in condition", &value[cur]);
0789         return NGX_CONF_ERROR;
0790 
0791     } else if ((len == 2 && p[0] == '-')
0792                || (len == 3 && p[0] == '!' && p[1] == '-'))
0793     {
0794         if (cur + 1 != last) {
0795             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0796                                "invalid condition \"%V\"", &value[cur]);
0797             return NGX_CONF_ERROR;
0798         }
0799 
0800         value[last].data[value[last].len] = '\0';
0801         value[last].len++;
0802 
0803         if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
0804             return NGX_CONF_ERROR;
0805         }
0806 
0807         fop = ngx_http_script_start_code(cf->pool, &lcf->codes,
0808                                           sizeof(ngx_http_script_file_code_t));
0809         if (fop == NULL) {
0810             return NGX_CONF_ERROR;
0811         }
0812 
0813         fop->code = ngx_http_script_file_code;
0814 
0815         if (p[1] == 'f') {
0816             fop->op = ngx_http_script_file_plain;
0817             return NGX_CONF_OK;
0818         }
0819 
0820         if (p[1] == 'd') {
0821             fop->op = ngx_http_script_file_dir;
0822             return NGX_CONF_OK;
0823         }
0824 
0825         if (p[1] == 'e') {
0826             fop->op = ngx_http_script_file_exists;
0827             return NGX_CONF_OK;
0828         }
0829 
0830         if (p[1] == 'x') {
0831             fop->op = ngx_http_script_file_exec;
0832             return NGX_CONF_OK;
0833         }
0834 
0835         if (p[0] == '!') {
0836             if (p[2] == 'f') {
0837                 fop->op = ngx_http_script_file_not_plain;
0838                 return NGX_CONF_OK;
0839             }
0840 
0841             if (p[2] == 'd') {
0842                 fop->op = ngx_http_script_file_not_dir;
0843                 return NGX_CONF_OK;
0844             }
0845 
0846             if (p[2] == 'e') {
0847                 fop->op = ngx_http_script_file_not_exists;
0848                 return NGX_CONF_OK;
0849             }
0850 
0851             if (p[2] == 'x') {
0852                 fop->op = ngx_http_script_file_not_exec;
0853                 return NGX_CONF_OK;
0854             }
0855         }
0856 
0857         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0858                            "invalid condition \"%V\"", &value[cur]);
0859         return NGX_CONF_ERROR;
0860     }
0861 
0862     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0863                        "invalid condition \"%V\"", &value[cur]);
0864 
0865     return NGX_CONF_ERROR;
0866 }
0867 
0868 
0869 static char *
0870 ngx_http_rewrite_variable(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf,
0871     ngx_str_t *value)
0872 {
0873     ngx_int_t                    index;
0874     ngx_http_script_var_code_t  *var_code;
0875 
0876     value->len--;
0877     value->data++;
0878 
0879     index = ngx_http_get_variable_index(cf, value);
0880 
0881     if (index == NGX_ERROR) {
0882         return NGX_CONF_ERROR;
0883     }
0884 
0885     var_code = ngx_http_script_start_code(cf->pool, &lcf->codes,
0886                                           sizeof(ngx_http_script_var_code_t));
0887     if (var_code == NULL) {
0888         return NGX_CONF_ERROR;
0889     }
0890 
0891     var_code->code = ngx_http_script_var_code;
0892     var_code->index = index;
0893 
0894     return NGX_CONF_OK;
0895 }
0896 
0897 
0898 static char *
0899 ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0900 {
0901     ngx_http_rewrite_loc_conf_t  *lcf = conf;
0902 
0903     ngx_int_t                            index;
0904     ngx_str_t                           *value;
0905     ngx_http_variable_t                 *v;
0906     ngx_http_script_var_code_t          *vcode;
0907     ngx_http_script_var_handler_code_t  *vhcode;
0908 
0909     value = cf->args->elts;
0910 
0911     if (value[1].data[0] != '$') {
0912         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0913                            "invalid variable name \"%V\"", &value[1]);
0914         return NGX_CONF_ERROR;
0915     }
0916 
0917     value[1].len--;
0918     value[1].data++;
0919 
0920     v = ngx_http_add_variable(cf, &value[1],
0921                               NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_WEAK);
0922     if (v == NULL) {
0923         return NGX_CONF_ERROR;
0924     }
0925 
0926     index = ngx_http_get_variable_index(cf, &value[1]);
0927     if (index == NGX_ERROR) {
0928         return NGX_CONF_ERROR;
0929     }
0930 
0931     if (v->get_handler == NULL) {
0932         v->get_handler = ngx_http_rewrite_var;
0933         v->data = index;
0934     }
0935 
0936     if (ngx_http_rewrite_value(cf, lcf, &value[2]) != NGX_CONF_OK) {
0937         return NGX_CONF_ERROR;
0938     }
0939 
0940     if (v->set_handler) {
0941         vhcode = ngx_http_script_start_code(cf->pool, &lcf->codes,
0942                                    sizeof(ngx_http_script_var_handler_code_t));
0943         if (vhcode == NULL) {
0944             return NGX_CONF_ERROR;
0945         }
0946 
0947         vhcode->code = ngx_http_script_var_set_handler_code;
0948         vhcode->handler = v->set_handler;
0949         vhcode->data = v->data;
0950 
0951         return NGX_CONF_OK;
0952     }
0953 
0954     vcode = ngx_http_script_start_code(cf->pool, &lcf->codes,
0955                                        sizeof(ngx_http_script_var_code_t));
0956     if (vcode == NULL) {
0957         return NGX_CONF_ERROR;
0958     }
0959 
0960     vcode->code = ngx_http_script_set_var_code;
0961     vcode->index = (uintptr_t) index;
0962 
0963     return NGX_CONF_OK;
0964 }
0965 
0966 
0967 static char *
0968 ngx_http_rewrite_value(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf,
0969     ngx_str_t *value)
0970 {
0971     ngx_int_t                              n;
0972     ngx_http_script_compile_t              sc;
0973     ngx_http_script_value_code_t          *val;
0974     ngx_http_script_complex_value_code_t  *complex;
0975 
0976     n = ngx_http_script_variables_count(value);
0977 
0978     if (n == 0) {
0979         val = ngx_http_script_start_code(cf->pool, &lcf->codes,
0980                                          sizeof(ngx_http_script_value_code_t));
0981         if (val == NULL) {
0982             return NGX_CONF_ERROR;
0983         }
0984 
0985         n = ngx_atoi(value->data, value->len);
0986 
0987         if (n == NGX_ERROR) {
0988             n = 0;
0989         }
0990 
0991         val->code = ngx_http_script_value_code;
0992         val->value = (uintptr_t) n;
0993         val->text_len = (uintptr_t) value->len;
0994         val->text_data = (uintptr_t) value->data;
0995 
0996         return NGX_CONF_OK;
0997     }
0998 
0999     complex = ngx_http_script_start_code(cf->pool, &lcf->codes,
1000                                  sizeof(ngx_http_script_complex_value_code_t));
1001     if (complex == NULL) {
1002         return NGX_CONF_ERROR;
1003     }
1004 
1005     complex->code = ngx_http_script_complex_value_code;
1006     complex->lengths = NULL;
1007 
1008     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1009 
1010     sc.cf = cf;
1011     sc.source = value;
1012     sc.lengths = &complex->lengths;
1013     sc.values = &lcf->codes;
1014     sc.variables = n;
1015     sc.complete_lengths = 1;
1016 
1017     if (ngx_http_script_compile(&sc) != NGX_OK) {
1018         return NGX_CONF_ERROR;
1019     }
1020 
1021     return NGX_CONF_OK;
1022 }