gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/net/http/httpproxy/proxy_test.go (about)

     1  // Copyright 2017 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 httpproxy_test
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  	"fmt"
    11  	"net/url"
    12  	"os"
    13  	"strings"
    14  	"testing"
    15  
    16  	"gitee.com/ks-custle/core-gm/net/http/httpproxy"
    17  )
    18  
    19  // setHelper calls t.Helper() for Go 1.9+ (see go19_test.go) and does nothing otherwise.
    20  var setHelper = func(t *testing.T) {}
    21  
    22  type proxyForURLTest struct {
    23  	cfg     httpproxy.Config
    24  	req     string // URL to fetch; blank means "http://example.com"
    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  	// Don't use secure for http
    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  	// Use secure for https.
   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  	// Issue 16405: don't use HTTP_PROXY in a CGI environment,
   128  	// where HTTP_PROXY can be attacker-controlled.
   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  	// HTTPS proxy is still used even in CGI environment.
   137  	// (perhaps dubious but it's the historical behaviour).
   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  
   183  func testProxyForURL(t *testing.T, tt proxyForURLTest) {
   184  	setHelper(t)
   185  	reqURLStr := tt.req
   186  	if reqURLStr == "" {
   187  		reqURLStr = "http://example.com"
   188  	}
   189  	reqURL, err := url.Parse(reqURLStr)
   190  	if err != nil {
   191  		t.Errorf("invalid URL %q", reqURLStr)
   192  		return
   193  	}
   194  	cfg := tt.cfg
   195  	proxyForURL := cfg.ProxyFunc()
   196  	url, err := proxyForURL(reqURL)
   197  	if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.wanterr); g != e {
   198  		t.Errorf("%v: got error = %q, want %q", tt, g, e)
   199  		return
   200  	}
   201  	if got := fmt.Sprintf("%s", url); got != tt.want {
   202  		t.Errorf("%v: got URL = %q, want %q", tt, url, tt.want)
   203  	}
   204  
   205  	// Check that changing the Config doesn't change the results
   206  	// of the functuon.
   207  	cfg = httpproxy.Config{}
   208  	url, err = proxyForURL(reqURL)
   209  	if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.wanterr); g != e {
   210  		t.Errorf("(after mutating config) %v: got error = %q, want %q", tt, g, e)
   211  		return
   212  	}
   213  	if got := fmt.Sprintf("%s", url); got != tt.want {
   214  		t.Errorf("(after mutating config) %v: got URL = %q, want %q", tt, url, tt.want)
   215  	}
   216  }
   217  
   218  func TestProxyForURL(t *testing.T) {
   219  	for _, tt := range proxyForURLTests {
   220  		testProxyForURL(t, tt)
   221  	}
   222  }
   223  
   224  func TestFromEnvironment(t *testing.T) {
   225  	os.Setenv("HTTP_PROXY", "httpproxy")
   226  	os.Setenv("HTTPS_PROXY", "httpsproxy")
   227  	os.Setenv("NO_PROXY", "noproxy")
   228  	os.Setenv("REQUEST_METHOD", "")
   229  	got := httpproxy.FromEnvironment()
   230  	want := httpproxy.Config{
   231  		HTTPProxy:  "httpproxy",
   232  		HTTPSProxy: "httpsproxy",
   233  		NoProxy:    "noproxy",
   234  	}
   235  	if *got != want {
   236  		t.Errorf("unexpected proxy config, got %#v want %#v", got, want)
   237  	}
   238  }
   239  
   240  func TestFromEnvironmentWithRequestMethod(t *testing.T) {
   241  	os.Setenv("HTTP_PROXY", "httpproxy")
   242  	os.Setenv("HTTPS_PROXY", "httpsproxy")
   243  	os.Setenv("NO_PROXY", "noproxy")
   244  	os.Setenv("REQUEST_METHOD", "PUT")
   245  	got := httpproxy.FromEnvironment()
   246  	want := httpproxy.Config{
   247  		HTTPProxy:  "httpproxy",
   248  		HTTPSProxy: "httpsproxy",
   249  		NoProxy:    "noproxy",
   250  		CGI:        true,
   251  	}
   252  	if *got != want {
   253  		t.Errorf("unexpected proxy config, got %#v want %#v", got, want)
   254  	}
   255  }
   256  
   257  func TestFromEnvironmentLowerCase(t *testing.T) {
   258  	os.Setenv("http_proxy", "httpproxy")
   259  	os.Setenv("https_proxy", "httpsproxy")
   260  	os.Setenv("no_proxy", "noproxy")
   261  	os.Setenv("REQUEST_METHOD", "")
   262  	got := httpproxy.FromEnvironment()
   263  	want := httpproxy.Config{
   264  		HTTPProxy:  "httpproxy",
   265  		HTTPSProxy: "httpsproxy",
   266  		NoProxy:    "noproxy",
   267  	}
   268  	if *got != want {
   269  		t.Errorf("unexpected proxy config, got %#v want %#v", got, want)
   270  	}
   271  }
   272  
   273  var UseProxyTests = []struct {
   274  	host  string
   275  	match bool
   276  }{
   277  	// Never proxy localhost:
   278  	{"localhost", false},
   279  	{"127.0.0.1", false},
   280  	{"127.0.0.2", false},
   281  	{"[::1]", false},
   282  	{"[::2]", true}, // not a loopback address
   283  
   284  	{"192.168.1.1", false},                // matches exact IPv4
   285  	{"192.168.1.2", true},                 // ports do not match
   286  	{"192.168.1.3", false},                // matches exact IPv4:port
   287  	{"192.168.1.4", true},                 // no match
   288  	{"10.0.0.2", false},                   // matches IPv4/CIDR
   289  	{"[2001:db8::52:0:1]", false},         // matches exact IPv6
   290  	{"[2001:db8::52:0:2]", true},          // no match
   291  	{"[2001:db8::52:0:3]", false},         // matches exact [IPv6]:port
   292  	{"[2002:db8:a::123]", false},          // matches IPv6/CIDR
   293  	{"[fe80::424b:c8be:1643:a1b6]", true}, // no match
   294  
   295  	{"barbaz.net", true},          // does not match as .barbaz.net
   296  	{"www.barbaz.net", false},     // does match as .barbaz.net
   297  	{"foobar.com", false},         // does match as foobar.com
   298  	{"www.foobar.com", false},     // match because NO_PROXY includes "foobar.com"
   299  	{"foofoobar.com", true},       // not match as a part of foobar.com
   300  	{"baz.com", true},             // not match as a part of barbaz.com
   301  	{"localhost.net", true},       // not match as suffix of address
   302  	{"local.localhost", true},     // not match as prefix as address
   303  	{"barbarbaz.net", true},       // not match, wrong domain
   304  	{"wildcard.io", true},         // does not match as *.wildcard.io
   305  	{"nested.wildcard.io", false}, // match as *.wildcard.io
   306  	{"awildcard.io", true},        // not a match because of '*'
   307  }
   308  
   309  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"
   310  
   311  func TestUseProxy(t *testing.T) {
   312  	cfg := &httpproxy.Config{
   313  		NoProxy: noProxy,
   314  	}
   315  	for _, test := range UseProxyTests {
   316  		if httpproxy.ExportUseProxy(cfg, test.host+":80") != test.match {
   317  			t.Errorf("useProxy(%v) = %v, want %v", test.host, !test.match, test.match)
   318  		}
   319  	}
   320  }
   321  
   322  func TestInvalidNoProxy(t *testing.T) {
   323  	cfg := &httpproxy.Config{
   324  		NoProxy: ":1",
   325  	}
   326  	ok := httpproxy.ExportUseProxy(cfg, "example.com:80") // should not panic
   327  	if !ok {
   328  		t.Errorf("useProxy unexpected return; got false; want true")
   329  	}
   330  }
   331  
   332  func TestAllNoProxy(t *testing.T) {
   333  	cfg := &httpproxy.Config{
   334  		NoProxy: "*",
   335  	}
   336  	for _, test := range UseProxyTests {
   337  		if httpproxy.ExportUseProxy(cfg, test.host+":80") != false {
   338  			t.Errorf("useProxy(%v) = true, want false", test.host)
   339  		}
   340  	}
   341  }
   342  
   343  func BenchmarkProxyForURL(b *testing.B) {
   344  	cfg := &httpproxy.Config{
   345  		HTTPProxy:  "http://proxy.example.org",
   346  		HTTPSProxy: "https://proxy.example.org",
   347  		NoProxy:    noProxy,
   348  	}
   349  	for _, test := range UseProxyTests {
   350  		u, err := url.Parse("https://" + test.host + ":80")
   351  		if err != nil {
   352  			b.Fatalf("parsed failed: %s", test.host)
   353  		}
   354  		proxyFunc := cfg.ProxyFunc()
   355  		b.Run(test.host, func(b *testing.B) {
   356  			for n := 0; n < b.N; n++ {
   357  				if au, e := proxyFunc(u); e != nil && test.match == (au != nil) {
   358  					b.Errorf("useProxy(%v) = %v, want %v", test.host, !test.match, test.match)
   359  				}
   360  			}
   361  		})
   362  	}
   363  }