
1 定义ngx_http_set_virtual_server 函数 定义在 ./nginx-1.24.0/src/http/ngx_http_request.cstaticngx_int_tngx_http_set_virtual_server(ngx_http_request_t*r,ngx_str_t*host){ngx_int_trc;ngx_http_connection_t*hc;ngx_http_core_loc_conf_t*clcf;ngx_http_core_srv_conf_t*cscf;#if(NGX_SUPPRESS_WARN)cscfNULL;#endifhcr-http_connection;#if(NGX_HTTP_SSLdefined SSL_CTRL_SET_TLSEXT_HOSTNAME)if(hc-ssl_servername){if(hc-ssl_servername-lenhost-lenngx_strncmp(hc-ssl_servername-data,host-data,host-len)0){#if(NGX_PCRE)if(hc-ssl_servername_regexngx_http_regex_exec(r,hc-ssl_servername_regex,hc-ssl_servername)!NGX_OK){ngx_http_close_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);returnNGX_ERROR;}#endifreturnNGX_OK;}}#endifrcngx_http_find_virtual_server(r-connection,hc-addr_conf-virtual_names,host,r,cscf);if(rcNGX_ERROR){ngx_http_close_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);returnNGX_ERROR;}#if(NGX_HTTP_SSLdefined SSL_CTRL_SET_TLSEXT_HOSTNAME)if(hc-ssl_servername){ngx_http_ssl_srv_conf_t*sscf;if(rcNGX_DECLINED){cscfhc-addr_conf-default_server;rcNGX_OK;}sscfngx_http_get_module_srv_conf(cscf-ctx,ngx_http_ssl_module);if(sscf-verify){ngx_log_error(NGX_LOG_INFO,r-connection-log,0,client attempted to request the server name different from the one that was negotiated);ngx_http_finalize_request(r,NGX_HTTP_MISDIRECTED_REQUEST);returnNGX_ERROR;}}#endifif(rcNGX_DECLINED){returnNGX_OK;}r-srv_confcscf-ctx-srv_conf;r-loc_confcscf-ctx-loc_conf;clcfngx_http_get_module_loc_conf(r,ngx_http_core_module);ngx_set_connection_log(r-connection,clcf-error_log);returnNGX_OK;}ngx_http_set_virtual_server 函数的作用是 根据 HTTP 请求的 Host 头为请求选定并设置对应的虚拟主机server 块配置。2 详解1 函数签名staticngx_int_tngx_http_set_virtual_server(ngx_http_request_t*r,ngx_str_t*host)返回值 NGX_OK成功设置了请求对应的虚拟主机配置 NGX_ERROR发生错误参数1 ngx_http_request_t *r 指向当前正在处理的请求的上下文环境参数2 ngx_str_t *host 解析出的主机名2 逻辑流程1 局部变量 2 SSL 快速匹配路径 3 查找虚拟主机 4 错误检查 5 SSL 处理 6 未匹配 7 更新请求的配置 8 返回 成功1 局部变量{ngx_int_trc;ngx_http_connection_t*hc;ngx_http_core_loc_conf_t*clcf;ngx_http_core_srv_conf_t*cscf;#if(NGX_SUPPRESS_WARN)cscfNULL;#endifhcr-http_connection;rc 用于保存函数调用的返回值记录操作结果状态 hc 将指向当前请求关联的 HTTP 连接结构体r-http_connection 可从中获取地址配置信息等。 clcf 将指向核心模块ngx_http_core_module的 location 级配置 主要用于后续重设连接日志。 cscf 将指向匹配到的 server 级别的核心配置 即虚拟主机对应的 ngx_http_core_srv_conf_t 这是函数最终要确定并赋予请求的配置对象。条件编译 若定义了宏 NGX_SUPPRESS_WARN用于抑制某些编译器“可能未初始化”的警告 则将 cscf 初始化为 NULL。 这只影响编译警告对运行时逻辑无实际影响 因为所有可达路径都会给 cscf 赋值。将请求中的 HTTP 连接对象指针赋值给 hc 方便后续访问 hc-addr_conf、hc-ssl_servername 等字段。2 SSL 快速匹配路径#if(NGX_HTTP_SSLdefined SSL_CTRL_SET_TLSEXT_HOSTNAME)if(hc-ssl_servername){if(hc-ssl_servername-lenhost-lenngx_strncmp(hc-ssl_servername-data,host-data,host-len)0){#if(NGX_PCRE)if(hc-ssl_servername_regexngx_http_regex_exec(r,hc-ssl_servername_regex,hc-ssl_servername)!NGX_OK){ngx_http_close_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);returnNGX_ERROR;}#endifreturnNGX_OK;}}#endif条件编译开始 仅当 Nginx 编译时包含 SSL 模块 并且 OpenSSL 库支持 SSL_CTRL_SET_TLSEXT_HOSTNAME即 SNI 扩展时 才编译 SNI 相关代码块。3 查找虚拟主机rcngx_http_find_virtual_server(r-connection,hc-addr_conf-virtual_names,host,r,cscf);调用核心函数 ngx_http_find_virtual_server 执行真正的虚拟主机查找 参数1 r-connection底层网络连接。 参数2 hc-addr_conf-virtual_names 监听地址addr_conf下的所有虚拟主机名集合包含精确名、前置通配、后置通配、正则表达式等。 参数3 host请求的 Host 头内容。 参数4 r请求对象可能用于日志或上下文。 参数5 cscf输出参数 若找到匹配则将对应的 ngx_http_core_srv_conf_t 指针写入此处。 返回值 rc 表示查找结果 NGX_OK成功找到匹配的虚拟主机。 NGX_DECLINED未找到任何匹配。 NGX_ERROR查找过程出错如正则匹配异常。4 错误检查if(rcNGX_ERROR){ngx_http_close_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);returnNGX_ERROR;}如果查找过程发生错误 以 500 内部服务器错误结束请求 并返回 NGX_ERROR 给上层 通知其停止进一步处理。5 SSL 处理#if(NGX_HTTP_SSLdefined SSL_CTRL_SET_TLSEXT_HOSTNAME)if(hc-ssl_servername){ngx_http_ssl_srv_conf_t*sscf;if(rcNGX_DECLINED){cscfhc-addr_conf-default_server;rcNGX_OK;}sscfngx_http_get_module_srv_conf(cscf-ctx,ngx_http_ssl_module);if(sscf-verify){ngx_log_error(NGX_LOG_INFO,r-connection-log,0,client attempted to request the server name different from the one that was negotiated);ngx_http_finalize_request(r,NGX_HTTP_MISDIRECTED_REQUEST);returnNGX_ERROR;}}#endifSSL 场景下匹配失败的补救及主机名验证6 未匹配if(rcNGX_DECLINED){returnNGX_OK;}未找到匹配 返回成功 意味着请求将继续使用之前已设置的 server 配置 通常是在收到请求前根据 IP/端口选定的默认 server7 更新请求的配置r-srv_confcscf-ctx-srv_conf;r-loc_confcscf-ctx-loc_conf;找到了匹配的虚拟主机 将请求对象的模块配置指针切换到新选定的 server 块clcfngx_http_get_module_loc_conf(r,ngx_http_core_module);ngx_set_connection_log(r-connection,clcf-error_log);获取新选定 server及当前 location 上下文下 核心模块的 location 级配置其中包含 error_log 等设置。 更新底层连接的日志对象 这样后续日志会输出到正确的地方 并遵循该虚拟主机定义的日志级别8 返回 成功returnNGX_OK;}