ngx_http_core_server_name

发布于:2025-03-24 ⋅ 阅读:(26) ⋅ 点赞:(0)

定义在 src\http\ngx_http_core_module.c

static char *
ngx_http_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_core_srv_conf_t *cscf = conf;

    u_char                   ch;
    ngx_str_t               *value;
    ngx_uint_t               i;
    ngx_http_server_name_t  *sn;

    value = cf->args->elts;

    for (i = 1; i < cf->args->nelts; i++) {

        ch = value[i].data[0];

        if ((ch == '*' && (value[i].len < 3 || value[i].data[1] != '.'))
            || (ch == '.' && value[i].len < 2))
        {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "server name \"%V\" is invalid", &value[i]);
            return NGX_CONF_ERROR;
        }

        if (ngx_strchr(value[i].data, '/')) {
            ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
                               "server name \"%V\" has suspicious symbols",
                               &value[i]);
        }

        sn = ngx_array_push(&cscf->server_names);
        if (sn == NULL) {
            return NGX_CONF_ERROR;
        }

#if (NGX_PCRE)
        sn->regex = NULL;
#endif
        sn->server = cscf;

        if (ngx_strcasecmp(value[i].data, (u_char *) "$hostname") == 0) {
            sn->name = cf->cycle->hostname;

        } else {
            sn->name = value[i];
        }

        if (value[i].data[0] != '~') {
            ngx_strlow(sn->name.data, sn->name.data, sn->name.len);
            continue;
        }

#if (NGX_PCRE)
        {
        u_char               *p;
        ngx_regex_compile_t   rc;
        u_char                errstr[NGX_MAX_CONF_ERRSTR];

        if (value[i].len == 1) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "empty regex in server name \"%V\"", &value[i]);
            return NGX_CONF_ERROR;
        }

        value[i].len--;
        value[i].data++;

        ngx_memzero(&rc, sizeof(ngx_regex_compile_t));

        rc.pattern = value[i];
        rc.err.len = NGX_MAX_CONF_ERRSTR;
        rc.err.data = errstr;

        for (p = value[i].data; p < value[i].data + value[i].len; p++) {
            if (*p >= 'A' && *p <= 'Z') {
                rc.options = NGX_REGEX_CASELESS;
                break;
            }
        }

        sn->regex = ngx_http_regex_compile(cf, &rc);
        if (sn->regex == NULL) {
            return NGX_CONF_ERROR;
        }

        sn->name = value[i];
        cscf->captures = (rc.captures > 0);
        }
#else
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "using regex \"%V\" "
                           "requires PCRE library", &value[i]);

        return NGX_CONF_ERROR;
#endif
    }

    return NGX_CONF_OK;
}

ngx_http_core_server_name 函数是 Nginx 中处理 HTTP 服务器配置指令 server_name 的核心实现


    value = cf->args->elts;

 获取配置指令的参数列表

    for (i = 1; i < cf->args->nelts; i++) {

从第1个参数开始(跳过指令名本身)

        ch = value[i].data[0];

取当前参数的第一个字符

        if ((ch == '*' && (value[i].len < 3 || value[i].data[1] != '.'))
            || (ch == '.' && value[i].len < 2))
        {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "server name \"%V\" is invalid", &value[i]);
            return NGX_CONF_ERROR;
        }

server_name* 开头时,需满足以下任一情况即判定为非法:

长度不足 value[i].len < 3

格式错误 value[i].data[1] != '.'
(如 *example.com,第二个字符是 e 而非 .

*. 表示匹配任意子域名(. 为字面量)

server_name. 开头且长度不足 2 时判定为非法

        if (ngx_strchr(value[i].data, '/')) {
            ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
                               "server name \"%V\" has suspicious symbols",
                               &value[i]);
        }

 检查是否存在 / 符号

HTTP 协议中,Host 头字段的合法格式为 hostname[:port]不允许包含路径符号 /

        sn = ngx_array_push(&cscf->server_names);
        if (sn == NULL) {
            return NGX_CONF_ERROR;
        }

#if (NGX_PCRE)
        sn->regex = NULL;
#endif
        sn->server = cscf;

 将解析后的 server_name添加到当前服务器配置的 server_names 数组中 

cscf->server_names 数组末尾动态分配一个 ngx_http_server_name_t 结构体,并返回其指针 sn

若编译时启用了 PCRE 库(NGX_PCRE 宏定义存在),则将 sn->regex 初始化为 NULL,表示当前名称尚未关联正则表达式

sn->server 指向当前服务器配置块(ngx_http_core_srv_conf_t 类型)

当请求匹配到该服务器名称时,Nginx 可通过 sn->server 快速定位到对应的虚拟主机配置(如监听端口、根目录、location 块等)

        if (ngx_strcasecmp(value[i].data, (u_char *) "$hostname") == 0) {
            sn->name = cf->cycle->hostname;

        } else {
            sn->name = value[i];
        }

 server_name 中的 $hostname 替换为 Nginx 进程的主机名 ,实现动态服务器名称配置。
例如,若 Nginx 运行在主机 web-server01 上,则 server_name $hostname; 等效于 server_name web-server01;

        if (value[i].data[0] != '~') {
            ngx_strlow(sn->name.data, sn->name.data, sn->name.len);
            continue;
        }

 将非正则表达式的 server_name 转换为全小写格式,确保请求的 Host 头匹配时不区分大小写

若服务器名称以 ~ 开头(表示正则表达式),则跳过小写转换,进入正则编译流程

此时 条件成立,进入下一次循环,但当前 server_name 的参数只有一个,所以循环结束

return NGX_CONF_OK;

返回 NGX_CONF_OK


网站公告

今日签到

点亮在社区的每一天
去签到