mirror of
https://github.com/gin-gonic/gin.git
synced 2026-09-04 14:49:27 +08:00
fix: reset skippedNodes in HandleMethodNotAllowed loop to prevent panic
Fixes #4818 When HandleMethodNotAllowed is enabled, the handleHTTPRequest method loops through all method trees calling getValue() with the same skippedNodes slice. Since getValue() appends to skippedNodes without clearing it, and the slice cannot grow beyond its initial capacity (engine.maxSections), accumulated entries from previous iterations can cause a slice bounds panic when the reslice operation exceeds capacity. This fix resets skippedNodes to length 0 before each getValue() call in the HandleMethodNotAllowed loop, preventing accumulation across multiple method trees. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
parent
dcaa4296d1
commit
c7a67900ae
3
gin.go
3
gin.go
@ -743,6 +743,9 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
|
||||
if tree.method == httpMethod {
|
||||
continue
|
||||
}
|
||||
// Reset skippedNodes before each getValue call to prevent accumulation
|
||||
// across multiple method trees, which could cause slice bounds panic
|
||||
*c.skippedNodes = (*c.skippedNodes)[:0]
|
||||
if value := tree.root.getValue(rPath, nil, c.skippedNodes, unescape); value.handlers != nil {
|
||||
allowed = append(allowed, tree.method)
|
||||
}
|
||||
|
||||
37
gin_test_issue_4818.go
Normal file
37
gin_test_issue_4818.go
Normal file
@ -0,0 +1,37 @@
|
||||
package gin
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHandleMethodNotAllowedSkippedNodesPanic(t *testing.T) {
|
||||
SetMode(ReleaseMode)
|
||||
router := New()
|
||||
router.HandleMethodNotAllowed = true
|
||||
|
||||
h := func(c *Context) {}
|
||||
router.OPTIONS("/:p0/:p1/a/:p2", h)
|
||||
router.GET("/:p0/:p1/a/:p2", h)
|
||||
router.PATCH("/b/:p0/:p1/c", h)
|
||||
router.DELETE("/b/:p0/:p1/d/:p3", h)
|
||||
router.GET("/b/:p0/:p1/e/f", h)
|
||||
router.POST("/b/:p0/:p1/g/:p4/h", h)
|
||||
router.OPTIONS("/b/:p0/:p1/g/:p4/h", h)
|
||||
router.DELETE("/b/cache", h)
|
||||
router.GET("/b/clients/:p1/g", h)
|
||||
router.POST("/b/clients/:p1/g", h)
|
||||
router.PATCH("/b/clients/:p1/g/:p4", h)
|
||||
router.OPTIONS("/b/clients/:p1/g/:p4", h)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/b/clients/42", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
// This should return 405 Method Not Allowed, not panic
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusMethodNotAllowed {
|
||||
t.Errorf("Expected status 405, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user