summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorY.Horie <u5.horie@gmail.com>2023-01-09 16:13:34 +0900
committerGitHub <noreply@github.com>2023-01-09 00:13:34 -0700
commit845bc4d50b437995d574819850206e4b3db4040d (patch)
tree3ad6e8428062a04b06f715391fb4a5f2e469c53f
parente450a7377b00f7f2a99042ba8e440fed69072028 (diff)
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
-rw-r--r--modules/caddyhttp/reverseproxy/reverseproxy.go23
1 files changed, 17 insertions, 6 deletions
diff --git a/modules/caddyhttp/reverseproxy/reverseproxy.go b/modules/caddyhttp/reverseproxy/reverseproxy.go
index 55d3aa8..3adec3d 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.