gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/transport/http_proxy.go (about) 1 package transport 2 3 import ( 4 "bufio" 5 "encoding/base64" 6 "fmt" 7 "io" 8 "net" 9 "net/http" 10 "net/http/httputil" 11 "net/url" 12 ) 13 14 const ( 15 proxyAuthHeader = "Proxy-Authorization" 16 ) 17 18 func getURL(addr string) (*url.URL, error) { 19 r := &http.Request{ 20 URL: &url.URL{ 21 Scheme: "https", 22 Host: addr, 23 }, 24 } 25 return http.ProxyFromEnvironment(r) 26 } 27 28 type pbuffer struct { 29 net.Conn 30 r io.Reader 31 } 32 33 func (p *pbuffer) Read(b []byte) (int, error) { 34 return p.r.Read(b) 35 } 36 37 func proxyDial(conn net.Conn, addr string, proxyURL *url.URL) (_ net.Conn, err error) { 38 defer func() { 39 if err != nil { 40 conn.Close() 41 } 42 }() 43 44 r := &http.Request{ 45 Method: http.MethodConnect, 46 URL: &url.URL{Host: addr}, 47 Header: map[string][]string{"User-Agent": {"micro/latest"}}, 48 } 49 50 if user := proxyURL.User; user != nil { 51 u := user.Username() 52 p, _ := user.Password() 53 auth := []byte(u + ":" + p) 54 basicAuth := base64.StdEncoding.EncodeToString(auth) 55 r.Header.Add(proxyAuthHeader, "Basic "+basicAuth) 56 } 57 58 if err := r.Write(conn); err != nil { 59 return nil, fmt.Errorf("failed to write the HTTP request: %v", err) 60 } 61 62 br := bufio.NewReader(conn) 63 rsp, err := http.ReadResponse(br, r) 64 if err != nil { 65 return nil, fmt.Errorf("reading server HTTP response: %v", err) 66 } 67 defer rsp.Body.Close() 68 if rsp.StatusCode != http.StatusOK { 69 dump, err := httputil.DumpResponse(rsp, true) 70 if err != nil { 71 return nil, fmt.Errorf("failed to do connect handshake, status code: %s", rsp.Status) 72 } 73 return nil, fmt.Errorf("failed to do connect handshake, response: %q", dump) 74 } 75 76 return &pbuffer{Conn: conn, r: br}, nil 77 } 78 79 // Creates a new connection 80 func newConn(dial func(string) (net.Conn, error)) func(string) (net.Conn, error) { 81 return func(addr string) (net.Conn, error) { 82 // get the proxy url 83 proxyURL, err := getURL(addr) 84 if err != nil { 85 return nil, err 86 } 87 88 // set to addr 89 callAddr := addr 90 91 // got proxy 92 if proxyURL != nil { 93 callAddr = proxyURL.Host 94 } 95 96 // dial the addr 97 c, err := dial(callAddr) 98 if err != nil { 99 return nil, err 100 } 101 102 // do proxy connect if we have proxy url 103 if proxyURL != nil { 104 c, err = proxyDial(c, addr, proxyURL) 105 } 106 107 return c, err 108 } 109 }