github.com/searKing/golang/go@v1.2.117/net/http/client.go (about) 1 // Copyright 2022 The searKing Author. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package http 6 7 import ( 8 "context" 9 "io" 10 "net" 11 "net/http" 12 "net/url" 13 "strings" 14 15 "github.com/searKing/golang/go/net/http/httphost" 16 "github.com/searKing/golang/go/net/http/httpproxy" 17 ) 18 19 type Client struct { 20 http.Client 21 22 Proxy *httpproxy.Proxy 23 Host *httphost.Host 24 } 25 26 // Use adds middleware handlers to the transport. 27 func (c *Client) Use(d ...RoundTripDecorator) *Client { 28 if len(d) == 0 { 29 return c 30 } 31 var rts RoundTripDecorators 32 rts = append(rts, d...) 33 c.Transport = rts.WrapRoundTrip(c.Transport) 34 // for chained call 35 return c 36 } 37 38 // parseURL is just url.Parse. It exists only so that url.Parse can be called 39 // in places where url is shadowed for godoc. See https://golang.org/cl/49930. 40 var parseURL = url.Parse 41 42 // NewClient returns a http client wrapper behaves like http.Client, 43 // sends HTTP Request to target by proxy url with Host replaced by proxyTarget 44 // 45 // u is the original url to send HTTP request, empty usually. 46 // target is the resolver to resolve Host to send HTTP request, 47 // that is replacing host in url(NOT HOST in http header) by address resolved by Host 48 // fixedProxyUrl is proxy's url, like socks5://127.0.0.1:8080 49 // fixedProxyTarget is as like gRPC Naming for proxy service discovery, with Host in TargetUrl replaced if not empty. 50 func NewClient(u, hostTarget string, proxyUrl string, proxyTarget string) (*Client, error) { 51 tr := DefaultTransportWithDynamicHostAndProxy 52 if len(u) > 0 { 53 urlParsed, err := parseURL(u) 54 if err != nil { 55 return nil, err 56 } 57 hostname := urlParsed.Hostname() 58 if strings.Index(hostname, "unix:") == 0 { 59 tr = &http.Transport{ 60 DisableCompression: true, 61 DialContext: func(ctx context.Context, network, addr string) (conn net.Conn, e error) { 62 return net.Dial("unix", urlParsed.Host) 63 }, 64 } 65 } 66 } 67 client := http.Client{Transport: tr} 68 c := &Client{ 69 Client: client, 70 } 71 if hostTarget != "" { 72 c.Host = &httphost.Host{ 73 HostTarget: hostTarget, 74 ReplaceHostInRequest: false, 75 } 76 } 77 if proxyUrl != "" { 78 c.Proxy = &httpproxy.Proxy{ 79 ProxyUrl: proxyUrl, 80 ProxyTarget: proxyTarget, 81 } 82 } 83 return c, nil 84 } 85 86 // NewClientWithTarget returns a Client with http.Client and host replaced by resolver.Host 87 // target is the resolver to resolve Host to send HTTP request, 88 // that is replacing host in url(NOT HOST in http header) by address resolved by Host 89 func NewClientWithTarget(target string) *Client { 90 cli, _ := NewClient("", target, "", "") 91 return cli 92 } 93 94 // NewClientWithProxy returns a Client with http.Client with proxy set by resolver.Host 95 // TargetUrl is proxy's url, like socks5://127.0.0.1:8080 96 // Host is proxy's addr, replace the HOST in TargetUrl if not empty 97 func NewClientWithProxy(proxyUrl string, proxyTarget string) *Client { 98 cli, _ := NewClient("", "", proxyUrl, proxyTarget) 99 return cli 100 } 101 102 func NewClientWithUnixDisableCompression(u string) (*Client, error) { 103 return NewClient(u, "", "", "") 104 } 105 106 func (c *Client) Do(req *http.Request) (_ *http.Response, err error) { 107 return c.Client.Do(RequestWithHostTarget(RequestWithProxyTarget(req, c.Proxy), c.Host)) 108 } 109 110 func (c *Client) Head(url string) (resp *http.Response, err error) { 111 req, err := http.NewRequest(http.MethodHead, url, nil) 112 if err != nil { 113 return nil, err 114 } 115 return c.Do(req) 116 } 117 118 func (c *Client) Get(url string) (resp *http.Response, err error) { 119 req, err := http.NewRequest(http.MethodGet, url, nil) 120 if err != nil { 121 return nil, err 122 } 123 return c.Do(req) 124 } 125 126 func (c *Client) Post(url string, contentType string, body io.Reader) (resp *http.Response, err error) { 127 req, err := http.NewRequest(http.MethodPost, url, body) 128 if err != nil { 129 return nil, err 130 } 131 req.Header.Set("Content-Type", contentType) 132 return c.Do(req) 133 } 134 135 func (c *Client) PostForm(url string, data url.Values) (resp *http.Response, err error) { 136 return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) 137 } 138 139 func Head(url string) (resp *http.Response, err error) { 140 client, err := NewClientWithUnixDisableCompression(url) 141 if err != nil { 142 return nil, err 143 } 144 return client.Head(url) 145 146 } 147 148 func Get(url string) (resp *http.Response, err error) { 149 client, err := NewClientWithUnixDisableCompression(url) 150 if err != nil { 151 return nil, err 152 } 153 return client.Get(url) 154 } 155 156 func Post(url, contentType string, body io.Reader) (resp *http.Response, err error) { 157 client, err := NewClientWithUnixDisableCompression(url) 158 if err != nil { 159 return nil, err 160 } 161 return client.Post(url, contentType, body) 162 } 163 164 func PostForm(url string, data url.Values) (resp *http.Response, err error) { 165 client, err := NewClientWithUnixDisableCompression(url) 166 if err != nil { 167 return nil, err 168 } 169 return client.PostForm(url, data) 170 }