Locking SendWithAuth to fix race condition

When SendWithAuth gets called in a multithreaded environment on the
same Client object, a concurrent read and write of c.Token might happen
in GetAccessToken.
This patch solves the issue by locking the client while we get a new
access token in SendWithAuth.
This commit is contained in:
Antoine Pourchet 2019-02-26 23:26:37 -08:00
parent 7a8d9e5531
commit bb976e776e
2 changed files with 5 additions and 0 deletions

View File

@ -125,10 +125,12 @@ func (c *Client) Send(req *http.Request, v interface{}) error {
// making the main request // making the main request
// client.Token will be updated when changed // client.Token will be updated when changed
func (c *Client) SendWithAuth(req *http.Request, v interface{}) error { func (c *Client) SendWithAuth(req *http.Request, v interface{}) error {
c.Lock()
if c.Token != nil { if c.Token != nil {
if !c.tokenExpiresAt.IsZero() && c.tokenExpiresAt.Sub(time.Now()) < RequestNewTokenBeforeExpiresIn { if !c.tokenExpiresAt.IsZero() && c.tokenExpiresAt.Sub(time.Now()) < RequestNewTokenBeforeExpiresIn {
// c.Token will be updated in GetAccessToken call // c.Token will be updated in GetAccessToken call
if _, err := c.GetAccessToken(); err != nil { if _, err := c.GetAccessToken(); err != nil {
c.Unlock()
return err return err
} }
} }
@ -136,6 +138,7 @@ func (c *Client) SendWithAuth(req *http.Request, v interface{}) error {
req.Header.Set("Authorization", "Bearer "+c.Token.Token) req.Header.Set("Authorization", "Bearer "+c.Token.Token)
} }
c.Unlock()
return c.Send(req, v) return c.Send(req, v)
} }

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"sync"
"time" "time"
) )
@ -168,6 +169,7 @@ type (
// Client represents a Paypal REST API Client // Client represents a Paypal REST API Client
Client struct { Client struct {
sync.Mutex
Client *http.Client Client *http.Client
ClientID string ClientID string
Secret string Secret string