Nginx(一) 配置文件解析流程研究
默认配置文件
默认配置文件全路径在NGX_CONF_PATH宏中定义。NGX_CONF_PATH宏在auto目录下的options脚本中定义的。这里还可以看到其他宏的定义。
对于NGX_CORE_MODULE类型的模块,也就是核心模块,调用它的create_conf()钩子函数。这个函数应该是用来创建存放各个模块的conf信息的内存空间。成功申请到空间的首地址放入conf_ctx[]数组对应位置。很明显conf_ctx[]数组中保存着所有的模块的配置信息。每个模块通过自身相应的下标对应。
Conf_ctx是个四维指针,即也可看作四维数组。
接下来对核心模块中NGX_MAIN_CONF类型配置信息进行解析。
conf.ctx = cycle->conf_ctx; /* notice */
conf.cycle = cycle;
conf.pool = pool;
conf.log = log;
conf.module_type = NGX_CORE_MODULE;
conf.cmd_type = NGX_MAIN_CONF;
注:conf作为参数传入其他函数(如ngx_conf_param(),ngx_conf_parse())中,对conf.ctx操作即对全局配置信息上下文操作
…
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;
}
…
ngx_conf_param()函数中创建一个解析配置信息用的临时buffer,设置了conf_file对象,调用ngx_conf_parse()函数来解析。所以ngx_conf_parse()才是重点。
注:ngx_conf_param()调用ngx_conf_parse()时,文件名参数用的是NULL。配置文件的fd也设为NGX_INVALID_FILE。
conf_file.file.fd = NGX_INVALID_FILE;
conf_file.file.name.data = NULL;
conf_file.line = 0;
ngx_conf_parse()函数是解析的入口。ngx_conf_parse()中解析分为三种:
enum {
parse_file = 0,
parse_block,
parse_param
} type;
在ngx_conf_param()中的设置,使得ngx_conf_parse() 按parse_param方式解析。
解析配置信息的主体部份是一个循环。
for ( ;; ) {
rc = ngx_conf_read_token(cf);
/*
* ngx_conf_read_token() may return
*
* NGX_ERROR there is error
* NGX_OK the token terminated by ";" was found
* NGX_CONF_BLOCK_START the token terminated by "{" was found
* NGX_CONF_BLOCK_DONE the "}" was found
* NGX_CONF_FILE_DONE the configuration file is done
*/
异常情况不多说,也容易看明白。正常情况下,rc若返回是NGX_CONF_BLOCK_DONE或NGX_CONF_FILE_DONE表示一块信息(如http{…}),或配置文件结束。于是跳到done处退出。
if (cf->handler) { /* 从ngx_init_cycle()中的conf对象中没有设handler() */
/*
* the custom handler, i.e., that is used in the http's
* "types { ... }" directive
*/
rv = (*cf->handler)(cf, NULL, cf->handler_conf);
if (rv == NGX_CONF_OK) {
continue;
}
if (rv == NGX_CONF_ERROR) {
goto failed;
}
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv);
goto failed;
}
rc = ngx_conf_handler(cf, rc);
}
很清楚,ngx_conf_parse()函数不断地用ngx_conf_read_token()去解析配置文件,对应的每个配置项的读取设定由cf->handler()来处理。接着调用ngx_conf_handler()。
ngx_conf_handler()函数主要作用是调用各模块中command_t对象中的set()钩子。这个函数中主要是两个嵌套的循环。由于nginx设计成由模块为单位来开发的,如默认的是http模块,还有mail模块。一个模块中有一个command列表。下面是mail模块中的代码:
static ngx_command_t ngx_mail_commands[] = {
{ ngx_string("mail"),
NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
ngx_mail_block,
0,
0,
NULL },
{ ngx_string("imap"),
NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
ngx_mail_block,
0,
0,
NULL },
ngx_null_command
};
ngx_module_t ngx_mail_module = {
NGX_MODULE_V1,
&ngx_mail_module_ctx, /* module context */
ngx_mail_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
};
ngx_conf_handler()的主体部分为:
foreach NGX_CONF_MODULE类型的模块 do
foreach 模块中的command对象 do
检查command对象的名字;
检查command对象的类型;(略)
取得模块的conf上下文对象;
rv = cmd->set(cf, cmd, conf); /* 调用command对象的set钩子 */
end
end
http模块中的command对象中的set()钩子就是http_block(),同理mail模块中的command对象中的set()钩子是mail_block()。
NGX_CONF_PATH=${NGX_CONF_PATH:-conf/nginx.conf}
NGX_CONF_PREFIX=`dirname $NGX_CONF_PATH`
NGX_PID_PATH=${NGX_PID_PATH:-logs/nginx.pid}
NGX_LOCK_PATH=${NGX_LOCK_PATH:-logs/nginx.lock}
在biogine.c文件中的ngx_process_options()函数中,有如下代码段:
if (ngx_conf_file) {
cycle->conf_file.len = ngx_strlen(ngx_conf_file);
cycle->conf_file.data = ngx_conf_file;
} else {
cycle->conf_file.len = sizeof(NGX_CONF_PATH) - 1;
cycle->conf_file.data = (u_char *) NGX_CONF_PATH;
}
…
变量ngx_conf_file用来保存用户在命令行中指定的配置文件名。ngx_conf_file的类型为static u_char*类型,如果没有指定,ngx_conf_file为NULL,于是用NGX_CONF_PATH宏中预定义的默认配置文件名。接下来跟踪cycle->conf_file。
ngx_cycle.c文件中的ngx_init_cycle()函数中开始解析配置文件。在210行处(ver 0.8.19),看到下面代码。
…
for (i = 0; ngx_modules[i]; i++) {
if (ngx_modules[i]->type != NGX_CORE_MODULE) {
continue;
}
module = ngx_modules[i]->ctx;
if (module->create_conf) {
rv = module->create_conf(cycle);
if (rv == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
cycle->conf_ctx[ngx_modules[i]->index] = rv;
}
}
…