oauth: fix oauth token race in http_transport (#1269) · sourcegraph/src-cli@7bc2fb6

@@ -12,9 +12,12 @@ var _ http.Transport

1212

var _ http.RoundTripper = (*Transport)(nil)

13131414

type 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

1618

Token *Token

171920+

//mu is a mutex that should be acquired whenever token used

1821

mu sync.Mutex

1922

}

2023

@@ -29,16 +32,25 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {

2932

if err := t.refreshToken(ctx); err != nil {

3033

return nil, err

3134

}

35+

token := t.getToken()

32363337

req2 := req.Clone(req.Context())

34-

req2.Header.Set("Authorization", "Bearer "+t.Token.AccessToken)

38+

req2.Header.Set("Authorization", "Bearer "+token.AccessToken)

35393640

if t.Base != nil {

3741

return t.Base.RoundTrip(req2)

3842

}

3943

return 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.