@@ -3,6 +3,7 @@ package api
3
3
import (
4
4
"bufio"
5
5
"fmt"
6
+ "io"
6
7
"net"
7
8
"net/http"
8
9
"regexp"
@@ -51,7 +52,7 @@ func (p *PrometheusMiddleware) Handler(next http.Handler) http.Handler {
51
52
begin := time .Now ()
52
53
interceptor := & interceptor {ResponseWriter : w , statusCode : http .StatusOK }
53
54
path := p .getRouteName (r )
54
- next .ServeHTTP (interceptor , r )
55
+ next .ServeHTTP (interceptor . wrappedResponseWriter () , r )
55
56
var (
56
57
status = strconv .Itoa (interceptor .statusCode )
57
58
took = time .Since (begin )
@@ -94,6 +95,14 @@ type interceptor struct {
94
95
recorded bool
95
96
}
96
97
98
+ func (i * interceptor ) Hijack () (net.Conn , * bufio.ReadWriter , error ) {
99
+ hj , ok := i .ResponseWriter .(http.Hijacker )
100
+ if ! ok {
101
+ return nil , nil , fmt .Errorf ("interceptor: can't cast parent ResponseWriter to Hijacker" )
102
+ }
103
+ return hj .Hijack ()
104
+ }
105
+
97
106
func (i * interceptor ) WriteHeader (code int ) {
98
107
if ! i .recorded {
99
108
i .statusCode = code
@@ -102,10 +111,262 @@ func (i *interceptor) WriteHeader(code int) {
102
111
i .ResponseWriter .WriteHeader (code )
103
112
}
104
113
105
- func (i * interceptor ) Hijack () (net.Conn , * bufio.ReadWriter , error ) {
106
- hj , ok := i .ResponseWriter .(http.Hijacker )
107
- if ! ok {
108
- return nil , nil , fmt .Errorf ("interceptor: can't cast parent ResponseWriter to Hijacker" )
114
+ // Returns a wrapped http.ResponseWriter that implements the same optional interfaces
115
+ // that the underlying ResponseWriter has.
116
+ // Handle every possible combination so that code that checks for the existence of each
117
+ // optional interface functions properly.
118
+ // Based on https://github.com/felixge/httpsnoop/blob/eadd4fad6aac69ae62379194fe0219f3dbc80fd3/wrap_generated_gteq_1.8.go#L66
119
+ func (i * interceptor ) wrappedResponseWriter () http.ResponseWriter {
120
+ closeNotifier , isCloseNotifier := i .ResponseWriter .(http.CloseNotifier )
121
+ flush , isFlusher := i .ResponseWriter .(http.Flusher )
122
+ hijack , isHijacker := i .ResponseWriter .(http.Hijacker )
123
+ push , isPusher := i .ResponseWriter .(http.Pusher )
124
+ readFrom , isReaderFrom := i .ResponseWriter .(io.ReaderFrom )
125
+
126
+ switch {
127
+ case ! isCloseNotifier && ! isFlusher && ! isHijacker && ! isPusher && ! isReaderFrom :
128
+ return struct {
129
+ http.ResponseWriter
130
+ }{i }
131
+
132
+ case isCloseNotifier && ! isFlusher && ! isHijacker && ! isPusher && ! isReaderFrom :
133
+ return struct {
134
+ http.ResponseWriter
135
+ http.CloseNotifier
136
+ }{i , closeNotifier }
137
+
138
+ case ! isCloseNotifier && isFlusher && ! isHijacker && ! isPusher && ! isReaderFrom :
139
+ return struct {
140
+ http.ResponseWriter
141
+ http.Flusher
142
+ }{i , flush }
143
+
144
+ case ! isCloseNotifier && ! isFlusher && isHijacker && ! isPusher && ! isReaderFrom :
145
+ return struct {
146
+ http.ResponseWriter
147
+ http.Hijacker
148
+ }{i , hijack }
149
+
150
+ case ! isCloseNotifier && ! isFlusher && ! isHijacker && isPusher && ! isReaderFrom :
151
+ return struct {
152
+ http.ResponseWriter
153
+ http.Pusher
154
+ }{i , push }
155
+
156
+ case ! isCloseNotifier && ! isFlusher && ! isHijacker && ! isPusher && isReaderFrom :
157
+ return struct {
158
+ http.ResponseWriter
159
+ io.ReaderFrom
160
+ }{i , readFrom }
161
+
162
+ case isCloseNotifier && isFlusher && ! isHijacker && ! isPusher && ! isReaderFrom :
163
+ return struct {
164
+ http.ResponseWriter
165
+ http.CloseNotifier
166
+ http.Flusher
167
+ }{i , closeNotifier , flush }
168
+
169
+ case isCloseNotifier && ! isFlusher && isHijacker && ! isPusher && ! isReaderFrom :
170
+ return struct {
171
+ http.ResponseWriter
172
+ http.CloseNotifier
173
+ http.Hijacker
174
+ }{i , closeNotifier , hijack }
175
+
176
+ case isCloseNotifier && ! isFlusher && ! isHijacker && isPusher && ! isReaderFrom :
177
+ return struct {
178
+ http.ResponseWriter
179
+ http.CloseNotifier
180
+ http.Pusher
181
+ }{i , closeNotifier , push }
182
+
183
+ case isCloseNotifier && ! isFlusher && ! isHijacker && ! isPusher && isReaderFrom :
184
+ return struct {
185
+ http.ResponseWriter
186
+ http.CloseNotifier
187
+ io.ReaderFrom
188
+ }{i , closeNotifier , readFrom }
189
+
190
+ case ! isCloseNotifier && isFlusher && isHijacker && ! isPusher && ! isReaderFrom :
191
+ return struct {
192
+ http.ResponseWriter
193
+ http.Flusher
194
+ http.Hijacker
195
+ }{i , flush , hijack }
196
+
197
+ case ! isCloseNotifier && isFlusher && ! isHijacker && isPusher && ! isReaderFrom :
198
+ return struct {
199
+ http.ResponseWriter
200
+ http.Flusher
201
+ http.Pusher
202
+ }{i , flush , push }
203
+
204
+ case ! isCloseNotifier && isFlusher && ! isHijacker && ! isPusher && isReaderFrom :
205
+ return struct {
206
+ http.ResponseWriter
207
+ http.Flusher
208
+ io.ReaderFrom
209
+ }{i , flush , readFrom }
210
+
211
+ case ! isCloseNotifier && ! isFlusher && isHijacker && isPusher && ! isReaderFrom :
212
+ return struct {
213
+ http.ResponseWriter
214
+ http.Hijacker
215
+ http.Pusher
216
+ }{i , hijack , push }
217
+
218
+ case ! isCloseNotifier && ! isFlusher && isHijacker && ! isPusher && isReaderFrom :
219
+ return struct {
220
+ http.ResponseWriter
221
+ http.Hijacker
222
+ io.ReaderFrom
223
+ }{i , hijack , readFrom }
224
+
225
+ case ! isCloseNotifier && ! isFlusher && ! isHijacker && isPusher && isReaderFrom :
226
+ return struct {
227
+ http.ResponseWriter
228
+ http.Pusher
229
+ io.ReaderFrom
230
+ }{i , push , readFrom }
231
+
232
+ case isCloseNotifier && isFlusher && isHijacker && ! isPusher && ! isReaderFrom :
233
+ return struct {
234
+ http.ResponseWriter
235
+ http.CloseNotifier
236
+ http.Flusher
237
+ http.Hijacker
238
+ }{i , closeNotifier , flush , hijack }
239
+
240
+ case isCloseNotifier && isFlusher && ! isHijacker && isPusher && ! isReaderFrom :
241
+ return struct {
242
+ http.ResponseWriter
243
+ http.CloseNotifier
244
+ http.Flusher
245
+ http.Pusher
246
+ }{i , closeNotifier , flush , push }
247
+
248
+ case isCloseNotifier && isFlusher && ! isHijacker && ! isPusher && isReaderFrom :
249
+ return struct {
250
+ http.ResponseWriter
251
+ http.CloseNotifier
252
+ http.Flusher
253
+ io.ReaderFrom
254
+ }{i , closeNotifier , flush , readFrom }
255
+
256
+ case isCloseNotifier && ! isFlusher && isHijacker && isPusher && ! isReaderFrom :
257
+ return struct {
258
+ http.ResponseWriter
259
+ http.CloseNotifier
260
+ http.Hijacker
261
+ http.Pusher
262
+ }{i , closeNotifier , hijack , push }
263
+
264
+ case isCloseNotifier && ! isFlusher && isHijacker && ! isPusher && isReaderFrom :
265
+ return struct {
266
+ http.ResponseWriter
267
+ http.CloseNotifier
268
+ http.Hijacker
269
+ io.ReaderFrom
270
+ }{i , closeNotifier , hijack , readFrom }
271
+
272
+ case isCloseNotifier && ! isFlusher && ! isHijacker && isPusher && isReaderFrom :
273
+ return struct {
274
+ http.ResponseWriter
275
+ http.CloseNotifier
276
+ http.Pusher
277
+ io.ReaderFrom
278
+ }{i , closeNotifier , push , readFrom }
279
+
280
+ case ! isCloseNotifier && isFlusher && isHijacker && isPusher && ! isReaderFrom :
281
+ return struct {
282
+ http.ResponseWriter
283
+ http.Flusher
284
+ http.Hijacker
285
+ http.Pusher
286
+ }{i , flush , hijack , push }
287
+
288
+ case ! isCloseNotifier && isFlusher && isHijacker && ! isPusher && isReaderFrom :
289
+ return struct {
290
+ http.ResponseWriter
291
+ http.Flusher
292
+ http.Hijacker
293
+ io.ReaderFrom
294
+ }{i , flush , hijack , readFrom }
295
+
296
+ case ! isCloseNotifier && isFlusher && ! isHijacker && isPusher && isReaderFrom :
297
+ return struct {
298
+ http.ResponseWriter
299
+ http.Flusher
300
+ http.Pusher
301
+ io.ReaderFrom
302
+ }{i , flush , push , readFrom }
303
+
304
+ case ! isCloseNotifier && ! isFlusher && isHijacker && isPusher && isReaderFrom :
305
+ return struct {
306
+ http.ResponseWriter
307
+ http.Hijacker
308
+ http.Pusher
309
+ io.ReaderFrom
310
+ }{i , hijack , push , readFrom }
311
+
312
+ case isCloseNotifier && isFlusher && isHijacker && isPusher && ! isReaderFrom :
313
+ return struct {
314
+ http.ResponseWriter
315
+ http.CloseNotifier
316
+ http.Flusher
317
+ http.Hijacker
318
+ http.Pusher
319
+ }{i , closeNotifier , flush , hijack , push }
320
+
321
+ case isCloseNotifier && isFlusher && isHijacker && ! isPusher && isReaderFrom :
322
+ return struct {
323
+ http.ResponseWriter
324
+ http.CloseNotifier
325
+ http.Flusher
326
+ http.Hijacker
327
+ io.ReaderFrom
328
+ }{i , closeNotifier , flush , hijack , readFrom }
329
+
330
+ case isCloseNotifier && isFlusher && ! isHijacker && isPusher && isReaderFrom :
331
+ return struct {
332
+ http.ResponseWriter
333
+ http.CloseNotifier
334
+ http.Flusher
335
+ http.Pusher
336
+ io.ReaderFrom
337
+ }{i , closeNotifier , flush , push , readFrom }
338
+
339
+ case isCloseNotifier && ! isFlusher && isHijacker && isPusher && isReaderFrom :
340
+ return struct {
341
+ http.ResponseWriter
342
+ http.CloseNotifier
343
+ http.Hijacker
344
+ http.Pusher
345
+ io.ReaderFrom
346
+ }{i , closeNotifier , hijack , push , readFrom }
347
+
348
+ case ! isCloseNotifier && isFlusher && isHijacker && isPusher && isReaderFrom :
349
+ return struct {
350
+ http.ResponseWriter
351
+ http.Flusher
352
+ http.Hijacker
353
+ http.Pusher
354
+ io.ReaderFrom
355
+ }{i , flush , hijack , push , readFrom }
356
+
357
+ case isCloseNotifier && isFlusher && isHijacker && isPusher && isReaderFrom :
358
+ return struct {
359
+ http.ResponseWriter
360
+ http.CloseNotifier
361
+ http.Flusher
362
+ http.Hijacker
363
+ http.Pusher
364
+ io.ReaderFrom
365
+ }{i , closeNotifier , flush , hijack , push , readFrom }
366
+
367
+ default :
368
+ return struct {
369
+ http.ResponseWriter
370
+ }{i }
109
371
}
110
- return hj .Hijack ()
111
372
}
0 commit comments