Index: Src/GoogleApis/Apis/[Media]/Upload/ResumableUpload.cs =================================================================== --- a/Src/GoogleApis/Apis/[Media]/Upload/ResumableUpload.cs +++ b/Src/GoogleApis/Apis/[Media]/Upload/ResumableUpload.cs @@ -45,16 +45,16 @@ { #region Constants - /// The class logger. + /// The class logger. private static readonly ILogger logger = ApplicationContext.Logger.ForType>(); private const int KB = 0x400; private const int MB = 0x100000; - /// Minimum chunk size (except the last one). Default value is 256*KB. + /// Minimum chunk size (except the last one). Default value is 256*KB. public const int MinimumChunkSize = 256 * KB; - /// Default chunk size. Default value is 10*MB. + /// Default chunk size. Default value is 10*MB. public const int DefaultChunkSize = 10 * MB; /// @@ -63,25 +63,25 @@ /// internal int BufferSize = 4 * KB; - /// Indicates the stream's size is unknown. + /// Indicates the stream's size is unknown. private const int UnknownSize = -1; - /// The mime type for the encoded JSON body. + /// The mime type for the encoded JSON body. private const string JsonMimeType = "application/json; charset=UTF-8"; - /// Payload description headers, describing the content itself. + /// Payload description headers, describing the content itself. private const string PayloadContentTypeHeader = "X-Upload-Content-Type"; - /// Payload description headers, describing the content itself. + /// Payload description headers, describing the content itself. private const string PayloadContentLengthHeader = "X-Upload-Content-Length"; - /// Specify the type of this upload (this class supports resumable only). + /// Specify the type of this upload (this class supports resumable only). private const string UploadType = "uploadType"; - /// The uploadType parameter value for resumable uploads. + /// The uploadType parameter value for resumable uploads. private const string Resumable = "resumable"; - /// Content-Range header value for the body upload of zero length files. + /// Content-Range header value for the body upload of zero length files. private const string ZeroByteContentRangeHeader = "bytes */0"; #endregion // Constants @@ -93,7 +93,7 @@ /// /// The client service. /// The path for this media upload method. - /// The Http method to start this upload. + /// The HTTP method to start this upload. /// The stream containing the content to upload. /// Content type of the content to be uploaded. /// @@ -121,22 +121,22 @@ #region Properties - /// Gets or sets the service. + /// Gets or sets the service. public IClientService Service { get; private set; } - /// + /// /// Gets or sets the path of the method (combined with ) to produce /// absolute Uri. /// public string Path { get; private set; } - /// Gets or sets the Http method of this upload (used to initialize the upload). + /// Gets or sets the HTTP method of this upload (used to initialize the upload). public string HttpMethod { get; private set; } - /// Gets or sets the stream to upload. + /// Gets or sets the stream to upload. public Stream ContentStream { get; private set; } - /// Gets or sets the stream's Content-Type. + /// Gets or sets the stream's Content-Type. public string ContentType { get; private set; } /// @@ -151,31 +151,31 @@ /// private byte[] LastMediaRequest { get; set; } - /// Gets or sets cached byte which indicates if end of stream has been reached. + /// Gets or sets cached byte which indicates if end of stream has been reached. private byte[] CachedByte { get; set; } - /// Gets or sets the last request length. + /// Gets or sets the last request length. private int LastMediaLength { get; set; } - /// + /// /// Gets or sets the resumable session Uri. /// See https://developers.google.com/drive/manage-uploads#save-session-uri" for more details. /// private Uri UploadUri { get; set; } - /// Gets or sets the amount of bytes the server had received so far. + /// Gets or sets the amount of bytes the server had received so far. private long BytesServerReceived { get; set; } - /// Gets or sets the amount of bytes the client had sent so far. + /// Gets or sets the amount of bytes the client had sent so far. private long BytesClientSent { get; set; } - /// Gets or sets the body of this request. + /// Gets or sets the body of this request. public TRequest Body { get; set; } [VisibleForTestOnly] internal int chunkSize = DefaultChunkSize; - /// + /// /// Gets or sets the size of each chunk sent to the server. /// Chunks (except the last chunk) must be a multiple of to be compatible with /// Google upload servers. @@ -197,12 +197,12 @@ #region Events - /// Event called whenever the progress of the upload changes. + /// Event called whenever the progress of the upload changes. public event Action ProgressChanged; #endregion //Events - #region Error handling (Expcetion and 5xx) + #region Error handling (Exception and 5xx) /// /// Callback class that is invoked on abnormal response or an exception. @@ -214,7 +214,7 @@ { private ResumableUpload Owner { get; set; } - /// + /// /// Constructs a new callback and register it as unsuccessful response handler and exception handler on the /// configurable message handler. /// @@ -225,8 +225,9 @@ Owner.Service.HttpClient.MessageHandler.ExceptionHandlers.Add(this); } - public bool HandleResponse(HandleUnsuccessfulResponseArgs args) + public Task HandleResponseAsync(HandleUnsuccessfulResponseArgs args) { + var result = false; var statusCode = (int)args.Response.StatusCode; // handle the error if and only if all the following conditions occur: // - there is going to be an actual retry @@ -236,18 +237,25 @@ // - we got a 5xx server error. if (args.SupportsRetry && args.Request.RequestUri.Equals(Owner.UploadUri) && statusCode / 100 == 5) { - return OnServerError(args.Request); + result = OnServerError(args.Request); } - return false; + + TaskCompletionSource tcs = new TaskCompletionSource(); + tcs.SetResult(result); + return tcs.Task; } - public bool HandleException(HandleExceptionArgs args) + public Task HandleExceptionAsync(HandleExceptionArgs args) { - return args.SupportsRetry && !args.CancellationToken.IsCancellationRequested && + var result = args.SupportsRetry && !args.CancellationToken.IsCancellationRequested && args.Request.RequestUri.Equals(Owner.UploadUri) ? OnServerError(args.Request) : false; + + TaskCompletionSource tcs = new TaskCompletionSource(); + tcs.SetResult(result); + return tcs.Task; } - /// Changes the request in order to resume the interrupted upload. + /// Changes the request in order to resume the interrupted upload. private bool OnServerError(HttpRequestMessage request) { // clear all headers and set Content-Range and Content-Length headers @@ -269,7 +277,7 @@ #region Progress Monitoring - /// Class that communicates the progress of resumable uploads to a container. + /// Class that communicates the progress of resumable uploads to a container. private class ResumableUploadProgress : IUploadProgress { /// @@ -375,7 +383,7 @@ return Progress; } - /// Uploads the content asynchronously to the server. + /// Uploads the content asynchronously to the server. /// /// In case the upload fails the task will not be completed. In that case the task's /// property will bet set, or its @@ -386,7 +394,7 @@ return UploadAsync(CancellationToken.None); } - /// Uploads the content asynchronously to the server. + /// Uploads the content asynchronously to the server. /// The cancellation token to cancel a request in the middle. public Task UploadAsync(CancellationToken cancellationToken) { @@ -436,7 +444,7 @@ { } - /// + /// /// Uploads the next chunk of data to the server. /// /// @@ -485,7 +493,7 @@ throw new GoogleApiException(Service.Name, error.ToString()); } - /// A callback when the media was uploaded successfully. + /// A callback when the media was uploaded successfully. private void MediaCompleted(HttpResponseMessage response) { logger.Debug("MediaUpload[{0}] - media was uploaded successfully", UploadUri); @@ -496,7 +504,7 @@ LastMediaRequest = null; } - /// Prepares the given request with the next chunk in case the steam length is unknown. + /// Prepares the given request with the next chunk in case the steam length is unknown. private void PrepareNextChunkUnknownSize(HttpRequestMessage request, Stream stream, CancellationToken cancellationToken) { @@ -564,7 +572,7 @@ request.Content = byteArrayContent; } - /// Prepares the given request with the next chunk in case the steam length is known. + /// Prepares the given request with the next chunk in case the steam length is known. private void PrepareNextChunkKnownSize(HttpRequestMessage request, Stream stream, CancellationToken cancellationToken) { @@ -603,7 +611,7 @@ LastMediaLength = chunkSize; } - /// Returns the next byte index need to be sent. + /// Returns the next byte index need to be sent. private long GetNextByte(string range) { return long.Parse(range.Substring(range.IndexOf('-') + 1)) + 1; @@ -642,7 +650,7 @@ } } - /// Creates a request to initialize a request. + /// Creates a request to initialize a request. private HttpRequestMessage CreateInitializeRequest() { var builder = new RequestBuilder() @@ -722,7 +730,7 @@ /// /// The client service. /// The path for this media upload method. - /// The Http method to start this upload. + /// The HTTP method to start this upload. /// The stream containing the content to upload. /// Content type of the content to be uploaded. /// @@ -752,14 +760,14 @@ #region Events - /// Event which is called when the response metadata is processed. + /// Event which is called when the response metadata is processed. public event Action ResponseReceived; #endregion // Events #region Overrides - /// Process the response body + /// Process the response body protected override void ProcessResponse(HttpResponseMessage response) { base.ProcessResponse(response);