From 372cc4a0100efd3dbd80193b74ee65752d139ea8 Mon Sep 17 00:00:00 2001 From: Lanco <35420416+lancoLiu@users.noreply.github.com> Date: Fri, 2 Jul 2021 09:58:43 +0800 Subject: [PATCH 01/15] Fix typo (#2772) --- context.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context.go b/context.go index ede16fd4..8aabf7ae 100644 --- a/context.go +++ b/context.go @@ -732,7 +732,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 != "" { From 9c27053243cb24ecc90d01c8ff379bd98fed9c8e Mon Sep 17 00:00:00 2001 From: Lanco <35420416+lancoLiu@users.noreply.github.com> Date: Sun, 4 Jul 2021 10:37:13 +0800 Subject: [PATCH 02/15] byte alignment (#2774) --- gin.go | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/gin.go b/gin.go index fd4fa512..7bdb6857 100644 --- a/gin.go +++ b/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 From 9d2883ef47c726e9eb466cdd75123c0e4472ac65 Mon Sep 17 00:00:00 2001 From: Helios <674876158@qq.com> Date: Tue, 6 Jul 2021 16:36:32 +0800 Subject: [PATCH 03/15] update the version of validator in the comment (#2780) Co-authored-by: shangyilong --- binding/binding.go | 4 ++-- binding/binding_nomsgpack.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/binding/binding.go b/binding/binding.go index 5caeb581..deb71661 100644 --- a/binding/binding.go +++ b/binding/binding.go @@ -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{} diff --git a/binding/binding_nomsgpack.go b/binding/binding_nomsgpack.go index 9afa3dcf..23424470 100644 --- a/binding/binding_nomsgpack.go +++ b/binding/binding_nomsgpack.go @@ -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{} From c7a28f85320125709e47c592a92421a4d6f192a7 Mon Sep 17 00:00:00 2001 From: ziheng Date: Tue, 6 Jul 2021 16:37:14 +0800 Subject: [PATCH 04/15] use bit shift operation instead of division (#2776) --- context.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/context.go b/context.go index 8aabf7ae..ecf74ba9 100644 --- a/context.go +++ b/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. From 3116a2d7a1bf5ed07c50a2b0851a4bed15b3e3b4 Mon Sep 17 00:00:00 2001 From: ziheng Date: Fri, 9 Jul 2021 10:30:44 +0800 Subject: [PATCH 05/15] use std http method constant instead of raw string (#2782) --- gin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gin.go b/gin.go index 7bdb6857..6ab2be66 100644 --- a/gin.go +++ b/gin.go @@ -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 From f96678cb6b897f92921a2a52ae1c9f0248346a12 Mon Sep 17 00:00:00 2001 From: Lanco <35420416+lancoLiu@users.noreply.github.com> Date: Sun, 11 Jul 2021 14:38:45 +0800 Subject: [PATCH 06/15] use assert1 func (#2783) --- routergroup.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/routergroup.go b/routergroup.go index 6f14bf59..bb24bd52 100644 --- a/routergroup.go +++ b/routergroup.go @@ -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) From caf2802593277033683c4e8cb5f22c81cc35eae8 Mon Sep 17 00:00:00 2001 From: ziheng Date: Tue, 13 Jul 2021 09:44:19 +0800 Subject: [PATCH 07/15] Improve router group tests (#2787) --- routergroup_test.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/routergroup_test.go b/routergroup_test.go index 0e49d65b..d6d8b452 100644 --- a/routergroup_test.go +++ b/routergroup_test.go @@ -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...) }) } From d4ca9a0fb1211108f0a893634ee01b0006890c16 Mon Sep 17 00:00:00 2001 From: qm012 <67568757+qm012@users.noreply.github.com> Date: Thu, 22 Jul 2021 17:58:15 -0500 Subject: [PATCH 08/15] fix #2762 (#2767) --- gin_integration_test.go | 78 ++++++++++++++++++++++++++++++++++-- tree.go | 88 +++++++++++++++++++++++++++++------------ tree_test.go | 36 +++++++++++++++++ 3 files changed, 172 insertions(+), 30 deletions(-) diff --git a/gin_integration_test.go b/gin_integration_test.go index 2eb2d52b..ed7196fd 100644 --- a/gin_integration_test.go +++ b/gin_integration_test.go @@ -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,52 @@ 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") }) + + 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+"/a", "", "/:cc") + testRequest(t, ts.URL+"/get/test/abc/", "", "/get/test/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/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") + // 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") +} diff --git a/tree.go b/tree.go index 4b5656fb..2e46b8e5 100644 --- a/tree.go +++ b/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,23 @@ 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 + // path: /abc/123/def + // level 1 router:abc + // level 2 router:123 + // level 3 router:def + var ( + skippedPath string + latestNode = n // not found `level 2 router` use latestNode + + // match '/' count + // matchNum < 1: `level 2 router` not found,the current node needs to be equal to latestNode + // matchNum >= 1: `level (2 or 3 or 4 or ...) router`: Normal handling + matchNum int // each match will accumulate + ) + //if path == "/", no need to look for tree node + if len(path) == 1 { + matchNum = 1 + } walk: // Outer loop for walking the tree for { @@ -418,32 +429,41 @@ 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, } } n = n.children[i] + + // match '/', If this condition is matched, the next route is found + if (len(n.fullPath) != 0 && n.wildChild) || path[len(path)-1] == '/' { + matchNum++ + } continue walk } } + // level 2 router not found,the current node needs to be equal to latestNode + if matchNum < 1 { + 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 } @@ -483,6 +503,18 @@ walk: // Outer loop for walking the tree if len(n.children) > 0 { path = path[end:] n = n.children[0] + // next node,the latestNode needs to be equal to currentNode and handle next router + latestNode = n + // not found router in (level 1 router and handle next node),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 + // matchNum: Go to the next level of routing tree node search,need add matchNum + skippedPath = "" + matchNum++ continue walk } @@ -535,6 +567,10 @@ walk: // Outer loop for walking the tree } if path == prefix { + // level 2 router not found and latestNode.wildChild is true + if matchNum < 1 && latestNode.wildChild { + 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 +600,18 @@ 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 + // path != "/" && skippedPath != "" + if len(path) != 1 && len(skippedPath) > 0 && strings.HasSuffix(skippedPath, path) { + path = skippedPath + n = latestNode + 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 } } diff --git a/tree_test.go b/tree_test.go index 7459317f..91213eee 100644 --- a/tree_test.go +++ b/tree_test.go @@ -154,6 +154,18 @@ 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", } for _, route := range routes { tree.addRoute(route, fakeHandler(route)) @@ -186,6 +198,30 @@ 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"}}}, + // * level 1 router match param will be Intercept first + // new PR handle (/all /all/cc /a/cc) + {"/all", false, "/:cc", Params{Param{Key: "cc", Value: "ll"}}}, + {"/all/cc", false, "/:cc/cc", Params{Param{Key: "cc", Value: "ll"}}}, + {"/a/cc", false, "/:cc/cc", Params{Param{Key: "cc", Value: ""}}}, + {"/get/test/abc/", false, "/get/test/abc/", nil}, + {"/get/te/abc/", false, "/get/:param/abc/", Params{Param{Key: "param", Value: "te"}}}, + {"/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/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"}}}, }) checkPriorities(t, tree) From 0a55865c3fc4c2b30dce86dfa9cff7654ba9bc74 Mon Sep 17 00:00:00 2001 From: qm012 <67568757+qm012@users.noreply.github.com> Date: Sun, 25 Jul 2021 21:07:54 -0500 Subject: [PATCH 09/15] fix #2786 (#2796) * update match rule * add comments --- gin_integration_test.go | 82 +++++++++++++++++++++++++++++++++++++ tree.go | 67 +++++++++++++----------------- tree_test.go | 91 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 197 insertions(+), 43 deletions(-) diff --git a/gin_integration_test.go b/gin_integration_test.go index ed7196fd..094c46e8 100644 --- a/gin_integration_test.go +++ b/gin_integration_test.go @@ -410,6 +410,25 @@ func TestTreeRunDynamicRouting(t *testing.T) { 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() @@ -424,8 +443,26 @@ func TestTreeRunDynamicRouting(t *testing.T) { 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/") @@ -434,10 +471,55 @@ func TestTreeRunDynamicRouting(t *testing.T) { 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") diff --git a/tree.go b/tree.go index 2e46b8e5..eb549591 100644 --- a/tree.go +++ b/tree.go @@ -400,23 +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) { - // path: /abc/123/def - // level 1 router:abc - // level 2 router:123 - // level 3 router:def var ( skippedPath string - latestNode = n // not found `level 2 router` use latestNode - - // match '/' count - // matchNum < 1: `level 2 router` not found,the current node needs to be equal to latestNode - // matchNum >= 1: `level (2 or 3 or 4 or ...) router`: Normal handling - matchNum int // each match will accumulate + latestNode = n // Caching the latest node ) - //if path == "/", no need to look for tree node - if len(path) == 1 { - matchNum = 1 - } walk: // Outer loop for walking the tree for { @@ -444,17 +431,13 @@ walk: // Outer loop for walking the tree } n = n.children[i] - - // match '/', If this condition is matched, the next route is found - if (len(n.fullPath) != 0 && n.wildChild) || path[len(path)-1] == '/' { - matchNum++ - } continue walk } } - - // level 2 router not found,the current node needs to be equal to latestNode - if matchNum < 1 { + // 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 } @@ -472,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] != '/' { @@ -503,18 +496,6 @@ walk: // Outer loop for walking the tree if len(n.children) > 0 { path = path[end:] n = n.children[0] - // next node,the latestNode needs to be equal to currentNode and handle next router - latestNode = n - // not found router in (level 1 router and handle next node),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 - // matchNum: Go to the next level of routing tree node search,need add matchNum - skippedPath = "" - matchNum++ continue walk } @@ -567,8 +548,9 @@ walk: // Outer loop for walking the tree } if path == prefix { - // level 2 router not found and latestNode.wildChild is true - if matchNum < 1 && latestNode.wildChild { + // 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. @@ -600,10 +582,17 @@ walk: // Outer loop for walking the tree return } - // path != "/" && skippedPath != "" - if len(path) != 1 && len(skippedPath) > 0 && strings.HasSuffix(skippedPath, path) { + if path != "/" && len(skippedPath) > 0 && strings.HasSuffix(skippedPath, path) { path = skippedPath - n = latestNode + // 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 } diff --git a/tree_test.go b/tree_test.go index 91213eee..ea13c30e 100644 --- a/tree_test.go +++ b/tree_test.go @@ -166,6 +166,25 @@ func TestTreeWildcard(t *testing.T) { "/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)) @@ -201,13 +220,31 @@ func TestTreeWildcard(t *testing.T) { {"/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"}}}, - // * level 1 router match param will be Intercept first + // * Error with argument being intercepted // new PR handle (/all /all/cc /a/cc) - {"/all", false, "/:cc", Params{Param{Key: "cc", Value: "ll"}}}, - {"/all/cc", false, "/:cc/cc", Params{Param{Key: "cc", Value: "ll"}}}, - {"/a/cc", false, "/:cc/cc", Params{Param{Key: "cc", Value: ""}}}, + // 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"}}}, @@ -216,12 +253,58 @@ func TestTreeWildcard(t *testing.T) { {"/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) From 11aa11a65618b6b66bf2b5123e08db6e879c4a1e Mon Sep 17 00:00:00 2001 From: "Eren A. Akyol" Date: Tue, 27 Jul 2021 02:59:53 +0300 Subject: [PATCH 10/15] fix readability in recovery test (#2797) --- recovery_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/recovery_test.go b/recovery_test.go index 6cc2a47a..d164bfa3 100644 --- a/recovery_test.go +++ b/recovery_test.go @@ -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 From 9a575a4c05601954e0848ff8271238dd73485536 Mon Sep 17 00:00:00 2001 From: wei Date: Sun, 1 Aug 2021 00:46:53 +0800 Subject: [PATCH 11/15] fallback Context.Deadline() Context.Done() Context.Err() to Context.Request.Context() (#2769) * fallback Context.Deadline() Context.Done() Context.Err() to Context.Request.Context() * update comments wording --- context.go | 24 +++++++++++++++--------- context_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/context.go b/context.go index ecf74ba9..1a953006 100644 --- a/context.go +++ b/context.go @@ -1161,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 diff --git a/context_test.go b/context_test.go index 2a4d2185..ffbe5cca 100644 --- a/context_test.go +++ b/context_test.go @@ -2058,6 +2058,48 @@ 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()) +} + func TestContextWithFallbackValueFromRequestContext(t *testing.T) { tests := []struct { name string From 6ebb945bd7ac10b0fec87299129b6d9603e1e4ab Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Tue, 3 Aug 2021 10:26:26 +0800 Subject: [PATCH 12/15] docs: release v1.7.3 (#2802) * docs: release v1.7.3 Signed-off-by: Bo-Yi Wu * fix: format Signed-off-by: Bo-Yi Wu --- CHANGELOG.md | 6 ++++++ version.go | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a28edc84..308af74c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/version.go b/version.go index a80ab69a..535bfc82 100644 --- a/version.go +++ b/version.go @@ -5,4 +5,4 @@ package gin // Version is the current gin framework's version. -const Version = "v1.7.2" +const Version = "v1.7.3" From b463b1c2a175cd17365d114e4827aa2d680c3dc9 Mon Sep 17 00:00:00 2001 From: goqihoo Date: Wed, 11 Aug 2021 09:42:25 +0800 Subject: [PATCH 13/15] Update README.md (#2804) 1. c.FullPath() == "/user/:name/*action" get following error: evaluated but not used 2. c.String(http.StatusOK, "The available groups are [...]", name) get following error: undefined: name --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ef801179..198bf011 100644 --- a/README.md +++ b/README.md @@ -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") From 435a76b735db28b6223b323d30503de51c637b89 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Thu, 19 Aug 2021 09:46:31 +0200 Subject: [PATCH 14/15] chore(ci): update dependencies (#2827) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Matthieu MOREL --- .github/dependabot.yml | 10 + .github/workflows/gin.yml | 41 ++++- .golangci.yml | 23 +++ binding/binding_test.go | 3 +- binding/form_mapping.go | 5 +- binding/form_mapping_test.go | 2 +- binding/protobuf.go | 2 +- binding/uri.go | 2 +- context_test.go | 24 ++- go.mod | 14 +- go.sum | 90 +++++---- mode.go | 6 +- render/json.go | 4 +- render/protobuf.go | 2 +- render/render_test.go | 11 +- response_writer_test.go | 14 +- testdata/protoexample/test.pb.go | 301 +++++++++++++++++++++++++------ tree_test.go | 2 +- 18 files changed, 412 insertions(+), 144 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .golangci.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..632e8eb2 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + - package-ecosystem: gomod + directory: / + schedule: + interval: weekly diff --git a/.github/workflows/gin.yml b/.github/workflows/gin.yml index 85cc560e..ab450ab8 100644 --- a/.github/workflows/gin.yml +++ b/.github/workflows/gin.yml @@ -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: @@ -31,21 +50,23 @@ jobs: uses: actions/checkout@v2 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 diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 00000000..1c3cb758 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,23 @@ +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:" diff --git a/binding/binding_test.go b/binding/binding_test.go index 17336177..17df7dc5 100644 --- a/binding/binding_test.go +++ b/binding/binding_test.go @@ -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) { diff --git a/binding/form_mapping.go b/binding/form_mapping.go index cb66dd4a..54b3eabd 100644 --- a/binding/form_mapping.go +++ b/binding/form_mapping.go @@ -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 == "" { diff --git a/binding/form_mapping_test.go b/binding/form_mapping_test.go index 608594e2..516554eb 100644 --- a/binding/form_mapping_test.go +++ b/binding/form_mapping_test.go @@ -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) } diff --git a/binding/protobuf.go b/binding/protobuf.go index f9ece928..ca02897a 100644 --- a/binding/protobuf.go +++ b/binding/protobuf.go @@ -8,7 +8,7 @@ import ( "io/ioutil" "net/http" - "github.com/golang/protobuf/proto" + "google.golang.org/protobuf/proto" ) type protobufBinding struct{} diff --git a/binding/uri.go b/binding/uri.go index f91ec381..a3c0df51 100644 --- a/binding/uri.go +++ b/binding/uri.go @@ -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) diff --git a/context_test.go b/context_test.go index ffbe5cca..176eaae6 100644 --- a/context_test.go +++ b/context_test.go @@ -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) @@ -2100,6 +2096,8 @@ func TestContextWithFallbackErrFromRequestContext(t *testing.T) { assert.EqualError(t, c2.Err(), context.Canceled.Error()) } +type contextKey string + func TestContextWithFallbackValueFromRequestContext(t *testing.T) { tests := []struct { name string @@ -2122,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", }, diff --git a/go.mod b/go.mod index 9484b264..bf682593 100644 --- a/go.mod +++ b/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 ) diff --git a/go.sum b/go.sum index e61ef908..351ee253 100644 --- a/go.sum +++ b/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= diff --git a/mode.go b/mode.go index c8813aff..4d199df3 100644 --- a/mode.go +++ b/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) diff --git a/render/json.go b/render/json.go index e25415b0..b80adcff 100644 --- a/render/json.go +++ b/render/json.go @@ -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. diff --git a/render/protobuf.go b/render/protobuf.go index 15aca995..1d2aa871 100644 --- a/render/protobuf.go +++ b/render/protobuf.go @@ -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. diff --git a/render/render_test.go b/render/render_test.go index 353c82bb..22e7d5ab 100644 --- a/render/render_test.go +++ b/render/render_test.go @@ -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, diff --git a/response_writer_test.go b/response_writer_test.go index 1f113e74..9061d021 100644 --- a/response_writer_test.go +++ b/response_writer_test.go @@ -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) diff --git a/testdata/protoexample/test.pb.go b/testdata/protoexample/test.pb.go index 21997ca1..bf45e028 100644 --- a/testdata/protoexample/test.pb.go +++ b/testdata/protoexample/test.pb.go @@ -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 } diff --git a/tree_test.go b/tree_test.go index ea13c30e..cbb37340 100644 --- a/tree_test.go +++ b/tree_test.go @@ -843,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) From a46dee3a9af4edd9de1694e3ba3592b20c6a8968 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Thu, 19 Aug 2021 10:16:18 +0200 Subject: [PATCH 15/15] Update .golangci.yml (#2829) --- .golangci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.golangci.yml b/.golangci.yml index 1c3cb758..cfcff00c 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,3 +1,5 @@ +run: + timeout: 5m linters: enable: - gofmt