public static Task CopyToAsync(this Stream stream, Stream destination, int bufferSize, CancellationToken cancellationToken) { byte[] buffer = new byte[bufferSize]; int bytesRead = 0; return(InternalExtensions.WhileAsync(() => stream.ReadAsync(buffer, 0, bufferSize, cancellationToken).OnSuccess(delegate(Task <int> readTask) { bytesRead = readTask.Result; return bytesRead > 0; }), delegate { cancellationToken.ThrowIfCancellationRequested(); return destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).OnSuccess(delegate(Task _) { cancellationToken.ThrowIfCancellationRequested(); }); })); }
public Task <Tuple <HttpStatusCode, string> > ExecuteAsync(HttpRequest httpRequest, IProgress <ParseUploadProgressEventArgs> uploadProgress, IProgress <ParseDownloadProgressEventArgs> downloadProgress, CancellationToken cancellationToken) { uploadProgress = uploadProgress ?? new Progress <ParseUploadProgressEventArgs>(); downloadProgress = downloadProgress ?? new Progress <ParseDownloadProgressEventArgs>(); var httpMethod = new HttpMethod(httpRequest.Method); var message = new HttpRequestMessage(httpMethod, httpRequest.Uri); // Fill in zero-length data if method is post. Stream data = httpRequest.Data; if (httpRequest.Data == null && httpRequest.Method.ToLower().Equals("post")) { data = new MemoryStream(new byte[0]); } if (data != null) { message.Content = new StreamContent(data); } if (httpRequest.Headers != null) { foreach (var header in httpRequest.Headers) { if (HttpContentHeaders.Contains(header.Key)) { message.Content.Headers.Add(header.Key, header.Value); } else { message.Headers.Add(header.Key, header.Value); } } } // Avoid aggressive caching on Windows Phone 8.1. message.Headers.Add("Cache-Control", "no-cache"); message.Headers.IfModifiedSince = DateTimeOffset.UtcNow; // TODO: (richardross) investigate progress here, maybe there's something we're missing in order to support this. uploadProgress.Report(new ParseUploadProgressEventArgs { Progress = 0 }); return(_client.SendAsync(message, HttpCompletionOption.ResponseHeadersRead, cancellationToken) .ContinueWith(httpMessageTask => { var response = httpMessageTask.Result; uploadProgress.Report(new ParseUploadProgressEventArgs { Progress = 1 }); return response.Content.ReadAsStreamAsync().ContinueWith(streamTask => { var resultStream = new MemoryStream(); var responseStream = streamTask.Result; int bufferSize = 4096; byte[] buffer = new byte[bufferSize]; int bytesRead = 0; long totalLength = -1; long readSoFar = 0; try { totalLength = responseStream.Length; } catch (NotSupportedException) { } return InternalExtensions.WhileAsync(() => { return responseStream.ReadAsync(buffer, 0, bufferSize, cancellationToken).OnSuccess( readTask => { bytesRead = readTask.Result; return bytesRead > 0; }); }, () => { cancellationToken.ThrowIfCancellationRequested(); return resultStream.WriteAsync(buffer, 0, bytesRead, cancellationToken).OnSuccess(_ => { cancellationToken.ThrowIfCancellationRequested(); readSoFar += bytesRead; if (totalLength > -1) { downloadProgress.Report( new ParseDownloadProgressEventArgs { Progress = 1.0 * readSoFar / totalLength }); } }); }).ContinueWith(_ => { responseStream.Dispose(); return _; }, cancellationToken).Unwrap().OnSuccess(_ => { // If getting stream size is not supported, then report download only once. if (totalLength == -1) { downloadProgress.Report(new ParseDownloadProgressEventArgs { Progress = 1.0 }); } // Assume UTF-8 encoding. var resultAsArray = resultStream.ToArray(); var resultString = Encoding.UTF8.GetString(resultAsArray, 0, resultAsArray.Length); resultStream.Dispose(); return new Tuple <HttpStatusCode, string>(response.StatusCode, resultString); }); }, cancellationToken); }, cancellationToken).Unwrap().Unwrap()); }