@marcel91200 / caddy Mirror · read-only / commits / 845bc4d5
Fork 0

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, 08:00 UTC

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

Y.Horie committed Jan 9, 2023 at 16:13 UTC 845bc4d50b437995d574819850206e4b3db4040d
1 file changed +17 -6
modules/caddyhttp/reverseproxy/reverseproxy.go
+17 -6
@@ -622,8 +622,9 @@ func (h Handler) prepareRequest(req *http.Request, repl *caddy.Replacer) (*http.
622 // attacks, so it is strongly recommended to only use this
623 // feature if absolutely required, if read timeouts are
624 // 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))
628 }
629
630 if req.ContentLength == 0 {
@@ -854,7 +855,7 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, origRe
855
856 // if enabled, buffer the response body
857 if h.BufferResponses {
857 - res.Body = h.bufferedBody(res.Body)
858 + res.Body, _ = h.bufferedBody(res.Body)
859 }
860
861 // see if any response handler is configured for this response from the backend
@@ -1125,7 +1126,8 @@ func (h Handler) provisionUpstream(upstream *Upstream) {
1126
1127 // bufferedBody reads originalBody into a buffer, then returns a reader for the buffer.
1128 // 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
1131 buf := bufPool.Get().(*bytes.Buffer)
1132 buf.Reset()
1133 if h.MaxBufferSize > 0 {
@@ -1135,16 +1137,25 @@ func (h Handler) bufferedBody(originalBody io.ReadCloser) io.ReadCloser {
1137 Reader: io.MultiReader(buf, originalBody),
1138 buf: buf,
1139 body: originalBody,
1138 - }
1140 + }, n
1141 }
1142 } else {
1141 - _, _ = io.Copy(buf, originalBody)
1143 + written, _ = io.Copy(buf, originalBody)
1144 }
1145 originalBody.Close() // no point in keeping it open
1146 return bodyReadCloser{
1147 Reader: buf,
1148 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 + }
1157 }
1158 + return false
1159 }
1160
1161 // cloneRequest makes a semi-deep clone of origReq.