mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-11-04 10:11:18 +01:00 
			
		
		
		
	Updates #11058 Change-Id: I35e7ef9b90e83cac04ca93fd964ad00ed5b48430 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
		
			
				
	
	
		
			208 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			208 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright (c) Tailscale Inc & AUTHORS
 | 
						|
// SPDX-License-Identifier: BSD-3-Clause
 | 
						|
 | 
						|
package tshttpproxy
 | 
						|
 | 
						|
import (
 | 
						|
	"net/http"
 | 
						|
	"net/url"
 | 
						|
	"os"
 | 
						|
	"runtime"
 | 
						|
	"strings"
 | 
						|
	"testing"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"tailscale.com/util/must"
 | 
						|
)
 | 
						|
 | 
						|
func TestGetAuthHeaderNoResult(t *testing.T) {
 | 
						|
	const proxyURL = "http://127.0.0.1:38274"
 | 
						|
 | 
						|
	u, err := url.Parse(proxyURL)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("can't parse %q: %v", proxyURL, err)
 | 
						|
	}
 | 
						|
 | 
						|
	got, err := GetAuthHeader(u)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("can't get auth header value: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	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)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestGetAuthHeaderBasicAuth(t *testing.T) {
 | 
						|
	const proxyURL = "http://user:password@127.0.0.1:38274"
 | 
						|
	const want = "Basic dXNlcjpwYXNzd29yZA=="
 | 
						|
 | 
						|
	u, err := url.Parse(proxyURL)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("can't parse %q: %v", proxyURL, err)
 | 
						|
	}
 | 
						|
 | 
						|
	got, err := GetAuthHeader(u)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("can't get auth header value: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if got != want {
 | 
						|
		t.Fatalf("GetAuthHeader(%q) = %q; want %q", proxyURL, got, want)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
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/"))}
 | 
						|
	for i := range 3 {
 | 
						|
		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)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
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)
 | 
						|
				}
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 |