Commit b06c93e4 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

net/http: add Transport.ProxyConnectHeader to control headers to proxies

Fixes #13290

Change-Id: I0f7e7683d86db501cbedb6a0b7349ceb0769701c
Reviewed-on: https://go-review.googlesource.com/32481Reviewed-by: default avatarMartin Möhrmann <martisch@uos.de>
Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent 8380de41
...@@ -175,6 +175,10 @@ type Transport struct { ...@@ -175,6 +175,10 @@ type Transport struct {
// If TLSNextProto is nil, HTTP/2 support is enabled automatically. // If TLSNextProto is nil, HTTP/2 support is enabled automatically.
TLSNextProto map[string]func(authority string, c *tls.Conn) RoundTripper TLSNextProto map[string]func(authority string, c *tls.Conn) RoundTripper
// ProxyConnectHeader optionally specifies headers to send to
// proxies during CONNECT requests.
ProxyConnectHeader Header
// MaxResponseHeaderBytes specifies a limit on how many // MaxResponseHeaderBytes specifies a limit on how many
// response bytes are allowed in the server's response // response bytes are allowed in the server's response
// header. // header.
...@@ -1012,11 +1016,15 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon ...@@ -1012,11 +1016,15 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon
} }
case cm.targetScheme == "https": case cm.targetScheme == "https":
conn := pconn.conn conn := pconn.conn
hdr := t.ProxyConnectHeader
if hdr == nil {
hdr = make(Header)
}
connectReq := &Request{ connectReq := &Request{
Method: "CONNECT", Method: "CONNECT",
URL: &url.URL{Opaque: cm.targetAddr}, URL: &url.URL{Opaque: cm.targetAddr},
Host: cm.targetAddr, Host: cm.targetAddr,
Header: make(Header), Header: hdr,
} }
if pa := cm.proxyAuth(); pa != "" { if pa := cm.proxyAuth(); pa != "" {
connectReq.Header.Set("Proxy-Authorization", pa) connectReq.Header.Set("Proxy-Authorization", pa)
......
...@@ -3777,6 +3777,52 @@ func testTransportIDNA(t *testing.T, h2 bool) { ...@@ -3777,6 +3777,52 @@ func testTransportIDNA(t *testing.T, h2 bool) {
} }
} }
// Issue 13290: send User-Agent in proxy CONNECT
func TestTransportProxyConnectHeader(t *testing.T) {
defer afterTest(t)
reqc := make(chan *Request, 1)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.Method != "CONNECT" {
t.Errorf("method = %q; want CONNECT", r.Method)
}
reqc <- r
c, _, err := w.(Hijacker).Hijack()
if err != nil {
t.Errorf("Hijack: %v", err)
return
}
c.Close()
}))
defer ts.Close()
tr := &Transport{
ProxyConnectHeader: Header{
"User-Agent": {"foo"},
"Other": {"bar"},
},
Proxy: func(r *Request) (*url.URL, error) {
return url.Parse(ts.URL)
},
}
defer tr.CloseIdleConnections()
c := &Client{Transport: tr}
res, err := c.Get("https://dummy.tld/") // https to force a CONNECT
if err == nil {
res.Body.Close()
t.Errorf("unexpected success")
}
select {
case <-time.After(3 * time.Second):
t.Fatal("timeout")
case r := <-reqc:
if got, want := r.Header.Get("User-Agent"), "foo"; got != want {
t.Errorf("CONNECT request User-Agent = %q; want %q", got, want)
}
if got, want := r.Header.Get("Other"), "bar"; got != want {
t.Errorf("CONNECT request Other = %q; want %q", got, want)
}
}
}
var errFakeRoundTrip = errors.New("fake roundtrip") var errFakeRoundTrip = errors.New("fake roundtrip")
type funcRoundTripper func() type funcRoundTripper func()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment