~juju-qa/ubuntu/xenial/juju/xenial-2.0-beta3

« back to all changes in this revision

Viewing changes to src/github.com/lxc/lxd/shared/proxy.go

  • Committer: Martin Packman
  • Date: 2016-03-30 19:31:08 UTC
  • mfrom: (1.1.41)
  • Revision ID: martin.packman@canonical.com-20160330193108-h9iz3ak334uk0z5r
Merge new upstream source 2.0~beta3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package shared
 
2
 
 
3
import (
 
4
        "fmt"
 
5
        "net"
 
6
        "net/http"
 
7
        "net/url"
 
8
        "os"
 
9
        "strings"
 
10
        "sync"
 
11
)
 
12
 
 
13
var (
 
14
        httpProxyEnv = &envOnce{
 
15
                names: []string{"HTTP_PROXY", "http_proxy"},
 
16
        }
 
17
        httpsProxyEnv = &envOnce{
 
18
                names: []string{"HTTPS_PROXY", "https_proxy"},
 
19
        }
 
20
        noProxyEnv = &envOnce{
 
21
                names: []string{"NO_PROXY", "no_proxy"},
 
22
        }
 
23
)
 
24
 
 
25
type envOnce struct {
 
26
        names []string
 
27
        once  sync.Once
 
28
        val   string
 
29
}
 
30
 
 
31
func (e *envOnce) Get() string {
 
32
        e.once.Do(e.init)
 
33
        return e.val
 
34
}
 
35
 
 
36
func (e *envOnce) init() {
 
37
        for _, n := range e.names {
 
38
                e.val = os.Getenv(n)
 
39
                if e.val != "" {
 
40
                        return
 
41
                }
 
42
        }
 
43
}
 
44
 
 
45
// This is basically the same as golang's ProxyFromEnvironment, except it
 
46
// doesn't fall back to http_proxy when https_proxy isn't around, which is
 
47
// incorrect behavior. It still respects HTTP_PROXY, HTTPS_PROXY, and NO_PROXY.
 
48
func ProxyFromEnvironment(req *http.Request) (*url.URL, error) {
 
49
        return ProxyFromConfig("", "", "")(req)
 
50
}
 
51
 
 
52
func ProxyFromConfig(httpsProxy string, httpProxy string, noProxy string) func(req *http.Request) (*url.URL, error) {
 
53
        return func(req *http.Request) (*url.URL, error) {
 
54
                var proxy, port string
 
55
                var err error
 
56
 
 
57
                switch req.URL.Scheme {
 
58
                case "https":
 
59
                        proxy = httpsProxy
 
60
                        if proxy == "" {
 
61
                                proxy = httpsProxyEnv.Get()
 
62
                        }
 
63
                        port = ":443"
 
64
                case "http":
 
65
                        proxy = httpProxy
 
66
                        if proxy == "" {
 
67
                                proxy = httpProxyEnv.Get()
 
68
                        }
 
69
                        port = ":80"
 
70
                default:
 
71
                        return nil, fmt.Errorf("unknown scheme %s", req.URL.Scheme)
 
72
                }
 
73
 
 
74
                if proxy == "" {
 
75
                        return nil, nil
 
76
                }
 
77
 
 
78
                addr := req.URL.Host
 
79
                if !hasPort(addr) {
 
80
                        addr = addr + port
 
81
                }
 
82
 
 
83
                use, err := useProxy(addr, noProxy)
 
84
                if err != nil {
 
85
                        return nil, err
 
86
                }
 
87
                if !use {
 
88
                        return nil, nil
 
89
                }
 
90
 
 
91
                proxyURL, err := url.Parse(proxy)
 
92
                if err != nil || !strings.HasPrefix(proxyURL.Scheme, "http") {
 
93
                        // proxy was bogus. Try prepending "http://" to it and
 
94
                        // see if that parses correctly. If not, we fall
 
95
                        // through and complain about the original one.
 
96
                        if proxyURL, err := url.Parse("http://" + proxy); err == nil {
 
97
                                return proxyURL, nil
 
98
                        }
 
99
                }
 
100
                if err != nil {
 
101
                        return nil, fmt.Errorf("invalid proxy address %q: %v", proxy, err)
 
102
                }
 
103
                return proxyURL, nil
 
104
        }
 
105
}
 
106
 
 
107
func hasPort(s string) bool {
 
108
        return strings.LastIndex(s, ":") > strings.LastIndex(s, "]")
 
109
}
 
110
 
 
111
func useProxy(addr string, noProxy string) (bool, error) {
 
112
        if noProxy == "" {
 
113
                noProxy = noProxyEnv.Get()
 
114
        }
 
115
 
 
116
        if len(addr) == 0 {
 
117
                return true, nil
 
118
        }
 
119
        host, _, err := net.SplitHostPort(addr)
 
120
        if err != nil {
 
121
                return false, nil
 
122
        }
 
123
        if host == "localhost" {
 
124
                return false, nil
 
125
        }
 
126
        if ip := net.ParseIP(host); ip != nil {
 
127
                if ip.IsLoopback() {
 
128
                        return false, nil
 
129
                }
 
130
        }
 
131
 
 
132
        if noProxy == "*" {
 
133
                return false, nil
 
134
        }
 
135
 
 
136
        addr = strings.ToLower(strings.TrimSpace(addr))
 
137
        if hasPort(addr) {
 
138
                addr = addr[:strings.LastIndex(addr, ":")]
 
139
        }
 
140
 
 
141
        for _, p := range strings.Split(noProxy, ",") {
 
142
                p = strings.ToLower(strings.TrimSpace(p))
 
143
                if len(p) == 0 {
 
144
                        continue
 
145
                }
 
146
                if hasPort(p) {
 
147
                        p = p[:strings.LastIndex(p, ":")]
 
148
                }
 
149
                if addr == p {
 
150
                        return false, nil
 
151
                }
 
152
                if p[0] == '.' && (strings.HasSuffix(addr, p) || addr == p[1:]) {
 
153
                        // noProxy ".foo.com" matches "bar.foo.com" or "foo.com"
 
154
                        return false, nil
 
155
                }
 
156
                if p[0] != '.' && strings.HasSuffix(addr, p) && addr[len(addr)-len(p)-1] == '.' {
 
157
                        // noProxy "foo.com" matches "bar.foo.com"
 
158
                        return false, nil
 
159
                }
 
160
        }
 
161
        return true, nil
 
162
}