-
Notifications
You must be signed in to change notification settings - Fork 1
/
router.go
171 lines (143 loc) · 6.14 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
package middleware
import (
"net/http"
"os"
)
// router is an HTTP routing machine. The default host automatically creates a
// router and all the top-level endpoints are automatically associated to this
// pointer. If the user wants to serve HTTP requests for two different hosts in
// the same web server, they can register the new host to automatically create
// a new routing machine.
type router struct {
nodes map[string]*privTrie
}
// newRouter creates a new instance of the routing machine.
func newRouter() *router {
return &router{
nodes: map[string]*privTrie{},
}
}
// register registers a new request register with the given path and method.
//
// This function is intended for bulk loading and to allow the usage of less
// frequently used, non-standardized or custom methods (e.g. for internal
// communication with a proxy).
func (r *router) register(method string, endpoint string, fn http.Handler) {
if _, ok := r.nodes[method]; !ok {
r.nodes[method] = newPrivTrie()
}
r.nodes[method].Insert(endpoint, fn)
}
// Handle registers the handler for the given pattern.
func (r *router) Handle(method string, endpoint string, fn http.HandlerFunc) {
r.register(method, endpoint, fn)
}
// GET requests a representation of the specified resource.
//
// Note that GET should not be used for operations that cause side-effects,
// such as using it for taking actions in web applications. One reason for this
// is that GET may be used arbitrarily by robots or crawlers, which should not
// need to consider the side effects that a request should cause.
func (r *router) GET(endpoint string, fn http.HandlerFunc) {
r.register(http.MethodGet, endpoint, fn)
}
// POST submits data to be processed to the identified resource.
//
// The data is included in the body of the request. This may result in the
// creation of a new resource or the updates of existing resources or both.
//
// Authors of services which use the HTTP protocol SHOULD NOT use GET based
// forms for the submission of sensitive data, because this will cause this
// data to be encoded in the Request-URI. Many existing servers, proxies, and
// user agents will log the request URI in some place where it might be visible
// to third parties. Servers can use POST-based form submission instead.
func (r *router) POST(endpoint string, fn http.HandlerFunc) {
r.register(http.MethodPost, endpoint, fn)
}
// PUT is a shortcut for middleware.handle("PUT", endpoint, handle).
func (r *router) PUT(endpoint string, fn http.HandlerFunc) {
r.register(http.MethodPut, endpoint, fn)
}
// PATCH is a shortcut for middleware.handle("PATCH", endpoint, handle).
func (r *router) PATCH(endpoint string, fn http.HandlerFunc) {
r.register(http.MethodPatch, endpoint, fn)
}
// DELETE is a shortcut for middleware.handle("DELETE", endpoint, handle).
func (r *router) DELETE(endpoint string, fn http.HandlerFunc) {
r.register(http.MethodDelete, endpoint, fn)
}
// HEAD is a shortcut for middleware.handle("HEAD", endpoint, handle).
func (r *router) HEAD(endpoint string, fn http.HandlerFunc) {
r.register(http.MethodHead, endpoint, fn)
}
// OPTIONS is a shortcut for middleware.handle("OPTIONS", endpoint, handle).
func (r *router) OPTIONS(endpoint string, fn http.HandlerFunc) {
r.register(http.MethodOptions, endpoint, fn)
}
// CONNECT is a shortcut for middleware.handle("CONNECT", endpoint, handle).
func (r *router) CONNECT(endpoint string, fn http.HandlerFunc) {
r.register(http.MethodConnect, endpoint, fn)
}
// TRACE is a shortcut for middleware.handle("TRACE", endpoint, handle).
func (r *router) TRACE(endpoint string, fn http.HandlerFunc) {
r.register(http.MethodTrace, endpoint, fn)
}
// COPY is a shortcut for middleware.handle("WebDAV.COPY", endpoint, handle).
func (r *router) COPY(endpoint string, fn http.HandlerFunc) {
r.register("COPY", endpoint, fn)
}
// LOCK is a shortcut for middleware.handle("WebDAV.LOCK", endpoint, handle).
func (r *router) LOCK(endpoint string, fn http.HandlerFunc) {
r.register("LOCK", endpoint, fn)
}
// MKCOL is a shortcut for middleware.handle("WebDAV.MKCOL", endpoint, handle).
func (r *router) MKCOL(endpoint string, fn http.HandlerFunc) {
r.register("MKCOL", endpoint, fn)
}
// MOVE is a shortcut for middleware.handle("WebDAV.MOVE", endpoint, handle).
func (r *router) MOVE(endpoint string, fn http.HandlerFunc) {
r.register("MOVE", endpoint, fn)
}
// PROPFIND is a shortcut for middleware.handle("WebDAV.PROPFIND", endpoint, handle).
func (r *router) PROPFIND(endpoint string, fn http.HandlerFunc) {
r.register("PROPFIND", endpoint, fn)
}
// PROPPATCH is a shortcut for middleware.handle("WebDAV.PROPPATCH", endpoint, handle).
func (r *router) PROPPATCH(endpoint string, fn http.HandlerFunc) {
r.register("PROPPATCH", endpoint, fn)
}
// UNLOCK is a shortcut for middleware.handle("WebDAV.UNLOCK", endpoint, handle).
func (r *router) UNLOCK(endpoint string, fn http.HandlerFunc) {
r.register("UNLOCK", endpoint, fn)
}
// STATIC refers to the static assets folder, a place where people can store
// files that change with low frequency like images, documents, archives and
// to some extend CSS and JavaScript files too. These files are usually better
// served by a cache system and thanks to the design of this library you can
// put one in the middle of your requests as easy as you attach normal HTTP
// handlers.
func (r *router) STATIC(folder string, urlPrefix string) {
fn := r.serveFiles(folder, urlPrefix)
r.HEAD(urlPrefix+"/*", fn)
r.GET(urlPrefix+"/*", fn)
r.POST(urlPrefix+"/*", fn)
}
// serveFiles serves files from the root of the given file system.
func (r *router) serveFiles(root string, prefix string) http.HandlerFunc {
fs := http.FileServer(http.Dir(root))
handler := http.StripPrefix(prefix, fs)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fifo, err := os.Stat(root + r.URL.Path[len(prefix):])
if err != nil {
// requested resource does not exists; return 404 Not Found
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
}
if fifo.IsDir() {
// requested resource is a directory; return 403 Forbidden
http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
return
}
handler.ServeHTTP(w, r)
})
}