Skip to content

Commit b06c93e

Browse files
committed
net/http: add Transport.ProxyConnectHeader to control headers to proxies
Fixes #13290 Change-Id: I0f7e7683d86db501cbedb6a0b7349ceb0769701c Reviewed-on: https://go-review.googlesource.com/32481 Reviewed-by: Martin Möhrmann <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 8380de4 commit b06c93e

File tree

2 files changed

+55
-1
lines changed

2 files changed

+55
-1
lines changed

src/net/http/transport.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ type Transport struct {
175175
// If TLSNextProto is nil, HTTP/2 support is enabled automatically.
176176
TLSNextProto map[string]func(authority string, c *tls.Conn) RoundTripper
177177

178+
// ProxyConnectHeader optionally specifies headers to send to
179+
// proxies during CONNECT requests.
180+
ProxyConnectHeader Header
181+
178182
// MaxResponseHeaderBytes specifies a limit on how many
179183
// response bytes are allowed in the server's response
180184
// header.
@@ -1012,11 +1016,15 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon
10121016
}
10131017
case cm.targetScheme == "https":
10141018
conn := pconn.conn
1019+
hdr := t.ProxyConnectHeader
1020+
if hdr == nil {
1021+
hdr = make(Header)
1022+
}
10151023
connectReq := &Request{
10161024
Method: "CONNECT",
10171025
URL: &url.URL{Opaque: cm.targetAddr},
10181026
Host: cm.targetAddr,
1019-
Header: make(Header),
1027+
Header: hdr,
10201028
}
10211029
if pa := cm.proxyAuth(); pa != "" {
10221030
connectReq.Header.Set("Proxy-Authorization", pa)

src/net/http/transport_test.go

+46
Original file line numberDiff line numberDiff line change
@@ -3777,6 +3777,52 @@ func testTransportIDNA(t *testing.T, h2 bool) {
37773777
}
37783778
}
37793779

3780+
// Issue 13290: send User-Agent in proxy CONNECT
3781+
func TestTransportProxyConnectHeader(t *testing.T) {
3782+
defer afterTest(t)
3783+
reqc := make(chan *Request, 1)
3784+
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
3785+
if r.Method != "CONNECT" {
3786+
t.Errorf("method = %q; want CONNECT", r.Method)
3787+
}
3788+
reqc <- r
3789+
c, _, err := w.(Hijacker).Hijack()
3790+
if err != nil {
3791+
t.Errorf("Hijack: %v", err)
3792+
return
3793+
}
3794+
c.Close()
3795+
}))
3796+
defer ts.Close()
3797+
tr := &Transport{
3798+
ProxyConnectHeader: Header{
3799+
"User-Agent": {"foo"},
3800+
"Other": {"bar"},
3801+
},
3802+
Proxy: func(r *Request) (*url.URL, error) {
3803+
return url.Parse(ts.URL)
3804+
},
3805+
}
3806+
defer tr.CloseIdleConnections()
3807+
c := &Client{Transport: tr}
3808+
res, err := c.Get("https://dummy.tld/") // https to force a CONNECT
3809+
if err == nil {
3810+
res.Body.Close()
3811+
t.Errorf("unexpected success")
3812+
}
3813+
select {
3814+
case <-time.After(3 * time.Second):
3815+
t.Fatal("timeout")
3816+
case r := <-reqc:
3817+
if got, want := r.Header.Get("User-Agent"), "foo"; got != want {
3818+
t.Errorf("CONNECT request User-Agent = %q; want %q", got, want)
3819+
}
3820+
if got, want := r.Header.Get("Other"), "bar"; got != want {
3821+
t.Errorf("CONNECT request Other = %q; want %q", got, want)
3822+
}
3823+
}
3824+
}
3825+
37803826
var errFakeRoundTrip = errors.New("fake roundtrip")
37813827

37823828
type funcRoundTripper func()

0 commit comments

Comments
 (0)