1
2
3
4
5 package httpproxy_test
6
7 import (
8 "bytes"
9 "errors"
10 "fmt"
11 "net/url"
12 "os"
13 "strings"
14 "testing"
15
16 "golang.org/x/net/http/httpproxy"
17 )
18
19
20 var setHelper = func(t *testing.T) {}
21
22 type proxyForURLTest struct {
23 cfg httpproxy.Config
24 req string
25 want string
26 wanterr error
27 }
28
29 func (t proxyForURLTest) String() string {
30 var buf bytes.Buffer
31 space := func() {
32 if buf.Len() > 0 {
33 buf.WriteByte(' ')
34 }
35 }
36 if t.cfg.HTTPProxy != "" {
37 fmt.Fprintf(&buf, "http_proxy=%q", t.cfg.HTTPProxy)
38 }
39 if t.cfg.HTTPSProxy != "" {
40 space()
41 fmt.Fprintf(&buf, "https_proxy=%q", t.cfg.HTTPSProxy)
42 }
43 if t.cfg.NoProxy != "" {
44 space()
45 fmt.Fprintf(&buf, "no_proxy=%q", t.cfg.NoProxy)
46 }
47 req := "http://example.com"
48 if t.req != "" {
49 req = t.req
50 }
51 space()
52 fmt.Fprintf(&buf, "req=%q", req)
53 return strings.TrimSpace(buf.String())
54 }
55
56 var proxyForURLTests = []proxyForURLTest{{
57 cfg: httpproxy.Config{
58 HTTPProxy: "127.0.0.1:8080",
59 },
60 want: "http://127.0.0.1:8080",
61 }, {
62 cfg: httpproxy.Config{
63 HTTPProxy: "cache.corp.example.com:1234",
64 },
65 want: "http://cache.corp.example.com:1234",
66 }, {
67 cfg: httpproxy.Config{
68 HTTPProxy: "cache.corp.example.com",
69 },
70 want: "http://cache.corp.example.com",
71 }, {
72 cfg: httpproxy.Config{
73 HTTPProxy: "https://cache.corp.example.com",
74 },
75 want: "https://cache.corp.example.com",
76 }, {
77 cfg: httpproxy.Config{
78 HTTPProxy: "http://127.0.0.1:8080",
79 },
80 want: "http://127.0.0.1:8080",
81 }, {
82 cfg: httpproxy.Config{
83 HTTPProxy: "https://127.0.0.1:8080",
84 },
85 want: "https://127.0.0.1:8080",
86 }, {
87 cfg: httpproxy.Config{
88 HTTPProxy: "socks5://127.0.0.1",
89 },
90 want: "socks5://127.0.0.1",
91 }, {
92
93 cfg: httpproxy.Config{
94 HTTPProxy: "http.proxy.tld",
95 HTTPSProxy: "secure.proxy.tld",
96 },
97 req: "http://insecure.tld/",
98 want: "http://http.proxy.tld",
99 }, {
100
101 cfg: httpproxy.Config{
102 HTTPProxy: "http.proxy.tld",
103 HTTPSProxy: "secure.proxy.tld",
104 },
105 req: "https://secure.tld/",
106 want: "http://secure.proxy.tld",
107 }, {
108 cfg: httpproxy.Config{
109 HTTPProxy: "http.proxy.tld",
110 HTTPSProxy: "https://secure.proxy.tld",
111 },
112 req: "https://secure.tld/",
113 want: "https://secure.proxy.tld",
114 }, {
115 cfg: httpproxy.Config{
116 HTTPProxy: "http.proxy.tld",
117 },
118 req: "https://secure.tld/",
119 want: "<nil>",
120 }, {
121 cfg: httpproxy.Config{
122 HTTPProxy: "http.proxy.tld",
123 },
124 req: "ftp://insecure.tld/",
125 want: "<nil>",
126 }, {
127
128
129 cfg: httpproxy.Config{
130 HTTPProxy: "http://10.1.2.3:8080",
131 CGI: true,
132 },
133 want: "<nil>",
134 wanterr: errors.New("refusing to use HTTP_PROXY value in CGI environment; see golang.org/s/cgihttpproxy"),
135 }, {
136
137
138 cfg: httpproxy.Config{
139 HTTPSProxy: "https://secure.proxy.tld",
140 CGI: true,
141 },
142 req: "https://secure.tld/",
143 want: "https://secure.proxy.tld",
144 }, {
145 want: "<nil>",
146 }, {
147 cfg: httpproxy.Config{
148 NoProxy: "example.com",
149 HTTPProxy: "proxy",
150 },
151 req: "http://example.com/",
152 want: "<nil>",
153 }, {
154 cfg: httpproxy.Config{
155 NoProxy: ".example.com",
156 HTTPProxy: "proxy",
157 },
158 req: "http://example.com/",
159 want: "http://proxy",
160 }, {
161 cfg: httpproxy.Config{
162 NoProxy: "ample.com",
163 HTTPProxy: "proxy",
164 },
165 req: "http://example.com/",
166 want: "http://proxy",
167 }, {
168 cfg: httpproxy.Config{
169 NoProxy: "example.com",
170 HTTPProxy: "proxy",
171 },
172 req: "http://foo.example.com/",
173 want: "<nil>",
174 }, {
175 cfg: httpproxy.Config{
176 NoProxy: ".foo.com",
177 HTTPProxy: "proxy",
178 },
179 req: "http://example.com/",
180 want: "http://proxy",
181 }, {
182 cfg: httpproxy.Config{
183 NoProxy: ".示例.com",
184 HTTPProxy: "proxy",
185 },
186 req: "http://www.示例.com",
187 want: "<nil>",
188 }, {
189 cfg: httpproxy.Config{
190 NoProxy: "xn--fsq092h.com",
191 HTTPProxy: "proxy",
192 },
193 req: "http://www.示例.com",
194 want: "<nil>",
195 }, {
196 cfg: httpproxy.Config{
197 NoProxy: "示例.com",
198 HTTPProxy: "proxy",
199 },
200 req: "http://www.xn--fsq092h.com",
201 want: "<nil>",
202 },
203 }
204
205 func testProxyForURL(t *testing.T, tt proxyForURLTest) {
206 setHelper(t)
207 reqURLStr := tt.req
208 if reqURLStr == "" {
209 reqURLStr = "http://example.com"
210 }
211 reqURL, err := url.Parse(reqURLStr)
212 if err != nil {
213 t.Errorf("invalid URL %q", reqURLStr)
214 return
215 }
216 cfg := tt.cfg
217 proxyForURL := cfg.ProxyFunc()
218 url, err := proxyForURL(reqURL)
219 if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.wanterr); g != e {
220 t.Errorf("%v: got error = %q, want %q", tt, g, e)
221 return
222 }
223 if got := fmt.Sprintf("%s", url); got != tt.want {
224 t.Errorf("%v: got URL = %q, want %q", tt, url, tt.want)
225 }
226
227
228
229 cfg = httpproxy.Config{}
230 url, err = proxyForURL(reqURL)
231 if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.wanterr); g != e {
232 t.Errorf("(after mutating config) %v: got error = %q, want %q", tt, g, e)
233 return
234 }
235 if got := fmt.Sprintf("%s", url); got != tt.want {
236 t.Errorf("(after mutating config) %v: got URL = %q, want %q", tt, url, tt.want)
237 }
238 }
239
240 func TestProxyForURL(t *testing.T) {
241 for _, tt := range proxyForURLTests {
242 testProxyForURL(t, tt)
243 }
244 }
245
246 func TestFromEnvironment(t *testing.T) {
247 os.Setenv("HTTP_PROXY", "httpproxy")
248 os.Setenv("HTTPS_PROXY", "httpsproxy")
249 os.Setenv("NO_PROXY", "noproxy")
250 os.Setenv("REQUEST_METHOD", "")
251 got := httpproxy.FromEnvironment()
252 want := httpproxy.Config{
253 HTTPProxy: "httpproxy",
254 HTTPSProxy: "httpsproxy",
255 NoProxy: "noproxy",
256 }
257 if *got != want {
258 t.Errorf("unexpected proxy config, got %#v want %#v", got, want)
259 }
260 }
261
262 func TestFromEnvironmentWithRequestMethod(t *testing.T) {
263 os.Setenv("HTTP_PROXY", "httpproxy")
264 os.Setenv("HTTPS_PROXY", "httpsproxy")
265 os.Setenv("NO_PROXY", "noproxy")
266 os.Setenv("REQUEST_METHOD", "PUT")
267 got := httpproxy.FromEnvironment()
268 want := httpproxy.Config{
269 HTTPProxy: "httpproxy",
270 HTTPSProxy: "httpsproxy",
271 NoProxy: "noproxy",
272 CGI: true,
273 }
274 if *got != want {
275 t.Errorf("unexpected proxy config, got %#v want %#v", got, want)
276 }
277 }
278
279 func TestFromEnvironmentLowerCase(t *testing.T) {
280 os.Setenv("http_proxy", "httpproxy")
281 os.Setenv("https_proxy", "httpsproxy")
282 os.Setenv("no_proxy", "noproxy")
283 os.Setenv("REQUEST_METHOD", "")
284 got := httpproxy.FromEnvironment()
285 want := httpproxy.Config{
286 HTTPProxy: "httpproxy",
287 HTTPSProxy: "httpsproxy",
288 NoProxy: "noproxy",
289 }
290 if *got != want {
291 t.Errorf("unexpected proxy config, got %#v want %#v", got, want)
292 }
293 }
294
295 var UseProxyTests = []struct {
296 host string
297 match bool
298 }{
299
300 {"localhost", false},
301 {"127.0.0.1", false},
302 {"127.0.0.2", false},
303 {"[::1]", false},
304 {"[::2]", true},
305
306 {"192.168.1.1", false},
307 {"192.168.1.2", true},
308 {"192.168.1.3", false},
309 {"192.168.1.4", true},
310 {"10.0.0.2", false},
311 {"[2001:db8::52:0:1]", false},
312 {"[2001:db8::52:0:2]", true},
313 {"[2001:db8::52:0:3]", false},
314 {"[2002:db8:a::123]", false},
315 {"[fe80::424b:c8be:1643:a1b6]", true},
316
317 {"barbaz.net", true},
318 {"www.barbaz.net", false},
319 {"foobar.com", false},
320 {"www.foobar.com", false},
321 {"foofoobar.com", true},
322 {"baz.com", true},
323 {"localhost.net", true},
324 {"local.localhost", true},
325 {"barbarbaz.net", true},
326 {"wildcard.io", true},
327 {"nested.wildcard.io", false},
328 {"awildcard.io", true},
329 }
330
331 var noProxy = "foobar.com, .barbaz.net, *.wildcard.io, 192.168.1.1, 192.168.1.2:81, 192.168.1.3:80, 10.0.0.0/30, 2001:db8::52:0:1, [2001:db8::52:0:2]:443, [2001:db8::52:0:3]:80, 2002:db8:a::45/64"
332
333 func TestUseProxy(t *testing.T) {
334 cfg := &httpproxy.Config{
335 NoProxy: noProxy,
336 }
337 for _, test := range UseProxyTests {
338 if httpproxy.ExportUseProxy(cfg, test.host+":80") != test.match {
339 t.Errorf("useProxy(%v) = %v, want %v", test.host, !test.match, test.match)
340 }
341 }
342 }
343
344 func TestInvalidNoProxy(t *testing.T) {
345 cfg := &httpproxy.Config{
346 NoProxy: ":1",
347 }
348 ok := httpproxy.ExportUseProxy(cfg, "example.com:80")
349 if !ok {
350 t.Errorf("useProxy unexpected return; got false; want true")
351 }
352 }
353
354 func TestAllNoProxy(t *testing.T) {
355 cfg := &httpproxy.Config{
356 NoProxy: "*",
357 }
358 for _, test := range UseProxyTests {
359 if httpproxy.ExportUseProxy(cfg, test.host+":80") != false {
360 t.Errorf("useProxy(%v) = true, want false", test.host)
361 }
362 }
363 }
364
365 func BenchmarkProxyForURL(b *testing.B) {
366 cfg := &httpproxy.Config{
367 HTTPProxy: "http://proxy.example.org",
368 HTTPSProxy: "https://proxy.example.org",
369 NoProxy: noProxy,
370 }
371 for _, test := range UseProxyTests {
372 u, err := url.Parse("https://" + test.host + ":80")
373 if err != nil {
374 b.Fatalf("parsed failed: %s", test.host)
375 }
376 proxyFunc := cfg.ProxyFunc()
377 b.Run(test.host, func(b *testing.B) {
378 for n := 0; n < b.N; n++ {
379 if au, e := proxyFunc(u); e != nil && test.match == (au != nil) {
380 b.Errorf("useProxy(%v) = %v, want %v", test.host, !test.match, test.match)
381 }
382 }
383 })
384 }
385 }
386
View as plain text