mirror of
https://github.com/gin-gonic/gin.git
synced 2025-12-03 05:12:17 +08:00
fix(gin): literal colon routes not working with engine.Handler() (#4415)
* fix: call updateRouteTrees in ServeHTTP using sync.Once to support literal colon routes in all usage scenarios (#4413) * chore: fixed golangci-lint issue in test cases for literal colon * fix: gofumpt formatting issue * fix: gofumpt issue in gin.go * chore: updated routeTreesUpdated comments * chore: removed unused variable and updated TestUpdateRouteTreesCalledOnce testcase * chore: moved tests from literal_colon_test.go into gin_test.go --------- Co-authored-by: pawannn <pawan@zenz.tech>
This commit is contained in:
parent
93ff771e6d
commit
5fad976b37
8
gin.go
8
gin.go
@ -98,6 +98,10 @@ const (
|
|||||||
type Engine struct {
|
type Engine struct {
|
||||||
RouterGroup
|
RouterGroup
|
||||||
|
|
||||||
|
// routeTreesUpdated ensures that the initialization or update of the route trees
|
||||||
|
// (used for routing HTTP requests) happens only once, even if called multiple times concurrently.
|
||||||
|
routeTreesUpdated sync.Once
|
||||||
|
|
||||||
// RedirectTrailingSlash enables automatic redirection if the current route can't be matched but a
|
// RedirectTrailingSlash enables automatic redirection if the current route can't be matched but a
|
||||||
// handler for the path with (without) the trailing slash exists.
|
// handler for the path with (without) the trailing slash exists.
|
||||||
// For example if /foo/ is requested but a route only exists for /foo, the
|
// For example if /foo/ is requested but a route only exists for /foo, the
|
||||||
@ -654,6 +658,10 @@ func (engine *Engine) RunListener(listener net.Listener) (err error) {
|
|||||||
|
|
||||||
// ServeHTTP conforms to the http.Handler interface.
|
// ServeHTTP conforms to the http.Handler interface.
|
||||||
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
|
engine.routeTreesUpdated.Do(func() {
|
||||||
|
engine.updateRouteTrees()
|
||||||
|
})
|
||||||
|
|
||||||
c := engine.pool.Get().(*Context)
|
c := engine.pool.Get().(*Context)
|
||||||
c.writermem.reset(w)
|
c.writermem.reset(w)
|
||||||
c.Request = req
|
c.Request = req
|
||||||
|
|||||||
99
gin_test.go
99
gin_test.go
@ -913,3 +913,102 @@ func TestMethodNotAllowedNoRoute(t *testing.T) {
|
|||||||
assert.NotPanics(t, func() { g.ServeHTTP(resp, req) })
|
assert.NotPanics(t, func() { g.ServeHTTP(resp, req) })
|
||||||
assert.Equal(t, http.StatusNotFound, resp.Code)
|
assert.Equal(t, http.StatusNotFound, resp.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test the fix for https://github.com/gin-gonic/gin/pull/4415
|
||||||
|
func TestLiteralColonWithRun(t *testing.T) {
|
||||||
|
SetMode(TestMode)
|
||||||
|
router := New()
|
||||||
|
|
||||||
|
router.GET(`/test\:action`, func(c *Context) {
|
||||||
|
c.JSON(http.StatusOK, H{"path": "literal_colon"})
|
||||||
|
})
|
||||||
|
|
||||||
|
router.updateRouteTrees()
|
||||||
|
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
req, _ := http.NewRequest(http.MethodGet, "/test:action", nil)
|
||||||
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
assert.Contains(t, w.Body.String(), "literal_colon")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLiteralColonWithDirectServeHTTP(t *testing.T) {
|
||||||
|
SetMode(TestMode)
|
||||||
|
router := New()
|
||||||
|
|
||||||
|
router.GET(`/test\:action`, func(c *Context) {
|
||||||
|
c.JSON(http.StatusOK, H{"path": "literal_colon"})
|
||||||
|
})
|
||||||
|
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
req, _ := http.NewRequest(http.MethodGet, "/test:action", nil)
|
||||||
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
assert.Contains(t, w.Body.String(), "literal_colon")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLiteralColonWithHandler(t *testing.T) {
|
||||||
|
SetMode(TestMode)
|
||||||
|
router := New()
|
||||||
|
|
||||||
|
router.GET(`/test\:action`, func(c *Context) {
|
||||||
|
c.JSON(http.StatusOK, H{"path": "literal_colon"})
|
||||||
|
})
|
||||||
|
|
||||||
|
handler := router.Handler()
|
||||||
|
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
req, _ := http.NewRequest(http.MethodGet, "/test:action", nil)
|
||||||
|
handler.ServeHTTP(w, req)
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
assert.Contains(t, w.Body.String(), "literal_colon")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLiteralColonWithHTTPServer(t *testing.T) {
|
||||||
|
SetMode(TestMode)
|
||||||
|
router := New()
|
||||||
|
|
||||||
|
router.GET(`/test\:action`, func(c *Context) {
|
||||||
|
c.JSON(http.StatusOK, H{"path": "literal_colon"})
|
||||||
|
})
|
||||||
|
|
||||||
|
router.GET("/test/:param", func(c *Context) {
|
||||||
|
c.JSON(http.StatusOK, H{"param": c.Param("param")})
|
||||||
|
})
|
||||||
|
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
req, _ := http.NewRequest(http.MethodGet, "/test:action", nil)
|
||||||
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
assert.Contains(t, w.Body.String(), "literal_colon")
|
||||||
|
|
||||||
|
w2 := httptest.NewRecorder()
|
||||||
|
req2, _ := http.NewRequest(http.MethodGet, "/test/foo", nil)
|
||||||
|
router.ServeHTTP(w2, req2)
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, w2.Code)
|
||||||
|
assert.Contains(t, w2.Body.String(), "foo")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that updateRouteTrees is called only once
|
||||||
|
func TestUpdateRouteTreesCalledOnce(t *testing.T) {
|
||||||
|
SetMode(TestMode)
|
||||||
|
router := New()
|
||||||
|
|
||||||
|
router.GET(`/test\:action`, func(c *Context) {
|
||||||
|
c.String(http.StatusOK, "ok")
|
||||||
|
})
|
||||||
|
|
||||||
|
for range 5 {
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
req, _ := http.NewRequest(http.MethodGet, "/test:action", nil)
|
||||||
|
router.ServeHTTP(w, req)
|
||||||
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
assert.Equal(t, "ok", w.Body.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user