ngx_http_range_body_filter

📅 2026/7/16 22:40:47 👁️ 阅读次数 📝 编程学习
ngx_http_range_body_filter

1 定义

ngx_http_range_body_filter 函数 定义在 src/http/modules/ngx_http_range_filter_module.c
staticngx_int_tngx_http_range_body_filter(ngx_http_request_t*r,ngx_chain_t*in){ngx_http_range_filter_ctx_t*ctx;if(in==NULL){returnngx_http_next_body_filter(r,in);}ctx=ngx_http_get_module_ctx(r,ngx_http_range_body_filter_module);if(ctx==NULL){returnngx_http_next_body_filter(r,in);}if(ctx->ranges.nelts==1){returnngx_http_range_singlepart_body(r,ctx,in);}/* * multipart ranges are supported only if whole body is in a single buffer */if(ngx_buf_special(in->buf)){returnngx_http_next_body_filter(r,in);}if(ngx_http_range_test_overlapped(r,ctx,in)!=NGX_OK){returnNGX_ERROR;}returnngx_http_range_multipart_body(r,ctx,in);}

2 目的

1 设计意图

ngx_http_range_body_filter
Nginx HTTP Range Body Filter 模块的核心入口函数,
属于HTTP 输出 body 过滤链的关键一环。

其核心职责是:
根据客户端请求的 Range 范围,
从完整响应 body 中截取指定字节段,
只将客户端实际请求的那部分数据传递到下游过滤链

当一个 HTTP 响应包含Accept-Ranges: bytes
客户端发送了Range: bytes=...请求头时,
Nginx 需要在 header 过滤阶段 (由ngx_http_range_header_filter处理) 将状态码
改为206 Partial Content,然后在 body 过滤阶段精确裁剪 body 数据。


3 详解

1 函数签名

staticngx_int_tngx_http_range_body_filter(ngx_http_request_t*r,ngx_chain_t*in)

1 返回值:ngx_int_t

返回值含义
NGX_OK成功处理或透传,下游过滤器继续处理
NGX_ERROR内部错误(如缓冲区重叠检测失败)
下游过滤器返回值透传下游ngx_http_next_body_filter的返回结果

2 函数名:ngx_http_range_body_filter

词段含义
ngx_httpNginx HTTP 子系统
range模块名,表示 HTTP Range 功能
bodybody 过滤阶段(对应 header 过滤阶段的range_header_filter
filter过滤器模式,属于 HTTP 输出过滤链的一部分

3 参数列表

参数类型含义来源约束
rngx_http_request_t *HTTP 请求对象,包含请求和响应的全部信息上游调用传入非 NULL
inngx_chain_t *待输出的 body 数据链表(ngx_buf_t 的链表结构)上游过滤器产出可为 NULL(表示 body 结束);非 NULL 时不能无限循环

2 逻辑流程

ngx_http_range_body_filter(r, in) ├─ [1] 空输入检测 │ └─ in == NULL → 透传下游,返回 ├─ [2] 上下文缺失检测 │ └─ ctx == NULL → 透传下游,返回 ├─ [3] 单 range 路由 │ └─ nelts == 1 → singlepart_body,返回 └─ [4] 多 range 处理(nelts > 1) ├─ [4.1] 特殊缓冲区检测 │ └─ ngx_buf_special → 透传下游,返回 ├─ [4.2] 缓冲区重叠检测 │ └─ test_overlapped != OK → return NGX_ERROR └─ [4.3] 多 range body 构造 └─ multipart_body,返回

{ngx_http_range_filter_ctx_t*ctx;

1 空输入检测

if(in==NULL){returnngx_http_next_body_filter(r,in);}

过滤链中,in == NULL是 Nginx 约定的一种 body 结束标记(或空调用)。
此时不需要做任何 range 裁剪,直接原样传递给下游过滤器。

in == NULL在 Nginx 的 body 过滤链中是合法的输入,表示"本次调用不携带数据"
此时直接调用下游函数,跳过后面的所有 range 处理逻辑


2 上下文缺失检测

ctx=ngx_http_get_module_ctx(r,ngx_http_range_body_filter_module);if(ctx==NULL){returnngx_http_next_body_filter(r,in);}

Range 上下文是在 header 过滤阶段由ngx_http_range_header_filter创建的。
如果请求中没有有效的 Range 请求头(或 range 解析失败),
ctx 不会被创建。此时 body 阶段不需要做任何处理,直接透传。

ngx_http_get_module_ctx(r, module)展开为r->ctx[module.ctx_index]
从请求对象的上下文数组中获取模块私有上下文

ctx 的创建发生在 header 过滤阶段(ngx_http_range_header_filterparse:标签处

ctx 为 NULL 意味着该请求不需要 range 处理,
或者 range 解析失败导致 header 阶段已经直接返回


3 单 range 路由

if(ctx->ranges.nelts==1){returnngx_http_range_singlepart_body(r,ctx,in);}

ctx->ranges.nelts
表示解析出了多少个 range 段。
当只有一个 range 时,走ngx_http_range_singlepart_body路径,
该函数直接在原缓冲区的pos/lastfile_pos/file_last指针上做偏移裁剪,
零拷贝且高效。


4 多 range 处理

ctx->ranges.nelts > 1
(即客户端请求了多个不连续的字节范围),
走 multipart 路径。

这条路径的约束远多于单 range 路径,
因为 multipart/byteranges 格式要求将 body 切成多个片段,
每个片段前插入 boundary 分隔头和 Content-Range 头,
需要在一个连续的缓冲区上同时操作。


4-1 特殊缓冲区
/* * multipart ranges are supported only if whole body is in a single buffer */if(ngx_buf_special(in->buf)){returnngx_http_next_body_filter(r,in);}

ngx_buf_special宏检测当前缓冲区是否
仅为控制标记(flush/last_buf/sync)且无实际数据。
这类 buffer 是纯控制型 buffer——只传达控制信息,不携带 body 载荷

如果是 这类 buffer ,则无事可做,继续 下一个 body_filter


4-2 缓冲区重叠检测
if(ngx_http_range_test_overlapped(r,ctx,in)!=NGX_OK){returnNGX_ERROR;}

ngx_http_range_test_overlapped是 multipart 路径的第二道安全屏障。
它检查传入的 body 缓冲区in是否满足"单 buffer 完整覆盖所有 range"的约束:

  • 如果检查通过(返回NGX_OK),程序继续进入 4-3 的多 range 构造阶段。
  • 如果检查失败(返回NGX_ERROR),立即返回NGX_ERROR给上游过滤链,

ngx_http_range_test_overlapped函数
对 multipart 路径实施一个关键约束:
所有请求的 range 必须在同一个 body buffer 中完整交付

安全意义

这个检查有其安全必要性:
multipart/byteranges 格式需要在原始 body buffer 上做多次零拷贝切片(通过指针偏移)。
如果原始 buffer 不完整或不连续,切出的子 buffer 会指向错误的内存地址或文件偏移,
产生损坏的 multipart 响应,甚至可能泄露服务器内存中的其他数据。


4-3 多 range body 构造
returnngx_http_range_multipart_body(r,ctx,in);}

将多 range body 的构造委托给ngx_http_range_multipart_body

这是 multipart 路径的最后一步。
它将经过前两道安全检查的 buffer 和 range 上下文委托给ngx_http_range_multipart_body
由该函数完成完整的 multipart/byteranges 响应 body 的拼装。
组装完成后,结果链被传入下游过滤链(ngx_http_next_body_filter)。


ngx_http_range_multipart_body函数

该函数以 body 的原始 buffer(in->buf)作为数据源,
为每个请求的 range 构建一段对应的 multipart 片段,
最后将所有这些片段串联成一个完整的输出链传给下游。