-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrouter.go
More file actions
166 lines (140 loc) · 4.85 KB
/
Copy pathrouter.go
File metadata and controls
166 lines (140 loc) · 4.85 KB
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
package zttp
import (
"log"
"net"
"path"
"strings"
)
type Handler func(req *Req, res *Res)
type Route struct {
path string
handler Handler
}
type Router struct {
*App
prefix string
getRoutes []Route
postRoutes []Route
deleteRoutes []Route
putRoutes []Route
patchRoutes []Route
middlewares []MiddlewareWrapper
}
// Register the passed handler and path with the app's get routes
func (app *App) Get(path string, handler Handler) {
app.getRoutes = append(app.getRoutes, Route{path, applyMiddleware(handler, app.Router)})
}
// Register the passed handler and path with the app's delete routes
func (app *App) Delete(path string, handler Handler) {
app.deleteRoutes = append(app.deleteRoutes, Route{path, applyMiddleware(handler, app.Router)})
}
// Register the passed handler and path with the app's post routes
func (app *App) Post(path string, handler Handler) {
app.postRoutes = append(app.postRoutes, Route{path, applyMiddleware(handler, app.Router)})
}
// Register the passed handler and path with the app's put routes
func (app *App) Put(path string, handler Handler) {
app.putRoutes = append(app.putRoutes, Route{path, applyMiddleware(handler, app.Router)})
}
// Register the passed handler and path with the app's patch routes
func (app *App) Patch(path string, handler Handler) {
app.patchRoutes = append(app.patchRoutes, Route{path, applyMiddleware(handler, app.Router)})
}
// Register the passed handler and path with the router's get routes
func (router *Router) Get(path string, handler Handler) {
router.getRoutes = append(router.getRoutes, Route{cleanPath(router.prefix, path), applyMiddleware(handler, router)})
}
// Register the passed handler and path with the router's delete routes
func (router *Router) Delete(path string, handler Handler) {
router.deleteRoutes = append(router.deleteRoutes, Route{cleanPath(router.prefix, path), applyMiddleware(handler, router)})
}
// Register the passed handler and path with the router's post routes
func (router *Router) Post(path string, handler Handler) {
router.postRoutes = append(router.postRoutes, Route{cleanPath(router.prefix, path), applyMiddleware(handler, router)})
}
// Register the passed handler and path with the router's put routes
func (router *Router) Put(path string, handler Handler) {
router.putRoutes = append(router.putRoutes, Route{cleanPath(router.prefix, path), applyMiddleware(handler, router)})
}
// Register the passed handler and path with the router's patch routes
func (router *Router) Patch(path string, handler Handler) {
router.patchRoutes = append(router.patchRoutes, Route{cleanPath(router.prefix, path), applyMiddleware(handler, router)})
}
func cleanPath(prefix, p string) string {
// Ensure prefix starts with "/" and does not end with "/"
if prefix == "" {
prefix = "/"
}
if prefix != "/" {
prefix = path.Clean("/" + prefix)
}
// Ensure path starts with "/"
if !path.IsAbs(p) {
p = "/" + p
}
p = path.Clean(p)
// Concatenate and clean the final path
full := path.Join(prefix, p)
if full != "/" && full[len(full)-1] == '/' {
full = full[:len(full)-1]
}
return full
}
// Find the matched handler with the passed path from the router and parse params, if exist
func findHandler(method, path string, socket net.Conn, app *App) (Handler, map[string]string) {
for _, router := range app.Routers {
var routes []Route
switch method {
case "GET":
routes = router.getRoutes
case "DELETE":
routes = router.deleteRoutes
case "POST":
routes = router.postRoutes
case "PUT":
routes = router.putRoutes
case "PATCH":
routes = router.patchRoutes
default:
log.Println("unsupported method:", method)
sendResponse(socket, []byte("Method Not Allowed"), 405, "text/plain", nil)
return nil, nil
}
if handler, params := matchRoute(path, routes); handler != nil {
return handler, params
}
}
return nil, nil
}
// This function searches for the matching handler for the passed request path
// As well as extracting the params, if exist
func matchRoute(requestPath string, routes []Route) (Handler, map[string]string) {
for _, route := range routes {
params := make(map[string]string)
// Split both route and request paths with `/` delimiter to compare each part respectively
routeParts := strings.Split(route.path, "/")
requestParts := strings.Split(requestPath, "/")
// if the lengths don't match, we don't have to compare to know they don't match
if len(routeParts) != len(requestParts) {
continue
}
match := true
for i := range routeParts {
// If it's a param, parse it
// Otherwise, check for equality
if strings.HasPrefix(routeParts[i], ":") {
paramName := routeParts[i][1:]
params[paramName] = requestParts[i]
} else if routeParts[i] != requestParts[i] {
match = false
break
}
}
// If matched, return it
if match {
return route.handler, params
}
}
// Default: no match
return nil, nil
}