feat(http_get): 体验与健壮性全面升级 + 独立 review 安全修复 - #18
Open
Doris2026-0 wants to merge 2 commits into
Open
Conversation
- 编码嗅探: 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
approved these changes
Sep 2, 2026
irmia2026
left a comment
Owner
There was a problem hiding this comment.
整体质量很高,安全修复到位,测试全部通过(本地实测 82 passed in 4.98s)。同意合并。
✅ 值得肯定的点
- 压缩炸弹防护正确:zlib.decompressobj 流式限长(max_length=max_bytes+1),配合 unconsumed_tail/eof 判断,1GB 炸弹不会撑爆内存——实测 test_gzip_bomb_bounded 通过
- 跨凭据缓存泄露修复到位:cache key 纳入 headers 规范化指纹 + _NO_CACHE 哨兵兜底,杜绝无凭据方命中带凭据缓存
- ReDoS 修复干净:_strip_tag_blocks 线性扫描替代 O(n·m) 正则,且对未闭合标签做了优雅降级(保留正文不误删)
- 重试策略克制:仅 5xx/连接错误重试、4xx 与 SSRF 不重试、POST 非幂等不重试、总预算 cap 180s——决策都合理
- 编码三级嗅探、二进制 Content-Type 分流、错误 hint 化、offset/timeout 参数校验,健壮性提升全面
🔍 Minor(不阻塞,可进 backlog)
- _decompress_limited 对 gzip 多成员流(罕见)会因 unconsumed_tail 非空误标 truncated——内容仍完整,仅标记不准
- 翻页 offset 越界时回退 offset=0 会整页重下(缓存有完整内容)——可优化为直接提示越界
- _strip_tag_blocks 会误删 HTML 注释/文本中出现的 <script> 字面量——对提取场景影响极小
- _read_limited 按 chunk 读,末 chunk 可能让 body 略超 5MB(原有行为,非本次引入)
📝 备注
- PR 描述中提到的 36 个预存失败(缺 psutil 等)为环境问题,与本次改动无关,已在 HEAD 上验证
- DNS rebinding TOCTOU 与 SPA 渲染已如实列入 backlog,建议后续跟进
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述
对高频工具
http_get做两轮改造:第一轮体验/健壮性升级,第二轮由两个独立 review 代理(正确性 + 安全)审查后修复全部发现。第一轮:体验升级(05a4e27)
第二轮:独立 review 修复(610243e)
两个独立审查代理(正确性 + 安全,均实测复现)发现的 1 Blocker + 全部 Major 已修:
zlib.decompressobj流式限长——原全量解压后才截断,1MB gzip 实测撑 2.1GB;现 1GB 炸弹 RSS 增量 ~0MBnext_call透传 headers——原实现无凭据方翻页可命中带凭据缓存拿到机密内容(已实测复现)<script[\s\S]*?</script>在大量无闭合标签时 O(n·m)(160KB 构造实测 26.8s),改线性扫描RemoteDisconnected/ConnectionResetError等非 URLError 连接错误纳入重试;offset 非整型返回错误而非 TypeErrorSsrfBlocked专用异常替代文案匹配;HTTP 错误体读取限长 4KB;重试总预算 cap 180s;重试前 close 失败响应;429 hint 与行为对齐;UA/Accept-Encoding 大小写不敏感;post 补二进制分流;编码嗅探限前 64KB测试
test_http_get.py+test_http_utils.py: 82 passed(新增约 30 条,含 review 全部回归)startswith("")恒真,改为与缓存全文比对test_safe_edit等 36 个失败为预存环境问题(缺 psutil、只读 /home/rinzi),在未改动的 HEAD 上同样失败(stash 对比验证)已知遗留(backlog)