commit
29ef3676b2
109
transport/http_proxy.go
Normal file
109
transport/http_proxy.go
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package transport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
proxyAuthHeader = "Proxy-Authorization"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getURL(addr string) (*url.URL, error) {
|
||||||
|
r := &http.Request{
|
||||||
|
URL: &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: addr,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return http.ProxyFromEnvironment(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
type pbuffer struct {
|
||||||
|
net.Conn
|
||||||
|
r io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pbuffer) Read(b []byte) (int, error) {
|
||||||
|
return p.r.Read(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func proxyDial(conn net.Conn, addr string, proxyURL *url.URL) (_ net.Conn, err error) {
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
r := &http.Request{
|
||||||
|
Method: http.MethodConnect,
|
||||||
|
URL: &url.URL{Host: addr},
|
||||||
|
Header: map[string][]string{"User-Agent": {"micro/latest"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
if user := proxyURL.User; user != nil {
|
||||||
|
u := user.Username()
|
||||||
|
p, _ := user.Password()
|
||||||
|
auth := []byte(u + ":" + p)
|
||||||
|
basicAuth := base64.StdEncoding.EncodeToString(auth)
|
||||||
|
r.Header.Add(proxyAuthHeader, "Basic "+basicAuth)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.Write(conn); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to write the HTTP request: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
br := bufio.NewReader(conn)
|
||||||
|
rsp, err := http.ReadResponse(br, r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("reading server HTTP response: %v", err)
|
||||||
|
}
|
||||||
|
defer rsp.Body.Close()
|
||||||
|
if rsp.StatusCode != http.StatusOK {
|
||||||
|
dump, err := httputil.DumpResponse(rsp, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to do connect handshake, status code: %s", rsp.Status)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("failed to do connect handshake, response: %q", dump)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pbuffer{Conn: conn, r: br}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new connection
|
||||||
|
func newConn(dial func(string) (net.Conn, error)) func(string) (net.Conn, error) {
|
||||||
|
return func(addr string) (net.Conn, error) {
|
||||||
|
// get the proxy url
|
||||||
|
proxyURL, err := getURL(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// set to addr
|
||||||
|
callAddr := addr
|
||||||
|
|
||||||
|
// got proxy
|
||||||
|
if proxyURL != nil {
|
||||||
|
callAddr = proxyURL.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
// dial the addr
|
||||||
|
c, err := dial(callAddr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// do proxy connect if we have proxy url
|
||||||
|
if proxyURL != nil {
|
||||||
|
c, err = proxyDial(c, addr, proxyURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
}
|
@ -452,9 +452,13 @@ func (h *httpTransport) Dial(addr string, opts ...DialOption) (Client, error) {
|
|||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conn, err = tls.DialWithDialer(&net.Dialer{Timeout: dopts.Timeout}, "tcp", addr, config)
|
conn, err = newConn(func(addr string) (net.Conn, error) {
|
||||||
|
return tls.DialWithDialer(&net.Dialer{Timeout: dopts.Timeout}, "tcp", addr, config)
|
||||||
|
})(addr)
|
||||||
} else {
|
} else {
|
||||||
conn, err = net.DialTimeout("tcp", addr, dopts.Timeout)
|
conn, err = newConn(func(addr string) (net.Conn, error) {
|
||||||
|
return net.DialTimeout("tcp", addr, dopts.Timeout)
|
||||||
|
})(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user