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 "golang.org/x/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 }
150