diff options
Diffstat (limited to 'src/net/http/httputil/reverseproxy.go')
| -rw-r--r-- | src/net/http/httputil/reverseproxy.go | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go index 9d8784cd2b..7c220319c4 100644 --- a/src/net/http/httputil/reverseproxy.go +++ b/src/net/http/httputil/reverseproxy.go @@ -21,6 +21,7 @@ import ( "net/url" "strings" "sync" + "sync/atomic" "time" "golang.org/x/net/http/httpguts" @@ -435,6 +436,18 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { outreq.Body = nil // Issue 16036: nil Body for http.Transport retries } if outreq.Body != nil { + // Wrap the body in a reader where Close does nothing. This is done + // because p.Transport.RoundTrip would close the reverse proxy's + // outbound request body if it fails to connect to upstream. If we do + // not wrap the body, when we close the reverse proxy's outbound + // request, it will also close the reverse proxy's inbound request body + // (i.e. the client's outbound request body). This is because + // http.(*Request).Clone creates a shallow copy of the body. This can + // cause an infinite hang in cases where the body is not yet received + // from the client (e.g. 100-continue requests): Close, which + // internally tries to consume the body content, would be called too + // early and would hang. + outreq.Body = &noopCloseReader{readCloser: outreq.Body} // Reading from the request body after returning from a handler is not // allowed, and the RoundTrip goroutine that reads the Body can outlive // this handler. This can lead to a crash if the handler panics (see @@ -941,3 +954,20 @@ func ishex(c byte) bool { } return false } + +type noopCloseReader struct { + readCloser io.ReadCloser + closed atomic.Bool +} + +func (ncr *noopCloseReader) Close() error { + ncr.closed.Store(true) + return nil +} + +func (ncr *noopCloseReader) Read(p []byte) (int, error) { + if ncr.closed.Load() { + return 0, errors.New("ReverseProxy does an invalid Read on closed Body") + } + return ncr.readCloser.Read(p) +} |
