OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / net / proxy / proxy.go
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 type Dialer interface {
19         // Dial connects to the given address via the proxy.
20         Dial(network, addr string) (c net.Conn, err error)
21 }
22
23 // Auth contains authentication parameters that specific Dialers may require.
24 type Auth struct {
25         User, Password string
26 }
27
28 // FromEnvironment returns the dialer specified by the proxy related variables in
29 // the environment.
30 func FromEnvironment() Dialer {
31         allProxy := allProxyEnv.Get()
32         if len(allProxy) == 0 {
33                 return Direct
34         }
35
36         proxyURL, err := url.Parse(allProxy)
37         if err != nil {
38                 return Direct
39         }
40         proxy, err := FromURL(proxyURL, Direct)
41         if err != nil {
42                 return Direct
43         }
44
45         noProxy := noProxyEnv.Get()
46         if len(noProxy) == 0 {
47                 return proxy
48         }
49
50         perHost := NewPerHost(proxy, Direct)
51         perHost.AddFromString(noProxy)
52         return perHost
53 }
54
55 // proxySchemes is a map from URL schemes to a function that creates a Dialer
56 // from a URL with such a scheme.
57 var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error)
58
59 // RegisterDialerType takes a URL scheme and a function to generate Dialers from
60 // a URL with that scheme and a forwarding Dialer. Registered schemes are used
61 // by FromURL.
62 func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) {
63         if proxySchemes == nil {
64                 proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error))
65         }
66         proxySchemes[scheme] = f
67 }
68
69 // FromURL returns a Dialer given a URL specification and an underlying
70 // Dialer for it to make network requests.
71 func FromURL(u *url.URL, forward Dialer) (Dialer, error) {
72         var auth *Auth
73         if u.User != nil {
74                 auth = new(Auth)
75                 auth.User = u.User.Username()
76                 if p, ok := u.User.Password(); ok {
77                         auth.Password = p
78                 }
79         }
80
81         switch u.Scheme {
82         case "socks5":
83                 return SOCKS5("tcp", u.Host, auth, forward)
84         }
85
86         // If the scheme doesn't match any of the built-in schemes, see if it
87         // was registered by another package.
88         if proxySchemes != nil {
89                 if f, ok := proxySchemes[u.Scheme]; ok {
90                         return f(u, forward)
91                 }
92         }
93
94         return nil, errors.New("proxy: unknown scheme: " + u.Scheme)
95 }
96
97 var (
98         allProxyEnv = &envOnce{
99                 names: []string{"ALL_PROXY", "all_proxy"},
100         }
101         noProxyEnv = &envOnce{
102                 names: []string{"NO_PROXY", "no_proxy"},
103         }
104 )
105
106 // envOnce looks up an environment variable (optionally by multiple
107 // names) once. It mitigates expensive lookups on some platforms
108 // (e.g. Windows).
109 // (Borrowed from net/http/transport.go)
110 type envOnce struct {
111         names []string
112         once  sync.Once
113         val   string
114 }
115
116 func (e *envOnce) Get() string {
117         e.once.Do(e.init)
118         return e.val
119 }
120
121 func (e *envOnce) init() {
122         for _, n := range e.names {
123                 e.val = os.Getenv(n)
124                 if e.val != "" {
125                         return
126                 }
127         }
128 }
129
130 // reset is used by tests
131 func (e *envOnce) reset() {
132         e.once = sync.Once{}
133         e.val = ""
134 }