-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmiddleware.go
138 lines (122 loc) · 3.14 KB
/
middleware.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
package chimera
import (
"net/http"
)
// NextFunc is the format for allowing middleware to continue to child middleware
type NextFunc func(req *http.Request) (ResponseWriter, error)
// MiddlewareFunc is a function that can be used as middleware
type MiddlewareFunc func(req *http.Request, ctx RouteContext, next NextFunc) (ResponseWriter, error)
type middlewareWrapper struct {
writer *httpResponseWriter
handler func(w *httpResponseWriter, r *http.Request) (ResponseWriter, error)
}
func (w *middlewareWrapper) Next(r *http.Request) (ResponseWriter, error) {
return w.handler(w.writer, r)
}
// TODO: add func to wrap and convert a http.Handler to a MiddlewareFunc
type httpMiddlewareWriter struct {
parts []ResponseBodyWriter
statusCode int
header http.Header
savedHeader http.Header
}
type respBody []byte
func (r respBody) WriteBody(write BodyWriteFunc) error {
_, err := write(r)
return err
}
// Header returns the response headers
func (w *httpMiddlewareWriter) Header() http.Header {
if w.statusCode > 0 {
return w.savedHeader
}
return w.header
}
// Write writes to the response body
func (w *httpMiddlewareWriter) Write(b []byte) (int, error) {
if w.statusCode < 1 {
w.WriteHeader(200)
}
w.parts = append(w.parts, respBody(b))
return len(b), nil
}
// WriteHeader sets the status code
func (w *httpMiddlewareWriter) WriteHeader(s int) {
if w.statusCode > 0 {
return
}
w.statusCode = s
w.savedHeader = make(http.Header)
for k, v := range w.header {
w.savedHeader[k] = v
}
}
// WriteHead returns the status code and header for this response object
func (w *httpMiddlewareWriter) WriteHead(head *ResponseHead) error {
if w.statusCode > 0 {
head.StatusCode = w.statusCode
}
for k, v := range w.Header() {
head.Headers[k] = v
}
return nil
}
func (w *httpMiddlewareWriter) WriteBody(write BodyWriteFunc) error {
var err error
for _, p := range w.parts {
err = p.WriteBody(write)
if err != nil {
return err
}
}
return nil
}
func (w *httpMiddlewareWriter) OpenAPIResponsesSpec() Responses {
return Responses{}
}
func HTTPMiddleware(middleware func(http.Handler) http.Handler) MiddlewareFunc {
return func(req *http.Request, ctx RouteContext, next NextFunc) (ResponseWriter, error) {
writer := httpMiddlewareWriter{
header: make(http.Header),
}
nextWrapper := http.HandlerFunc(func (w http.ResponseWriter, req *http.Request) {
unchanged := w.(*httpMiddlewareWriter) == &writer
resp, err := next(req)
if err != nil {
if unchanged && writer.statusCode < 1 {
writeError(err, w)
}
return
}
if resp == nil {
return
}
head := ResponseHead{
Headers: w.Header(),
StatusCode: ctx.DefaultResponseCode(),
}
err = resp.WriteHead(&head)
if err != nil {
if unchanged && writer.statusCode < 1 {
writeError(err, w)
}
return
}
if head.StatusCode > 0 {
w.WriteHeader(head.StatusCode)
} else {
w.WriteHeader(ctx.DefaultResponseCode())
}
if resp == nil {
return
}
if unchanged {
writer.parts = append(writer.parts, resp)
} else {
resp.WriteBody(w.Write)
}
})
middleware(nextWrapper).ServeHTTP(&writer, req)
return &writer, nil
}
}