1// 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} 358