-
Notifications
You must be signed in to change notification settings - Fork 0
/
handler.go
95 lines (85 loc) · 2.7 KB
/
handler.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
package itsy
import (
"net/http"
"go.uber.org/zap"
)
// ServeHTTP is the main entry point for the Itsy instance.
func (i *Itsy) ServeHTTP(res http.ResponseWriter, req *http.Request) {
path := req.URL.Path
c := i.prepareRequestContext(res, req, path)
n := i.processRouteSegments(c, path)
if n == nil {
i.Logger.Error("No route found", zap.String("path", path))
return
}
i.handleRequestNode(n, c, req, res)
}
// prepareRequestContext creates a new context for the request.
func (i *Itsy) prepareRequestContext(res http.ResponseWriter, req *http.Request, path string) Context {
c := newBaseContext(req, NewResponse(res, i), i.Resource(path), path, i)
if c.Request().Header.Get(HeaderAccept) == "" {
c.Request().Header.Set(HeaderContentType, MIMETextHTML)
}
return c
}
// processRouteSegments processes the route segments of the request path.
func (i *Itsy) processRouteSegments(c Context, path string) *node {
segments := splitPath(path)
currentNode := i.router.index
for _, segment := range segments {
if segment != "" {
found := false
for _, child := range currentNode.children {
if child.path == segment || (child.regex != nil && child.regex.MatchString(segment)) {
if child.regex != nil && child.regex.MatchString(segment) {
c.AddParam(child.param, segment)
c.SetResource(child.resource)
}
currentNode = child
found = true
break
}
}
if !found {
i.sendHTTPError(StatusNotFound, "Resource does not exist", c.Response().Writer, i.Logger)
return nil
}
}
}
return currentNode
}
// handleRequestNode handles the request node by calling the appropriate handler.
func (i *Itsy) handleRequestNode(n *node, c Context, req *http.Request, res http.ResponseWriter) {
if n == nil {
i.sendHTTPError(StatusNotFound, "Resource does not exist", res, i.Logger)
return
}
if n.resource != nil {
switch req.Method {
case GET:
if n.resource.Handler(GET) == nil {
i.sendHTTPError(StatusMethodNotAllowed, "Handler does not exist for the request method", res, i.Logger)
return
}
callHandler(n.resource, GET, c)
case POST:
if n.resource.Handler(POST) == nil {
i.sendHTTPError(StatusMethodNotAllowed, "Handler does not exist for the request method", res, i.Logger)
return
}
callHandler(n.resource, POST, c)
default:
i.sendHTTPError(StatusMethodNotAllowed, "Handler does not exist for the request method", res, i.Logger)
}
} else {
i.sendHTTPError(StatusNotFound, "Resource does not exist", res, i.Logger)
}
}
// callHandler calls the handler of the resource.
func callHandler(resource Resource, method string, c Context) error {
handler := resource.Handler(method)
if handler == nil {
return nil
}
return handler(c)
}