Description
Setting HandleMethodNotAllowed
on the engine and configuring the routes in a intricate way, gin panics when a certain request is sent. See details below on how to reproduce.
How to reproduce
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.HandleMethodNotAllowed = true
r.GET("/base/metrics", handler)
r.GET("/base/v1/:id/devices", handler)
r.GET("/base/v1/user/:id/groups", handler)
r.GET("/base/v1/organizations/:id", handler)
r.DELETE("/base/v1/organizations/:id", handler)
r.Run()
}
Now, make a GET
on "localhost:8080/base/v1/user/groups", in which case gin panics.
I must admit that the above setup is a bit off, with how ".../:id/devices" and ".../user/:id/groups" is overlapping somewhat, but I still do not expect a panic. If the setup of the routes truly is wrong, then I would expect a panic to happen earlier, either at r.GET()
or r.Run()
.
I've also tried to delete some of the routes to minimize the example, but it seems that all lines are needed for this to fail, which further emphasize that this is a corner case.
Expectations
$ curl http://localhost:8080/base/v1/user/groups
404 page not found
Actual result
$ curl -i http://localhost:8080/base/v1/user/groups
curl: (52) Empty reply from server
With the following log message from the gin app:
2023/01/03 10:16:50 http: panic serving 127.0.0.1:56181: runtime error: index out of range [0] with length 0
goroutine 34 [running]:
net/http.(*conn).serve.func1()
/usr/local/go/src/net/http/server.go:1850 +0xb0
panic({0x1053aefe0, 0x140000260f0})
/usr/local/go/src/runtime/panic.go:890 +0x258
github.com/gin-gonic/gin.(*node).getValue(0x1400012d938?, {0x14000520244?, 0x1400012d9d8?}, 0x0, 0x1400000e030, 0x0)
/Users/kristiansvalland/go/pkg/mod/github.com/gin-gonic/gin@v1.8.2/tree.go:637 +0x378
github.com/gin-gonic/gin.(*Engine).handleHTTPRequest(0x1400054c4e0, 0x140000ae000)
/Users/kristiansvalland/go/pkg/mod/github.com/gin-gonic/gin@v1.8.2/gin.go:637 +0x474
github.com/gin-gonic/gin.(*Engine).ServeHTTP(0x1400054c4e0, {0x1053d9df8?, 0x140000a8000}, 0x14000512100)
/Users/kristiansvalland/go/pkg/mod/github.com/gin-gonic/gin@v1.8.2/gin.go:572 +0x1d4
net/http.serverHandler.ServeHTTP({0x14000502e70?}, {0x1053d9df8, 0x140000a8000}, 0x14000512100)
/usr/local/go/src/net/http/server.go:2947 +0x2c4
net/http.(*conn).serve(0x1400051ab40, {0x1053da5e0, 0x14000502d80})
/usr/local/go/src/net/http/server.go:1991 +0x560
created by net/http.(*Server).Serve
/usr/local/go/src/net/http/server.go:3102 +0x444
Environment
- go version: go1.19.4
- gin version (or commit ref): v1.8.2 and master
- operating system: MacOS
Suggested fix
As hinted by in the backtrace, the panic occurs in tree.go#L637
, specifically here (with commentary and suggested fix commented):
if !value.tsr && path != "/" {
for l := len(*skippedNodes); l > 0; {
skippedNode := (*skippedNodes)[l-1] // <-- Panic occurs here in the second round of the for loop
*skippedNodes = (*skippedNodes)[:l-1]
l-- // suggested fix
if strings.HasSuffix(skippedNode.path, path) {
path = skippedNode.path
n = skippedNode.node
if value.params != nil {
*value.params = (*value.params)[:skippedNode.paramsCount]
}
globalParamsCount = skippedNode.paramsCount
continue walk
}
}
}
Note: The above logic happens three places in tree.go
, so they should probably also be fixed at the same time.
Capacity for working on this
I have already created a test and fix for this issue, which I will create a PR for promptly.