2023-01-27 21:37:20 +00:00
|
|
|
// Copyright (c) Tailscale Inc & AUTHORS
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
2021-02-17 21:01:47 +00:00
|
|
|
|
|
|
|
package tshttpproxy
|
|
|
|
|
|
|
|
import (
|
2022-11-13 17:58:47 +00:00
|
|
|
"net/http"
|
2021-02-17 21:01:47 +00:00
|
|
|
"net/url"
|
2022-11-13 17:58:47 +00:00
|
|
|
"os"
|
2021-02-18 05:23:39 +00:00
|
|
|
"runtime"
|
|
|
|
"strings"
|
2021-02-17 21:01:47 +00:00
|
|
|
"testing"
|
2022-11-13 17:58:47 +00:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"tailscale.com/util/must"
|
2021-02-17 21:01:47 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestGetAuthHeaderNoResult(t *testing.T) {
|
2021-02-18 05:23:39 +00:00
|
|
|
const proxyURL = "http://127.0.0.1:38274"
|
2021-02-17 21:01:47 +00:00
|
|
|
|
|
|
|
u, err := url.Parse(proxyURL)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("can't parse %q: %v", proxyURL, err)
|
|
|
|
}
|
|
|
|
|
2021-02-18 05:23:39 +00:00
|
|
|
got, err := GetAuthHeader(u)
|
2021-02-17 21:01:47 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("can't get auth header value: %v", err)
|
|
|
|
}
|
|
|
|
|
2021-02-18 05:23:39 +00:00
|
|
|
if runtime.GOOS == "windows" && strings.HasPrefix(got, "Negotiate") {
|
|
|
|
t.Logf("didn't get empty result, but got acceptable Windows Negotiate header")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if got != "" {
|
|
|
|
t.Fatalf("GetAuthHeader(%q) = %q; want empty string", proxyURL, got)
|
2021-02-17 21:01:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetAuthHeaderBasicAuth(t *testing.T) {
|
2021-02-18 05:23:39 +00:00
|
|
|
const proxyURL = "http://user:password@127.0.0.1:38274"
|
|
|
|
const want = "Basic dXNlcjpwYXNzd29yZA=="
|
2021-02-17 21:01:47 +00:00
|
|
|
|
|
|
|
u, err := url.Parse(proxyURL)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("can't parse %q: %v", proxyURL, err)
|
|
|
|
}
|
|
|
|
|
2021-02-18 05:23:39 +00:00
|
|
|
got, err := GetAuthHeader(u)
|
2021-02-17 21:01:47 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("can't get auth header value: %v", err)
|
|
|
|
}
|
|
|
|
|
2021-02-18 05:23:39 +00:00
|
|
|
if got != want {
|
|
|
|
t.Fatalf("GetAuthHeader(%q) = %q; want %q", proxyURL, got, want)
|
2021-02-17 21:01:47 +00:00
|
|
|
}
|
|
|
|
}
|
2022-11-13 17:58:47 +00:00
|
|
|
|
|
|
|
func TestProxyFromEnvironment_setNoProxyUntil(t *testing.T) {
|
|
|
|
const fakeProxyEnv = "10.1.2.3:456"
|
|
|
|
const fakeProxyFull = "http://" + fakeProxyEnv
|
|
|
|
|
|
|
|
defer os.Setenv("HTTPS_PROXY", os.Getenv("HTTPS_PROXY"))
|
|
|
|
os.Setenv("HTTPS_PROXY", fakeProxyEnv)
|
|
|
|
|
|
|
|
req := &http.Request{URL: must.Get(url.Parse("https://example.com/"))}
|
2024-04-16 21:15:13 +01:00
|
|
|
for i := range 3 {
|
2022-11-13 17:58:47 +00:00
|
|
|
switch i {
|
|
|
|
case 1:
|
|
|
|
setNoProxyUntil(time.Minute)
|
|
|
|
case 2:
|
|
|
|
setNoProxyUntil(0)
|
|
|
|
}
|
|
|
|
got, err := ProxyFromEnvironment(req)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("[%d] ProxyFromEnvironment: %v", i, err)
|
|
|
|
}
|
|
|
|
if got == nil || got.String() != fakeProxyFull {
|
|
|
|
t.Errorf("[%d] Got proxy %v; want %v", i, got, fakeProxyFull)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2023-03-05 02:49:05 +00:00
|
|
|
|
|
|
|
func TestSetSelfProxy(t *testing.T) {
|
|
|
|
// Ensure we clean everything up at the end of our test
|
|
|
|
t.Cleanup(func() {
|
|
|
|
config = nil
|
|
|
|
proxyFunc = nil
|
|
|
|
})
|
|
|
|
|
|
|
|
testCases := []struct {
|
|
|
|
name string
|
|
|
|
env map[string]string
|
|
|
|
self []string
|
|
|
|
wantHTTP string
|
|
|
|
wantHTTPS string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "no self proxy",
|
|
|
|
env: map[string]string{
|
|
|
|
"HTTP_PROXY": "127.0.0.1:1234",
|
|
|
|
"HTTPS_PROXY": "127.0.0.1:1234",
|
|
|
|
},
|
|
|
|
self: nil,
|
|
|
|
wantHTTP: "127.0.0.1:1234",
|
|
|
|
wantHTTPS: "127.0.0.1:1234",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "skip proxies",
|
|
|
|
env: map[string]string{
|
|
|
|
"HTTP_PROXY": "127.0.0.1:1234",
|
|
|
|
"HTTPS_PROXY": "127.0.0.1:5678",
|
|
|
|
},
|
|
|
|
self: []string{"127.0.0.1:1234", "127.0.0.1:5678"},
|
|
|
|
wantHTTP: "", // skipped
|
|
|
|
wantHTTPS: "", // skipped
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "localhost normalization of env var",
|
|
|
|
env: map[string]string{
|
|
|
|
"HTTP_PROXY": "localhost:1234",
|
|
|
|
"HTTPS_PROXY": "[::1]:5678",
|
|
|
|
},
|
|
|
|
self: []string{"127.0.0.1:1234", "127.0.0.1:5678"},
|
|
|
|
wantHTTP: "", // skipped
|
|
|
|
wantHTTPS: "", // skipped
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "localhost normalization of addr",
|
|
|
|
env: map[string]string{
|
|
|
|
"HTTP_PROXY": "127.0.0.1:1234",
|
|
|
|
"HTTPS_PROXY": "127.0.0.1:1234",
|
|
|
|
},
|
|
|
|
self: []string{"[::1]:1234"},
|
|
|
|
wantHTTP: "", // skipped
|
|
|
|
wantHTTPS: "", // skipped
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "no ports",
|
|
|
|
env: map[string]string{
|
|
|
|
"HTTP_PROXY": "myproxy",
|
|
|
|
"HTTPS_PROXY": "myproxy",
|
|
|
|
},
|
|
|
|
self: []string{"127.0.0.1:1234"},
|
|
|
|
wantHTTP: "myproxy",
|
|
|
|
wantHTTPS: "myproxy",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tt := range testCases {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
for k, v := range tt.env {
|
|
|
|
oldEnv, found := os.LookupEnv(k)
|
|
|
|
if found {
|
|
|
|
t.Cleanup(func() {
|
|
|
|
os.Setenv(k, oldEnv)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
os.Setenv(k, v)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset computed variables
|
|
|
|
config = nil
|
|
|
|
proxyFunc = func(*url.URL) (*url.URL, error) {
|
|
|
|
panic("should not be called")
|
|
|
|
}
|
|
|
|
|
|
|
|
SetSelfProxy(tt.self...)
|
|
|
|
|
|
|
|
if got := config.HTTPProxy; got != tt.wantHTTP {
|
|
|
|
t.Errorf("got HTTPProxy=%q; want %q", got, tt.wantHTTP)
|
|
|
|
}
|
|
|
|
if got := config.HTTPSProxy; got != tt.wantHTTPS {
|
|
|
|
t.Errorf("got HTTPSProxy=%q; want %q", got, tt.wantHTTPS)
|
|
|
|
}
|
|
|
|
if proxyFunc != nil {
|
|
|
|
t.Errorf("wanted nil proxyFunc")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify that we do actually proxy through the
|
|
|
|
// expected proxy, if we have one configured.
|
|
|
|
pf := getProxyFunc()
|
|
|
|
if tt.wantHTTP != "" {
|
|
|
|
want := "http://" + tt.wantHTTP
|
|
|
|
|
|
|
|
uu, _ := url.Parse("http://tailscale.com")
|
|
|
|
dest, err := pf(uu)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
} else if dest.String() != want {
|
|
|
|
t.Errorf("got dest=%q; want %q", dest, want)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if tt.wantHTTPS != "" {
|
|
|
|
want := "http://" + tt.wantHTTPS
|
|
|
|
|
|
|
|
uu, _ := url.Parse("https://tailscale.com")
|
|
|
|
dest, err := pf(uu)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
} else if dest.String() != want {
|
|
|
|
t.Errorf("got dest=%q; want %q", dest, want)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|