From e3d8bf23053c3ce369f4897f141746dfb5710fae Mon Sep 17 00:00:00 2001 From: goingforstudying-ctrl Date: Thu, 4 Jun 2026 21:42:09 +0000 Subject: [PATCH 1/2] feat: add SkipMethodNotAllowedMiddleware option Adds a new Engine option that, when enabled, prevents global middleware registered via Use() from being executed for 405 Method Not Allowed responses. This allows NoMethod handlers to run without triggering middleware that may reject the request (e.g., authentication, checksum validation) before the 405 response can be sent. Fixes gin-gonic/gin#4189 --- gin.go | 11 ++++++++++ gin_test.go | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/gin.go b/gin.go index 2e033bf3..0ffa3e91 100644 --- a/gin.go +++ b/gin.go @@ -122,6 +122,13 @@ type Engine struct { // handler. HandleMethodNotAllowed bool + // SkipMethodNotAllowedMiddleware if enabled, global middleware registered via Use() + // will not be executed for 405 Method Not Allowed responses. This allows + // NoMethod handlers to run without triggering middleware that may reject + // the request (e.g., authentication, checksum validation) before the 405 + // response can be sent. + SkipMethodNotAllowedMiddleware bool + // ForwardedByClientIP if enabled, client IP will be parsed from the request's headers that // match those stored at `(*gin.Engine).RemoteIPHeaders`. If no IP was // fetched, it falls back to the IP obtained from @@ -358,6 +365,10 @@ func (engine *Engine) rebuild404Handlers() { } func (engine *Engine) rebuild405Handlers() { + if engine.SkipMethodNotAllowedMiddleware { + engine.allNoMethod = engine.noMethod + return + } engine.allNoMethod = engine.combineHandlers(engine.noMethod) } diff --git a/gin_test.go b/gin_test.go index a9cf1755..dfb7ac6e 100644 --- a/gin_test.go +++ b/gin_test.go @@ -1156,3 +1156,62 @@ func TestUpdateRouteTreesCalledOnce(t *testing.T) { assert.Equal(t, "ok", w.Body.String()) } } + +// Test the fix for https://github.com/gin-gonic/gin/issues/4189 +func TestSkipMethodNotAllowedMiddleware(t *testing.T) { + g := New() + g.HandleMethodNotAllowed = true + g.SkipMethodNotAllowedMiddleware = true + + var middlewareCalled bool + middleware := func(c *Context) { + middlewareCalled = true + c.Next() + } + noMethodHandler := func(c *Context) { + c.String(http.StatusMethodNotAllowed, "method not allowed") + } + + g.Use(middleware) + g.NoMethod(noMethodHandler) + g.POST("/test", func(c *Context) { + c.String(http.StatusOK, "ok") + }) + + w := httptest.NewRecorder() + req, _ := http.NewRequest(http.MethodGet, "/test", nil) + g.ServeHTTP(w, req) + + assert.Equal(t, http.StatusMethodNotAllowed, w.Code) + assert.Equal(t, "method not allowed", w.Body.String()) + assert.False(t, middlewareCalled, "middleware should not be called when SkipMethodNotAllowedMiddleware is true") +} + +func TestSkipMethodNotAllowedMiddlewareDisabled(t *testing.T) { + g := New() + g.HandleMethodNotAllowed = true + g.SkipMethodNotAllowedMiddleware = false + + var middlewareCalled bool + middleware := func(c *Context) { + middlewareCalled = true + c.Next() + } + noMethodHandler := func(c *Context) { + c.String(http.StatusMethodNotAllowed, "method not allowed") + } + + g.Use(middleware) + g.NoMethod(noMethodHandler) + g.POST("/test", func(c *Context) { + c.String(http.StatusOK, "ok") + }) + + w := httptest.NewRecorder() + req, _ := http.NewRequest(http.MethodGet, "/test", nil) + g.ServeHTTP(w, req) + + assert.Equal(t, http.StatusMethodNotAllowed, w.Code) + assert.Equal(t, "method not allowed", w.Body.String()) + assert.True(t, middlewareCalled, "middleware should be called when SkipMethodNotAllowedMiddleware is false") +} From 8234f242dbc7cfe0e86453eee98adc0f306fdbd9 Mon Sep 17 00:00:00 2001 From: goingforstudying-ctrl Date: Thu, 4 Jun 2026 22:07:01 +0000 Subject: [PATCH 2/2] fix(deps): bump quic-go to v0.59.1 to resolve CVE-2026-40898 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index df181253..c67c5fed 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/mattn/go-isatty v0.0.20 github.com/modern-go/reflect2 v1.0.2 github.com/pelletier/go-toml/v2 v2.2.4 - github.com/quic-go/quic-go v0.59.0 + github.com/quic-go/quic-go v0.59.1 github.com/stretchr/testify v1.11.1 github.com/ugorji/go/codec v1.3.1 go.mongodb.org/mongo-driver/v2 v2.5.0 diff --git a/go.sum b/go.sum index f7f9e27b..e69bfeee 100644 --- a/go.sum +++ b/go.sum @@ -52,8 +52,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= -github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw= -github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= +github.com/quic-go/quic-go v0.59.1 h1:0Gmua0HW1Tv7ANR7hUYwRyD0MG5OJfgvYSZasGZzBic= +github.com/quic-go/quic-go v0.59.1/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=