ngx_http_core_location
定义在 src\http\ngx_http_core_module.c
static char *
ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
{char *rv;u_char *mod;size_t len;ngx_str_t *value, *name;ngx_uint_t i;ngx_conf_t save;ngx_http_module_t *module;ngx_http_conf_ctx_t *ctx, *pctx;ngx_http_core_loc_conf_t *clcf, *pclcf;ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));if (ctx == NULL) {return NGX_CONF_ERROR;}pctx = cf->ctx;ctx->main_conf = pctx->main_conf;ctx->srv_conf = pctx->srv_conf;ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);if (ctx->loc_conf == NULL) {return NGX_CONF_ERROR;}for (i = 0; cf->cycle->modules[i]; i++) {if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {continue;}module = cf->cycle->modules[i]->ctx;if (module->create_loc_conf) {ctx->loc_conf[cf->cycle->modules[i]->ctx_index] =module->create_loc_conf(cf);if (ctx->loc_conf[cf->cycle->modules[i]->ctx_index] == NULL) {return NGX_CONF_ERROR;}}}clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];clcf->loc_conf = ctx->loc_conf;value = cf->args->elts;if (cf->args->nelts == 3) {len = value[1].len;mod = value[1].data;name = &value[2];if (len == 1 && mod[0] == '=') {clcf->name = *name;clcf->exact_match = 1;} else if (len == 2 && mod[0] == '^' && mod[1] == '~') {clcf->name = *name;clcf->noregex = 1;} else if (len == 1 && mod[0] == '~') {if (ngx_http_core_regex_location(cf, clcf, name, 0) != NGX_OK) {return NGX_CONF_ERROR;}} else if (len == 2 && mod[0] == '~' && mod[1] == '*') {if (ngx_http_core_regex_location(cf, clcf, name, 1) != NGX_OK) {return NGX_CONF_ERROR;}} else {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"invalid location modifier \"%V\"", &value[1]);return NGX_CONF_ERROR;}} else {name = &value[1];if (name->data[0] == '=') {clcf->name.len = name->len - 1;clcf->name.data = name->data + 1;clcf->exact_match = 1;} else if (name->data[0] == '^' && name->data[1] == '~') {clcf->name.len = name->len - 2;clcf->name.data = name->data + 2;clcf->noregex = 1;} else if (name->data[0] == '~') {name->len--;name->data++;if (name->data[0] == '*') {name->len--;name->data++;if (ngx_http_core_regex_location(cf, clcf, name, 1) != NGX_OK) {return NGX_CONF_ERROR;}} else {if (ngx_http_core_regex_location(cf, clcf, name, 0) != NGX_OK) {return NGX_CONF_ERROR;}}} else {clcf->name = *name;if (name->data[0] == '@') {clcf->named = 1;}}}pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];if (cf->cmd_type == NGX_HTTP_LOC_CONF) {/* nested location */#if 0clcf->prev_location = pclcf;
#endifif (pclcf->exact_match) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"location \"%V\" cannot be inside ""the exact location \"%V\"",&clcf->name, &pclcf->name);return NGX_CONF_ERROR;}if (pclcf->named) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"location \"%V\" cannot be inside ""the named location \"%V\"",&clcf->name, &pclcf->name);return NGX_CONF_ERROR;}if (clcf->named) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"named location \"%V\" can be ""on the server level only",&clcf->name);return NGX_CONF_ERROR;}len = pclcf->name.len;#if (NGX_PCRE)if (clcf->regex == NULL&& ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0)
#elseif (ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0)
#endif{ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"location \"%V\" is outside location \"%V\"",&clcf->name, &pclcf->name);return NGX_CONF_ERROR;}}if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {return NGX_CONF_ERROR;}save = *cf;cf->ctx = ctx;cf->cmd_type = NGX_HTTP_LOC_CONF;rv = ngx_conf_parse(cf, NULL);*cf = save;return rv;
}
该函数是 Nginx 解析
location
配置块的核心实现,负责:
- 解析
location
语法 :支持精确匹配(=
)、前缀匹配(^~
)、正则表达式(~
和~*
)及命名 location(@
)。- 创建配置上下文 :为当前
location
块初始化模块配置结构体。- 管理嵌套规则 :确保
location
块的嵌套符合 Nginx 语法限制(如禁止在精确匹配或命名 location 内嵌套)。- 注册 location 到父级配置 :将解析后的
location
添加到所属父级(server 或上层 location)的配置中。
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));if (ctx == NULL) {return NGX_CONF_ERROR;}
为
location
块创建独立的配置上下文 ,用于存储该作用域内的模块配置数据ngx_http_conf_ctx_t -CSDN博客
pctx = cf->ctx;ctx->main_conf = pctx->main_conf;ctx->srv_conf = pctx->srv_conf;
继承父级配置上下文 ,确保
location
块可以复用父级(http
或server
块)的全局配置,同时允许独立覆盖或扩展自己的loc_conf
。
main_conf
:所有location
共享同一份http
配置。srv_conf
:同一server
下的所有location
共享server
配置。loc_conf
:每个location
独立,用于覆盖或扩展配置。
ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);if (ctx->loc_conf == NULL) {return NGX_CONF_ERROR;}
为
location
块的模块配置分配存储空间 ,确保每个 HTTP 模块可以在当前作用域(location
)中存储自己的配置数据
for (i = 0; cf->cycle->modules[i]; i++) {if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {continue;}module = cf->cycle->modules[i]->ctx;if (module->create_loc_conf) {ctx->loc_conf[cf->cycle->modules[i]->ctx_index] =module->create_loc_conf(cf);if (ctx->loc_conf[cf->cycle->modules[i]->ctx_index] == NULL) {return NGX_CONF_ERROR;}}}
为每个 HTTP 模块初始化
location
级别的配置结构体
clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];clcf->loc_conf = ctx->loc_conf;
将当前
location
的配置上下文(loc_conf
数组)关联到核心模块的配置结构体中 ,使得核心模块能够访问所有模块的配置数据,协调请求处理流程ngx_http_core_loc_conf_t-CSDN博客
value = cf->args->elts;
获取指令的参数列表
if (cf->args->nelts == 3) {
参数数量检查
cf->args->nelts
:
表示当前配置指令(如location
)的参数数量。
nelts == 3
:用户使用了显式修饰符(如location = /exact
)。nelts == 2
:用户未显式指定修饰符此时 cf->args->nelts=2
条件不成立
进入 else
else {name = &value[1];
获取 location 指令的第一个参数
此时 name->data=/
if (name->data[0] == '=') {
此时条件不成立
} else if (name->data[0] == '^' && name->data[1] == '~') {
此时 条件不成立
} else if (name->data[0] == '~') {
此时 条件不成立
} else {clcf->name = *name;if (name->data[0] == '@') {clcf->named = 1;}}
name
是location
指令的路径参数(如value[1]
,即用户配置中的第二个参数)。将路径字符串赋值给核心模块配置结构体的
name
字段此时 这里的 if 条件不成立
pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
获取父级
location
的核心模块配置 ,用于校验嵌套规则或继承配置通过索引从父级的
loc_conf
数组中获取核心模块的配置结构体指向父级
location
的核心模块配置结构体
if (cf->cmd_type == NGX_HTTP_LOC_CONF) {
判断当前是否处于
location
块的配置解析阶段此时 cf->cmd_type=4000000 NGX_HTTP_LOC_CONF=8000000
条件不成立,当前还未进入
location
块内部配置解析的阶段
if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {return NGX_CONF_ERROR;}
将新解析的
location
配置添加到父级(server
或上层location
)的链表中 ,确保请求处理时能够遍历所有location
进行匹配。
ngx_http_add_location
函数 :
- 功能 :将当前
location
(clcf
)添加到父级的locations
链表(pclcf->locations
)。- 参数 :
cf
:配置解析上下文。&pclcf->locations
:父级的locations
链表指针。clcf
:当前location
的核心模块配置结构体。
locations
链表 :
存储所有location
配置
ngx_http_add_location-CSDN博客
save = *cf;cf->ctx = ctx;cf->cmd_type = NGX_HTTP_LOC_CONF;rv = ngx_conf_parse(cf, NULL);*cf = save;
save = *cf;
- 保存当前配置解析上下文。
- 逻辑 :
cf
是指向当前配置解析上下文(ngx_conf_t
结构)的指针。save
是一个局部变量,类型为ngx_conf_t
。- 通过
*cf
解引用操作,将当前配置解析状态(包括上下文指针、命令类型等)完整复制到save
中。- 意义 :
- 在后续解析 location 块时,会临时修改
cf
的上下文。此操作保存原始状态,以便解析完成后恢复。
cf->ctx = ctx;
- 作用 :切换配置上下文到当前 location 的上下文。
- 逻辑 :
ctx
是新创建的ngx_http_conf_ctx_t
结构,专用于当前 location 块。cf->ctx
是配置解析的核心上下文指针,指向当前生效的配置存储结构。- 将
cf->ctx
指向新的ctx
,使得后续解析的指令会将配置存储到该 location 的上下文中。
cf->cmd_type = NGX_HTTP_LOC_CONF;
- 作用 :设置当前解析的指令类型为 "HTTP Location 配置"。
- 逻辑 :
cmd_type
是ngx_conf_t
中的字段,用于标识当前解析的指令类型。NGX_HTTP_LOC_CONF
表示接下来解析的指令属于 location 块。- 意义 :
- 指令过滤 :Nginx 根据
cmd_type
调用对应模块的指令处理函数。例如,只有声明为NGX_HTTP_LOC_CONF
类型的指令会被处理,其他指令(如 server 级指令)会触发错误。
rv = ngx_conf_parse(cf, NULL);
- 作用 :解析 location 块内的配置指令。
- 逻辑 :
ngx_conf_parse
是 Nginx 的核心配置解析函数。- 传入
cf
(已切换到 location 上下文)和NULL
(表示继续解析当前配置流,而非新文件)。- 返回值
rv
表示解析结果(成功或错误码)。- 意义 :
- 递归解析 :处理 location 块内的所有指令
ngx_conf_parse - location块-CSDN博客
*cf = save;
- 作用 :恢复原始配置解析上下文。
- 逻辑 :
- 将之前保存的
save
值复制回cf
,覆盖当前修改后的cf
状态。- 恢复字段包括
ctx
(父级上下文)和cmd_type
(如 server 级指令类型)。- 意义 :
- 上下文回退 :确保解析完当前 location 后,父级配置解析(如 server 块)能继续正确执行。
- 避免污染 :防止 location 的临时配置影响后续指令的解析。
整体逻辑总结
- 保存现场 :备份父级配置上下文。
- 切换上下文 :为 location 块创建独立的配置存储空间。
- 标记指令类型 :确保仅处理 location 级指令。
- 解析子配置 :处理 location 内的所有指令。
- 恢复现场 :回到父级配置解析流程。
return rv;
返回 NGX_CONF_OK