ngx_http_update_location_config

ngx_http_update_location_config

1 定义

ngx_http_update_location_config 函数 定义在 src/http/ngx_http_core_module.c

2 作用

ngx_http_update_location_config 函数的作用是 将请求已匹配到的 location 配置应用到请求对象 `r` 上, 使其在运行时生效。

3 详解

1 函数签名

voidngx_http_update_location_config(ngx_http_request_t*r)

1. 返回值类型 void

函数不返回任何值,调用者无法获得操作成功与否的直接反馈。


2. 函数名 ngx_http_update_location_config

ngx_http_
表明该函数属于 HTTP 核心模块,处理的是 HTTP 协议相关的逻辑。

update
动词,准确地描述了函数的行为——“更新”。
它不是“创建”或“初始化”,而是将已经确定的 location 配置刷新到请求的运行时状态中。
这种更新可能发生多次,比如在内部重定向后重新匹配 location 时会再次调用。

location_config
宾语,指明了更新的对象是“location 配置”。
在 Nginx 中,一个请求在通过FIND_CONFIG阶段匹配到具体的 location 块后,
就获得了该块下所有模块的配置集合,
本函数负责把这些静态配置转化为请求动态运行时的参数。

整体语义:
该函数是连接“静态 location 配置”与“动态请求处理”的桥梁。
每当请求匹配到一个新的 location,
都需要调用此函数将对应的配置参数 应用到请求对象上,
确保后续处理严格遵循该 location 的指令。


3. 参数ngx_http_request_t *r

指向 当前请求的 上下文结构体


2 逻辑流程

1 获取配置 2 更新各个配置 2-1 方法限制 2-2 更新连接错误日志(仅主请求) 2-3 配置 sendfile 2-4 请求体文件存储 2-5 设置请求体单缓冲区标志 2-6 Keep-Alive 2-7 配置 TCP_NOPUSH 2-8 设置内容处理器

1 获取配置

{ngx_http_core_loc_conf_t*clcf;clcf=ngx_http_get_module_loc_conf(r,ngx_http_core_module);

2 更新各配置

2-1 方法限制
if(r->method&clcf->limit_except){r->loc_conf=clcf->limit_except_loc_conf;clcf=ngx_http_get_module_loc_conf(r,ngx_http_core_module);}

r->method是当前 HTTP 请求的方法,它以位掩码的形式存储

limit_except字段也是一个位掩码,记录着被limit_except指令禁止的方法集合。

r->method & clcf->limit_except是按位与操作。
如果结果非零,说明当前请求的 HTTP 方法恰好属于被限制的方法之一,条件成立。


r->loc_conf = clcf->limit_except_loc_conf;

clcf->limit_except_loc_conflimit_except指令块内部的独立配置数组指针。
这个配置数组包含了limit_except块内所有指令
(如 allow、deny、以及可能嵌套的其他模块指令)所对应的模块配置。

这行赋值语句的作用是:
将请求的配置上下文整体切换为limit_except块内部的配置。
这意味着,从此刻起,所有后续模块看到的配置都将是limit_except块内部定义的规则,
而不是原 location 块的规则。


clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
由于r->loc_conf刚刚被替换成了新的配置数组,
原先的 clcf 指针现在可能已经不指向当前生效的核心模块配置了
(因为配置数组已经改变)。

根据请求当前最新的r->loc_conf,重新取出 HTTP 核心模块在 location 级别的配置,
并将这个新的指针赋值给 clcf。

这样做是为了保证后续代码使用的是limit_except块内部可能重新定义的核心配置。
如果不更新 clcf,后续代码将继续读取原 location 的核心配置,这可能导致行为与预期不符。


2-2 更新连接错误日志(仅主请求)
if(r==r->main){ngx_set_connection_log(r->connection,clcf->error_log);}

2-3 配置 sendfile
if((ngx_io.flags&NGX_IO_SENDFILE)&&clcf->sendfile){r->connection->sendfile=1;}else{r->connection->sendfile=0;}

据操作系统能力和当前 location 的配置,
决定是否为该连接启用 sendfile 功能。


2-4 请求体文件存储
if(clcf->client_body_in_file_only){r->request_body_in_file_only=1;r->request_body_in_persistent_file=1;r->request_body_in_clean_file=clcf->client_body_in_file_only==NGX_HTTP_REQUEST_BODY_FILE_CLEAN;r->request_body_file_log_level=NGX_LOG_NOTICE;}else{r->request_body_file_log_level=NGX_LOG_WARN;}

根据 location 的配置,
设置请求对象中关于“客户端请求体文件存储”的相关标志和日志级别


2-5 设置请求体单缓冲区标志
r->request_body_in_single_buf=clcf->client_body_in_single_buffer;

用于控制后续读取客户端请求体时的内存缓冲策略。


2-6 Keep-Alive
if(r->keepalive){

只有当r->keepalive当前为 1(即初步允许长连接)时,
才进入该代码块进行更细致的检查。
如果基础条件就不满足(例如客户端明确要求 Connection: close),
后续检查就没有必要,直接跳过。


if(clcf->keepalive_timeout==0){r->keepalive=0;

keepalive_timeout对应指令keepalive_timeout的第一个参数。
该指令控制服务器在长连接上等待下一个请求的空闲超时时间(单位秒,内部转换为毫秒)。

当该值被显式设置为 0 时,表示完全禁用长连接。
因此,如果 location 配置了 keepalive_timeout 0;,
那么无论客户端如何请求,服务器都会在本次响应后关闭连接。

动作:
将 r->keepalive 置为 0,本函数后面不再重新设置它,后续的连接管理逻辑会据此关闭连接。


}elseif(r->connection->requests>=clcf->keepalive_requests){r->keepalive=0;

r->connection->requests记录了当前连接上已经处理过的请求总数。
每完成一个请求,该计数就会增加。

clcf->keepalive_requests对应指令keepalive_requests
指定了单个长连接上允许处理的最大请求数。
达到该数量后,服务器会主动关闭连接,强制客户端重新建立连接,以平衡负载和资源。

比较:如果已处理的请求数已经达到或超过了配置的上限,则强制关闭长连接。

设计意义:
防止单个连接处理过多请求,确保连接能够被及时回收,
避免一个连接长时间占用服务器资源。


}elseif(ngx_current_msec-r->connection->start_time>clcf->keepalive_time){r->keepalive=0;

ngx_current_msec
Nginx 缓存的当前时间,单位毫秒。

r->connection->start_time
连接建立时的起始时间(毫秒戳)。

clcf->keepalive_time
对应指令keepalive_time
指定了一个长连接从建立开始所允许的最大存活时间(毫秒)。

计算:
当前时间减去连接建立时间,即为连接已经存活的总时长。
如果超过了keepalive_time,则关闭长连接。

设计意义:
限制连接的总生命周期,避免连接因频繁复用而长期不释放,
有助于平滑升级或资源回收


}elseif(r->headers_in.msie6&&r->method==NGX_HTTP_POST&&(clcf->keepalive_disable&NGX_HTTP_KEEPALIVE_DISABLE_MSIE6)){/* * MSIE may wait for some time if an response for * a POST request was sent over a keepalive connection */r->keepalive=0;

检查是否对 MSIE 6 禁用 Keep-Alive

r->headers_in.msie6
一个请求标志,当 User-Agent 头部表明客户端是旧版 MSIE 6 时被设置为 1。

这些旧版本浏览器在处理 Keep-Alive 时存在已知问题。


}elseif(r->headers_in.safari&&(clcf->keepalive_disable&NGX_HTTP_KEEPALIVE_DISABLE_SAFARI)){/* * Safari may send a POST request to a closed keepalive * connection and may stall for some time, see * https://bugs.webkit.org/show_bug.cgi?id=5760 */r->keepalive=0;}}

检查是否对 Safari 禁用 Keep-Alive


2-7 配置 TCP_NOPUSH
if(!clcf->tcp_nopush){/* disable TCP_NOPUSH/TCP_CORK use */r->connection->tcp_nopush=NGX_TCP_NOPUSH_DISABLED;}

clcf->tcp_nopush就是tcp_nopush指令的值:
如果配置了tcp_nopush on;,它为非零值;
如果是tcp_nopush off;或者没配置,它通常为 0。

r->connection->tcp_nopush
这个字段位于连接对象上,而不是请求对象。
它表示当前连接是否启用 TCP 层面的推送优化。

Nginx 在发送静态文件时,会调用操作系统提供的选项,
先将数据攒起来,等数据块足够大后再一起发送,
这样可以减少网络上小包的数量,提高传输效率。

NGX_TCP_NOPUSH_DISABLED
这是一个 Nginx 内部定义的特殊常量,
表示“明确禁用TCP_NOPUSH/TCP_CORK”。
把它赋给r->connection->tcp_nopush,就相当于告诉后续的发送逻辑:
不要使用这个优化,数据应该尽快发送,不要故意延迟等待更多数据。


2-8 设置内容处理器
if(clcf->handler){r->content_handler=clcf->handler;}}

把当前 location 指定的“内容处理器”绑定到请求对象上。