public async Task <HttpWebResponse> GetDownloadResponseAsync([NotNull] string driveId, [NotNull] string itemId, long?from, CancellationToken cancellationToken)
        {
            var downloadUrl = GetDownloadUrl(driveId, itemId);
            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);
        }
        public async Task <Item> UploadFileAsync([NotNull] string driveId, [NotNull] string parentId, [NotNull] string name, [NotNull] Stream input, CancellationToken cancellationToken)
        {
            // Create upload session
            var request = CreateRequest($"drives/{driveId}/items/{parentId}:/{name}:/upload.createSession");

            request.AddBody(
                new
            {
                Item = new Item
                {
                    Name             = name,
                    ConflictBehavior = ConflictBehavior.Replace,
                },
            });
            var deserializer = new JsonDeserializer();
            var response     = await _restClient.Execute <UploadSession>(request, cancellationToken);

            var uploadSession = response.Data;
            var inputLength   = input.Length;
            var sessionUri    = uploadSession.UploadUrl;

            // Upload the data
            using (var uploadClient = CreateClient())
            {
                uploadClient.IgnoreResponseStatusCode = true;
                int    blockSize = 262144; // Info from Google PUT error message
                var    buffer    = new byte[blockSize];
                byte[] temp      = null;

                // As long as we have an upload session, upload the data...
                while (uploadSession != null)
                {
                    IRestResponse fragmentUploadResponse = null;

                    // Upload all data requested by the given ranges
                    var ranges = uploadSession.ToHttpRange();
                    foreach (var range in ranges.Normalize(input.Length))
                    {
                        // Split the data to upload into blocks (to keep memory usage small)
                        int size;
                        var length = range.Length;
                        for (long i = 0; i != length; i += size)
                        {
                            size = (int)Math.Min(range.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(range.From + i, range.From + 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(), inputLength));
                            requestUploadChunk.AddParameter(string.Empty, temp, ParameterType.RequestBody, "application/octet-stream");

                            fragmentUploadResponse = await uploadClient.Execute(requestUploadChunk, cancellationToken);

                            if (!fragmentUploadResponse.IsSuccess)
                            {
                                throw new WebException(fragmentUploadResponse.StatusDescription, WebExceptionStatus.UnknownError);
                            }
                        }
                    }

                    if (fragmentUploadResponse != null)
                    {
                        // Deserialize the data into a JObject
                        var data = deserializer.Deserialize <JObject>(fragmentUploadResponse);
                        if (data.Property("id") == null)
                        {
                            // Convert to a new UploadSession when we don't have the "id" property
                            uploadSession = data.ToObject <UploadSession>();
                        }
                        else
                        {
                            // Otherwise return the data (which means: we just uploaded the last chunk)
                            var item = data.ToObject <Item>();
                            return(item);
                        }
                    }
                    else
                    {
                        // should never happen...
                        uploadSession = null;
                    }
                }
            }

            // We didn't receive an "Item" object in the last upload chunk: Just query it
            // from the server ourselves.
            var result = await GetChildItemAsync(driveId, parentId, name, cancellationToken);

            if (result == null)
            {
                throw new InvalidOperationException();
            }
            return(result);
        }
        public async Task<Item> UploadFileAsync([NotNull] string driveId, [NotNull] string parentId, [NotNull] string name, [NotNull] Stream input, CancellationToken cancellationToken)
        {
            // Create upload session
            var request = CreateRequest($"drives/{driveId}/items/{parentId}:/{name}:/upload.createSession");
            request.AddBody(
                new
                {
                    Item = new Item
                    {
                        Name = name,
                        ConflictBehavior = ConflictBehavior.Replace,
                    },
                });
            var deserializer = new JsonDeserializer();
            var response = await _restClient.Execute<UploadSession>(request, cancellationToken);
            var uploadSession = response.Data;
            var inputLength = input.Length;
            var sessionUri = uploadSession.UploadUrl;

            // Upload the data
            using (var uploadClient = CreateClient())
            {
                uploadClient.IgnoreResponseStatusCode = true;
                int blockSize = 262144; // Info from Google PUT error message
                var buffer = new byte[blockSize];
                byte[] temp = null;

                // As long as we have an upload session, upload the data...
                while (uploadSession != null)
                {
                    IRestResponse fragmentUploadResponse = null;

                    // Upload all data requested by the given ranges
                    var ranges = uploadSession.ToHttpRange();
                    foreach (var range in ranges.Normalize(input.Length))
                    {
                        // Split the data to upload into blocks (to keep memory usage small)
                        int size;
                        var length = range.Length;
                        for (long i = 0; i != length; i += size)
                        {
                            size = (int)Math.Min(range.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(range.From + i, range.From + 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(), inputLength));
                            requestUploadChunk.AddParameter(string.Empty, temp, ParameterType.RequestBody, "application/octet-stream");

                            fragmentUploadResponse = await uploadClient.Execute(requestUploadChunk, cancellationToken);
                            if (!fragmentUploadResponse.IsSuccess)
                                throw new WebException(fragmentUploadResponse.StatusDescription, WebExceptionStatus.UnknownError);
                        }
                    }

                    if (fragmentUploadResponse != null)
                    {
                        // Deserialize the data into a JObject
                        var data = deserializer.Deserialize<JObject>(fragmentUploadResponse);
                        if (data.Property("id") == null)
                        {
                            // Convert to a new UploadSession when we don't have the "id" property
                            uploadSession = data.ToObject<UploadSession>();
                        }
                        else
                        {
                            // Otherwise return the data (which means: we just uploaded the last chunk)
                            var item = data.ToObject<Item>();
                            return item;
                        }
                    }
                    else
                    {
                        // should never happen...
                        uploadSession = null;
                    }
                }
            }

            // We didn't receive an "Item" object in the last upload chunk: Just query it
            // from the server ourselves.
            var result = await GetChildItemAsync(driveId, parentId, name, cancellationToken);
            if (result == null)
                throw new InvalidOperationException();
            return result;
        }
 public async Task<HttpWebResponse> GetDownloadResponseAsync([NotNull] string driveId, [NotNull] string itemId, long? from, CancellationToken cancellationToken)
 {
     var downloadUrl = GetDownloadUrl(driveId, itemId);
     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;
 }