| 473 | } |
| 474 | |
| 475 | func (c *Client) doRequest( |
| 476 | ctx context.Context, |
| 477 | rawURL string, |
| 478 | accept string, |
| 479 | ) (*http.Response, error) { |
| 480 | if err := ctx.Err(); err != nil { |
| 481 | return nil, fmt.Errorf("github: request aborted: %w", err) |
| 482 | } |
| 483 | if strings.TrimSpace(rawURL) == "" { |
| 484 | return nil, errors.New("github: request URL is required") |
| 485 | } |
| 486 | |
| 487 | backoff := c.initialBackoff |
| 488 | var lastErr error |
| 489 | |
| 490 | for attempt := 0; attempt <= c.maxRetries; attempt++ { |
| 491 | request, err := c.newRequest(ctx, rawURL, accept) |
| 492 | if err != nil { |
| 493 | return nil, err |
| 494 | } |
| 495 | |
| 496 | response, err := c.httpClient.Do(request) |
| 497 | if err != nil { |
| 498 | lastErr, err = c.handleRequestError(ctx, err) |
| 499 | if err != nil || attempt == c.maxRetries { |
| 500 | if err != nil { |
| 501 | return nil, err |
| 502 | } |
| 503 | return nil, lastErr |
| 504 | } |
| 505 | backoff, err = c.waitForRetry(ctx, backoff) |
| 506 | if err != nil { |
| 507 | return nil, err |
| 508 | } |
| 509 | continue |
| 510 | } |
| 511 | |
| 512 | if err := c.checkRateLimit(response); err != nil { |
| 513 | return nil, err |
| 514 | } |
| 515 | |
| 516 | if shouldRetryStatus(response.StatusCode) && attempt < c.maxRetries { |
| 517 | c.prepareRetryResponse(response, attempt) |
| 518 | backoff, err = c.waitForRetry(ctx, backoff) |
| 519 | if err != nil { |
| 520 | return nil, err |
| 521 | } |
| 522 | continue |
| 523 | } |
| 524 | |
| 525 | return response, nil |
| 526 | } |
| 527 | |
| 528 | if lastErr == nil { |
| 529 | lastErr = fmt.Errorf("github: request failed: %s", rawURL) |
| 530 | } |
| 531 | return nil, lastErr |
| 532 | } |