mirror of
https://github.com/gin-gonic/gin.git
synced 2026-07-05 01:31:21 +08:00
Merge 232172b7e4237f70561e404992267788f33f906d into c3d5a28ed6d3849da820195b6774d212bcc038a9
This commit is contained in:
commit
8ed70764ce
24
gin.go
24
gin.go
@ -23,10 +23,12 @@ import (
|
|||||||
"golang.org/x/net/http2/h2c"
|
"golang.org/x/net/http2/h2c"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultMultipartMemory = 32 << 20 // 32 MB
|
const (
|
||||||
const escapedColon = "\\:"
|
defaultMultipartMemory = 32 << 20 // 32 MB
|
||||||
const colon = ":"
|
escapedColon = "\\:"
|
||||||
const backslash = "\\"
|
colon = ":"
|
||||||
|
backslash = "\\"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
default404Body = []byte("404 page not found")
|
default404Body = []byte("404 page not found")
|
||||||
@ -46,8 +48,10 @@ var defaultTrustedCIDRs = []*net.IPNet{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var regSafePrefix = regexp.MustCompile("[^a-zA-Z0-9/-]+")
|
var (
|
||||||
var regRemoveRepeatedChar = regexp.MustCompile("/{2,}")
|
regSafePrefix = regexp.MustCompile("[^a-zA-Z0-9/-]+")
|
||||||
|
regRemoveRepeatedChar = regexp.MustCompile("/{2,}")
|
||||||
|
)
|
||||||
|
|
||||||
// HandlerFunc defines the handler used by gin middleware as return value.
|
// HandlerFunc defines the handler used by gin middleware as return value.
|
||||||
type HandlerFunc func(*Context)
|
type HandlerFunc func(*Context)
|
||||||
@ -94,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
|
||||||
@ -636,6 +644,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
|
||||||
|
|||||||
107
literal_colon_test.go
Normal file
107
literal_colon_test.go
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
package gin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
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