mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-15 21:06:39 +08:00
Merge branch 'master' into support_go1.21
This commit is contained in:
commit
381fbd082b
14
.github/workflows/codeql.yml
vendored
14
.github/workflows/codeql.yml
vendored
@ -7,12 +7,12 @@ name: "CodeQL"
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [master]
|
||||||
pull_request:
|
pull_request:
|
||||||
# The branches below must be a subset of the branches above
|
# The branches below must be a subset of the branches above
|
||||||
branches: [ master ]
|
branches: [master]
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 17 * * 5'
|
- cron: "0 17 * * 5"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
analyze:
|
analyze:
|
||||||
@ -29,15 +29,15 @@ jobs:
|
|||||||
# Override automatic language detection by changing the below list
|
# Override automatic language detection by changing the below list
|
||||||
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
||||||
# TODO: Enable for javascript later
|
# TODO: Enable for javascript later
|
||||||
language: [ 'go']
|
language: ["go"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v2
|
uses: github/codeql-action/init@v3
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
@ -46,4 +46,4 @@ jobs:
|
|||||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v2
|
uses: github/codeql-action/analyze@v3
|
||||||
|
23
.github/workflows/gin.yml
vendored
23
.github/workflows/gin.yml
vendored
@ -16,23 +16,23 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Setup go
|
- name: Setup go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '^1.19'
|
go-version: "^1.19"
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Setup golangci-lint
|
- name: Setup golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v3.4.0
|
uses: golangci/golangci-lint-action@v3.7.0
|
||||||
with:
|
with:
|
||||||
version: v1.52.2
|
version: v1.55.2
|
||||||
args: --verbose
|
args: --verbose
|
||||||
test:
|
test:
|
||||||
needs: lint
|
needs: lint
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest]
|
os: [ubuntu-latest, macos-latest]
|
||||||
go: ['1.19', '1.20', '1.21']
|
go: ["1.19", "1.20", "1.21"]
|
||||||
test-tags: ['', '-tags nomsgpack', '-tags "sonic avx"', '-tags go_json']
|
test-tags: ["", "-tags nomsgpack", '-tags "sonic avx"', "-tags go_json"]
|
||||||
include:
|
include:
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
go-build: ~/.cache/go-build
|
go-build: ~/.cache/go-build
|
||||||
@ -46,16 +46,17 @@ jobs:
|
|||||||
GOPROXY: https://proxy.golang.org
|
GOPROXY: https://proxy.golang.org
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Go ${{ matrix.go }}
|
- name: Set up Go ${{ matrix.go }}
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go }}
|
go-version: ${{ matrix.go }}
|
||||||
|
cache: false
|
||||||
|
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.ref }}
|
ref: ${{ github.ref }}
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
${{ matrix.go-build }}
|
${{ matrix.go-build }}
|
||||||
@ -68,7 +69,7 @@ jobs:
|
|||||||
run: make test
|
run: make test
|
||||||
|
|
||||||
- name: Upload coverage to Codecov
|
- name: Upload coverage to Codecov
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v4
|
||||||
with:
|
with:
|
||||||
flags: ${{ matrix.os }},go-${{ matrix.go }},${{ matrix.test-tags }}
|
flags: ${{ matrix.os }},go-${{ matrix.go }},${{ matrix.test-tags }}
|
||||||
|
|
||||||
|
13
.github/workflows/goreleaser.yml
vendored
13
.github/workflows/goreleaser.yml
vendored
@ -3,7 +3,7 @@ name: Goreleaser
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- '*'
|
- "*"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
@ -12,19 +12,18 @@ jobs:
|
|||||||
goreleaser:
|
goreleaser:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
-
|
- name: Checkout
|
||||||
name: Checkout
|
uses: actions/checkout@v4
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
-
|
-
|
||||||
name: Set up Go
|
name: Set up Go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: 1.21
|
go-version: "^1"
|
||||||
-
|
-
|
||||||
name: Run GoReleaser
|
name: Run GoReleaser
|
||||||
uses: goreleaser/goreleaser-action@v4
|
uses: goreleaser/goreleaser-action@v5
|
||||||
with:
|
with:
|
||||||
# either 'goreleaser' (default) or 'goreleaser-pro'
|
# either 'goreleaser' (default) or 'goreleaser-pro'
|
||||||
distribution: goreleaser
|
distribution: goreleaser
|
||||||
|
@ -3,7 +3,6 @@ run:
|
|||||||
linters:
|
linters:
|
||||||
enable:
|
enable:
|
||||||
- asciicheck
|
- asciicheck
|
||||||
- depguard
|
|
||||||
- dogsled
|
- dogsled
|
||||||
- durationcheck
|
- durationcheck
|
||||||
- errcheck
|
- errcheck
|
||||||
|
@ -7,6 +7,7 @@ package binding
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"mime/multipart"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -235,10 +236,17 @@ func setWithProperType(val string, value reflect.Value, field reflect.StructFiel
|
|||||||
switch value.Interface().(type) {
|
switch value.Interface().(type) {
|
||||||
case time.Time:
|
case time.Time:
|
||||||
return setTimeField(val, field, value)
|
return setTimeField(val, field, value)
|
||||||
|
case multipart.FileHeader:
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface())
|
return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface())
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface())
|
return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface())
|
||||||
|
case reflect.Ptr:
|
||||||
|
if !value.Elem().IsValid() {
|
||||||
|
value.Set(reflect.New(value.Type().Elem()))
|
||||||
|
}
|
||||||
|
return setWithProperType(val, value.Elem(), field)
|
||||||
default:
|
default:
|
||||||
return errUnknownType
|
return errUnknownType
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package binding
|
package binding
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"mime/multipart"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -43,6 +44,7 @@ func TestMappingBaseTypes(t *testing.T) {
|
|||||||
{"zero value", struct{ F uint }{}, "", uint(0)},
|
{"zero value", struct{ F uint }{}, "", uint(0)},
|
||||||
{"zero value", struct{ F bool }{}, "", false},
|
{"zero value", struct{ F bool }{}, "", false},
|
||||||
{"zero value", struct{ F float32 }{}, "", float32(0)},
|
{"zero value", struct{ F float32 }{}, "", float32(0)},
|
||||||
|
{"file value", struct{ F *multipart.FileHeader }{}, "", &multipart.FileHeader{}},
|
||||||
} {
|
} {
|
||||||
tp := reflect.TypeOf(tt.value)
|
tp := reflect.TypeOf(tt.value)
|
||||||
testName := tt.name + ":" + tp.Field(0).Type.String()
|
testName := tt.name + ":" + tp.Field(0).Type.String()
|
||||||
@ -269,6 +271,39 @@ func TestMappingStructField(t *testing.T) {
|
|||||||
assert.Equal(t, 9, s.J.I)
|
assert.Equal(t, 9, s.J.I)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMappingPtrField(t *testing.T) {
|
||||||
|
type ptrStruct struct {
|
||||||
|
Key int64 `json:"key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ptrRequest struct {
|
||||||
|
Items []*ptrStruct `json:"items" form:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// With 0 items.
|
||||||
|
var req0 ptrRequest
|
||||||
|
err = mappingByPtr(&req0, formSource{}, "form")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Empty(t, req0.Items)
|
||||||
|
|
||||||
|
// With 1 item.
|
||||||
|
var req1 ptrRequest
|
||||||
|
err = mappingByPtr(&req1, formSource{"items": {`{"key": 1}`}}, "form")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, req1.Items, 1)
|
||||||
|
assert.EqualValues(t, 1, req1.Items[0].Key)
|
||||||
|
|
||||||
|
// With 2 items.
|
||||||
|
var req2 ptrRequest
|
||||||
|
err = mappingByPtr(&req2, formSource{"items": {`{"key": 1}`, `{"key": 2}`}}, "form")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, req2.Items, 2)
|
||||||
|
assert.EqualValues(t, 1, req2.Items[0].Key)
|
||||||
|
assert.EqualValues(t, 2, req2.Items[1].Key)
|
||||||
|
}
|
||||||
|
|
||||||
func TestMappingMapField(t *testing.T) {
|
func TestMappingMapField(t *testing.T) {
|
||||||
var s struct {
|
var s struct {
|
||||||
M map[string]int
|
M map[string]int
|
||||||
|
38
docs/doc.md
38
docs/doc.md
@ -508,6 +508,44 @@ Sample Output
|
|||||||
::1 - [Fri, 07 Dec 2018 17:04:38 JST] "GET /ping HTTP/1.1 200 122.767µs "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36" "
|
::1 - [Fri, 07 Dec 2018 17:04:38 JST] "GET /ping HTTP/1.1 200 122.767µs "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36" "
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Skip logging
|
||||||
|
|
||||||
|
```go
|
||||||
|
func main() {
|
||||||
|
router := gin.New()
|
||||||
|
|
||||||
|
// skip logging for desired paths by setting SkipPaths in LoggerConfig
|
||||||
|
loggerConfig := gin.LoggerConfig{SkipPaths: []string{"/metrics"}}
|
||||||
|
|
||||||
|
// skip logging based on your logic by setting Skip func in LoggerConfig
|
||||||
|
loggerConfig.Skip = func(c *gin.Context) bool {
|
||||||
|
// as an example skip non server side errors
|
||||||
|
return c.Writer.Status() < http.StatusInternalServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
engine.Use(gin.LoggerWithConfig(loggerConfig))
|
||||||
|
router.Use(gin.Recovery())
|
||||||
|
|
||||||
|
// skipped
|
||||||
|
router.GET("/metrics", func(c *gin.Context) {
|
||||||
|
c.Status(http.StatusNotImplemented)
|
||||||
|
})
|
||||||
|
|
||||||
|
// skipped
|
||||||
|
router.GET("/ping", func(c *gin.Context) {
|
||||||
|
c.String(http.StatusOK, "pong")
|
||||||
|
})
|
||||||
|
|
||||||
|
// not skipped
|
||||||
|
router.GET("/data", func(c *gin.Context) {
|
||||||
|
c.Status(http.StatusNotImplemented)
|
||||||
|
})
|
||||||
|
|
||||||
|
router.Run(":8080")
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
### Controlling Log output coloring
|
### Controlling Log output coloring
|
||||||
|
|
||||||
By default, logs output on console should be colorized depending on the detected TTY.
|
By default, logs output on console should be colorized depending on the detected TTY.
|
||||||
|
15
gin.go
15
gin.go
@ -334,7 +334,6 @@ func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {
|
|||||||
}
|
}
|
||||||
root.addRoute(path, handlers)
|
root.addRoute(path, handlers)
|
||||||
|
|
||||||
// Update maxParams
|
|
||||||
if paramsCount := countParams(path); paramsCount > engine.maxParams {
|
if paramsCount := countParams(path); paramsCount > engine.maxParams {
|
||||||
engine.maxParams = paramsCount
|
engine.maxParams = paramsCount
|
||||||
}
|
}
|
||||||
@ -634,17 +633,25 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if engine.HandleMethodNotAllowed {
|
if engine.HandleMethodNotAllowed {
|
||||||
|
// According to RFC 7231 section 6.5.5, MUST generate an Allow header field in response
|
||||||
|
// containing a list of the target resource's currently supported methods.
|
||||||
|
allowed := make([]string, 0, len(t)-1)
|
||||||
for _, tree := range engine.trees {
|
for _, tree := range engine.trees {
|
||||||
if tree.method == httpMethod {
|
if tree.method == httpMethod {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if value := tree.root.getValue(rPath, nil, c.skippedNodes, unescape); value.handlers != nil {
|
if value := tree.root.getValue(rPath, nil, c.skippedNodes, unescape); value.handlers != nil {
|
||||||
c.handlers = engine.allNoMethod
|
allowed = append(allowed, tree.method)
|
||||||
serveError(c, http.StatusMethodNotAllowed, default405Body)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(allowed) > 0 {
|
||||||
|
c.handlers = engine.allNoMethod
|
||||||
|
c.writermem.Header().Set("Allow", strings.Join(allowed, ", "))
|
||||||
|
serveError(c, http.StatusMethodNotAllowed, default405Body)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.handlers = engine.allNoRoute
|
c.handlers = engine.allNoRoute
|
||||||
serveError(c, http.StatusNotFound, default404Body)
|
serveError(c, http.StatusNotFound, default404Body)
|
||||||
}
|
}
|
||||||
|
33
go.mod
33
go.mod
@ -3,34 +3,35 @@ module github.com/gin-gonic/gin
|
|||||||
go 1.21
|
go 1.21
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bytedance/sonic v1.9.1
|
github.com/bytedance/sonic v1.10.2
|
||||||
github.com/gin-contrib/sse v0.1.0
|
github.com/gin-contrib/sse v0.1.0
|
||||||
github.com/go-playground/validator/v10 v10.14.0
|
github.com/go-playground/validator/v10 v10.17.0
|
||||||
github.com/goccy/go-json v0.10.2
|
github.com/goccy/go-json v0.10.2
|
||||||
github.com/json-iterator/go v1.1.12
|
github.com/json-iterator/go v1.1.12
|
||||||
github.com/mattn/go-isatty v0.0.19
|
github.com/mattn/go-isatty v0.0.20
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8
|
github.com/pelletier/go-toml/v2 v2.1.1
|
||||||
github.com/stretchr/testify v1.8.3
|
github.com/stretchr/testify v1.8.4
|
||||||
github.com/ugorji/go/codec v1.2.11
|
github.com/ugorji/go/codec v1.2.12
|
||||||
golang.org/x/net v0.13.0
|
golang.org/x/net v0.20.0
|
||||||
google.golang.org/protobuf v1.30.0
|
google.golang.org/protobuf v1.32.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||||
|
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
||||||
github.com/leodido/go-urn v1.2.4 // indirect
|
github.com/leodido/go-urn v1.3.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.7.0 // indirect
|
||||||
golang.org/x/crypto v0.9.0 // indirect
|
golang.org/x/crypto v0.18.0 // indirect
|
||||||
golang.org/x/sys v0.8.0 // indirect
|
golang.org/x/sys v0.16.0 // indirect
|
||||||
golang.org/x/text v0.9.0 // indirect
|
golang.org/x/text v0.14.0 // indirect
|
||||||
)
|
)
|
||||||
|
83
go.sum
83
go.sum
@ -1,16 +1,19 @@
|
|||||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||||
github.com/bytedance/sonic v1.9.0 h1:iwLYBds8bYtzwOX7kmdYwtS+aY2GgekVoIs2/IxR0tM=
|
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
|
||||||
github.com/bytedance/sonic v1.9.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE=
|
||||||
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
||||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
|
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
|
||||||
|
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||||
|
github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=
|
||||||
|
github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
@ -18,32 +21,29 @@ 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/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 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
github.com/go-playground/validator/v10 v10.17.0 h1:SmVVlfAOtlZncTxRuinDPomC2DkXJ4E5T9gDA0AIH74=
|
||||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
github.com/go-playground/validator/v10 v10.17.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
|
||||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
|
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
github.com/leodido/go-urn v1.3.0 h1:jX8FDLfW4ThVXctBNZ+3cIWnCSnrACDV73r76dy0aQQ=
|
||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
github.com/leodido/go-urn v1.3.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
@ -54,37 +54,32 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
|
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
|
||||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
|
||||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
|
||||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
|
63
logger.go
63
logger.go
@ -47,8 +47,15 @@ type LoggerConfig struct {
|
|||||||
// SkipPaths is an url path array which logs are not written.
|
// SkipPaths is an url path array which logs are not written.
|
||||||
// Optional.
|
// Optional.
|
||||||
SkipPaths []string
|
SkipPaths []string
|
||||||
|
|
||||||
|
// Skip is a Skipper that indicates which logs should not be written.
|
||||||
|
// Optional.
|
||||||
|
Skip Skipper
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skipper is a function to skip logs based on provided Context
|
||||||
|
type Skipper func(c *Context) bool
|
||||||
|
|
||||||
// LogFormatter gives the signature of the formatter function passed to LoggerWithFormatter
|
// LogFormatter gives the signature of the formatter function passed to LoggerWithFormatter
|
||||||
type LogFormatter func(params LogFormatterParams) string
|
type LogFormatter func(params LogFormatterParams) string
|
||||||
|
|
||||||
@ -83,6 +90,8 @@ func (p *LogFormatterParams) StatusCodeColor() string {
|
|||||||
code := p.StatusCode
|
code := p.StatusCode
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
case code >= http.StatusContinue && code < http.StatusOK:
|
||||||
|
return white
|
||||||
case code >= http.StatusOK && code < http.StatusMultipleChoices:
|
case code >= http.StatusOK && code < http.StatusMultipleChoices:
|
||||||
return green
|
return green
|
||||||
case code >= http.StatusMultipleChoices && code < http.StatusBadRequest:
|
case code >= http.StatusMultipleChoices && code < http.StatusBadRequest:
|
||||||
@ -239,32 +248,34 @@ func LoggerWithConfig(conf LoggerConfig) HandlerFunc {
|
|||||||
// Process request
|
// Process request
|
||||||
c.Next()
|
c.Next()
|
||||||
|
|
||||||
// Log only when path is not being skipped
|
// Log only when it is not being skipped
|
||||||
if _, ok := skip[path]; !ok {
|
if _, ok := skip[path]; ok || (conf.Skip != nil && conf.Skip(c)) {
|
||||||
param := LogFormatterParams{
|
return
|
||||||
Request: c.Request,
|
|
||||||
isTerm: isTerm,
|
|
||||||
Keys: c.Keys,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop timer
|
|
||||||
param.TimeStamp = time.Now()
|
|
||||||
param.Latency = param.TimeStamp.Sub(start)
|
|
||||||
|
|
||||||
param.ClientIP = c.ClientIP()
|
|
||||||
param.Method = c.Request.Method
|
|
||||||
param.StatusCode = c.Writer.Status()
|
|
||||||
param.ErrorMessage = c.Errors.ByType(ErrorTypePrivate).String()
|
|
||||||
|
|
||||||
param.BodySize = c.Writer.Size()
|
|
||||||
|
|
||||||
if raw != "" {
|
|
||||||
path = path + "?" + raw
|
|
||||||
}
|
|
||||||
|
|
||||||
param.Path = path
|
|
||||||
|
|
||||||
fmt.Fprint(out, formatter(param))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
param := LogFormatterParams{
|
||||||
|
Request: c.Request,
|
||||||
|
isTerm: isTerm,
|
||||||
|
Keys: c.Keys,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop timer
|
||||||
|
param.TimeStamp = time.Now()
|
||||||
|
param.Latency = param.TimeStamp.Sub(start)
|
||||||
|
|
||||||
|
param.ClientIP = c.ClientIP()
|
||||||
|
param.Method = c.Request.Method
|
||||||
|
param.StatusCode = c.Writer.Status()
|
||||||
|
param.ErrorMessage = c.Errors.ByType(ErrorTypePrivate).String()
|
||||||
|
|
||||||
|
param.BodySize = c.Writer.Size()
|
||||||
|
|
||||||
|
if raw != "" {
|
||||||
|
path = path + "?" + raw
|
||||||
|
}
|
||||||
|
|
||||||
|
param.Path = path
|
||||||
|
|
||||||
|
fmt.Fprint(out, formatter(param))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,6 +310,7 @@ func TestColorForStatus(t *testing.T) {
|
|||||||
return p.StatusCodeColor()
|
return p.StatusCodeColor()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, white, colorForStatus(http.StatusContinue), "1xx should be white")
|
||||||
assert.Equal(t, green, colorForStatus(http.StatusOK), "2xx should be green")
|
assert.Equal(t, green, colorForStatus(http.StatusOK), "2xx should be green")
|
||||||
assert.Equal(t, white, colorForStatus(http.StatusMovedPermanently), "3xx should be white")
|
assert.Equal(t, white, colorForStatus(http.StatusMovedPermanently), "3xx should be white")
|
||||||
assert.Equal(t, yellow, colorForStatus(http.StatusNotFound), "4xx should be yellow")
|
assert.Equal(t, yellow, colorForStatus(http.StatusNotFound), "4xx should be yellow")
|
||||||
@ -414,6 +415,26 @@ func TestLoggerWithConfigSkippingPaths(t *testing.T) {
|
|||||||
assert.Contains(t, buffer.String(), "")
|
assert.Contains(t, buffer.String(), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoggerWithConfigSkipper(t *testing.T) {
|
||||||
|
buffer := new(strings.Builder)
|
||||||
|
router := New()
|
||||||
|
router.Use(LoggerWithConfig(LoggerConfig{
|
||||||
|
Output: buffer,
|
||||||
|
Skip: func(c *Context) bool {
|
||||||
|
return c.Writer.Status() == http.StatusNoContent
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
router.GET("/logged", func(c *Context) { c.Status(http.StatusOK) })
|
||||||
|
router.GET("/skipped", func(c *Context) { c.Status(http.StatusNoContent) })
|
||||||
|
|
||||||
|
PerformRequest(router, "GET", "/logged")
|
||||||
|
assert.Contains(t, buffer.String(), "200")
|
||||||
|
|
||||||
|
buffer.Reset()
|
||||||
|
PerformRequest(router, "GET", "/skipped")
|
||||||
|
assert.Contains(t, buffer.String(), "")
|
||||||
|
}
|
||||||
|
|
||||||
func TestDisableConsoleColor(t *testing.T) {
|
func TestDisableConsoleColor(t *testing.T) {
|
||||||
New()
|
New()
|
||||||
assert.Equal(t, autoColor, consoleColorMode)
|
assert.Equal(t, autoColor, consoleColorMode)
|
||||||
|
@ -578,3 +578,16 @@ func TestRenderReaderNoContentLength(t *testing.T) {
|
|||||||
assert.Equal(t, headers["Content-Disposition"], w.Header().Get("Content-Disposition"))
|
assert.Equal(t, headers["Content-Disposition"], w.Header().Get("Content-Disposition"))
|
||||||
assert.Equal(t, headers["x-request-id"], w.Header().Get("x-request-id"))
|
assert.Equal(t, headers["x-request-id"], w.Header().Get("x-request-id"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRenderWriteError(t *testing.T) {
|
||||||
|
data := []interface{}{"value1", "value2"}
|
||||||
|
prefix := "my-prefix:"
|
||||||
|
r := SecureJSON{Data: data, Prefix: prefix}
|
||||||
|
ew := &errorWriter{
|
||||||
|
bufString: prefix,
|
||||||
|
ResponseRecorder: httptest.NewRecorder(),
|
||||||
|
}
|
||||||
|
err := r.Render(ew)
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
assert.Equal(t, `write "my-prefix:" error`, err.Error())
|
||||||
|
}
|
||||||
|
@ -156,3 +156,33 @@ func TestResponseWriterStatusCode(t *testing.T) {
|
|||||||
// status must be 200 although we tried to change it
|
// status must be 200 although we tried to change it
|
||||||
assert.Equal(t, http.StatusOK, w.Status())
|
assert.Equal(t, http.StatusOK, w.Status())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mockPusherResponseWriter is an http.ResponseWriter that implements http.Pusher.
|
||||||
|
type mockPusherResponseWriter struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockPusherResponseWriter) Push(target string, opts *http.PushOptions) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// nonPusherResponseWriter is an http.ResponseWriter that does not implement http.Pusher.
|
||||||
|
type nonPusherResponseWriter struct {
|
||||||
|
http.ResponseWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPusherWithPusher(t *testing.T) {
|
||||||
|
rw := &mockPusherResponseWriter{}
|
||||||
|
w := &responseWriter{ResponseWriter: rw}
|
||||||
|
|
||||||
|
pusher := w.Pusher()
|
||||||
|
assert.NotNil(t, pusher, "Expected pusher to be non-nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPusherWithoutPusher(t *testing.T) {
|
||||||
|
rw := &nonPusherResponseWriter{}
|
||||||
|
w := &responseWriter{ResponseWriter: rw}
|
||||||
|
|
||||||
|
pusher := w.Pusher()
|
||||||
|
assert.Nil(t, pusher, "Expected pusher to be nil")
|
||||||
|
}
|
||||||
|
@ -337,6 +337,45 @@ func TestRouteParamsByNameWithExtraSlash(t *testing.T) {
|
|||||||
assert.Equal(t, "/is/super/great", wild)
|
assert.Equal(t, "/is/super/great", wild)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestRouteParamsNotEmpty tests that context parameters will be set
|
||||||
|
// even if a route with params/wildcards is registered after the context
|
||||||
|
// initialisation (which happened in a previous requets).
|
||||||
|
func TestRouteParamsNotEmpty(t *testing.T) {
|
||||||
|
name := ""
|
||||||
|
lastName := ""
|
||||||
|
wild := ""
|
||||||
|
router := New()
|
||||||
|
|
||||||
|
w := PerformRequest(router, http.MethodGet, "/test/john/smith/is/super/great")
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||||
|
|
||||||
|
router.GET("/test/:name/:last_name/*wild", func(c *Context) {
|
||||||
|
name = c.Params.ByName("name")
|
||||||
|
lastName = c.Params.ByName("last_name")
|
||||||
|
var ok bool
|
||||||
|
wild, ok = c.Params.Get("wild")
|
||||||
|
|
||||||
|
assert.True(t, ok)
|
||||||
|
assert.Equal(t, name, c.Param("name"))
|
||||||
|
assert.Equal(t, lastName, c.Param("last_name"))
|
||||||
|
|
||||||
|
assert.Empty(t, c.Param("wtf"))
|
||||||
|
assert.Empty(t, c.Params.ByName("wtf"))
|
||||||
|
|
||||||
|
wtf, ok := c.Params.Get("wtf")
|
||||||
|
assert.Empty(t, wtf)
|
||||||
|
assert.False(t, ok)
|
||||||
|
})
|
||||||
|
|
||||||
|
w = PerformRequest(router, http.MethodGet, "/test/john/smith/is/super/great")
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusOK, w.Code)
|
||||||
|
assert.Equal(t, "john", name)
|
||||||
|
assert.Equal(t, "smith", lastName)
|
||||||
|
assert.Equal(t, "/is/super/great", wild)
|
||||||
|
}
|
||||||
|
|
||||||
// TestHandleStaticFile - ensure the static file handles properly
|
// TestHandleStaticFile - ensure the static file handles properly
|
||||||
func TestRouteStaticFile(t *testing.T) {
|
func TestRouteStaticFile(t *testing.T) {
|
||||||
// SETUP file
|
// SETUP file
|
||||||
@ -475,6 +514,18 @@ func TestRouteNotAllowedEnabled2(t *testing.T) {
|
|||||||
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
|
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRouteNotAllowedEnabled3(t *testing.T) {
|
||||||
|
router := New()
|
||||||
|
router.HandleMethodNotAllowed = true
|
||||||
|
router.GET("/path", func(c *Context) {})
|
||||||
|
router.POST("/path", func(c *Context) {})
|
||||||
|
w := PerformRequest(router, http.MethodPut, "/path")
|
||||||
|
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
|
||||||
|
allowed := w.Header().Get("Allow")
|
||||||
|
assert.Contains(t, allowed, "GET")
|
||||||
|
assert.Contains(t, allowed, "POST")
|
||||||
|
}
|
||||||
|
|
||||||
func TestRouteNotAllowedDisabled(t *testing.T) {
|
func TestRouteNotAllowedDisabled(t *testing.T) {
|
||||||
router := New()
|
router := New()
|
||||||
router.HandleMethodNotAllowed = false
|
router.HandleMethodNotAllowed = false
|
||||||
|
43
tree.go
43
tree.go
@ -351,7 +351,10 @@ func (n *node) insertChild(path string, fullPath string, handlers HandlersChain)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(n.path) > 0 && n.path[len(n.path)-1] == '/' {
|
if len(n.path) > 0 && n.path[len(n.path)-1] == '/' {
|
||||||
pathSeg := strings.SplitN(n.children[0].path, "/", 2)[0]
|
pathSeg := ""
|
||||||
|
if len(n.children) != 0 {
|
||||||
|
pathSeg = strings.SplitN(n.children[0].path, "/", 2)[0]
|
||||||
|
}
|
||||||
panic("catch-all wildcard '" + path +
|
panic("catch-all wildcard '" + path +
|
||||||
"' in new path '" + fullPath +
|
"' in new path '" + fullPath +
|
||||||
"' conflicts with existing path segment '" + pathSeg +
|
"' conflicts with existing path segment '" + pathSeg +
|
||||||
@ -478,7 +481,7 @@ walk: // Outer loop for walking the tree
|
|||||||
// We can recommend to redirect to the same URL without a
|
// We can recommend to redirect to the same URL without a
|
||||||
// trailing slash if a leaf exists for that path.
|
// trailing slash if a leaf exists for that path.
|
||||||
value.tsr = path == "/" && n.handlers != nil
|
value.tsr = path == "/" && n.handlers != nil
|
||||||
return
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle wildcard child, which is always at the end of the array
|
// Handle wildcard child, which is always at the end of the array
|
||||||
@ -497,7 +500,14 @@ walk: // Outer loop for walking the tree
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save param value
|
// Save param value
|
||||||
if params != nil && cap(*params) > 0 {
|
if params != nil {
|
||||||
|
// Preallocate capacity if necessary
|
||||||
|
if cap(*params) < int(globalParamsCount) {
|
||||||
|
newParams := make(Params, len(*params), globalParamsCount)
|
||||||
|
copy(newParams, *params)
|
||||||
|
*params = newParams
|
||||||
|
}
|
||||||
|
|
||||||
if value.params == nil {
|
if value.params == nil {
|
||||||
value.params = params
|
value.params = params
|
||||||
}
|
}
|
||||||
@ -526,12 +536,12 @@ walk: // Outer loop for walking the tree
|
|||||||
|
|
||||||
// ... but we can't
|
// ... but we can't
|
||||||
value.tsr = len(path) == end+1
|
value.tsr = len(path) == end+1
|
||||||
return
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
if value.handlers = n.handlers; value.handlers != nil {
|
if value.handlers = n.handlers; value.handlers != nil {
|
||||||
value.fullPath = n.fullPath
|
value.fullPath = n.fullPath
|
||||||
return
|
return value
|
||||||
}
|
}
|
||||||
if len(n.children) == 1 {
|
if len(n.children) == 1 {
|
||||||
// No handle found. Check if a handle for this path + a
|
// No handle found. Check if a handle for this path + a
|
||||||
@ -539,11 +549,18 @@ walk: // Outer loop for walking the tree
|
|||||||
n = n.children[0]
|
n = n.children[0]
|
||||||
value.tsr = (n.path == "/" && n.handlers != nil) || (n.path == "" && n.indices == "/")
|
value.tsr = (n.path == "/" && n.handlers != nil) || (n.path == "" && n.indices == "/")
|
||||||
}
|
}
|
||||||
return
|
return value
|
||||||
|
|
||||||
case catchAll:
|
case catchAll:
|
||||||
// Save param value
|
// Save param value
|
||||||
if params != nil {
|
if params != nil {
|
||||||
|
// Preallocate capacity if necessary
|
||||||
|
if cap(*params) < int(globalParamsCount) {
|
||||||
|
newParams := make(Params, len(*params), globalParamsCount)
|
||||||
|
copy(newParams, *params)
|
||||||
|
*params = newParams
|
||||||
|
}
|
||||||
|
|
||||||
if value.params == nil {
|
if value.params == nil {
|
||||||
value.params = params
|
value.params = params
|
||||||
}
|
}
|
||||||
@ -564,7 +581,7 @@ walk: // Outer loop for walking the tree
|
|||||||
|
|
||||||
value.handlers = n.handlers
|
value.handlers = n.handlers
|
||||||
value.fullPath = n.fullPath
|
value.fullPath = n.fullPath
|
||||||
return
|
return value
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic("invalid node type")
|
panic("invalid node type")
|
||||||
@ -595,7 +612,7 @@ walk: // Outer loop for walking the tree
|
|||||||
// Check if this node has a handle registered.
|
// Check if this node has a handle registered.
|
||||||
if value.handlers = n.handlers; value.handlers != nil {
|
if value.handlers = n.handlers; value.handlers != nil {
|
||||||
value.fullPath = n.fullPath
|
value.fullPath = n.fullPath
|
||||||
return
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is no handle for this route, but this route has a
|
// If there is no handle for this route, but this route has a
|
||||||
@ -603,12 +620,12 @@ walk: // Outer loop for walking the tree
|
|||||||
// additional trailing slash
|
// additional trailing slash
|
||||||
if path == "/" && n.wildChild && n.nType != root {
|
if path == "/" && n.wildChild && n.nType != root {
|
||||||
value.tsr = true
|
value.tsr = true
|
||||||
return
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
if path == "/" && n.nType == static {
|
if path == "/" && n.nType == static {
|
||||||
value.tsr = true
|
value.tsr = true
|
||||||
return
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
// No handle found. Check if a handle for this path + a
|
// No handle found. Check if a handle for this path + a
|
||||||
@ -618,11 +635,11 @@ walk: // Outer loop for walking the tree
|
|||||||
n = n.children[i]
|
n = n.children[i]
|
||||||
value.tsr = (len(n.path) == 1 && n.handlers != nil) ||
|
value.tsr = (len(n.path) == 1 && n.handlers != nil) ||
|
||||||
(n.nType == catchAll && n.children[0].handlers != nil)
|
(n.nType == catchAll && n.children[0].handlers != nil)
|
||||||
return
|
return value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nothing found. We can recommend to redirect to the same URL with an
|
// Nothing found. We can recommend to redirect to the same URL with an
|
||||||
@ -648,7 +665,7 @@ walk: // Outer loop for walking the tree
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
36
tree_test.go
36
tree_test.go
@ -417,6 +417,8 @@ func TestTreeWildcardConflict(t *testing.T) {
|
|||||||
{"/user_:name", false},
|
{"/user_:name", false},
|
||||||
{"/id:id", false},
|
{"/id:id", false},
|
||||||
{"/id/:id", false},
|
{"/id/:id", false},
|
||||||
|
{"/static/*file", false},
|
||||||
|
{"/static/", true},
|
||||||
}
|
}
|
||||||
testRoutes(t, routes)
|
testRoutes(t, routes)
|
||||||
}
|
}
|
||||||
@ -893,9 +895,9 @@ func TestTreeInvalidNodeType(t *testing.T) {
|
|||||||
|
|
||||||
func TestTreeInvalidParamsType(t *testing.T) {
|
func TestTreeInvalidParamsType(t *testing.T) {
|
||||||
tree := &node{}
|
tree := &node{}
|
||||||
tree.wildChild = true
|
// add a child with wildcard
|
||||||
tree.children = append(tree.children, &node{})
|
route := "/:path"
|
||||||
tree.children[0].nType = 2
|
tree.addRoute(route, fakeHandler(route))
|
||||||
|
|
||||||
// set invalid Params type
|
// set invalid Params type
|
||||||
params := make(Params, 0)
|
params := make(Params, 0)
|
||||||
@ -904,6 +906,34 @@ func TestTreeInvalidParamsType(t *testing.T) {
|
|||||||
tree.getValue("/test", ¶ms, getSkippedNodes(), false)
|
tree.getValue("/test", ¶ms, getSkippedNodes(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTreeExpandParamsCapacity(t *testing.T) {
|
||||||
|
data := []struct {
|
||||||
|
path string
|
||||||
|
}{
|
||||||
|
{"/:path"},
|
||||||
|
{"/*path"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range data {
|
||||||
|
tree := &node{}
|
||||||
|
tree.addRoute(item.path, fakeHandler(item.path))
|
||||||
|
params := make(Params, 0)
|
||||||
|
|
||||||
|
value := tree.getValue("/test", ¶ms, getSkippedNodes(), false)
|
||||||
|
|
||||||
|
if value.params == nil {
|
||||||
|
t.Errorf("Expected %s params to be set, but they weren't", item.path)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(*value.params) != 1 {
|
||||||
|
t.Errorf("Wrong number of %s params: got %d, want %d",
|
||||||
|
item.path, len(*value.params), 1)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTreeWildcardConflictEx(t *testing.T) {
|
func TestTreeWildcardConflictEx(t *testing.T) {
|
||||||
conflicts := [...]struct {
|
conflicts := [...]struct {
|
||||||
route string
|
route string
|
||||||
|
Loading…
x
Reference in New Issue
Block a user