@marcel91200 / caddy Mirror · read-only / commits / f5dce84a
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 13, 15:30 UTC

reverseproxy: Ignore context cancel in stream mode (#4952)

Matt Holt committed Aug 12, 2022 at 13:15 UTC f5dce84a7028d1b116db7fead27ff8b2506baf78
1 file changed +27
modules/caddyhttp/reverseproxy/reverseproxy.go
+27
@@ -109,6 +109,11 @@ type Handler struct {
109 // response is recognized as a streaming response, or if its
110 // content length is -1; for such responses, writes are flushed
111 // to the client immediately.
112 + //
113 + // Normally, a request will be canceled if the client disconnects
114 + // before the response is received from the backend. If explicitly
115 + // set to -1, client disconnection will be ignored and the request
116 + // will be completed to help facilitate low-latency streaming.
117 FlushInterval caddy.Duration `json:"flush_interval,omitempty"`
118
119 // A list of IP ranges (supports CIDR notation) from which
@@ -757,6 +762,15 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, origRe
762 req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
763 }
764
765 + // if FlushInterval is explicitly configured to -1 (i.e. flush continuously to achieve
766 + // low-latency streaming), don't let the transport cancel the request if the client
767 + // disconnects: user probably wants us to finish sending the data to the upstream
768 + // regardless, and we should expect client disconnection in low-latency streaming
769 + // scenarios (see issue #4922)
770 + if h.FlushInterval == -1 {
771 + req = req.WithContext(ignoreClientGoneContext{req.Context(), h.ctx.Done()})
772 + }
773 +
774 // do the round-trip; emit debug log with values we know are
775 // safe, or if there is no error, emit fuller log entry
776 start := time.Now()
@@ -1374,6 +1388,19 @@ type handleResponseContext struct {
1388 isFinalized bool
1389 }
1390
1391 +// ignoreClientGoneContext is a special context.Context type
1392 +// intended for use when doing a RoundTrip where you don't
1393 +// want a client disconnection to cancel the request during
1394 +// the roundtrip. Set its done field to a Done() channel
1395 +// of a context that doesn't get canceled when the client
1396 +// disconnects, such as caddy.Context.Done() instead.
1397 +type ignoreClientGoneContext struct {
1398 + context.Context
1399 + done <-chan struct{}
1400 +}
1401 +
1402 +func (c ignoreClientGoneContext) Done() <-chan struct{} { return c.done }
1403 +
1404 // proxyHandleResponseContextCtxKey is the context key for the active proxy handler
1405 // so that handle_response routes can inherit some config options
1406 // from the proxy handler.