fix remaining framework contract gaps
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -10,6 +11,11 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// DefaultMaxJSONBodyBytes 是 BindJSON 的默认请求体上限。
|
||||
// 入口层无上限读 JSON 会让任意 handler 暴露 OOM 面;需要更大请求体的业务可改用
|
||||
// BindJSONWithMaxBytes 显式声明上限。
|
||||
const DefaultMaxJSONBodyBytes int64 = 1 << 20 // 1 MiB
|
||||
|
||||
// HealthCheck 健康检查
|
||||
// @Summary 健康检查
|
||||
// @Description 检查服务是否正常运行
|
||||
@@ -28,6 +34,16 @@ func HealthCheck(c *gin.Context) {
|
||||
|
||||
// BindJSON 绑定 JSON 请求
|
||||
func BindJSON(c *gin.Context, req any) error {
|
||||
return BindJSONWithMaxBytes(c, req, DefaultMaxJSONBodyBytes)
|
||||
}
|
||||
|
||||
// BindJSONWithMaxBytes 绑定 JSON 请求,并限制最大 body 大小。
|
||||
// maxBytes<=0 时返回明确错误,避免 http.MaxBytesReader 的非正上限产生不可读语义。
|
||||
func BindJSONWithMaxBytes(c *gin.Context, req any, maxBytes int64) error {
|
||||
if maxBytes <= 0 {
|
||||
return errors.New("handler: max JSON body bytes must be positive")
|
||||
}
|
||||
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, maxBytes)
|
||||
return c.ShouldBindJSON(req)
|
||||
}
|
||||
|
||||
|
||||
+29
-5
@@ -62,8 +62,8 @@ func TestQueryInt(t *testing.T) {
|
||||
expected int
|
||||
}{
|
||||
{"?page=10", 10},
|
||||
{"?page=abc", 1}, // 无效返回默认
|
||||
{"", 1}, // 无参数返回默认
|
||||
{"?page=abc", 1}, // 无效返回默认
|
||||
{"", 1}, // 无参数返回默认
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -185,9 +185,9 @@ func TestGetPage(t *testing.T) {
|
||||
expectedSize int
|
||||
}{
|
||||
{"?page=2&page_size=50", 2, 50},
|
||||
{"?page=0&page_size=0", 1, 20}, // 边界修正
|
||||
{"?page=0&page_size=0", 1, 20}, // 边界修正
|
||||
{"?page=-1&page_size=200", 1, 100}, // 超限修正
|
||||
{"", 1, 20}, // 默认值
|
||||
{"", 1, 20}, // 默认值
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -387,4 +387,28 @@ func TestBindJSON(t *testing.T) {
|
||||
if w.Code != 200 {
|
||||
t.Errorf("BindJSON valid status = %d", w.Code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBindJSONWithMaxBytesRejectsOversizedBody_M6(t *testing.T) {
|
||||
r := setupTestRouter()
|
||||
r.POST("/test", func(c *gin.Context) {
|
||||
var req struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
if err := handler.BindJSONWithMaxBytes(c, &req, 8); err == nil {
|
||||
c.JSON(http.StatusOK, req)
|
||||
return
|
||||
}
|
||||
handler.BadRequest(c, "绑定失败")
|
||||
})
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest("POST", "/test", strings.NewReader(`{"name":"body-too-large"}`))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
r.ServeHTTP(w, req)
|
||||
|
||||
body := decodeBody(t, w)
|
||||
if body.Code != response.CodeFail {
|
||||
t.Fatalf("oversized BindJSON code = %d, want %d", body.Code, response.CodeFail)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user