forked from go-zoo/bone
-
Notifications
You must be signed in to change notification settings - Fork 0
/
route.go
168 lines (146 loc) · 3.59 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
162
163
164
165
166
167
168
/********************************
*** Multiplexer for Go ***
*** Code is under MIT license ***
*** Code by CodingFerret ***
*** github.com/squiidz ***
*********************************/
package bone
import (
"fmt"
"net/http"
"net/url"
"strings"
)
// Route content the required information for a valid route
// Path: is the Route URL
// Size: is the length of the path
// Token: is the value of each part of the path, split by /
// pattern: is content information about the route, if it's have a route variable
// handler: is the handler who handle this route
// Method: define HTTP method on the route
type Route struct {
Path string
Size int
Token token
pattern pattern
handler http.Handler
Method string
}
// token content all value of a spliting route path
// tokens: string value of each token
// size: number of token
type token struct {
tokens []string
size int
}
// pattern content the required information for the route pattern
// Exist: check if a variable was declare on the route
// Id: the name of the variable
// Pos: postition of var in the route path
type pattern struct {
Exist bool
Id string
Pos int
}
// NewRoute return a pointer to a Route instance and call save() on it
func NewRoute(url string, h http.Handler) *Route {
r := &Route{Path: url, handler: h}
r.save()
return r
}
// Save, set automaticly the the Route.Size and Route.pattern value
func (r *Route) save() {
r.Token.tokens = strings.Split(r.Path, "/")
for i, s := range r.Token.tokens {
if len(s) >= 1 {
if s[:1] == ":" {
r.pattern.Exist = true
r.pattern.Id = s[1:]
r.pattern.Pos = i
}
}
}
r.Size = len(r.Path)
r.Token.size = len(r.Token.tokens)
}
// Info is only used for debugging
func (r *Route) Info() {
fmt.Printf("Path : %s\n", r.Path)
fmt.Printf("Size : %d\n", r.Size)
fmt.Printf("Have Pattern : %t\n", r.pattern.Exist)
fmt.Printf("ID : %s\n", r.pattern.Id)
fmt.Printf("Position : %d\n", r.pattern.Pos)
fmt.Printf("Method : %s\n", r.Method)
}
// Check if the request match the route pattern
func (r *Route) Match(path string) (url.Values, bool) {
ss := strings.Split(path, "/")
if len(path) >= r.Token.size && r.Path[:r.pattern.Pos] == path[:r.pattern.Pos] {
if len(ss) == r.Token.size && ss[r.Token.size-1] != "" {
uV := url.Values{}
uV.Add(r.pattern.Id, ss[r.pattern.Pos])
return uV, true
}
}
return nil, false
}
// Check if the request respect the route method if provided.
func (r *Route) MethCheck(req *http.Request) bool {
if r.Method != "" {
if req.Method == r.Method {
return true
} else {
return false
}
} else {
return true
}
}
// Set the route method to Get
func (r *Route) Get() *Route {
r.Method = "GET"
return r
}
// Set the route method to Post
func (r *Route) Post() *Route {
r.Method = "POST"
return r
}
// Set the route method to Put
func (r *Route) Put() *Route {
r.Method = "PUT"
return r
}
// Set the route method to Delete
func (r *Route) Delete() *Route {
r.Method = "DELETE"
return r
}
// Set the route method to Head
func (r *Route) Head() *Route {
r.Method = "HEAD"
return r
}
// Set the route method to Patch
func (r *Route) Patch() *Route {
r.Method = "PATCH"
return r
}
// Set the route method to Options
func (r *Route) Options() *Route {
r.Method = "OPTIONS"
return r
}
// Only using this in squiidz/fur package
func (r Route) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if r.Method != "" {
if req.Method == r.Method {
r.handler.ServeHTTP(rw, req)
} else {
http.NotFound(rw, req)
}
} else {
r.handler.ServeHTTP(rw, req)
}
// DEBUG r.Info()
}