github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/net/proxy/proxy.go (about) 1 // Copyright 2011 The Go Authors. 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 proxy provides support for a variety of protocols to proxy network 6 // data. 7 package proxy // import "github.com/hxx258456/ccgo/net/proxy" 8 9 import ( 10 "errors" 11 "net" 12 "net/url" 13 "os" 14 "sync" 15 ) 16 17 // A Dialer is a means to establish a connection. 18 // Custom dialers should also implement ContextDialer. 19 type Dialer interface { 20 // Dial connects to the given address via the proxy. 21 Dial(network, addr string) (c net.Conn, err error) 22 } 23 24 // Auth contains authentication parameters that specific Dialers may require. 25 type Auth struct { 26 User, Password string 27 } 28 29 // FromEnvironment returns the dialer specified by the proxy-related 30 // variables in the environment and makes underlying connections 31 // directly. 32 func FromEnvironment() Dialer { 33 return FromEnvironmentUsing(Direct) 34 } 35 36 // FromEnvironmentUsing returns the dialer specify by the proxy-related 37 // variables in the environment and makes underlying connections 38 // using the provided forwarding Dialer (for instance, a *net.Dialer 39 // with desired configuration). 40 func FromEnvironmentUsing(forward Dialer) Dialer { 41 allProxy := allProxyEnv.Get() 42 if len(allProxy) == 0 { 43 return forward 44 } 45 46 proxyURL, err := url.Parse(allProxy) 47 if err != nil { 48 return forward 49 } 50 proxy, err := FromURL(proxyURL, forward) 51 if err != nil { 52 return forward 53 } 54 55 noProxy := noProxyEnv.Get() 56 if len(noProxy) == 0 { 57 return proxy 58 } 59 60 perHost := NewPerHost(proxy, forward) 61 perHost.AddFromString(noProxy) 62 return perHost 63 } 64 65 // proxySchemes is a map from URL schemes to a function that creates a Dialer 66 // from a URL with such a scheme. 67 var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error) 68 69 // RegisterDialerType takes a URL scheme and a function to generate Dialers from 70 // a URL with that scheme and a forwarding Dialer. Registered schemes are used 71 // by FromURL. 72 func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) { 73 if proxySchemes == nil { 74 proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error)) 75 } 76 proxySchemes[scheme] = f 77 } 78 79 // FromURL returns a Dialer given a URL specification and an underlying 80 // Dialer for it to make network requests. 81 func FromURL(u *url.URL, forward Dialer) (Dialer, error) { 82 var auth *Auth 83 if u.User != nil { 84 auth = new(Auth) 85 auth.User = u.User.Username() 86 if p, ok := u.User.Password(); ok { 87 auth.Password = p 88 } 89 } 90 91 switch u.Scheme { 92 case "socks5", "socks5h": 93 addr := u.Hostname() 94 port := u.Port() 95 if port == "" { 96 port = "1080" 97 } 98 return SOCKS5("tcp", net.JoinHostPort(addr, port), auth, forward) 99 } 100 101 // If the scheme doesn't match any of the built-in schemes, see if it 102 // was registered by another package. 103 if proxySchemes != nil { 104 if f, ok := proxySchemes[u.Scheme]; ok { 105 return f(u, forward) 106 } 107 } 108 109 return nil, errors.New("proxy: unknown scheme: " + u.Scheme) 110 } 111 112 var ( 113 allProxyEnv = &envOnce{ 114 names: []string{"ALL_PROXY", "all_proxy"}, 115 } 116 noProxyEnv = &envOnce{ 117 names: []string{"NO_PROXY", "no_proxy"}, 118 } 119 ) 120 121 // envOnce looks up an environment variable (optionally by multiple 122 // names) once. It mitigates expensive lookups on some platforms 123 // (e.g. Windows). 124 // (Borrowed from net/http/transport.go) 125 type envOnce struct { 126 names []string 127 once sync.Once 128 val string 129 } 130 131 func (e *envOnce) Get() string { 132 e.once.Do(e.init) 133 return e.val 134 } 135 136 func (e *envOnce) init() { 137 for _, n := range e.names { 138 e.val = os.Getenv(n) 139 if e.val != "" { 140 return 141 } 142 } 143 } 144 145 // reset is used by tests 146 func (e *envOnce) reset() { 147 e.once = sync.Once{} 148 e.val = "" 149 }