@marcel91200 / caddy Mirror · read-only
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 01:00 UTC

master
go 491 lines 14.7 KB
Raw
1 // Copyright 2015 Matthew Holt and The Caddy Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package caddyhttp
16
17 import (
18 "bufio"
19 "bytes"
20 "fmt"
21 "io"
22 "net"
23 "net/http"
24 "reflect"
25
26 "github.com/caddyserver/caddy/v2"
27 )
28
29 // ResponseWriterWrapper wraps an underlying ResponseWriter and
30 // promotes its Pusher method as well. To use this type, embed
31 // a pointer to it within your own struct type that implements
32 // the http.ResponseWriter interface, then call methods on the
33 // embedded value.
34 type ResponseWriterWrapper struct {
35 http.ResponseWriter
36 }
37
38 // Push implements http.Pusher. It simply calls the underlying
39 // ResponseWriter's Push method if there is one, or returns
40 // ErrNotImplemented otherwise.
41 func (rww *ResponseWriterWrapper) Push(target string, opts *http.PushOptions) error {
42 if pusher, ok := rww.ResponseWriter.(http.Pusher); ok {
43 return pusher.Push(target, opts)
44 }
45 return ErrNotImplemented
46 }
47
48 // ReadFrom implements io.ReaderFrom. It retries to use io.ReaderFrom if available,
49 // then fallback to io.Copy.
50 // see: https://github.com/caddyserver/caddy/issues/6546
51 func (rww *ResponseWriterWrapper) ReadFrom(r io.Reader) (n int64, err error) {
52 if rf, ok := rww.ResponseWriter.(io.ReaderFrom); ok {
53 return rf.ReadFrom(r)
54 }
55 return io.Copy(rww.ResponseWriter, r)
56 }
57
58 // Unwrap returns the underlying ResponseWriter, necessary for
59 // http.ResponseController to work correctly.
60 func (rww *ResponseWriterWrapper) Unwrap() http.ResponseWriter {
61 return rww.ResponseWriter
62 }
63
64 // UnwrapResponseWriterAs walks w through its Unwrap() http.ResponseWriter
65 // chain and returns the first writer that satisfies T (along with true).
66 // If no writer in the chain satisfies T, it returns the zero value of T
67 // and false. This mirrors how http.ResponseController traverses wrapped
68 // writers internally and is useful when code needs to reach interfaces
69 // implemented only by the raw writer owned by the HTTP server — for
70 // example, Extended CONNECT or WebTransport helpers that perform their
71 // own type assertions and cannot see past a wrapper.
72 func UnwrapResponseWriterAs[T any](w http.ResponseWriter) (T, bool) {
73 var zero T
74 seen := make(map[uintptr]struct{})
75 // Bound the walk so a cycle of uncomparable (non-pointer) writers
76 // cannot hang. Production wrapper stacks are a handful of layers.
77 for range 64 {
78 if w == nil {
79 return zero, false
80 }
81 if t, ok := any(w).(T); ok {
82 return t, true
83 }
84 if p := responseWriterPointer(w); p != 0 {
85 if _, dup := seen[p]; dup {
86 return zero, false
87 }
88 seen[p] = struct{}{}
89 }
90 u, ok := w.(interface{ Unwrap() http.ResponseWriter })
91 if !ok {
92 return zero, false
93 }
94 w = u.Unwrap()
95 }
96 return zero, false
97 }
98
99 func responseWriterPointer(w http.ResponseWriter) uintptr {
100 v := reflect.ValueOf(w)
101 // Only pointer-like kinds have stable identity.
102 //exhaustive:ignore
103 switch v.Kind() {
104 case reflect.Pointer, reflect.Map, reflect.Chan, reflect.Func, reflect.Slice, reflect.UnsafePointer:
105 if v.IsNil() {
106 return 0
107 }
108 return v.Pointer()
109 default:
110 return 0
111 }
112 }
113
114 // RecordHijackedStatus records that a status was already flushed to the
115 // client by a writer further down the unwrap chain (for example
116 // webtransport.Server.Upgrade writing through the naked HTTP/3 writer).
117 // It updates any wrapping responseRecorder so access logs and metrics
118 // observe the client-visible status, without writing headers again.
119 func RecordHijackedStatus(w http.ResponseWriter, status int) {
120 rec, ok := UnwrapResponseWriterAs[*responseRecorder](w)
121 if !ok || rec == nil {
122 return
123 }
124 if rec.statusCode == 0 {
125 rec.statusCode = status
126 }
127 rec.wroteHeader = true
128 rec.stream = true
129 }
130
131 // ErrNotImplemented is returned when an underlying
132 // ResponseWriter does not implement the required method.
133 var ErrNotImplemented = fmt.Errorf("method not implemented")
134
135 type responseRecorder struct {
136 *ResponseWriterWrapper
137 statusCode int
138 buf *bytes.Buffer
139 shouldBuffer ShouldBufferFunc
140 size int
141 wroteHeader bool
142 stream bool
143 hijacked bool
144 detached bool
145
146 readSize *int
147 }
148
149 // NewResponseRecorder returns a new ResponseRecorder that can be
150 // used instead of a standard http.ResponseWriter. The recorder is
151 // useful for middlewares which need to buffer a response and
152 // potentially process its entire body before actually writing the
153 // response to the underlying writer. Of course, buffering the entire
154 // body has a memory overhead, but sometimes there is no way to avoid
155 // buffering the whole response, hence the existence of this type.
156 // Still, if at all practical, handlers should strive to stream
157 // responses by wrapping Write and WriteHeader methods instead of
158 // buffering whole response bodies.
159 //
160 // Buffering is actually optional. The shouldBuffer function will
161 // be called just before the headers are written. If it returns
162 // true, the headers and body will be buffered by this recorder
163 // and not written to the underlying writer; if false, the headers
164 // will be written immediately and the body will be streamed out
165 // directly to the underlying writer. If shouldBuffer is nil,
166 // the response will never be buffered and will always be streamed
167 // directly to the writer.
168 //
169 // You can know if shouldBuffer returned true by calling Buffered().
170 //
171 // The provided buffer buf should be obtained from a pool for best
172 // performance (see the sync.Pool type).
173 //
174 // Proper usage of a recorder looks like this:
175 //
176 // rec := caddyhttp.NewResponseRecorder(w, buf, shouldBuffer)
177 // err := next.ServeHTTP(rec, req)
178 // if err != nil {
179 // return err
180 // }
181 // if !rec.Buffered() {
182 // return nil
183 // }
184 // // process the buffered response here
185 //
186 // The header map is not buffered; i.e. the ResponseRecorder's Header()
187 // method returns the same header map of the underlying ResponseWriter.
188 // This is a crucial design decision to allow HTTP trailers to be
189 // flushed properly (https://github.com/caddyserver/caddy/issues/3236).
190 //
191 // Once you are ready to write the response, there are two ways you can
192 // do it. The easier way is to have the recorder do it:
193 //
194 // rec.WriteResponse()
195 //
196 // This writes the recorded response headers as well as the buffered body.
197 // Or, you may wish to do it yourself, especially if you manipulated the
198 // buffered body. First you will need to write the headers with the
199 // recorded status code, then write the body (this example writes the
200 // recorder's body buffer, but you might have your own body to write
201 // instead):
202 //
203 // w.WriteHeader(rec.Status())
204 // io.Copy(w, rec.Buffer())
205 //
206 // As a special case, 1xx responses are not buffered nor recorded
207 // because they are not the final response; they are passed through
208 // directly to the underlying ResponseWriter.
209 func NewResponseRecorder(w http.ResponseWriter, buf *bytes.Buffer, shouldBuffer ShouldBufferFunc) ResponseRecorder {
210 return &responseRecorder{
211 ResponseWriterWrapper: &ResponseWriterWrapper{ResponseWriter: w},
212 buf: buf,
213 shouldBuffer: shouldBuffer,
214 }
215 }
216
217 // WriteHeader writes the headers with statusCode to the wrapped
218 // ResponseWriter unless the response is to be buffered instead.
219 // 1xx responses are never buffered, except 101 which is treated
220 // as a final upgrade response.
221 func (rr *responseRecorder) WriteHeader(statusCode int) {
222 if rr.wroteHeader {
223 return
224 }
225
226 // save statusCode always, in case HTTP middleware upgrades websocket
227 // connections by manually setting headers and writing status 101
228 rr.statusCode = statusCode
229
230 // decide whether we should buffer the response
231 if rr.shouldBuffer == nil {
232 rr.stream = true
233 } else {
234 rr.stream = !rr.shouldBuffer(rr.statusCode, rr.ResponseWriterWrapper.Header())
235 }
236
237 // 1xx responses except 101 aren't final; just informational
238 if statusCode < 100 || statusCode > 199 || statusCode == http.StatusSwitchingProtocols {
239 rr.wroteHeader = true
240 }
241
242 // if 1xx or not buffered, immediately write header
243 if rr.stream || (100 <= statusCode && statusCode <= 199) {
244 rr.ResponseWriterWrapper.WriteHeader(statusCode)
245 }
246 }
247
248 func (rr *responseRecorder) Write(data []byte) (int, error) {
249 rr.WriteHeader(http.StatusOK)
250 var n int
251 var err error
252 if rr.stream {
253 n, err = rr.ResponseWriterWrapper.Write(data)
254 } else {
255 n, err = rr.buf.Write(data)
256 }
257
258 rr.size += n
259 return n, err
260 }
261
262 func (rr *responseRecorder) ReadFrom(r io.Reader) (int64, error) {
263 rr.WriteHeader(http.StatusOK)
264 var n int64
265 var err error
266 if rr.stream {
267 n, err = rr.ResponseWriterWrapper.ReadFrom(r)
268 } else {
269 n, err = rr.buf.ReadFrom(r)
270 }
271
272 rr.size += int(n)
273 return n, err
274 }
275
276 // Status returns the status code that was written, if any.
277 func (rr *responseRecorder) Status() int {
278 return rr.statusCode
279 }
280
281 // Size returns the number of bytes written,
282 // not including the response headers.
283 func (rr *responseRecorder) Size() int {
284 return rr.size
285 }
286
287 // Buffer returns the body buffer that rr was created with.
288 // You should still have your original pointer, though.
289 func (rr *responseRecorder) Buffer() *bytes.Buffer {
290 return rr.buf
291 }
292
293 // Buffered returns whether rr has decided to buffer the response.
294 func (rr *responseRecorder) Buffered() bool {
295 return !rr.stream
296 }
297
298 func (rr *responseRecorder) DetachAfterHijack(detached bool) bool {
299 if rr.hijacked {
300 return false
301 }
302 rr.detached = detached
303 return true
304 }
305
306 func (rr *responseRecorder) WriteResponse() error {
307 if rr.hijacked {
308 return nil
309 }
310 if rr.statusCode == 0 {
311 // could happen if no handlers actually wrote anything,
312 // and this prevents a panic; status must be > 0
313 rr.WriteHeader(http.StatusOK)
314 }
315 if rr.stream {
316 return nil
317 }
318 rr.ResponseWriterWrapper.WriteHeader(rr.statusCode)
319 _, err := io.Copy(rr.ResponseWriterWrapper, rr.buf)
320 return err
321 }
322
323 // FlushError will suppress actual flushing if the response is buffered. See:
324 // https://github.com/caddyserver/caddy/issues/6144
325 func (rr *responseRecorder) FlushError() error {
326 if rr.stream {
327 //nolint:bodyclose
328 return http.NewResponseController(rr.ResponseWriterWrapper).Flush()
329 }
330 return nil
331 }
332
333 // Private interface so it can only be used in this package
334 // #TODO: maybe export it later
335 func (rr *responseRecorder) setReadSize(size *int) {
336 rr.readSize = size
337 }
338
339 func (rr *responseRecorder) Hijack() (net.Conn, *bufio.ReadWriter, error) {
340 if !rr.wroteHeader {
341 // hijacking without writing status code first works as long as
342 // subsequent writes follows http1.1 wire format, but it will
343 // show up with a status code of 0 in the access log and bytes
344 // written will include response headers. Response headers won't
345 // be present in the log if not set on the response writer.
346 caddy.Log().Warn("hijacking without writing status code first")
347 }
348 //nolint:bodyclose
349 conn, brw, err := http.NewResponseController(rr.ResponseWriterWrapper).Hijack()
350 if err != nil {
351 return nil, nil, err
352 }
353 rr.hijacked = true
354 rr.stream = true
355 rr.wroteHeader = true
356 if rr.detached {
357 return conn, brw, nil
358 }
359 // Per http documentation, returned bufio.Writer is empty, but bufio.Read maybe not
360 conn = &hijackedConn{conn, rr}
361 brw.Writer.Reset(conn)
362
363 buffered := brw.Reader.Buffered()
364 if buffered != 0 {
365 conn.(*hijackedConn).updateReadSize(buffered)
366 data, _ := brw.Peek(buffered)
367 brw.Reader.Reset(io.MultiReader(bytes.NewReader(data), conn))
368 // peek to make buffered data appear, as Reset will make it 0
369 _, _ = brw.Peek(buffered)
370 } else {
371 brw.Reader.Reset(conn)
372 }
373 return conn, brw, nil
374 }
375
376 // used to track the size of hijacked response writers
377 type hijackedConn struct {
378 net.Conn
379 rr *responseRecorder
380 }
381
382 func (hc *hijackedConn) updateReadSize(n int) {
383 if hc.rr.readSize != nil {
384 *hc.rr.readSize += n
385 }
386 }
387
388 func (hc *hijackedConn) Read(p []byte) (int, error) {
389 n, err := hc.Conn.Read(p)
390 hc.updateReadSize(n)
391 return n, err
392 }
393
394 func (hc *hijackedConn) WriteTo(w io.Writer) (int64, error) {
395 n, err := io.Copy(w, hc.Conn)
396 hc.updateReadSize(int(n))
397 return n, err
398 }
399
400 func (hc *hijackedConn) Write(p []byte) (int, error) {
401 n, err := hc.Conn.Write(p)
402 hc.rr.size += n
403 return n, err
404 }
405
406 func (hc *hijackedConn) ReadFrom(r io.Reader) (int64, error) {
407 n, err := io.Copy(hc.Conn, r)
408 hc.rr.size += int(n)
409 return n, err
410 }
411
412 // DetachResponseWriterAfterHijack configures w and its wrapped response
413 // writers to detach when hijacked. It succeeds only if every detaching writer
414 // accepts and the unwrap chain reaches the server-owned writer recorded on r.
415 // When detached, bytes read or written stats will not be recorded for the
416 // hijacked connection, and it's safe to use the connection after HTTP
417 // middleware returns.
418 func DetachResponseWriterAfterHijack(w http.ResponseWriter, r *http.Request, detached bool) bool {
419 if r == nil {
420 return false
421 }
422 boundaryWriter, _ := r.Context().Value(responseWriterBoundaryCtxKey).(http.ResponseWriter)
423 boundary := responseWriterPointer(boundaryWriter)
424 if boundary == 0 {
425 return false
426 }
427 seen := make(map[uintptr]struct{})
428 for range 64 {
429 if w == nil {
430 return false
431 }
432 pointer := responseWriterPointer(w)
433 if pointer != 0 {
434 if _, duplicate := seen[pointer]; duplicate {
435 return false
436 }
437 seen[pointer] = struct{}{}
438 }
439 if detacher, ok := w.(interface{ DetachAfterHijack(bool) bool }); ok {
440 if !detacher.DetachAfterHijack(detached) {
441 return false
442 }
443 }
444 if pointer == boundary {
445 return true
446 }
447 unwrapper, ok := w.(interface{ Unwrap() http.ResponseWriter })
448 if !ok {
449 return false
450 }
451 w = unwrapper.Unwrap()
452 }
453 return false
454 }
455
456 type responseWriterBoundaryCtxKeyType struct{}
457
458 var responseWriterBoundaryCtxKey = responseWriterBoundaryCtxKeyType{}
459
460 // ResponseRecorder is a http.ResponseWriter that records
461 // responses instead of writing them to the client. See
462 // docs for NewResponseRecorder for proper usage.
463 type ResponseRecorder interface {
464 http.ResponseWriter
465 Status() int
466 Buffer() *bytes.Buffer
467 Buffered() bool
468 DetachAfterHijack(bool) bool
469 Size() int
470 WriteResponse() error
471 }
472
473 // ShouldBufferFunc is a function that returns true if the
474 // response should be buffered, given the pending HTTP status
475 // code and response headers.
476 type ShouldBufferFunc func(status int, header http.Header) bool
477
478 // Interface guards
479 var (
480 _ http.ResponseWriter = (*ResponseWriterWrapper)(nil)
481 _ ResponseRecorder = (*responseRecorder)(nil)
482
483 // Implementing ReaderFrom can be such a significant
484 // optimization that it should probably be required!
485 // see PR #5022 (25%-50% speedup)
486 _ io.ReaderFrom = (*ResponseWriterWrapper)(nil)
487 _ io.ReaderFrom = (*responseRecorder)(nil)
488 _ io.ReaderFrom = (*hijackedConn)(nil)
489
490 _ io.WriterTo = (*hijackedConn)(nil)
491 )