From fdfaab521b6fa0fad46951d1191d07ccb5c621ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Garamv=C3=B6lgyi?= Date: Thu, 22 Oct 2026 10:50:22 +0200 Subject: [PATCH] fix: API hardening for bridge-history and shared metrics --- bridge-history-api/cmd/api/app/app.go | 9 ++++++++- .../internal/logic/history_logic.go | 2 +- bridge-history-api/internal/types/schema.go | 2 +- common/observability/ginmetrics/middleware.go | 16 ++++++++++++++-- common/version/version.go | 2 +- 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/bridge-history-api/cmd/api/app/app.go b/bridge-history-api/cmd/api/app/app.go index 12c07d732a..66c31d3d37 100644 --- a/bridge-history-api/cmd/api/app/app.go +++ b/bridge-history-api/cmd/api/app/app.go @@ -3,6 +3,7 @@ package app import ( "crypto/tls" "fmt" + "net/http" "os" "os/signal" "time" @@ -79,7 +80,13 @@ func action(ctx *cli.Context) error { go func() { port := ctx.Int(utils.ServicePortFlag.Name) - if runServerErr := router.Run(fmt.Sprintf(":%d", port)); runServerErr != nil { + server := &http.Server{ + Addr: fmt.Sprintf(":%d", port), + Handler: router, + ReadHeaderTimeout: 10 * time.Second, + ReadTimeout: 30 * time.Second, + } + if runServerErr := server.ListenAndServe(); runServerErr != nil { log.Crit("run http server failure", "error", runServerErr) } }() diff --git a/bridge-history-api/internal/logic/history_logic.go b/bridge-history-api/internal/logic/history_logic.go index 4dbf9ba812..cb613fd945 100644 --- a/bridge-history-api/internal/logic/history_logic.go +++ b/bridge-history-api/internal/logic/history_logic.go @@ -473,7 +473,7 @@ func (h *HistoryLogic) processAndCacheTxHistoryInfo(ctx context.Context, cacheKe if !isHit { log.Error("cache miss after write, expect hit", "cached key", cacheKey, "page", page, "page size", pageSize, "error", err) - return nil, 0, err + return nil, 0, errors.New("cache miss after write") } return pagedTxs, total, nil diff --git a/bridge-history-api/internal/types/schema.go b/bridge-history-api/internal/types/schema.go index 78cbfd7011..d6baad13b5 100644 --- a/bridge-history-api/internal/types/schema.go +++ b/bridge-history-api/internal/types/schema.go @@ -26,7 +26,7 @@ const ( // QueryByAddressRequest the request parameter of address api type QueryByAddressRequest struct { Address string `form:"address" binding:"required,eth_addr"` - Page uint64 `form:"page" binding:"required,min=1"` + Page uint64 `form:"page" binding:"required,min=1,max=10000"` PageSize uint64 `form:"page_size" binding:"required,min=1,max=100"` } diff --git a/common/observability/ginmetrics/middleware.go b/common/observability/ginmetrics/middleware.go index 79f74bee0d..a2c5ba273a 100644 --- a/common/observability/ginmetrics/middleware.go +++ b/common/observability/ginmetrics/middleware.go @@ -2,6 +2,7 @@ package ginmetrics import ( "fmt" + "net/http" "strconv" "time" @@ -131,7 +132,7 @@ func (m *Monitor) ginMetricHandle(ctx *gin.Context, start time.Time) { } // set uri request total - _ = m.GetMetric(metricURIRequestTotal).Inc([]string{ctx.FullPath(), r.Method, errCode}) + _ = m.GetMetric(metricURIRequestTotal).Inc([]string{ctx.FullPath(), metricMethod(r.Method), errCode}) // set request body size // since r.ContentLength can be negative (in some occasions) guard the operation @@ -142,7 +143,7 @@ func (m *Monitor) ginMetricHandle(ctx *gin.Context, start time.Time) { // set slow request latency := time.Since(start) if int32(latency.Seconds()) > m.slowTime { - _ = m.GetMetric(metricSlowRequest).Inc([]string{ctx.FullPath(), r.Method, strconv.Itoa(w.Status())}) + _ = m.GetMetric(metricSlowRequest).Inc([]string{ctx.FullPath(), metricMethod(r.Method), strconv.Itoa(w.Status())}) } // set request duration @@ -153,3 +154,14 @@ func (m *Monitor) ginMetricHandle(ctx *gin.Context, start time.Time) { _ = m.GetMetric(metricResponseBody).Add(nil, float64(w.Size())) } } + +// metricMethod bounds the method label, since clients can send any method token. +func metricMethod(method string) string { + switch method { + case http.MethodGet, http.MethodHead, http.MethodPost, http.MethodPut, http.MethodPatch, + http.MethodDelete, http.MethodConnect, http.MethodOptions, http.MethodTrace: + return method + default: + return "OTHER" + } +} diff --git a/common/version/version.go b/common/version/version.go index 5299b102c8..566d9ce4b2 100644 --- a/common/version/version.go +++ b/common/version/version.go @@ -5,7 +5,7 @@ import ( "runtime/debug" ) -var tag = "v4.8.2" +var tag = "v4.8.3" var commit = func() string { if info, ok := debug.ReadBuildInfo(); ok {