]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: add Transport.ProxyConnectHeader to control headers to proxies
authorBrad Fitzpatrick <bradfitz@golang.org>
Tue, 1 Nov 2016 17:12:48 +0000 (17:12 +0000)
committerBrad Fitzpatrick <bradfitz@golang.org>
Tue, 1 Nov 2016 17:45:35 +0000 (17:45 +0000)
Fixes #13290

Change-Id: I0f7e7683d86db501cbedb6a0b7349ceb0769701c
Reviewed-on: https://go-review.googlesource.com/32481
Reviewed-by: Martin Möhrmann <martisch@uos.de>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/net/http/transport.go
src/net/http/transport_test.go

index e227b3764a3a378fe7ae818939ce53cd1285766c..de666fb55480bd54915949305e462c215ffce92f 100644 (file)
@@ -175,6 +175,10 @@ type Transport struct {
        // If TLSNextProto is nil, HTTP/2 support is enabled automatically.
        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
        // response bytes are allowed in the server's response
        // header.
@@ -1012,11 +1016,15 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon
                }
        case cm.targetScheme == "https":
                conn := pconn.conn
+               hdr := t.ProxyConnectHeader
+               if hdr == nil {
+                       hdr = make(Header)
+               }
                connectReq := &Request{
                        Method: "CONNECT",
                        URL:    &url.URL{Opaque: cm.targetAddr},
                        Host:   cm.targetAddr,
-                       Header: make(Header),
+                       Header: hdr,
                }
                if pa := cm.proxyAuth(); pa != "" {
                        connectReq.Header.Set("Proxy-Authorization", pa)
index a5c86989d1c8da639fb6d19810ecbde83594632b..cf01e29c850bd81da5ec91f9d697a8aac71d1f1c 100644 (file)
@@ -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")
 
 type funcRoundTripper func()