Skip to content

fix(http): add read/idle timeouts to http.Server to prevent slow-client resource exhaustion - #116

Open
suantea wants to merge 1 commit into
PIKACHUIM:mainfrom
suantea:fix/http-server-timeout
Open

suantea wants to merge 1 commit into
PIKACHUIM:mainfrom
suantea:fix/http-server-timeout

Conversation

@suantea

@suantea suantea commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

概述

http.Server 此前零超时配置,慢连接可长期占住 goroutine 与文件描述符,影响稳定性。

改动

  • ReadTimeout: 30s / ReadHeaderTimeout: 10s / IdleTimeout: 120s / MaxHeaderBytes: 1MB
  • WriteTimeout 保持 0(有意为之):AI 对话与 CF 隧道日志走 SSE 流式响应、监控终端走 WebSocket 升级,任何写超时都会掐断长连接

验证

  • go build / go vet / 全量 go test ./... 通过
  • SSE(ai/cftunnel)与 WebSocket(terminal)路由不受影响

pikachuren

This comment was marked as outdated.

@suantea

suantea commented Sep 22, 2026

Copy link
Copy Markdown
Collaborator Author

分支已 restack 到当前 main,请重评

按维护者建议(#87 上「每个 PR 都基于 main 重新创建,PR 之间的修改不要重叠」),本分支已重建。

问题背景:本分支此前的 merge-base 停在 dc2877b(#80 合并点),且 #113–#118 这几个 commit 同时挂在多条分支上,导致 PR 的 GitHub diff 被放大成"巨型回退补丁",评审看到的是累积 diff 而非本 PR 的真实增量。

本次变更:仅把本分支自身的 commit cherry-pick 到当前 main。

  • 旧 head:11dc22a
  • 新 head:e5509b0

有一处需要说明:原 commit 的父提交带有 #114(数据保留清理器)的代码,因此该 commit 的 diff 里混入了一段恢复 backend/main.go 中 retention 接线的改动。这段内容本不属于「仅加 HTTP 超时」这一主题,restack 到当前 main 后已自然剔除。新 head 的 diff 只包含本 PR 的真实意图:

backend/main.go | 10 ++++++++++

即 ReadTimeout / ReadHeaderTimeout / WriteTimeout=0 / IdleTimeout / MaxHeaderBytes(WriteTimeout 保持 0 是因为 SSE 与 WebSocket 长连接)。

已验证:go build ./... 通过。

请在新 head 上重评。

@pikachuren pikachuren left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🙏 感谢 @suantea 提交!
🤖 AI 自动审核声明:本评审报告由 AI 自动生成,当前使用 Claude Opus 5 模型进行分析。
⚠️ AI 分析结果仅供参考,可能存在误判或遗漏。如您发现任何问题或有不同意见,欢迎随时提出讨论和纠正。
⚠️ 重要提醒:即使 AI 评审认为代码质量良好且建议合并,最终是否合并仍需由项目维护者进行人工判定。项目维护者会综合考虑代码质量、项目规划、技术方向、团队资源等多方面因素做出是否合并的决策。

🔄 增量评审:上轮 → 本轮

本轮无新增内容改动 —— 分支被 rebase 到 #85 合入后的 main(dc2877b → 26c4301)。已用 git diff 11dc22a1 e5509b0f -- <本PR自身文件> 逐文件核对,结果为空,改动内容与上轮评审时逐字一致(HEAD 变化仅来自 rebase)。

新增改动的问题:无(纯 rebase)。

旧问题解决情况:

  • ⏳ [原评审] 本轮 diff 由 -10/+11 变为 10 insertions(+),即 http.Server 超时配置从「改动现有字面量」变为「新增显式字段赋值」。语义等价,无新增问题。
  • 💡 建议确认 ReadHeaderTimeout 是否一并设置(仅设 ReadTimeout 时,慢速发 header 的连接仍会长时间占用 goroutine 直到 ReadTimeout 到期)。如已在别处处理可忽略。

🎯 结论:🔄 Request Changes — 内容未变,上轮问题状态同上

@pikachuren pikachuren left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🙏 感谢 @suantea 提交!
🤖 AI 自动审核声明。⚠️ 最终合并决策由项目维护者判定。

🎯 结论

🔄 Request Changes — WriteTimeout=0 的权衡及 hijacked 连接读超时风险需验证

📖 概要

给 http.Server 增加读/空闲超时防止慢客户端资源耗尽(10行改动)

🚨 关键问题

P1:

  • 💡 WriteTimeout=0 是全局配置,对所有路由生效而非仅 SSE/WS 路由,普通 JSON API 的慢速读取客户端仍可无限期占住连接。建议改用 Go 1.20+ 的 http.ResponseController(w).SetWriteDeadline(...),仅在 SSE/WS handler 里显式清除写超时,其余路由保留合理的全局 WriteTimeout。
  • 💡 ReadTimeout=30s 会在 handler 调用前基于此值设置 deadline,如果 WebSocket/终端升级的 handler 在 Hijack() 后没有显式清除该 deadline,长连接会在建立后 30 秒被意外断开,与本 PR"不掐断 WS/终端"的设计目标矛盾,需要验证。

P2:若存在大文件上传接口,ReadTimeout 覆盖整个请求体读取过程,慢网络下可能被意外中断。

🎯 结论:🔄 Request Changes — 方向正确(行业标准 Slowloris 防护实践),但需验证 WS/终端场景不受影响后合并

- ReadTimeout 30s / ReadHeaderTimeout 10s / IdleTimeout 120s / MaxHeaderBytes 1MB
- WriteTimeout 保持 0:AI 对话与 CF 隧道日志走 SSE、终端走 WebSocket,写超时会掐断长连接
@suantea
suantea force-pushed the fix/http-server-timeout branch from e5509b0 to 9ad41ee Compare September 30, 2026 08:34

This branch has not been deployed

No deployments
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