| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- // Copyright (c) 2020 Tailscale Inc & 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 tshttpproxy contains Tailscale additions to httpproxy not available
- // in golang.org/x/net/http/httpproxy. Notably, it aims to support Windows better.
- package tshttpproxy
- import (
- "net/http"
- "net/url"
- "os"
- "sync"
- "time"
- )
- // InvalidateCache invalidates the package-level cache for ProxyFromEnvironment.
- //
- // It's intended to be called on network link/routing table changes.
- func InvalidateCache() {
- mu.Lock()
- defer mu.Unlock()
- noProxyUntil = time.Time{}
- }
- var (
- mu sync.Mutex
- noProxyUntil time.Time // if non-zero, time at which ProxyFromEnvironment should check again
- )
- func setNoProxyUntil(d time.Duration) {
- mu.Lock()
- defer mu.Unlock()
- noProxyUntil = time.Now().Add(d)
- }
- var _ = setNoProxyUntil // quiet staticcheck; Windows uses the above, more might later
- // sysProxyFromEnv, if non-nil, specifies a platform-specific ProxyFromEnvironment
- // func to use if http.ProxyFromEnvironment doesn't return a proxy.
- // For example, WPAD PAC files on Windows.
- var sysProxyFromEnv func(*http.Request) (*url.URL, error)
- func ProxyFromEnvironment(req *http.Request) (*url.URL, error) {
- mu.Lock()
- noProxyTime := noProxyUntil
- mu.Unlock()
- if time.Now().Before(noProxyTime) {
- return nil, nil
- }
- u, err := http.ProxyFromEnvironment(req)
- if u != nil && err == nil {
- return u, nil
- }
- if sysProxyFromEnv != nil {
- u, err := sysProxyFromEnv(req)
- if u != nil && err == nil {
- return u, nil
- }
- }
- return nil, err
- }
- var sysAuthHeader func(*url.URL) (string, error)
- // GetAuthHeader returns the Authorization header value to send to proxy u.
- func GetAuthHeader(u *url.URL) (string, error) {
- if fake := os.Getenv("TS_DEBUG_FAKE_PROXY_AUTH"); fake != "" {
- return fake, nil
- }
- if user := u.User.Username(); user != "" {
- pass, ok := u.User.Password()
- if !ok {
- return "", nil
- }
- req := &http.Request{Header: make(http.Header)}
- req.SetBasicAuth(user, pass)
- return req.Header.Get("Authorization"), nil
- }
- if sysAuthHeader != nil {
- return sysAuthHeader(u)
- }
- return "", nil
- }
- var condSetTransportGetProxyConnectHeader func(*http.Transport)
- // SetTarnsportGetProxyConnectHeader sets the provided Transport's
- // GetProxyConnectHeader field, if the current build of Go supports
- // it.
- //
- // See https://github.com/golang/go/issues/41048.
- func SetTransportGetProxyConnectHeader(tr *http.Transport) {
- if f := condSetTransportGetProxyConnectHeader; f != nil {
- f(tr)
- }
- }
|