-
Notifications
You must be signed in to change notification settings - Fork 0
/
router.go
107 lines (95 loc) · 2.49 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
/*
* Copyright 2015 Xuyuan Pang
* Author: Pang Xuyuan <xuyuanp # gmail dot com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package hodor
import (
"context"
"net/http"
)
// Method is HTTP method.
type Method string
// available methods.
const (
OPTIONS Method = "OPTIONS"
GET = "GET"
HEAD = "HEAD"
POST = "POST"
PUT = "PUT"
DELETE = "DELETE"
TRACE = "TRACE"
CONNECT = "CONNECT"
PATCH = "PATCH"
)
// Methods is a list of all valid methods.
var Methods = []Method{
OPTIONS,
GET,
HEAD,
POST,
PUT,
DELETE,
TRACE,
CONNECT,
PATCH,
}
func (m Method) String() string {
return string(m)
}
// Router interface
type Router interface {
http.Handler
AddRoute(method Method, pattern string, handler http.Handler, filters ...Filter)
}
// NodeRouter struct
type NodeRouter struct {
root *node
Handler404 http.Handler
Handler405 http.Handler
}
func errHandler(status int) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(status), status)
}
}
// NewRouter creates a new router
func NewRouter() *NodeRouter {
return &NodeRouter{
root: newNode(nil, ""),
Handler404: errHandler(http.StatusNotFound),
Handler405: errHandler(http.StatusMethodNotAllowed),
}
}
func (nr *NodeRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
p, h, err := nr.root.match(background, Method(r.Method), r.URL.Path)
switch err {
case errNotFound:
nr.Handler404.ServeHTTP(w, r)
case errMethodNotAllowed:
nr.Handler405.ServeHTTP(w, r)
case nil:
if p != background {
ctx := context.WithValue(r.Context(), paramsKey, p)
r = r.WithContext(ctx)
}
h.ServeHTTP(w, r)
default:
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
// AddRoute implements Router interface
func (nr *NodeRouter) AddRoute(method Method, pattern string, handler http.Handler, filters ...Filter) {
nr.root.addRoute(method, pattern, MergeFilters(filters...).Do(handler))
}