Annotation of embedaddon/nginx/src/http/modules/ngx_http_rewrite_module.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (C) Igor Sysoev
                      4:  * Copyright (C) Nginx, Inc.
                      5:  */
                      6: 
                      7: 
                      8: #include <ngx_config.h>
                      9: #include <ngx_core.h>
                     10: #include <ngx_http.h>
                     11: 
                     12: 
                     13: typedef struct {
                     14:     ngx_array_t  *codes;        /* uintptr_t */
                     15: 
                     16:     ngx_uint_t    stack_size;
                     17: 
                     18:     ngx_flag_t    log;
                     19:     ngx_flag_t    uninitialized_variable_warn;
                     20: } ngx_http_rewrite_loc_conf_t;
                     21: 
                     22: 
                     23: static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf);
                     24: static char *ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf,
                     25:     void *parent, void *child);
                     26: static ngx_int_t ngx_http_rewrite_init(ngx_conf_t *cf);
                     27: static char *ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
                     28: static char *ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd,
                     29:     void *conf);
                     30: static char *ngx_http_rewrite_break(ngx_conf_t *cf, ngx_command_t *cmd,
                     31:     void *conf);
                     32: static char *ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd,
                     33:     void *conf);
                     34: static char * ngx_http_rewrite_if_condition(ngx_conf_t *cf,
                     35:     ngx_http_rewrite_loc_conf_t *lcf);
                     36: static char *ngx_http_rewrite_variable(ngx_conf_t *cf,
                     37:     ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value);
                     38: static char *ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd,
                     39:     void *conf);
                     40: static char * ngx_http_rewrite_value(ngx_conf_t *cf,
                     41:     ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value);
                     42: 
                     43: 
                     44: static ngx_command_t  ngx_http_rewrite_commands[] = {
                     45: 
                     46:     { ngx_string("rewrite"),
                     47:       NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
                     48:                        |NGX_CONF_TAKE23,
                     49:       ngx_http_rewrite,
                     50:       NGX_HTTP_LOC_CONF_OFFSET,
                     51:       0,
                     52:       NULL },
                     53: 
                     54:     { ngx_string("return"),
                     55:       NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
                     56:                        |NGX_CONF_TAKE12,
                     57:       ngx_http_rewrite_return,
                     58:       NGX_HTTP_LOC_CONF_OFFSET,
                     59:       0,
                     60:       NULL },
                     61: 
                     62:     { ngx_string("break"),
                     63:       NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
                     64:                        |NGX_CONF_NOARGS,
                     65:       ngx_http_rewrite_break,
                     66:       NGX_HTTP_LOC_CONF_OFFSET,
                     67:       0,
                     68:       NULL },
                     69: 
                     70:     { ngx_string("if"),
                     71:       NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_1MORE,
                     72:       ngx_http_rewrite_if,
                     73:       NGX_HTTP_LOC_CONF_OFFSET,
                     74:       0,
                     75:       NULL },
                     76: 
                     77:     { ngx_string("set"),
                     78:       NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
                     79:                        |NGX_CONF_TAKE2,
                     80:       ngx_http_rewrite_set,
                     81:       NGX_HTTP_LOC_CONF_OFFSET,
                     82:       0,
                     83:       NULL },
                     84: 
                     85:     { ngx_string("rewrite_log"),
                     86:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF
                     87:                         |NGX_HTTP_LIF_CONF|NGX_CONF_FLAG,
                     88:       ngx_conf_set_flag_slot,
                     89:       NGX_HTTP_LOC_CONF_OFFSET,
                     90:       offsetof(ngx_http_rewrite_loc_conf_t, log),
                     91:       NULL },
                     92: 
                     93:     { ngx_string("uninitialized_variable_warn"),
                     94:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF
                     95:                         |NGX_HTTP_LIF_CONF|NGX_CONF_FLAG,
                     96:       ngx_conf_set_flag_slot,
                     97:       NGX_HTTP_LOC_CONF_OFFSET,
                     98:       offsetof(ngx_http_rewrite_loc_conf_t, uninitialized_variable_warn),
                     99:       NULL },
                    100: 
                    101:       ngx_null_command
                    102: };
                    103: 
                    104: 
                    105: static ngx_http_module_t  ngx_http_rewrite_module_ctx = {
                    106:     NULL,                                  /* preconfiguration */
                    107:     ngx_http_rewrite_init,                 /* postconfiguration */
                    108: 
                    109:     NULL,                                  /* create main configuration */
                    110:     NULL,                                  /* init main configuration */
                    111: 
                    112:     NULL,                                  /* create server configuration */
                    113:     NULL,                                  /* merge server configuration */
                    114: 
                    115:     ngx_http_rewrite_create_loc_conf,      /* create location configuration */
                    116:     ngx_http_rewrite_merge_loc_conf        /* merge location configuration */
                    117: };
                    118: 
                    119: 
                    120: ngx_module_t  ngx_http_rewrite_module = {
                    121:     NGX_MODULE_V1,
                    122:     &ngx_http_rewrite_module_ctx,          /* module context */
                    123:     ngx_http_rewrite_commands,             /* module directives */
                    124:     NGX_HTTP_MODULE,                       /* module type */
                    125:     NULL,                                  /* init master */
                    126:     NULL,                                  /* init module */
                    127:     NULL,                                  /* init process */
                    128:     NULL,                                  /* init thread */
                    129:     NULL,                                  /* exit thread */
                    130:     NULL,                                  /* exit process */
                    131:     NULL,                                  /* exit master */
                    132:     NGX_MODULE_V1_PADDING
                    133: };
                    134: 
                    135: 
                    136: static ngx_int_t
                    137: ngx_http_rewrite_handler(ngx_http_request_t *r)
                    138: {
                    139:     ngx_int_t                     index;
                    140:     ngx_http_script_code_pt       code;
                    141:     ngx_http_script_engine_t     *e;
                    142:     ngx_http_core_srv_conf_t     *cscf;
                    143:     ngx_http_core_main_conf_t    *cmcf;
                    144:     ngx_http_rewrite_loc_conf_t  *rlcf;
                    145: 
                    146:     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
                    147:     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
                    148:     index = cmcf->phase_engine.location_rewrite_index;
                    149: 
                    150:     if (r->phase_handler == index && r->loc_conf == cscf->ctx->loc_conf) {
                    151:         /* skipping location rewrite phase for server null location */
                    152:         return NGX_DECLINED;
                    153:     }
                    154: 
                    155:     rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
                    156: 
                    157:     if (rlcf->codes == NULL) {
                    158:         return NGX_DECLINED;
                    159:     }
                    160: 
                    161:     e = ngx_pcalloc(r->pool, sizeof(ngx_http_script_engine_t));
                    162:     if (e == NULL) {
                    163:         return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    164:     }
                    165: 
                    166:     e->sp = ngx_pcalloc(r->pool,
                    167:                         rlcf->stack_size * sizeof(ngx_http_variable_value_t));
                    168:     if (e->sp == NULL) {
                    169:         return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    170:     }
                    171: 
                    172:     e->ip = rlcf->codes->elts;
                    173:     e->request = r;
                    174:     e->quote = 1;
                    175:     e->log = rlcf->log;
                    176:     e->status = NGX_DECLINED;
                    177: 
                    178:     while (*(uintptr_t *) e->ip) {
                    179:         code = *(ngx_http_script_code_pt *) e->ip;
                    180:         code(e);
                    181:     }
                    182: 
                    183:     if (e->status < NGX_HTTP_BAD_REQUEST) {
                    184:         return e->status;
                    185:     }
                    186: 
                    187:     if (r->err_status == 0) {
                    188:         return e->status;
                    189:     }
                    190: 
                    191:     return r->err_status;
                    192: }
                    193: 
                    194: 
                    195: static ngx_int_t
                    196: ngx_http_rewrite_var(ngx_http_request_t *r, ngx_http_variable_value_t *v,
                    197:     uintptr_t data)
                    198: {
                    199:     ngx_http_variable_t          *var;
                    200:     ngx_http_core_main_conf_t    *cmcf;
                    201:     ngx_http_rewrite_loc_conf_t  *rlcf;
                    202: 
                    203:     rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
                    204: 
                    205:     if (rlcf->uninitialized_variable_warn == 0) {
                    206:         *v = ngx_http_variable_null_value;
                    207:         return NGX_OK;
                    208:     }
                    209: 
                    210:     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
                    211: 
                    212:     var = cmcf->variables.elts;
                    213: 
                    214:     /*
                    215:      * the ngx_http_rewrite_module sets variables directly in r->variables,
                    216:      * and they should be handled by ngx_http_get_indexed_variable(),
                    217:      * so the handler is called only if the variable is not initialized
                    218:      */
                    219: 
                    220:     ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
                    221:                   "using uninitialized \"%V\" variable", &var[data].name);
                    222: 
                    223:     *v = ngx_http_variable_null_value;
                    224: 
                    225:     return NGX_OK;
                    226: }
                    227: 
                    228: 
                    229: static void *
                    230: ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf)
                    231: {
                    232:     ngx_http_rewrite_loc_conf_t  *conf;
                    233: 
                    234:     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_rewrite_loc_conf_t));
                    235:     if (conf == NULL) {
                    236:         return NULL;
                    237:     }
                    238: 
                    239:     conf->stack_size = NGX_CONF_UNSET_UINT;
                    240:     conf->log = NGX_CONF_UNSET;
                    241:     conf->uninitialized_variable_warn = NGX_CONF_UNSET;
                    242: 
                    243:     return conf;
                    244: }
                    245: 
                    246: 
                    247: static char *
                    248: ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
                    249: {
                    250:     ngx_http_rewrite_loc_conf_t *prev = parent;
                    251:     ngx_http_rewrite_loc_conf_t *conf = child;
                    252: 
                    253:     uintptr_t  *code;
                    254: 
                    255:     ngx_conf_merge_value(conf->log, prev->log, 0);
                    256:     ngx_conf_merge_value(conf->uninitialized_variable_warn,
                    257:                          prev->uninitialized_variable_warn, 1);
                    258:     ngx_conf_merge_uint_value(conf->stack_size, prev->stack_size, 10);
                    259: 
                    260:     if (conf->codes == NULL) {
                    261:         return NGX_CONF_OK;
                    262:     }
                    263: 
                    264:     if (conf->codes == prev->codes) {
                    265:         return NGX_CONF_OK;
                    266:     }
                    267: 
                    268:     code = ngx_array_push_n(conf->codes, sizeof(uintptr_t));
                    269:     if (code == NULL) {
                    270:         return NGX_CONF_ERROR;
                    271:     }
                    272: 
                    273:     *code = (uintptr_t) NULL;
                    274: 
                    275:     return NGX_CONF_OK;
                    276: }
                    277: 
                    278: 
                    279: static ngx_int_t
                    280: ngx_http_rewrite_init(ngx_conf_t *cf)
                    281: {
                    282:     ngx_http_handler_pt        *h;
                    283:     ngx_http_core_main_conf_t  *cmcf;
                    284: 
                    285:     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
                    286: 
                    287:     h = ngx_array_push(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers);
                    288:     if (h == NULL) {
                    289:         return NGX_ERROR;
                    290:     }
                    291: 
                    292:     *h = ngx_http_rewrite_handler;
                    293: 
                    294:     h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
                    295:     if (h == NULL) {
                    296:         return NGX_ERROR;
                    297:     }
                    298: 
                    299:     *h = ngx_http_rewrite_handler;
                    300: 
                    301:     return NGX_OK;
                    302: }
                    303: 
                    304: 
                    305: static char *
                    306: ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                    307: {
                    308:     ngx_http_rewrite_loc_conf_t  *lcf = conf;
                    309: 
                    310:     ngx_str_t                         *value;
                    311:     ngx_uint_t                         last;
                    312:     ngx_regex_compile_t                rc;
                    313:     ngx_http_script_code_pt           *code;
                    314:     ngx_http_script_compile_t          sc;
                    315:     ngx_http_script_regex_code_t      *regex;
                    316:     ngx_http_script_regex_end_code_t  *regex_end;
                    317:     u_char                             errstr[NGX_MAX_CONF_ERRSTR];
                    318: 
                    319:     regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
                    320:                                        sizeof(ngx_http_script_regex_code_t));
                    321:     if (regex == NULL) {
                    322:         return NGX_CONF_ERROR;
                    323:     }
                    324: 
                    325:     ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));
                    326: 
                    327:     value = cf->args->elts;
                    328: 
                    329:     ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
                    330: 
                    331:     rc.pattern = value[1];
                    332:     rc.err.len = NGX_MAX_CONF_ERRSTR;
                    333:     rc.err.data = errstr;
                    334: 
                    335:     /* TODO: NGX_REGEX_CASELESS */
                    336: 
                    337:     regex->regex = ngx_http_regex_compile(cf, &rc);
                    338:     if (regex->regex == NULL) {
                    339:         return NGX_CONF_ERROR;
                    340:     }
                    341: 
                    342:     regex->code = ngx_http_script_regex_start_code;
                    343:     regex->uri = 1;
                    344:     regex->name = value[1];
                    345: 
                    346:     if (value[2].data[value[2].len - 1] == '?') {
                    347: 
                    348:         /* the last "?" drops the original arguments */
                    349:         value[2].len--;
                    350: 
                    351:     } else {
                    352:         regex->add_args = 1;
                    353:     }
                    354: 
                    355:     last = 0;
                    356: 
                    357:     if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0
                    358:         || ngx_strncmp(value[2].data, "https://", sizeof("https://") - 1) == 0
                    359:         || ngx_strncmp(value[2].data, "$scheme", sizeof("$scheme") - 1) == 0)
                    360:     {
                    361:         regex->status = NGX_HTTP_MOVED_TEMPORARILY;
                    362:         regex->redirect = 1;
                    363:         last = 1;
                    364:     }
                    365: 
                    366:     if (cf->args->nelts == 4) {
                    367:         if (ngx_strcmp(value[3].data, "last") == 0) {
                    368:             last = 1;
                    369: 
                    370:         } else if (ngx_strcmp(value[3].data, "break") == 0) {
                    371:             regex->break_cycle = 1;
                    372:             last = 1;
                    373: 
                    374:         } else if (ngx_strcmp(value[3].data, "redirect") == 0) {
                    375:             regex->status = NGX_HTTP_MOVED_TEMPORARILY;
                    376:             regex->redirect = 1;
                    377:             last = 1;
                    378: 
                    379:         } else if (ngx_strcmp(value[3].data, "permanent") == 0) {
                    380:             regex->status = NGX_HTTP_MOVED_PERMANENTLY;
                    381:             regex->redirect = 1;
                    382:             last = 1;
                    383: 
                    384:         } else {
                    385:             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                    386:                                "invalid parameter \"%V\"", &value[3]);
                    387:             return NGX_CONF_ERROR;
                    388:         }
                    389:     }
                    390: 
                    391:     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
                    392: 
                    393:     sc.cf = cf;
                    394:     sc.source = &value[2];
                    395:     sc.lengths = &regex->lengths;
                    396:     sc.values = &lcf->codes;
                    397:     sc.variables = ngx_http_script_variables_count(&value[2]);
                    398:     sc.main = regex;
                    399:     sc.complete_lengths = 1;
                    400:     sc.compile_args = !regex->redirect;
                    401: 
                    402:     if (ngx_http_script_compile(&sc) != NGX_OK) {
                    403:         return NGX_CONF_ERROR;
                    404:     }
                    405: 
                    406:     regex = sc.main;
                    407: 
                    408:     regex->size = sc.size;
                    409:     regex->args = sc.args;
                    410: 
                    411:     if (sc.variables == 0 && !sc.dup_capture) {
                    412:         regex->lengths = NULL;
                    413:     }
                    414: 
                    415:     regex_end = ngx_http_script_add_code(lcf->codes,
                    416:                                       sizeof(ngx_http_script_regex_end_code_t),
                    417:                                       &regex);
                    418:     if (regex_end == NULL) {
                    419:         return NGX_CONF_ERROR;
                    420:     }
                    421: 
                    422:     regex_end->code = ngx_http_script_regex_end_code;
                    423:     regex_end->uri = regex->uri;
                    424:     regex_end->args = regex->args;
                    425:     regex_end->add_args = regex->add_args;
                    426:     regex_end->redirect = regex->redirect;
                    427: 
                    428:     if (last) {
                    429:         code = ngx_http_script_add_code(lcf->codes, sizeof(uintptr_t), &regex);
                    430:         if (code == NULL) {
                    431:             return NGX_CONF_ERROR;
                    432:         }
                    433: 
                    434:         *code = NULL;
                    435:     }
                    436: 
                    437:     regex->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
                    438:                                               - (u_char *) regex;
                    439: 
                    440:     return NGX_CONF_OK;
                    441: }
                    442: 
                    443: 
                    444: static char *
                    445: ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                    446: {
                    447:     ngx_http_rewrite_loc_conf_t  *lcf = conf;
                    448: 
                    449:     u_char                            *p;
                    450:     ngx_str_t                         *value, *v;
                    451:     ngx_http_script_return_code_t     *ret;
                    452:     ngx_http_compile_complex_value_t   ccv;
                    453: 
                    454:     ret = ngx_http_script_start_code(cf->pool, &lcf->codes,
                    455:                                      sizeof(ngx_http_script_return_code_t));
                    456:     if (ret == NULL) {
                    457:         return NGX_CONF_ERROR;
                    458:     }
                    459: 
                    460:     value = cf->args->elts;
                    461: 
                    462:     ngx_memzero(ret, sizeof(ngx_http_script_return_code_t));
                    463: 
                    464:     ret->code = ngx_http_script_return_code;
                    465: 
                    466:     p = value[1].data;
                    467: 
                    468:     ret->status = ngx_atoi(p, value[1].len);
                    469: 
                    470:     if (ret->status == (uintptr_t) NGX_ERROR) {
                    471: 
                    472:         if (cf->args->nelts == 2
                    473:             && (ngx_strncmp(p, "http://", sizeof("http://") - 1) == 0
                    474:                 || ngx_strncmp(p, "https://", sizeof("https://") - 1) == 0
                    475:                 || ngx_strncmp(p, "$scheme", sizeof("$scheme") - 1) == 0))
                    476:         {
                    477:             ret->status = NGX_HTTP_MOVED_TEMPORARILY;
                    478:             v = &value[1];
                    479: 
                    480:         } else {
                    481:             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                    482:                                "invalid return code \"%V\"", &value[1]);
                    483:             return NGX_CONF_ERROR;
                    484:         }
                    485: 
                    486:     } else {
                    487: 
                    488:         if (ret->status > 999) {
                    489:             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                    490:                                "invalid return code \"%V\"", &value[1]);
                    491:             return NGX_CONF_ERROR;
                    492:         }
                    493: 
                    494:         if (cf->args->nelts == 2) {
                    495:             return NGX_CONF_OK;
                    496:         }
                    497: 
                    498:         v = &value[2];
                    499:     }
                    500: 
                    501:     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
                    502: 
                    503:     ccv.cf = cf;
                    504:     ccv.value = v;
                    505:     ccv.complex_value = &ret->text;
                    506: 
                    507:     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
                    508:         return NGX_CONF_ERROR;
                    509:     }
                    510: 
                    511:     return NGX_CONF_OK;
                    512: }
                    513: 
                    514: 
                    515: static char *
                    516: ngx_http_rewrite_break(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                    517: {
                    518:     ngx_http_rewrite_loc_conf_t *lcf = conf;
                    519: 
                    520:     ngx_http_script_code_pt  *code;
                    521: 
                    522:     code = ngx_http_script_start_code(cf->pool, &lcf->codes, sizeof(uintptr_t));
                    523:     if (code == NULL) {
                    524:         return NGX_CONF_ERROR;
                    525:     }
                    526: 
                    527:     *code = ngx_http_script_break_code;
                    528: 
                    529:     return NGX_CONF_OK;
                    530: }
                    531: 
                    532: 
                    533: static char *
                    534: ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                    535: {
                    536:     ngx_http_rewrite_loc_conf_t  *lcf = conf;
                    537: 
                    538:     void                         *mconf;
                    539:     char                         *rv;
                    540:     u_char                       *elts;
                    541:     ngx_uint_t                    i;
                    542:     ngx_conf_t                    save;
                    543:     ngx_http_module_t            *module;
                    544:     ngx_http_conf_ctx_t          *ctx, *pctx;
                    545:     ngx_http_core_loc_conf_t     *clcf, *pclcf;
                    546:     ngx_http_script_if_code_t    *if_code;
                    547:     ngx_http_rewrite_loc_conf_t  *nlcf;
                    548: 
                    549:     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
                    550:     if (ctx == NULL) {
                    551:         return NGX_CONF_ERROR;
                    552:     }
                    553: 
                    554:     pctx = cf->ctx;
                    555:     ctx->main_conf = pctx->main_conf;
                    556:     ctx->srv_conf = pctx->srv_conf;
                    557: 
                    558:     ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
                    559:     if (ctx->loc_conf == NULL) {
                    560:         return NGX_CONF_ERROR;
                    561:     }
                    562: 
                    563:     for (i = 0; ngx_modules[i]; i++) {
                    564:         if (ngx_modules[i]->type != NGX_HTTP_MODULE) {
                    565:             continue;
                    566:         }
                    567: 
                    568:         module = ngx_modules[i]->ctx;
                    569: 
                    570:         if (module->create_loc_conf) {
                    571: 
                    572:             mconf = module->create_loc_conf(cf);
                    573:             if (mconf == NULL) {
                    574:                  return NGX_CONF_ERROR;
                    575:             }
                    576: 
                    577:             ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf;
                    578:         }
                    579:     }
                    580: 
                    581:     pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
                    582: 
                    583:     clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
                    584:     clcf->loc_conf = ctx->loc_conf;
                    585:     clcf->name = pclcf->name;
                    586:     clcf->noname = 1;
                    587: 
                    588:     if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {
                    589:         return NGX_CONF_ERROR;
                    590:     }
                    591: 
                    592:     if (ngx_http_rewrite_if_condition(cf, lcf) != NGX_CONF_OK) {
                    593:         return NGX_CONF_ERROR;
                    594:     }
                    595: 
                    596:     if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_script_if_code_t));
                    597:     if (if_code == NULL) {
                    598:         return NGX_CONF_ERROR;
                    599:     }
                    600: 
                    601:     if_code->code = ngx_http_script_if_code;
                    602: 
                    603:     elts = lcf->codes->elts;
                    604: 
                    605: 
                    606:     /* the inner directives must be compiled to the same code array */
                    607: 
                    608:     nlcf = ctx->loc_conf[ngx_http_rewrite_module.ctx_index];
                    609:     nlcf->codes = lcf->codes;
                    610: 
                    611: 
                    612:     save = *cf;
                    613:     cf->ctx = ctx;
                    614: 
                    615:     if (pclcf->name.len == 0) {
                    616:         if_code->loc_conf = NULL;
                    617:         cf->cmd_type = NGX_HTTP_SIF_CONF;
                    618: 
                    619:     } else {
                    620:         if_code->loc_conf = ctx->loc_conf;
                    621:         cf->cmd_type = NGX_HTTP_LIF_CONF;
                    622:     }
                    623: 
                    624:     rv = ngx_conf_parse(cf, NULL);
                    625: 
                    626:     *cf = save;
                    627: 
                    628:     if (rv != NGX_CONF_OK) {
                    629:         return rv;
                    630:     }
                    631: 
                    632: 
                    633:     if (elts != lcf->codes->elts) {
                    634:         if_code = (ngx_http_script_if_code_t *)
                    635:                    ((u_char *) if_code + ((u_char *) lcf->codes->elts - elts));
                    636:     }
                    637: 
                    638:     if_code->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
                    639:                                                 - (u_char *) if_code;
                    640: 
                    641:     /* the code array belong to parent block */
                    642: 
                    643:     nlcf->codes = NULL;
                    644: 
                    645:     return NGX_CONF_OK;
                    646: }
                    647: 
                    648: 
                    649: static char *
                    650: ngx_http_rewrite_if_condition(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf)
                    651: {
                    652:     u_char                        *p;
                    653:     size_t                         len;
                    654:     ngx_str_t                     *value;
                    655:     ngx_uint_t                     cur, last;
                    656:     ngx_regex_compile_t            rc;
                    657:     ngx_http_script_code_pt       *code;
                    658:     ngx_http_script_file_code_t   *fop;
                    659:     ngx_http_script_regex_code_t  *regex;
                    660:     u_char                         errstr[NGX_MAX_CONF_ERRSTR];
                    661: 
                    662:     value = cf->args->elts;
                    663:     last = cf->args->nelts - 1;
                    664: 
                    665:     if (value[1].len < 1 || value[1].data[0] != '(') {
                    666:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                    667:                            "invalid condition \"%V\"", &value[1]);
                    668:         return NGX_CONF_ERROR;
                    669:     }
                    670: 
                    671:     if (value[1].len == 1) {
                    672:         cur = 2;
                    673: 
                    674:     } else {
                    675:         cur = 1;
                    676:         value[1].len--;
                    677:         value[1].data++;
                    678:     }
                    679: 
                    680:     if (value[last].len < 1 || value[last].data[value[last].len - 1] != ')') {
                    681:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                    682:                            "invalid condition \"%V\"", &value[last]);
                    683:         return NGX_CONF_ERROR;
                    684:     }
                    685: 
                    686:     if (value[last].len == 1) {
                    687:         last--;
                    688: 
                    689:     } else {
                    690:         value[last].len--;
                    691:         value[last].data[value[last].len] = '\0';
                    692:     }
                    693: 
                    694:     len = value[cur].len;
                    695:     p = value[cur].data;
                    696: 
                    697:     if (len > 1 && p[0] == '$') {
                    698: 
                    699:         if (cur != last && cur + 2 != last) {
                    700:             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                    701:                                "invalid condition \"%V\"", &value[cur]);
                    702:             return NGX_CONF_ERROR;
                    703:         }
                    704: 
                    705:         if (ngx_http_rewrite_variable(cf, lcf, &value[cur]) != NGX_CONF_OK) {
                    706:             return NGX_CONF_ERROR;
                    707:         }
                    708: 
                    709:         if (cur == last) {
                    710:             return NGX_CONF_OK;
                    711:         }
                    712: 
                    713:         cur++;
                    714: 
                    715:         len = value[cur].len;
                    716:         p = value[cur].data;
                    717: 
                    718:         if (len == 1 && p[0] == '=') {
                    719: 
                    720:             if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
                    721:                 return NGX_CONF_ERROR;
                    722:             }
                    723: 
                    724:             code = ngx_http_script_start_code(cf->pool, &lcf->codes,
                    725:                                               sizeof(uintptr_t));
                    726:             if (code == NULL) {
                    727:                 return NGX_CONF_ERROR;
                    728:             }
                    729: 
                    730:             *code = ngx_http_script_equal_code;
                    731: 
                    732:             return NGX_CONF_OK;
                    733:         }
                    734: 
                    735:         if (len == 2 && p[0] == '!' && p[1] == '=') {
                    736: 
                    737:             if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
                    738:                 return NGX_CONF_ERROR;
                    739:             }
                    740: 
                    741:             code = ngx_http_script_start_code(cf->pool, &lcf->codes,
                    742:                                               sizeof(uintptr_t));
                    743:             if (code == NULL) {
                    744:                 return NGX_CONF_ERROR;
                    745:             }
                    746: 
                    747:             *code = ngx_http_script_not_equal_code;
                    748:             return NGX_CONF_OK;
                    749:         }
                    750: 
                    751:         if ((len == 1 && p[0] == '~')
                    752:             || (len == 2 && p[0] == '~' && p[1] == '*')
                    753:             || (len == 2 && p[0] == '!' && p[1] == '~')
                    754:             || (len == 3 && p[0] == '!' && p[1] == '~' && p[2] == '*'))
                    755:         {
                    756:             regex = ngx_http_script_start_code(cf->pool, &lcf->codes,
                    757:                                          sizeof(ngx_http_script_regex_code_t));
                    758:             if (regex == NULL) {
                    759:                 return NGX_CONF_ERROR;
                    760:             }
                    761: 
                    762:             ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));
                    763: 
                    764:             ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
                    765: 
                    766:             rc.pattern = value[last];
                    767:             rc.options = (p[len - 1] == '*') ? NGX_REGEX_CASELESS : 0;
                    768:             rc.err.len = NGX_MAX_CONF_ERRSTR;
                    769:             rc.err.data = errstr;
                    770: 
                    771:             regex->regex = ngx_http_regex_compile(cf, &rc);
                    772:             if (regex->regex == NULL) {
                    773:                 return NGX_CONF_ERROR;
                    774:             }
                    775: 
                    776:             regex->code = ngx_http_script_regex_start_code;
                    777:             regex->next = sizeof(ngx_http_script_regex_code_t);
                    778:             regex->test = 1;
                    779:             if (p[0] == '!') {
                    780:                 regex->negative_test = 1;
                    781:             }
                    782:             regex->name = value[last];
                    783: 
                    784:             return NGX_CONF_OK;
                    785:         }
                    786: 
                    787:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                    788:                            "unexpected \"%V\" in condition", &value[cur]);
                    789:         return NGX_CONF_ERROR;
                    790: 
                    791:     } else if ((len == 2 && p[0] == '-')
                    792:                || (len == 3 && p[0] == '!' && p[1] == '-'))
                    793:     {
                    794:         if (cur + 1 != last) {
                    795:             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                    796:                                "invalid condition \"%V\"", &value[cur]);
                    797:             return NGX_CONF_ERROR;
                    798:         }
                    799: 
                    800:         value[last].data[value[last].len] = '\0';
                    801:         value[last].len++;
                    802: 
                    803:         if (ngx_http_rewrite_value(cf, lcf, &value[last]) != NGX_CONF_OK) {
                    804:             return NGX_CONF_ERROR;
                    805:         }
                    806: 
                    807:         fop = ngx_http_script_start_code(cf->pool, &lcf->codes,
                    808:                                           sizeof(ngx_http_script_file_code_t));
                    809:         if (fop == NULL) {
                    810:             return NGX_CONF_ERROR;
                    811:         }
                    812: 
                    813:         fop->code = ngx_http_script_file_code;
                    814: 
                    815:         if (p[1] == 'f') {
                    816:             fop->op = ngx_http_script_file_plain;
                    817:             return NGX_CONF_OK;
                    818:         }
                    819: 
                    820:         if (p[1] == 'd') {
                    821:             fop->op = ngx_http_script_file_dir;
                    822:             return NGX_CONF_OK;
                    823:         }
                    824: 
                    825:         if (p[1] == 'e') {
                    826:             fop->op = ngx_http_script_file_exists;
                    827:             return NGX_CONF_OK;
                    828:         }
                    829: 
                    830:         if (p[1] == 'x') {
                    831:             fop->op = ngx_http_script_file_exec;
                    832:             return NGX_CONF_OK;
                    833:         }
                    834: 
                    835:         if (p[0] == '!') {
                    836:             if (p[2] == 'f') {
                    837:                 fop->op = ngx_http_script_file_not_plain;
                    838:                 return NGX_CONF_OK;
                    839:             }
                    840: 
                    841:             if (p[2] == 'd') {
                    842:                 fop->op = ngx_http_script_file_not_dir;
                    843:                 return NGX_CONF_OK;
                    844:             }
                    845: 
                    846:             if (p[2] == 'e') {
                    847:                 fop->op = ngx_http_script_file_not_exists;
                    848:                 return NGX_CONF_OK;
                    849:             }
                    850: 
                    851:             if (p[2] == 'x') {
                    852:                 fop->op = ngx_http_script_file_not_exec;
                    853:                 return NGX_CONF_OK;
                    854:             }
                    855:         }
                    856: 
                    857:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                    858:                            "invalid condition \"%V\"", &value[cur]);
                    859:         return NGX_CONF_ERROR;
                    860:     }
                    861: 
                    862:     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                    863:                        "invalid condition \"%V\"", &value[cur]);
                    864: 
                    865:     return NGX_CONF_ERROR;
                    866: }
                    867: 
                    868: 
                    869: static char *
                    870: ngx_http_rewrite_variable(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf,
                    871:     ngx_str_t *value)
                    872: {
                    873:     ngx_int_t                    index;
                    874:     ngx_http_script_var_code_t  *var_code;
                    875: 
                    876:     value->len--;
                    877:     value->data++;
                    878: 
                    879:     index = ngx_http_get_variable_index(cf, value);
                    880: 
                    881:     if (index == NGX_ERROR) {
                    882:         return NGX_CONF_ERROR;
                    883:     }
                    884: 
                    885:     var_code = ngx_http_script_start_code(cf->pool, &lcf->codes,
                    886:                                           sizeof(ngx_http_script_var_code_t));
                    887:     if (var_code == NULL) {
                    888:         return NGX_CONF_ERROR;
                    889:     }
                    890: 
                    891:     var_code->code = ngx_http_script_var_code;
                    892:     var_code->index = index;
                    893: 
                    894:     return NGX_CONF_OK;
                    895: }
                    896: 
                    897: 
                    898: static char *
                    899: ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                    900: {
                    901:     ngx_http_rewrite_loc_conf_t  *lcf = conf;
                    902: 
                    903:     ngx_int_t                            index;
                    904:     ngx_str_t                           *value;
                    905:     ngx_http_variable_t                 *v;
                    906:     ngx_http_script_var_code_t          *vcode;
                    907:     ngx_http_script_var_handler_code_t  *vhcode;
                    908: 
                    909:     value = cf->args->elts;
                    910: 
                    911:     if (value[1].data[0] != '$') {
                    912:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                    913:                            "invalid variable name \"%V\"", &value[1]);
                    914:         return NGX_CONF_ERROR;
                    915:     }
                    916: 
                    917:     value[1].len--;
                    918:     value[1].data++;
                    919: 
                    920:     v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGEABLE);
                    921:     if (v == NULL) {
                    922:         return NGX_CONF_ERROR;
                    923:     }
                    924: 
                    925:     index = ngx_http_get_variable_index(cf, &value[1]);
                    926:     if (index == NGX_ERROR) {
                    927:         return NGX_CONF_ERROR;
                    928:     }
                    929: 
                    930:     if (v->get_handler == NULL
                    931:         && ngx_strncasecmp(value[1].data, (u_char *) "http_", 5) != 0
                    932:         && ngx_strncasecmp(value[1].data, (u_char *) "sent_http_", 10) != 0
                    933:         && ngx_strncasecmp(value[1].data, (u_char *) "upstream_http_", 14) != 0)
                    934:     {
                    935:         v->get_handler = ngx_http_rewrite_var;
                    936:         v->data = index;
                    937:     }
                    938: 
                    939:     if (ngx_http_rewrite_value(cf, lcf, &value[2]) != NGX_CONF_OK) {
                    940:         return NGX_CONF_ERROR;
                    941:     }
                    942: 
                    943:     if (v->set_handler) {
                    944:         vhcode = ngx_http_script_start_code(cf->pool, &lcf->codes,
                    945:                                    sizeof(ngx_http_script_var_handler_code_t));
                    946:         if (vhcode == NULL) {
                    947:             return NGX_CONF_ERROR;
                    948:         }
                    949: 
                    950:         vhcode->code = ngx_http_script_var_set_handler_code;
                    951:         vhcode->handler = v->set_handler;
                    952:         vhcode->data = v->data;
                    953: 
                    954:         return NGX_CONF_OK;
                    955:     }
                    956: 
                    957:     vcode = ngx_http_script_start_code(cf->pool, &lcf->codes,
                    958:                                        sizeof(ngx_http_script_var_code_t));
                    959:     if (vcode == NULL) {
                    960:         return NGX_CONF_ERROR;
                    961:     }
                    962: 
                    963:     vcode->code = ngx_http_script_set_var_code;
                    964:     vcode->index = (uintptr_t) index;
                    965: 
                    966:     return NGX_CONF_OK;
                    967: }
                    968: 
                    969: 
                    970: static char *
                    971: ngx_http_rewrite_value(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf,
                    972:     ngx_str_t *value)
                    973: {
                    974:     ngx_int_t                              n;
                    975:     ngx_http_script_compile_t              sc;
                    976:     ngx_http_script_value_code_t          *val;
                    977:     ngx_http_script_complex_value_code_t  *complex;
                    978: 
                    979:     n = ngx_http_script_variables_count(value);
                    980: 
                    981:     if (n == 0) {
                    982:         val = ngx_http_script_start_code(cf->pool, &lcf->codes,
                    983:                                          sizeof(ngx_http_script_value_code_t));
                    984:         if (val == NULL) {
                    985:             return NGX_CONF_ERROR;
                    986:         }
                    987: 
                    988:         n = ngx_atoi(value->data, value->len);
                    989: 
                    990:         if (n == NGX_ERROR) {
                    991:             n = 0;
                    992:         }
                    993: 
                    994:         val->code = ngx_http_script_value_code;
                    995:         val->value = (uintptr_t) n;
                    996:         val->text_len = (uintptr_t) value->len;
                    997:         val->text_data = (uintptr_t) value->data;
                    998: 
                    999:         return NGX_CONF_OK;
                   1000:     }
                   1001: 
                   1002:     complex = ngx_http_script_start_code(cf->pool, &lcf->codes,
                   1003:                                  sizeof(ngx_http_script_complex_value_code_t));
                   1004:     if (complex == NULL) {
                   1005:         return NGX_CONF_ERROR;
                   1006:     }
                   1007: 
                   1008:     complex->code = ngx_http_script_complex_value_code;
                   1009:     complex->lengths = NULL;
                   1010: 
                   1011:     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
                   1012: 
                   1013:     sc.cf = cf;
                   1014:     sc.source = value;
                   1015:     sc.lengths = &complex->lengths;
                   1016:     sc.values = &lcf->codes;
                   1017:     sc.variables = n;
                   1018:     sc.complete_lengths = 1;
                   1019: 
                   1020:     if (ngx_http_script_compile(&sc) != NGX_OK) {
                   1021:         return NGX_CONF_ERROR;
                   1022:     }
                   1023: 
                   1024:     return NGX_CONF_OK;
                   1025: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>