mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-17 22:32:26 +08:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
9946e37b9d
@ -1,5 +1,11 @@
|
||||
# Gin ChangeLog
|
||||
|
||||
## Gin v1.7.2
|
||||
|
||||
### BUGFIXES
|
||||
|
||||
* Fix conflict between param and exact path [#2706](https://github.com/gin-gonic/gin/issues/2706). Close issue [#2682](https://github.com/gin-gonic/gin/issues/2682) [#2696](https://github.com/gin-gonic/gin/issues/2696).
|
||||
|
||||
## Gin v1.7.1
|
||||
|
||||
### BUGFIXES
|
||||
|
15
README.md
15
README.md
@ -24,6 +24,7 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi
|
||||
- [Benchmarks](#benchmarks)
|
||||
- [Gin v1. stable](#gin-v1-stable)
|
||||
- [Build with jsoniter/go-json](#build-with-json-replacement)
|
||||
- [Build without `MsgPack` rendering feature](#build-without-msgpack-rendering-feature)
|
||||
- [API Examples](#api-examples)
|
||||
- [Using GET, POST, PUT, PATCH, DELETE and OPTIONS](#using-get-post-put-patch-delete-and-options)
|
||||
- [Parameters in path](#parameters-in-path)
|
||||
@ -195,6 +196,16 @@ $ go build -tags=jsoniter .
|
||||
$ go build -tags=go_json .
|
||||
```
|
||||
|
||||
## Build without `MsgPack` rendering feature
|
||||
|
||||
Gin enables `MsgPack` rendering feature by default. But you can disable this feature by specifying `nomsgpack` build tag.
|
||||
|
||||
```sh
|
||||
$ go build -tags=nomsgpack .
|
||||
```
|
||||
|
||||
This is useful to reduce the binary size of executable files. See the [detail information](https://github.com/gin-gonic/gin/pull/1852).
|
||||
|
||||
## API Examples
|
||||
|
||||
You can find a number of ready-to-run examples at [Gin examples repository](https://github.com/gin-gonic/examples).
|
||||
@ -691,7 +702,7 @@ func main() {
|
||||
// Example for binding XML (
|
||||
// <?xml version="1.0" encoding="UTF-8"?>
|
||||
// <root>
|
||||
// <user>user</user>
|
||||
// <user>manu</user>
|
||||
// <password>123</password>
|
||||
// </root>)
|
||||
router.POST("/loginXML", func(c *gin.Context) {
|
||||
@ -930,7 +941,7 @@ func main() {
|
||||
route.GET("/:name/:id", func(c *gin.Context) {
|
||||
var person Person
|
||||
if err := c.ShouldBindUri(&person); err != nil {
|
||||
c.JSON(400, gin.H{"msg": err})
|
||||
c.JSON(400, gin.H{"msg": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(200, gin.H{"name": person.Name, "uuid": person.ID})
|
||||
|
@ -138,8 +138,7 @@ var defaultLogFormatter = func(param LogFormatterParams) string {
|
||||
}
|
||||
|
||||
if param.Latency > time.Minute {
|
||||
// Truncate in a golang < 1.8 safe way
|
||||
param.Latency = param.Latency - param.Latency%time.Second
|
||||
param.Latency = param.Latency.Truncate(time.Second)
|
||||
}
|
||||
return fmt.Sprintf("[GIN] %v |%s %3d %s| %13v | %15s |%s %-7s %s %#v\n%s",
|
||||
param.TimeStamp.Format("2006/01/02 - 15:04:05"),
|
||||
|
29
tree.go
29
tree.go
@ -118,6 +118,11 @@ 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
|
||||
@ -400,6 +405,8 @@ 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
|
||||
|
||||
walk: // Outer loop for walking the tree
|
||||
for {
|
||||
prefix := n.path
|
||||
@ -411,6 +418,21 @@ 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,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
n = n.children[i]
|
||||
continue walk
|
||||
}
|
||||
@ -542,6 +564,13 @@ 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
|
||||
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 == "/") ||
|
||||
|
18
tree_test.go
18
tree_test.go
@ -135,13 +135,16 @@ func TestTreeWildcard(t *testing.T) {
|
||||
|
||||
routes := [...]string{
|
||||
"/",
|
||||
"/cmd/:tool/:sub",
|
||||
"/cmd/:tool/",
|
||||
"/cmd/:tool/:sub",
|
||||
"/cmd/whoami",
|
||||
"/cmd/whoami/root",
|
||||
"/cmd/whoami/root/",
|
||||
"/src/*filepath",
|
||||
"/search/",
|
||||
"/search/:query",
|
||||
"/search/gin-gonic",
|
||||
"/search/google",
|
||||
"/user_:name",
|
||||
"/user_:name/about",
|
||||
"/files/:dir/*filepath",
|
||||
@ -150,6 +153,7 @@ func TestTreeWildcard(t *testing.T) {
|
||||
"/doc/go1.html",
|
||||
"/info/:user/public",
|
||||
"/info/:user/project/:project",
|
||||
"/info/:user/project/golang",
|
||||
}
|
||||
for _, route := range routes {
|
||||
tree.addRoute(route, fakeHandler(route))
|
||||
@ -159,21 +163,29 @@ func TestTreeWildcard(t *testing.T) {
|
||||
{"/", false, "/", nil},
|
||||
{"/cmd/test", true, "/cmd/:tool/", Params{Param{"tool", "test"}}},
|
||||
{"/cmd/test/", false, "/cmd/:tool/", Params{Param{"tool", "test"}}},
|
||||
{"/cmd/test/3", false, "/cmd/:tool/:sub", Params{Param{Key: "tool", Value: "test"}, Param{Key: "sub", Value: "3"}}},
|
||||
{"/cmd/who", true, "/cmd/:tool/", Params{Param{"tool", "who"}}},
|
||||
{"/cmd/who/", false, "/cmd/:tool/", Params{Param{"tool", "who"}}},
|
||||
{"/cmd/whoami", false, "/cmd/whoami", nil},
|
||||
{"/cmd/whoami/", true, "/cmd/whoami", nil},
|
||||
{"/cmd/whoami/r", false, "/cmd/:tool/:sub", Params{Param{Key: "tool", Value: "whoami"}, Param{Key: "sub", Value: "r"}}},
|
||||
{"/cmd/whoami/r/", true, "/cmd/:tool/:sub", Params{Param{Key: "tool", Value: "whoami"}, Param{Key: "sub", Value: "r"}}},
|
||||
{"/cmd/whoami/root", false, "/cmd/whoami/root", nil},
|
||||
{"/cmd/whoami/root/", false, "/cmd/whoami/root/", nil},
|
||||
{"/cmd/whoami/root", true, "/cmd/whoami/root/", nil},
|
||||
{"/cmd/test/3", false, "/cmd/:tool/:sub", Params{Param{Key: "tool", Value: "test"}, Param{Key: "sub", Value: "3"}}},
|
||||
{"/src/", false, "/src/*filepath", Params{Param{Key: "filepath", Value: "/"}}},
|
||||
{"/src/some/file.png", false, "/src/*filepath", Params{Param{Key: "filepath", Value: "/some/file.png"}}},
|
||||
{"/search/", false, "/search/", nil},
|
||||
{"/search/someth!ng+in+ünìcodé", false, "/search/:query", Params{Param{Key: "query", Value: "someth!ng+in+ünìcodé"}}},
|
||||
{"/search/someth!ng+in+ünìcodé/", true, "", Params{Param{Key: "query", Value: "someth!ng+in+ünìcodé"}}},
|
||||
{"/search/gin", false, "/search/:query", Params{Param{"query", "gin"}}},
|
||||
{"/search/gin-gonic", false, "/search/gin-gonic", nil},
|
||||
{"/search/google", false, "/search/google", nil},
|
||||
{"/user_gopher", false, "/user_:name", Params{Param{Key: "name", Value: "gopher"}}},
|
||||
{"/user_gopher/about", false, "/user_:name/about", Params{Param{Key: "name", Value: "gopher"}}},
|
||||
{"/files/js/inc/framework.js", false, "/files/:dir/*filepath", Params{Param{Key: "dir", Value: "js"}, Param{Key: "filepath", Value: "/inc/framework.js"}}},
|
||||
{"/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"}}},
|
||||
})
|
||||
|
||||
checkPriorities(t, tree)
|
||||
|
@ -5,4 +5,4 @@
|
||||
package gin
|
||||
|
||||
// Version is the current gin framework's version.
|
||||
const Version = "v1.7.1"
|
||||
const Version = "v1.7.2"
|
||||
|
Loading…
x
Reference in New Issue
Block a user