Compare commits

...

2 Commits

Author SHA1 Message Date
goingforstudying-ctrl
8234f242db fix(deps): bump quic-go to v0.59.1 to resolve CVE-2026-40898 2026-06-04 22:07:01 +00:00
goingforstudying-ctrl
e3d8bf2305 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
2026-06-04 21:42:09 +00:00
4 changed files with 73 additions and 3 deletions

11
gin.go
View File

@ -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)
}

View File

@ -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")
}

2
go.mod
View File

@ -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

4
go.sum
View File

@ -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=