/
mux.go
141 lines (131 loc) · 3.33 KB
/
mux.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
like mux router
use regexp
sam
*/
package gow
import (
"net/url"
"regexp"
"strings"
)
type routerPathInfo struct {
Path string
fullPath string
handlers HandlersChain
params *Params
tsr bool
}
// RoutesInfo defines a routerPathInfo array.
type RouterPath []routerPathInfo
// getMuxValue Returns the handle registered with the given path (key). The values of
// wildcards are saved to a map.
// 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
// given path.
func (n *node) getMuxValue(path string, params *Params, unescape bool) (value nodeValue) {
rpm := getNodeRouterPathMap(n)
routerPath, ok := getMatchPath(path, rpm, unescape)
if ok {
if params != nil {
value.params = params
value.params = routerPath.params
}
value.handlers = routerPath.handlers
value.fullPath = routerPath.fullPath
return
}
return
}
var (
intRegexp = []byte(`(\d+)`)
charRegexp = []byte(`(\w+)`)
starRegexp = []byte(`(.*)`)
)
func mathPath(path string) (regPath string, keys []string) {
var (
replaceRegexp []byte
nPath string
)
nSplit := strings.Split(path, "/")
// like {uid} or {uid:int}
// replace {uid} to regexp
replaceRegexp = charRegexp
wildcardRegexp := regexp.MustCompile(`{\w+}`)
for _, n := range nSplit {
if strings.Contains(n, "{") || strings.Contains(n, "*") {
// math {uid:int}
if strings.Contains(n, ":int") {
n = strings.ReplaceAll(n, ":int", "")
replaceRegexp = intRegexp
}
// static /static/*filepath
if strings.Contains(n, "*filepath") {
n = strings.ReplaceAll(n, "*filepath", string(starRegexp))
replaceRegexp = starRegexp
}
key := wildcardRegexp.FindAllString(n, -1)
keys = append(keys, key...)
nPath = string(wildcardRegexp.ReplaceAll([]byte(n), replaceRegexp))
} else {
nPath = n
}
regPath = regPath + nPath + "/"
}
regPath = regPath[:len(regPath)-1]
return regPath, keys
}
// getMatchPath return routerPathInfo
// regexp match
func getMatchPath(path string, rp RouterPath, unescape bool) (*routerPathInfo, bool) {
lastChar := path[len(path)-1:]
if path != "/" && lastChar == "/" && !strings.Contains(path, ".") {
path = path[:len(path)-1]
}
for _, p := range rp {
regPath, keys := mathPath(p.Path)
if path == regPath {
return &p, true
} else {
// all match
ok, _ := regexp.MatchString("^"+regPath+"$", path)
if ok {
valueRegexp := regexp.MustCompile(regPath)
if unescape {
if v, err := url.QueryUnescape(path); err == nil {
path = v
}
}
values := valueRegexp.FindStringSubmatch(path)
params := new(Params)
for i, k := range keys {
*params = append(*params, Param{
Key: strings.ReplaceAll(strings.ReplaceAll(k, "{", ""), "}", ""),
Value: values[i+1],
})
}
p.params = params
return &p, ok
}
}
}
return nil, false
}
func getNodeRouterPathMap(n *node) (rp RouterPath) {
rp = getNodeRouterPath("", rp, n)
return
}
func getNodeRouterPath(path string, rp RouterPath, root *node) RouterPath {
path += root.path
if len(root.handlers) > 0 {
rp = append(rp, routerPathInfo{
Path: strings.ToLower(path),
fullPath: root.fullPath,
handlers: root.handlers,
})
}
for _, child := range root.children {
rp = getNodeRouterPath(path, rp, child)
}
return rp
}