Skip to content

Commit 845bc4d

Browse files
authored
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
1 parent e450a73 commit 845bc4d

1 file changed

Lines changed: 17 additions & 6 deletions

File tree

modules/caddyhttp/reverseproxy/reverseproxy.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -622,8 +622,9 @@ func (h Handler) prepareRequest(req *http.Request, repl *caddy.Replacer) (*http.
622622
// attacks, so it is strongly recommended to only use this
623623
// feature if absolutely required, if read timeouts are
624624
// set, and if body size is limited
625-
if h.BufferRequests && req.Body != nil {
626-
req.Body = h.bufferedBody(req.Body)
625+
if (h.BufferRequests || isChunkedRequest(req)) && req.Body != nil {
626+
req.Body, req.ContentLength = h.bufferedBody(req.Body)
627+
req.Header.Set("Content-Length", strconv.FormatInt(req.ContentLength, 10))
627628
}
628629

629630
if req.ContentLength == 0 {
@@ -854,7 +855,7 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, origRe
854855

855856
// if enabled, buffer the response body
856857
if h.BufferResponses {
857-
res.Body = h.bufferedBody(res.Body)
858+
res.Body, _ = h.bufferedBody(res.Body)
858859
}
859860

860861
// see if any response handler is configured for this response from the backend
@@ -1125,7 +1126,8 @@ func (h Handler) provisionUpstream(upstream *Upstream) {
11251126

11261127
// bufferedBody reads originalBody into a buffer, then returns a reader for the buffer.
11271128
// Always close the return value when done with it, just like if it was the original body!
1128-
func (h Handler) bufferedBody(originalBody io.ReadCloser) io.ReadCloser {
1129+
func (h Handler) bufferedBody(originalBody io.ReadCloser) (io.ReadCloser, int64) {
1130+
var written int64
11291131
buf := bufPool.Get().(*bytes.Buffer)
11301132
buf.Reset()
11311133
if h.MaxBufferSize > 0 {
@@ -1135,16 +1137,25 @@ func (h Handler) bufferedBody(originalBody io.ReadCloser) io.ReadCloser {
11351137
Reader: io.MultiReader(buf, originalBody),
11361138
buf: buf,
11371139
body: originalBody,
1138-
}
1140+
}, n
11391141
}
11401142
} else {
1141-
_, _ = io.Copy(buf, originalBody)
1143+
written, _ = io.Copy(buf, originalBody)
11421144
}
11431145
originalBody.Close() // no point in keeping it open
11441146
return bodyReadCloser{
11451147
Reader: buf,
11461148
buf: buf,
1149+
}, written
1150+
}
1151+
1152+
func isChunkedRequest(req *http.Request) bool {
1153+
for _, transferEncoding := range req.TransferEncoding {
1154+
if transferEncoding == "chunked" {
1155+
return true
1156+
}
11471157
}
1158+
return false
11481159
}
11491160

11501161
// cloneRequest makes a semi-deep clone of origReq.

0 commit comments

Comments
 (0)