fix: 限制管理接口请求体大小与读取时间

This commit is contained in:
Nixevol
2026-09-30 16:22:48 +08:00
parent b40ef5c548
commit 1a4bf6f185
7 changed files with 170 additions and 8 deletions
+35 -1
View File
@@ -1,6 +1,7 @@
package admin
import (
"errors"
"log/slog"
"net"
"net/http"
@@ -11,6 +12,7 @@ import (
"git.asio.asia/nixevol/NixMsg/internal/app/identity"
"git.asio.asia/nixevol/NixMsg/internal/auth"
"git.asio.asia/nixevol/NixMsg/internal/config"
"git.asio.asia/nixevol/NixMsg/internal/httpx"
"git.asio.asia/nixevol/NixMsg/internal/store"
)
@@ -23,6 +25,13 @@ const (
defaultSessionTTL = 12 * time.Hour
minPasswordLen = 12
lastUsedMinGap = time.Minute
maxLoginBodyBytes = 8 << 10
maxJSONBodyBytes = 1 << 20
maxImportBodyBytes = 8 << 20
defaultReadFor = 15 * time.Second
loginReadFor = 10 * time.Second
importReadFor = 2 * time.Minute
)
// Deps 是管理 Handler 的依赖。
@@ -129,11 +138,36 @@ func New(d Deps) *Handler {
return h
}
// ServeHTTP 实现 http.Handler。
// ServeHTTP 实现 http.Handler。按路由限制请求体大小与读截止时间。
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
limit, readFor := requestBodyBudget(r)
if err := http.NewResponseController(w).SetReadDeadline(time.Now().Add(readFor)); err != nil && !errors.Is(err, http.ErrNotSupported) {
// 测试用 ResponseRecorder 或不支持截止时间的封装:忽略。
}
if r.Body != nil {
r.Body = http.MaxBytesReader(w, r.Body, limit)
}
h.mux.ServeHTTP(w, r)
}
func requestBodyBudget(r *http.Request) (int64, time.Duration) {
if r.Method == http.MethodPost && r.URL.Path == "/api/admin/endpoints/import" {
return maxImportBodyBytes, importReadFor
}
if r.Method == http.MethodPost && r.URL.Path == "/api/admin/login" {
return maxLoginBodyBytes, loginReadFor
}
return maxJSONBodyBytes, defaultReadFor
}
func writeDecodeError(w http.ResponseWriter, err error) {
if httpx.IsBodyTooLarge(err) {
httpx.WriteError(w, http.StatusRequestEntityTooLarge, "payload_too_large", "请求体过大")
return
}
httpx.WriteError(w, http.StatusBadRequest, "bad_request", "请求体无效")
}
func (h *Handler) routes() {
// 公开
h.mux.HandleFunc("POST /api/admin/login", h.handleLogin)