Commit 4deead76 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

net/http: cache transport environment lookup

Apparently this is expensive on Windows.

Fixes #7020

R=golang-codereviews, alex.brainman, mattn.jp, dvyukov
CC=golang-codereviews
https://golang.org/cl/52840043
parent fc908a02
...@@ -63,4 +63,9 @@ func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler { ...@@ -63,4 +63,9 @@ func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler {
return &timeoutHandler{handler, f, ""} return &timeoutHandler{handler, f, ""}
} }
func ResetCachedEnvironment() {
httpProxyEnv.reset()
noProxyEnv.reset()
}
var DefaultUserAgent = defaultUserAgent var DefaultUserAgent = defaultUserAgent
...@@ -99,7 +99,7 @@ type Transport struct { ...@@ -99,7 +99,7 @@ type Transport struct {
// A nil URL and nil error are returned if no proxy is defined in the // A nil URL and nil error are returned if no proxy is defined in the
// environment, or a proxy should not be used for the given request. // environment, or a proxy should not be used for the given request.
func ProxyFromEnvironment(req *Request) (*url.URL, error) { func ProxyFromEnvironment(req *Request) (*url.URL, error) {
proxy := getenvEitherCase("HTTP_PROXY") proxy := httpProxyEnv.Get()
if proxy == "" { if proxy == "" {
return nil, nil return nil, nil
} }
...@@ -243,11 +243,42 @@ func (t *Transport) CancelRequest(req *Request) { ...@@ -243,11 +243,42 @@ func (t *Transport) CancelRequest(req *Request) {
// Private implementation past this point. // Private implementation past this point.
// //
func getenvEitherCase(k string) string { var (
if v := os.Getenv(strings.ToUpper(k)); v != "" { httpProxyEnv = &envOnce{
return v names: []string{"HTTP_PROXY", "http_proxy"},
} }
return os.Getenv(strings.ToLower(k)) noProxyEnv = &envOnce{
names: []string{"NO_PROXY", "no_proxy"},
}
)
// envOnce looks up an environment variable (optionally by multiple
// names) once. It mitigates expensive lookups on some platforms
// (e.g. Windows).
type envOnce struct {
names []string
once sync.Once
val string
}
func (e *envOnce) Get() string {
e.once.Do(e.init)
return e.val
}
func (e *envOnce) init() {
for _, n := range e.names {
e.val = os.Getenv(n)
if e.val != "" {
return
}
}
}
// reset is used by tests
func (e *envOnce) reset() {
e.once = sync.Once{}
e.val = ""
} }
func (t *Transport) connectMethodForRequest(treq *transportRequest) (*connectMethod, error) { func (t *Transport) connectMethodForRequest(treq *transportRequest) (*connectMethod, error) {
...@@ -550,7 +581,7 @@ func useProxy(addr string) bool { ...@@ -550,7 +581,7 @@ func useProxy(addr string) bool {
} }
} }
no_proxy := getenvEitherCase("NO_PROXY") no_proxy := noProxyEnv.Get()
if no_proxy == "*" { if no_proxy == "*" {
return false return false
} }
......
...@@ -1566,6 +1566,7 @@ func TestProxyFromEnvironment(t *testing.T) { ...@@ -1566,6 +1566,7 @@ func TestProxyFromEnvironment(t *testing.T) {
for _, tt := range proxyFromEnvTests { for _, tt := range proxyFromEnvTests {
os.Setenv("HTTP_PROXY", tt.env) os.Setenv("HTTP_PROXY", tt.env)
os.Setenv("NO_PROXY", tt.noenv) os.Setenv("NO_PROXY", tt.noenv)
ResetCachedEnvironment()
reqURL := tt.req reqURL := tt.req
if reqURL == "" { if reqURL == "" {
reqURL = "http://example.com" reqURL = "http://example.com"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment