<commit_before>using Box.V2.Config;
using Box.V2.Utility;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace Box.V2.Request
{
    public class HttpRequestHandler : IRequestHandler
    {
        const HttpStatusCode TooManyRequests = (HttpStatusCode)429;
        const int RetryLimit = 5;

        public async Task<IBoxResponse<T>> ExecuteAsync<T>(IBoxRequest request)
            where T : class
        {
            // Need to account for special cases when the return type is a stream
            bool isStream = typeof(T) == typeof(Stream);
            var retryCounter = 0;
            ExponentialBackoff expBackoff = new ExponentialBackoff();

            try
            {
                // TODO: yhu@ better handling of different request
                var isMultiPartRequest = request.GetType() == typeof(BoxMultiPartRequest);
                var isBinaryRequest = request.GetType() == typeof(BoxBinaryRequest);

                while (true)
                {
                    HttpRequestMessage httpRequest = null;

                    if (isMultiPartRequest)
                    {
                        httpRequest = BuildMultiPartRequest(request as BoxMultiPartRequest);
                    }
                    else if (isBinaryRequest)
                    {
                        httpRequest = BuildBinaryRequest(request as BoxBinaryRequest);
                    }
                    else
                    {
                        httpRequest = BuildRequest(request);
                    }

                    // Add headers
                    foreach (var kvp in request.HttpHeaders)
                    {
                        // They could not be added to the headers directly
                        if (kvp.Key == Constants.RequestParameters.ContentMD5
                            || kvp.Key == Constants.RequestParameters.ContentRange)
                        {
                            httpRequest.Content.Headers.Add(kvp.Key, kvp.Value);
                        }
                        else
                        {
                            httpRequest.Headers.TryAddWithoutValidation(kvp.Key, kvp.Value);
                        }
                    }

                    // If we are retrieving a stream, we should return without reading the entire response
                    HttpCompletionOption completionOption = isStream ?
                        HttpCompletionOption.ResponseHeadersRead :
                        HttpCompletionOption.ResponseContentRead;

                    Debug.WriteLine(string.Format("RequestUri: {0}", httpRequest.RequestUri));

                    HttpClient client = GetClient(request);

                    // Not disposing the reponse since it will affect stream response 
                    var response = await client.SendAsync(httpRequest, completionOption).ConfigureAwait(false);

                    //need to wait for Retry-After seconds and then retry request
                    var retryAfterHeader = response.Headers.RetryAfter;

                    // If we get a 429 error code and this is not a multi part request (meaning a file upload, which cannot be retried
                    // because the stream cannot be reset) and we haven't exceeded the number of allowed retries, then retry the request.
                    // If we get a 202 code and has a retry-after header, we will retry after
                    if (
                        ((response.StatusCode == TooManyRequests && !isMultiPartRequest)
                        ||
                        (response.StatusCode == HttpStatusCode.Accepted && retryAfterHeader != null)) 
                        && retryCounter++ < RetryLimit)
                    {
                        TimeSpan delay = expBackoff.GetRetryTimeout(retryCounter);                        <commit_msg>Retry API requests on 5xx errors (#556)<commit_after>using Box.V2.Config;
using Box.V2.Utility;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace Box.V2.Request
{
    public class HttpRequestHandler : IRequestHandler
    {
        const HttpStatusCode TooManyRequests = (HttpStatusCode)429;
        const int RetryLimit = 5;

        public async Task<IBoxResponse<T>> ExecuteAsync<T>(IBoxRequest request)
            where T : class
        {
            // Need to account for special cases when the return type is a stream
            bool isStream = typeof(T) == typeof(Stream);
            var retryCounter = 0;
            ExponentialBackoff expBackoff = new ExponentialBackoff();

            try
            {
                // TODO: yhu@ better handling of different request
                var isMultiPartRequest = request.GetType() == typeof(BoxMultiPartRequest);
                var isBinaryRequest = request.GetType() == typeof(BoxBinaryRequest);

                while (true)
                {
                    HttpRequestMessage httpRequest = null;

                    if (isMultiPartRequest)
                    {
                        httpRequest = BuildMultiPartRequest(request as BoxMultiPartRequest);
                    }
                    else if (isBinaryRequest)
                    {
                        httpRequest = BuildBinaryRequest(request as BoxBinaryRequest);
                    }
                    else
                    {
                        httpRequest = BuildRequest(request);
                    }

                    // Add headers
                    foreach (var kvp in request.HttpHeaders)
                    {
                        // They could not be added to the headers directly
                        if (kvp.Key == Constants.RequestParameters.ContentMD5
                            || kvp.Key == Constants.RequestParameters.ContentRange)
                        {
                            httpRequest.Content.Headers.Add(kvp.Key, kvp.Value);
                        }
                        else
                        {
                            httpRequest.Headers.TryAddWithoutValidation(kvp.Key, kvp.Value);
                        }
                    }

                    // If we are retrieving a stream, we should return without reading the entire response
                    HttpCompletionOption completionOption = isStream ?
                        HttpCompletionOption.ResponseHeadersRead :
                        HttpCompletionOption.ResponseContentRead;

                    Debug.WriteLine(string.Format("RequestUri: {0}", httpRequest.RequestUri));

                    HttpClient client = GetClient(request);

                    // Not disposing the reponse since it will affect stream response 
                    var response = await client.SendAsync(httpRequest, completionOption).ConfigureAwait(false);

                    //need to wait for Retry-After seconds and then retry request
                    var retryAfterHeader = response.Headers.RetryAfter;

                    // If we get a retryable/transient error code and this is not a multi part request (meaning a file upload, which cannot be retried
                    // because the stream cannot be reset) and we haven't exceeded the number of allowed retries, then retry the request.
                    // If we get a 202 code and has a retry-after header, we will retry after
                    if (!isMultiPartRequest &&
                        (response.StatusCode == TooManyRequests
                        ||
                        response.StatusCode == HttpStatusCode.InternalServerError
                        ||
                        response.StatusCode == HttpStatusCode.GatewayTimeout
                        ||
                        response.StatusCode == HttpStatusCode.BadGateway
                        ||
                        (response.StatusCode == HttpStatusCode.Accepted && retryAfterHeader != null)) 
                        && retryCounter++ < RetryLimit)
                    {
                        TimeSpan delay = expBackoff.GetRetryTimeout(retryCounter);                        
{'fraction_non_alphanumeric': 0.06356033452807647, 'fraction_numerical': 0.003942652329749104, 'mean_word_length': 1.3965073003149155, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5432458', 'n_tokens_mistral': 1852, 'n_tokens_neox': 1726, 'n_words': 524}