1 定义 ngx_http_find_virtual_server 函数 定义在 ./nginx-1.24.0/src/http/ngx_http_request.cstatic ngx_int_t ngx_http_find_virtual_server ( ngx_connection_t * c, ngx_http_virtual_names_t * virtual_names, ngx_str_t * host, ngx_http_request_t * r, ngx_http_core_srv_conf_t * * cscfp) { ngx_http_core_srv_conf_t * cscf; if ( virtual_names== NULL ) { return NGX_DECLINED; } cscf= ngx_hash_find_combined ( & virtual_names-> names, ngx_hash_key ( host-> data, host-> len) , host-> data, host-> len) ; if ( cscf) { * cscfp= cscf; return NGX_OK; } # if ( NGX_PCRE) if ( host-> len&& virtual_names-> nregex) { ngx_int_t n; ngx_uint_t i; ngx_http_server_name_t * sn; sn= virtual_names-> regex; # if ( NGX_HTTP_SSL&& defined SSL_CTRL_SET_TLSEXT_HOSTNAME) if ( r== NULL ) { ngx_http_connection_t * hc; for ( i= 0 ; i< virtual_names-> nregex; i++ ) { n= ngx_regex_exec ( sn[ i] . regex-> regex, host, NULL , 0 ) ; if ( n== NGX_REGEX_NO_MATCHED) { continue ; } if ( n>= 0 ) { hc= c-> data; hc-> ssl_servername_regex= sn[ i] . regex; * cscfp= sn[ i] . server; return NGX_OK; } ngx_log_error ( NGX_LOG_ALERT, c-> log, 0 , ngx_regex_exec_n" failed: %i " "on \"%V\" using \"%V\"" , n, host, & sn[ i] . regex-> name) ; return NGX_ERROR; } return NGX_DECLINED; } # endif /* NGX_HTTP_SSL && defined SSL_CTRL_SET_TLSEXT_HOSTNAME */ for ( i= 0 ; i< virtual_names-> nregex; i++ ) { n= ngx_http_regex_exec ( r, sn[ i] . regex, host) ; if ( n== NGX_DECLINED) { continue ; } if ( n== NGX_OK) { * cscfp= sn[ i] . server; return NGX_OK; } return NGX_ERROR; } } # endif /* NGX_PCRE */ return NGX_DECLINED; } ngx_http_find_virtual_server 函数用于 根据 HTTP 请求的主机名(`Host` 头) 在监听端口的虚拟主机名集合中查找对应的 `server` 配置。 它优先进行精确及通配符哈希查找, 若失败则按顺序尝试正则匹配(支持 SSL SNI 阶段的特殊处理), 最终返回匹配到的虚拟服务器配置或未找到标志。2 详解 1 函数签名 static ngx_int_t ngx_http_find_virtual_server ( ngx_connection_t * c, ngx_http_virtual_names_t * virtual_names, ngx_str_t * host, ngx_http_request_t * r, ngx_http_core_srv_conf_t * * cscfp) 返回值 NGX_OK:成功找到匹配的虚拟服务器,*cscfp 已指向对应配置。 NGX_DECLINED:未找到任何匹配,调用者应使用默认服务器。 NGX_ERROR:匹配过程中发生严重错误,应中断当前连接。参数1 ngx_connection_t *c 当前连接参数2 ngx_http_virtual_names_t *virtual_names 指向 该地址端口下的虚拟主机名集合参数3 ngx_str_t *host 表示待匹配的主机名参数4 ngx_http_request_t *r 指向 当前 HTTP 请求结构体的指针,可以为 NULL参数5 ngx_http_core_srv_conf_t **cscfp 指向服务器配置指针的指针(二级指针) 输出参数,当查找成功时, 将 *cscfp 设置为匹配到的 server 块配置。 查找失败时不修改。2 逻辑流程 1 局部变量 2 空集合检查 3 hash 查找 4 查找成功 5 正则相关处理 6 未匹配1 局部变量{ ngx_http_core_srv_conf_t * cscf; cscf:类型为指向服务器核心配置的指针, 用于暂存哈希查找的结果,初始值未定义2 空集合检查if ( virtual_names== NULL ) { return NGX_DECLINED; } 空指针检查: 若传入的虚拟主机名集合为 NULL (通常意味着当前监听端口未配置任何 server_name), 则立即返回 NGX_DECLINED,表示未找到匹配, 调用者会使用默认服务器。 这避免了对空指针的非法访问。3 hash 查找cscf= ngx_hash_find_combined ( & virtual_names-> names, ngx_hash_key ( host-> data, host-> len) , host-> data, host-> len) ; 精确/通配哈希查找: 调用 ngx_hash_find_combined 在组合哈希表 virtual_names->names 中查找。 该哈希表同时存储了精确名称、前缀通配符(*.example.com)和后缀通配符(www.*)。 ngx_hash_key(host->data, host->len) 计算主机名字符串的哈希值(BKDR 哈希算法),用于定位桶。 后两个参数传递原始字符串和长度,用于在桶内逐字比对,防止哈希碰撞。 返回匹配到的 ngx_http_core_srv_conf_t 指针,若未找到则为 NULL。4 查找成功if ( cscf) { * cscfp= cscf; return NGX_OK; } 检查哈希查找结果: 若 cscf 非空,说明成功匹配。 *cscfp = cscf: 将输出参数指向该服务器配置。 返回 NGX_OK,调用者即可使用 *cscfp 获得服务器配置。5 正则相关处理# if ( NGX_PCRE) if ( host-> len&& virtual_names-> nregex) { ngx_int_t n; ngx_uint_t i; ngx_http_server_name_t * sn; sn= virtual_names-> regex; # if ( NGX_HTTP_SSL&& defined SSL_CTRL_SET_TLSEXT_HOSTNAME) if ( r== NULL ) { ngx_http_connection_t * hc; for ( i= 0 ; i< virtual_names-> nregex; i++ ) { n= ngx_regex_exec ( sn[ i] . regex-> regex, host, NULL , 0 ) ; if ( n== NGX_REGEX_NO_MATCHED) { continue ; } if ( n>= 0 ) { hc= c-> data; hc-> ssl_servername_regex= sn[ i] . regex; * cscfp= sn[ i] . server; return NGX_OK; } ngx_log_error ( NGX_LOG_ALERT, c-> log, 0 , ngx_regex_exec_n" failed: %i " "on \"%V\" using \"%V\"" , n, host, & sn[ i] . regex-> name) ; return NGX_ERROR; } return NGX_DECLINED; } # endif /* NGX_HTTP_SSL && defined SSL_CTRL_SET_TLSEXT_HOSTNAME */ for ( i= 0 ; i< virtual_names-> nregex; i++ ) { n= ngx_http_regex_exec ( r, sn[ i] . regex, host) ; if ( n== NGX_DECLINED) { continue ; } if ( n== NGX_OK) { * cscfp= sn[ i] . server; return NGX_OK; } return NGX_ERROR; } } # endif /* NGX_PCRE */ 6 未匹配return NGX_DECLINED; } 最终未匹配: 如果哈希表和所有正则(如果有)都未找到, 返回 NGX_DECLINED。 调用者将使用监听端口的默认服务器。