11package api
22
33import (
4- "bufio"
54 "context"
65 "crypto/tls"
7- "encoding/base64"
8- "fmt"
96 "net"
107 "net/http"
118 "net/url"
@@ -15,22 +12,22 @@ import (
1512//
1613// Note: baseTransport is considered to be a clone created with transport.Clone()
1714//
18- // - If a the proxyPath is not empty, a unix socket proxy is created.
19- // - Otherwise, the proxyURL is used to determine if we should proxy socks5 / http connections
15+ // - If proxyPath is not empty, a unix socket proxy is created.
16+ // - Otherwise, proxyURL is used to determine if we should proxy socks5 / http connections
2017func withProxyTransport (baseTransport * http.Transport , proxyURL * url.URL , proxyPath string ) * http.Transport {
2118 handshakeTLS := func (ctx context.Context , conn net.Conn , addr string ) (net.Conn , error ) {
2219 // Extract the hostname (without the port) for TLS SNI
2320 host , _ , err := net .SplitHostPort (addr )
2421 if err != nil {
2522 return nil , err
2623 }
27- tlsConn := tls .Client (conn , & tls.Config {
28- ServerName : host ,
29- // Pull InsecureSkipVerify from the target host transport
30- // so that insecure-skip-verify flag settings are honored for the proxy server
31- InsecureSkipVerify : baseTransport .TLSClientConfig .InsecureSkipVerify ,
32- })
24+ cfg := baseTransport .TLSClientConfig .Clone ()
25+ if cfg .ServerName == "" {
26+ cfg .ServerName = host
27+ }
28+ tlsConn := tls .Client (conn , cfg )
3329 if err := tlsConn .HandshakeContext (ctx ); err != nil {
30+ tlsConn .Close ()
3431 return nil , err
3532 }
3633 return tlsConn , nil
@@ -53,82 +50,7 @@ func withProxyTransport(baseTransport *http.Transport, proxyURL *url.URL, proxyP
5350 // clear out any system proxy settings
5451 baseTransport .Proxy = nil
5552 } else if proxyURL != nil {
56- switch proxyURL .Scheme {
57- case "socks5" , "socks5h" :
58- // SOCKS proxies work out of the box - no need to manually dial
59- baseTransport .Proxy = http .ProxyURL (proxyURL )
60- case "http" , "https" :
61- dial := func (ctx context.Context , network , addr string ) (net.Conn , error ) {
62- // Dial the proxy
63- d := net.Dialer {}
64- conn , err := d .DialContext (ctx , "tcp" , proxyURL .Host )
65- if err != nil {
66- return nil , err
67- }
68-
69- // this is the whole point of manually dialing the HTTP(S) proxy:
70- // being able to force HTTP/1.
71- // When relying on Transport.Proxy, the protocol is always HTTP/2,
72- // but many proxy servers don't support HTTP/2.
73- // We don't want to disable HTTP/2 in general because we want to use it when
74- // connecting to the Sourcegraph API, using HTTP/1 for the proxy connection only.
75- protocol := "HTTP/1.1"
76-
77- // CONNECT is the HTTP method used to set up a tunneling connection with a proxy
78- method := "CONNECT"
79-
80- // Manually writing out the HTTP commands because it's not complicated,
81- // and http.Request has some janky behavior:
82- // - ignores the Proto field and hard-codes the protocol to HTTP/1.1
83- // - ignores the Host Header (Header.Set("Host", host)) and uses URL.Host instead.
84- // - When the Host field is set, overrides the URL field
85- connectReq := fmt .Sprintf ("%s %s %s\r \n " , method , addr , protocol )
86-
87- // A Host header is required per RFC 2616, section 14.23
88- connectReq += fmt .Sprintf ("Host: %s\r \n " , addr )
89-
90- // use authentication if proxy credentials are present
91- if proxyURL .User != nil {
92- password , _ := proxyURL .User .Password ()
93- auth := base64 .StdEncoding .EncodeToString ([]byte (proxyURL .User .Username () + ":" + password ))
94- connectReq += fmt .Sprintf ("Proxy-Authorization: Basic %s\r \n " , auth )
95- }
96-
97- // finish up with an extra carriage return + newline, as per RFC 7230, section 3
98- connectReq += "\r \n "
99-
100- // Send the CONNECT request to the proxy to establish the tunnel
101- if _ , err := conn .Write ([]byte (connectReq )); err != nil {
102- conn .Close ()
103- return nil , err
104- }
105-
106- // Read and check the response from the proxy
107- resp , err := http .ReadResponse (bufio .NewReader (conn ), nil )
108- if err != nil {
109- conn .Close ()
110- return nil , err
111- }
112- if resp .StatusCode != http .StatusOK {
113- conn .Close ()
114- return nil , fmt .Errorf ("failed to connect to proxy %v: %v" , proxyURL , resp .Status )
115- }
116- resp .Body .Close ()
117- return conn , nil
118- }
119- dialTLS := func (ctx context.Context , network , addr string ) (net.Conn , error ) {
120- // Dial the underlying connection through the proxy
121- conn , err := dial (ctx , network , addr )
122- if err != nil {
123- return nil , err
124- }
125- return handshakeTLS (ctx , conn , addr )
126- }
127- baseTransport .DialContext = dial
128- baseTransport .DialTLSContext = dialTLS
129- // clear out any system proxy settings
130- baseTransport .Proxy = nil
131- }
53+ baseTransport .Proxy = http .ProxyURL (proxyURL )
13254 }
13355
13456 return baseTransport
0 commit comments