1. nginx配置说明
nginx的配置文件在nginx系统中占有非常重要地位。
nginx的配置文件,它具有层次性。可以树来表示nginx的配置文件,假想一个树根ROOT,配置文件中配置命令 daemon、event、http等,是ROOT的孩子,而event、http又有自己的孩子。如下图:
2. nginx配置文件解析
nginx对配置的解析处理就是对该配置树进行递归的深度优先遍历出各个配置命令,然后对每个配置指令进行处理。
现在看一下nginx源码是如何解析配置文件的。
--main
--ngx_init_cycle
--ngx_conf_parse
2.1 ngx_cycle_init
nginx对配置文件的解析,对复杂的应该是http部分的解析处理。http部分的配置解析是当遇到'http'配置命令开始的,从上面的配置树中,我知道http部分的配置指令又分为多个层次
http server location等。
-
ngx_cycle_t *
-
ngx_init_cycle(ngx_cycle_t *old_cycle)
-
{
-
// ......
-
ngx_conf_t conf;
-
-
// ......
-
-
// 设置配置上下文
-
conf.ctx = cycle->conf_ctx;
-
conf.cycle = cycle;
-
conf.pool = pool;
-
conf.log = log;
-
conf.module_type = NGX_CORE_MODULE; //
-
conf.cmd_type = NGX_MAIN_CONF;
-
-
#if 0
-
log->log_level = NGX_LOG_DEBUG_ALL;
-
#endif
-
-
if (ngx_conf_param(&conf) != NGX_CONF_OK) {
-
environ = senv;
-
ngx_destroy_cycle_pools(&conf);
-
return NULL;
-
}
-
-
if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {
-
environ = senv;
-
ngx_destroy_cycle_pools(&conf);
-
return NULL;
-
}
-
// 至此,配置文件已经解析完毕
-
-
// ......
-
}
'http'配置指令属于 ngx_http_module 核心模块。该核心模块作为http部分的代理,是nginx系统处理http部分的入口。
-
static ngx_command_t ngx_http_commands[] = {
-
-
{ ngx_string("http"),
-
NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
-
ngx_http_block,
-
0,
-
0,
-
NULL },
-
-
ngx_null_command
-
};
-
-
-
static ngx_core_module_t ngx_http_module_ctx = {
-
ngx_string("http"),
-
NULL,
-
NULL
-
};
-
-
-
ngx_module_t ngx_http_module = {
-
NGX_MODULE_V1,
-
&ngx_http_module_ctx, /* module context */
-
ngx_http_commands, /* module directives */
-
NGX_CORE_MODULE, /* module type */
-
NULL, /* init master */
-
NULL, /* init module */
-
NULL, /* init process */
-
NULL, /* init thread */
-
NULL, /* exit thread */
-
NULL, /* exit process */
-
NULL, /* exit master */
-
NGX_MODULE_V1_PADDING
-
};
2.2 ngx_http_block
当遇到'http'配置命令是,nginx的调用 ngx_http_block()进行处理:
-
static char *
-
ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-
{
-
char *rv;
-
ngx_uint_t mi, m, s;
-
ngx_conf_t pcf;
-
ngx_http_module_t *module;
-
ngx_http_conf_ctx_t *ctx;
-
ngx_http_core_loc_conf_t *clcf;
-
ngx_http_core_srv_conf_t **cscfp;
-
ngx_http_core_main_conf_t *cmcf;
-
-
/* the main http context */
-
/*
-
* typedef struct {
-
* void **main_conf;
-
* void **srv_conf;
-
* void **loc_conf;
-
* } ngx_http_conf_ctx_t;
-
* ctx == ngx_http_conf_ctx_t
-
* main_conf -> [ m0 ] [ m1 ] ... [ ngx_http_max_module - 1]
-
* srv_conf -> [ s0 ] [ s1 ] ... [ ngx_http_max_module - 1]
-
* loc_conf -> [ l0 ] [ l1 ] ... [ ngx_http_max_module - 1]
-
*/
-
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
-
if (ctx == NULL) {
-
return NGX_CONF_ERROR;
-
}
-
-
// 保存到 cycle->conf_ctx[ngx_http_module.index] 中
-
*(ngx_http_conf_ctx_t **) conf = ctx;
-
-
-
/* count the number of the http modules and set up their indices */
-
-
ngx_http_max_module = 0;
-
for (m = 0; ngx_modules[m]; m++) {
-
if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
-
continue;
-
}
-
-
ngx_modules[m]->ctx_index = ngx_http_max_module++;
-
}
-
-
-
/* the http main_conf context, it is the same in the all http contexts */
-
// main_conf -> [ m0 ] [ m1 ] ... [ ngx_http_max_module - 1]
-
-
ctx->main_conf = ngx_pcalloc(cf->pool,
-
sizeof(void *) * ngx_http_max_module);
-
if (ctx->main_conf == NULL) {
-
return NGX_CONF_ERROR;
-
}
-
-
-
/*
-
* the http null srv_conf context, it is used to merge
-
* the server{}s' srv_conf's
-
*/
-
// srv_conf -> [ s0 ] [ s1 ] ... [ ngx_http_max_module - 1]
-
-
ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
-
if (ctx->srv_conf == NULL) {
-
return NGX_CONF_ERROR;
-
}
-
-
-
/*
-
* the http null loc_conf context, it is used to merge
-
* the server{}s' loc_conf's
-
*/
-
// loc_conf -> [ l0 ] [ l1 ] ... [ ngx_http_max_module - 1]
-
ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
-
if (ctx->loc_conf == NULL) {
-
return NGX_CONF_ERROR;
-
}
-
-
-
-
/*
-
* create the main_conf's, the null srv_conf's, and the null loc_conf's
-
* of the all http modules
-
*/
-
//
-
for (m = 0; ngx_modules[m]; m++) {
-
if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
-
continue;
-
}
-
-
module = ngx_modules[m]->ctx;
-
mi = ngx_modules[m]->ctx_index;
-
-
if (module->create_main_conf) {
-
ctx->main_conf[mi] = module->create_main_conf(cf);
-
if (ctx->main_conf[mi] == NULL) {
-
return NGX_CONF_ERROR;
-
}
-
}
-
-
if (module->create_srv_conf) {
-
ctx->srv_conf[mi] = module->create_srv_conf(cf);
-
if (ctx->srv_conf[mi] == NULL) {
-
return NGX_CONF_ERROR;
-
}
-
}
-
-
if (module->create_loc_conf) {
-
ctx->loc_conf[mi] = module->create_loc_conf(cf);
-
if (ctx->loc_conf[mi] == NULL) {
-
return NGX_CONF_ERROR;
-
}
-
}
-
}
-
-
// 保存父配置的上下文
-
pcf = *cf;
-
// 修改为当前配置的上下文
-
cf->ctx = ctx;
-
-
for (m = 0; ngx_modules[m]; m++) {
-
if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
-
continue;
-
}
-
-
module = ngx_modules[m]->ctx;
-
-
if (module->preconfiguration) {
-
if (module->preconfiguration(cf) != NGX_OK) {
-
return NGX_CONF_ERROR;
-
}
-
}
-
}
-
-
/* parse inside the http{} block */
-
-
-
cf->module_type = NGX_HTTP_MODULE;
-
cf->cmd_type = NGX_HTTP_MAIN_CONF;
-
// 递归解析 'http' 子树部分的配置命令
-
rv = ngx_conf_parse(cf, NULL);
-
-
// 至此, 'http'子树的配置命令解析完毕
-
-
// ......
-
}
2.3 ngx_http_core_server
当 ngx_http_block 中调用 ngx_conf_parse(), 如果遇到 'server' 配置指令,则会调用 ngx_http_core_server.
-
static char *
-
ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
-
{
-
char *rv;
-
void *mconf;
-
ngx_uint_t i;
-
ngx_conf_t pcf;
-
ngx_http_module_t *module;
-
struct sockaddr_in *sin;
-
ngx_http_conf_ctx_t *ctx, *http_ctx;
-
ngx_http_listen_opt_t lsopt;
-
ngx_http_core_srv_conf_t *cscf, **cscfp;
-
ngx_http_core_main_conf_t *cmcf;
-
-
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
-
if (ctx == NULL) {
-
return NGX_CONF_ERROR;
-
}
-
-
-
http_ctx = cf->ctx;
-
ctx->main_conf = http_ctx->main_conf;
-
-
/* the server{}'s srv_conf */
-
-
ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
-
if (ctx->srv_conf == NULL) {
-
return NGX_CONF_ERROR;
-
}
-
-
/* the server{}'s loc_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_srv_conf) {
-
mconf = module->create_srv_conf(cf);
-
if (mconf == NULL) {
-
return NGX_CONF_ERROR;
-
}
-
-
ctx->srv_conf[ngx_modules[i]->ctx_index] = mconf;
-
}
-
-
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;
-
}
-
}
-
-
-
cscf = ctx->srv_conf[ngx_http_core_module.ctx_index];
-
cscf->ctx = ctx;
-
-
-
cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
-
-
cscfp = ngx_array_push(&cmcf->servers);
-
if (cscfp == NULL) {
-
return NGX_CONF_ERROR;
-
}
-
*cscfp = cscf;
-
-
-
pcf = *cf;
-
cf->ctx = ctx;
-
cf->cmd_type = NGX_HTTP_SRV_CONF;
-
-
// 递归调用 ngx_conf_parse ,解析 'server' 配置块(或者配置子树)中的命令
-
rv = ngx_conf_parse(cf, NULL);
-
// 至此,该'server'块下的配置命令解析完毕
-
-
// 回复为父亲的配置上下文
-
*cf = pcf;
-
-
if (rv == NGX_CONF_OK && !cscf->listen) {
-
// 如果该server配置块未配置为listen,则使用默认的端口 80/8000
-
ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t));
-
-
sin = &lsopt.u.sockaddr_in;
-
-
sin->sin_family = AF_INET;
-
#if (NGX_WIN32)
-
sin->sin_port = htons(80);
-
#else
-
sin->sin_port = htons((getuid() == 0) ? 80 : 8000);
-
#endif
-
sin->sin_addr.s_addr = INADDR_ANY;
-
-
lsopt.socklen = sizeof(struct sockaddr_in);
-
-
lsopt.backlog = NGX_LISTEN_BACKLOG;
-
lsopt.rcvbuf = -1;
-
lsopt.sndbuf = -1;
-
#if (NGX_HAVE_SETFIB)
-
lsopt.setfib = -1;
-
#endif
-
lsopt.wildcard = 1;
-
-
(void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.socklen, lsopt.addr,
-
NGX_SOCKADDR_STRLEN, 1);
-
-
if (ngx_http_add_listen(cf, cscf, &lsopt) != NGX_OK) {
-
return NGX_CONF_ERROR;
-
}
-
}
-
-
return rv;
-
}
2.4 ngx_http_core_location
当 ngx_http_core_server 中调用 ngx_conf_parse(), 如果遇到 'location' 配置指令,则会调用 ngx_http_core_location .
-
static char *
-
ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
-
{
-
char *rv;
-
u_char *mod;
-
size_t len;
-
ngx_str_t *value, *name;
-
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;
-
-
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) {
-
ctx->loc_conf[ngx_modules[i]->ctx_index] =
-
module->create_loc_conf(cf);
-
if (ctx->loc_conf[ngx_modules[i]->ctx_index] == NULL) {
-
return NGX_CONF_ERROR;
-
}
-
}
-
}
-
-
clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
-
clcf->loc_conf = ctx->loc_conf;
-
-
value = cf->args->elts;
-
-
if (cf->args->nelts == 3) {
-
-
len = value[1].len;
-
mod = value[1].data;
-
name = &value[2];
-
-
if (len == 1 && mod[0] == '=') { // location = /a/b
-
-
clcf->name = *name;
-
clcf->exact_match = 1;
-
-
} else if (len == 2 && mod[0] == '^' && mod[1] == '~') { // location ^~ /a/b
-
-
clcf->name = *name;
-
clcf->noregex = 1;
-
-
} else if (len == 1 && mod[0] == '~') { // location ~ /a/b
-
-
if (ngx_http_core_regex_location(cf, clcf, name, 0) != NGX_OK) {
-
return NGX_CONF_ERROR;
-
}
-
-
} else if (len == 2 && mod[0] == '~' && mod[1] == '*') {// location = /a/b
-
-
if (ngx_http_core_regex_location(cf, clcf, name, 1) != NGX_OK) {
-
return NGX_CONF_ERROR;
-
}
-
-
} else {
-
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-
"invalid location modifier \"%V\"", &value[1]);
-
return NGX_CONF_ERROR;
-
}
-
-
} else {
-
-
name = &value[1];
-
-
if (name->data[0] == '=') {
-
-
clcf->name.len = name->len - 1;
-
clcf->name.data = name->data + 1;
-
clcf->exact_match = 1;
-
-
} else if (name->data[0] == '^' && name->data[1] == '~') {
-
-
clcf->name.len = name->len - 2;
-
clcf->name.data = name->data + 2;
-
clcf->noregex = 1;
-
-
} else if (name->data[0] == '~') {
-
-
name->len--;
-
name->data++;
-
-
if (name->data[0] == '*') {
-
-
name->len--;
-
name->data++;
-
-
if (ngx_http_core_regex_location(cf, clcf, name, 1) != NGX_OK) {
-
return NGX_CONF_ERROR;
-
}
-
-
} else {
-
if (ngx_http_core_regex_location(cf, clcf, name, 0) != NGX_OK) {
-
return NGX_CONF_ERROR;
-
}
-
}
-
-
} else {
-
-
clcf->name = *name;
-
-
if (name->data[0] == '@') {
-
clcf->named = 1;
-
}
-
}
-
}
-
-
pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
-
-
if (pclcf->name.len) {
-
-
/* nested location */
-
-
#if 0
-
clcf->prev_location = pclcf;
-
#endif
-
-
if (pclcf->exact_match) {
-
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-
"location \"%V\" cannot be inside "
-
"the exact location \"%V\"",
-
&clcf->name, &pclcf->name);
-
return NGX_CONF_ERROR;
-
}
-
-
if (pclcf->named) {
-
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-
"location \"%V\" cannot be inside "
-
"the named location \"%V\"",
-
&clcf->name, &pclcf->name);
-
return NGX_CONF_ERROR;
-
}
-
-
if (clcf->named) {
-
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-
"named location \"%V\" can be "
-
"on the server level only",
-
&clcf->name);
-
return NGX_CONF_ERROR;
-
}
-
-
len = pclcf->name.len;
-
-
#if (NGX_PCRE)
-
if (clcf->regex == NULL
-
&& ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0)
-
#else
-
if (ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0)
-
#endif
-
{
-
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-
"location \"%V\" is outside location \"%V\"",
-
&clcf->name, &pclcf->name);
-
return NGX_CONF_ERROR;
-
}
-
}
-
-
if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {
-
return NGX_CONF_ERROR;
-
}
-
-
// 保存父配置上下文信息
-
save = *cf;
-
// 设置该部分的配置上下文信息
-
cf->ctx = ctx;
-
cf->cmd_type = NGX_HTTP_LOC_CONF;
-
-
// 递归调用, 解析 'location' 配置块(子树)的配置命令
-
rv = ngx_conf_parse(cf, NULL);
-
// 至此,该 'location' 配置块(子树)的配置命令解析完毕
-
-
// 回复为父亲的配置上下文
-
*cf = save;
-
-
return rv;
-
}
2.5 总结
可以看出,nginx的配置文件的解析处理是按照深度优先遍历配置文件的各个配置命令。
当ngx_http_block()中 ngx_conf_parse() 返回后,整个 'http'块(子树)的所有的配置命令解析完毕。此时,nginx保存的配置信息的内存布局如下图所示。
3. ngx_http_block 解析完http配置块后的处理
从代码以及图中可以看出,http层次既有main_conf,也有srv_conf、loc_conf;server层既有srv_conf,也有 loc_conf; location层,有 loc_conf,还可能有 nested locaton层的配置。这就需要把相关部分的配置信息进行合并。
-
static char *
-
ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-
{
-
// http 配置块解析完毕
-
-
if (rv != NGX_CONF_OK) {
-
goto failed;
-
}
-
-
/*
-
* init http{} main_conf's, merge the server{}s' srv_conf's
-
* and its location{}s' loc_conf's
-
*/
-
-
cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
-
cscfp = cmcf->servers.elts;
-
-
for (m = 0; ngx_modules[m]; m++) {
-
if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
-
continue;
-
}
-
-
module = ngx_modules[m]->ctx;
-
mi = ngx_modules[m]->ctx_index;
-
-
/* init http{} main_conf's */
-
-
if (module->init_main_conf) {
-
rv = module->init_main_conf(cf, ctx->main_conf[mi]);
-
if (rv != NGX_CONF_OK) {
-
goto failed;
-
}
-
}
-
-
// 合并server的配置信息,该函数会继续调用合并location的配置信息
-
rv = ngx_http_merge_servers(cf, cmcf, module, mi);//
-
if (rv != NGX_CONF_OK) {
-
goto failed;
-
}
-
}
-
-
-
/* create location trees */
-
-
// 对各个server下的location配置信息进行整理,其目的是后面对location进行查询时,
-
// 效率尽可能的高
-
for (s = 0; s < cmcf->servers.nelts; s++) {
-
-
// clcf鎸囧悜ngx_http_core_module鐨剆rv绾у埆鐨刲ocation淇℃伅
-
clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
-
-
// 后续blog进行分析
-
if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) {
-
return NGX_CONF_ERROR;
-
}
-
-
// 后续blog进行分析
-
if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {
-
return NGX_CONF_ERROR;
-
}
-
}
-
-
// ngx把对 接受完http请求后的处理分为11个处理阶段,
-
// 也就是说可以在这个11个阶段注册各个模块的钩子函数,
-
// 使模块参与处理http业务。
-
if (ngx_http_init_phases(cf, cmcf) != NGX_OK) {
-
return NGX_CONF_ERROR;
-
}
-
-
-
// cmcf->headers_in_hash
-
if (ngx_http_init_headers_in_hash(cf, cmcf) != NGX_OK) {
-
return NGX_CONF_ERROR;
-
}
-
-
-
for (m = 0; ngx_modules[m]; m++) {
-
if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
-
continue;
-
}
-
-
module = ngx_modules[m]->ctx;
-
-
if (module->postconfiguration) {
-
// 上面已经初始化好了各个阶段,
-
// 各个模块可以根据需要插入相应阶段的处理函数
-
if (module->postconfiguration(cf) != NGX_OK) {
-
return NGX_CONF_ERROR;
-
}
-
}
-
}
-
-
if (ngx_http_variables_init_vars(cf) != NGX_OK) {
-
return NGX_CONF_ERROR;
-
}
-
-
/*
-
* http{}
至此整个http部分的配置解析完毕,理解了该部分配置信息的处理,其他配置信息可以很容易理解了。
阅读(2715) | 评论(0) | 转发(0) |