github.com/m3db/m3@v1.5.0/src/x/http/status.go (about) 1 // Copyright (c) 2021 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 // Package http adds extension to the stdlib http package. 22 package http 23 24 import ( 25 "encoding/json" 26 "io" 27 "net/http" 28 29 xhttp "github.com/m3db/m3/src/x/net/http" 30 ) 31 32 // StatusCodeTracker tracks the status code written to a http.ResponseWriter. 33 type StatusCodeTracker struct { 34 http.ResponseWriter 35 Status int 36 WroteHeader bool 37 TrackError bool 38 ErrMsg string 39 } 40 41 // WriteHeader saves the status . 42 func (w *StatusCodeTracker) WriteHeader(status int) { 43 w.Status = status 44 w.WroteHeader = true 45 w.ResponseWriter.WriteHeader(status) 46 } 47 48 // Write saves the status as 200 if it has not already been set. 49 func (w *StatusCodeTracker) Write(b []byte) (int, error) { 50 if !w.WroteHeader { 51 w.WroteHeader = true 52 w.Status = 200 53 } 54 if w.TrackError && w.Status >= 400 { 55 var errResp xhttp.ErrorResponse 56 if err := json.Unmarshal(b, &errResp); err == nil { 57 w.ErrMsg = errResp.Error 58 } 59 } 60 return w.ResponseWriter.Write(b) 61 } 62 63 // WrappedResponseWriter returns a wrapped version of the original 64 // ResponseWriter and only implements the same combination of additional 65 // interfaces as the original. This implementation is based on 66 // https://github.com/felixge/httpsnoop. 67 func (w *StatusCodeTracker) WrappedResponseWriter() http.ResponseWriter { 68 var ( 69 hj, i0 = w.ResponseWriter.(http.Hijacker) 70 cn, i1 = w.ResponseWriter.(http.CloseNotifier) //nolint:staticcheck 71 pu, i2 = w.ResponseWriter.(http.Pusher) 72 fl, i3 = w.ResponseWriter.(http.Flusher) 73 rf, i4 = w.ResponseWriter.(io.ReaderFrom) 74 ) 75 76 switch { 77 case !i0 && !i1 && !i2 && !i3 && !i4: 78 return struct { 79 http.ResponseWriter 80 }{w} 81 case !i0 && !i1 && !i2 && !i3 && i4: 82 return struct { 83 http.ResponseWriter 84 io.ReaderFrom 85 }{w, rf} 86 case !i0 && !i1 && !i2 && i3 && !i4: 87 return struct { 88 http.ResponseWriter 89 http.Flusher 90 }{w, fl} 91 case !i0 && !i1 && !i2 && i3 && i4: 92 return struct { 93 http.ResponseWriter 94 http.Flusher 95 io.ReaderFrom 96 }{w, fl, rf} 97 case !i0 && !i1 && i2 && !i3 && !i4: 98 return struct { 99 http.ResponseWriter 100 http.Pusher 101 }{w, pu} 102 case !i0 && !i1 && i2 && !i3 && i4: 103 return struct { 104 http.ResponseWriter 105 http.Pusher 106 io.ReaderFrom 107 }{w, pu, rf} 108 case !i0 && !i1 && i2 && i3 && !i4: 109 return struct { 110 http.ResponseWriter 111 http.Pusher 112 http.Flusher 113 }{w, pu, fl} 114 case !i0 && !i1 && i2 && i3 && i4: 115 return struct { 116 http.ResponseWriter 117 http.Pusher 118 http.Flusher 119 io.ReaderFrom 120 }{w, pu, fl, rf} 121 case !i0 && i1 && !i2 && !i3 && !i4: 122 return struct { 123 http.ResponseWriter 124 http.CloseNotifier 125 }{w, cn} 126 case !i0 && i1 && !i2 && !i3 && i4: 127 return struct { 128 http.ResponseWriter 129 http.CloseNotifier 130 io.ReaderFrom 131 }{w, cn, rf} 132 case !i0 && i1 && !i2 && i3 && !i4: 133 return struct { 134 http.ResponseWriter 135 http.CloseNotifier 136 http.Flusher 137 }{w, cn, fl} 138 case !i0 && i1 && !i2 && i3 && i4: 139 return struct { 140 http.ResponseWriter 141 http.CloseNotifier 142 http.Flusher 143 io.ReaderFrom 144 }{w, cn, fl, rf} 145 case !i0 && i1 && i2 && !i3 && !i4: 146 return struct { 147 http.ResponseWriter 148 http.CloseNotifier 149 http.Pusher 150 }{w, cn, pu} 151 case !i0 && i1 && i2 && !i3 && i4: 152 return struct { 153 http.ResponseWriter 154 http.CloseNotifier 155 http.Pusher 156 io.ReaderFrom 157 }{w, cn, pu, rf} 158 case !i0 && i1 && i2 && i3 && !i4: 159 return struct { 160 http.ResponseWriter 161 http.CloseNotifier 162 http.Pusher 163 http.Flusher 164 }{w, cn, pu, fl} 165 case !i0 && i1 && i2 && i3 && i4: 166 return struct { 167 http.ResponseWriter 168 http.CloseNotifier 169 http.Pusher 170 http.Flusher 171 io.ReaderFrom 172 }{w, cn, pu, fl, rf} 173 case i0 && !i1 && !i2 && !i3 && !i4: 174 return struct { 175 http.ResponseWriter 176 http.Hijacker 177 }{w, hj} 178 case i0 && !i1 && !i2 && !i3 && i4: 179 return struct { 180 http.ResponseWriter 181 http.Hijacker 182 io.ReaderFrom 183 }{w, hj, rf} 184 case i0 && !i1 && !i2 && i3 && !i4: 185 return struct { 186 http.ResponseWriter 187 http.Hijacker 188 http.Flusher 189 }{w, hj, fl} 190 case i0 && !i1 && !i2 && i3 && i4: 191 return struct { 192 http.ResponseWriter 193 http.Hijacker 194 http.Flusher 195 io.ReaderFrom 196 }{w, hj, fl, rf} 197 case i0 && !i1 && i2 && !i3 && !i4: 198 return struct { 199 http.ResponseWriter 200 http.Hijacker 201 http.Pusher 202 }{w, hj, pu} 203 case i0 && !i1 && i2 && !i3 && i4: 204 return struct { 205 http.ResponseWriter 206 http.Hijacker 207 http.Pusher 208 io.ReaderFrom 209 }{w, hj, pu, rf} 210 case i0 && !i1 && i2 && i3 && !i4: 211 return struct { 212 http.ResponseWriter 213 http.Hijacker 214 http.Pusher 215 http.Flusher 216 }{w, hj, pu, fl} 217 case i0 && !i1 && i2 && i3 && i4: 218 return struct { 219 http.ResponseWriter 220 http.Hijacker 221 http.Pusher 222 http.Flusher 223 io.ReaderFrom 224 }{w, hj, pu, fl, rf} 225 case i0 && i1 && !i2 && !i3 && !i4: 226 return struct { 227 http.ResponseWriter 228 http.Hijacker 229 http.CloseNotifier 230 }{w, hj, cn} 231 case i0 && i1 && !i2 && !i3 && i4: 232 return struct { 233 http.ResponseWriter 234 http.Hijacker 235 http.CloseNotifier 236 io.ReaderFrom 237 }{w, hj, cn, rf} 238 case i0 && i1 && !i2 && i3 && !i4: 239 return struct { 240 http.ResponseWriter 241 http.Hijacker 242 http.CloseNotifier 243 http.Flusher 244 }{w, hj, cn, fl} 245 case i0 && i1 && !i2 && i3 && i4: 246 return struct { 247 http.ResponseWriter 248 http.Hijacker 249 http.CloseNotifier 250 http.Flusher 251 io.ReaderFrom 252 }{w, hj, cn, fl, rf} 253 case i0 && i1 && i2 && !i3 && !i4: 254 return struct { 255 http.ResponseWriter 256 http.Hijacker 257 http.CloseNotifier 258 http.Pusher 259 }{w, hj, cn, pu} 260 case i0 && i1 && i2 && !i3 && i4: 261 return struct { 262 http.ResponseWriter 263 http.Hijacker 264 http.CloseNotifier 265 http.Pusher 266 io.ReaderFrom 267 }{w, hj, cn, pu, rf} 268 case i0 && i1 && i2 && i3 && !i4: 269 return struct { 270 http.ResponseWriter 271 http.Hijacker 272 http.CloseNotifier 273 http.Pusher 274 http.Flusher 275 }{w, hj, cn, pu, fl} 276 case i0 && i1 && i2 && i3 && i4: 277 return struct { 278 http.ResponseWriter 279 http.Hijacker 280 http.CloseNotifier 281 http.Pusher 282 http.Flusher 283 io.ReaderFrom 284 }{w, hj, cn, pu, fl, rf} 285 default: 286 return struct { 287 http.ResponseWriter 288 }{w} 289 } 290 }