...
1
2
3
4
5
6
7 package proxy
8
9 import (
10 "errors"
11 "net"
12 "net/url"
13 "os"
14 "sync"
15 )
16
17
18
19 type Dialer interface {
20
21 Dial(network, addr string) (c net.Conn, err error)
22 }
23
24
25 type Auth struct {
26 User, Password string
27 }
28
29
30
31
32 func FromEnvironment() Dialer {
33 return FromEnvironmentUsing(Direct)
34 }
35
36
37
38
39
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
66
67 var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error)
68
69
70
71
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
80
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
102
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
122
123
124
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
146 func (e *envOnce) reset() {
147 e.once = sync.Once{}
148 e.val = ""
149 }
150
View as plain text