mirror of
https://github.com/golang/net.git
synced 2026-03-31 02:17:08 +09:00
Now that the x/net module requires Go 1.25.0, the go1.25 build constraint is always satisfied. Simplify the code accordingly. Change-Id: I3d6fe4a132a26918455489b998730b494f5273c4 Reviewed-on: https://go-review.googlesource.com/c/net/+/744800 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org> Reviewed-by: Nicholas Husin <nsh@golang.org> Reviewed-by: Nicholas Husin <husin@google.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
402 lines
10 KiB
Go
402 lines
10 KiB
Go
// Copyright 2017 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package httpproxy_test
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"golang.org/x/net/http/httpproxy"
|
|
)
|
|
|
|
type proxyForURLTest struct {
|
|
cfg httpproxy.Config
|
|
req string // URL to fetch; blank means "http://example.com"
|
|
want string
|
|
wanterr error
|
|
}
|
|
|
|
func (t proxyForURLTest) String() string {
|
|
var buf bytes.Buffer
|
|
space := func() {
|
|
if buf.Len() > 0 {
|
|
buf.WriteByte(' ')
|
|
}
|
|
}
|
|
if t.cfg.HTTPProxy != "" {
|
|
fmt.Fprintf(&buf, "http_proxy=%q", t.cfg.HTTPProxy)
|
|
}
|
|
if t.cfg.HTTPSProxy != "" {
|
|
space()
|
|
fmt.Fprintf(&buf, "https_proxy=%q", t.cfg.HTTPSProxy)
|
|
}
|
|
if t.cfg.NoProxy != "" {
|
|
space()
|
|
fmt.Fprintf(&buf, "no_proxy=%q", t.cfg.NoProxy)
|
|
}
|
|
req := "http://example.com"
|
|
if t.req != "" {
|
|
req = t.req
|
|
}
|
|
space()
|
|
fmt.Fprintf(&buf, "req=%q", req)
|
|
return strings.TrimSpace(buf.String())
|
|
}
|
|
|
|
var proxyForURLTests = []proxyForURLTest{{
|
|
cfg: httpproxy.Config{
|
|
HTTPProxy: "127.0.0.1:8080",
|
|
},
|
|
want: "http://127.0.0.1:8080",
|
|
}, {
|
|
cfg: httpproxy.Config{
|
|
HTTPProxy: "cache.corp.example.com:1234",
|
|
},
|
|
want: "http://cache.corp.example.com:1234",
|
|
}, {
|
|
cfg: httpproxy.Config{
|
|
HTTPProxy: "cache.corp.example.com",
|
|
},
|
|
want: "http://cache.corp.example.com",
|
|
}, {
|
|
// single label domain is recognized as scheme by url.Parse
|
|
cfg: httpproxy.Config{
|
|
HTTPProxy: "localhost",
|
|
},
|
|
want: "http://localhost",
|
|
}, {
|
|
cfg: httpproxy.Config{
|
|
HTTPProxy: "https://cache.corp.example.com",
|
|
},
|
|
want: "https://cache.corp.example.com",
|
|
}, {
|
|
cfg: httpproxy.Config{
|
|
HTTPProxy: "http://127.0.0.1:8080",
|
|
},
|
|
want: "http://127.0.0.1:8080",
|
|
}, {
|
|
cfg: httpproxy.Config{
|
|
HTTPProxy: "https://127.0.0.1:8080",
|
|
},
|
|
want: "https://127.0.0.1:8080",
|
|
}, {
|
|
cfg: httpproxy.Config{
|
|
HTTPProxy: "socks5://127.0.0.1",
|
|
},
|
|
want: "socks5://127.0.0.1",
|
|
}, {
|
|
// Preserve unknown schemes.
|
|
cfg: httpproxy.Config{
|
|
HTTPProxy: "foo://host",
|
|
},
|
|
want: "foo://host",
|
|
}, {
|
|
// Don't use secure for http
|
|
cfg: httpproxy.Config{
|
|
HTTPProxy: "http.proxy.tld",
|
|
HTTPSProxy: "secure.proxy.tld",
|
|
},
|
|
req: "http://insecure.tld/",
|
|
want: "http://http.proxy.tld",
|
|
}, {
|
|
// Use secure for https.
|
|
cfg: httpproxy.Config{
|
|
HTTPProxy: "http.proxy.tld",
|
|
HTTPSProxy: "secure.proxy.tld",
|
|
},
|
|
req: "https://secure.tld/",
|
|
want: "http://secure.proxy.tld",
|
|
}, {
|
|
cfg: httpproxy.Config{
|
|
HTTPProxy: "http.proxy.tld",
|
|
HTTPSProxy: "https://secure.proxy.tld",
|
|
},
|
|
req: "https://secure.tld/",
|
|
want: "https://secure.proxy.tld",
|
|
}, {
|
|
cfg: httpproxy.Config{
|
|
HTTPProxy: "http.proxy.tld",
|
|
},
|
|
req: "https://secure.tld/",
|
|
want: "<nil>",
|
|
}, {
|
|
cfg: httpproxy.Config{
|
|
HTTPProxy: "http.proxy.tld",
|
|
},
|
|
req: "ftp://insecure.tld/",
|
|
want: "<nil>",
|
|
}, {
|
|
// Issue 16405: don't use HTTP_PROXY in a CGI environment,
|
|
// where HTTP_PROXY can be attacker-controlled.
|
|
cfg: httpproxy.Config{
|
|
HTTPProxy: "http://10.1.2.3:8080",
|
|
CGI: true,
|
|
},
|
|
want: "<nil>",
|
|
wanterr: errors.New("refusing to use HTTP_PROXY value in CGI environment; see golang.org/s/cgihttpproxy"),
|
|
}, {
|
|
// HTTPS proxy is still used even in CGI environment.
|
|
// (perhaps dubious but it's the historical behaviour).
|
|
cfg: httpproxy.Config{
|
|
HTTPSProxy: "https://secure.proxy.tld",
|
|
CGI: true,
|
|
},
|
|
req: "https://secure.tld/",
|
|
want: "https://secure.proxy.tld",
|
|
}, {
|
|
want: "<nil>",
|
|
}, {
|
|
cfg: httpproxy.Config{
|
|
NoProxy: "example.com",
|
|
HTTPProxy: "proxy",
|
|
},
|
|
req: "http://example.com/",
|
|
want: "<nil>",
|
|
}, {
|
|
cfg: httpproxy.Config{
|
|
NoProxy: ".example.com",
|
|
HTTPProxy: "proxy",
|
|
},
|
|
req: "http://example.com/",
|
|
want: "http://proxy",
|
|
}, {
|
|
cfg: httpproxy.Config{
|
|
NoProxy: "ample.com",
|
|
HTTPProxy: "proxy",
|
|
},
|
|
req: "http://example.com/",
|
|
want: "http://proxy",
|
|
}, {
|
|
cfg: httpproxy.Config{
|
|
NoProxy: "example.com",
|
|
HTTPProxy: "proxy",
|
|
},
|
|
req: "http://foo.example.com/",
|
|
want: "<nil>",
|
|
}, {
|
|
cfg: httpproxy.Config{
|
|
NoProxy: ".foo.com",
|
|
HTTPProxy: "proxy",
|
|
},
|
|
req: "http://example.com/",
|
|
want: "http://proxy",
|
|
}, {
|
|
cfg: httpproxy.Config{
|
|
NoProxy: ".示例.com",
|
|
HTTPProxy: "proxy",
|
|
},
|
|
req: "http://www.示例.com",
|
|
want: "<nil>",
|
|
}, {
|
|
cfg: httpproxy.Config{
|
|
NoProxy: "xn--fsq092h.com",
|
|
HTTPProxy: "proxy",
|
|
},
|
|
req: "http://www.示例.com",
|
|
want: "<nil>",
|
|
}, {
|
|
cfg: httpproxy.Config{
|
|
NoProxy: "示例.com",
|
|
HTTPProxy: "proxy",
|
|
},
|
|
req: "http://www.xn--fsq092h.com",
|
|
want: "<nil>",
|
|
}, {
|
|
cfg: httpproxy.Config{
|
|
NoProxy: "example.com",
|
|
HTTPProxy: "proxy",
|
|
},
|
|
req: "http://[1000::%25.example.com]:123",
|
|
want: "http://proxy",
|
|
},
|
|
}
|
|
|
|
func testProxyForURL(t *testing.T, tt proxyForURLTest) {
|
|
t.Helper()
|
|
reqURLStr := tt.req
|
|
if reqURLStr == "" {
|
|
reqURLStr = "http://example.com"
|
|
}
|
|
reqURL, err := url.Parse(reqURLStr)
|
|
if err != nil {
|
|
t.Errorf("invalid URL %q", reqURLStr)
|
|
return
|
|
}
|
|
cfg := tt.cfg
|
|
proxyForURL := cfg.ProxyFunc()
|
|
url, err := proxyForURL(reqURL)
|
|
if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.wanterr); g != e {
|
|
t.Errorf("%v: got error = %q, want %q", tt, g, e)
|
|
return
|
|
}
|
|
if got := fmt.Sprintf("%s", url); got != tt.want {
|
|
t.Errorf("%v: got URL = %q, want %q", tt, url, tt.want)
|
|
}
|
|
|
|
// Check that changing the Config doesn't change the results
|
|
// of the functuon.
|
|
cfg = httpproxy.Config{}
|
|
url, err = proxyForURL(reqURL)
|
|
if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.wanterr); g != e {
|
|
t.Errorf("(after mutating config) %v: got error = %q, want %q", tt, g, e)
|
|
return
|
|
}
|
|
if got := fmt.Sprintf("%s", url); got != tt.want {
|
|
t.Errorf("(after mutating config) %v: got URL = %q, want %q", tt, url, tt.want)
|
|
}
|
|
}
|
|
|
|
func TestProxyForURL(t *testing.T) {
|
|
for _, tt := range proxyForURLTests {
|
|
testProxyForURL(t, tt)
|
|
}
|
|
}
|
|
|
|
func TestFromEnvironment(t *testing.T) {
|
|
os.Setenv("HTTP_PROXY", "httpproxy")
|
|
os.Setenv("HTTPS_PROXY", "httpsproxy")
|
|
os.Setenv("NO_PROXY", "noproxy")
|
|
os.Setenv("REQUEST_METHOD", "")
|
|
got := httpproxy.FromEnvironment()
|
|
want := httpproxy.Config{
|
|
HTTPProxy: "httpproxy",
|
|
HTTPSProxy: "httpsproxy",
|
|
NoProxy: "noproxy",
|
|
}
|
|
if *got != want {
|
|
t.Errorf("unexpected proxy config, got %#v want %#v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestFromEnvironmentWithRequestMethod(t *testing.T) {
|
|
os.Setenv("HTTP_PROXY", "httpproxy")
|
|
os.Setenv("HTTPS_PROXY", "httpsproxy")
|
|
os.Setenv("NO_PROXY", "noproxy")
|
|
os.Setenv("REQUEST_METHOD", "PUT")
|
|
got := httpproxy.FromEnvironment()
|
|
want := httpproxy.Config{
|
|
HTTPProxy: "httpproxy",
|
|
HTTPSProxy: "httpsproxy",
|
|
NoProxy: "noproxy",
|
|
CGI: true,
|
|
}
|
|
if *got != want {
|
|
t.Errorf("unexpected proxy config, got %#v want %#v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestFromEnvironmentLowerCase(t *testing.T) {
|
|
os.Setenv("http_proxy", "httpproxy")
|
|
os.Setenv("https_proxy", "httpsproxy")
|
|
os.Setenv("no_proxy", "noproxy")
|
|
os.Setenv("REQUEST_METHOD", "")
|
|
got := httpproxy.FromEnvironment()
|
|
want := httpproxy.Config{
|
|
HTTPProxy: "httpproxy",
|
|
HTTPSProxy: "httpsproxy",
|
|
NoProxy: "noproxy",
|
|
}
|
|
if *got != want {
|
|
t.Errorf("unexpected proxy config, got %#v want %#v", got, want)
|
|
}
|
|
}
|
|
|
|
var UseProxyTests = []struct {
|
|
host string
|
|
match bool
|
|
}{
|
|
// Never proxy localhost:
|
|
{"localhost", false},
|
|
{"127.0.0.1", false},
|
|
{"127.0.0.2", false},
|
|
{"[::1]", false},
|
|
{"[::2]", true}, // not a loopback address
|
|
|
|
{"192.168.1.1", false}, // matches exact IPv4
|
|
{"192.168.1.2", true}, // ports do not match
|
|
{"192.168.1.3", false}, // matches exact IPv4:port
|
|
{"192.168.1.4", true}, // no match
|
|
{"10.0.0.2", false}, // matches IPv4/CIDR
|
|
{"[2001:db8::52:0:1]", false}, // matches exact IPv6
|
|
{"[2001:db8::52:0:2]", true}, // no match
|
|
{"[2001:db8::52:0:3]", false}, // matches exact [IPv6]:port
|
|
{"[2002:db8:a::123]", false}, // matches IPv6/CIDR
|
|
{"[fe80::424b:c8be:1643:a1b6]", true}, // no match
|
|
|
|
{"barbaz.net", true}, // does not match as .barbaz.net
|
|
{"www.barbaz.net", false}, // does match as .barbaz.net
|
|
{"foobar.com", false}, // does match as foobar.com
|
|
{"www.foobar.com", false}, // match because NO_PROXY includes "foobar.com"
|
|
{"foofoobar.com", true}, // not match as a part of foobar.com
|
|
{"baz.com", true}, // not match as a part of barbaz.com
|
|
{"localhost.net", true}, // not match as suffix of address
|
|
{"local.localhost", true}, // not match as prefix as address
|
|
{"barbarbaz.net", true}, // not match, wrong domain
|
|
{"wildcard.io", true}, // does not match as *.wildcard.io
|
|
{"nested.wildcard.io", false}, // match as *.wildcard.io
|
|
{"awildcard.io", true}, // not a match because of '*'
|
|
}
|
|
|
|
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"
|
|
|
|
func TestUseProxy(t *testing.T) {
|
|
cfg := &httpproxy.Config{
|
|
NoProxy: noProxy,
|
|
}
|
|
for _, test := range UseProxyTests {
|
|
if httpproxy.ExportUseProxy(cfg, test.host+":80") != test.match {
|
|
t.Errorf("useProxy(%v) = %v, want %v", test.host, !test.match, test.match)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestInvalidNoProxy(t *testing.T) {
|
|
cfg := &httpproxy.Config{
|
|
NoProxy: ":1",
|
|
}
|
|
ok := httpproxy.ExportUseProxy(cfg, "example.com:80") // should not panic
|
|
if !ok {
|
|
t.Errorf("useProxy unexpected return; got false; want true")
|
|
}
|
|
}
|
|
|
|
func TestAllNoProxy(t *testing.T) {
|
|
cfg := &httpproxy.Config{
|
|
NoProxy: "*",
|
|
}
|
|
for _, test := range UseProxyTests {
|
|
if httpproxy.ExportUseProxy(cfg, test.host+":80") != false {
|
|
t.Errorf("useProxy(%v) = true, want false", test.host)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkProxyForURL(b *testing.B) {
|
|
cfg := &httpproxy.Config{
|
|
HTTPProxy: "http://proxy.example.org",
|
|
HTTPSProxy: "https://proxy.example.org",
|
|
NoProxy: noProxy,
|
|
}
|
|
for _, test := range UseProxyTests {
|
|
u, err := url.Parse("https://" + test.host + ":80")
|
|
if err != nil {
|
|
b.Fatalf("parsed failed: %s", test.host)
|
|
}
|
|
proxyFunc := cfg.ProxyFunc()
|
|
b.Run(test.host, func(b *testing.B) {
|
|
for n := 0; n < b.N; n++ {
|
|
if au, e := proxyFunc(u); e != nil && test.match == (au != nil) {
|
|
b.Errorf("useProxy(%v) = %v, want %v", test.host, !test.match, test.match)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|