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 0
        clcf->prev_location = pclcf;
#endif

        if (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)
#else
        if (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 配置块的核心实现,负责:

  1. 解析 location 语法 :支持精确匹配(=)、前缀匹配(^~)、正则表达式(~ 和 ~*)及命名 location(@)。
  2. 创建配置上下文 :为当前 location 块初始化模块配置结构体。
  3. 管理嵌套规则 :确保 location 块的嵌套符合 Nginx 语法限制(如禁止在精确匹配或命名 location 内嵌套)。
  4. 注册 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 的临时配置影响后续指令的解析。

整体逻辑总结

  1. 保存现场 :备份父级配置上下文。
  2. 切换上下文 :为 location 块创建独立的配置存储空间。
  3. 标记指令类型 :确保仅处理 location 级指令。
  4. 解析子配置 :处理 location 内的所有指令。
  5. 恢复现场 :回到父级配置解析流程。
复制代码
return rv;

返回 NGX_CONF_OK

相关推荐
2601_965619694 小时前
AI视频制作:财经数据可视化视频怎么做:AI 自动生成图表动画的实操流程
人工智能·nginx·音视频
2601_965619694 小时前
历史解说视频怎么做:青铜器瓷器文物画面自动对齐的完整教程
运维·nginx·音视频
姜鱼问生18 小时前
每次开机手动检查 6 样东西?我写了个 2 秒自检脚本
运维·网络·nginx·docker·容器
xixingzhe22 天前
Nginx 看懂请求耗时瓶颈
服务器·前端·nginx
北风toto2 天前
Windows 下用 OpenSSL 生成 SSL 密钥并配置 Nginx 教程
windows·nginx·ssl
卜锦元2 天前
Docker Compose 部署 Nginx 1.30.6 完整指南
nginx·docker·容器
小小龙学IT2 天前
Nginx 开源 Web 服务器与反向代理深度解
前端·nginx·开源
Coisinier3 天前
docker命令管理镜像及容器
linux·运维·nginx·docker·容器·操作系统
2301_32241428043 天前
基于web的校园失物招领管理系统59695-计算机毕设 原创(免费领源码+部署教程+开发环境)
mysql·nginx·php·apache·thinkphp·phpstudy·wampserver
flytalei3 天前
从YAML到Nginx服务访问:动手理解 Kubernetes Pod、Deployment 与 Service
运维·nginx·kubernetes