oauth: fix oauth token race in http_transport (#1269) · sourcegraph/src-cli@7bc2fb6
@@ -12,9 +12,12 @@ var _ http.Transport
1212var _ http.RoundTripper = (*Transport)(nil)
13131414type Transport struct {
15-Base http.RoundTripper
15+Base http.RoundTripper
16+//Token is a OAuth token (which has a refresh token) that should be used during roundtrip to automatically
17+//refresh the OAuth access token once the current one has expired or is soon to expire
1618Token *Token
171920+//mu is a mutex that should be acquired whenever token used
1821mu sync.Mutex
1922}
2023@@ -29,16 +32,25 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
2932if err := t.refreshToken(ctx); err != nil {
3033return nil, err
3134 }
35+token := t.getToken()
32363337req2 := req.Clone(req.Context())
34-req2.Header.Set("Authorization", "Bearer "+t.Token.AccessToken)
38+req2.Header.Set("Authorization", "Bearer "+token.AccessToken)
35393640if t.Base != nil {
3741return t.Base.RoundTrip(req2)
3842 }
3943return http.DefaultTransport.RoundTrip(req2)
4044}
414546+// getToken returns a value copy of token and is guarded by a mutex
47+func (t *Transport) getToken() Token {
48+t.mu.Lock()
49+defer t.mu.Unlock()
50+51+return *t.Token
52+}
53+4254// refreshToken checks if the token has expired or expiring soon and refreshes it. Once the token is
4355// refreshed, the in-memory token is updated and a best effort is made to store the token.
4456// If storing the token fails, no error is returned.