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.