blob: fa535684f96cb48cac428bd66ae01274a1a90951 [file] [log] [blame]
khenaidooab1f7bd2019-11-14 14:00:27 -05001// Copyright 2017 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package promhttp
15
16import (
17 "bufio"
18 "io"
19 "net"
20 "net/http"
21)
22
23const (
24 closeNotifier = 1 << iota
25 flusher
26 hijacker
27 readerFrom
28 pusher
29)
30
31type delegator interface {
32 http.ResponseWriter
33
34 Status() int
35 Written() int64
36}
37
38type responseWriterDelegator struct {
39 http.ResponseWriter
40
41 status int
42 written int64
43 wroteHeader bool
44 observeWriteHeader func(int)
45}
46
47func (r *responseWriterDelegator) Status() int {
48 return r.status
49}
50
51func (r *responseWriterDelegator) Written() int64 {
52 return r.written
53}
54
55func (r *responseWriterDelegator) WriteHeader(code int) {
56 r.status = code
57 r.wroteHeader = true
58 r.ResponseWriter.WriteHeader(code)
59 if r.observeWriteHeader != nil {
60 r.observeWriteHeader(code)
61 }
62}
63
64func (r *responseWriterDelegator) Write(b []byte) (int, error) {
65 if !r.wroteHeader {
66 r.WriteHeader(http.StatusOK)
67 }
68 n, err := r.ResponseWriter.Write(b)
69 r.written += int64(n)
70 return n, err
71}
72
73type closeNotifierDelegator struct{ *responseWriterDelegator }
74type flusherDelegator struct{ *responseWriterDelegator }
75type hijackerDelegator struct{ *responseWriterDelegator }
76type readerFromDelegator struct{ *responseWriterDelegator }
77type pusherDelegator struct{ *responseWriterDelegator }
78
79func (d closeNotifierDelegator) CloseNotify() <-chan bool {
80 //lint:ignore SA1019 http.CloseNotifier is deprecated but we don't want to
81 //remove support from client_golang yet.
82 return d.ResponseWriter.(http.CloseNotifier).CloseNotify()
83}
84func (d flusherDelegator) Flush() {
85 d.ResponseWriter.(http.Flusher).Flush()
86}
87func (d hijackerDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) {
88 return d.ResponseWriter.(http.Hijacker).Hijack()
89}
90func (d readerFromDelegator) ReadFrom(re io.Reader) (int64, error) {
91 if !d.wroteHeader {
92 d.WriteHeader(http.StatusOK)
93 }
94 n, err := d.ResponseWriter.(io.ReaderFrom).ReadFrom(re)
95 d.written += n
96 return n, err
97}
98func (d pusherDelegator) Push(target string, opts *http.PushOptions) error {
99 return d.ResponseWriter.(http.Pusher).Push(target, opts)
100}
101
102var pickDelegator = make([]func(*responseWriterDelegator) delegator, 32)
103
104func init() {
105 // TODO(beorn7): Code generation would help here.
106 pickDelegator[0] = func(d *responseWriterDelegator) delegator { // 0
107 return d
108 }
109 pickDelegator[closeNotifier] = func(d *responseWriterDelegator) delegator { // 1
110 return closeNotifierDelegator{d}
111 }
112 pickDelegator[flusher] = func(d *responseWriterDelegator) delegator { // 2
113 return flusherDelegator{d}
114 }
115 pickDelegator[flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 3
116 return struct {
117 *responseWriterDelegator
118 http.Flusher
119 http.CloseNotifier
120 }{d, flusherDelegator{d}, closeNotifierDelegator{d}}
121 }
122 pickDelegator[hijacker] = func(d *responseWriterDelegator) delegator { // 4
123 return hijackerDelegator{d}
124 }
125 pickDelegator[hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 5
126 return struct {
127 *responseWriterDelegator
128 http.Hijacker
129 http.CloseNotifier
130 }{d, hijackerDelegator{d}, closeNotifierDelegator{d}}
131 }
132 pickDelegator[hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 6
133 return struct {
134 *responseWriterDelegator
135 http.Hijacker
136 http.Flusher
137 }{d, hijackerDelegator{d}, flusherDelegator{d}}
138 }
139 pickDelegator[hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 7
140 return struct {
141 *responseWriterDelegator
142 http.Hijacker
143 http.Flusher
144 http.CloseNotifier
145 }{d, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}}
146 }
147 pickDelegator[readerFrom] = func(d *responseWriterDelegator) delegator { // 8
148 return readerFromDelegator{d}
149 }
150 pickDelegator[readerFrom+closeNotifier] = func(d *responseWriterDelegator) delegator { // 9
151 return struct {
152 *responseWriterDelegator
153 io.ReaderFrom
154 http.CloseNotifier
155 }{d, readerFromDelegator{d}, closeNotifierDelegator{d}}
156 }
157 pickDelegator[readerFrom+flusher] = func(d *responseWriterDelegator) delegator { // 10
158 return struct {
159 *responseWriterDelegator
160 io.ReaderFrom
161 http.Flusher
162 }{d, readerFromDelegator{d}, flusherDelegator{d}}
163 }
164 pickDelegator[readerFrom+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 11
165 return struct {
166 *responseWriterDelegator
167 io.ReaderFrom
168 http.Flusher
169 http.CloseNotifier
170 }{d, readerFromDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}}
171 }
172 pickDelegator[readerFrom+hijacker] = func(d *responseWriterDelegator) delegator { // 12
173 return struct {
174 *responseWriterDelegator
175 io.ReaderFrom
176 http.Hijacker
177 }{d, readerFromDelegator{d}, hijackerDelegator{d}}
178 }
179 pickDelegator[readerFrom+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 13
180 return struct {
181 *responseWriterDelegator
182 io.ReaderFrom
183 http.Hijacker
184 http.CloseNotifier
185 }{d, readerFromDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}}
186 }
187 pickDelegator[readerFrom+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 14
188 return struct {
189 *responseWriterDelegator
190 io.ReaderFrom
191 http.Hijacker
192 http.Flusher
193 }{d, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}}
194 }
195 pickDelegator[readerFrom+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 15
196 return struct {
197 *responseWriterDelegator
198 io.ReaderFrom
199 http.Hijacker
200 http.Flusher
201 http.CloseNotifier
202 }{d, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}}
203 }
204 pickDelegator[pusher] = func(d *responseWriterDelegator) delegator { // 16
205 return pusherDelegator{d}
206 }
207 pickDelegator[pusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 17
208 return struct {
209 *responseWriterDelegator
210 http.Pusher
211 http.CloseNotifier
212 }{d, pusherDelegator{d}, closeNotifierDelegator{d}}
213 }
214 pickDelegator[pusher+flusher] = func(d *responseWriterDelegator) delegator { // 18
215 return struct {
216 *responseWriterDelegator
217 http.Pusher
218 http.Flusher
219 }{d, pusherDelegator{d}, flusherDelegator{d}}
220 }
221 pickDelegator[pusher+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 19
222 return struct {
223 *responseWriterDelegator
224 http.Pusher
225 http.Flusher
226 http.CloseNotifier
227 }{d, pusherDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}}
228 }
229 pickDelegator[pusher+hijacker] = func(d *responseWriterDelegator) delegator { // 20
230 return struct {
231 *responseWriterDelegator
232 http.Pusher
233 http.Hijacker
234 }{d, pusherDelegator{d}, hijackerDelegator{d}}
235 }
236 pickDelegator[pusher+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 21
237 return struct {
238 *responseWriterDelegator
239 http.Pusher
240 http.Hijacker
241 http.CloseNotifier
242 }{d, pusherDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}}
243 }
244 pickDelegator[pusher+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 22
245 return struct {
246 *responseWriterDelegator
247 http.Pusher
248 http.Hijacker
249 http.Flusher
250 }{d, pusherDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}}
251 }
252 pickDelegator[pusher+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { //23
253 return struct {
254 *responseWriterDelegator
255 http.Pusher
256 http.Hijacker
257 http.Flusher
258 http.CloseNotifier
259 }{d, pusherDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}}
260 }
261 pickDelegator[pusher+readerFrom] = func(d *responseWriterDelegator) delegator { // 24
262 return struct {
263 *responseWriterDelegator
264 http.Pusher
265 io.ReaderFrom
266 }{d, pusherDelegator{d}, readerFromDelegator{d}}
267 }
268 pickDelegator[pusher+readerFrom+closeNotifier] = func(d *responseWriterDelegator) delegator { // 25
269 return struct {
270 *responseWriterDelegator
271 http.Pusher
272 io.ReaderFrom
273 http.CloseNotifier
274 }{d, pusherDelegator{d}, readerFromDelegator{d}, closeNotifierDelegator{d}}
275 }
276 pickDelegator[pusher+readerFrom+flusher] = func(d *responseWriterDelegator) delegator { // 26
277 return struct {
278 *responseWriterDelegator
279 http.Pusher
280 io.ReaderFrom
281 http.Flusher
282 }{d, pusherDelegator{d}, readerFromDelegator{d}, flusherDelegator{d}}
283 }
284 pickDelegator[pusher+readerFrom+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 27
285 return struct {
286 *responseWriterDelegator
287 http.Pusher
288 io.ReaderFrom
289 http.Flusher
290 http.CloseNotifier
291 }{d, pusherDelegator{d}, readerFromDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}}
292 }
293 pickDelegator[pusher+readerFrom+hijacker] = func(d *responseWriterDelegator) delegator { // 28
294 return struct {
295 *responseWriterDelegator
296 http.Pusher
297 io.ReaderFrom
298 http.Hijacker
299 }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}}
300 }
301 pickDelegator[pusher+readerFrom+hijacker+closeNotifier] = func(d *responseWriterDelegator) delegator { // 29
302 return struct {
303 *responseWriterDelegator
304 http.Pusher
305 io.ReaderFrom
306 http.Hijacker
307 http.CloseNotifier
308 }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, closeNotifierDelegator{d}}
309 }
310 pickDelegator[pusher+readerFrom+hijacker+flusher] = func(d *responseWriterDelegator) delegator { // 30
311 return struct {
312 *responseWriterDelegator
313 http.Pusher
314 io.ReaderFrom
315 http.Hijacker
316 http.Flusher
317 }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}}
318 }
319 pickDelegator[pusher+readerFrom+hijacker+flusher+closeNotifier] = func(d *responseWriterDelegator) delegator { // 31
320 return struct {
321 *responseWriterDelegator
322 http.Pusher
323 io.ReaderFrom
324 http.Hijacker
325 http.Flusher
326 http.CloseNotifier
327 }{d, pusherDelegator{d}, readerFromDelegator{d}, hijackerDelegator{d}, flusherDelegator{d}, closeNotifierDelegator{d}}
328 }
329}
330
331func newDelegator(w http.ResponseWriter, observeWriteHeaderFunc func(int)) delegator {
332 d := &responseWriterDelegator{
333 ResponseWriter: w,
334 observeWriteHeader: observeWriteHeaderFunc,
335 }
336
337 id := 0
338 //lint:ignore SA1019 http.CloseNotifier is deprecated but we don't want to
339 //remove support from client_golang yet.
340 if _, ok := w.(http.CloseNotifier); ok {
341 id += closeNotifier
342 }
343 if _, ok := w.(http.Flusher); ok {
344 id += flusher
345 }
346 if _, ok := w.(http.Hijacker); ok {
347 id += hijacker
348 }
349 if _, ok := w.(io.ReaderFrom); ok {
350 id += readerFrom
351 }
352 if _, ok := w.(http.Pusher); ok {
353 id += pusher
354 }
355
356 return pickDelegator[id](d)
357}