mirror of
https://github.com/gin-gonic/gin.git
synced 2026-06-13 00:59:29 +08:00
Compare commits
8 Commits
70e4bbb6f7
...
c1340d4016
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1340d4016 | ||
|
|
81dba46872 | ||
|
|
0c219e7902 | ||
|
|
00900fb3e1 | ||
|
|
96f63d68d3 | ||
|
|
5f94d6f3e8 | ||
|
|
51ef7a6a10 | ||
|
|
22b88e0ed1 |
4
.github/workflows/gin.yml
vendored
4
.github/workflows/gin.yml
vendored
@ -26,14 +26,14 @@ jobs:
|
||||
- name: Setup golangci-lint
|
||||
uses: golangci/golangci-lint-action@v9
|
||||
with:
|
||||
version: v2.6
|
||||
version: v2.9
|
||||
args: --verbose
|
||||
test:
|
||||
needs: lint
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
go: ["1.24", "1.25"]
|
||||
go: ["1.24", "1.25", "1.26"]
|
||||
test-tags:
|
||||
[
|
||||
"",
|
||||
|
||||
32
.github/workflows/trivy-scan.yml
vendored
32
.github/workflows/trivy-scan.yml
vendored
@ -9,7 +9,7 @@ on:
|
||||
- master
|
||||
schedule:
|
||||
# Run daily at 00:00 UTC
|
||||
- cron: '0 0 * * *'
|
||||
- cron: "0 0 * * *"
|
||||
workflow_dispatch: # Allow manual trigger
|
||||
|
||||
permissions:
|
||||
@ -27,30 +27,30 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Run Trivy vulnerability scanner (source code)
|
||||
uses: aquasecurity/trivy-action@0.34.0
|
||||
uses: aquasecurity/trivy-action@0.34.1
|
||||
with:
|
||||
scan-type: 'fs'
|
||||
scan-ref: '.'
|
||||
scanners: 'vuln,secret,misconfig'
|
||||
format: 'sarif'
|
||||
output: 'trivy-results.sarif'
|
||||
severity: 'CRITICAL,HIGH,MEDIUM'
|
||||
scan-type: "fs"
|
||||
scan-ref: "."
|
||||
scanners: "vuln,secret,misconfig"
|
||||
format: "sarif"
|
||||
output: "trivy-results.sarif"
|
||||
severity: "CRITICAL,HIGH,MEDIUM"
|
||||
ignore-unfixed: true
|
||||
|
||||
- name: Upload Trivy results to GitHub Security tab
|
||||
uses: github/codeql-action/upload-sarif@v4
|
||||
if: always()
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
sarif_file: "trivy-results.sarif"
|
||||
|
||||
- name: Run Trivy scanner (table output for logs)
|
||||
uses: aquasecurity/trivy-action@0.34.0
|
||||
uses: aquasecurity/trivy-action@0.34.1
|
||||
if: always()
|
||||
with:
|
||||
scan-type: 'fs'
|
||||
scan-ref: '.'
|
||||
scanners: 'vuln,secret,misconfig'
|
||||
format: 'table'
|
||||
severity: 'CRITICAL,HIGH,MEDIUM'
|
||||
scan-type: "fs"
|
||||
scan-ref: "."
|
||||
scanners: "vuln,secret,misconfig"
|
||||
format: "table"
|
||||
severity: "CRITICAL,HIGH,MEDIUM"
|
||||
ignore-unfixed: true
|
||||
exit-code: '1'
|
||||
exit-code: "1"
|
||||
|
||||
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
|
||||
@ -334,6 +336,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.
|
||||
@ -341,6 +350,7 @@ func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
|
||||
engine.RouterGroup.Use(middleware...)
|
||||
engine.rebuild404Handlers()
|
||||
engine.rebuild405Handlers()
|
||||
engine.rebuildAutoRedirectHandlers()
|
||||
return engine
|
||||
}
|
||||
|
||||
@ -361,6 +371,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")
|
||||
@ -724,6 +738,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
|
||||
@ -819,13 +834,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
@ -601,6 +601,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)
|
||||
|
||||
4
go.mod
4
go.mod
@ -7,7 +7,7 @@ toolchain go1.24.7
|
||||
require (
|
||||
github.com/bytedance/sonic v1.15.0
|
||||
github.com/gin-contrib/sse v1.1.0
|
||||
github.com/go-playground/validator/v10 v10.28.0
|
||||
github.com/go-playground/validator/v10 v10.30.1
|
||||
github.com/goccy/go-json v0.10.5
|
||||
github.com/goccy/go-yaml v1.19.2
|
||||
github.com/json-iterator/go v1.1.12
|
||||
@ -29,7 +29,7 @@ require (
|
||||
github.com/bytedance/sonic/loader v0.5.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.12 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
|
||||
8
go.sum
8
go.sum
@ -10,8 +10,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw=
|
||||
github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
||||
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
@ -20,8 +20,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688=
|
||||
github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU=
|
||||
github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w=
|
||||
github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
|
||||
|
||||
@ -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