Skip to content

Commit ee2aac9

Browse files
Fix bug/AST-89866 and bug/AST-95350 (#1145)
Co-authored-by: cx-Margarita-LevitM <cx-margarita-levitm>
1 parent f332603 commit ee2aac9

File tree

2 files changed

+113
-2
lines changed

2 files changed

+113
-2
lines changed

internal/wrappers/client.go

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,28 @@ func retryHTTPRequest(requestFunc func() (*http.Response, error), retries int, b
9999
return resp, nil
100100
}
101101

102+
// "Check the response status; if it is one of 500, 501, 502, 503, or 504 the request will be resending (only 4 retries)."
103+
func retryHTTPForIAMRequest(requestFunc func() (*http.Response, error), retries int, baseDelayInMilliSec time.Duration) (*http.Response, error) {
104+
105+
var resp *http.Response
106+
var err error
107+
108+
for attempt := 0; attempt < retries; attempt++ {
109+
resp, err = requestFunc()
110+
if err != nil {
111+
return nil, err
112+
}
113+
if resp.StatusCode >= 500 && resp.StatusCode <= 504 {
114+
logger.PrintIfVerbose(fmt.Sprintf("Encountered HTTP %s response — will retry ", resp.Status))
115+
} else {
116+
return resp, nil
117+
}
118+
_ = resp.Body.Close()
119+
time.Sleep(baseDelayInMilliSec * (3 << attempt))
120+
}
121+
return nil, err
122+
}
123+
102124
func setAgentNameAndOrigin(req *http.Request) {
103125
agentStr := viper.GetString(commonParams.AgentNameKey) + "/" + commonParams.Version
104126
req.Header.Set("User-Agent", agentStr)
@@ -513,7 +535,26 @@ func getNewToken(credentialsPayload, authServerURI string) (string, error) {
513535
clientTimeout := viper.GetUint(commonParams.ClientTimeoutKey)
514536
client := GetClient(clientTimeout)
515537

516-
res, err := doPrivateRequest(client, req)
538+
//Save body for retry logic
539+
var body []byte
540+
if req.Body != nil {
541+
body, err = io.ReadAll(req.Body)
542+
if err != nil {
543+
fmt.Errorf("failed to read request body: %w", err)
544+
}
545+
if req.Body != nil {
546+
req.Body.Close()
547+
}
548+
}
549+
fn := func() (*http.Response, error) {
550+
if body != nil {
551+
_ = req.Body.Close()
552+
req.Body = io.NopCloser(bytes.NewBuffer(body))
553+
}
554+
return doPrivateRequest(client, req)
555+
}
556+
res, err := retryHTTPForIAMRequest(fn, retryAttempts, retryDelay*time.Millisecond)
557+
517558
if err != nil {
518559
authURL, _ := GetAuthURI()
519560
return "", errors.Errorf("%s %s", checkmarxURLError, authURL)
@@ -528,7 +569,7 @@ func getNewToken(credentialsPayload, authServerURI string) (string, error) {
528569
return "", errors.Errorf("%d %s \n", res.StatusCode, invalidCredentialsError)
529570
}
530571

531-
body, _ := ioutil.ReadAll(res.Body)
572+
body, _ = ioutil.ReadAll(res.Body)
532573
if res.StatusCode != http.StatusOK {
533574
credentialsErr := ClientCredentialsError{}
534575
err = json.Unmarshal(body, &credentialsErr)

internal/wrappers/client_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,3 +207,73 @@ func TestSetAgentNameAndOrigin(t *testing.T) {
207207
t.Errorf("Origin header mismatch: got %v, want %v", origin, expectedOrigin)
208208
}
209209
}
210+
211+
func TestRetryIAMHTTPRequest_Success(t *testing.T) {
212+
fn := func() (*http.Response, error) {
213+
return &http.Response{
214+
StatusCode: http.StatusOK,
215+
Body: &mockReadCloser{},
216+
}, nil
217+
}
218+
219+
resp, err := retryHTTPForIAMRequest(fn, retryAttempts, retryDelay*time.Millisecond)
220+
assert.NoError(t, err)
221+
assert.NotNil(t, resp)
222+
assert.Equal(t, http.StatusOK, resp.StatusCode)
223+
}
224+
225+
func TestRetryHTTPIAMRequest_RetryOnBadGateway(t *testing.T) {
226+
attempts := 0
227+
fn := func() (*http.Response, error) {
228+
attempts++
229+
if attempts < retryAttempts {
230+
return &http.Response{
231+
StatusCode: http.StatusBadGateway,
232+
Body: &mockReadCloser{},
233+
}, nil
234+
}
235+
return &http.Response{
236+
StatusCode: http.StatusOK,
237+
Body: &mockReadCloser{},
238+
}, nil
239+
}
240+
241+
resp, err := retryHTTPForIAMRequest(fn, retryAttempts, retryDelay*time.Millisecond)
242+
assert.NoError(t, err)
243+
assert.NotNil(t, resp)
244+
assert.Equal(t, http.StatusOK, resp.StatusCode)
245+
assert.Equal(t, retryAttempts, attempts)
246+
}
247+
248+
func TestRetryHTTPIAMRequest_RetryOnStatusNotImplemented(t *testing.T) {
249+
attempts := 0
250+
fn := func() (*http.Response, error) {
251+
attempts++
252+
if attempts < retryAttempts {
253+
return &http.Response{
254+
StatusCode: http.StatusNotImplemented,
255+
Body: &mockReadCloser{},
256+
}, nil
257+
}
258+
return &http.Response{
259+
StatusCode: http.StatusOK,
260+
Body: &mockReadCloser{},
261+
}, nil
262+
}
263+
264+
resp, err := retryHTTPForIAMRequest(fn, retryAttempts, retryDelay*time.Millisecond)
265+
assert.NoError(t, err)
266+
assert.NotNil(t, resp)
267+
assert.Equal(t, http.StatusOK, resp.StatusCode)
268+
assert.Equal(t, retryAttempts, attempts)
269+
}
270+
271+
func TestRetryHTTPIAMRequest_Fail(t *testing.T) {
272+
fn := func() (*http.Response, error) {
273+
return nil, errors.New("Resource Unavailable")
274+
}
275+
276+
resp, err := retryHTTPForIAMRequest(fn, retryAttempts, retryDelay*time.Millisecond)
277+
assert.Error(t, err)
278+
assert.Nil(t, resp)
279+
}

0 commit comments

Comments
 (0)