Skip to content

feat(http_get): 体验与健壮性全面升级 + 独立 review 安全修复 - #18

Open
Doris2026-0 wants to merge 2 commits into
irmia2026:mainfrom
Doris2026-0:feat/http-get-robustness
Open

feat(http_get): 体验与健壮性全面升级 + 独立 review 安全修复#18
Doris2026-0 wants to merge 2 commits into
irmia2026:mainfrom
Doris2026-0:feat/http-get-robustness

Conversation

@Doris2026-0

Copy link
Copy Markdown

概述

对高频工具 http_get 做两轮改造:第一轮体验/健壮性升级,第二轮由两个独立 review 代理(正确性 + 安全)审查后修复全部发现。

第一轮:体验升级(05a4e27)

  • 编码嗅探: Content-Type charset → charset_normalizer/chardet → UTF-8,修复 GBK 站点静默乱码
  • gzip/deflate 自动解压 + Accept-Encoding 协商
  • GET 指数退避重试(5xx/连接错误,默认 2 次;4xx 与 SSRF 拦截不重试;POST 非幂等不重试)
  • 二进制 Content-Type 分流: PDF/图片等明确报错并 hint 改用 http_download
  • 返回新增 final_url/content_type;错误按状态码附排查 hint(401/403/404/405/429/5xx、DNS/超时/拒连),透传 retries
  • 修复: 翻页缓存前置(原缓存检查在下载之后,翻页整页重下且对端故障时缓存失效)
  • 修复: markdownify strip 只去标签不去文本,内联 script/style 源码泄漏进正文
  • 修复: 恰好 5MB 时截断误报;SPA 空页检测提示;timeout clamp 1~600s

第二轮:独立 review 修复(610243e)

两个独立审查代理(正确性 + 安全,均实测复现)发现的 1 Blocker + 全部 Major 已修:

  • 压缩炸弹(Blocker): 解压改 zlib.decompressobj 流式限长——原全量解压后才截断,1MB gzip 实测撑 2.1GB;现 1GB 炸弹 RSS 增量 ~0MB
  • 跨凭据缓存泄露: 翻页缓存 key 纳入 headers 规范化指纹,next_call 透传 headers——原实现无凭据方翻页可命中带凭据缓存拿到机密内容(已实测复现)
  • script 剔除 ReDoS: 正则 <script[\s\S]*?</script> 在大量无闭合标签时 O(n·m)(160KB 构造实测 26.8s),改线性扫描
  • 重试盲区: RemoteDisconnected/ConnectionResetError 等非 URLError 连接错误纳入重试;offset 非整型返回错误而非 TypeError
  • 截断压缩流: 返回已解压部分内容并标记(原静默返回压缩垃圾);br/zstd 明确报错
  • 其他: SsrfBlocked 专用异常替代文案匹配;HTTP 错误体读取限长 4KB;重试总预算 cap 180s;重试前 close 失败响应;429 hint 与行为对齐;UA/Accept-Encoding 大小写不敏感;post 补二进制分流;编码嗅探限前 64KB

测试

  • test_http_get.py + test_http_utils.py: 82 passed(新增约 30 条,含 review 全部回归)
  • 修复 review 指出的测试假阳性:分页衔接断言原 startswith("") 恒真,改为与缓存全文比对
  • 全量套件中 test_safe_edit 等 36 个失败为预存环境问题(缺 psutil、只读 /home/rinzi),在未改动的 HEAD 上同样失败(stash 对比验证)

已知遗留(backlog)

  • DNS rebinding TOCTOU(校验与连接两次解析,urllib 层难根治)
  • JS 渲染站(SPA)只能检测提示,根治需外挂 headless browser / Jina Reader

- 编码嗅探: Content-Type charset → charset_normalizer/chardet → utf-8,修复 GBK 站点静默乱码
- gzip/deflate 自动解压 + Accept-Encoding 协商,解压后再截断防压缩炸弹
- GET 对 5xx/连接错误指数退避重试(默认2次),4xx 与 SSRF 拦截不重试,POST 非幂等不重试
- 二进制 Content-Type (PDF/图片/音视频等) 明确报错并 hint 改用 http_download
- 返回新增 final_url/content_type;错误按状态码附排查 hint,区分 DNS/超时/拒连,透传 retries
- 修复: 翻页缓存前置(原缓存在下载后检查,翻页整页重下且对端故障时缓存失效)
- 修复: markdownify strip 只去标签不去文本导致内联 script/style 源码泄漏进正文
- 修复: _read_limited 恰好 5MB 时截断误报(多读 1 字节确认)
- SPA 检测: 转换后近乎无文本且原始 HTML 含大量脚本时附 JS 渲染提示
- get/post timeout clamp 1~600s;新增 30 条测试;版本 2.6.5
安全:
- 解压改 zlib.decompressobj 流式限长(原全量解压后才截断,1MB gzip 实测撑 2GB;现 1GB 炸弹 RSS 增量 ~0)
- 翻页缓存 key 纳入 headers 规范化指纹,修复跨凭据缓存命中泄露机密内容;next_call 透传 headers
- script/style 剔除改线性扫描(原正则在大量无闭合标签时 O(n·m) DoS)
- SSRF 拦截改专用异常 SsrfBlocked(原字符串匹配耦合文案)

健壮性:
- RemoteDisconnected/ConnectionReset 等非 URLError 连接错误纳入重试
- offset 非整型返回错误(原 TypeError 泄漏);截断压缩流返回部分内容并标记(原静默返回压缩垃圾)
- br/zstd 等不支持编码明确报错;HTTP 错误体读取限长 4KB;重试总预算 cap 180s;重试前 close 失败响应
- 429 hint 与不重试行为对齐;UA/Accept-Encoding 大小写不敏感;post 补二进制分流;编码嗅探限前 64KB

测试:
- 分页衔接断言假阳性修复(原 startswith("") 恒真,改为与缓存全文比对)
- FakeResponse headers 大小写不敏感;GBK skip 守卫修正;新增 20 条回归(共 82 passed)

@irmia2026 irmia2026 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

整体质量很高,安全修复到位,测试全部通过(本地实测 82 passed in 4.98s)。同意合并。

✅ 值得肯定的点

  1. 压缩炸弹防护正确:zlib.decompressobj 流式限长(max_length=max_bytes+1),配合 unconsumed_tail/eof 判断,1GB 炸弹不会撑爆内存——实测 test_gzip_bomb_bounded 通过
  2. 跨凭据缓存泄露修复到位:cache key 纳入 headers 规范化指纹 + _NO_CACHE 哨兵兜底,杜绝无凭据方命中带凭据缓存
  3. ReDoS 修复干净:_strip_tag_blocks 线性扫描替代 O(n·m) 正则,且对未闭合标签做了优雅降级(保留正文不误删)
  4. 重试策略克制:仅 5xx/连接错误重试、4xx 与 SSRF 不重试、POST 非幂等不重试、总预算 cap 180s——决策都合理
  5. 编码三级嗅探、二进制 Content-Type 分流、错误 hint 化、offset/timeout 参数校验,健壮性提升全面

🔍 Minor(不阻塞,可进 backlog)

  1. _decompress_limited 对 gzip 多成员流(罕见)会因 unconsumed_tail 非空误标 truncated——内容仍完整,仅标记不准
  2. 翻页 offset 越界时回退 offset=0 会整页重下(缓存有完整内容)——可优化为直接提示越界
  3. _strip_tag_blocks 会误删 HTML 注释/文本中出现的 <script> 字面量——对提取场景影响极小
  4. _read_limited 按 chunk 读,末 chunk 可能让 body 略超 5MB(原有行为,非本次引入)

📝 备注

  • PR 描述中提到的 36 个预存失败(缺 psutil 等)为环境问题,与本次改动无关,已在 HEAD 上验证
  • DNS rebinding TOCTOU 与 SPA 渲染已如实列入 backlog,建议后续跟进

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants