AngleSharp by AngleSharp

<PackageReference Include="AngleSharp" Version="0.9.8.1" />

 BaseLoader

public abstract class BaseLoader : ILoader
Represents the base class for all loaders.
using AngleSharp.Dom; using AngleSharp.Dom.Events; using AngleSharp.Extensions; using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Threading; using System.Threading.Tasks; namespace AngleSharp.Network.Default { public abstract class BaseLoader : ILoader { private readonly IBrowsingContext _context; private readonly Predicate<IRequest> _filter; private readonly List<IDownload> _downloads; public int MaxRedirects { get; set; } public BaseLoader(IBrowsingContext context, Predicate<IRequest> filter) { _context = context; _filter = (filter ?? ((Predicate<IRequest>)((IRequest _) => true))); _downloads = new List<IDownload>(); MaxRedirects = 50; } protected virtual void Add(IDownload download) { lock (this) { _downloads.Add(download); } } protected virtual void Remove(IDownload download) { lock (this) { _downloads.Remove(download); } } protected virtual string GetCookie(Url url) { return _context.Configuration.GetCookie(url.Origin); } protected virtual void SetCookie(Url url, string value) { _context.Configuration.SetCookie(url.Origin, value); } protected virtual IDownload DownloadAsync(Request request, INode originator) { CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); if (_filter(request)) { Task<IResponse> task = LoadAsync(request, cancellationTokenSource.Token); Download download = new Download(task, cancellationTokenSource, request.Address, originator); Add(download); task.ContinueWith(delegate { Remove(download); }); return download; } return new Download(TaskEx.FromResult<IResponse>(null), cancellationTokenSource, request.Address, originator); } public IEnumerable<IDownload> GetDownloads() { lock (this) { return _downloads.ToArray(); } } protected async Task<IResponse> LoadAsync(Request request, CancellationToken cancel) { IEnumerable<IRequester> requesters = _context.Configuration.GetServices<IRequester>(); IResponse response = null; int redirectCount = 0; do { if (response != null) { redirectCount++; string orDefault = response.Headers.GetOrDefault(HeaderNames.SetCookie, null); if (orDefault != null) SetCookie(request.Address, orDefault); request = CreateNewRequest(request, response); string cookie = GetCookie(request.Address); if (cookie != null) request.Headers[HeaderNames.Cookie] = cookie; } foreach (IRequester item in requesters) { if (item.SupportsProtocol(request.Address.Scheme)) { _context.Fire(new RequestEvent(request, null)); response = await item.RequestAsync(request, cancel).ConfigureAwait(false); _context.Fire(new RequestEvent(request, response)); break; } } } while (response != null && response.StatusCode.IsRedirected() && redirectCount < MaxRedirects); return response; } protected static Request CreateNewRequest(IRequest request, IResponse response) { HttpMethod method = request.Method; Stream stream = request.Content; string relativeAddress = response.Headers[HeaderNames.Location]; if (response.StatusCode == HttpStatusCode.Found || response.StatusCode == HttpStatusCode.SeeOther) { method = HttpMethod.Get; stream = Stream.Null; } else if (stream.Length > 0) { stream.Position = 0; } return new Request { Address = new Url(request.Address, relativeAddress), Method = method, Content = stream, Headers = request.Headers }; } } }