Skip to content

Commit 367da16

Browse files
author
Bryan C. Mills
committed
[release-branch.go1.13] net/http: avoid writing to Transport.ProxyConnectHeader
Previously, we accidentally wrote the Proxy-Authorization header for the initial CONNECT request to the shared ProxyConnectHeader map when it was non-nil. Updates #36431 Fixes #36434 Change-Id: I5cb414f391dddf8c23d85427eb6973f14c949025 Reviewed-on: https://go-review.googlesource.com/c/go/+/213638 Run-TryBot: Bryan C. Mills <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> (cherry picked from commit 249c85d) Reviewed-on: https://go-review.googlesource.com/c/go/+/213657
1 parent b570a41 commit 367da16

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

src/net/http/transport.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -1526,15 +1526,16 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *pers
15261526
if hdr == nil {
15271527
hdr = make(Header)
15281528
}
1529+
if pa := cm.proxyAuth(); pa != "" {
1530+
hdr = hdr.Clone()
1531+
hdr.Set("Proxy-Authorization", pa)
1532+
}
15291533
connectReq := &Request{
15301534
Method: "CONNECT",
15311535
URL: &url.URL{Opaque: cm.targetAddr},
15321536
Host: cm.targetAddr,
15331537
Header: hdr,
15341538
}
1535-
if pa := cm.proxyAuth(); pa != "" {
1536-
connectReq.Header.Set("Proxy-Authorization", pa)
1537-
}
15381539
connectReq.Write(conn)
15391540

15401541
// Read response.

src/net/http/transport_test.go

+38
Original file line numberDiff line numberDiff line change
@@ -1483,6 +1483,44 @@ func TestTransportDialPreservesNetOpProxyError(t *testing.T) {
14831483
}
14841484
}
14851485

1486+
// Issue 36431: calls to RoundTrip should not mutate t.ProxyConnectHeader.
1487+
//
1488+
// (A bug caused dialConn to instead write the per-request Proxy-Authorization
1489+
// header through to the shared Header instance, introducing a data race.)
1490+
func TestTransportProxyDialDoesNotMutateProxyConnectHeader(t *testing.T) {
1491+
setParallel(t)
1492+
defer afterTest(t)
1493+
1494+
proxy := httptest.NewTLSServer(NotFoundHandler())
1495+
defer proxy.Close()
1496+
c := proxy.Client()
1497+
1498+
tr := c.Transport.(*Transport)
1499+
tr.Proxy = func(*Request) (*url.URL, error) {
1500+
u, _ := url.Parse(proxy.URL)
1501+
u.User = url.UserPassword("aladdin", "opensesame")
1502+
return u, nil
1503+
}
1504+
h := tr.ProxyConnectHeader
1505+
if h == nil {
1506+
h = make(Header)
1507+
}
1508+
tr.ProxyConnectHeader = h.Clone()
1509+
1510+
req, err := NewRequest("GET", "https://golang.fake.tld/", nil)
1511+
if err != nil {
1512+
t.Fatal(err)
1513+
}
1514+
_, err = c.Do(req)
1515+
if err == nil {
1516+
t.Errorf("unexpected Get success")
1517+
}
1518+
1519+
if !reflect.DeepEqual(tr.ProxyConnectHeader, h) {
1520+
t.Errorf("tr.ProxyConnectHeader = %v; want %v", tr.ProxyConnectHeader, h)
1521+
}
1522+
}
1523+
14861524
// TestTransportGzipRecursive sends a gzip quine and checks that the
14871525
// client gets the same value back. This is more cute than anything,
14881526
// but checks that we don't recurse forever, and checks that

0 commit comments

Comments
 (0)