1. ngx_command_t

为了统一配置项目的解析,Nginx 定义了如下数据类型对所有的 Nginx 配置项进行了统一的描述。

typedef struct ngx_command_s         ngx_command_t;

struct ngx_command_s {
/*
* 该配置指令的名称,如 daemon, worker_processes 等
*/
ngx_str_t name;
/*
* 该配置项的类型,指定配置项可以出现的位置。如,出现在 server{}
* 或 location{} 中,以及它可以携带的参数个数
*/
ngx_uint_t type;
/*
* 当 Nginx 在解析配置的时候,如果遇到这个配置指令,将会把读取到的值
* 传递给这个函数进行处理.
* @cf: 保存从配置文件读取到原始字符串以及相关的一些信息。这个参数的
* args 字段是一个 ngx_array_t 类型的数组,该数组的首个元素是这个
* 配置指令本身,第二个元素是指令的第一个参数,第三个元素是第二个
* 参数,以此类推.
* @cmd: 这个配置指令对应的 ngx_command_t 结构
* @conf: 就是定义的存储这个配置值的结构体,即该配置指令所在模块的配置信息
* 结构体.
*/
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
/*
* 该字段主要被 HTTP/RTMP 系列模块所用,该字段指定当前配置项存储的内存
* 位置。实际上是使用哪个内存池的问题。因为 http/rtmp 模块对所有 http 模块
* 都要保存的配置信息,划分了 main,server,location 三个地方进行存储,
* 每个地方都有一个内存池用来分配存储这些信息的内存。这里可能的值有
* NGX_HTTP_MAIN_CONF_OFFSET(直接为 0 表示该项)、NGX_HTTP_SRV_CONF_OFFSET 以及
* NGX_HTTP_LOC_CONF_OFFSET
*/
ngx_uint_t conf;
/*
* 指定该配置项值的精确存放位置,一般指定为某个结构体变量的字段偏移。因为对于
* 配置信息的存储,一般我们都是定义一个结构体来存储。比如定义了结构体 A,该项
* 配置的值需要存储到该结构体的 b 字段,那么这里可以填写 offsetof(A, b)。
* 对于有些配置项,若它的值不需要保存或者是需要保存到更为复杂的结构中时,直接
* 设为 0.
*/
ngx_uint_t offset;
/*
* 该字段存储一个指针,可以指向任何一个在读取配置项过程需要的数据,以便于进行
* 配置读取的处理。大多数时候,都不需要该值,直接设为 0 即可.
*/
void *post;
};

2. ngx_conf_t

typedef struct ngx_conf_s            ngx_conf_t;

struct ngx_conf_s {
char *name;
/*
* 用于存放该配置项的元素字符串,它是一个数组,假设当前配置项为"daemon off;"
* 则 args[0] 指向 "daemon",args[1] 指向 "off".
*/
ngx_array_t *args; /*
* 指向当前的核心结构体 ngx_cycle_t
*/
ngx_cycle_t *cycle;
/*
* 指向核心结构体所用的内存池
*/
ngx_pool_t *pool;
ngx_pool_t *temp_pool;
/* 保存的是配置文件的信息 */
ngx_conf_file_t *conf_file;
ngx_log_t *log; void *ctx;
/*
* 当前解析配置项所在的模块的类型
*/
ngx_uint_t module_type;
ngx_uint_t cmd_type; ngx_conf_handler_pt handler;
char *handler_conf;
};

ngx_open_file_s

struct ngx_open_file_s {
ngx_fd_t fd;
ngx_str_t name; void (*flush)(ngx_open_file_t *file, ngx_log_t *log);
void *data;
};

ngx_conf_file_t

typedef struct ngx_file_s            ngx_file_t;

struct ngx_file_s {
/*
* 打开的文件描述符
*/
ngx_fd_t fd;
/*
* 保存该文件的绝对路径
*/
ngx_str_t name;
/*
* ngx_file_info_t 即 struct stat 结构体类型
*/
ngx_file_info_t info; off_t offset;
off_t sys_offset; ngx_log_t *log; #if (NGX_THREADS || NGX_COMPAT)
ngx_int_t (*thread_handler)(ngx_thread_task_t *task,
ngx_file_t *file);
void *thread_ctx;
ngx_thread_task_t *thread_task;
#endif #if (NGX_HAVE_FILE_AIO || NGX_COMPAT)
ngx_event_aio_t *aio;
#endif unsigned valid_info:1;
unsigned directio:1;
}; typedef struct ngx_buf_s ngx_buf_t; struct ngx_buf_s {
/*
* pos通常是用来告诉使用者本次应该从pos这个位置开始处理内存中的数据,
* 这样设置是因为同一个ngx_buf_t可能被多次反复处理。当然,pos的含义
* 是由使用它的模块定义的
*/
u_char *pos;
/*
* last通常表示有效的内容到此为止,注意,pos与last之间的内存是希望nginx
* 处理的内容
*/
u_char *last;
/*
* 处理文件时,file_pos与file_last的含义与处理内存时的pos与last相同,
* file_pos表示将要处理的文件位置,file_last表示截止的文件位置
*/
off_t file_pos;
off_t file_last; /*
* 如果ngx_buf_t缓冲区用于内存,那么start指向这段内存的起始地址
*/
u_char *start; /* start of buffer */
/*
* 与start成员对应,指向缓冲区内存的末尾
*/
u_char *end; /* end of buffer */
/*
* 表示当前缓冲区的类型,例如由哪个模块使用就指向这个模块
* ngx_module_t 变量的地址
*/
ngx_buf_tag_t tag;
/*
* 引用的文件
*/
ngx_file_t *file;
/*
* 当前缓冲区的影子缓冲区,该成员很少用到
*/
ngx_buf_t *shadow; /*
* 临时内存标志位,为1时表示数据在内存中且这段数据可以修改
*/
/* the buf's content could be changed */
unsigned temporary:1; /*
* the buf's content is in a memory cache or in a read only memory
* and must not be changed
*/
unsigned memory:1; /* the buf's content is mmap()ed and must not be changed */
unsigned mmap:1; /*
* 标志位,为1时表示可回收
*/
unsigned recycled:1;
/*
* 标志位,为1时表示这段缓冲区处理的是文件而不是内存
*/
unsigned in_file:1;
/*
* 标志位,为1时表示需要执行flush操作
*/
unsigned flush:1;
/*
* 标志位,对于操作这块缓冲区时是否使用同步方式,需谨慎考虑,这可能会阻塞Nginx进程,
* Nginx中所有操作几乎都是异步的,这是它支持高并发的关键。有些框架代码在sync为1时
* 可能会用阻塞的方式进行I/O操作,它的意义视使用它的Nginx模块而定
*/
unsigned sync:1;
/*
* 标志位,表示是否是最后一块缓冲区,因为ngx_buf_t可以由ngx_chain_t链表串联起来,
* 因此,当last_buf为1时,表示当前是最后一块待处理的缓冲区
*/
unsigned last_buf:1;
/*
* 标志位,表示是否是ngx_chain_t中的最后一块缓冲区
*/
unsigned last_in_chain:1; /*
* 标志位,表示是否是最后一个影子缓冲区,与shadow域配合使用。通常不建议使用它
*/
unsigned last_shadow:1;
/*
* 标志位,表示当前缓冲区是否属于临时文件
*/
unsigned temp_file:1; /* STUB */ int num;
}; typedef struct {
/*
* 保存配置文件的信息
*/
ngx_file_t file;
/*
* 储存从配置文件中读取到的数据
*/
ngx_buf_t *buffer;
ngx_buf_t *dump;
/*
* 记录当前正在解析的行号
*/
ngx_uint_t line;
} ngx_conf_file_t;

ngx_conf_dump_t

typedef struct {
ngx_str_t name;
ngx_buf_t *buffer;
} ngx_conf_dump_t;

3. ngx_conf_parse

该函数是开始解析配置文件的入口函数。

/*
* 该函数是一个间接递归函数,就是虽然在该函数体内看不到直接对其本身的调用,
* 但是它执行的一些其他函数(如ngx_conf_handler())内会有调用到ngx_conf_parse()
* 函数,从而形成递归。这一般在处理复杂配置项和一些特殊配置指令时发生.
*
* 该函数总体分为三个步骤:
* 1. 判断当前解析状态
* 2. 读取配置标记 token
* 3. 当读取了合适数量的标记 token 后对其进行实际的处理,也就是将配置值转换为
* Nginx 内对应控制变量的值.
*
* 当进入到 ngx_conf_parse() 函数时,首先做的第一步就是判断当前解析过程处在一个
* 什么样的状态,这有三种可能:
* 1. 正要开始解析一个配置文件: 此时的参数filename指向一个配置文件路径字符串,
* 需要函数ngx_conf_parse() 打开该文件并获取相关的文件信息(比如文件描述符等)
* 以便下面代码读取文件内容并进行解析。此外还有一种属于此种情况,就是当遇到
* include 指令时也将以这种状态调用 ngx_conf_parse() 函数,因为 include 指令
* 表示一个新的配置文件要开始解析。状态标记为type=parse_file;
*
* 2. 正要开始解析一个复杂配置项值:此时配置文件已经打开并且也已经对文件进行了
* 部分解析,当遇到复杂配置项比如events、http 等时,这些复杂配置项的处理函数
* 又会递归调用 ngx_conf_parse() 函数,此时解析的内容还是来自当前的配置文件,
* 因此无需再次打开它,状态标记为type=parse_block;
*
* 3. 正要开始解析命令行参数配置项值:在对用户通过命令行 -g 参数输入的配置信息
* 进行解析时处于这种状态,如nginx -g 'daemon on;',Nginx在调用ngx_conf_parse()
* 函数对命令行参数配置信息'daemon on;'进行解析时就是这种状态,状态标记为
* type=parse_param.
*/
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; /* 该宏即为 fstat,获取配置文件的信息,保存到 file.info 中 */
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;
} /* pos通常是用来告诉使用者本次应该从pos这个位置开始处理内存中的数据,
* 这样设置是因为同一个ngx_buf_t可能被多次反复处理。当然,pos的含义
* 是由使用它的模块定义的 */
buf.pos = buf.start;
/* last通常表示有效的内容到此为止,注意,pos与last之间的内存是希望nginx
* 处理的内容,由于该缓存中还没有数据,因此置为 start */
buf.last = buf.start;
/* 与start成员对应,指向缓冲区内存的末尾 */
buf.end = buf.last + NGX_CONF_BUFFER;
/* 标志位,为 1 表示数据在内存中且这段数据可以被修改 */
buf.temporary = 1; /* 将该配置文件的信息赋值给 cf->conf_file */
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; /* 当首次开始解析配置文件时,类型为 parse_file */
type = parse_file; if (ngx_dump_config
#if (NGX_DEBUG)
|| 1
#endif
)
{
if (ngx_conf_add_dump(cf, filename) != NGX_OK) {
goto failed;
} } else {
cf->conf_file->dump = NULL;
} /* 由开头的分析知,开始解析复杂配置项时,为此类型 */
} else if (cf->conf_file->file.fd != NGX_INVALID_FILE) { type = parse_block; /* 若为解析命令行参数配置项时,为此类型 */
} else {
type = parse_param;
} /* 判断好当前解析状态后就开始读取配置文件内容,配置文件是由一个个token组成的,
* 因此接下来就是循环从配置文件里读取token. */
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_command_t,然后调用该 ngx_comand_t 的 set 回调函数,
* 将读取到的指令参数设置到该模块的配置信息结构体中的相应字段 */
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);
rc = NGX_ERROR;
} cf->conf_file = prev;
} if (rc == NGX_ERROR) {
return NGX_CONF_ERROR;
} return NGX_CONF_OK;
}

3.1 ngx_conf_read_token

static ngx_int_t
ngx_conf_read_token(ngx_conf_t *cf)
{
u_char *start, ch, *src, *dst;
off_t file_size;
size_t len;
ssize_t n, size;
ngx_uint_t found, need_space, last_space, sharp_comment, variable;
ngx_uint_t quoted, s_quoted, d_quoted, start_line;
ngx_str_t *word;
ngx_buf_t *b, *dump; found = 0;
need_space = 0;
last_space = 1;
/* 注释标志位 */
sharp_comment = 0;
variable = 0;
/* 单/双引号标志位 */
quoted = 0;
/* 单引号标志位 */
s_quoted = 0;
/* 双引号标志位 */
d_quoted = 0; cf->args->nelts = 0;
b = cf->conf_file->buffer;
dump = cf->conf_file->dump;
/* 指向当前开始解析的位置 */
start = b->pos;
/* 当前解析的行 */
start_line = cf->conf_file->line; /* 配置文件的大小 */
file_size = ngx_file_size(&cf->conf_file->file.info); for ( ;; ) { /* 当 pos 大于等于 last 时,表示当前缓存中没有待解析的有效数据
* 需要从配置文件中读取新的数据 */
if (b->pos >= b->last) { /* 若该配置文件的偏移值已经大于等于文件大小,说明配置文件的数据
* 已经读取完毕 */
if (cf->conf_file->file.offset >= file_size) { if (cf->args->nelts > 0 || !last_space) { if (cf->conf_file->file.fd == NGX_INVALID_FILE) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"unexpected end of parameter, "
"expecting \";\"");
return NGX_ERROR;
} ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"unexpected end of file, "
"expecting \";\" or \"}\"");
return NGX_ERROR;
} /* 配置文件数据读取完毕,且没有出现错误,则返回该标志 */
return NGX_CONF_FILE_DONE;
} /* 若文件还没有读取完毕,则计算当前buf缓存中已经解析过的数据大小 */
len = b->pos - start; if (len == NGX_CONF_BUFFER) {
cf->conf_file->line = start_line; if (d_quoted) {
ch = '"'; } else if (s_quoted) {
ch = '\''; } else {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"too long parameter \"%*s...\" started",
10, start);
return NGX_ERROR;
} ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"too long parameter, probably "
"missing terminating \"%c\" character", ch);
return NGX_ERROR;
} if (len) {
ngx_memmove(b->start, start, len);
} /* 计算当前配置文件剩余待解析的数据大小 */
size = (ssize_t) (file_size - cf->conf_file->file.offset); if (size > b->end - (b->start + len)) {
size = b->end - (b->start + len);
} /* 从配置文件中读取 size 字节到 b->start + len 指向的缓存处,
* file.offset 保存此次从配置文件中读取的字节数,返回值 n 为
* 读取到的字节数 */
n = ngx_read_file(&cf->conf_file->file, b->start + len, size,
cf->conf_file->file.offset); if (n == NGX_ERROR) {
return NGX_ERROR;
} /* 若实际读取到的字节数 n 与指定要求读取的字节数不相等,则
* 表明发生错误了 */
if (n != size) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
ngx_read_file_n " returned "
"only %z bytes instead of %z",
n, size);
return NGX_ERROR;
} /* pos 指向当前待解析的有效内容的起始处 */
b->pos = b->start + len;
/* last 指向当前待解析的有效内容的末尾 */
b->last = b->pos + n;
start = b->start; if (dump) {
dump->last = ngx_cpymem(dump->last, b->pos, size);
}
} /* 取出一个字符 */
ch = *b->pos++; /* 若当前字符为换行符 '\n' */
if (ch == LF) {
/* 行计数器加 1 */
cf->conf_file->line++; /* 若该标志位为 1,表示当前行为注释 */
if (sharp_comment) {
/* 重置该标志位为 0 */
sharp_comment = 0;
}
} /* 若当前行为注释,则回到循环开始,重新开始读取数据 */
if (sharp_comment) {
continue;
} if (quoted) {
quoted = 0;
continue;
} if (need_space) {
if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
last_space = 1;
need_space = 0;
continue;
} if (ch == ';') {
return NGX_OK;
} if (ch == '{') {
return NGX_CONF_BLOCK_START;
} if (ch == ')') {
last_space = 1;
need_space = 0; } else {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"unexpected \"%c\"", ch);
return NGX_ERROR;
}
} if (last_space) {
/* 若当前字符为以下这些字符,则回到循环开始继续取下一个字符 */
if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
continue;
} /* 若当前读取到的是注释,下面这两个变量可忽略 */
/* 记录当前读取指令的起始位置 */
start = b->pos - 1;
/* 记录当前读取指令的起始行 */
start_line = cf->conf_file->line; switch (ch) { case ';':
case '{':
if (cf->args->nelts == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"unexpected \"%c\"", ch);
return NGX_ERROR;
} if (ch == '{') {
return NGX_CONF_BLOCK_START;
} return NGX_OK; /* 为该字符,表明当前的复杂配置项的内容已经读取完毕 */
case '}':
if (cf->args->nelts != 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"unexpected \"}\"");
return NGX_ERROR;
} return NGX_CONF_BLOCK_DONE; case '#':
/* 若当前字符为 '#',表示遇到注释了,因此回到循环开始
* 继续去下一个字符 */
sharp_comment = 1;
continue; case '\\':
quoted = 1;
last_space = 0;
continue; case '"':
start++;
d_quoted = 1;
last_space = 0;
continue; case '\'':
start++;
s_quoted = 1;
last_space = 0;
continue; default:
last_space = 0;
} } else {
if (ch == '{' && variable) {
continue;
} variable = 0; if (ch == '\\') {
quoted = 1;
continue;
} if (ch == '$') {
variable = 1;
continue;
} if (d_quoted) {
if (ch == '"') {
d_quoted = 0;
need_space = 1;
found = 1;
} } else if (s_quoted) {
if (ch == '\'') {
s_quoted = 0;
need_space = 1;
found = 1;
} } else if (ch == ' ' || ch == '\t' || ch == CR || ch == LF
|| ch == ';' || ch == '{')
{
last_space = 1;
found = 1;
} /* found 为 1 表明读取到完整的一个字符串,该指令的名称/参数 */
if (found) {
word = ngx_array_push(cf->args);
if (word == NULL) {
return NGX_ERROR;
} word->data = ngx_pnalloc(cf->pool, b->pos - 1 - start + 1);
if (word->data == NULL) {
return NGX_ERROR;
} for (dst = word->data, src = start, len = 0;
src < b->pos - 1;
len++)
{
if (*src == '\\') {
switch (src[1]) {
case '"':
case '\'':
case '\\':
src++;
break; case 't':
*dst++ = '\t';
src += 2;
continue; case 'r':
*dst++ = '\r';
src += 2;
continue; case 'n':
*dst++ = '\n';
src += 2;
continue;
} }
*dst++ = *src++;
}
*dst = '\0';
word->len = len; /* 若当前字符为 ';',表明一个指令已经读取完毕 */
if (ch == ';') {
return NGX_OK;
} /* 若当前字符为 '{',则表明将要开始解析复杂配置项 */
if (ch == '{') {
return NGX_CONF_BLOCK_START;
} found = 0;
}
}
}
}

3.2 ngx_conf_handler

/*
* Nginx的每一个配置指令都对应一个ngx_command_s数据类型变量,记录着该配置指令的解析回调函数、
* 转换值存储位置等,而每一个模块又都把自身所相关的所有指令以数组的形式组织起来,所以函数
* ngx_conf_handler()首先做的就是查找当前指令所对应的ngx_command_s变量,这通过循环遍历各个
* 模块的指令数组即可。
*/
static ngx_int_t
ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
{
char *rv;
void *conf, **confp;
ngx_uint_t i, found;
ngx_str_t *name;
ngx_command_t *cmd; /* 此时 cf->elts 数组保存的是从配置文件中读取到的一行指令 */
name = cf->args->elts; found = 0; /* 遍历所有模块 */
for (i = 0; cf->cycle->modules[i]; i++) { /* 获取该模块保存的所有配置指令的数组 */
cmd = cf->cycle->modules[i]->commands;
if (cmd == NULL) {
continue;
} for ( /* void */ ; cmd->name.len; cmd++) { /* 若指令的名称长度不等,下一个 */
if (name->len != cmd->name.len) {
continue;
} /* 若内容不相等,则继续下一个 */
if (ngx_strcmp(name->data, cmd->name.data) != 0) {
continue;
} /* 若上面检测到指令的长度和名称都相等,则表示找到 */
found = 1; if (cf->cycle->modules[i]->type != NGX_CONF_MODULE
&& cf->cycle->modules[i]->type != cf->module_type)
{
continue;
} /* is the directive's location right ? */ /* */
if (!(cmd->type & cf->cmd_type)) {
continue;
} if (!(cmd->type & NGX_CONF_BLOCK) && last != NGX_OK) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"directive \"%s\" is not terminated by \";\"",
name->data);
return NGX_ERROR;
} if ((cmd->type & NGX_CONF_BLOCK) && last != NGX_CONF_BLOCK_START)
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"directive \"%s\" has no opening \"{\"",
name->data);
return NGX_ERROR;
} /* is the directive's argument count right ? */ /* NGX_CONF_ANY:该配置指令可以出现在任意配置级别上 */
if (!(cmd->type & NGX_CONF_ANY)) { /* 配置指令可以接受的是"on"或者"off",最终会被转成bool值 */
if (cmd->type & NGX_CONF_FLAG) { if (cf->args->nelts != 2) {
goto invalid;
} /* 配置指令接受至少一个参数 */
} else if (cmd->type & NGX_CONF_1MORE) { if (cf->args->nelts < 2) {
goto invalid;
} /* 配置指令接受至少两个参数 */
} else if (cmd->type & NGX_CONF_2MORE) { if (cf->args->nelts < 3) {
goto invalid;
} } else if (cf->args->nelts > NGX_CONF_MAX_ARGS) { goto invalid; } else if (!(cmd->type & argument_number[cf->args->nelts - 1]))
{
goto invalid;
}
} /* set up the directive's configuration context */ conf = NULL; /* 可以出现在配置文件的最外层。例如已经提供的配置指令daemon,
* master_process等 */
if (cmd->type & NGX_DIRECT_CONF) { /* 获取该模块对应的配置文件结构体,该配置结构体用于保存
* 该模块感兴趣的配置项值 */
conf = ((void **) cf->ctx)[cf->cycle->modules[i]->index]; /* 配置文件最外层,如http、mail、events、error_log 等 */
} else if (cmd->type & NGX_MAIN_CONF) { /* 获取该模块的总配置信息结构体,对于http模块,当解析到http时,
* 该http核心模块ngx_http_module由于没有实现create_conf方法,
* 因此,当第一次解析到http{}时,这里获取到的conf的具体内容
* 为NULL,需要在解析http{}时才分配 */
conf = &(((void **) cf->ctx)[cf->cycle->modules[i]->index]); /* 对应解析http{}里的内容时 */
} else if (cf->ctx) {
/* 获取该http配置项应存储在http的main、server、locaiton这三块内存池
* 中哪个内存池上 */
confp = *(void **) ((char *) cf->ctx + cmd->conf); if (confp) { /* 又根据该模块的ctx_index序号获取在该内存池(即指针数组)中
* 指向该类模块对应配置信息结构体的指针 */
conf = confp[cf->cycle->modules[i]->ctx_index];
}
} /* 调用该配置指令对应的回调函数,将读取到到值设置到该配置结构体
* conf 的相应字段 */
rv = cmd->set(cf, cmd, conf); if (rv == NGX_CONF_OK) {
return NGX_OK;
} if (rv == NGX_CONF_ERROR) {
return NGX_ERROR;
} ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"%s\" directive %s", name->data, rv); return NGX_ERROR;
}
} if (found) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"%s\" directive is not allowed here", name->data); return NGX_ERROR;
} ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"unknown directive \"%s\"", name->data); return NGX_ERROR; invalid: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid number of arguments in \"%s\" directive",
name->data); return NGX_ERROR;
}

Nginx之配置文件的解析的更多相关文章

  1. Centos7 nginx的目录结构与nginx主配置文件解析

    一.nginx的目录结构 [root@node nginx_116]# ls client_body_temp  conf  fastcgi_temp  html  logs  proxy_temp ...

  2. Nginx的配置文件(nginx.conf)解析和领读官网

    步骤一:vi nginx.conf配置文件,参考本博文的最下面总结,自行去设置 最后nginx.conf内容为 步骤二:每次修改了nginx.conf配置文件后,都要reload下. index.ht ...

  3. Nginx的配置文件nginx.conf解析

    安装openresty的nginx.conf配置文件 0.ng运行的用户和用户组 1.ng进程数,设置为CPU总核心数 2.ng错误日志 3.进程文件,有时ng启动不了,将进程文件删除即可. 4.单进 ...

  4. 在nginx上用FastCGI解析PHP

    nginx配置文件: Nginx 默认使用  include enable-php.conf;   通过enable-php.conf 来解析PHP,该文件内容如下 location ~ [^/]\. ...

  5. 第四百零二节,Django+Xadmin打造上线标准的在线教育平台—生产环境部署,uwsgi安装和启动,nginx的安装与启动,uwsgi与nginx的配置文件+虚拟主机配置

    第四百零二节,Django+Xadmin打造上线标准的在线教育平台—生产环境部署,uwsgi安装和启动,nginx的安装与启动,uwsgi与nginx的配置文件+虚拟主机配置 软件版本  uwsgi- ...

  6. Nginx核心配置文件常用参数详解

    Nginx核心配置文件常用参数详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 关于Nginx权威文档的话童鞋们可以参考Nginx官方文档介绍:http://nginx.org/ ...

  7. nginx中配置文件的讲解

    一: 1.配置文件的结构 nginx由配置文件中指定的指令控制的模块组成. 指令分为简单指令和块指令. 一个简单的指令由空格分隔的名称和参数组成,并以分号(;)结尾. 块指令具有与简单指令相同的结构, ...

  8. nginx文件类型错误解析漏洞

    漏洞介绍:nginx是一款高性能的web服务器,使用非常广泛,其不仅经常被用作反向代理,也可以非常好的支持PHP的运行.80sec发现 其中存在一个较为严重的安全问题,默认情况下可能导致服务器错误的将 ...

  9. Nginx配置配置文件详解

    文章目录 配置文件 nginx.conf配置文件详解 用于调试.定位问题的配置参数 正常运行必备的配置参数 优化性能的配置参数 事件相关配置 Fastcgi相关配置参数 常需要调整的参数 nginx作 ...

随机推荐

  1. canvas学习之初级运用

    <html> <head> <meta charset=utf-8> <title>绘制简单图形</title> <style typ ...

  2. Javascript简单教程汇总

    什么是函数 一段定义好的代码,并可以反复使用的代码块 函数的作用 提升代码的可复用性,将一段代码进行预定义,需要使用的时候才触发 代码块 形成了一个相对独立的作用域 语法: function  函数名 ...

  3. Phoenix的jdbc封装

    一.Phoenix版本 <dependency> <groupId>org.apache.phoenix</groupId> <artifactId>p ...

  4. Java优化高性能高并发+高并发程序设计视频教程

    转自:https://www.cnblogs.com/ajianku/p/10236573.html 第1章 课程介绍及项目框架搭建1-1 Java高并发商城秒杀优化导学1-2 项目环境搭建(Ecli ...

  5. 如何用Java代码在SAP Marketing Cloud里创建contact数据

    我们可以使用SAP Marketing Cloud提供的Contact create OData API在第三方应用里创建Contact主数据. API地址:/sap/opu/odata/sap/CU ...

  6. 如何在Marketing Cloud里创建extension field扩展字段

    首先在Marketing Cloud里找到创建扩展字段的tile入口,搜索关键字extension: 这会进入Fiori应用"Custom fields",能看到系统里所有创建好的 ...

  7. asp.net mvc5 DataBase First下model校验问题(MetadataType使用)

    最近学习asp.net mvc5,使用   asp.net mvc5+EF6+AutoFac做个小Demo,其中是先设计的数据库表,就直接选择了EF的DataBase First(三种开发模式分别是c ...

  8. redis—django-redis

    自定义连接池 这种方式跟普通py文件操作redis一样,代码如下: views.py import redis from django.shortcuts import render,HttpResp ...

  9. linux基础1_文件类型、拓展名、目录配置

    命令ls -l,显示的第一个属性代表了这个档案的档案类型 [d]:目录 [-]:普通文件 [l]:连接文件 [b]:存储数据以供系统访问的接口设备 [c]:串行接口的端口设备,例如键盘.鼠标 [s]: ...

  10. Hadoop_31_MapReduce参数优化

    1.资源相关参数 (1) mapreduce.map.memory.mb: 一个Map Task可使用的资源上限(单位:MB),默认为1024.如果Map Task实际使用 的资源量超过该值,则会被强 ...