"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "tree.go" between
gin-1.7.6.tar.gz and gin-1.7.7.tar.gz

About: Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API (with much better performance).

tree.go  (gin-1.7.6):tree.go  (gin-1.7.7)
skipping to change at line 20 skipping to change at line 20
"strings" "strings"
"unicode" "unicode"
"unicode/utf8" "unicode/utf8"
"github.com/gin-gonic/gin/internal/bytesconv" "github.com/gin-gonic/gin/internal/bytesconv"
) )
var ( var (
strColon = []byte(":") strColon = []byte(":")
strStar = []byte("*") strStar = []byte("*")
strSlash = []byte("/")
) )
// Param is a single URL parameter, consisting of a key and a value. // Param is a single URL parameter, consisting of a key and a value.
type Param struct { type Param struct {
Key string Key string
Value string Value string
} }
// Params is a Param-slice, as returned by the router. // Params is a Param-slice, as returned by the router.
// The slice is ordered, the first URL parameter is also the first slice value. // The slice is ordered, the first URL parameter is also the first slice value.
skipping to change at line 101 skipping to change at line 102
} }
func countParams(path string) uint16 { func countParams(path string) uint16 {
var n uint16 var n uint16
s := bytesconv.StringToBytes(path) s := bytesconv.StringToBytes(path)
n += uint16(bytes.Count(s, strColon)) n += uint16(bytes.Count(s, strColon))
n += uint16(bytes.Count(s, strStar)) n += uint16(bytes.Count(s, strStar))
return n return n
} }
func countSections(path string) uint16 {
s := bytesconv.StringToBytes(path)
return uint16(bytes.Count(s, strSlash))
}
type nodeType uint8 type nodeType uint8
const ( const (
static nodeType = iota // default static nodeType = iota // default
root root
param param
catchAll catchAll
) )
type node struct { type node struct {
skipping to change at line 397 skipping to change at line 403
} }
// nodeValue holds return values of (*Node).getValue method // nodeValue holds return values of (*Node).getValue method
type nodeValue struct { type nodeValue struct {
handlers HandlersChain handlers HandlersChain
params *Params params *Params
tsr bool tsr bool
fullPath string fullPath string
} }
type skippedNode struct {
path string
node *node
paramsCount int16
}
// Returns the handle registered with the given path (key). The values of // Returns the handle registered with the given path (key). The values of
// wildcards are saved to a map. // wildcards are saved to a map.
// If no handle can be found, a TSR (trailing slash redirect) recommendation is // If no handle can be found, a TSR (trailing slash redirect) recommendation is
// made if a handle exists with an extra (without the) trailing slash for the // made if a handle exists with an extra (without the) trailing slash for the
// given path. // given path.
func (n *node) getValue(path string, params *Params, unescape bool) (value nodeV func (n *node) getValue(path string, params *Params, skippedNodes *[]skippedNode
alue) { , unescape bool) (value nodeValue) {
var ( var globalParamsCount int16
skippedPath string
latestNode = n // Caching the latest node
)
walk: // Outer loop for walking the tree walk: // Outer loop for walking the tree
for { for {
prefix := n.path prefix := n.path
if len(path) > len(prefix) { if len(path) > len(prefix) {
if path[:len(prefix)] == prefix { if path[:len(prefix)] == prefix {
path = path[len(prefix):] path = path[len(prefix):]
// Try all the non-wildcard children first by mat ching the indices // Try all the non-wildcard children first by mat ching the indices
idxc := path[0] idxc := path[0]
for i, c := range []byte(n.indices) { for i, c := range []byte(n.indices) {
if c == idxc { if c == idxc {
// strings.HasPrefix(n.children[ len(n.children)-1].path, ":") == n.wildChild // strings.HasPrefix(n.children[ len(n.children)-1].path, ":") == n.wildChild
if n.wildChild { if n.wildChild {
skippedPath = prefix + pa index := len(*skippedNode
th s)
latestNode = &node{ *skippedNodes = (*skipped
path: n.path Nodes)[:index+1]
, (*skippedNodes)[index] =
wildChild: n.wild skippedNode{
Child, path: prefix + pa
nType: n.nTyp th,
e, node: &node{
priority: n.prio path:
rity, n.path,
children: n.chil wildChild
dren, : n.wildChild,
handlers: n.hand nType:
lers, n.nType,
fullPath: n.full priority:
Path, n.priority,
children:
n.children,
handlers:
n.handlers,
fullPath:
n.fullPath,
},
paramsCount: glob
alParamsCount,
} }
} }
n = n.children[i] n = n.children[i]
continue walk continue walk
} }
} }
// If the path at the end of the loop is not equa
l to '/' and the current node has no child nodes
// the current node needs to be equal to the late
st matching node
matched := path != "/" && !n.wildChild
if matched {
n = latestNode
}
// If there is no wildcard pattern, recommend a r edirection
if !n.wildChild { if !n.wildChild {
// 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
if path != "/" {
for l := len(*skippedNodes); l >
0; {
skippedNode := (*skippedN
odes)[l-1]
*skippedNodes = (*skipped
Nodes)[:l-1]
if strings.HasSuffix(skip
pedNode.path, path) {
path = skippedNod
e.path
n = skippedNode.n
ode
if value.params !
= nil {
*value.pa
rams = (*value.params)[:skippedNode.paramsCount]
}
globalParamsCount
= skippedNode.paramsCount
continue walk
}
}
}
// Nothing found. // Nothing found.
// We can recommend to redirect to the sa me URL without a // We can recommend to redirect to the sa me URL without a
// trailing slash if a leaf exists for th at path. // trailing slash if a leaf exists for th at path.
value.tsr = path == "/" && n.handlers != nil value.tsr = path == "/" && n.handlers != nil
return return
} }
// Handle wildcard child, which is always at the end of the array // Handle wildcard child, which is always at the end of the array
n = n.children[len(n.children)-1] n = n.children[len(n.children)-1]
globalParamsCount++
switch n.nType { switch n.nType {
case param: case param:
// fix truncate the parameter // fix truncate the parameter
// tree_test.go line: 204 // tree_test.go line: 204
if matched {
path = prefix + path
// The saved path is used after t
he prefix route is intercepted by matching
if n.indices == "/" {
path = skippedPath[1:]
}
}
// Find param end (either '/' or path end ) // Find param end (either '/' or path end )
end := 0 end := 0
for end < len(path) && path[end] != '/' { for end < len(path) && path[end] != '/' {
end++ end++
} }
// Save param value // Save param value
if params != nil { if params != nil && cap(*params) > 0 {
if value.params == nil { if value.params == nil {
value.params = params value.params = params
} }
// Expand slice within preallocat ed capacity // Expand slice within preallocat ed capacity
i := len(*value.params) i := len(*value.params)
*value.params = (*value.params)[: i+1] *value.params = (*value.params)[: i+1]
val := path[:end] val := path[:end]
if unescape { if unescape {
if v, err := url.QueryUne scape(val); err == nil { if v, err := url.QueryUne scape(val); err == nil {
val = v val = v
skipping to change at line 503 skipping to change at line 522
// we need to go deeper! // we need to go deeper!
if end < len(path) { if end < len(path) {
if len(n.children) > 0 { if len(n.children) > 0 {
path = path[end:] path = path[end:]
n = n.children[0] n = n.children[0]
continue walk continue walk
} }
// ... but we can't // ... but we can't
value.tsr = (len(path) == end+1) value.tsr = len(path) == end+1
return return
} }
if value.handlers = n.handlers; value.han dlers != nil { if value.handlers = n.handlers; value.han dlers != nil {
value.fullPath = n.fullPath value.fullPath = n.fullPath
return return
} }
if len(n.children) == 1 { if len(n.children) == 1 {
// No handle found. Check if a ha ndle for this path + a // No handle found. Check if a ha ndle for this path + a
// trailing slash exists for TSR recommendation // trailing slash exists for TSR recommendation
n = n.children[0] n = n.children[0]
value.tsr = (n.path == "/" && n.h andlers != nil) value.tsr = n.path == "/" && n.ha ndlers != nil
} }
return return
case catchAll: case catchAll:
// Save param value // Save param value
if params != nil { if params != nil {
if value.params == nil { if value.params == nil {
value.params = params value.params = params
} }
// Expand slice within preallocat ed capacity // Expand slice within preallocat ed capacity
skipping to change at line 552 skipping to change at line 571
return return
default: default:
panic("invalid node type") panic("invalid node type")
} }
} }
} }
if path == prefix { if path == prefix {
// If the current path does not equal '/' and the node do es not have a registered handle and the most recently matched node has a child n ode // If the current path does not equal '/' and the node do es not have a registered handle and the most recently matched node has a child n ode
// the current node needs to be equal to the latest match // the current node needs to roll back to last vaild skip
ing node pedNode
if latestNode.wildChild && n.handlers == nil && path != " if n.handlers == nil && path != "/" {
/" { for l := len(*skippedNodes); l > 0; {
n = latestNode.children[len(latestNode.children)- skippedNode := (*skippedNodes)[l-1]
1] *skippedNodes = (*skippedNodes)[:l-1]
if strings.HasSuffix(skippedNode.path, pa
th) {
path = skippedNode.path
n = skippedNode.node
if value.params != nil {
*value.params = (*value.p
arams)[:skippedNode.paramsCount]
}
globalParamsCount = skippedNode.p
aramsCount
continue walk
}
}
// n = latestNode.children[len(latestNode.ch
ildren)-1]
} }
// We should have reached the node containing the handle. // We should have reached the node containing the handle.
// Check if this node has a handle registered. // Check if this node has a handle registered.
if value.handlers = n.handlers; value.handlers != nil { if value.handlers = n.handlers; value.handlers != nil {
value.fullPath = n.fullPath value.fullPath = n.fullPath
return return
} }
// If there is no handle for this route, but this route h as a // If there is no handle for this route, but this route h as a
// wildcard child, there must be a handle for this path w ith an // wildcard child, there must be a handle for this path w ith an
skipping to change at line 585 skipping to change at line 617
n = n.children[i] n = n.children[i]
value.tsr = (len(n.path) == 1 && n.handle rs != nil) || value.tsr = (len(n.path) == 1 && n.handle rs != nil) ||
(n.nType == catchAll && n.childre n[0].handlers != nil) (n.nType == catchAll && n.childre n[0].handlers != nil)
return return
} }
} }
return return
} }
if path != "/" && len(skippedPath) > 0 && strings.HasSuffix(skipp
edPath, path) {
path = skippedPath
// Reduce the number of cycles
n, latestNode = latestNode, n
// skippedPath cannot execute
// example:
// * /:cc/cc
// call /a/cc expectations:match/200 Actual:m
atch/200
// call /a/dd expectations:unmatch/404 Actual:
panic
// call /addr/dd/aa expectations:unmatch/404 Actual:
panic
// skippedPath: It can only be executed if the secondary
route is not found
skippedPath = ""
continue walk
}
// Nothing found. We can recommend to redirect to the same URL wi th an // Nothing found. We can recommend to redirect to the same URL wi th an
// extra trailing slash if a leaf exists for that path // extra trailing slash if a leaf exists for that path
value.tsr = path == "/" || value.tsr = path == "/" ||
(len(prefix) == len(path)+1 && n.handlers != nil) (len(prefix) == len(path)+1 && prefix[len(path)] == '/' &
&
path == prefix[:len(prefix)-1] && n.handlers != n
il)
// roll back to last valid skippedNode
if !value.tsr && path != "/" {
for l := len(*skippedNodes); l > 0; {
skippedNode := (*skippedNodes)[l-1]
*skippedNodes = (*skippedNodes)[:l-1]
if strings.HasSuffix(skippedNode.path, path) {
path = skippedNode.path
n = skippedNode.node
if value.params != nil {
*value.params = (*value.params)[:
skippedNode.paramsCount]
}
globalParamsCount = skippedNode.paramsCou
nt
continue walk
}
}
}
return return
} }
} }
// Makes a case-insensitive lookup of the given path and tries to find a handler . // Makes a case-insensitive lookup of the given path and tries to find a handler .
// It can optionally also fix trailing slashes. // It can optionally also fix trailing slashes.
// It returns the case-corrected path and a bool indicating whether the lookup // It returns the case-corrected path and a bool indicating whether the lookup
// was successful. // was successful.
func (n *node) findCaseInsensitivePath(path string, fixTrailingSlash bool) ([]by te, bool) { func (n *node) findCaseInsensitivePath(path string, fixTrailingSlash bool) ([]by te, bool) {
const stackBufSize = 128 const stackBufSize = 128
 End of changes. 16 change blocks. 
70 lines changed or deleted 119 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)