-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
router.go
259 lines (226 loc) · 9.08 KB
/
router.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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
package navaros
import (
"net/http"
"reflect"
"strings"
)
var PrintHandlerErrors = false
// Router is the main component of Navaros. It is an HTTP handler that can be
// used to handle requests, and route them to the appropriate handlers. It
// implements the http.Handler interface, and can be used as a handler in
// standard http servers. It also implements Navaros' own Handler interface,
// which allows nesting routers for better code organization.
type Router struct {
routeDescriptorMap map[HTTPMethod]map[string]bool
routeDescriptors []*RouteDescriptor
firstHandlerNode *HandlerNode
lastHandlerNode *HandlerNode
}
// NewRouter creates a new router.
func NewRouter() *Router {
return &Router{}
}
// ServeHTTP allows the router to be used as a handler in standard go http
// servers. It handles the incoming request - creating a context and running
// the handler chain over it, then finalizing the response.
func (r *Router) ServeHTTP(res http.ResponseWriter, req *http.Request) {
ctx := NewContextWithNode(res, req, r.firstHandlerNode)
ctx.Next()
ctx.finalize()
ctx.free()
}
// Handle is for the purpose of taking an existing context, and running it
// through the mux's handler chain. If the last handler calls next, it
// will call next on the original context.
func (r *Router) Handle(ctx *Context) {
subCtx := NewSubContextWithNode(ctx, r.firstHandlerNode)
subCtx.Next()
subCtx.free()
if subCtx.currentHandlerNode == nil {
ctx.Next()
}
}
// RouteDescriptors returns a list of all the route descriptors that this
// router is responsible for. Useful for gateway configuration.
func (r *Router) RouteDescriptors() []*RouteDescriptor {
return r.routeDescriptors
}
// Use is for middleware handlers. It allows the handlers to be executed on
// every request. If a path is provided, the middleware will only be executed
// on requests that match the path.
//
// Note that routers are middleware handlers, and so can be passed to Use to
// attach them as sub-routers. It's also important to know that if you provide
// a path with a router, the router will set the mount path as the base path
// for all of it's handlers. This means that if you have a router with a path
// of "/foo", and you bind a handler with a path of "/bar", the handler will
// only be executed on requests with a path of "/foo/bar".
func (r *Router) Use(handlersAndTransformers ...any) {
mountPath := "/**"
if len(handlersAndTransformers) != 0 {
if customMountPath, ok := handlersAndTransformers[0].(string); ok {
if !strings.HasSuffix(customMountPath, "/**") {
customMountPath = strings.TrimSuffix(customMountPath, "/")
customMountPath += "/**"
}
mountPath = customMountPath
handlersAndTransformers = handlersAndTransformers[1:]
}
}
r.bind(false, All, mountPath, handlersAndTransformers...)
}
// All allows binding handlers to all HTTP methods at a given route path
// pattern.
func (r *Router) All(path string, handlersAndTransformers ...any) {
r.bind(false, All, path, handlersAndTransformers...)
}
// Post allows binding handlers to the POST HTTP method at a given route path
// pattern.
func (r *Router) Post(path string, handlersAndTransformers ...any) {
r.bind(false, Post, path, handlersAndTransformers...)
}
// Get allows binding handlers to the GET HTTP method at a given route path
// pattern.
func (r *Router) Get(path string, handlersAndTransformers ...any) {
r.bind(false, Get, path, handlersAndTransformers...)
}
// Put allows binding handlers to the PUT HTTP method at a given route path
// pattern.
func (r *Router) Put(path string, handlersAndTransformers ...any) {
r.bind(false, Put, path, handlersAndTransformers...)
}
// Patch allows binding handlers to the PATCH HTTP method at a given route path
// pattern.
func (r *Router) Patch(path string, handlersAndTransformers ...any) {
r.bind(false, Patch, path, handlersAndTransformers...)
}
// Delete allows binding handlers to the DELETE HTTP method at a given route
// path pattern.
func (r *Router) Delete(path string, handlersAndTransformers ...any) {
r.bind(false, Delete, path, handlersAndTransformers...)
}
// Options allows binding handlers to the OPTIONS HTTP method at a given
// route path pattern.
func (r *Router) Options(path string, handlersAndTransformers ...any) {
r.bind(false, Options, path, handlersAndTransformers...)
}
// Head allows binding handlers to the HEAD HTTP method at a given route
// path pattern.
func (r *Router) Head(path string, handlersAndTransformers ...any) {
r.bind(false, Head, path, handlersAndTransformers...)
}
// PublicAll is the same as All, but it also adds the route descriptor to the
// router's list of public route descriptors.
func (r *Router) PublicAll(path string, handlersAndTransformers ...any) {
r.bind(true, All, path, handlersAndTransformers...)
}
// PublicPost is the same as Post, but it also adds the route descriptor to the
// router's list of public route descriptors.
func (r *Router) PublicPost(path string, handlersAndTransformers ...any) {
r.bind(true, Post, path, handlersAndTransformers...)
}
// PublicGet is the same as Get, but it also adds the route descriptor to the
// router's list of public route descriptors.
func (r *Router) PublicGet(path string, handlersAndTransformers ...any) {
r.bind(true, Get, path, handlersAndTransformers...)
}
// PublicPut is the same as Put, but it also adds the route descriptor to the
// router's list of public route descriptors.
func (r *Router) PublicPut(path string, handlersAndTransformers ...any) {
r.bind(true, Put, path, handlersAndTransformers...)
}
// PublicPatch is the same as Patch, but it also adds the route descriptor to
// the router's list of public route descriptors.
func (r *Router) PublicPatch(path string, handlersAndTransformers ...any) {
r.bind(true, Patch, path, handlersAndTransformers...)
}
// PublicDelete is the same as Delete, but it also adds the route descriptor
// to the router's list of public route descriptors.
func (r *Router) PublicDelete(path string, handlersAndTransformers ...any) {
r.bind(true, Delete, path, handlersAndTransformers...)
}
// PublicOptions is the same as Options, but it also adds the route descriptor
// to the router's list of public route descriptors.
func (r *Router) PublicOptions(path string, handlersAndTransformers ...any) {
r.bind(true, Options, path, handlersAndTransformers...)
}
// PublicHead is the same as Head, but it also adds the route descriptor to the
// router's list of public route descriptors.
func (r *Router) PublicHead(path string, handlersAndTransformers ...any) {
r.bind(true, Head, path, handlersAndTransformers...)
}
// bind creates a pattern object from the route pattern as well as a handler
// node. It then attaches the new link to the end of the router's handler
// chain.
func (r *Router) bind(isPublic bool, method HTTPMethod, path string, handlersAndTransformers ...any) {
if len(handlersAndTransformers) == 0 {
panic("no handlers or transformers provided")
}
pattern, err := NewPattern(path)
if err != nil {
panic(err)
}
for _, handlerOrTransformer := range handlersAndTransformers {
if _, ok := handlerOrTransformer.(Transformer); ok {
continue
} else if _, ok := handlerOrTransformer.(Handler); ok {
continue
} else if _, ok := handlerOrTransformer.(HandlerFunc); ok {
continue
} else if _, ok := handlerOrTransformer.(func(*Context)); ok {
continue
}
panic("invalid handler type. Must be a Transformer, Handler, or " +
"HandlerFunc. Got: " + reflect.TypeOf(handlerOrTransformer).String())
}
hasAddedOwnRouteDescriptor := false
for _, handlerOrTransformer := range handlersAndTransformers {
if routerHandler, ok := handlerOrTransformer.(RouterHandler); ok {
for _, routeDescriptor := range routerHandler.RouteDescriptors() {
mountPath := strings.TrimSuffix(path, "/**")
subPattern, err := NewPattern(mountPath + routeDescriptor.Pattern.String())
if err != nil {
panic(err)
}
r.addRouteDescriptor(routeDescriptor.Method, subPattern)
}
} else if isPublic && !hasAddedOwnRouteDescriptor {
r.addRouteDescriptor(method, pattern)
hasAddedOwnRouteDescriptor = true
}
}
nextHandlerNode := &HandlerNode{
Method: method,
Pattern: pattern,
HandlersAndTransformers: handlersAndTransformers,
}
if r.firstHandlerNode == nil {
r.firstHandlerNode = nextHandlerNode
r.lastHandlerNode = nextHandlerNode
} else {
r.lastHandlerNode.Next = nextHandlerNode
r.lastHandlerNode = nextHandlerNode
}
}
// addRouteDescriptor adds a route descriptor to the router's list of route
// descriptors, but only if it doesn't already exist.
func (r *Router) addRouteDescriptor(method HTTPMethod, pattern *Pattern) {
path := pattern.String()
if r.routeDescriptorMap == nil {
r.routeDescriptorMap = map[HTTPMethod]map[string]bool{}
}
if r.routeDescriptors == nil {
r.routeDescriptors = []*RouteDescriptor{}
}
if _, ok := r.routeDescriptorMap[method]; !ok {
r.routeDescriptorMap[method] = map[string]bool{}
}
if _, ok := r.routeDescriptorMap[method][path]; ok {
return
}
r.routeDescriptorMap[method][path] = true
r.routeDescriptors = append(r.routeDescriptors, &RouteDescriptor{
Method: method,
Pattern: pattern,
})
}