mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-16 21:32:11 +08:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
c8e2a990f5
10
.github/dependabot.yml
vendored
Normal file
10
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
- package-ecosystem: gomod
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
39
.github/workflows/gin.yml
vendored
39
.github/workflows/gin.yml
vendored
@ -9,12 +9,31 @@ on:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '^1.16'
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup golangci-lint
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
with:
|
||||
version: v1.41.1
|
||||
args: --verbose
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
go: [1.13, 1.14, 1.15, 1.16]
|
||||
test-tags: ['', nomsgpack]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
go-build: ~/.cache/go-build
|
||||
- os: macos-latest
|
||||
go-build: ~/Library/Caches/go-build
|
||||
name: ${{ matrix.os }} @ Go ${{ matrix.go }} ${{ matrix.test-tags }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
@ -32,20 +51,22 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- name: Install Dependencies
|
||||
run: make tools
|
||||
|
||||
- name: Run Check
|
||||
run: |
|
||||
make vet
|
||||
make fmt-check
|
||||
make misspell-check
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
${{ matrix.go-build }}
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
- name: Run Tests
|
||||
run: make test
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v1
|
||||
uses: codecov/codecov-action@v2
|
||||
with:
|
||||
flags: ${{ matrix.os }},go-${{ matrix.go }},${{ matrix.test-tags }}
|
||||
notification-gitter:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
|
25
.golangci.yml
Normal file
25
.golangci.yml
Normal file
@ -0,0 +1,25 @@
|
||||
run:
|
||||
timeout: 5m
|
||||
linters:
|
||||
enable:
|
||||
- gofmt
|
||||
- misspell
|
||||
- revive
|
||||
issues:
|
||||
exclude-rules:
|
||||
- linters:
|
||||
- deadcode
|
||||
text: "`static` is unused"
|
||||
- linters:
|
||||
- structcheck
|
||||
- unused
|
||||
text: "`data` is unused"
|
||||
- linters:
|
||||
- staticcheck
|
||||
text: "SA1019:"
|
||||
- linters:
|
||||
- revive
|
||||
text: "var-naming:"
|
||||
- linters:
|
||||
- revive
|
||||
text: "exported:"
|
@ -1,5 +1,11 @@
|
||||
# Gin ChangeLog
|
||||
|
||||
## Gin v1.7.3
|
||||
|
||||
### BUGFIXES
|
||||
|
||||
* fix level 1 router match [#2767](https://github.com/gin-gonic/gin/issues/2767), [#2796](https://github.com/gin-gonic/gin/issues/2796)
|
||||
|
||||
## Gin v1.7.2
|
||||
|
||||
### BUGFIXES
|
||||
|
@ -256,14 +256,15 @@ func main() {
|
||||
|
||||
// For each matched request Context will hold the route definition
|
||||
router.POST("/user/:name/*action", func(c *gin.Context) {
|
||||
c.FullPath() == "/user/:name/*action" // true
|
||||
b := c.FullPath() == "/user/:name/*action" // true
|
||||
c.String(http.StatusOK, "%t", b)
|
||||
})
|
||||
|
||||
// This handler will add a new router for /user/groups.
|
||||
// Exact routes are resolved before param routes, regardless of the order they were defined.
|
||||
// Routes starting with /user/groups are never interpreted as /user/:name/... routes
|
||||
router.GET("/user/groups", func(c *gin.Context) {
|
||||
c.String(http.StatusOK, "The available groups are [...]", name)
|
||||
c.String(http.StatusOK, "The available groups are [...]")
|
||||
})
|
||||
|
||||
router.Run(":8080")
|
||||
|
@ -49,7 +49,7 @@ type BindingUri interface {
|
||||
// StructValidator is the minimal interface which needs to be implemented in
|
||||
// order for it to be used as the validator engine for ensuring the correctness
|
||||
// of the request. Gin provides a default implementation for this using
|
||||
// https://github.com/go-playground/validator/tree/v8.18.2.
|
||||
// https://github.com/go-playground/validator/tree/v10.6.1.
|
||||
type StructValidator interface {
|
||||
// ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right.
|
||||
// If the received type is a slice|array, the validation should be performed travel on every element.
|
||||
@ -65,7 +65,7 @@ type StructValidator interface {
|
||||
}
|
||||
|
||||
// Validator is the default validator which implements the StructValidator
|
||||
// interface. It uses https://github.com/go-playground/validator/tree/v8.18.2
|
||||
// interface. It uses https://github.com/go-playground/validator/tree/v10.6.1
|
||||
// under the hood.
|
||||
var Validator StructValidator = &defaultValidator{}
|
||||
|
||||
|
@ -47,7 +47,7 @@ type BindingUri interface {
|
||||
// StructValidator is the minimal interface which needs to be implemented in
|
||||
// order for it to be used as the validator engine for ensuring the correctness
|
||||
// of the request. Gin provides a default implementation for this using
|
||||
// https://github.com/go-playground/validator/tree/v8.18.2.
|
||||
// https://github.com/go-playground/validator/tree/v10.6.1.
|
||||
type StructValidator interface {
|
||||
// ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right.
|
||||
// If the received type is not a struct, any validation should be skipped and nil must be returned.
|
||||
@ -62,7 +62,7 @@ type StructValidator interface {
|
||||
}
|
||||
|
||||
// Validator is the default validator which implements the StructValidator
|
||||
// interface. It uses https://github.com/go-playground/validator/tree/v8.18.2
|
||||
// interface. It uses https://github.com/go-playground/validator/tree/v10.6.1
|
||||
// under the hood.
|
||||
var Validator StructValidator = &defaultValidator{}
|
||||
|
||||
|
@ -20,8 +20,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin/testdata/protoexample"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type appkey struct {
|
||||
@ -832,7 +832,6 @@ func testFormBindingEmbeddedStruct(t *testing.T, method, path, badPath, body, ba
|
||||
assert.Equal(t, 1, obj.Page)
|
||||
assert.Equal(t, 2, obj.Size)
|
||||
assert.Equal(t, "test-appkey", obj.Appkey)
|
||||
|
||||
}
|
||||
|
||||
func testFormBinding(t *testing.T, method, path, badPath, body, badBody string) {
|
||||
|
@ -26,7 +26,7 @@ var (
|
||||
ErrConvertToMapString = errors.New("can not convert to map of strings")
|
||||
)
|
||||
|
||||
func mapUri(ptr interface{}, m map[string][]string) error {
|
||||
func mapURI(ptr interface{}, m map[string][]string) error {
|
||||
return mapFormByTag(ptr, m, "uri")
|
||||
}
|
||||
|
||||
@ -83,7 +83,7 @@ func mapping(value reflect.Value, field reflect.StructField, setter setter, tag
|
||||
return false, nil
|
||||
}
|
||||
|
||||
var vKind = value.Kind()
|
||||
vKind := value.Kind()
|
||||
|
||||
if vKind == reflect.Ptr {
|
||||
var isNew bool
|
||||
@ -310,7 +310,6 @@ func setTimeField(val string, structField reflect.StructField, value reflect.Val
|
||||
t := time.Unix(tv/int64(d), tv%int64(d))
|
||||
value.Set(reflect.ValueOf(t))
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
if val == "" {
|
||||
|
@ -131,7 +131,7 @@ func TestMappingURI(t *testing.T) {
|
||||
var s struct {
|
||||
F int `uri:"field"`
|
||||
}
|
||||
err := mapUri(&s, map[string][]string{"field": {"6"}})
|
||||
err := mapURI(&s, map[string][]string{"field": {"6"}})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int(6), s.F)
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type protobufBinding struct{}
|
||||
|
@ -11,7 +11,7 @@ func (uriBinding) Name() string {
|
||||
}
|
||||
|
||||
func (uriBinding) BindUri(m map[string][]string, obj interface{}) error {
|
||||
if err := mapUri(obj, m); err != nil {
|
||||
if err := mapURI(obj, m); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
|
29
context.go
29
context.go
@ -40,7 +40,8 @@ const (
|
||||
// BodyBytesKey indicates a default body bytes key.
|
||||
const BodyBytesKey = "_gin-gonic/gin/bodybyteskey"
|
||||
|
||||
const abortIndex int8 = math.MaxInt8 / 2
|
||||
// abortIndex represents a typical value used in abort functions.
|
||||
const abortIndex int8 = math.MaxInt8 >> 1
|
||||
|
||||
// Context is the most important part of gin. It allows us to pass variables between middleware,
|
||||
// manage the flow, validate the JSON of a request and render a JSON response for example.
|
||||
@ -732,7 +733,7 @@ func (c *Context) ShouldBindBodyWith(obj interface{}, bb binding.BindingBody) (e
|
||||
// If the headers are nots syntactically valid OR the remote IP does not correspong to a trusted proxy,
|
||||
// the remote IP (coming form Request.RemoteAddr) is returned.
|
||||
func (c *Context) ClientIP() string {
|
||||
// Check if we're running on a tursted platform
|
||||
// Check if we're running on a trusted platform
|
||||
switch c.engine.TrustedPlatform {
|
||||
case PlatformGoogleAppEngine:
|
||||
if addr := c.requestHeader("X-Appengine-Remote-Addr"); addr != "" {
|
||||
@ -1160,22 +1161,28 @@ func (c *Context) SetAccepted(formats ...string) {
|
||||
/***** GOLANG.ORG/X/NET/CONTEXT *****/
|
||||
/************************************/
|
||||
|
||||
// Deadline always returns that there is no deadline (ok==false),
|
||||
// maybe you want to use Request.Context().Deadline() instead.
|
||||
// Deadline returns that there is no deadline (ok==false) when c.Request has no Context.
|
||||
func (c *Context) Deadline() (deadline time.Time, ok bool) {
|
||||
return
|
||||
if c.Request == nil || c.Request.Context() == nil {
|
||||
return
|
||||
}
|
||||
return c.Request.Context().Deadline()
|
||||
}
|
||||
|
||||
// Done always returns nil (chan which will wait forever),
|
||||
// if you want to abort your work when the connection was closed
|
||||
// you should use Request.Context().Done() instead.
|
||||
// Done returns nil (chan which will wait forever) when c.Request has no Context.
|
||||
func (c *Context) Done() <-chan struct{} {
|
||||
return nil
|
||||
if c.Request == nil || c.Request.Context() == nil {
|
||||
return nil
|
||||
}
|
||||
return c.Request.Context().Done()
|
||||
}
|
||||
|
||||
// Err always returns nil, maybe you want to use Request.Context().Err() instead.
|
||||
// Err returns nil when c.Request has no Context.
|
||||
func (c *Context) Err() error {
|
||||
return nil
|
||||
if c.Request == nil || c.Request.Context() == nil {
|
||||
return nil
|
||||
}
|
||||
return c.Request.Context().Err()
|
||||
}
|
||||
|
||||
// Value returns the value associated with this context for key, or nil
|
||||
|
@ -23,8 +23,8 @@ import (
|
||||
|
||||
"github.com/gin-contrib/sse"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
testdata "github.com/gin-gonic/gin/testdata/protoexample"
|
||||
)
|
||||
@ -234,7 +234,6 @@ func TestContextSetGetValues(t *testing.T) {
|
||||
assert.Exactly(t, c.MustGet("float32").(float32), float32(4.2))
|
||||
assert.Exactly(t, c.MustGet("float64").(float64), 4.2)
|
||||
assert.Exactly(t, c.MustGet("intInterface").(int), 1)
|
||||
|
||||
}
|
||||
|
||||
func TestContextGetString(t *testing.T) {
|
||||
@ -300,7 +299,7 @@ func TestContextGetStringSlice(t *testing.T) {
|
||||
|
||||
func TestContextGetStringMap(t *testing.T) {
|
||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
||||
var m = make(map[string]interface{})
|
||||
m := make(map[string]interface{})
|
||||
m["foo"] = 1
|
||||
c.Set("map", m)
|
||||
|
||||
@ -310,7 +309,7 @@ func TestContextGetStringMap(t *testing.T) {
|
||||
|
||||
func TestContextGetStringMapString(t *testing.T) {
|
||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
||||
var m = make(map[string]string)
|
||||
m := make(map[string]string)
|
||||
m["foo"] = "bar"
|
||||
c.Set("map", m)
|
||||
|
||||
@ -320,7 +319,7 @@ func TestContextGetStringMapString(t *testing.T) {
|
||||
|
||||
func TestContextGetStringMapStringSlice(t *testing.T) {
|
||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
||||
var m = make(map[string][]string)
|
||||
m := make(map[string][]string)
|
||||
m["foo"] = []string{"foo"}
|
||||
c.Set("map", m)
|
||||
|
||||
@ -369,15 +368,12 @@ func TestContextHandlerNames(t *testing.T) {
|
||||
}
|
||||
|
||||
func handlerNameTest(c *Context) {
|
||||
|
||||
}
|
||||
|
||||
func handlerNameTest2(c *Context) {
|
||||
|
||||
}
|
||||
|
||||
var handlerTest HandlerFunc = func(c *Context) {
|
||||
|
||||
}
|
||||
|
||||
func TestContextHandler(t *testing.T) {
|
||||
@ -659,8 +655,7 @@ func TestContextBodyAllowedForStatus(t *testing.T) {
|
||||
assert.True(t, true, bodyAllowedForStatus(http.StatusInternalServerError))
|
||||
}
|
||||
|
||||
type TestPanicRender struct {
|
||||
}
|
||||
type TestPanicRender struct{}
|
||||
|
||||
func (*TestPanicRender) Render(http.ResponseWriter) error {
|
||||
return errors.New("TestPanicRender")
|
||||
@ -1329,7 +1324,7 @@ func TestContextAbortWithStatusJSON(t *testing.T) {
|
||||
_, err := buf.ReadFrom(w.Body)
|
||||
assert.NoError(t, err)
|
||||
jsonStringBody := buf.String()
|
||||
assert.Equal(t, fmt.Sprint("{\"foo\":\"fooValue\",\"bar\":\"barValue\"}"), jsonStringBody)
|
||||
assert.Equal(t, "{\"foo\":\"fooValue\",\"bar\":\"barValue\"}", jsonStringBody)
|
||||
}
|
||||
|
||||
func TestContextError(t *testing.T) {
|
||||
@ -1545,6 +1540,7 @@ func TestContextBindWithJSON(t *testing.T) {
|
||||
assert.Equal(t, "bar", obj.Foo)
|
||||
assert.Equal(t, 0, w.Body.Len())
|
||||
}
|
||||
|
||||
func TestContextBindWithXML(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := CreateTestContext(w)
|
||||
@ -2058,6 +2054,50 @@ func TestRemoteIPFail(t *testing.T) {
|
||||
assert.False(t, trust)
|
||||
}
|
||||
|
||||
func TestContextWithFallbackDeadlineFromRequestContext(t *testing.T) {
|
||||
c := &Context{}
|
||||
deadline, ok := c.Deadline()
|
||||
assert.Zero(t, deadline)
|
||||
assert.False(t, ok)
|
||||
|
||||
c2 := &Context{}
|
||||
c2.Request, _ = http.NewRequest(http.MethodGet, "/", nil)
|
||||
d := time.Now().Add(time.Second)
|
||||
ctx, cancel := context.WithDeadline(context.Background(), d)
|
||||
defer cancel()
|
||||
c2.Request = c2.Request.WithContext(ctx)
|
||||
deadline, ok = c2.Deadline()
|
||||
assert.Equal(t, d, deadline)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
|
||||
func TestContextWithFallbackDoneFromRequestContext(t *testing.T) {
|
||||
c := &Context{}
|
||||
assert.Nil(t, c.Done())
|
||||
|
||||
c2 := &Context{}
|
||||
c2.Request, _ = http.NewRequest(http.MethodGet, "/", nil)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
c2.Request = c2.Request.WithContext(ctx)
|
||||
cancel()
|
||||
assert.NotNil(t, <-c2.Done())
|
||||
}
|
||||
|
||||
func TestContextWithFallbackErrFromRequestContext(t *testing.T) {
|
||||
c := &Context{}
|
||||
assert.Nil(t, c.Err())
|
||||
|
||||
c2 := &Context{}
|
||||
c2.Request, _ = http.NewRequest(http.MethodGet, "/", nil)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
c2.Request = c2.Request.WithContext(ctx)
|
||||
cancel()
|
||||
|
||||
assert.EqualError(t, c2.Err(), context.Canceled.Error())
|
||||
}
|
||||
|
||||
type contextKey string
|
||||
|
||||
func TestContextWithFallbackValueFromRequestContext(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@ -2080,8 +2120,8 @@ func TestContextWithFallbackValueFromRequestContext(t *testing.T) {
|
||||
getContextAndKey: func() (*Context, interface{}) {
|
||||
c := &Context{}
|
||||
c.Request, _ = http.NewRequest("POST", "/", nil)
|
||||
c.Request = c.Request.WithContext(context.WithValue(context.TODO(), "key", "value"))
|
||||
return c, "key"
|
||||
c.Request = c.Request.WithContext(context.WithValue(context.TODO(), contextKey("key"), "value"))
|
||||
return c, contextKey("key")
|
||||
},
|
||||
value: "value",
|
||||
},
|
||||
|
36
gin.go
36
gin.go
@ -99,6 +99,23 @@ type Engine struct {
|
||||
// `(*gin.Context).Request.RemoteAddr`.
|
||||
ForwardedByClientIP bool
|
||||
|
||||
// DEPRECATED: USE `TrustedPlatform` WITH VALUE `gin.GoogleAppEngine` INSTEAD
|
||||
// #726 #755 If enabled, it will trust some headers starting with
|
||||
// 'X-AppEngine...' for better integration with that PaaS.
|
||||
AppEngine bool
|
||||
|
||||
// If enabled, the url.RawPath will be used to find parameters.
|
||||
UseRawPath bool
|
||||
|
||||
// If true, the path value will be unescaped.
|
||||
// If UseRawPath is false (by default), the UnescapePathValues effectively is true,
|
||||
// as url.Path gonna be used, which is already unescaped.
|
||||
UnescapePathValues bool
|
||||
|
||||
// RemoveExtraSlash a parameter can be parsed from the URL even with extra slashes.
|
||||
// See the PR #1817 and issue #1644
|
||||
RemoveExtraSlash bool
|
||||
|
||||
// List of headers used to obtain the client IP when
|
||||
// `(*gin.Engine).ForwardedByClientIP` is `true` and
|
||||
// `(*gin.Context).Request.RemoteAddr` is matched by at least one of the
|
||||
@ -115,27 +132,10 @@ type Engine struct {
|
||||
// that platform, for example to determine the client IP
|
||||
TrustedPlatform string
|
||||
|
||||
// DEPRECATED: USE `TrustedPlatform` WITH VALUE `gin.GoogleAppEngine` INSTEAD
|
||||
// #726 #755 If enabled, it will trust some headers starting with
|
||||
// 'X-AppEngine...' for better integration with that PaaS.
|
||||
AppEngine bool
|
||||
|
||||
// If enabled, the url.RawPath will be used to find parameters.
|
||||
UseRawPath bool
|
||||
|
||||
// If true, the path value will be unescaped.
|
||||
// If UseRawPath is false (by default), the UnescapePathValues effectively is true,
|
||||
// as url.Path gonna be used, which is already unescaped.
|
||||
UnescapePathValues bool
|
||||
|
||||
// Value of 'maxMemory' param that is given to http.Request's ParseMultipartForm
|
||||
// method call.
|
||||
MaxMultipartMemory int64
|
||||
|
||||
// RemoveExtraSlash a parameter can be parsed from the URL even with extra slashes.
|
||||
// See the PR #1817 and issue #1644
|
||||
RemoveExtraSlash bool
|
||||
|
||||
delims render.Delims
|
||||
secureJSONPrefix string
|
||||
HTMLRender render.HTMLRender
|
||||
@ -539,7 +539,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
|
||||
c.writermem.WriteHeaderNow()
|
||||
return
|
||||
}
|
||||
if httpMethod != "CONNECT" && rPath != "/" {
|
||||
if httpMethod != http.MethodConnect && rPath != "/" {
|
||||
if value.tsr && engine.RedirectTrailingSlash {
|
||||
redirectTrailingSlash(c)
|
||||
return
|
||||
|
@ -22,7 +22,15 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testRequest(t *testing.T, url string) {
|
||||
// params[0]=url example:http://127.0.0.1:8080/index (cannot be empty)
|
||||
// params[1]=response status (custom compare status) default:"200 OK"
|
||||
// params[2]=response body (custom compare content) default:"it worked"
|
||||
func testRequest(t *testing.T, params ...string) {
|
||||
|
||||
if len(params) == 0 {
|
||||
t.Fatal("url cannot be empty")
|
||||
}
|
||||
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
@ -30,14 +38,27 @@ func testRequest(t *testing.T, url string) {
|
||||
}
|
||||
client := &http.Client{Transport: tr}
|
||||
|
||||
resp, err := client.Get(url)
|
||||
resp, err := client.Get(params[0])
|
||||
assert.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, ioerr := ioutil.ReadAll(resp.Body)
|
||||
assert.NoError(t, ioerr)
|
||||
assert.Equal(t, "it worked", string(body), "resp body should match")
|
||||
assert.Equal(t, "200 OK", resp.Status, "should get a 200")
|
||||
|
||||
var responseStatus = "200 OK"
|
||||
if len(params) > 1 && params[1] != "" {
|
||||
responseStatus = params[1]
|
||||
}
|
||||
|
||||
var responseBody = "it worked"
|
||||
if len(params) > 2 && params[2] != "" {
|
||||
responseBody = params[2]
|
||||
}
|
||||
|
||||
assert.Equal(t, responseStatus, resp.Status, "should get a "+responseStatus)
|
||||
if responseStatus == "200 OK" {
|
||||
assert.Equal(t, responseBody, string(body), "resp body should match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunEmpty(t *testing.T) {
|
||||
@ -373,3 +394,134 @@ func testGetRequestHandler(t *testing.T, h http.Handler, url string) {
|
||||
assert.Equal(t, "it worked", w.Body.String(), "resp body should match")
|
||||
assert.Equal(t, 200, w.Code, "should get a 200")
|
||||
}
|
||||
|
||||
func TestTreeRunDynamicRouting(t *testing.T) {
|
||||
router := New()
|
||||
router.GET("/aa/*xx", func(c *Context) { c.String(http.StatusOK, "/aa/*xx") })
|
||||
router.GET("/ab/*xx", func(c *Context) { c.String(http.StatusOK, "/ab/*xx") })
|
||||
router.GET("/", func(c *Context) { c.String(http.StatusOK, "home") })
|
||||
router.GET("/:cc", func(c *Context) { c.String(http.StatusOK, "/:cc") })
|
||||
router.GET("/:cc/cc", func(c *Context) { c.String(http.StatusOK, "/:cc/cc") })
|
||||
router.GET("/:cc/:dd/ee", func(c *Context) { c.String(http.StatusOK, "/:cc/:dd/ee") })
|
||||
router.GET("/:cc/:dd/:ee/ff", func(c *Context) { c.String(http.StatusOK, "/:cc/:dd/:ee/ff") })
|
||||
router.GET("/:cc/:dd/:ee/:ff/gg", func(c *Context) { c.String(http.StatusOK, "/:cc/:dd/:ee/:ff/gg") })
|
||||
router.GET("/:cc/:dd/:ee/:ff/:gg/hh", func(c *Context) { c.String(http.StatusOK, "/:cc/:dd/:ee/:ff/:gg/hh") })
|
||||
router.GET("/get/test/abc/", func(c *Context) { c.String(http.StatusOK, "/get/test/abc/") })
|
||||
router.GET("/get/:param/abc/", func(c *Context) { c.String(http.StatusOK, "/get/:param/abc/") })
|
||||
router.GET("/something/:paramname/thirdthing", func(c *Context) { c.String(http.StatusOK, "/something/:paramname/thirdthing") })
|
||||
router.GET("/something/secondthing/test", func(c *Context) { c.String(http.StatusOK, "/something/secondthing/test") })
|
||||
router.GET("/get/abc", func(c *Context) { c.String(http.StatusOK, "/get/abc") })
|
||||
router.GET("/get/:param", func(c *Context) { c.String(http.StatusOK, "/get/:param") })
|
||||
router.GET("/get/abc/123abc", func(c *Context) { c.String(http.StatusOK, "/get/abc/123abc") })
|
||||
router.GET("/get/abc/:param", func(c *Context) { c.String(http.StatusOK, "/get/abc/:param") })
|
||||
router.GET("/get/abc/123abc/xxx8", func(c *Context) { c.String(http.StatusOK, "/get/abc/123abc/xxx8") })
|
||||
router.GET("/get/abc/123abc/:param", func(c *Context) { c.String(http.StatusOK, "/get/abc/123abc/:param") })
|
||||
router.GET("/get/abc/123abc/xxx8/1234", func(c *Context) { c.String(http.StatusOK, "/get/abc/123abc/xxx8/1234") })
|
||||
router.GET("/get/abc/123abc/xxx8/:param", func(c *Context) { c.String(http.StatusOK, "/get/abc/123abc/xxx8/:param") })
|
||||
router.GET("/get/abc/123abc/xxx8/1234/ffas", func(c *Context) { c.String(http.StatusOK, "/get/abc/123abc/xxx8/1234/ffas") })
|
||||
router.GET("/get/abc/123abc/xxx8/1234/:param", func(c *Context) { c.String(http.StatusOK, "/get/abc/123abc/xxx8/1234/:param") })
|
||||
router.GET("/get/abc/123abc/xxx8/1234/kkdd/12c", func(c *Context) { c.String(http.StatusOK, "/get/abc/123abc/xxx8/1234/kkdd/12c") })
|
||||
router.GET("/get/abc/123abc/xxx8/1234/kkdd/:param", func(c *Context) { c.String(http.StatusOK, "/get/abc/123abc/xxx8/1234/kkdd/:param") })
|
||||
router.GET("/get/abc/:param/test", func(c *Context) { c.String(http.StatusOK, "/get/abc/:param/test") })
|
||||
router.GET("/get/abc/123abd/:param", func(c *Context) { c.String(http.StatusOK, "/get/abc/123abd/:param") })
|
||||
router.GET("/get/abc/123abddd/:param", func(c *Context) { c.String(http.StatusOK, "/get/abc/123abddd/:param") })
|
||||
router.GET("/get/abc/123/:param", func(c *Context) { c.String(http.StatusOK, "/get/abc/123/:param") })
|
||||
router.GET("/get/abc/123abg/:param", func(c *Context) { c.String(http.StatusOK, "/get/abc/123abg/:param") })
|
||||
router.GET("/get/abc/123abf/:param", func(c *Context) { c.String(http.StatusOK, "/get/abc/123abf/:param") })
|
||||
router.GET("/get/abc/123abfff/:param", func(c *Context) { c.String(http.StatusOK, "/get/abc/123abfff/:param") })
|
||||
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
testRequest(t, ts.URL+"/", "", "home")
|
||||
testRequest(t, ts.URL+"/aa/aa", "", "/aa/*xx")
|
||||
testRequest(t, ts.URL+"/ab/ab", "", "/ab/*xx")
|
||||
testRequest(t, ts.URL+"/all", "", "/:cc")
|
||||
testRequest(t, ts.URL+"/all/cc", "", "/:cc/cc")
|
||||
testRequest(t, ts.URL+"/a/cc", "", "/:cc/cc")
|
||||
testRequest(t, ts.URL+"/c/d/ee", "", "/:cc/:dd/ee")
|
||||
testRequest(t, ts.URL+"/c/d/e/ff", "", "/:cc/:dd/:ee/ff")
|
||||
testRequest(t, ts.URL+"/c/d/e/f/gg", "", "/:cc/:dd/:ee/:ff/gg")
|
||||
testRequest(t, ts.URL+"/c/d/e/f/g/hh", "", "/:cc/:dd/:ee/:ff/:gg/hh")
|
||||
testRequest(t, ts.URL+"/cc/dd/ee/ff/gg/hh", "", "/:cc/:dd/:ee/:ff/:gg/hh")
|
||||
testRequest(t, ts.URL+"/a", "", "/:cc")
|
||||
testRequest(t, ts.URL+"/d", "", "/:cc")
|
||||
testRequest(t, ts.URL+"/ad", "", "/:cc")
|
||||
testRequest(t, ts.URL+"/dd", "", "/:cc")
|
||||
testRequest(t, ts.URL+"/aa", "", "/:cc")
|
||||
testRequest(t, ts.URL+"/aaa", "", "/:cc")
|
||||
testRequest(t, ts.URL+"/aaa/cc", "", "/:cc/cc")
|
||||
testRequest(t, ts.URL+"/ab", "", "/:cc")
|
||||
testRequest(t, ts.URL+"/abb", "", "/:cc")
|
||||
testRequest(t, ts.URL+"/abb/cc", "", "/:cc/cc")
|
||||
testRequest(t, ts.URL+"/dddaa", "", "/:cc")
|
||||
testRequest(t, ts.URL+"/allxxxx", "", "/:cc")
|
||||
testRequest(t, ts.URL+"/alldd", "", "/:cc")
|
||||
testRequest(t, ts.URL+"/cc/cc", "", "/:cc/cc")
|
||||
testRequest(t, ts.URL+"/ccc/cc", "", "/:cc/cc")
|
||||
testRequest(t, ts.URL+"/deedwjfs/cc", "", "/:cc/cc")
|
||||
testRequest(t, ts.URL+"/acllcc/cc", "", "/:cc/cc")
|
||||
testRequest(t, ts.URL+"/get/test/abc/", "", "/get/test/abc/")
|
||||
testRequest(t, ts.URL+"/get/testaa/abc/", "", "/get/:param/abc/")
|
||||
testRequest(t, ts.URL+"/get/te/abc/", "", "/get/:param/abc/")
|
||||
testRequest(t, ts.URL+"/get/xx/abc/", "", "/get/:param/abc/")
|
||||
testRequest(t, ts.URL+"/get/tt/abc/", "", "/get/:param/abc/")
|
||||
testRequest(t, ts.URL+"/get/a/abc/", "", "/get/:param/abc/")
|
||||
testRequest(t, ts.URL+"/get/t/abc/", "", "/get/:param/abc/")
|
||||
testRequest(t, ts.URL+"/get/aa/abc/", "", "/get/:param/abc/")
|
||||
testRequest(t, ts.URL+"/get/abas/abc/", "", "/get/:param/abc/")
|
||||
testRequest(t, ts.URL+"/something/secondthing/test", "", "/something/secondthing/test")
|
||||
testRequest(t, ts.URL+"/something/secondthingaaaa/thirdthing", "", "/something/:paramname/thirdthing")
|
||||
testRequest(t, ts.URL+"/something/abcdad/thirdthing", "", "/something/:paramname/thirdthing")
|
||||
testRequest(t, ts.URL+"/something/se/thirdthing", "", "/something/:paramname/thirdthing")
|
||||
testRequest(t, ts.URL+"/something/s/thirdthing", "", "/something/:paramname/thirdthing")
|
||||
testRequest(t, ts.URL+"/something/secondthing/thirdthing", "", "/something/:paramname/thirdthing")
|
||||
testRequest(t, ts.URL+"/get/abc", "", "/get/abc")
|
||||
testRequest(t, ts.URL+"/get/a", "", "/get/:param")
|
||||
testRequest(t, ts.URL+"/get/abz", "", "/get/:param")
|
||||
testRequest(t, ts.URL+"/get/12a", "", "/get/:param")
|
||||
testRequest(t, ts.URL+"/get/abcd", "", "/get/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc", "", "/get/abc/123abc")
|
||||
testRequest(t, ts.URL+"/get/abc/12", "", "/get/abc/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123ab", "", "/get/abc/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/xyz", "", "/get/abc/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abcddxx", "", "/get/abc/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx8", "", "/get/abc/123abc/xxx8")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/x", "", "/get/abc/123abc/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx", "", "/get/abc/123abc/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/abc", "", "/get/abc/123abc/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx8xxas", "", "/get/abc/123abc/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx8/1234", "", "/get/abc/123abc/xxx8/1234")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx8/1", "", "/get/abc/123abc/xxx8/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx8/123", "", "/get/abc/123abc/xxx8/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx8/78k", "", "/get/abc/123abc/xxx8/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx8/1234xxxd", "", "/get/abc/123abc/xxx8/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx8/1234/ffas", "", "/get/abc/123abc/xxx8/1234/ffas")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx8/1234/f", "", "/get/abc/123abc/xxx8/1234/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx8/1234/ffa", "", "/get/abc/123abc/xxx8/1234/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx8/1234/kka", "", "/get/abc/123abc/xxx8/1234/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx8/1234/ffas321", "", "/get/abc/123abc/xxx8/1234/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx8/1234/kkdd/12c", "", "/get/abc/123abc/xxx8/1234/kkdd/12c")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx8/1234/kkdd/1", "", "/get/abc/123abc/xxx8/1234/kkdd/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx8/1234/kkdd/12", "", "/get/abc/123abc/xxx8/1234/kkdd/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx8/1234/kkdd/12b", "", "/get/abc/123abc/xxx8/1234/kkdd/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx8/1234/kkdd/34", "", "/get/abc/123abc/xxx8/1234/kkdd/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abc/xxx8/1234/kkdd/12c2e3", "", "/get/abc/123abc/xxx8/1234/kkdd/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/12/test", "", "/get/abc/:param/test")
|
||||
testRequest(t, ts.URL+"/get/abc/123abdd/test", "", "/get/abc/:param/test")
|
||||
testRequest(t, ts.URL+"/get/abc/123abdddf/test", "", "/get/abc/:param/test")
|
||||
testRequest(t, ts.URL+"/get/abc/123ab/test", "", "/get/abc/:param/test")
|
||||
testRequest(t, ts.URL+"/get/abc/123abgg/test", "", "/get/abc/:param/test")
|
||||
testRequest(t, ts.URL+"/get/abc/123abff/test", "", "/get/abc/:param/test")
|
||||
testRequest(t, ts.URL+"/get/abc/123abffff/test", "", "/get/abc/:param/test")
|
||||
testRequest(t, ts.URL+"/get/abc/123abd/test", "", "/get/abc/123abd/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abddd/test", "", "/get/abc/123abddd/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123/test22", "", "/get/abc/123/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abg/test", "", "/get/abc/123abg/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abf/testss", "", "/get/abc/123abf/:param")
|
||||
testRequest(t, ts.URL+"/get/abc/123abfff/te", "", "/get/abc/123abfff/:param")
|
||||
// 404 not found
|
||||
testRequest(t, ts.URL+"/a/dd", "404 Not Found")
|
||||
testRequest(t, ts.URL+"/addr/dd/aa", "404 Not Found")
|
||||
testRequest(t, ts.URL+"/something/secondthing/121", "404 Not Found")
|
||||
}
|
||||
|
14
go.mod
14
go.mod
@ -4,12 +4,12 @@ go 1.13
|
||||
|
||||
require (
|
||||
github.com/gin-contrib/sse v0.1.0
|
||||
github.com/go-playground/validator/v10 v10.6.1
|
||||
github.com/goccy/go-json v0.5.1
|
||||
github.com/golang/protobuf v1.3.3
|
||||
github.com/json-iterator/go v1.1.9
|
||||
github.com/mattn/go-isatty v0.0.12
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/go-playground/validator/v10 v10.9.0
|
||||
github.com/goccy/go-json v0.7.6
|
||||
github.com/json-iterator/go v1.1.11
|
||||
github.com/mattn/go-isatty v0.0.13
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/ugorji/go/codec v1.2.6
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
google.golang.org/protobuf v1.27.1
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
90
go.sum
90
go.sum
@ -1,3 +1,4 @@
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
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=
|
||||
@ -5,51 +6,76 @@ 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/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.6.1 h1:W6TRDXt4WcWp4c4nf/G+6BkGdhiIo0k417gfr+V6u4I=
|
||||
github.com/go-playground/validator/v10 v10.6.1/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk=
|
||||
github.com/goccy/go-json v0.5.1 h1:R9UYTOUvo7eIY9aeDMZ4L6OVtHaSr1k2No9W6MKjXrA=
|
||||
github.com/goccy/go-json v0.5.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
|
||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
|
||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
github.com/go-playground/validator/v10 v10.9.0 h1:NgTtmN58D0m8+UuxtYmGztBJB7VnPgjj221I1QHci2A=
|
||||
github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||
github.com/goccy/go-json v0.7.6 h1:H0wq4jppBQ+9222sk5+hPLL25abZQiRuQ6YPnjO9c+A=
|
||||
github.com/goccy/go-json v0.7.6/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/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
|
||||
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
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/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/ugorji/go v1.2.6 h1:tGiWC9HENWE2tqYycIqFTNorMmFRVhNwCpDOpWqnk8E=
|
||||
github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
|
||||
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
|
||||
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 h1:siQdpVirKtzPhKl3lZWozZraCFObP8S1v6PRp0bLrtU=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
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.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
6
mode.go
6
mode.go
@ -41,8 +41,10 @@ var DefaultWriter io.Writer = os.Stdout
|
||||
// DefaultErrorWriter is the default io.Writer used by Gin to debug errors
|
||||
var DefaultErrorWriter io.Writer = os.Stderr
|
||||
|
||||
var ginMode = debugCode
|
||||
var modeName = DebugMode
|
||||
var (
|
||||
ginMode = debugCode
|
||||
modeName = DebugMode
|
||||
)
|
||||
|
||||
func init() {
|
||||
mode := os.Getenv(EnvGinMode)
|
||||
|
@ -92,14 +92,14 @@ func TestPanicWithAbort(t *testing.T) {
|
||||
|
||||
func TestSource(t *testing.T) {
|
||||
bs := source(nil, 0)
|
||||
assert.Equal(t, []byte("???"), bs)
|
||||
assert.Equal(t, dunno, bs)
|
||||
|
||||
in := [][]byte{
|
||||
[]byte("Hello world."),
|
||||
[]byte("Hi, gin.."),
|
||||
}
|
||||
bs = source(in, 10)
|
||||
assert.Equal(t, []byte("???"), bs)
|
||||
assert.Equal(t, dunno, bs)
|
||||
|
||||
bs = source(in, 1)
|
||||
assert.Equal(t, []byte("Hello world."), bs)
|
||||
@ -107,7 +107,7 @@ func TestSource(t *testing.T) {
|
||||
|
||||
func TestFunction(t *testing.T) {
|
||||
bs := function(1)
|
||||
assert.Equal(t, []byte("???"), bs)
|
||||
assert.Equal(t, dunno, bs)
|
||||
}
|
||||
|
||||
// TestPanicWithBrokenPipe asserts that recovery specifically handles
|
||||
|
@ -49,7 +49,7 @@ type PureJSON struct {
|
||||
var (
|
||||
jsonContentType = []string{"application/json; charset=utf-8"}
|
||||
jsonpContentType = []string{"application/javascript; charset=utf-8"}
|
||||
jsonAsciiContentType = []string{"application/json"}
|
||||
jsonASCIIContentType = []string{"application/json"}
|
||||
)
|
||||
|
||||
// Render (JSON) writes data with custom ContentType.
|
||||
@ -178,7 +178,7 @@ func (r AsciiJSON) Render(w http.ResponseWriter) (err error) {
|
||||
|
||||
// WriteContentType (AsciiJSON) writes JSON ContentType.
|
||||
func (r AsciiJSON) WriteContentType(w http.ResponseWriter) {
|
||||
writeContentType(w, jsonAsciiContentType)
|
||||
writeContentType(w, jsonASCIIContentType)
|
||||
}
|
||||
|
||||
// Render (PureJSON) writes custom ContentType and encodes the given interface object.
|
||||
|
@ -7,7 +7,7 @@ package render
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// ProtoBuf contains the given interface object.
|
||||
|
@ -14,8 +14,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
testdata "github.com/gin-gonic/gin/testdata/protoexample"
|
||||
)
|
||||
@ -420,7 +420,8 @@ func TestRenderHTMLTemplateEmptyName(t *testing.T) {
|
||||
|
||||
func TestRenderHTMLDebugFiles(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
htmlRender := HTMLDebug{Files: []string{"../testdata/template/hello.tmpl"},
|
||||
htmlRender := HTMLDebug{
|
||||
Files: []string{"../testdata/template/hello.tmpl"},
|
||||
Glob: "",
|
||||
Delims: Delims{Left: "{[{", Right: "}]}"},
|
||||
FuncMap: nil,
|
||||
@ -438,7 +439,8 @@ func TestRenderHTMLDebugFiles(t *testing.T) {
|
||||
|
||||
func TestRenderHTMLDebugGlob(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
htmlRender := HTMLDebug{Files: nil,
|
||||
htmlRender := HTMLDebug{
|
||||
Files: nil,
|
||||
Glob: "../testdata/template/hello*",
|
||||
Delims: Delims{Left: "{[{", Right: "}]}"},
|
||||
FuncMap: nil,
|
||||
@ -455,7 +457,8 @@ func TestRenderHTMLDebugGlob(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRenderHTMLDebugPanics(t *testing.T) {
|
||||
htmlRender := HTMLDebug{Files: nil,
|
||||
htmlRender := HTMLDebug{
|
||||
Files: nil,
|
||||
Glob: "",
|
||||
Delims: Delims{"{{", "}}"},
|
||||
FuncMap: nil,
|
||||
|
@ -17,12 +17,14 @@ import (
|
||||
// func (w *responseWriter) CloseNotify() <-chan bool {
|
||||
// func (w *responseWriter) Flush() {
|
||||
|
||||
var _ ResponseWriter = &responseWriter{}
|
||||
var _ http.ResponseWriter = &responseWriter{}
|
||||
var _ http.ResponseWriter = ResponseWriter(&responseWriter{})
|
||||
var _ http.Hijacker = ResponseWriter(&responseWriter{})
|
||||
var _ http.Flusher = ResponseWriter(&responseWriter{})
|
||||
var _ http.CloseNotifier = ResponseWriter(&responseWriter{})
|
||||
var (
|
||||
_ ResponseWriter = &responseWriter{}
|
||||
_ http.ResponseWriter = &responseWriter{}
|
||||
_ http.ResponseWriter = ResponseWriter(&responseWriter{})
|
||||
_ http.Hijacker = ResponseWriter(&responseWriter{})
|
||||
_ http.Flusher = ResponseWriter(&responseWriter{})
|
||||
_ http.CloseNotifier = ResponseWriter(&responseWriter{})
|
||||
)
|
||||
|
||||
func init() {
|
||||
SetMode(TestMode)
|
||||
|
@ -214,9 +214,7 @@ func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileS
|
||||
|
||||
func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain {
|
||||
finalSize := len(group.Handlers) + len(handlers)
|
||||
if finalSize >= int(abortIndex) {
|
||||
panic("too many handlers")
|
||||
}
|
||||
assert1(finalSize < int(abortIndex), "too many handlers")
|
||||
mergedHandlers := make(HandlersChain, finalSize)
|
||||
copy(mergedHandlers, group.Handlers)
|
||||
copy(mergedHandlers[len(group.Handlers):], handlers)
|
||||
|
@ -112,15 +112,19 @@ func TestRouterGroupInvalidStaticFile(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRouterGroupTooManyHandlers(t *testing.T) {
|
||||
const (
|
||||
panicValue = "too many handlers"
|
||||
maximumCnt = abortIndex
|
||||
)
|
||||
router := New()
|
||||
handlers1 := make([]HandlerFunc, 40)
|
||||
handlers1 := make([]HandlerFunc, maximumCnt-1)
|
||||
router.Use(handlers1...)
|
||||
|
||||
handlers2 := make([]HandlerFunc, 26)
|
||||
assert.Panics(t, func() {
|
||||
handlers2 := make([]HandlerFunc, maximumCnt+1)
|
||||
assert.PanicsWithValue(t, panicValue, func() {
|
||||
router.Use(handlers2...)
|
||||
})
|
||||
assert.Panics(t, func() {
|
||||
assert.PanicsWithValue(t, panicValue, func() {
|
||||
router.GET("/", handlers2...)
|
||||
})
|
||||
}
|
||||
|
301
testdata/protoexample/test.pb.go
vendored
301
testdata/protoexample/test.pb.go
vendored
@ -1,24 +1,24 @@
|
||||
// Code generated by protoc-gen-go.
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.0
|
||||
// protoc v3.15.8
|
||||
// source: test.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package protoexample is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
test.proto
|
||||
|
||||
It has these top-level messages:
|
||||
Test
|
||||
*/
|
||||
package protoexample
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import math "math"
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = math.Inf
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type FOO int32
|
||||
|
||||
@ -26,88 +26,273 @@ const (
|
||||
FOO_X FOO = 17
|
||||
)
|
||||
|
||||
var FOO_name = map[int32]string{
|
||||
17: "X",
|
||||
}
|
||||
var FOO_value = map[string]int32{
|
||||
"X": 17,
|
||||
}
|
||||
// Enum value maps for FOO.
|
||||
var (
|
||||
FOO_name = map[int32]string{
|
||||
17: "X",
|
||||
}
|
||||
FOO_value = map[string]int32{
|
||||
"X": 17,
|
||||
}
|
||||
)
|
||||
|
||||
func (x FOO) Enum() *FOO {
|
||||
p := new(FOO)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x FOO) String() string {
|
||||
return proto.EnumName(FOO_name, int32(x))
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
func (x *FOO) UnmarshalJSON(data []byte) error {
|
||||
value, err := proto.UnmarshalJSONEnum(FOO_value, data, "FOO")
|
||||
|
||||
func (FOO) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_test_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (FOO) Type() protoreflect.EnumType {
|
||||
return &file_test_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x FOO) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Do not use.
|
||||
func (x *FOO) UnmarshalJSON(b []byte) error {
|
||||
num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*x = FOO(value)
|
||||
*x = FOO(num)
|
||||
return nil
|
||||
}
|
||||
|
||||
type Test struct {
|
||||
Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"`
|
||||
Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"`
|
||||
Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"`
|
||||
Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
// Deprecated: Use FOO.Descriptor instead.
|
||||
func (FOO) EnumDescriptor() ([]byte, []int) {
|
||||
return file_test_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (m *Test) Reset() { *m = Test{} }
|
||||
func (m *Test) String() string { return proto.CompactTextString(m) }
|
||||
func (*Test) ProtoMessage() {}
|
||||
type Test struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
const Default_Test_Type int32 = 77
|
||||
Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"`
|
||||
Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"`
|
||||
Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"`
|
||||
Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup,json=optionalgroup" json:"optionalgroup,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Test) GetLabel() string {
|
||||
if m != nil && m.Label != nil {
|
||||
return *m.Label
|
||||
// Default values for Test fields.
|
||||
const (
|
||||
Default_Test_Type = int32(77)
|
||||
)
|
||||
|
||||
func (x *Test) Reset() {
|
||||
*x = Test{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_test_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Test) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Test) ProtoMessage() {}
|
||||
|
||||
func (x *Test) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_test_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Test.ProtoReflect.Descriptor instead.
|
||||
func (*Test) Descriptor() ([]byte, []int) {
|
||||
return file_test_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Test) GetLabel() string {
|
||||
if x != nil && x.Label != nil {
|
||||
return *x.Label
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Test) GetType() int32 {
|
||||
if m != nil && m.Type != nil {
|
||||
return *m.Type
|
||||
func (x *Test) GetType() int32 {
|
||||
if x != nil && x.Type != nil {
|
||||
return *x.Type
|
||||
}
|
||||
return Default_Test_Type
|
||||
}
|
||||
|
||||
func (m *Test) GetReps() []int64 {
|
||||
if m != nil {
|
||||
return m.Reps
|
||||
func (x *Test) GetReps() []int64 {
|
||||
if x != nil {
|
||||
return x.Reps
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Test) GetOptionalgroup() *Test_OptionalGroup {
|
||||
if m != nil {
|
||||
return m.Optionalgroup
|
||||
func (x *Test) GetOptionalgroup() *Test_OptionalGroup {
|
||||
if x != nil {
|
||||
return x.Optionalgroup
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Test_OptionalGroup struct {
|
||||
RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
RequiredField *string `protobuf:"bytes,5,req,name=RequiredField" json:"RequiredField,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} }
|
||||
func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) }
|
||||
func (*Test_OptionalGroup) ProtoMessage() {}
|
||||
func (x *Test_OptionalGroup) Reset() {
|
||||
*x = Test_OptionalGroup{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_test_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Test_OptionalGroup) GetRequiredField() string {
|
||||
if m != nil && m.RequiredField != nil {
|
||||
return *m.RequiredField
|
||||
func (x *Test_OptionalGroup) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Test_OptionalGroup) ProtoMessage() {}
|
||||
|
||||
func (x *Test_OptionalGroup) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_test_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Test_OptionalGroup.ProtoReflect.Descriptor instead.
|
||||
func (*Test_OptionalGroup) Descriptor() ([]byte, []int) {
|
||||
return file_test_proto_rawDescGZIP(), []int{0, 0}
|
||||
}
|
||||
|
||||
func (x *Test_OptionalGroup) GetRequiredField() string {
|
||||
if x != nil && x.RequiredField != nil {
|
||||
return *x.RequiredField
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterEnum("protoexample.FOO", FOO_name, FOO_value)
|
||||
var File_test_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_test_proto_rawDesc = []byte{
|
||||
0x0a, 0x0a, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x22, 0xc7, 0x01, 0x0a, 0x04, 0x54,
|
||||
0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x02,
|
||||
0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x04, 0x74, 0x79, 0x70,
|
||||
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x3a, 0x02, 0x37, 0x37, 0x52, 0x04, 0x74, 0x79, 0x70,
|
||||
0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x03, 0x52,
|
||||
0x04, 0x72, 0x65, 0x70, 0x73, 0x12, 0x46, 0x0a, 0x0d, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61,
|
||||
0x6c, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0a, 0x32, 0x20, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x54, 0x65, 0x73, 0x74,
|
||||
0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x0d,
|
||||
0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x1a, 0x35, 0x0a,
|
||||
0x0d, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x24,
|
||||
0x0a, 0x0d, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x18,
|
||||
0x05, 0x20, 0x02, 0x28, 0x09, 0x52, 0x0d, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x46,
|
||||
0x69, 0x65, 0x6c, 0x64, 0x2a, 0x0c, 0x0a, 0x03, 0x46, 0x4f, 0x4f, 0x12, 0x05, 0x0a, 0x01, 0x58,
|
||||
0x10, 0x11,
|
||||
}
|
||||
|
||||
var (
|
||||
file_test_proto_rawDescOnce sync.Once
|
||||
file_test_proto_rawDescData = file_test_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_test_proto_rawDescGZIP() []byte {
|
||||
file_test_proto_rawDescOnce.Do(func() {
|
||||
file_test_proto_rawDescData = protoimpl.X.CompressGZIP(file_test_proto_rawDescData)
|
||||
})
|
||||
return file_test_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_test_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_test_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_test_proto_goTypes = []interface{}{
|
||||
(FOO)(0), // 0: protoexample.FOO
|
||||
(*Test)(nil), // 1: protoexample.Test
|
||||
(*Test_OptionalGroup)(nil), // 2: protoexample.Test.OptionalGroup
|
||||
}
|
||||
var file_test_proto_depIdxs = []int32{
|
||||
2, // 0: protoexample.Test.optionalgroup:type_name -> protoexample.Test.OptionalGroup
|
||||
1, // [1:1] is the sub-list for method output_type
|
||||
1, // [1:1] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_test_proto_init() }
|
||||
func file_test_proto_init() {
|
||||
if File_test_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_test_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Test); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_test_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Test_OptionalGroup); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_test_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_test_proto_goTypes,
|
||||
DependencyIndexes: file_test_proto_depIdxs,
|
||||
EnumInfos: file_test_proto_enumTypes,
|
||||
MessageInfos: file_test_proto_msgTypes,
|
||||
}.Build()
|
||||
File_test_proto = out.File
|
||||
file_test_proto_rawDesc = nil
|
||||
file_test_proto_goTypes = nil
|
||||
file_test_proto_depIdxs = nil
|
||||
}
|
||||
|
77
tree.go
77
tree.go
@ -118,11 +118,6 @@ type node struct {
|
||||
fullPath string
|
||||
}
|
||||
|
||||
type skip struct {
|
||||
path string
|
||||
paramNode *node
|
||||
}
|
||||
|
||||
// Increments priority of the given child and reorders if necessary
|
||||
func (n *node) incrementChildPrio(pos int) int {
|
||||
cs := n.children
|
||||
@ -405,7 +400,10 @@ type nodeValue struct {
|
||||
// made if a handle exists with an extra (without the) trailing slash for the
|
||||
// given path.
|
||||
func (n *node) getValue(path string, params *Params, unescape bool) (value nodeValue) {
|
||||
var skipped *skip
|
||||
var (
|
||||
skippedPath string
|
||||
latestNode = n // Caching the latest node
|
||||
)
|
||||
|
||||
walk: // Outer loop for walking the tree
|
||||
for {
|
||||
@ -418,18 +416,17 @@ walk: // Outer loop for walking the tree
|
||||
idxc := path[0]
|
||||
for i, c := range []byte(n.indices) {
|
||||
if c == idxc {
|
||||
if strings.HasPrefix(n.children[len(n.children)-1].path, ":") {
|
||||
skipped = &skip{
|
||||
path: prefix + path,
|
||||
paramNode: &node{
|
||||
path: n.path,
|
||||
wildChild: n.wildChild,
|
||||
nType: n.nType,
|
||||
priority: n.priority,
|
||||
children: n.children,
|
||||
handlers: n.handlers,
|
||||
fullPath: n.fullPath,
|
||||
},
|
||||
// strings.HasPrefix(n.children[len(n.children)-1].path, ":") == n.wildChild
|
||||
if n.wildChild {
|
||||
skippedPath = prefix + path
|
||||
latestNode = &node{
|
||||
path: n.path,
|
||||
wildChild: n.wildChild,
|
||||
nType: n.nType,
|
||||
priority: n.priority,
|
||||
children: n.children,
|
||||
handlers: n.handlers,
|
||||
fullPath: n.fullPath,
|
||||
}
|
||||
}
|
||||
|
||||
@ -437,13 +434,19 @@ walk: // Outer loop for walking the tree
|
||||
continue walk
|
||||
}
|
||||
}
|
||||
// If the path at the end of the loop is not equal to '/' and the current node has no child nodes
|
||||
// the current node needs to be equal to the latest matching node
|
||||
matched := path != "/" && !n.wildChild
|
||||
if matched {
|
||||
n = latestNode
|
||||
}
|
||||
|
||||
// If there is no wildcard pattern, recommend a redirection
|
||||
if !n.wildChild {
|
||||
// Nothing found.
|
||||
// We can recommend to redirect to the same URL without a
|
||||
// trailing slash if a leaf exists for that path.
|
||||
value.tsr = (path == "/" && n.handlers != nil)
|
||||
value.tsr = path == "/" && n.handlers != nil
|
||||
return
|
||||
}
|
||||
|
||||
@ -452,6 +455,16 @@ walk: // Outer loop for walking the tree
|
||||
|
||||
switch n.nType {
|
||||
case param:
|
||||
// fix truncate the parameter
|
||||
// tree_test.go line: 204
|
||||
if matched {
|
||||
path = prefix + path
|
||||
// The saved path is used after the prefix route is intercepted by matching
|
||||
if n.indices == "/" {
|
||||
path = skippedPath[1:]
|
||||
}
|
||||
}
|
||||
|
||||
// Find param end (either '/' or path end)
|
||||
end := 0
|
||||
for end < len(path) && path[end] != '/' {
|
||||
@ -535,6 +548,11 @@ walk: // Outer loop for walking the tree
|
||||
}
|
||||
|
||||
if path == prefix {
|
||||
// If the current path does not equal '/' and the node does not have a registered handle and the most recently matched node has a child node
|
||||
// the current node needs to be equal to the latest matching node
|
||||
if latestNode.wildChild && n.handlers == nil && path != "/" {
|
||||
n = latestNode.children[len(latestNode.children)-1]
|
||||
}
|
||||
// We should have reached the node containing the handle.
|
||||
// Check if this node has a handle registered.
|
||||
if value.handlers = n.handlers; value.handlers != nil {
|
||||
@ -564,18 +582,25 @@ walk: // Outer loop for walking the tree
|
||||
return
|
||||
}
|
||||
|
||||
if path != "/" && skipped != nil && strings.HasSuffix(skipped.path, path) {
|
||||
path = skipped.path
|
||||
n = skipped.paramNode
|
||||
skipped = nil
|
||||
if path != "/" && len(skippedPath) > 0 && strings.HasSuffix(skippedPath, path) {
|
||||
path = skippedPath
|
||||
// Reduce the number of cycles
|
||||
n, latestNode = latestNode, n
|
||||
// skippedPath cannot execute
|
||||
// example:
|
||||
// * /:cc/cc
|
||||
// call /a/cc expectations:match/200 Actual:match/200
|
||||
// call /a/dd expectations:unmatch/404 Actual: panic
|
||||
// call /addr/dd/aa expectations:unmatch/404 Actual: panic
|
||||
// skippedPath: It can only be executed if the secondary route is not found
|
||||
skippedPath = ""
|
||||
continue walk
|
||||
}
|
||||
|
||||
// Nothing found. We can recommend to redirect to the same URL with an
|
||||
// extra trailing slash if a leaf exists for that path
|
||||
value.tsr = (path == "/") ||
|
||||
(len(prefix) == len(path)+1 && prefix[len(path)] == '/' &&
|
||||
path == prefix[:len(prefix)-1] && n.handlers != nil)
|
||||
value.tsr = path == "/" ||
|
||||
(len(prefix) == len(path)+1 && n.handlers != nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
121
tree_test.go
121
tree_test.go
@ -154,6 +154,37 @@ func TestTreeWildcard(t *testing.T) {
|
||||
"/info/:user/public",
|
||||
"/info/:user/project/:project",
|
||||
"/info/:user/project/golang",
|
||||
"/aa/*xx",
|
||||
"/ab/*xx",
|
||||
"/:cc",
|
||||
"/:cc/cc",
|
||||
"/:cc/:dd/ee",
|
||||
"/:cc/:dd/:ee/ff",
|
||||
"/:cc/:dd/:ee/:ff/gg",
|
||||
"/:cc/:dd/:ee/:ff/:gg/hh",
|
||||
"/get/test/abc/",
|
||||
"/get/:param/abc/",
|
||||
"/something/:paramname/thirdthing",
|
||||
"/something/secondthing/test",
|
||||
"/get/abc",
|
||||
"/get/:param",
|
||||
"/get/abc/123abc",
|
||||
"/get/abc/:param",
|
||||
"/get/abc/123abc/xxx8",
|
||||
"/get/abc/123abc/:param",
|
||||
"/get/abc/123abc/xxx8/1234",
|
||||
"/get/abc/123abc/xxx8/:param",
|
||||
"/get/abc/123abc/xxx8/1234/ffas",
|
||||
"/get/abc/123abc/xxx8/1234/:param",
|
||||
"/get/abc/123abc/xxx8/1234/kkdd/12c",
|
||||
"/get/abc/123abc/xxx8/1234/kkdd/:param",
|
||||
"/get/abc/:param/test",
|
||||
"/get/abc/123abd/:param",
|
||||
"/get/abc/123abddd/:param",
|
||||
"/get/abc/123/:param",
|
||||
"/get/abc/123abg/:param",
|
||||
"/get/abc/123abf/:param",
|
||||
"/get/abc/123abfff/:param",
|
||||
}
|
||||
for _, route := range routes {
|
||||
tree.addRoute(route, fakeHandler(route))
|
||||
@ -186,6 +217,94 @@ func TestTreeWildcard(t *testing.T) {
|
||||
{"/info/gordon/public", false, "/info/:user/public", Params{Param{Key: "user", Value: "gordon"}}},
|
||||
{"/info/gordon/project/go", false, "/info/:user/project/:project", Params{Param{Key: "user", Value: "gordon"}, Param{Key: "project", Value: "go"}}},
|
||||
{"/info/gordon/project/golang", false, "/info/:user/project/golang", Params{Param{Key: "user", Value: "gordon"}}},
|
||||
{"/aa/aa", false, "/aa/*xx", Params{Param{Key: "xx", Value: "/aa"}}},
|
||||
{"/ab/ab", false, "/ab/*xx", Params{Param{Key: "xx", Value: "/ab"}}},
|
||||
{"/a", false, "/:cc", Params{Param{Key: "cc", Value: "a"}}},
|
||||
// * Error with argument being intercepted
|
||||
// new PR handle (/all /all/cc /a/cc)
|
||||
// fix PR: https://github.com/gin-gonic/gin/pull/2796
|
||||
{"/all", false, "/:cc", Params{Param{Key: "cc", Value: "all"}}},
|
||||
{"/d", false, "/:cc", Params{Param{Key: "cc", Value: "d"}}},
|
||||
{"/ad", false, "/:cc", Params{Param{Key: "cc", Value: "ad"}}},
|
||||
{"/dd", false, "/:cc", Params{Param{Key: "cc", Value: "dd"}}},
|
||||
{"/dddaa", false, "/:cc", Params{Param{Key: "cc", Value: "dddaa"}}},
|
||||
{"/aa", false, "/:cc", Params{Param{Key: "cc", Value: "aa"}}},
|
||||
{"/aaa", false, "/:cc", Params{Param{Key: "cc", Value: "aaa"}}},
|
||||
{"/aaa/cc", false, "/:cc/cc", Params{Param{Key: "cc", Value: "aaa"}}},
|
||||
{"/ab", false, "/:cc", Params{Param{Key: "cc", Value: "ab"}}},
|
||||
{"/abb", false, "/:cc", Params{Param{Key: "cc", Value: "abb"}}},
|
||||
{"/abb/cc", false, "/:cc/cc", Params{Param{Key: "cc", Value: "abb"}}},
|
||||
{"/allxxxx", false, "/:cc", Params{Param{Key: "cc", Value: "allxxxx"}}},
|
||||
{"/alldd", false, "/:cc", Params{Param{Key: "cc", Value: "alldd"}}},
|
||||
{"/all/cc", false, "/:cc/cc", Params{Param{Key: "cc", Value: "all"}}},
|
||||
{"/a/cc", false, "/:cc/cc", Params{Param{Key: "cc", Value: "a"}}},
|
||||
{"/cc/cc", false, "/:cc/cc", Params{Param{Key: "cc", Value: "cc"}}},
|
||||
{"/ccc/cc", false, "/:cc/cc", Params{Param{Key: "cc", Value: "ccc"}}},
|
||||
{"/deedwjfs/cc", false, "/:cc/cc", Params{Param{Key: "cc", Value: "deedwjfs"}}},
|
||||
{"/acllcc/cc", false, "/:cc/cc", Params{Param{Key: "cc", Value: "acllcc"}}},
|
||||
{"/get/test/abc/", false, "/get/test/abc/", nil},
|
||||
{"/get/te/abc/", false, "/get/:param/abc/", Params{Param{Key: "param", Value: "te"}}},
|
||||
{"/get/testaa/abc/", false, "/get/:param/abc/", Params{Param{Key: "param", Value: "testaa"}}},
|
||||
{"/get/xx/abc/", false, "/get/:param/abc/", Params{Param{Key: "param", Value: "xx"}}},
|
||||
{"/get/tt/abc/", false, "/get/:param/abc/", Params{Param{Key: "param", Value: "tt"}}},
|
||||
{"/get/a/abc/", false, "/get/:param/abc/", Params{Param{Key: "param", Value: "a"}}},
|
||||
{"/get/t/abc/", false, "/get/:param/abc/", Params{Param{Key: "param", Value: "t"}}},
|
||||
{"/get/aa/abc/", false, "/get/:param/abc/", Params{Param{Key: "param", Value: "aa"}}},
|
||||
{"/get/abas/abc/", false, "/get/:param/abc/", Params{Param{Key: "param", Value: "abas"}}},
|
||||
{"/something/secondthing/test", false, "/something/secondthing/test", nil},
|
||||
{"/something/abcdad/thirdthing", false, "/something/:paramname/thirdthing", Params{Param{Key: "paramname", Value: "abcdad"}}},
|
||||
{"/something/secondthingaaaa/thirdthing", false, "/something/:paramname/thirdthing", Params{Param{Key: "paramname", Value: "secondthingaaaa"}}},
|
||||
{"/something/se/thirdthing", false, "/something/:paramname/thirdthing", Params{Param{Key: "paramname", Value: "se"}}},
|
||||
{"/something/s/thirdthing", false, "/something/:paramname/thirdthing", Params{Param{Key: "paramname", Value: "s"}}},
|
||||
{"/c/d/ee", false, "/:cc/:dd/ee", Params{Param{Key: "cc", Value: "c"}, Param{Key: "dd", Value: "d"}}},
|
||||
{"/c/d/e/ff", false, "/:cc/:dd/:ee/ff", Params{Param{Key: "cc", Value: "c"}, Param{Key: "dd", Value: "d"}, Param{Key: "ee", Value: "e"}}},
|
||||
{"/c/d/e/f/gg", false, "/:cc/:dd/:ee/:ff/gg", Params{Param{Key: "cc", Value: "c"}, Param{Key: "dd", Value: "d"}, Param{Key: "ee", Value: "e"}, Param{Key: "ff", Value: "f"}}},
|
||||
{"/c/d/e/f/g/hh", false, "/:cc/:dd/:ee/:ff/:gg/hh", Params{Param{Key: "cc", Value: "c"}, Param{Key: "dd", Value: "d"}, Param{Key: "ee", Value: "e"}, Param{Key: "ff", Value: "f"}, Param{Key: "gg", Value: "g"}}},
|
||||
{"/cc/dd/ee/ff/gg/hh", false, "/:cc/:dd/:ee/:ff/:gg/hh", Params{Param{Key: "cc", Value: "cc"}, Param{Key: "dd", Value: "dd"}, Param{Key: "ee", Value: "ee"}, Param{Key: "ff", Value: "ff"}, Param{Key: "gg", Value: "gg"}}},
|
||||
{"/get/abc", false, "/get/abc", nil},
|
||||
{"/get/a", false, "/get/:param", Params{Param{Key: "param", Value: "a"}}},
|
||||
{"/get/abz", false, "/get/:param", Params{Param{Key: "param", Value: "abz"}}},
|
||||
{"/get/12a", false, "/get/:param", Params{Param{Key: "param", Value: "12a"}}},
|
||||
{"/get/abcd", false, "/get/:param", Params{Param{Key: "param", Value: "abcd"}}},
|
||||
{"/get/abc/123abc", false, "/get/abc/123abc", nil},
|
||||
{"/get/abc/12", false, "/get/abc/:param", Params{Param{Key: "param", Value: "12"}}},
|
||||
{"/get/abc/123ab", false, "/get/abc/:param", Params{Param{Key: "param", Value: "123ab"}}},
|
||||
{"/get/abc/xyz", false, "/get/abc/:param", Params{Param{Key: "param", Value: "xyz"}}},
|
||||
{"/get/abc/123abcddxx", false, "/get/abc/:param", Params{Param{Key: "param", Value: "123abcddxx"}}},
|
||||
{"/get/abc/123abc/xxx8", false, "/get/abc/123abc/xxx8", nil},
|
||||
{"/get/abc/123abc/x", false, "/get/abc/123abc/:param", Params{Param{Key: "param", Value: "x"}}},
|
||||
{"/get/abc/123abc/xxx", false, "/get/abc/123abc/:param", Params{Param{Key: "param", Value: "xxx"}}},
|
||||
{"/get/abc/123abc/abc", false, "/get/abc/123abc/:param", Params{Param{Key: "param", Value: "abc"}}},
|
||||
{"/get/abc/123abc/xxx8xxas", false, "/get/abc/123abc/:param", Params{Param{Key: "param", Value: "xxx8xxas"}}},
|
||||
{"/get/abc/123abc/xxx8/1234", false, "/get/abc/123abc/xxx8/1234", nil},
|
||||
{"/get/abc/123abc/xxx8/1", false, "/get/abc/123abc/xxx8/:param", Params{Param{Key: "param", Value: "1"}}},
|
||||
{"/get/abc/123abc/xxx8/123", false, "/get/abc/123abc/xxx8/:param", Params{Param{Key: "param", Value: "123"}}},
|
||||
{"/get/abc/123abc/xxx8/78k", false, "/get/abc/123abc/xxx8/:param", Params{Param{Key: "param", Value: "78k"}}},
|
||||
{"/get/abc/123abc/xxx8/1234xxxd", false, "/get/abc/123abc/xxx8/:param", Params{Param{Key: "param", Value: "1234xxxd"}}},
|
||||
{"/get/abc/123abc/xxx8/1234/ffas", false, "/get/abc/123abc/xxx8/1234/ffas", nil},
|
||||
{"/get/abc/123abc/xxx8/1234/f", false, "/get/abc/123abc/xxx8/1234/:param", Params{Param{Key: "param", Value: "f"}}},
|
||||
{"/get/abc/123abc/xxx8/1234/ffa", false, "/get/abc/123abc/xxx8/1234/:param", Params{Param{Key: "param", Value: "ffa"}}},
|
||||
{"/get/abc/123abc/xxx8/1234/kka", false, "/get/abc/123abc/xxx8/1234/:param", Params{Param{Key: "param", Value: "kka"}}},
|
||||
{"/get/abc/123abc/xxx8/1234/ffas321", false, "/get/abc/123abc/xxx8/1234/:param", Params{Param{Key: "param", Value: "ffas321"}}},
|
||||
{"/get/abc/123abc/xxx8/1234/kkdd/12c", false, "/get/abc/123abc/xxx8/1234/kkdd/12c", nil},
|
||||
{"/get/abc/123abc/xxx8/1234/kkdd/1", false, "/get/abc/123abc/xxx8/1234/kkdd/:param", Params{Param{Key: "param", Value: "1"}}},
|
||||
{"/get/abc/123abc/xxx8/1234/kkdd/12", false, "/get/abc/123abc/xxx8/1234/kkdd/:param", Params{Param{Key: "param", Value: "12"}}},
|
||||
{"/get/abc/123abc/xxx8/1234/kkdd/12b", false, "/get/abc/123abc/xxx8/1234/kkdd/:param", Params{Param{Key: "param", Value: "12b"}}},
|
||||
{"/get/abc/123abc/xxx8/1234/kkdd/34", false, "/get/abc/123abc/xxx8/1234/kkdd/:param", Params{Param{Key: "param", Value: "34"}}},
|
||||
{"/get/abc/123abc/xxx8/1234/kkdd/12c2e3", false, "/get/abc/123abc/xxx8/1234/kkdd/:param", Params{Param{Key: "param", Value: "12c2e3"}}},
|
||||
{"/get/abc/12/test", false, "/get/abc/:param/test", Params{Param{Key: "param", Value: "12"}}},
|
||||
{"/get/abc/123abdd/test", false, "/get/abc/:param/test", Params{Param{Key: "param", Value: "123abdd"}}},
|
||||
{"/get/abc/123abdddf/test", false, "/get/abc/:param/test", Params{Param{Key: "param", Value: "123abdddf"}}},
|
||||
{"/get/abc/123ab/test", false, "/get/abc/:param/test", Params{Param{Key: "param", Value: "123ab"}}},
|
||||
{"/get/abc/123abgg/test", false, "/get/abc/:param/test", Params{Param{Key: "param", Value: "123abgg"}}},
|
||||
{"/get/abc/123abff/test", false, "/get/abc/:param/test", Params{Param{Key: "param", Value: "123abff"}}},
|
||||
{"/get/abc/123abffff/test", false, "/get/abc/:param/test", Params{Param{Key: "param", Value: "123abffff"}}},
|
||||
{"/get/abc/123abd/test", false, "/get/abc/123abd/:param", Params{Param{Key: "param", Value: "test"}}},
|
||||
{"/get/abc/123abddd/test", false, "/get/abc/123abddd/:param", Params{Param{Key: "param", Value: "test"}}},
|
||||
{"/get/abc/123/test22", false, "/get/abc/123/:param", Params{Param{Key: "param", Value: "test22"}}},
|
||||
{"/get/abc/123abg/test", false, "/get/abc/123abg/:param", Params{Param{Key: "param", Value: "test"}}},
|
||||
{"/get/abc/123abf/testss", false, "/get/abc/123abf/:param", Params{Param{Key: "param", Value: "testss"}}},
|
||||
{"/get/abc/123abfff/te", false, "/get/abc/123abfff/:param", Params{Param{Key: "param", Value: "te"}}},
|
||||
})
|
||||
|
||||
checkPriorities(t, tree)
|
||||
@ -724,7 +843,7 @@ func TestTreeInvalidParamsType(t *testing.T) {
|
||||
tree.children[0].nType = 2
|
||||
|
||||
// set invalid Params type
|
||||
params := make(Params, 0, 0)
|
||||
params := make(Params, 0)
|
||||
|
||||
// try to trigger slice bounds out of range with capacity 0
|
||||
tree.getValue("/test", ¶ms, false)
|
||||
|
@ -5,4 +5,4 @@
|
||||
package gin
|
||||
|
||||
// Version is the current gin framework's version.
|
||||
const Version = "v1.7.2"
|
||||
const Version = "v1.7.3"
|
||||
|
Loading…
x
Reference in New Issue
Block a user