-
Notifications
You must be signed in to change notification settings - Fork 50
/
route.go
161 lines (139 loc) · 4.53 KB
/
route.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// Copyright 2016 Qiang Xue. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package routing
import (
"fmt"
"net/url"
"strings"
)
// Route represents a URL path pattern that can be used to match requested URLs.
type Route struct {
group *RouteGroup
name, path string
template string
}
// newRoute creates a new Route with the given route path and route group.
func newRoute(path string, group *RouteGroup) *Route {
path = group.prefix + path
name := path
// an asterisk at the end matches any number of characters
if strings.HasSuffix(path, "*") {
path = path[:len(path)-1] + "<:.*>"
}
route := &Route{
group: group,
name: name,
path: path,
template: buildURLTemplate(path),
}
group.router.routes[name] = route
return route
}
// Name sets the name of the route.
// This method will update the registration of the route in the router as well.
func (r *Route) Name(name string) *Route {
r.name = name
r.group.router.routes[name] = r
return r
}
// Get adds the route to the router using the GET HTTP method.
func (r *Route) Get(handlers ...Handler) *Route {
return r.add("GET", handlers)
}
// Post adds the route to the router using the POST HTTP method.
func (r *Route) Post(handlers ...Handler) *Route {
return r.add("POST", handlers)
}
// Put adds the route to the router using the PUT HTTP method.
func (r *Route) Put(handlers ...Handler) *Route {
return r.add("PUT", handlers)
}
// Patch adds the route to the router using the PATCH HTTP method.
func (r *Route) Patch(handlers ...Handler) *Route {
return r.add("PATCH", handlers)
}
// Delete adds the route to the router using the DELETE HTTP method.
func (r *Route) Delete(handlers ...Handler) *Route {
return r.add("DELETE", handlers)
}
// Connect adds the route to the router using the CONNECT HTTP method.
func (r *Route) Connect(handlers ...Handler) *Route {
return r.add("CONNECT", handlers)
}
// Head adds the route to the router using the HEAD HTTP method.
func (r *Route) Head(handlers ...Handler) *Route {
return r.add("HEAD", handlers)
}
// Options adds the route to the router using the OPTIONS HTTP method.
func (r *Route) Options(handlers ...Handler) *Route {
return r.add("OPTIONS", handlers)
}
// Trace adds the route to the router using the TRACE HTTP method.
func (r *Route) Trace(handlers ...Handler) *Route {
return r.add("TRACE", handlers)
}
// To adds the route to the router with the given HTTP methods and handlers.
// Multiple HTTP methods should be separated by commas (without any surrounding spaces).
func (r *Route) To(methods string, handlers ...Handler) *Route {
for _, method := range strings.Split(methods, ",") {
r.add(method, handlers)
}
return r
}
// URL creates a URL using the current route and the given parameters.
// The parameters should be given in the sequence of name1, value1, name2, value2, and so on.
// If a parameter in the route is not provided a value, the parameter token will remain in the resulting URL.
// The method will perform URL encoding for all given parameter values.
func (r *Route) URL(pairs ...interface{}) (s string) {
s = r.template
for i := 0; i < len(pairs); i++ {
name := fmt.Sprintf("<%v>", pairs[i])
value := ""
if i < len(pairs)-1 {
value = url.QueryEscape(fmt.Sprint(pairs[i+1]))
}
s = strings.Replace(s, name, value, -1)
}
return
}
// add registers the route, the specified HTTP method and the handlers to the router.
// The handlers will be combined with the handlers of the route group.
func (r *Route) add(method string, handlers []Handler) *Route {
hh := combineHandlers(r.group.handlers, handlers)
r.group.router.add(method, r.path, hh)
return r
}
// buildURLTemplate converts a route pattern into a URL template by removing regular expressions in parameter tokens.
func buildURLTemplate(path string) string {
template, start, end := "", -1, -1
for i := 0; i < len(path); i++ {
if path[i] == '<' && start < 0 {
start = i
} else if path[i] == '>' && start >= 0 {
name := path[start+1 : i]
for j := start + 1; j < i; j++ {
if path[j] == ':' {
name = path[start+1 : j]
break
}
}
template += path[end+1:start] + "<" + name + ">"
end = i
start = -1
}
}
if end < 0 {
template = path
} else if end < len(path)-1 {
template += path[end+1:]
}
return template
}
// combineHandlers merges two lists of handlers into a new list.
func combineHandlers(h1 []Handler, h2 []Handler) []Handler {
hh := make([]Handler, len(h1)+len(h2))
copy(hh, h1)
copy(hh[len(h1):], h2)
return hh
}