]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: cache transport environment lookup
authorBrad Fitzpatrick <bradfitz@golang.org>
Thu, 16 Jan 2014 18:25:45 +0000 (10:25 -0800)
committerBrad Fitzpatrick <bradfitz@golang.org>
Thu, 16 Jan 2014 18:25:45 +0000 (10:25 -0800)
Apparently this is expensive on Windows.

Fixes #7020

R=golang-codereviews, alex.brainman, mattn.jp, dvyukov
CC=golang-codereviews
https://golang.org/cl/52840043

src/pkg/net/http/export_test.go
src/pkg/net/http/transport.go
src/pkg/net/http/transport_test.go

index 22b7f279689bccdb78e1aa3233ae4b366a84d50e..0494991bde6d07ecd344fcdc455b42c608a50d7c 100644 (file)
@@ -63,4 +63,9 @@ func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler {
        return &timeoutHandler{handler, f, ""}
 }
 
+func ResetCachedEnvironment() {
+       httpProxyEnv.reset()
+       noProxyEnv.reset()
+}
+
 var DefaultUserAgent = defaultUserAgent
index f6871afacd7a3c26efc3d76350b314be29897da1..8fc7329e361f0915fbe966c59bf4e831ea493804 100644 (file)
@@ -99,7 +99,7 @@ type Transport struct {
 // 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.
 func ProxyFromEnvironment(req *Request) (*url.URL, error) {
-       proxy := getenvEitherCase("HTTP_PROXY")
+       proxy := httpProxyEnv.Get()
        if proxy == "" {
                return nil, nil
        }
@@ -243,11 +243,42 @@ func (t *Transport) CancelRequest(req *Request) {
 // Private implementation past this point.
 //
 
-func getenvEitherCase(k string) string {
-       if v := os.Getenv(strings.ToUpper(k)); v != "" {
-               return v
+var (
+       httpProxyEnv = &envOnce{
+               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) {
@@ -550,7 +581,7 @@ func useProxy(addr string) bool {
                }
        }
 
-       no_proxy := getenvEitherCase("NO_PROXY")
+       no_proxy := noProxyEnv.Get()
        if no_proxy == "*" {
                return false
        }
index 2ce2b6b5180c86c6c73d047e8cda3f7665b2cc19..cb54a7b419725bc546bbe8c401b6b86bd7e6e55f 100644 (file)
@@ -1566,6 +1566,7 @@ func TestProxyFromEnvironment(t *testing.T) {
        for _, tt := range proxyFromEnvTests {
                os.Setenv("HTTP_PROXY", tt.env)
                os.Setenv("NO_PROXY", tt.noenv)
+               ResetCachedEnvironment()
                reqURL := tt.req
                if reqURL == "" {
                        reqURL = "http://example.com"