AngleSharp by AngleSharp

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

 RequesterExtensions

static class RequesterExtensions
Useful extensions for IRequester objects.
using AngleSharp.Dom; using AngleSharp.Events; using AngleSharp.Network; using System.Collections.Generic; using System.Diagnostics; using System.Net; using System.Threading; using System.Threading.Tasks; namespace AngleSharp.Extensions { [DebuggerStepThrough] internal static class RequesterExtensions { public static async Task<IResponse> LoadAsync(this IEnumerable<IRequester> requesters, IRequest request, IEventAggregator events, CancellationToken cancel) { foreach (IRequester requester in requesters) { if (requester.SupportsProtocol(request.Address.Scheme)) { RequestStartEvent evt = new RequestStartEvent(requester, request); events?.Publish(evt); IResponse result = await requester.RequestAsync(request, cancel).ConfigureAwait(false); evt.FireEnd(); return result; } } return null; } public static Task<IResponse> SendAsync(this IDocumentLoader loader, DocumentRequest request, CancellationToken cancel) { if (loader == null) return TaskEx.FromResult<IResponse>(null); return loader.LoadAsync(request, cancel); } public static Task<IResponse> FetchAsync(this IResourceLoader loader, ResourceRequest request, CancellationToken cancel) { if (loader == null) return TaskEx.FromResult<IResponse>(null); return loader.LoadAsync(request, cancel); } public static async Task<IResponse> FetchWithCorsAsync(this IResourceLoader loader, ResourceRequest request, CorsSetting setting, OriginBehavior behavior, CancellationToken cancel) { if (loader == null) return null; Url url = request.Target; if (request.Origin == url.Origin || url.Scheme == KnownProtocols.Data || url.Href == "about:blank") { IResponse result; while (true) { ResourceRequest data = new ResourceRequest(request.Source, url) { Origin = request.Origin, IsManualRedirectDesired = true }; result = await loader.LoadAsync(data, cancel).ConfigureAwait(false); if (result.StatusCode != HttpStatusCode.Found && result.StatusCode != HttpStatusCode.TemporaryRedirect && result.StatusCode != HttpStatusCode.SeeOther && result.StatusCode != HttpStatusCode.TemporaryRedirect && result.StatusCode != HttpStatusCode.MovedPermanently && result.StatusCode != HttpStatusCode.MultipleChoices) break; url = new Url(result.Headers.GetOrDefault(HeaderNames.Location, url.Href)); if (request.Origin == url.Origin) { request = new ResourceRequest(request.Source, url) { IsCookieBlocked = request.IsCookieBlocked, IsSameOriginForced = request.IsSameOriginForced, Origin = request.Origin }; return await loader.FetchWithCorsAsync(request, setting, behavior, cancel).ConfigureAwait(false); } } return result; } switch (setting) { case CorsSetting.None: if (behavior == OriginBehavior.Fail) throw new DomException(DomError.Network); return await loader.LoadAsync(request, cancel).ConfigureAwait(false); case CorsSetting.Anonymous: case CorsSetting.UseCredentials: { request.IsCredentialOmitted = (setting == CorsSetting.Anonymous); IResponse result2 = await loader.FetchAsync(request, cancel).ConfigureAwait(false); if (result2 != null && result2.StatusCode == HttpStatusCode.OK) return result2; result2?.Dispose(); break; } } throw new DomException(DomError.Network); } public static MimeType GetContentType(this IResponse response) { string path = response.Address.Path; int num = path.LastIndexOf('.'); if (num >= 0) path.Substring(num); string defaultType = MimeTypes.FromExtension(MimeTypes.Binary); return response.GetContentType(defaultType); } public static MimeType GetContentType(this IResponse response, string defaultType) { return new MimeType(response.Headers.GetOrDefault(HeaderNames.ContentType, defaultType)); } } }