diff --git a/lib/PuppeteerSharp.Tests/Issues/Issue1447.cs b/lib/PuppeteerSharp.Tests/Issues/Issue1447.cs new file mode 100644 index 000000000..ffb046436 --- /dev/null +++ b/lib/PuppeteerSharp.Tests/Issues/Issue1447.cs @@ -0,0 +1,51 @@ +using System.Linq; +using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; + +namespace PuppeteerSharp.Tests.Issues +{ + [Collection(TestConstants.TestFixtureCollectionName)] + public class Issue1447 : PuppeteerPageBaseTest + { + public Issue1447(ITestOutputHelper output) : base(output) { } + + [Fact(Skip = "It's an example")] + public async Task Example() + { + var opts = new LaunchOptions + { + Headless = false, + DefaultViewport = null, + IgnoredDefaultArgs = new[] { "--enable-automation" } + }; + + using (var browser = await new Launcher().LaunchAsync(opts)) + { + var pages = await browser.PagesAsync(); + + var page = pages.ElementAt(0); + + for (int i = 0; i < 20; i++) + { + await Navigate(page, "https://distilnetworks.com"); + await Navigate(page, "https://mail.com"); + await Navigate(page, "https://distilnetworks.com"); + await Navigate(page, "https://vk.com"); + await Navigate(page, "https://distilnetworks.com"); + await Navigate(page, "https://mail.com"); + await Navigate(page, "https://distilnetworks.com"); + await Navigate(page, "https://mail.com"); + await Navigate(page, "about:blank"); + } + } + } + + public Task Navigate(Page page, string url) + { + return page.MainFrame.GoToAsync( + url, + new NavigationOptions { Timeout = 0, WaitUntil = new[] { WaitUntilNavigation.DOMContentLoaded } }); + } + } +} \ No newline at end of file diff --git a/lib/PuppeteerSharp/FrameManager.cs b/lib/PuppeteerSharp/FrameManager.cs index 107e230fb..32b3b529c 100644 --- a/lib/PuppeteerSharp/FrameManager.cs +++ b/lib/PuppeteerSharp/FrameManager.cs @@ -431,6 +431,8 @@ private async Task EnsureIsolatedWorldAsync(string name) internal Task GetFrameAsync(string frameId) => _asyncFrames.GetItemAsync(frameId); + internal Task TryGetFrameAsync(string frameId) => _asyncFrames.TryGetItemAsync(frameId); + #endregion } } diff --git a/lib/PuppeteerSharp/Helpers/AsyncDictionaryHelper.cs b/lib/PuppeteerSharp/Helpers/AsyncDictionaryHelper.cs index 908320484..582b9b30e 100644 --- a/lib/PuppeteerSharp/Helpers/AsyncDictionaryHelper.cs +++ b/lib/PuppeteerSharp/Helpers/AsyncDictionaryHelper.cs @@ -29,7 +29,21 @@ internal async Task GetItemAsync(TKey key) } return await tcs.Task.WithTimeout(new Action(() => - throw new PuppeteerException(string.Format(_timeoutMessage, key)))).ConfigureAwait(false); + throw new PuppeteerException(string.Format(_timeoutMessage, key))), 1000).ConfigureAwait(false); + } + + internal async Task TryGetItemAsync(TKey key) + { + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + _pendingRequests.Add(key, tcs); + + if (_dictionary.TryGetValue(key, out var item)) + { + _pendingRequests.Delete(key, tcs); + return item; + } + + return await tcs.Task.WithTimeout(() => { }, 1000).ConfigureAwait(false); } internal void AddItem(TKey key, TValue value) diff --git a/lib/PuppeteerSharp/NetworkManager.cs b/lib/PuppeteerSharp/NetworkManager.cs index fbc44a0ce..46ebd72cf 100644 --- a/lib/PuppeteerSharp/NetworkManager.cs +++ b/lib/PuppeteerSharp/NetworkManager.cs @@ -22,10 +22,10 @@ internal class NetworkManager private Dictionary _extraHTTPHeaders; private bool _offine; private Credentials _credentials; - private List _attemptedAuthentications = new List(); + private readonly List _attemptedAuthentications = new List(); private bool _userRequestInterceptionEnabled; private bool _protocolRequestInterceptionEnabled; - private bool _ignoreHTTPSErrors; + private readonly bool _ignoreHTTPSErrors; private bool _userCacheDisabled; #endregion @@ -306,7 +306,7 @@ private async Task OnRequestAsync(RequestWillBeSentPayload e, string interceptio if (!_requestIdToRequest.TryGetValue(e.RequestId, out var currentRequest) || currentRequest.Frame == null) { - var frame = await FrameManager.GetFrameAsync(e.FrameId).ConfigureAwait(false); + var frame = await FrameManager.TryGetFrameAsync(e.FrameId).ConfigureAwait(false); request = new Request( _client, @@ -371,7 +371,7 @@ private async Task OnRequestWillBeSentAsync(RequestWillBeSentPayload e) // Request interception doesn't happen for data URLs with Network Service. if (_protocolRequestInterceptionEnabled && !e.Request.Url.StartsWith("data:", StringComparison.InvariantCultureIgnoreCase)) { - if (_requestIdToInterceptionId.TryRemove(e.RequestId, out var interceptionId)) + if (_requestIdToInterceptionId.TryRemove(e.RequestId, out string interceptionId)) { await OnRequestAsync(e, interceptionId).ConfigureAwait(false); }