Skip to content

Commit c5af2aa

Browse files
author
Bryan C. Mills
committed
[release-branch.go1.12] 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 #36433 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/+/213677
1 parent e42221d commit c5af2aa

File tree

2 files changed

+45
-3
lines changed

2 files changed

+45
-3
lines changed

src/net/http/transport.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -1309,15 +1309,16 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon
13091309
if hdr == nil {
13101310
hdr = make(Header)
13111311
}
1312+
if pa := cm.proxyAuth(); pa != "" {
1313+
hdr = hdr.clone()
1314+
hdr.Set("Proxy-Authorization", pa)
1315+
}
13121316
connectReq := &Request{
13131317
Method: "CONNECT",
13141318
URL: &url.URL{Opaque: cm.targetAddr},
13151319
Host: cm.targetAddr,
13161320
Header: hdr,
13171321
}
1318-
if pa := cm.proxyAuth(); pa != "" {
1319-
connectReq.Header.Set("Proxy-Authorization", pa)
1320-
}
13211322
connectReq.Write(conn)
13221323

13231324
// Read response.

src/net/http/transport_test.go

+41
Original file line numberDiff line numberDiff line change
@@ -1371,6 +1371,47 @@ func TestTransportDialPreservesNetOpProxyError(t *testing.T) {
13711371
}
13721372
}
13731373

1374+
// Issue 36431: calls to RoundTrip should not mutate t.ProxyConnectHeader.
1375+
//
1376+
// (A bug caused dialConn to instead write the per-request Proxy-Authorization
1377+
// header through to the shared Header instance, introducing a data race.)
1378+
func TestTransportProxyDialDoesNotMutateProxyConnectHeader(t *testing.T) {
1379+
setParallel(t)
1380+
defer afterTest(t)
1381+
1382+
proxy := httptest.NewTLSServer(NotFoundHandler())
1383+
defer proxy.Close()
1384+
c := proxy.Client()
1385+
1386+
tr := c.Transport.(*Transport)
1387+
tr.Proxy = func(*Request) (*url.URL, error) {
1388+
u, _ := url.Parse(proxy.URL)
1389+
u.User = url.UserPassword("aladdin", "opensesame")
1390+
return u, nil
1391+
}
1392+
h := tr.ProxyConnectHeader
1393+
if h == nil {
1394+
h = make(Header)
1395+
}
1396+
tr.ProxyConnectHeader = make(Header, len(h))
1397+
for k, vals := range h {
1398+
tr.ProxyConnectHeader[k] = append([]string(nil), vals...)
1399+
}
1400+
1401+
req, err := NewRequest("GET", "https://golang.fake.tld/", nil)
1402+
if err != nil {
1403+
t.Fatal(err)
1404+
}
1405+
_, err = c.Do(req)
1406+
if err == nil {
1407+
t.Errorf("unexpected Get success")
1408+
}
1409+
1410+
if !reflect.DeepEqual(tr.ProxyConnectHeader, h) {
1411+
t.Errorf("tr.ProxyConnectHeader = %v; want %v", tr.ProxyConnectHeader, h)
1412+
}
1413+
}
1414+
13741415
// TestTransportGzipRecursive sends a gzip quine and checks that the
13751416
// client gets the same value back. This is more cute than anything,
13761417
// but checks that we don't recurse forever, and checks that

0 commit comments

Comments
 (0)