github.com/searKing/golang/go@v1.2.117/net/http/transport.proxy.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 "net" 9 "net/http" 10 "net/url" 11 "time" 12 13 "github.com/searKing/golang/go/net/http/httpproxy" 14 "github.com/searKing/golang/go/net/resolver" 15 ) 16 17 // RequestWithProxyTarget returns a shallow copy of r with its context changed 18 // to ctx, TargetUrl and Host inside. The provided ctx must be non-nil. 19 // proxyUrl is proxy's url, like socks5://127.0.0.1:8080 20 // proxyTarget is as like gRPC Naming for proxy service discovery, with Host in TargetUrl replaced if not empty. 21 func RequestWithProxyTarget(req *http.Request, proxy *httpproxy.Proxy) *http.Request { 22 if proxy == nil { 23 return req 24 } 25 return req.WithContext(httpproxy.WithProxy(req.Context(), proxy)) 26 } 27 28 // ProxyFuncFromContextOrEnvironment builds a proxy function from the given string, which should 29 // represent a Target that can be used as a proxy. It performs basic 30 // sanitization of the Target retrieved in context of Request, and returns any error encountered. 31 func ProxyFuncFromContextOrEnvironment(req *http.Request) (*url.URL, error) { 32 proxy := httpproxy.ContextProxy(req.Context()) 33 // load proxy from environment if proxy not set 34 if proxy == nil || proxy.ProxyUrl == "" { 35 return http.ProxyFromEnvironment(req) 36 } 37 38 proxyUrl, err := httpproxy.ParseProxyUrl(proxy.ProxyUrl) 39 if err != nil { 40 return nil, err 41 } 42 if proxyUrl == nil { 43 return nil, nil 44 } 45 46 if proxy.ProxyTarget == "" { 47 return proxyUrl, nil 48 } 49 50 // replace host of proxy if target of proxy if resolved 51 address, err := resolver.ResolveOneAddr(req.Context(), proxy.ProxyTarget) 52 if err != nil { 53 return nil, err 54 } 55 if address.Addr != "" { 56 proxyUrl.Host = address.Addr 57 } 58 proxy.ProxyAddrResolved = address 59 return proxyUrl, nil 60 } 61 62 // DefaultTransportWithDynamicProxy is the default implementation of Transport and is 63 // used by DefaultClientWithDynamicProxy. It establishes network connections as needed 64 // and caches them for reuse by subsequent calls. It uses HTTP proxies 65 // as directed by the ProxyFuncFromContextOrEnvironment, $HTTP_PROXY and $NO_PROXY (or $http_proxy and 66 // $no_proxy) environment variables. 67 var DefaultTransportWithDynamicProxy http.RoundTripper = &http.Transport{ 68 Proxy: ProxyFuncFromContextOrEnvironment, 69 DialContext: (&net.Dialer{ 70 Timeout: 30 * time.Second, 71 KeepAlive: 30 * time.Second, 72 }).DialContext, 73 ForceAttemptHTTP2: true, 74 MaxIdleConns: 100, 75 IdleConnTimeout: 90 * time.Second, 76 TLSHandshakeTimeout: 10 * time.Second, 77 ExpectContinueTimeout: 1 * time.Second, 78 } 79 80 // DefaultClientWithDynamicProxy is the default Client with DefaultTransportWithDynamicProxy. 81 var DefaultClientWithDynamicProxy = &http.Client{ 82 Transport: DefaultTransportWithDynamicProxy, 83 } 84 85 // ProxyFuncWithTargetOrDefault builds a proxy function from the given string, which should 86 // represent a Target that can be used as a proxy. It performs basic 87 // sanitization of the Target and returns any error encountered. 88 // fixedProxyUrl is proxy's url, like socks5://127.0.0.1:8080 89 // fixedProxyTarget is as like gRPC Naming for proxy service discovery, with Host in TargetUrl replaced if not empty. 90 func ProxyFuncWithTargetOrDefault(fixedProxyUrl string, fixedProxyTarget string, def func(req *http.Request) (*url.URL, error)) func(req *http.Request) (*url.URL, error) { 91 if fixedProxyUrl == "" { 92 return def 93 } 94 proxy, err := httpproxy.ParseProxyUrl(fixedProxyUrl) 95 if err != nil { 96 return func(req *http.Request) (*url.URL, error) { 97 return nil, err 98 } 99 } 100 if proxy == nil || fixedProxyTarget == "" { 101 return func(req *http.Request) (*url.URL, error) { 102 return proxy, nil 103 } 104 } 105 return func(req *http.Request) (*url.URL, error) { 106 req2 := RequestWithProxyTarget(req, &httpproxy.Proxy{ 107 ProxyUrl: fixedProxyUrl, 108 ProxyTarget: fixedProxyTarget, 109 }) 110 return ProxyFuncFromContextOrEnvironment(req2) 111 } 112 } 113 114 // TransportWithProxyTarget wraps http.RoundTripper with request url replaced by Target resolved by resolver. 115 // fixedProxyUrl is proxy's url, like socks5://127.0.0.1:8080 116 // fixedProxyTarget is as like gRPC Naming for proxy service discovery, with Host in TargetUrl replaced if not empty. 117 func TransportWithProxyTarget(t *http.Transport, fixedProxyUrl string, fixedProxyTarget string) *http.Transport { 118 t.Proxy = ProxyFuncWithTargetOrDefault(fixedProxyUrl, fixedProxyTarget, t.Proxy) 119 return t 120 }