diff options
author | Y.Horie <[email protected]> | 2023-01-09 16:13:34 +0900 |
---|---|---|
committer | GitHub <[email protected]> | 2023-01-09 00:13:34 -0700 |
commit | 845bc4d50b437995d574819850206e4b3db4040d (patch) | |
tree | 3ad6e8428062a04b06f715391fb4a5f2e469c53f /modules/caddyhttp/reverseproxy/reverseproxy.go | |
parent | e450a7377b00f7f2a99042ba8e440fed69072028 (diff) | |
download | caddy-845bc4d50b437995d574819850206e4b3db4040d.tar.gz caddy-845bc4d50b437995d574819850206e4b3db4040d.zip |
reverseproxy: Fix hanging for Transfer-Encoding: chunked (#5289)
* Fixes #5236
* enable request body buffering in reverse proxy
when the request header has Transfer-Encoding: chunked
Diffstat (limited to 'modules/caddyhttp/reverseproxy/reverseproxy.go')
-rw-r--r-- | modules/caddyhttp/reverseproxy/reverseproxy.go | 23 |
1 files changed, 17 insertions, 6 deletions
diff --git a/modules/caddyhttp/reverseproxy/reverseproxy.go b/modules/caddyhttp/reverseproxy/reverseproxy.go index 55d3aa8ce..3adec3d9c 100644 --- a/modules/caddyhttp/reverseproxy/reverseproxy.go +++ b/modules/caddyhttp/reverseproxy/reverseproxy.go @@ -622,8 +622,9 @@ func (h Handler) prepareRequest(req *http.Request, repl *caddy.Replacer) (*http. // attacks, so it is strongly recommended to only use this // feature if absolutely required, if read timeouts are // set, and if body size is limited - if h.BufferRequests && req.Body != nil { - req.Body = h.bufferedBody(req.Body) + if (h.BufferRequests || isChunkedRequest(req)) && req.Body != nil { + req.Body, req.ContentLength = h.bufferedBody(req.Body) + req.Header.Set("Content-Length", strconv.FormatInt(req.ContentLength, 10)) } if req.ContentLength == 0 { @@ -854,7 +855,7 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, origRe // if enabled, buffer the response body if h.BufferResponses { - res.Body = h.bufferedBody(res.Body) + res.Body, _ = h.bufferedBody(res.Body) } // see if any response handler is configured for this response from the backend @@ -1125,7 +1126,8 @@ func (h Handler) provisionUpstream(upstream *Upstream) { // bufferedBody reads originalBody into a buffer, then returns a reader for the buffer. // Always close the return value when done with it, just like if it was the original body! -func (h Handler) bufferedBody(originalBody io.ReadCloser) io.ReadCloser { +func (h Handler) bufferedBody(originalBody io.ReadCloser) (io.ReadCloser, int64) { + var written int64 buf := bufPool.Get().(*bytes.Buffer) buf.Reset() if h.MaxBufferSize > 0 { @@ -1135,16 +1137,25 @@ func (h Handler) bufferedBody(originalBody io.ReadCloser) io.ReadCloser { Reader: io.MultiReader(buf, originalBody), buf: buf, body: originalBody, - } + }, n } } else { - _, _ = io.Copy(buf, originalBody) + written, _ = io.Copy(buf, originalBody) } originalBody.Close() // no point in keeping it open return bodyReadCloser{ Reader: buf, buf: buf, + }, written +} + +func isChunkedRequest(req *http.Request) bool { + for _, transferEncoding := range req.TransferEncoding { + if transferEncoding == "chunked" { + return true + } } + return false } // cloneRequest makes a semi-deep clone of origReq. |