fix: 限制管理接口请求体大小与读取时间
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user