mirror of https://github.com/caddyserver/caddy.git
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
This commit is contained in:
parent
e450a7377b
commit
845bc4d50b
|
@ -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
|
// attacks, so it is strongly recommended to only use this
|
||||||
// feature if absolutely required, if read timeouts are
|
// feature if absolutely required, if read timeouts are
|
||||||
// set, and if body size is limited
|
// set, and if body size is limited
|
||||||
if h.BufferRequests && req.Body != nil {
|
if (h.BufferRequests || isChunkedRequest(req)) && req.Body != nil {
|
||||||
req.Body = h.bufferedBody(req.Body)
|
req.Body, req.ContentLength = h.bufferedBody(req.Body)
|
||||||
|
req.Header.Set("Content-Length", strconv.FormatInt(req.ContentLength, 10))
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.ContentLength == 0 {
|
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 enabled, buffer the response body
|
||||||
if h.BufferResponses {
|
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
|
// 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.
|
// 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!
|
// 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 := bufPool.Get().(*bytes.Buffer)
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
if h.MaxBufferSize > 0 {
|
if h.MaxBufferSize > 0 {
|
||||||
|
@ -1135,16 +1137,25 @@ func (h Handler) bufferedBody(originalBody io.ReadCloser) io.ReadCloser {
|
||||||
Reader: io.MultiReader(buf, originalBody),
|
Reader: io.MultiReader(buf, originalBody),
|
||||||
buf: buf,
|
buf: buf,
|
||||||
body: originalBody,
|
body: originalBody,
|
||||||
}
|
}, n
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_, _ = io.Copy(buf, originalBody)
|
written, _ = io.Copy(buf, originalBody)
|
||||||
}
|
}
|
||||||
originalBody.Close() // no point in keeping it open
|
originalBody.Close() // no point in keeping it open
|
||||||
return bodyReadCloser{
|
return bodyReadCloser{
|
||||||
Reader: buf,
|
Reader: buf,
|
||||||
buf: 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.
|
// cloneRequest makes a semi-deep clone of origReq.
|
||||||
|
|
Loading…
Reference in New Issue