Canceling async web download
===

Can someone please inspect this code and tell me if everything is as it should be ...  Intention is as following: program will connect to web service and wait for data to arrive in async manner with cancellation support. Did I code this the right way or are any flaws in there? Thanks for any response! : )

    public static class WebRequestExtensions
    {
        public static Task<string> DownloadStringAsync(
            string url,
            TimeSpan requestTimeout,
            TimeSpan readWriteTimeout,
            CancellationToken ct)
        {
            if (String.IsNullOrEmpty(url))
                throw new ArgumentException("url");
    
            var tcs = new TaskCompletionSource<string>();
            Iterate(FetchAsyncCore(url, (int) requestTimeout.TotalMilliseconds, (int) readWriteTimeout.TotalMilliseconds, ct, tcs), tcs);
    
            return tcs.Task;
        }
    
        private static void Iterate<TResult>(IEnumerable<Task> asyncIterator, TaskCompletionSource<TResult> tcs)
        {
            var enumerator = asyncIterator.GetEnumerator();
            Action<Task> recursiveBody = null;
            recursiveBody = completedTask =>
            {
                if (completedTask != null && completedTask.IsFaulted)
                {
                    tcs.TrySetException(completedTask.Exception.InnerExceptions);
                    enumerator.Dispose();
                }
                else if (enumerator.MoveNext())
                {
                    enumerator.Current.ContinueWith(recursiveBody, TaskContinuationOptions.ExecuteSynchronously);
                }
                else
                {
                    enumerator.Dispose();
                }
            };
    
            recursiveBody(null);
        }
    
        private static IEnumerable<Task> FetchAsyncCore(
            string url,
            int requestTimeout,
            int readWriteTimeout,
            CancellationToken ct,
            TaskCompletionSource<string> tcs)
        {
            HttpWebRequest request;
            try
            {
                request = (HttpWebRequest) WebRequest.Create(url);
                request.Timeout = requestTimeout;
                request.ReadWriteTimeout = readWriteTimeout;
    
                ct.Register(request.Abort);
            }
            catch (Exception ex)
            {
                tcs.SetException(ex);
                yield break;
            }
    
            var getResponse = Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
            yield return getResponse;
    
            if (ct.IsCancellationRequested)
            {
                tcs.SetCanceled();
                yield break;
            }
    
            using (var response = (HttpWebResponse) getResponse.Result)
            using (var responseStream = response.GetResponseStream())
            using (var output = new MemoryStream())
            {
                var buffer = new byte[response.ContentLength > 0 ? response.ContentLength : 0x100];
                while (true)
                {
                    if (ct.IsCancellationRequested)
                    {
                        tcs.SetCanceled();
                        yield break;
                    }
    
                    var read = Task<int>.Factory.FromAsync(responseStream.BeginRead, responseStream.EndRead, buffer, 0,
                                                            buffer.Length, null);
                    yield return read;
                    if (read.Result == 0) break;
                    output.Write(buffer, 0, read.Result);
                }
    
                tcs.SetResult(Encoding.UTF8.GetString(output.ToArray()));
            }
        }
    }

