diff --git a/modules/caddyhttp/reverseproxy/reverseproxy.go b/modules/caddyhttp/reverseproxy/reverseproxy.go index 81a1ef1eb3c..3726eb19888 100644 --- a/modules/caddyhttp/reverseproxy/reverseproxy.go +++ b/modules/caddyhttp/reverseproxy/reverseproxy.go @@ -1108,6 +1108,13 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, origRe res.Body, _ = h.bufferedBody(res.Body, h.ResponseBuffers) } + var bodyReleased bool + defer func() { + if !bodyReleased && res != nil && res.Body != nil { + res.Body.Close() + } + }() + // set response placeholders so they can be used in retry match // expressions and handle_response routes; clear stale header // placeholders from a previous attempt first so they don't @@ -1139,6 +1146,7 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, origRe } if match { res.Body.Close() + bodyReleased = true return retryableResponseError{ error: fmt.Errorf("upstream response matched retry_match (status %d)", res.StatusCode), statusCode: res.StatusCode, @@ -1196,6 +1204,7 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, origRe if !hrc.isFinalized { res.Body.Close() } + bodyReleased = true // wrap any route error in roundtripSucceededError so caller knows that // the roundtrip was successful and to not retry @@ -1209,6 +1218,7 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, origRe } // copy the response body and headers back to the upstream client + bodyReleased = true return h.finalizeResponse(rw, req, res, repl, start, logger) }