Пример #1
0
        protected virtual async Task <byte[]> DownloadAsync(string url, CancellationToken token, HttpClient client, Action <DownloadProgress> progressAction, TaskParameter parameters)
        {
            using (var cancelHeadersToken = new CancellationTokenSource())
            {
                cancelHeadersToken.CancelAfter(TimeSpan.FromSeconds(Configuration.HttpHeadersTimeout));

                using (var linkedHeadersToken = CancellationTokenSource.CreateLinkedTokenSource(token, cancelHeadersToken.Token))
                {
                    try
                    {
                        using (var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, linkedHeadersToken.Token).ConfigureAwait(false))
                        {
                            if (!response.IsSuccessStatusCode)
                            {
                                throw new HttpRequestException(response.StatusCode.ToString());
                            }

                            if (response.Content == null)
                            {
                                throw new HttpRequestException("No Content");
                            }

                            var mediaType = response.Content.Headers?.ContentType?.MediaType;
                            if (!string.IsNullOrWhiteSpace(mediaType) && !mediaType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
                            {
                                if (InvalidContentTypes.Any(v => mediaType.StartsWith(v, StringComparison.OrdinalIgnoreCase)))
                                {
                                    throw new HttpRequestException($"Invalid response content type ({mediaType})");
                                }
                            }

                            ModifyParametersAfterResponse(response, parameters);

                            using (var cancelReadTimeoutToken = new CancellationTokenSource())
                            {
                                var readTimeoutToken = cancelReadTimeoutToken.Token;
                                cancelReadTimeoutToken.CancelAfter(TimeSpan.FromSeconds(Configuration.HttpReadTimeout));

                                int total             = (int)(response.Content.Headers.ContentLength ?? -1);
                                var canReportProgress = progressAction != null;

                                try
                                {
                                    using (var outputStream = new MemoryStream())
                                        using (var sourceStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
                                        {
                                            int totalRead = 0;
                                            var buffer    = new byte[Configuration.HttpReadBufferSize];

                                            int read = 0;
                                            while ((read = await sourceStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                                            {
                                                token.ThrowIfCancellationRequested();
                                                readTimeoutToken.ThrowIfCancellationRequested();
                                                outputStream.Write(buffer, 0, read);
                                                totalRead += read;

                                                if (canReportProgress)
                                                {
                                                    progressAction(new DownloadProgress()
                                                    {
                                                        Total = total, Current = totalRead
                                                    });
                                                }
                                            }

                                            return(outputStream.ToArray());
                                        }
                                }
                                catch (OperationCanceledException)
                                {
                                    if (cancelReadTimeoutToken.IsCancellationRequested)
                                    {
                                        throw new Exception("HttpReadTimeout");
                                    }
                                    else
                                    {
                                        throw;
                                    }
                                }
                            }
                        }
                    }
                    catch (OperationCanceledException)
                    {
                        if (cancelHeadersToken.IsCancellationRequested)
                        {
                            throw new Exception("HttpHeadersTimeout");
                        }
                        else
                        {
                            throw;
                        }
                    }
                }
            }
        }
Пример #2
0
        protected virtual async Task <byte[]> DownloadAsync(string url, CancellationToken token, HttpClient client, TaskParameter parameters, DownloadInformation downloadInformation)
        {
            if (!parameters.Preload)
            {
                await Task.Delay(25).ConfigureAwait(false);

                token.ThrowIfCancellationRequested();
            }

            var progressAction = parameters.OnDownloadProgress;

            using (var httpHeadersTimeoutTokenSource = new CancellationTokenSource())
                using (var headersTimeoutTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token, httpHeadersTimeoutTokenSource.Token))
                {
                    httpHeadersTimeoutTokenSource.CancelAfter(TimeSpan.FromSeconds(Configuration.HttpHeadersTimeout));

                    try
                    {
                        var headerTimeoutToken = headersTimeoutTokenSource.Token;

                        using (var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, headerTimeoutToken).ConfigureAwait(false))
                        {
                            headerTimeoutToken.ThrowIfCancellationRequested();

                            if (!response.IsSuccessStatusCode)
                            {
                                if (response.Content == null)
                                {
                                    throw new DownloadHttpStatusCodeException(response.StatusCode);
                                }

                                using (response.Content)
                                {
                                    var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

                                    throw new DownloadHttpStatusCodeException(response.StatusCode, content);
                                }
                            }

                            if (response.Content == null)
                            {
                                throw new DownloadException("No content");
                            }

                            var mediaType = response.Content.Headers?.ContentType?.MediaType;
                            if (!string.IsNullOrWhiteSpace(mediaType) && !mediaType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
                            {
                                if (InvalidContentTypes.Any(v => mediaType.StartsWith(v, StringComparison.OrdinalIgnoreCase)))
                                {
                                    throw new DownloadException($"Invalid response content type ({mediaType})");
                                }
                            }

                            if (!parameters.CacheDuration.HasValue && Configuration.TryToReadDiskCacheDurationFromHttpHeaders &&
                                response.Headers?.CacheControl?.MaxAge != null && response.Headers.CacheControl.MaxAge > TimeSpan.Zero)
                            {
                                downloadInformation.CacheValidity = response.Headers.CacheControl.MaxAge.Value;
                            }

                            ModifyParametersAfterResponse(response, parameters);

                            using (var httpReadTimeoutTokenSource = new CancellationTokenSource())
                                using (var readTimeoutTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token, httpReadTimeoutTokenSource.Token))
                                {
                                    var readTimeoutToken     = readTimeoutTokenSource.Token;
                                    var httpReadTimeoutToken = httpReadTimeoutTokenSource.Token;
                                    var total             = (int)(response.Content.Headers.ContentLength ?? -1);
                                    var canReportProgress = progressAction != null;

                                    httpReadTimeoutTokenSource.CancelAfter(TimeSpan.FromSeconds(Configuration.HttpReadTimeout));
                                    readTimeoutToken.ThrowIfCancellationRequested();

                                    try
                                    {
                                        using (var outputStream = new MemoryStream())
                                            using (var sourceStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
                                            {
                                                httpReadTimeoutToken.Register(() => sourceStream.TryDispose());

                                                var totalRead = 0;
                                                var buffer    = new byte[Configuration.HttpReadBufferSize];
                                                var read      = 0;

                                                while ((read = await sourceStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0)
                                                {
                                                    readTimeoutToken.ThrowIfCancellationRequested();
                                                    outputStream.Write(buffer, 0, read);
                                                    totalRead += read;

                                                    if (canReportProgress)
                                                    {
                                                        progressAction(new DownloadProgress(totalRead, total));
                                                    }
                                                }

                                                if (outputStream.Length == 0)
                                                {
                                                    throw new DownloadException("Zero length stream");
                                                }

                                                if (outputStream.Length < 32)
                                                {
                                                    throw new DownloadException("Invalid stream");
                                                }

                                                return(outputStream.ToArray());
                                            }
                                    }
                                    catch (Exception ex) when(ex is OperationCanceledException || ex is ObjectDisposedException)
                                    {
                                        if (httpReadTimeoutTokenSource.IsCancellationRequested)
                                        {
                                            throw new DownloadReadTimeoutException();
                                        }

                                        throw;
                                    }
                                }
                        }
                    }
                    catch (OperationCanceledException)
                    {
                        if (httpHeadersTimeoutTokenSource.IsCancellationRequested)
                        {
                            throw new DownloadHeadersTimeoutException();
                        }
                        else
                        {
                            throw;
                        }
                    }
                }
        }