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  }