ImportLinkRelation
using AngleSharp.Dom;
using AngleSharp.Dom.Html;
using AngleSharp.Extensions;
using AngleSharp.Network;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
namespace AngleSharp.Html.LinkRels
{
internal class ImportLinkRelation : BaseLinkRelation
{
private sealed class ImportList
{
private readonly List<ImportEntry> _list;
public ImportList()
{
_list = new List<ImportEntry>();
}
public bool Contains(Url location)
{
for (int i = 0; i < _list.Count; i++) {
if (_list[i].Relation.Url.Equals(location))
return true;
}
return false;
}
public void Add(ImportEntry item)
{
_list.Add(item);
}
public void Remove(ImportEntry item)
{
_list.Remove(item);
}
}
private struct ImportEntry
{
public ImportLinkRelation Relation;
public bool IsCycle;
}
private static readonly ConditionalWeakTable<IDocument, ImportList> ImportLists = new ConditionalWeakTable<IDocument, ImportList>();
private IDocument _import;
private bool _isasync;
public IDocument Import => _import;
public bool IsAsync => _isasync;
public ImportLinkRelation(HtmlLinkElement link)
: base(link)
{
}
public override async Task LoadAsync(IConfiguration configuration, IResourceLoader loader)
{
HtmlLinkElement link = base.Link;
Document document = link.Owner;
ImportList list = ImportLists.GetOrCreateValue(document);
Url location = base.Url;
ResourceRequest request = link.CreateRequestFor(location);
ImportEntry item = new ImportEntry {
Relation = this,
IsCycle = CheckCycle(document, location)
};
_isasync = link.HasAttribute(AttributeNames.Async);
list.Add(item);
if (!item.IsCycle) {
TaskCompletionSource<bool> nestedStatus = new TaskCompletionSource<bool>();
IDownload download = loader.DownloadAsync(request);
SetDownload(download);
await link.ProcessResponse(download, async delegate(IResponse response) {
BrowsingContext context = new BrowsingContext(document.Context, Sandboxes.None);
CreateDocumentOptions options = new CreateDocumentOptions(response, configuration) {
ImportAncestor = document
};
_import = await context.OpenAsync(options, CancellationToken.None).ConfigureAwait(false);
nestedStatus.SetResult(true);
}).ConfigureAwait(false);
await nestedStatus.Task.ConfigureAwait(false);
}
}
private static bool CheckCycle(IDocument document, Url location)
{
IDocument importAncestor = document.ImportAncestor;
ImportList value = null;
while (importAncestor != null && ImportLists.TryGetValue(importAncestor, out value)) {
if (value.Contains(location))
return true;
importAncestor = importAncestor.ImportAncestor;
}
return false;
}
}
}