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.