定义在 src\core\ngx_conf_file.c
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;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 ? */if (!(cmd->type & NGX_CONF_ANY)) {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;if (cmd->type & NGX_DIRECT_CONF) {conf = ((void **) cf->ctx)[cf->cycle->modules[i]->index];} else if (cmd->type & NGX_MAIN_CONF) {conf = &(((void **) cf->ctx)[cf->cycle->modules[i]->index]);} else if (cf->ctx) {confp = *(void **) ((char *) cf->ctx + cmd->conf);if (confp) {conf = confp[cf->cycle->modules[i]->ctx_index];}}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;
}
ngx_conf_handler
是 Nginx 配置解析的核心函数,其主要作用是根据当前解析到的配置指令,找到对应的模块命令并执行相关校验和设置
name = cf->args->elts;found = 0;
name = cf->args->elts;
将当前配置指令的参数列表(数组)的起始地址赋值给 name 指针,以便后续遍历和匹配指令名。found = 0;
初始化标志变量 found 为 0,表示尚未找到与当前配置指令匹配的模块命令。found 是一个布尔标记,用于记录是否在模块的指令列表中成功匹配到当前指令名。
初始值为 0(未找到),在后续遍历模块的 commands 数组时,若匹配到指令名,则置为 1
此时
name->data=worker_processes
worker_processes 用于定义 Nginx 工作进程(Worker Processes)的数量
- 每个
worker_process
是一个独立的进程,负责处理客户端请求。- 多进程设计 :通过启用多个工作进程,Nginx 可以充分利用多核 CPU 的性能,实现高并发处理。
- 默认值 :
1
(但通常建议根据服务器 CPU 核心数调整)。
for (i = 0; cf->cycle->modules[i]; i++) {cmd = cf->cycle->modules[i]->commands;if (cmd == NULL) {continue;}
遍历 Nginx 所有已加载的模块,检查每个模块是否包含需要处理的配置指令。
获取模块的指令列表:cmd = cf->cycle->modules[i]->commands;
获取当前模块支持的配置指令列表(commands 数组),用于后续匹配当前解析的指令。commands 是 ngx_module_t 结构体的成员,指向一个 ngx_command_t 数组,表示该模块支持的配置指令。
cmd 是 ngx_command_t* 类型指针,指向当前模块的指令列表。
后续内层循环会遍历 cmd 数组,匹配当前配置指令名。跳过无指令的模块:if (cmd == NULL) { continue; }
如果当前模块没有定义任何配置指令(commands 为 NULL),则跳过该模块,继续检查下一个模块。
某些模块可能不处理配置指令(例如仅提供功能的模块),其 commands 字段会被设为 NULL。意图
遍历所有模块
通过外层循环,确保每个模块都有机会检查是否支持当前解析的配置指令。筛选有效模块
仅处理包含配置指令(commands 非空)的模块,忽略无指令的模块。为内层循环做准备
每个模块的 commands 数组将在内层循环中被遍历,逐个匹配指令名
for ( /* void */ ; cmd->name.len; cmd++) {
遍历当前模块的指令列表(
commands
数组),逐个匹配当前解析的配置指令名。
cmd->name.len
为 0 时,表示已遍历到指令列表的末尾(每个模块的commands
数组以cmd->name.len = 0
的哨兵元素结束)。
if (name->len != cmd->name.len) {continue;}
如果长度不同,说明指令名一定不匹配,直接跳过当前
cmd
if (ngx_strcmp(name->data, cmd->name.data) != 0) {continue;}
比较当前配置指令名与模块定义的指令名是否完全一致。
返回值为 0 表示字符串内容完全相同,说明找到匹配的指令。
若名称不匹配,跳过当前指令,继续检查下一个
cmd
ngx_strcmp
ngx_strcmp-CSDN博客
found = 1;
找到了 匹配的指令
此时
cf->cycle->modules[0]->name=ngx_core_module
if (cf->cycle->modules[i]->type != NGX_CONF_MODULE&& cf->cycle->modules[i]->type != cf->module_type){continue;}
如果当前模块类型 既不是通用配置模块,也不匹配当前配置阶段的模块类型(
cf->module_type
),则跳过该指令
此时
cf->cycle->modules[0]->type=0x45524F43
cf->module_type=0x45524F43
NGX_CONF_MODULE=0x464E4F43
0x45524F43 是 NGX_CORE_MODULE
./nginx-1.24.0/src/core/ngx_conf_file.h:70:#define NGX_CORE_MODULE 0x45524F43 /* "CORE" */
条件不成立
/* is the directive's location right ? */if (!(cmd->type & cf->cmd_type)) {continue;}
验证 配置指令出现的位置
cmd->type 表示该指令预期可以出现的位置
cf->cmd_type 表示当前配置文件中的位置
此时
cmd->type =0x1010002
cf->cmd_type=0x1000000 (NGX_MAIN_CONF)./nginx-1.24.0/src/core/ngx_conf_file.h:51:#define NGX_MAIN_CONF 0x01000000
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;}
检查非块指令是否以分号结尾
cmd->type & NGX_CONF_BLOCK
NGX_CONF_BLOCK
是块指令标志,若未设置,说明当前指令是非块指令。last != NGX_OK
last
参数表示解析器的状态:
NGX_OK
:正常结束(指令以分号;
结尾)。
#define NGX_CONF_BLOCK 0x00000100
此时
last=0 (
NGX_OK
)
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;}
若指令是块类型,但未以
{
开始(last
非NGX_CONF_BLOCK_START
),则触发错误:
#define NGX_CONF_BLOCK_START 1
当前指令不是块类型
/* is the directive's argument count right ? */if (!(cmd->type & NGX_CONF_ANY)) {
检查指令的参数数量
NGX_CONF_ANY
表示指令允许任意数量参数不是 允许任意数量参数
进入进一步的检查
此时条件成立
cf->args->nelts=2
if (cmd->type & NGX_CONF_FLAG) {if (cf->args->nelts != 2) {goto invalid;}}
NGX_CONF_FLAG
表示指令需要一个布尔值参数。- 布尔指令的完整格式为
指令名 参数
,参数数量必须为 2(例如rewrite_log on;)
此时条件不成立
else if (cmd->type & NGX_CONF_1MORE) {if (cf->args->nelts < 2) {goto invalid;}}
NGX_CONF_1MORE
表示指令需要至少 1 个参数
此时条件不成立
} else if (cmd->type & NGX_CONF_2MORE) {if (cf->args->nelts < 3) {goto invalid;}}
NGX_CONF_2MORE
表示指令需要至少 2 个参数
此时条件不成立
} else if (cf->args->nelts > NGX_CONF_MAX_ARGS) {goto invalid;}
检查参数总数是否超过允许的最大值
此时条件不成立
} else if (!(cmd->type & argument_number[cf->args->nelts - 1])){goto invalid;}
精确匹配参数数量(当前指令的参数数量是固定的而不是 至少一个这种不固定的)
argument_number
是一个预定义的数组,将参数数量映射到对应的标志位。例如static ngx_uint_t argument_number[] = {NGX_CONF_NOARGS, // 0 参数(仅指令名)NGX_CONF_TAKE1, // 1 参数NGX_CONF_TAKE2, // 2 参数// ... 其他 };
cf->args->nelts - 1
将参数总数转换为实际参数数量(减去指令名)
此时条件不成立
通过了参数数量的校验
/* set up the directive's configuration context */conf = NULL;if (cmd->type & NGX_DIRECT_CONF) {conf = ((void **) cf->ctx)[cf->cycle->modules[i]->index];
为指令(
cmd
)设置配置上下文(conf
),并调用指令的set
方法将配置值写入上下文。
根据指令类型选择不同的配置存储位置,最终处理set
方法的返回值。
NGX_DIRECT_CONF
是一种指令类型,用于定义必须直接出现在配置文件顶层(全局作用域)的指令,而不是嵌套在http
、server
、location
等子配置块中
NGX_DIRECT_CONF
指令的配置结构指针直接存储在模块的配置数组中
此时 条件成立
cf->cycle->modules[0]->index=0
rv = cmd->set(cf, cmd, conf);
调用指令的
set
方法,解析指令,然后设置其所在配置结构的对应字段
当前指令是 worker_processes
worker_processes 指令的 set 函数
worker_processes 指令的 set 函数-CSDN博客
if (rv == NGX_CONF_OK) {return NGX_OK;}
返回 NGX_OK ,代表 指令处理成功