您的位置:首页 > 运维架构 > Nginx

nginx配置解析模块分析

2013-11-13 16:34 316 查看
nginx配置解析模块分析

 

    nginx提供配置文件供用户方便的定义nginx的行为,通过修改配置项可以指定nginx进程工作模块,指定log的输出方式,指定如何处理用户请求等等。ngx_conf_module模块提供ngx_conf_parse函数在nginx启动过程中被调用来解析配置文件,它读取配置文件内容并将配置项交由指定的模块处理,如将http配置项交由ngx_http_module处理。配置文件通常使用include配置项从其它文件中加载配置,如nginx.conf文件中使用”include mime.types”配置项加载mime.types文件。当在配置文件中发现include配置项时就调用ngx_conf_module模块提供的ngx_conf_include函数来解析,它首先分析出include配置项指定的文件名,对每一个文件分别调用ngx_conf_parse函数来解析。

ngx_conf_parse模块主要做三件事,第一提供ngx_conf_parse函数在nginx启动时被调用来处理配置文件。第二解析include配置项。第三提供预设的配置项解析回调函数(ngx_conf_module提供了12个回调函数)。

 

include配置项

    include file| mask

    在当前配置文件中包含其它配置文件,file用于指定被包含的某一个文件名,mask用于支持包含多个文件,如:

     include mime.types;

     include vhosts/*.conf;

 

ngx_conf_include函数分析

/*
*配置文件中找到include配置项时该函数被调用
*/
char *
ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char        *rv;
ngx_int_t    n;
ngx_str_t   *value, file, name;
ngx_glob_t   gl;

value = cf->args->elts;
file = value[1];

ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);

/***判断文件路径,当include配置项指定的文件名带绝对路径时不做任何处理,
否则默认在nginx启动时指定的配置文件存放路径中查找该文件***/
if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) {
return NGX_CONF_ERROR;
}

/***当文件名中包含"*?[" 字符时表示include配置项需包含多个文件***/
if (strpbrk((char *) file.data, "*?[") == NULL) {

ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);

return ngx_conf_parse(cf, &file);
}

ngx_memzero(&gl, sizeof(ngx_glob_t));

gl.pattern = file.data;
gl.log = cf->log;
gl.test = 1;

/***调用glob函数将查找所有匹配模式的文件名***/
if (ngx_open_glob(&gl) != NGX_OK) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
ngx_open_glob_n " \"%s\" failed", file.data);
return NGX_CONF_ERROR;
}

rv = NGX_CONF_OK;

for ( ;; ) {
/***获取匹配到的文件名***/
n = ngx_read_glob(&gl, &name);

if (n != NGX_OK) {
break;
}

file.len = name.len++;
file.data = ngx_pstrdup(cf->pool, &name);

ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);

/***调用ngx_conf_parse函数解析该文件***/
rv = ngx_conf_parse(cf, &file);

if (rv != NGX_CONF_OK) {
break;
}
}

/***释放glob_t对象***/
ngx_close_glob(&gl);

return rv;
}


ngx_conf_parse函数分析

/*
* ngx_conf_parse函数在如下三种情况下被调用:
* 1、nginx启动过程中。
* 2、解析带{}的配置项时。
* 3、解析include 配置项时。
*/
char *
ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
{
char             *rv;
ngx_fd_t          fd;
ngx_int_t         rc;
ngx_buf_t         buf;
ngx_conf_file_t  *prev, conf_file;
enum {
parse_file = 0,
parse_block,
parse_param
} type;

#if (NGX_SUPPRESS_WARN)
fd = NGX_INVALID_FILE;
prev = NULL;
#endif

/***当filename不为空时表示将要打开一个未被解析的配置文件进行解析***/
if (filename) {

/* open configuration file */

fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
if (fd == NGX_INVALID_FILE) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
ngx_open_file_n " \"%s\" failed",
filename->data);
return NGX_CONF_ERROR;
}

prev = cf->conf_file;

cf->conf_file = &conf_file;

if (ngx_fd_info(fd, &cf->conf_file->file.info) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
ngx_fd_info_n " \"%s\" failed", filename->data);
}

/***存放配置文件内容的buf***/
cf->conf_file->buffer = &buf;

buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log);
if (buf.start == NULL) {
goto failed;
}

buf.pos = buf.start;
buf.last = buf.start;
buf.end = buf.last + NGX_CONF_BUFFER;
buf.temporary = 1;

cf->conf_file->file.fd = fd;
cf->conf_file->file.name.len = filename->len;
cf->conf_file->file.name.data = filename->data;
cf->conf_file->file.offset = 0;
cf->conf_file->file.log = cf->log;
cf->conf_file->line = 1;

/***打开一个新配置文件时,按行解析该文件中的配置项***/
type = parse_file;

} else if (cf->conf_file->file.fd != NGX_INVALID_FILE) {

/***在遇到带{}的配置项时,filename参数常为空,file.fd 描述符为该配置项所在文件被打开时的描述符***/
type = parse_block;

} else {
type = 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
*/

if (rc == NGX_ERROR) {
goto done;
}

if (rc == NGX_CONF_BLOCK_DONE) {

if (type != parse_block) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\"");
goto failed;
}

goto done;
}

if (rc == NGX_CONF_FILE_DONE) {

if (type == parse_block) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"unexpected end of file, expecting \"}\"");
goto failed;
}

goto done;
}

if (rc == NGX_CONF_BLOCK_START) {

if (type == parse_param) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"block directives are not supported "
"in -g option");
goto failed;
}
}

/* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */

if (cf->handler) {

/*
* the custom handler, i.e., that is used in the http's
* "types { ... }" directive
*/

if (rc == NGX_CONF_BLOCK_START) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"{\"");
goto failed;
}

/***已找到一个有效的配置项,调用用户指定的回调函数***/
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;
}

/***已找到一个有效的配置项,调用ngx_conf_handler函数查找该由那个模块来解析***/
rc = ngx_conf_handler(cf, rc);

if (rc == NGX_ERROR) {
goto failed;
}
}

failed:

rc = NGX_ERROR;

done:

if (filename) {
if (cf->conf_file->buffer->start) {
ngx_free(cf->conf_file->buffer->start);
}

if (ngx_close_file(fd) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
ngx_close_file_n " %s failed",
filename->data);
return NGX_CONF_ERROR;
}

cf->conf_file = prev;
}

if (rc == NGX_ERROR) {
return NGX_CONF_ERROR;
}

return NGX_CONF_OK;
}


 

    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息