aboutsummaryrefslogtreecommitdiff
path: root/src/net/http/httputil/reverseproxy.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/http/httputil/reverseproxy.go')
-rw-r--r--src/net/http/httputil/reverseproxy.go30
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)
+}