定义在 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