ngx_http_range_body_filter
1 定义
ngx_http_range_body_filter 函数 定义在 src/http/modules/ngx_http_range_filter_module.cstaticngx_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_http | Nginx HTTP 子系统 |
range | 模块名,表示 HTTP Range 功能 |
body | body 过滤阶段(对应 header 过滤阶段的range_header_filter) |
filter | 过滤器模式,属于 HTTP 输出过滤链的一部分 |
3 参数列表
| 参数 | 类型 | 含义 | 来源 | 约束 |
|---|---|---|---|---|
r | ngx_http_request_t * | HTTP 请求对象,包含请求和响应的全部信息 | 上游调用传入 | 非 NULL |
in | ngx_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_filter的parse:标签处
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/last或file_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 片段,
最后将所有这些片段串联成一个完整的输出链传给下游。
