-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrequest-handler.go
113 lines (97 loc) · 2.12 KB
/
request-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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// go-rs/rest-api-framework
// Copyright(c) 2019-2022 Roshan Gade. All rights reserved.
// MIT Licensed
package rest
import (
"errors"
"fmt"
"net/http"
"strings"
)
type requestHandler struct {
router *router
}
// error variables to handle expected errors
var (
ErrCodeNotFound = "URL_NOT_FOUND"
ErrCodeRuntimeError = "RUNTIME_ERROR"
)
func (h *requestHandler) serveHTTP(w http.ResponseWriter, r *http.Request) {
var ctx = &context{
w: w,
r: r,
}
defer ctx.destroy()
// initialize the context and also prepare destroy
ctx.init()
// recovery/handle any runtime error
defer func() {
err := recover()
if err != nil {
ctx.Throw(ErrCodeRuntimeError, fmt.Errorf("%v", err))
}
h.caughtExceptions(ctx)
}()
// on context done, stop execution
go func() {
_ctx := r.Context()
select {
case <-_ctx.Done():
ctx.end = true
}
}()
// required "/" to match pattern
var uri = r.RequestURI
if !strings.HasSuffix(uri, sep) {
uri += sep
}
// STEP 1: middlewares
for _, handle := range h.router.middlewares {
if ctx.end || ctx.code != "" || ctx.err != nil {
break
}
if handle.pattern.test(uri) {
ctx.params = handle.pattern.match(uri)
handle.task(ctx)
}
}
// STEP 2: routes
for _, handle := range h.router.routes {
if ctx.end || ctx.code != "" || ctx.err != nil {
break
}
if r.Method == handle.method && handle.pattern.test(uri) {
ctx.params = handle.pattern.match(uri)
handle.task(ctx)
}
}
// if no error and still not ended that means its NOT FOUND
if !ctx.end && ctx.code == "" && ctx.err == nil {
ctx.Throw(ErrCodeNotFound, errors.New("URL not found"))
}
// STEP 3: errors
for _, handle := range h.router.exceptions {
if ctx.end || ctx.code == "" {
break
}
if ctx.code == handle.code {
handle.task(ctx.err, ctx)
}
}
}
func (h *requestHandler) caughtExceptions(ctx *context) {
defer h.recover(ctx)
if !ctx.end {
if h.router.uncaughtException != nil {
h.router.uncaughtException(ctx.err, ctx)
} else {
ctx.unhandledException()
}
}
}
func (h *requestHandler) recover(ctx *context) {
err := recover()
if err != nil {
ctx.unhandledException()
}
}