字号
1.相关指令
1.1 if指令
1
| Context: server, location
|
依据指定的条件决定是否执行 if 块语句中的内容
1.2 break指令
1
| Context: server, location, if
|
停止执行 ngx_http_rewrite_module 的指令集,但是其他模块指令是不受影响的
1.3 rewrite指令
1 2 3
| Context: server, location, if
rewrite regex replacement [flag];
|
rewrite 指令是使用指定的正则表达式regex来匹配请求的urI,如果匹配成功,则使用replacement更改URI。rewrite指令按照它们在配置文件中出现的顺序执行。可以使用flag标志来终止指令的进一步处理。如果替换字符串replacement以http://,https://或$scheme开头,则停止处理后续内容,并直接重定向返回给客户端。
1.4 return指令
1 2 3 4 5 6
| Context: server, location, if
return code [text]; return code URL; return URL;
|
停止处理并将指定的code码返回给客户端。 非标准code码 444 关闭连接而不发送响应报头
2.源码解析
2.1 rewrite指令源码解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
| static char * ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_rewrite_loc_conf_t *lcf = conf;
ngx_str_t *value; ngx_uint_t last; ngx_regex_compile_t rc; ngx_http_script_code_pt *code; ngx_http_script_compile_t sc; ngx_http_script_regex_code_t *regex; ngx_http_script_regex_end_code_t *regex_end; u_char errstr[NGX_MAX_CONF_ERRSTR];
regex = ngx_http_script_start_code(cf->pool, &lcf->codes, sizeof(ngx_http_script_regex_code_t)); if (regex == NULL) { return NGX_CONF_ERROR; }
ngx_memzero(regex, sizeof(ngx_http_script_regex_code_t));
value = cf->args->elts;
ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
rc.pattern = value[1]; rc.err.len = NGX_MAX_CONF_ERRSTR; rc.err.data = errstr;
regex->regex = ngx_http_regex_compile(cf, &rc); if (regex->regex == NULL) { return NGX_CONF_ERROR; } regex->code = ngx_http_script_regex_start_code; regex->uri = 1; regex->name = value[1];
if (value[2].data[value[2].len - 1] == '?') {
value[2].len--;
} else { regex->add_args = 1; }
last = 0;
if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0 || ngx_strncmp(value[2].data, "https://", sizeof("https://") - 1) == 0 || ngx_strncmp(value[2].data, "$scheme", sizeof("$scheme") - 1) == 0) { regex->status = NGX_HTTP_MOVED_TEMPORARILY; regex->redirect = 1; last = 1; }
if (cf->args->nelts == 4) { if (ngx_strcmp(value[3].data, "last") == 0) { last = 1;
} else if (ngx_strcmp(value[3].data, "break") == 0) { regex->break_cycle = 1; last = 1;
} else if (ngx_strcmp(value[3].data, "redirect") == 0) { regex->status = NGX_HTTP_MOVED_TEMPORARILY; regex->redirect = 1; last = 1;
} else if (ngx_strcmp(value[3].data, "permanent") == 0) { regex->status = NGX_HTTP_MOVED_PERMANENTLY; regex->redirect = 1; last = 1;
} else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[3]); return NGX_CONF_ERROR; } }
ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
sc.cf = cf; sc.source = &value[2]; sc.lengths = ®ex->lengths; sc.values = &lcf->codes; sc.variables = ngx_http_script_variables_count(&value[2]); sc.main = regex; sc.complete_lengths = 1; sc.compile_args = !regex->redirect;
if (ngx_http_script_compile(&sc) != NGX_OK) { return NGX_CONF_ERROR; }
regex = sc.main;
regex->size = sc.size; regex->args = sc.args;
if (sc.variables == 0 && !sc.dup_capture) { regex->lengths = NULL; }
regex_end = ngx_http_script_add_code(lcf->codes, sizeof(ngx_http_script_regex_end_code_t), ®ex); if (regex_end == NULL) { return NGX_CONF_ERROR; }
regex_end->code = ngx_http_script_regex_end_code; regex_end->uri = regex->uri; regex_end->args = regex->args; regex_end->add_args = regex->add_args; regex_end->redirect = regex->redirect;
if (last) { code = ngx_http_script_add_code(lcf->codes, sizeof(uintptr_t), ®ex); if (code == NULL) { return NGX_CONF_ERROR; }
*code = NULL; } regex->next = (u_char *) lcf->codes->elts + lcf->codes->nelts - (u_char *) regex;
return NGX_CONF_OK; }
|
2.2 return指令源码解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| static char * ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_rewrite_loc_conf_t *lcf = conf;
u_char *p; ngx_str_t *value, *v; ngx_http_script_return_code_t *ret; ngx_http_compile_complex_value_t ccv;
ret = ngx_http_script_start_code(cf->pool, &lcf->codes, sizeof(ngx_http_script_return_code_t)); if (ret == NULL) { return NGX_CONF_ERROR; }
value = cf->args->elts;
ngx_memzero(ret, sizeof(ngx_http_script_return_code_t)); ret->code = ngx_http_script_return_code;
p = value[1].data;
ret->status = ngx_atoi(p, value[1].len);
if (ret->status == (uintptr_t) NGX_ERROR) {
if (cf->args->nelts == 2 && (ngx_strncmp(p, "http://", sizeof("http://") - 1) == 0 || ngx_strncmp(p, "https://", sizeof("https://") - 1) == 0 || ngx_strncmp(p, "$scheme", sizeof("$scheme") - 1) == 0)) { ret->status = NGX_HTTP_MOVED_TEMPORARILY; v = &value[1];
} else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid return code \"%V\"", &value[1]); return NGX_CONF_ERROR; }
} else {
if (ret->status > 999) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid return code \"%V\"", &value[1]); return NGX_CONF_ERROR; }
if (cf->args->nelts == 2) { return NGX_CONF_OK; }
v = &value[2]; }
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
ccv.cf = cf; ccv.value = v; ccv.complex_value = &ret->text;
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { return NGX_CONF_ERROR; }
return NGX_CONF_OK; }
|
2.3 break指令源码解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| static char * ngx_http_rewrite_break(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_rewrite_loc_conf_t *lcf = conf;
ngx_http_script_code_pt *code;
code = ngx_http_script_start_code(cf->pool, &lcf->codes, sizeof(uintptr_t)); if (code == NULL) { return NGX_CONF_ERROR; }
*code = ngx_http_script_break_code;
return NGX_CONF_OK; }
|
配合ngx_http_rewrite_handler读代码,可以看到如果设置一个code节点到codes数组,那么在ngx_http_rewrite_handler的for循环执行到该节点code的时候,就会把e->ip置为NULL,这样就直接退出while (*(uintptr_t *) e->ip){}循环
2.4 if指令源码解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
| static char * ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_rewrite_loc_conf_t *lcf = conf;
void *mconf; char *rv; u_char *elts; ngx_uint_t i; ngx_conf_t save; ngx_http_module_t *module; ngx_http_conf_ctx_t *ctx, *pctx; ngx_http_core_loc_conf_t *clcf, *pclcf; ngx_http_script_if_code_t *if_code; ngx_http_rewrite_loc_conf_t *nlcf;
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); if (ctx == NULL) { return NGX_CONF_ERROR; }
pctx = cf->ctx; ctx->main_conf = pctx->main_conf; ctx->srv_conf = pctx->srv_conf;
ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); if (ctx->loc_conf == NULL) { return NGX_CONF_ERROR; }
for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_HTTP_MODULE) { continue; }
module = ngx_modules[i]->ctx;
if (module->create_loc_conf) {
mconf = module->create_loc_conf(cf); if (mconf == NULL) { return NGX_CONF_ERROR; }
ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf; } }
pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
clcf = ctx->loc_conf[ngx_http_core_module.ctx_index]; clcf->loc_conf = ctx->loc_conf; clcf->name = pclcf->name; clcf->noname = 1;
if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) { return NGX_CONF_ERROR; }
if (ngx_http_rewrite_if_condition(cf, lcf) != NGX_CONF_OK) { return NGX_CONF_ERROR; }
if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_script_if_code_t)); if (if_code == NULL) { return NGX_CONF_ERROR; }
if_code->code = ngx_http_script_if_code;
elts = lcf->codes->elts;
nlcf = ctx->loc_conf[ngx_http_rewrite_module.ctx_index]; nlcf->codes = lcf->codes;
save = *cf; cf->ctx = ctx;
if (pclcf->name.len == 0) { if_code->loc_conf = NULL; cf->cmd_type = NGX_HTTP_SIF_CONF;
} else { if_code->loc_conf = ctx->loc_conf; cf->cmd_type = NGX_HTTP_LIF_CONF; }
rv = ngx_conf_parse(cf, NULL);
*cf = save;
if (rv != NGX_CONF_OK) { return rv; }
if (elts != lcf->codes->elts) { if_code = (ngx_http_script_if_code_t *) ((u_char *) if_code + ((u_char *) lcf->codes->elts - elts)); }
if_code->next = (u_char *) lcf->codes->elts + lcf->codes->nelts - (u_char *) if_code;
nlcf->codes = NULL;
return NGX_CONF_OK; }
|
2.5 set指令源码解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
static char * ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_rewrite_loc_conf_t *lcf = conf;
ngx_int_t index; ngx_str_t *value; ngx_http_variable_t *v; ngx_http_script_var_code_t *vcode; ngx_http_script_var_handler_code_t *vhcode;
value = cf->args->elts;
if (value[1].data[0] != '$') { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid variable name \"%V\"", &value[1]); return NGX_CONF_ERROR; }
value[1].len--; value[1].data++; v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGEABLE); if (v == NULL) { return NGX_CONF_ERROR; } index = ngx_http_get_variable_index(cf, &value[1]); if (index == NGX_ERROR) { return NGX_CONF_ERROR; }
if (v->get_handler == NULL && ngx_strncasecmp(value[1].data, (u_char *) "http_", 5) != 0 && ngx_strncasecmp(value[1].data, (u_char *) "sent_http_", 10) != 0 && ngx_strncasecmp(value[1].data, (u_char *) "upstream_http_", 14) != 0 && ngx_strncasecmp(value[1].data, (u_char *) "cookie_", 7) != 0 && ngx_strncasecmp(value[1].data, (u_char *) "upstream_cookie_", 16) != 0 && ngx_strncasecmp(value[1].data, (u_char *) "arg_", 4) != 0) { v->get_handler = ngx_http_rewrite_var; v->data = index; }
if (ngx_http_rewrite_value(cf, lcf, &value[2]) != NGX_CONF_OK) { return NGX_CONF_ERROR; }
if (v->set_handler) { vhcode = ngx_http_script_start_code(cf->pool, &lcf->codes, sizeof(ngx_http_script_var_handler_code_t)); if (vhcode == NULL) { return NGX_CONF_ERROR; }
vhcode->code = ngx_http_script_var_set_handler_code; vhcode->handler = v->set_handler; vhcode->data = v->data;
return NGX_CONF_OK; }
vcode = ngx_http_script_start_code(cf->pool, &lcf->codes, sizeof(ngx_http_script_var_code_t)); if (vcode == NULL) { return NGX_CONF_ERROR; }
vcode->code = ngx_http_script_set_var_code; vcode->index = (uintptr_t) index;
return NGX_CONF_OK; }
|
3.总结
记录 Nginx、Linux 与性能分析的学习笔记。