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
{
private static readonly Task<IResponse> DefaultResponse = CreateDefaultResponse();
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.SetResult(result);
return result;
}
}
return null;
}
public static Task<IResponse> SendAsync(this IDocumentLoader loader, DocumentRequest request, CancellationToken cancel)
{
if (loader == null)
return DefaultResponse;
return loader.LoadAsync(request, cancel);
}
public static Task<IResponse> FetchAsync(this IResourceLoader loader, ResourceRequest request, CancellationToken cancel)
{
if (loader == null)
return DefaultResponse;
return loader.LoadAsync(request, cancel);
}
public static async Task<IResponse> FetchWithCorsAsync(this IResourceLoader loader, ResourceRequest request, CorsSetting setting, OriginBehavior behavior, CancellationToken cancel)
{
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;
}
if (setting == CorsSetting.None && behavior == OriginBehavior.Taint)
await loader.LoadAsync(request, cancel).ConfigureAwait(false);
if (setting == CorsSetting.Anonymous)
request.IsCredentialOmitted = true;
if (setting == CorsSetting.Anonymous || setting == CorsSetting.UseCredentials) {
IResponse result2 = await loader.FetchAsync(request, cancel).ConfigureAwait(false);
if (result2.StatusCode == HttpStatusCode.OK)
return result2;
}
throw new DomException(DomError.Network);
}
private static Task<IResponse> CreateDefaultResponse()
{
TaskCompletionSource<IResponse> taskCompletionSource = new TaskCompletionSource<IResponse>();
taskCompletionSource.SetResult(null);
return taskCompletionSource.Task;
}
}
}