From e8f3e77b93e4985114a0a5e32e4b9ef30a25acaf Mon Sep 17 00:00:00 2001 From: Chad Burnette Date: Thu, 19 Jan 2017 14:39:50 -0500 Subject: [PATCH] fix so request is not retried for a 429 (rate limit) error on file uploads (multipart request). The reason for this is that the stream has already been consumed by the time the error is received and there is not enough information about the stream to reset it. Added a ResponseHeaders field to BoxException and set that value where appropriate (all response processing). --- Box.V2/Exceptions/BoxException.cs | 6 ++++++ Box.V2/Extensions/BoxResponseExtensions.cs | 14 +++++++------- Box.V2/Request/HttpRequestHandler.cs | 14 +++++++++----- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/Box.V2/Exceptions/BoxException.cs b/Box.V2/Exceptions/BoxException.cs index e07065726..faf22e5f0 100644 --- a/Box.V2/Exceptions/BoxException.cs +++ b/Box.V2/Exceptions/BoxException.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; +using System.Net.Http.Headers; using System.Text; namespace Box.V2.Exceptions @@ -47,6 +48,11 @@ public BoxException(string message, BoxError error) : base(message) /// Error parsed from the message returned by the API /// public BoxError Error { get; set; } + + /// + /// Response headers returned by the API + /// + public HttpResponseHeaders ResponseHeaders { get; set; } } diff --git a/Box.V2/Extensions/BoxResponseExtensions.cs b/Box.V2/Extensions/BoxResponseExtensions.cs index 89a265155..601b4ab64 100644 --- a/Box.V2/Extensions/BoxResponseExtensions.cs +++ b/Box.V2/Extensions/BoxResponseExtensions.cs @@ -39,16 +39,16 @@ public static IBoxResponse ParseResults(this IBoxResponse response, IBo if (errorMsg != null) { var err = new BoxError() { Code = response.StatusCode.ToString(), Description = "Forbidden", Message = errorMsg.ToString() }; - throw new BoxException(err.Message, err); + throw new BoxException(err.Message, err) { StatusCode = response.StatusCode, ResponseHeaders = response.Headers }; } else if (!string.IsNullOrWhiteSpace(response.ContentString)) { response.Error = converter.Parse(response.ContentString); - throw new BoxException(response.ContentString, response.Error) {StatusCode = response.StatusCode}; + throw new BoxException(response.ContentString, response.Error) { StatusCode = response.StatusCode, ResponseHeaders = response.Headers }; } else { - throw new BoxException("Forbidden"); + throw new BoxException("Forbidden") { StatusCode = response.StatusCode, ResponseHeaders = response.Headers }; } default: if (!string.IsNullOrWhiteSpace(response.ContentString)) @@ -61,11 +61,11 @@ public static IBoxResponse ParseResults(this IBoxResponse response, IBo if (response is IBoxResponse) { BoxPreflightCheckConflictError err = converter.Parse>(response.ContentString); - exToThrow = new BoxPreflightCheckConflictException(response.ContentString, err); + exToThrow = new BoxPreflightCheckConflictException(response.ContentString, err) { StatusCode = response.StatusCode, ResponseHeaders = response.Headers }; } else { BoxConflictError error = converter.Parse>(response.ContentString); - exToThrow = new BoxConflictException(response.ContentString, error); + exToThrow = new BoxConflictException(response.ContentString, error) { StatusCode = response.StatusCode, ResponseHeaders = response.Headers }; } break; @@ -80,10 +80,10 @@ public static IBoxResponse ParseResults(this IBoxResponse response, IBo } throw exToThrow == null ? - new BoxException(response.ContentString, response.Error) { StatusCode = response.StatusCode } : + new BoxException(response.ContentString, response.Error) { StatusCode = response.StatusCode, ResponseHeaders = response.Headers } : exToThrow; } - throw new BoxException(response.ContentString) { StatusCode = response.StatusCode }; + throw new BoxException(response.ContentString) { StatusCode = response.StatusCode, ResponseHeaders = response.Headers }; } return response; } diff --git a/Box.V2/Request/HttpRequestHandler.cs b/Box.V2/Request/HttpRequestHandler.cs index 38a006a47..5691e1505 100644 --- a/Box.V2/Request/HttpRequestHandler.cs +++ b/Box.V2/Request/HttpRequestHandler.cs @@ -24,11 +24,13 @@ public async Task> ExecuteAsync(IBoxRequest request) try { - while(true) + var isMultiPartRequest = request.GetType() == typeof(BoxMultiPartRequest); + + while (true) { - HttpRequestMessage httpRequest = request.GetType() == typeof(BoxMultiPartRequest) ? - BuildMultiPartRequest(request as BoxMultiPartRequest) : - BuildRequest(request); + HttpRequestMessage httpRequest = isMultiPartRequest ? + BuildMultiPartRequest(request as BoxMultiPartRequest) : + BuildRequest(request); // Add headers foreach (var kvp in request.HttpHeaders) @@ -55,7 +57,9 @@ public async Task> ExecuteAsync(IBoxRequest request) HttpResponseMessage response = await client.SendAsync(httpRequest, completionOption).ConfigureAwait(false); - if(response.StatusCode == TooManyRequests && numRetries-- > 0) + // 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((response.StatusCode == TooManyRequests && !isMultiPartRequest) && numRetries-- > 0) { //need to wait for Retry-After seconds and then retry request var retryAfterHeader = response.Headers.RetryAfter;