mirror of
https://github.com/gin-gonic/gin.git
synced 2026-07-06 18:31:24 +08:00
Compare commits
6 Commits
03eaf659b1
...
a25fb34c64
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a25fb34c64 | ||
|
|
ecb3f7b5e2 | ||
|
|
96f63d68d3 | ||
|
|
5f94d6f3e8 | ||
|
|
51ef7a6a10 | ||
|
|
22b88e0ed1 |
22
gin.go
22
gin.go
@ -178,8 +178,10 @@ type Engine struct {
|
||||
FuncMap template.FuncMap
|
||||
allNoRoute HandlersChain
|
||||
allNoMethod HandlersChain
|
||||
allAutoRedirect HandlersChain
|
||||
noRoute HandlersChain
|
||||
noMethod HandlersChain
|
||||
autoRedirect HandlersChain
|
||||
pool sync.Pool
|
||||
trees methodTrees
|
||||
maxParams uint16
|
||||
@ -332,6 +334,13 @@ func (engine *Engine) NoMethod(handlers ...HandlerFunc) {
|
||||
engine.rebuild405Handlers()
|
||||
}
|
||||
|
||||
// AutoRedirect sets the handlers called when auto redirected
|
||||
// (RedirectTrailingSlash and RedirectFixedPath)
|
||||
func (engine *Engine) AutoRedirect(handlers ...HandlerFunc) {
|
||||
engine.autoRedirect = handlers
|
||||
engine.rebuildAutoRedirectHandlers()
|
||||
}
|
||||
|
||||
// Use attaches a global middleware to the router. i.e. the middleware attached through Use() will be
|
||||
// included in the handlers chain for every single request. Even 404, 405, static files...
|
||||
// For example, this is the right place for a logger or error management middleware.
|
||||
@ -339,6 +348,7 @@ func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
|
||||
engine.RouterGroup.Use(middleware...)
|
||||
engine.rebuild404Handlers()
|
||||
engine.rebuild405Handlers()
|
||||
engine.rebuildAutoRedirectHandlers()
|
||||
return engine
|
||||
}
|
||||
|
||||
@ -359,6 +369,10 @@ func (engine *Engine) rebuild405Handlers() {
|
||||
engine.allNoMethod = engine.combineHandlers(engine.noMethod)
|
||||
}
|
||||
|
||||
func (engine *Engine) rebuildAutoRedirectHandlers() {
|
||||
engine.allAutoRedirect = engine.combineHandlers(engine.autoRedirect)
|
||||
}
|
||||
|
||||
func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {
|
||||
assert1(path[0] == '/', "path must begin with '/'")
|
||||
assert1(method != "", "HTTP method can not be empty")
|
||||
@ -718,6 +732,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
|
||||
return
|
||||
}
|
||||
if httpMethod != http.MethodConnect && rPath != "/" {
|
||||
c.handlers = engine.allAutoRedirect
|
||||
if value.tsr && engine.RedirectTrailingSlash {
|
||||
redirectTrailingSlash(c)
|
||||
return
|
||||
@ -802,13 +817,14 @@ func redirectFixedPath(c *Context, root *node, trailingSlash bool) bool {
|
||||
|
||||
func redirectRequest(c *Context) {
|
||||
req := c.Request
|
||||
rPath := req.URL.Path
|
||||
rURL := req.URL.String()
|
||||
|
||||
code := http.StatusMovedPermanently // Permanent redirect, request with GET method
|
||||
if req.Method != http.MethodGet {
|
||||
code = http.StatusTemporaryRedirect
|
||||
}
|
||||
c.Next()
|
||||
|
||||
rPath := req.URL.Path
|
||||
rURL := req.URL.String()
|
||||
debugPrint("redirecting request %d: %s --> %s", code, rPath, rURL)
|
||||
http.Redirect(c.Writer, req, rURL, code)
|
||||
c.writermem.WriteHeaderNow()
|
||||
|
||||
53
gin_test.go
53
gin_test.go
@ -578,6 +578,59 @@ func TestNoMethodWithGlobalHandlers(t *testing.T) {
|
||||
compareFunc(t, router.allNoMethod[2], middleware0)
|
||||
}
|
||||
|
||||
func TestAutoRedirectWithoutGlobalHandlers(t *testing.T) {
|
||||
var middleware0 HandlerFunc = func(c *Context) {}
|
||||
var middleware1 HandlerFunc = func(c *Context) {}
|
||||
|
||||
router := New()
|
||||
|
||||
router.AutoRedirect(middleware0)
|
||||
assert.Nil(t, router.Handlers)
|
||||
assert.Len(t, router.autoRedirect, 1)
|
||||
assert.Len(t, router.allAutoRedirect, 1)
|
||||
compareFunc(t, router.autoRedirect[0], middleware0)
|
||||
compareFunc(t, router.allAutoRedirect[0], middleware0)
|
||||
|
||||
router.AutoRedirect(middleware1, middleware0)
|
||||
assert.Len(t, router.autoRedirect, 2)
|
||||
assert.Len(t, router.allAutoRedirect, 2)
|
||||
compareFunc(t, router.autoRedirect[0], middleware1)
|
||||
compareFunc(t, router.allAutoRedirect[0], middleware1)
|
||||
compareFunc(t, router.autoRedirect[1], middleware0)
|
||||
compareFunc(t, router.allAutoRedirect[1], middleware0)
|
||||
}
|
||||
|
||||
func TestAutoRedirectWithGlobalHandlers(t *testing.T) {
|
||||
var middleware0 HandlerFunc = func(c *Context) {}
|
||||
var middleware1 HandlerFunc = func(c *Context) {}
|
||||
var middleware2 HandlerFunc = func(c *Context) {}
|
||||
|
||||
router := New()
|
||||
router.Use(middleware2)
|
||||
|
||||
router.AutoRedirect(middleware0)
|
||||
assert.Len(t, router.allAutoRedirect, 2)
|
||||
assert.Len(t, router.Handlers, 1)
|
||||
assert.Len(t, router.autoRedirect, 1)
|
||||
|
||||
compareFunc(t, router.Handlers[0], middleware2)
|
||||
compareFunc(t, router.autoRedirect[0], middleware0)
|
||||
compareFunc(t, router.allAutoRedirect[0], middleware2)
|
||||
compareFunc(t, router.allAutoRedirect[1], middleware0)
|
||||
|
||||
router.Use(middleware1)
|
||||
assert.Len(t, router.allAutoRedirect, 3)
|
||||
assert.Len(t, router.Handlers, 2)
|
||||
assert.Len(t, router.autoRedirect, 1)
|
||||
|
||||
compareFunc(t, router.Handlers[0], middleware2)
|
||||
compareFunc(t, router.Handlers[1], middleware1)
|
||||
compareFunc(t, router.autoRedirect[0], middleware0)
|
||||
compareFunc(t, router.allAutoRedirect[0], middleware2)
|
||||
compareFunc(t, router.allAutoRedirect[1], middleware1)
|
||||
compareFunc(t, router.allAutoRedirect[2], middleware0)
|
||||
}
|
||||
|
||||
func compareFunc(t *testing.T, a, b any) {
|
||||
sf1 := reflect.ValueOf(a)
|
||||
sf2 := reflect.ValueOf(b)
|
||||
|
||||
2
go.mod
2
go.mod
@ -35,7 +35,7 @@ require (
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
golang.org/x/arch v0.20.0 // indirect
|
||||
golang.org/x/crypto v0.44.0 // indirect
|
||||
golang.org/x/crypto v0.45.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
4
go.sum
4
go.sum
@ -74,8 +74,8 @@ go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||
golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c=
|
||||
golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
|
||||
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
|
||||
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
||||
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
||||
@ -273,6 +273,27 @@ func TestRouteRedirectFixedPath(t *testing.T) {
|
||||
assert.Equal(t, http.StatusTemporaryRedirect, w.Code)
|
||||
}
|
||||
|
||||
func TestRouteRedirectWithHandler(t *testing.T) {
|
||||
router := New()
|
||||
router.RedirectTrailingSlash = true
|
||||
router.GET("/path", func(c *Context) {})
|
||||
passed := []bool{false, false}
|
||||
router.Use(func(c *Context) {
|
||||
passed[0] = true
|
||||
c.Next()
|
||||
})
|
||||
router.AutoRedirect(func(c *Context) {
|
||||
passed[1] = true
|
||||
c.Next()
|
||||
})
|
||||
|
||||
w := performRequest(router, http.MethodGet, "/path/")
|
||||
assert.Equal(t, "/path", w.Header().Get("Location"))
|
||||
assert.Equal(t, http.StatusMovedPermanently, w.Code)
|
||||
assert.True(t, passed[0])
|
||||
assert.True(t, passed[1])
|
||||
}
|
||||
|
||||
// TestContextParamsGet tests that a parameter can be parsed from the URL.
|
||||
func TestRouteParamsByName(t *testing.T) {
|
||||
name := ""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user