"os"
"strings"
"sync"
+ "sync/atomic"
"time"
"golang_org/x/net/lex/httplex"
reqMu sync.Mutex
reqCanceler map[*Request]func(error)
- altMu sync.RWMutex
- altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper
+ altMu sync.Mutex // guards changing altProto only
+ altProto atomic.Value // of nil or map[string]RoundTripper, key is URI scheme
// Proxy specifies a function to return a proxy for a given
// Request. If the function returns a non-nil error, the
}
}
}
- // TODO(bradfitz): switch to atomic.Value for this map instead of RWMutex
- t.altMu.RLock()
- altRT := t.altProto[scheme]
- t.altMu.RUnlock()
- if altRT != nil {
+
+ altProto, _ := t.altProto.Load().(map[string]RoundTripper)
+ if altRT := altProto[scheme]; altRT != nil {
if resp, err := altRT.RoundTrip(req); err != ErrSkipAltProtocol {
return resp, err
}
func (t *Transport) RegisterProtocol(scheme string, rt RoundTripper) {
t.altMu.Lock()
defer t.altMu.Unlock()
- if t.altProto == nil {
- t.altProto = make(map[string]RoundTripper)
- }
- if _, exists := t.altProto[scheme]; exists {
+ oldMap, _ := t.altProto.Load().(map[string]RoundTripper)
+ if _, exists := oldMap[scheme]; exists {
panic("protocol " + scheme + " already registered")
}
- t.altProto[scheme] = rt
+ newMap := make(map[string]RoundTripper)
+ for k, v := range oldMap {
+ newMap[k] = v
+ }
+ newMap[scheme] = rt
+ t.altProto.Store(newMap)
}
// CloseIdleConnections closes any connections which were previously