github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/net/proxy/http/client.go (about) 1 package http 2 3 import ( 4 "bufio" 5 "context" 6 "encoding/base64" 7 "fmt" 8 "net" 9 "net/http" 10 "net/url" 11 12 "github.com/Asutorufa/yuhaiin/pkg/net/netapi" 13 "github.com/Asutorufa/yuhaiin/pkg/protos/node/point" 14 "github.com/Asutorufa/yuhaiin/pkg/protos/node/protocol" 15 ) 16 17 type client struct { 18 netapi.Proxy 19 user, password string 20 } 21 22 func init() { 23 point.RegisterProtocol(NewClient) 24 } 25 26 func NewClient(config *protocol.Protocol_Http) point.WrapProxy { 27 return func(p netapi.Proxy) (netapi.Proxy, error) { 28 return &client{ 29 Proxy: p, 30 user: config.Http.User, 31 password: config.Http.Password, 32 }, nil 33 } 34 } 35 36 func (c *client) Conn(ctx context.Context, s netapi.Address) (net.Conn, error) { 37 conn, err := c.Proxy.Conn(ctx, s) 38 if err != nil { 39 return nil, fmt.Errorf("dialer conn failed: %w", err) 40 } 41 42 req := &http.Request{ 43 Method: http.MethodConnect, 44 URL: &url.URL{}, 45 Header: make(http.Header), 46 Host: s.String(), 47 } 48 49 if c.user != "" || c.password != "" { 50 req.Header.Set("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(c.user+":"+c.password))) 51 } 52 53 err = req.Write(conn) 54 if err != nil { 55 conn.Close() 56 return nil, fmt.Errorf("write request failed: %w", err) 57 } 58 59 bufioReader := bufio.NewReader(conn) 60 resp, err := http.ReadResponse(bufioReader, req) 61 if err != nil { 62 conn.Close() 63 return nil, fmt.Errorf("read response failed: %w", err) 64 } 65 66 if resp.StatusCode != http.StatusOK { 67 conn.Close() 68 return nil, fmt.Errorf("status code not ok: %d", resp.StatusCode) 69 } 70 71 conn, err = netapi.MergeBufioReaderConn(conn, bufioReader) 72 if err != nil { 73 conn.Close() 74 return nil, fmt.Errorf("merge bufio reader conn failed: %w", err) 75 } 76 77 return &clientConn{Conn: conn, resp: resp}, nil 78 } 79 80 type clientConn struct { 81 net.Conn 82 resp *http.Response 83 } 84 85 func (c *clientConn) Close() error { 86 c.resp.Body.Close() 87 return c.Conn.Close() 88 }