/// <summary>
        /// Upload a file
        /// </summary>
        /// <param name="folderId">The target <see cref="File"/> (folder) ID to upload to</param>
        /// <param name="name">The new file name</param>
        /// <param name="input">The data to upload</param>
        /// <param name="mimeType">The mime type of the file to upload</param>
        /// <param name="cancellationToken"></param>
        /// <returns>The <see cref="Task"/></returns>
        public async Task UploadAsync([NotNull] string folderId, [NotNull] string name, [NotNull] Stream input, [NotNull] string mimeType, CancellationToken cancellationToken)
        {
            using (var uploadClient = CreateClient())
            {
                var length = input.Length;

                var newItem = new File()
                {
                    Title = name,
                    MimeType = mimeType,
                    Parents = new List<ParentReference>
                    {
                        new ParentReference()
                        {
                            Id = folderId
                        }
                    },
                };

                var requestStartResumableSession = CreateRequest($"/{DriveUploadApiPath}files", Method.POST);
                requestStartResumableSession.AddQueryParameter("uploadType", "resumable");
                requestStartResumableSession.AddHeader("X-Upload-Content-Type", mimeType);
                requestStartResumableSession.AddHeader("X-Upload-Content-Length", length);
                requestStartResumableSession.AddBody(newItem);
                var responseStartResumableSession = await uploadClient.Execute(requestStartResumableSession, cancellationToken);
                var sessionUri = responseStartResumableSession.ResponseUri.OriginalString;

                uploadClient.IgnoreResponseStatusCode = true;
                int blockSize = 262144; // Info from Google PUT error message
                var buffer = new byte[blockSize];
                byte[] temp = null;
                int size;
                for (long i = 0; i != length; i += size)
                {
                    size = (int)Math.Min(length, blockSize);

                    var readSize = input.Read(buffer, 0, size);
                    if (readSize == 0)
                        throw new InvalidOperationException($"Failed to read {size} bytes from position {i}");

                    size = readSize;
                    var requestRange = new HttpRange("bytes", new HttpRangeItem(i, i + size - 1));

                    if (temp == null || temp.Length != size)
                        temp = new byte[size];
                    Array.Copy(buffer, temp, size);

                    var requestUploadChunk = CreateRequest(sessionUri, Method.PUT);
                    requestUploadChunk.AddHeader("Content-Range", requestRange.ToString(requestRange.RangeItems.Single(), length));
                    requestUploadChunk.AddParameter(string.Empty, temp, ParameterType.RequestBody, mimeType);

                    var responseUploadChunk = await uploadClient.Execute(requestUploadChunk, cancellationToken);
                    if (!responseUploadChunk.IsSuccess && responseUploadChunk.StatusCode != (HttpStatusCode)308)
                        throw new WebException(responseUploadChunk.StatusDescription, WebExceptionStatus.UnknownError);
                }
            }
        }
 /// <summary>
 /// Get a <see cref="HttpWebResponse"/> to download a <see cref="File"/>
 /// </summary>
 /// <param name="file">The <see cref="File"/> to download</param>
 /// <param name="from">The offset where the download starts from</param>
 /// <param name="cancellationToken"></param>
 /// <returns>The <see cref="HttpWebResponse"/> used to download the file</returns>
 public async Task<HttpWebResponse> GetDownloadResponseAsync(File file, long? from, CancellationToken cancellationToken)
 {
     var downloadUrl = GetDownloadUrl(file);
     var request = await _restClientFactory.CreateWebRequest(new Uri(downloadUrl));
     if (from != null)
     {
         if (_addRangeMethod != null)
         {
             _addRangeMethod.Invoke(request, new object[] { from.Value });
         }
         else
         {
             var range = new HttpRange("bytes", new HttpRangeItem(from, null));
             request.Headers[HttpRequestHeader.Range] = range.ToString();
         }
     }
     var response = (HttpWebResponse)await Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
     return response;
 }