Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Notealot 2021-11-21 21:44:52 +08:00
commit 725acf51eb
6 changed files with 57 additions and 34 deletions

View File

@ -21,7 +21,7 @@ jobs:
- name: Setup golangci-lint - name: Setup golangci-lint
uses: golangci/golangci-lint-action@v2 uses: golangci/golangci-lint-action@v2
with: with:
version: v1.42.1 version: v1.43.0
args: --verbose args: --verbose
test: test:
needs: lint needs: lint

View File

@ -252,7 +252,7 @@ func (c *Context) Set(key string, value interface{}) {
} }
// Get returns the value for the given key, ie: (value, true). // Get returns the value for the given key, ie: (value, true).
// If the value does not exists it returns (nil, false) // If the value does not exist it returns (nil, false)
func (c *Context) Get(key string) (value interface{}, exists bool) { func (c *Context) Get(key string) (value interface{}, exists bool) {
c.mu.RLock() c.mu.RLock()
value, exists = c.Keys[key] value, exists = c.Keys[key]
@ -602,7 +602,7 @@ func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error
} }
// Bind checks the Content-Type to select a binding engine automatically, // Bind checks the Content-Type to select a binding engine automatically,
// Depending the "Content-Type" header different bindings are used: // Depending on the "Content-Type" header different bindings are used:
// "application/json" --> JSON binding // "application/json" --> JSON binding
// "application/xml" --> XML binding // "application/xml" --> XML binding
// otherwise --> returns an error. // otherwise --> returns an error.
@ -661,7 +661,7 @@ func (c *Context) MustBindWith(obj interface{}, b binding.Binding) error {
} }
// ShouldBind checks the Content-Type to select a binding engine automatically, // ShouldBind checks the Content-Type to select a binding engine automatically,
// Depending the "Content-Type" header different bindings are used: // Depending on the "Content-Type" header different bindings are used:
// "application/json" --> JSON binding // "application/json" --> JSON binding
// "application/xml" --> XML binding // "application/xml" --> XML binding
// otherwise --> returns an error // otherwise --> returns an error
@ -863,7 +863,7 @@ func (c *Context) Status(code int) {
c.Writer.WriteHeader(code) c.Writer.WriteHeader(code)
} }
// Header is a intelligent shortcut for c.Writer.Header().Set(key, value). // Header is an intelligent shortcut for c.Writer.Header().Set(key, value).
// It writes a header in the response. // It writes a header in the response.
// If value == "", this method removes the header `c.Writer.Header().Del(key)` // If value == "", this method removes the header `c.Writer.Header().Del(key)`
func (c *Context) Header(key, value string) { func (c *Context) Header(key, value string) {
@ -946,7 +946,7 @@ func (c *Context) HTML(code int, name string, obj interface{}) {
// IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body. // IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body.
// It also sets the Content-Type as "application/json". // It also sets the Content-Type as "application/json".
// WARNING: we recommend to use this only for development purposes since printing pretty JSON is // WARNING: we recommend using this only for development purposes since printing pretty JSON is
// more CPU and bandwidth consuming. Use Context.JSON() instead. // more CPU and bandwidth consuming. Use Context.JSON() instead.
func (c *Context) IndentedJSON(code int, obj interface{}) { func (c *Context) IndentedJSON(code int, obj interface{}) {
c.Render(code, render.IndentedJSON{Data: obj}) c.Render(code, render.IndentedJSON{Data: obj})
@ -1010,7 +1010,7 @@ func (c *Context) String(code int, format string, values ...interface{}) {
c.Render(code, render.String{Format: format, Data: values}) c.Render(code, render.String{Format: format, Data: values})
} }
// Redirect returns a HTTP redirect to the specific location. // Redirect returns an HTTP redirect to the specific location.
func (c *Context) Redirect(code int, location string) { func (c *Context) Redirect(code int, location string) {
c.Render(-1, render.Redirect{ c.Render(-1, render.Redirect{
Code: code, Code: code,

View File

@ -122,7 +122,7 @@ func (a errorMsgs) Last() *Error {
return nil return nil
} }
// Errors returns an array will all the error messages. // Errors returns an array with all the error messages.
// Example: // Example:
// c.Error(errors.New("first")) // c.Error(errors.New("first"))
// c.Error(errors.New("second")) // c.Error(errors.New("second"))

22
tree.go
View File

@ -447,10 +447,11 @@ walk: // Outer loop for walking the tree
continue walk continue walk
} }
} }
if !n.wildChild {
// If the path at the end of the loop is not equal to '/' and the current node has no child nodes // 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 roll back to last vaild skippedNode // the current node needs to roll back to last vaild skippedNode
if path != "/" {
if path != "/" && !n.wildChild {
for l := len(*skippedNodes); l > 0; { for l := len(*skippedNodes); l > 0; {
skippedNode := (*skippedNodes)[l-1] skippedNode := (*skippedNodes)[l-1]
*skippedNodes = (*skippedNodes)[:l-1] *skippedNodes = (*skippedNodes)[:l-1]
@ -466,8 +467,6 @@ walk: // Outer loop for walking the tree
} }
} }
// If there is no wildcard pattern, recommend a redirection
if !n.wildChild {
// Nothing found. // Nothing found.
// We can recommend to redirect to the same URL without a // We can recommend to redirect to the same URL without a
// trailing slash if a leaf exists for that path. // trailing slash if a leaf exists for that path.
@ -614,8 +613,14 @@ walk: // Outer loop for walking the tree
return return
} }
// roll back to last vaild skippedNode // Nothing found. We can recommend to redirect to the same URL with an
if path != "/" { // 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)
// roll back to last valid skippedNode
if !value.tsr && path != "/" {
for l := len(*skippedNodes); l > 0; { for l := len(*skippedNodes); l > 0; {
skippedNode := (*skippedNodes)[l-1] skippedNode := (*skippedNodes)[l-1]
*skippedNodes = (*skippedNodes)[:l-1] *skippedNodes = (*skippedNodes)[:l-1]
@ -631,11 +636,6 @@ walk: // Outer loop for walking the tree
} }
} }
// 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)
return return
} }
} }

View File

@ -587,7 +587,14 @@ func TestTreeTrailingSlashRedirect(t *testing.T) {
"/doc/go1.html", "/doc/go1.html",
"/no/a", "/no/a",
"/no/b", "/no/b",
"/api/hello/:name", "/api/:page/:name",
"/api/hello/:name/bar/",
"/api/bar/:name",
"/api/baz/foo",
"/api/baz/foo/bar",
"/blog/:p",
"/posts/:b/:c",
"/posts/b/:c/d/",
} }
for _, route := range routes { for _, route := range routes {
recv := catchPanic(func() { recv := catchPanic(func() {
@ -613,7 +620,19 @@ func TestTreeTrailingSlashRedirect(t *testing.T) {
"/admin/config/", "/admin/config/",
"/admin/config/permissions/", "/admin/config/permissions/",
"/doc/", "/doc/",
"/admin/static/",
"/admin/cfg/",
"/admin/cfg/users/",
"/api/hello/x/bar",
"/api/baz/foo/",
"/api/baz/bax/",
"/api/bar/huh/",
"/api/baz/foo/bar/",
"/api/world/abc/",
"/blog/pp/",
"/posts/b/c/d",
} }
for _, route := range tsrRoutes { for _, route := range tsrRoutes {
value := tree.getValue(route, nil, getSkippedNodes(), false) value := tree.getValue(route, nil, getSkippedNodes(), false)
if value.handlers != nil { if value.handlers != nil {
@ -629,7 +648,11 @@ func TestTreeTrailingSlashRedirect(t *testing.T) {
"/no/", "/no/",
"/_", "/_",
"/_/", "/_/",
"/api/world/abc", "/api",
"/api/",
"/api/hello/x/foo",
"/api/baz/foo/bad",
"/foo/p/p",
} }
for _, route := range noTsrRoutes { for _, route := range noTsrRoutes {
value := tree.getValue(route, nil, getSkippedNodes(), false) value := tree.getValue(route, nil, getSkippedNodes(), false)

View File

@ -5,4 +5,4 @@
package gin package gin
// Version is the current gin framework's version. // Version is the current gin framework's version.
const Version = "v1.7.3" const Version = "v1.7.4"