AngleSharp by AngleSharp

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

 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; } } }