ngx_http_range_body_filter

📅 2026/7/16 22:34:38
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(inNULL){returnngx_http_next_body_filter(r,in);}ctxngx_http_get_module_ctx(r,ngx_http_range_body_filter_module);if(ctxNULL){returnngx_http_next_body_filter(r,in);}if(ctx-ranges.nelts1){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_filterfilter过滤器模式属于 HTTP 输出过滤链的一部分3 参数列表参数类型含义来源约束rngx_http_request_t *HTTP 请求对象包含请求和响应的全部信息上游调用传入非 NULLinngx_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(inNULL){returnngx_http_next_body_filter(r,in);}过滤链中in NULL是 Nginx 约定的一种 body 结束标记或空调用。此时不需要做任何 range 裁剪直接原样传递给下游过滤器。in NULL在 Nginx 的 body 过滤链中是合法的输入表示本次调用不携带数据此时直接调用下游函数跳过后面的所有 range 处理逻辑2 上下文缺失检测ctxngx_http_get_module_ctx(r,ngx_http_range_body_filter_module);if(ctxNULL){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.nelts1){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_filter4-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 的原始 bufferin-buf作为数据源为每个请求的 range 构建一段对应的 multipart 片段最后将所有这些片段串联成一个完整的输出链传给下游。