这里要先看一下配置文件格式:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
极其简单的配置文件格式:key-value.
具体把文件格式分为两类:简单和复杂配置.
简单配置:没有大括号的配置如:worker_processes 1;
复杂配置:含有大括号的配置:
events {
worker_connections 1024;
}
我们再看一下解析配置文件的函数:
staticngx_command_t ngx_http_core_commands[] ={
{
//配置项的key,用于定位处理配置的command函数
ngx_string("variables_hash_max_size"),
//配置类型
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
//配置的解析函数
ngx_conf_set_num_slot,
NGX_HTTP_MAIN_CONF_OFFSET,
offsetof(ngx_http_core_main_conf_t,variables_hash_max_size),
NULL },
………………………………………………….
ngx_null_command
};
个人理解:
通过配置文件解析函数ngx_conf_read_token,将buf里面的token解析出来.其实在解析过程中,所有以空格间隔的字符串都被看作token,存储在cf->argc中.通过分号,左括号,来区分一组token.在一组token中,以第一个token为key-value对中的key,(重点来了)根据第一个token来对所有模块的command进行扫描,如果匹配,则根据其定义的配置解析函数来处理.
例如:ngx_string("variables_hash_max_size"), 就是key,而以他为首的token组就是value(出去第一个token).
在ngx_conf_parse函数中,有这么一段代码:
if(cf->handler) {
………………
rv =(*cf->handler)(cf, NULL, cf->handler_conf);
……………
}
该代码含义是,如果定义了cf->handler函数,就先执行该函数,那么该函数的作用是什么呢?我们先来查询一下该函数在哪里赋值:
并且每个函数调用以后紧跟着就会调用ngx_conf_parse函数.例如:
我们注意到,这些模块的配置项的类型都是不定配置项,即一个key可能对应一个以上的value,(例如:text/html html thm shtml;)所以为此,nginx专门为他们准备了一个回调函数处理此种类型.
ngx_conf_read_token:把配置文件中的token解析出来,放入cf-args中.
ngx_conf_handler:处理配置文件中的key对应多对value的情况.
ngx_conf_handler(cf, rc):把cf-args中的数据存入对应的ngx变量中.
注意一点:ngx_conf_handler函数还可能递归调用ngx_conf_parse,用于解析复杂配置项.
//用于标记当前解析的状态.
enum {
parse_file = 0,
parse_block,
parse_param
} type;
parse_file: 正要开始解析一个配置文件.
状态:配置文件已经打开,文件将要被解析.用于新打开一个配置文件,或者解析过程中遇到include指令时候,也将以这种状态调用ngx_conf_parse函数.
parse_block:正要解析一个复杂配置项的值.
状态:配置文件已经打开,且已经进行了部分解析.
parse_param:即将对命令行参数进行解析.
状态:在命令行中遇到-g参数,即处在这种状态.
好了具体函数一看就会明白
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
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);
}
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) {
type = parse_block;
} else {
type = parse_param;
}
for ( ;; ) {
rc = ngx_conf_read_token(cf);
/*
* ngx_conf_read_token() may return
*
* NGX_ERROR there iserror
* NGX_OK the tokenterminated by ";" was found
* NGX_CONF_BLOCK_START the tokenterminated by "{" was found
* NGX_CONF_BLOCK_DONE the"}" was found
* NGX_CONF_FILE_DONE theconfiguration 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,
"blockdirectives are not supported "
"in -goption");
goto failed;
}
}
/* rc == NGX_OK || rc ==NGX_CONF_BLOCK_START */
if (cf->handler) {
/*
* the custom handler, i.e., thatis 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);
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;
}