/// <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; }