-
Notifications
You must be signed in to change notification settings - Fork 1
/
ambient_router.go
152 lines (133 loc) · 4.19 KB
/
ambient_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
package ambient
import (
"fmt"
"net/http"
)
// AppRouter represents a router.
type AppRouter interface {
Router
ServeHTTP(w http.ResponseWriter, r *http.Request)
SetNotFound(notFound http.Handler)
SetServeHTTP(h func(w http.ResponseWriter, r *http.Request, err error))
}
// Router represents a router.
type Router interface {
Handle(method string, path string, fn func(http.ResponseWriter, *http.Request) error)
Get(path string, fn func(http.ResponseWriter, *http.Request) error)
Post(path string, fn func(http.ResponseWriter, *http.Request) error)
Patch(path string, fn func(http.ResponseWriter, *http.Request) error)
Put(path string, fn func(http.ResponseWriter, *http.Request) error)
Delete(path string, fn func(http.ResponseWriter, *http.Request) error)
Head(path string, fn func(http.ResponseWriter, *http.Request) error)
Options(path string, fn func(http.ResponseWriter, *http.Request) error)
StatusError(status int, err error) error
Error(status int, w http.ResponseWriter, r *http.Request)
Param(r *http.Request, name string) string
Wrap(handler http.HandlerFunc) func(w http.ResponseWriter, r *http.Request) (err error)
}
// Route is a route for a router.
type Route struct {
Method string
Path string
}
// CustomServeHTTP allows customization of error handling by the router.
type CustomServeHTTP func(log Logger, renderer Renderer,
w http.ResponseWriter, r *http.Request, err error)
// SetupRouter sets the router with the NotFound handler and the default handler.
func SetupRouter(logger Logger, mux AppRouter, te Renderer, customServeHTTP CustomServeHTTP) {
// Set the default handler.
defaultServeHTTP := func(w http.ResponseWriter, r *http.Request, err error) {
if err != nil {
// Set default errors to internal server error.
status := http.StatusInternalServerError
friendlyError := "Darn, something went wrong."
// If the error is a status error, then use the information.
se, ok := err.(Error)
if ok {
if se.Status() > 0 {
status = se.Status()
}
if len(se.Message()) > 0 {
friendlyError = se.Message()
}
}
// Handle only errors.
if status >= 400 {
switch status {
case 403:
// Already logged on plugin access denials.
friendlyError = "A plugin has been denied permission."
case 404:
// No need to log.
friendlyError = "Darn, we cannot find the page."
case 400:
if err != nil {
logger.Info("router error (%v): %v", status, err.Error())
}
case 500:
if err != nil {
logger.Error("router error (%v): %v", status, err.Error())
}
default:
if err != nil {
logger.Info("router error (%v): %v", status, err.Error())
}
}
if te != nil {
err = te.Error(w, r, fmt.Sprintf("<h1>%v</h1>%v", status, friendlyError), status, nil, nil)
if err != nil {
if err != nil {
logger.Info("router error in rendering error template (%v): %v", status, err.Error())
}
http.Error(w, "500 internal server error", http.StatusInternalServerError)
return
}
} else {
http.Error(w, friendlyError, status)
}
}
}
}
// Use the custom handler if it's set.
serveHTTP := defaultServeHTTP
if customServeHTTP != nil {
serveHTTP = func(w http.ResponseWriter, r *http.Request, err error) {
customServeHTTP(logger, te, w, r, err)
}
}
// Send all 404 to the handler.
notFound := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mux.Error(http.StatusNotFound, w, r)
})
// Set up the router.
mux.SetServeHTTP(serveHTTP)
mux.SetNotFound(notFound)
}
// Error represents a handler error. It provides methods for a HTTP status
// code and embeds the built-in error interface.
type Error interface {
error
Status() int
Message() string
}
// StatusError represents an error with an associated HTTP status code.
type StatusError struct {
Code int
Err error
Friendly string
}
// Error returns the error.
func (se StatusError) Error() string {
if se.Err != nil {
return se.Err.Error()
}
return ""
}
// Status returns a HTTP status code.
func (se StatusError) Status() int {
return se.Code
}
// Message returns a optional user friendly error message.
func (se StatusError) Message() string {
return se.Friendly
}