cpx 的 requestBodyForCapture() 用 zlib.unzipSync() 处理除 zstd 之外的压缩请求,但这个 API 不解码 Brotli。请求头为 Content-Encoding: br 时,解码失败被 catch 吞掉,函数返回原始压缩字节。server.ts::handleProxy() 随后将这些字节当作 UTF-8 JSON 解析,parsedBody 变成 null,捕获内容无法取得请求中的 messages/input 及 stream 字段。
requestBodyForCapture()
zlib.unzipSync()
Content-Encoding: br
server.ts::handleProxy()
parsedBody
原始请求字节仍会转发上游,因此代理请求可以继续执行;缺陷在本地明文捕获解析。此报告只讨论单个 br 编码,不涉及叠加压缩编码。
9ce8017
packages/cpx/src/request-body-decoder.ts
src/server.ts:120-125
在 packages/cpx 使用 tsx 调用真实解码器:
packages/cpx
import zlib from 'node:zlib'; import { requestBodyForCapture } from './src/request-body-decoder.ts'; const json = Buffer.from(JSON.stringify({model: 'example-model', stream: true, messages: [{role: 'user', content: 'synthetic prompt'}]})); const br = zlib.brotliCompressSync(json); const decoded = requestBodyForCapture(br, 'openai', 'br'); console.log(decoded.equals(json)); JSON.parse(decoded.toString('utf-8'));
相等判断为 false,随后 JSON 解析失败。新增回归在修复前 6 failed、4 passed:三种已识别协议和 null 协议均不能解码 Brotli,大小写/数组头用例也失败;gzip、deflate 和原有回退行为通过。
用 Node 内置 Brotli 解码器还原用于捕获解析的副本,保持转发上游的原始 Buffer 字节不变。损坏压缩流继续使用原有原文回退行为。
修复后 cpx 全量 UT 为 20 个测试文件、190 个测试全部通过,其中新增解码回归 10 个;适用 pre-commit / OAT 通过。已检查 51 个历史 Issue 和 36 个开放 PR,没有发现该解码问题。#27 / #58 讨论捕获落盘的 gzip 与 7z 格式,属于不同层次。
/assign @Ethan_Zou
问题背景
cpx 的
requestBodyForCapture()用zlib.unzipSync()处理除 zstd 之外的压缩请求,但这个 API 不解码 Brotli。请求头为Content-Encoding: br时,解码失败被 catch 吞掉,函数返回原始压缩字节。server.ts::handleProxy()随后将这些字节当作 UTF-8 JSON 解析,parsedBody变成 null,捕获内容无法取得请求中的 messages/input 及 stream 字段。原始请求字节仍会转发上游,因此代理请求可以继续执行;缺陷在本地明文捕获解析。此报告只讨论单个 br 编码,不涉及叠加压缩编码。
环境
9ce8017。packages/cpx/src/request-body-decoder.ts及src/server.ts:120-125。复现步骤
在
packages/cpx使用 tsx 调用真实解码器:import zlib from 'node:zlib'; import { requestBodyForCapture } from './src/request-body-decoder.ts'; const json = Buffer.from(JSON.stringify({model: 'example-model', stream: true, messages: [{role: 'user', content: 'synthetic prompt'}]})); const br = zlib.brotliCompressSync(json); const decoded = requestBodyForCapture(br, 'openai', 'br'); console.log(decoded.equals(json)); JSON.parse(decoded.toString('utf-8'));实际行为
相等判断为 false,随后 JSON 解析失败。新增回归在修复前 6 failed、4 passed:三种已识别协议和 null 协议均不能解码 Brotli,大小写/数组头用例也失败;gzip、deflate 和原有回退行为通过。
期望行为
用 Node 内置 Brotli 解码器还原用于捕获解析的副本,保持转发上游的原始 Buffer 字节不变。损坏压缩流继续使用原有原文回退行为。
验证与去重
修复后 cpx 全量 UT 为 20 个测试文件、190 个测试全部通过,其中新增解码回归 10 个;适用 pre-commit / OAT 通过。已检查 51 个历史 Issue 和 36 个开放 PR,没有发现该解码问题。#27 / #58 讨论捕获落盘的 gzip 与 7z 格式,属于不同层次。