Skip to content

Commit 9c4e64e

Browse files
committed
Merge master into implement-upstream-change-14945
2 parents 71d723b + 5cf4ba2 commit 9c4e64e

12 files changed

Lines changed: 212 additions & 22 deletions

File tree

lib/PuppeteerSharp.Tests/NetworkRestrictionTests/NetworkRestrictionsTests.cs

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,11 @@ public async Task ShouldPreventLoadingOfBlocklistedSubresources()
114114

115115
await page.GoToAsync(TestConstants.EmptyPage);
116116

117+
var idleTask = page.WaitForNetworkIdleAsync();
117118
await page.SetContentAsync(
118119
$@"<img src=""{blockedUrl}"" />
119-
<link rel=""stylesheet"" href=""{allowedUrl}"" />",
120-
new NavigationOptions { WaitUntil = [WaitUntilNavigation.Networkidle0] });
120+
<link rel=""stylesheet"" href=""{allowedUrl}"" />");
121+
await idleTask;
121122

122123
Assert.That(failedRequests.ContainsKey(blockedUrl), Is.True);
123124
Assert.That(failedRequests[blockedUrl], Does.Contain("net::ERR_INTERNET_DISCONNECTED"));
@@ -289,10 +290,11 @@ public async Task ShouldPreventLoadingOfSubresourcesNotInAllowlist()
289290

290291
await page.GoToAsync(TestConstants.EmptyPage);
291292

293+
var idleTask = page.WaitForNetworkIdleAsync();
292294
await page.SetContentAsync(
293295
$@"<img src=""{blockedUrl}"" />
294-
<link rel=""stylesheet"" href=""{allowedUrl}"" />",
295-
new NavigationOptions { WaitUntil = [WaitUntilNavigation.Networkidle0] });
296+
<link rel=""stylesheet"" href=""{allowedUrl}"" />");
297+
await idleTask;
296298

297299
Assert.That(failedRequests.ContainsKey(blockedUrl), Is.True);
298300
Assert.That(failedRequests[blockedUrl], Does.Contain("net::ERR_INTERNET_DISCONNECTED"));
@@ -420,4 +422,51 @@ await frame.GoToAsync(blockedUrl).ContinueWith(t =>
420422
Assert.That(error, Is.Not.Null);
421423
Assert.That(error.Message, Does.Contain("is blocked by blocklist/allowlist rules"));
422424
}
425+
426+
[Test, PuppeteerTest("BrowserConnector.test", "BrowserConnector _connectToBrowser", "should reject blocklist for WebDriver BiDi connections")]
427+
public void ShouldRejectBlocklistForWebDriverBiDiConnections()
428+
{
429+
var connectOptions = new ConnectOptions
430+
{
431+
BrowserWSEndpoint = "ws://localhost:1234",
432+
Protocol = ProtocolType.WebdriverBiDi,
433+
BlockList = ["https://example.com/*"],
434+
};
435+
436+
var error = Assert.ThrowsAsync<PuppeteerException>(async () =>
437+
await Puppeteer.ConnectAsync(connectOptions));
438+
439+
Assert.That(error.Message, Does.Contain("blocklist and allowlist are only supported with the CDP protocol"));
440+
}
441+
442+
[Test, PuppeteerTest("BrowserConnector.test", "BrowserConnector _connectToBrowser", "should reject allowlist for WebDriver BiDi connections")]
443+
public void ShouldRejectAllowlistForWebDriverBiDiConnections()
444+
{
445+
var connectOptions = new ConnectOptions
446+
{
447+
BrowserWSEndpoint = "ws://localhost:1234",
448+
Protocol = ProtocolType.WebdriverBiDi,
449+
Allowlist = ["https://example.com/*"],
450+
};
451+
452+
var error = Assert.ThrowsAsync<PuppeteerException>(async () =>
453+
await Puppeteer.ConnectAsync(connectOptions));
454+
455+
Assert.That(error.Message, Does.Contain("blocklist and allowlist are only supported with the CDP protocol"));
456+
}
457+
458+
[Test, PuppeteerTest("FirefoxLauncher.test", "FirefoxLauncher launch", "should reject blocklist for the default Firefox WebDriver BiDi protocol")]
459+
public void ShouldRejectBlocklistForDefaultFirefoxWebDriverBiDiProtocol()
460+
{
461+
var options = new LaunchOptions
462+
{
463+
Browser = SupportedBrowser.Firefox,
464+
BlockList = ["https://example.com/*"],
465+
};
466+
467+
var error = Assert.ThrowsAsync<PuppeteerException>(async () =>
468+
await Puppeteer.LaunchAsync(options));
469+
470+
Assert.That(error.Message, Does.Contain("blocklist and allowlist are only supported with the CDP protocol"));
471+
}
423472
}

lib/PuppeteerSharp.Tests/PageTests/SetContentTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public async Task ShouldRespectTimeout()
6060

6161
await Page.GoToAsync(TestConstants.EmptyPage);
6262
var exception = Assert.ThrowsAsync<TimeoutException>(async () =>
63-
await Page.SetContentAsync($"<img src='{TestConstants.ServerUrl + imgPath}'></img>", new NavigationOptions
63+
await Page.SetContentAsync($"<img src='{TestConstants.ServerUrl + imgPath}'></img>", new SetContentOptions
6464
{
6565
Timeout = 1
6666
}));

lib/PuppeteerSharp/Bidi/BidiFrame.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,8 @@ public override async Task<IElementHandle> AddStyleTagAsync(AddTagOptions option
173173
}
174174

175175
/// <inheritdoc />
176-
public override async Task SetContentAsync(string html, NavigationOptions options = null)
176+
[Obsolete]
177+
public override async Task SetContentAsync(string html, NavigationOptions options)
177178
{
178179
var timeout = options?.Timeout ?? TimeoutSettings.NavigationTimeout;
179180

lib/PuppeteerSharp/Cdp/CdpFrame.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,8 @@ public override async Task<IResponse> WaitForNavigationAsync(NavigationOptions o
177177
}
178178

179179
/// <inheritdoc/>
180-
public override async Task SetContentAsync(string html, NavigationOptions options = null)
180+
[Obsolete]
181+
public override async Task SetContentAsync(string html, NavigationOptions options)
181182
{
182183
var waitUntil = options?.WaitUntil ?? new[] { WaitUntilNavigation.Load };
183184
var timeout = options?.Timeout ?? FrameManager.TimeoutSettings.NavigationTimeout;

lib/PuppeteerSharp/Cdp/FrameManager.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,9 +576,12 @@ private void RemoveFramesRecursively(Frame frame)
576576
RemoveFramesRecursively(frame.ChildFrames.First() as Frame);
577577
}
578578

579-
frame.Detach();
580579
FrameTree.RemoveFrame(frame);
581580
FrameDetached?.Invoke(this, new FrameEventArgs(frame));
581+
582+
// Needs to be last to ensure events are dispatched before
583+
// any per-frame cleanup runs. Mirrors upstream PR #14430.
584+
frame.Detach();
582585
}
583586

584587
private void OnFrameAttached(CDPSession session, PageFrameAttachedResponse frameAttached)

lib/PuppeteerSharp/Frame.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,14 @@ public Task<string> GetContentAsync(GetContentOptions options = null)
305305
options?.ReplaceLoneSurrogates ?? false);
306306

307307
/// <inheritdoc/>
308-
public abstract Task SetContentAsync(string html, NavigationOptions options = null);
308+
[System.Obsolete("Use SetContentAsync(string, SetContentOptions) instead. The networkidle0 and networkidle2 wait conditions never worked reliably with SetContent.")]
309+
public abstract Task SetContentAsync(string html, NavigationOptions options);
310+
311+
/// <inheritdoc/>
312+
public Task SetContentAsync(string html, SetContentOptions options = null)
313+
#pragma warning disable CS0618 // Type or member is obsolete
314+
=> SetContentAsync(html, options?.ToNavigationOptions());
315+
#pragma warning restore CS0618
309316

310317
/// <inheritdoc/>
311318
public Task<string> GetTitleAsync() => IsolatedRealm.EvaluateExpressionAsync<string>("document.title");
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// * MIT License
2+
// *
3+
// * Copyright (c) Darío Kondratiuk
4+
// *
5+
// * Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// * of this software and associated documentation files (the "Software"), to deal
7+
// * in the Software without restriction, including without limitation the rights
8+
// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// * copies of the Software, and to permit persons to whom the Software is
10+
// * furnished to do so, subject to the following conditions:
11+
// *
12+
// * The above copyright notice and this permission notice shall be included in all
13+
// * copies or substantial portions of the Software.
14+
// *
15+
// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// * SOFTWARE.
22+
23+
namespace PuppeteerSharp.Helpers
24+
{
25+
/// <summary>
26+
/// Provides validation for URL restriction options (blocklist/allowlist).
27+
/// </summary>
28+
internal static class UrlRestrictionsValidator
29+
{
30+
/// <summary>
31+
/// Validates that the URL restrictions (<paramref name="blockList"/>/<paramref name="allowList"/>)
32+
/// are supported by the given <paramref name="protocol"/>. URL restrictions are only enforced by
33+
/// the CDP target/navigation path; BiDi connections (and Firefox's default BiDi launch path) do
34+
/// not support them.
35+
/// </summary>
36+
/// <param name="protocol">The protocol that the connection or launch is using.</param>
37+
/// <param name="blockList">The blocklist URL patterns.</param>
38+
/// <param name="allowList">The allowlist URL patterns.</param>
39+
/// <exception cref="PuppeteerException">
40+
/// Thrown if both <paramref name="blockList"/> and <paramref name="allowList"/> are specified,
41+
/// or if either is specified together with <see cref="ProtocolType.WebdriverBiDi"/>.
42+
/// </exception>
43+
public static void AssertSupportedUrlRestrictions(ProtocolType protocol, string[] blockList, string[] allowList)
44+
{
45+
if (blockList != null && allowList != null)
46+
{
47+
throw new PuppeteerException("Cannot specify both blocklist and allowlist");
48+
}
49+
50+
if (protocol == ProtocolType.WebdriverBiDi && (blockList != null || allowList != null))
51+
{
52+
throw new PuppeteerException("blocklist and allowlist are only supported with the CDP protocol");
53+
}
54+
}
55+
}
56+
}

lib/PuppeteerSharp/IFrame.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,18 @@ public interface IFrame
318318
/// <param name="options">The options.</param>
319319
/// <returns>Task.</returns>
320320
/// <seealso cref="IPage.SetContentAsync(string, NavigationOptions)"/>
321-
Task SetContentAsync(string html, NavigationOptions options = null);
321+
[System.Obsolete("Use SetContentAsync(string, SetContentOptions) instead. The networkidle0 and networkidle2 wait conditions never worked reliably with SetContent.")]
322+
Task SetContentAsync(string html, NavigationOptions options);
323+
324+
/// <summary>
325+
/// Sets the HTML markup to the page.
326+
/// </summary>
327+
/// <param name="html">HTML markup to assign to the page.</param>
328+
/// <param name="options">The options. The <see cref="WaitUntilNavigation.Networkidle0"/> and
329+
/// <see cref="WaitUntilNavigation.Networkidle2"/> wait conditions are not supported for SetContent.</param>
330+
/// <returns>Task.</returns>
331+
/// <seealso cref="IPage.SetContentAsync(string, SetContentOptions)"/>
332+
Task SetContentAsync(string html, SetContentOptions options = null);
322333

323334
/// <summary>
324335
/// Sends a <c>keydown</c>, <c>keypress</c>/<c>input</c>, and <c>keyup</c> event for each character in the text.

lib/PuppeteerSharp/IPage.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1120,7 +1120,18 @@ public interface IPage : IDisposable, IAsyncDisposable
11201120
/// <param name="options">The navigations options.</param>
11211121
/// <returns>Task.</returns>
11221122
/// <seealso cref="IFrame.SetContentAsync(string, NavigationOptions)"/>
1123-
Task SetContentAsync(string html, NavigationOptions options = null);
1123+
[System.Obsolete("Use SetContentAsync(string, SetContentOptions) instead. The networkidle0 and networkidle2 wait conditions never worked reliably with SetContent.")]
1124+
Task SetContentAsync(string html, NavigationOptions options);
1125+
1126+
/// <summary>
1127+
/// Sets the HTML markup to the page.
1128+
/// </summary>
1129+
/// <param name="html">HTML markup to assign to the page.</param>
1130+
/// <param name="options">The options. The <see cref="WaitUntilNavigation.Networkidle0"/> and
1131+
/// <see cref="WaitUntilNavigation.Networkidle2"/> wait conditions are not supported for SetContent.</param>
1132+
/// <returns>Task.</returns>
1133+
/// <seealso cref="IFrame.SetContentAsync(string, SetContentOptions)"/>
1134+
Task SetContentAsync(string html, SetContentOptions options = null);
11241135

11251136
/// <summary>
11261137
/// Clears all of the current cookies and then sets the cookies for the page.

lib/PuppeteerSharp/Launcher.cs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using PuppeteerSharp.BrowserData;
1616
using PuppeteerSharp.Cdp;
1717
using PuppeteerSharp.Cdp.Messaging;
18+
using PuppeteerSharp.Helpers;
1819
using PuppeteerSharp.Helpers.Json;
1920
#if !CDP_ONLY
2021
using WebDriverBiDi;
@@ -62,11 +63,6 @@ public async Task<IBrowser> LaunchAsync(LaunchOptions options)
6263
throw new ArgumentNullException(nameof(options));
6364
}
6465

65-
if (options.BlockList != null && options.Allowlist != null)
66-
{
67-
throw new PuppeteerException("Cannot specify both blocklist and allowlist");
68-
}
69-
7066
EnsureSingleLaunchOrConnect();
7167
_browser = options.Browser;
7268

@@ -80,6 +76,8 @@ public async Task<IBrowser> LaunchAsync(LaunchOptions options)
8076
options.Protocol = ProtocolType.WebdriverBiDi;
8177
}
8278

79+
UrlRestrictionsValidator.AssertSupportedUrlRestrictions(options.Protocol, options.BlockList, options.Allowlist);
80+
8381
var executable = options.ExecutablePath;
8482
if (executable == null)
8583
{
@@ -277,6 +275,8 @@ public async Task<IBrowser> ConnectAsync(ConnectOptions options)
277275
throw new PuppeteerException("Exactly one of browserWSEndpoint or browserURL must be passed to puppeteer.connect");
278276
}
279277

278+
UrlRestrictionsValidator.AssertSupportedUrlRestrictions(options.Protocol, options.BlockList, options.Allowlist);
279+
280280
var browserWSEndpoint = string.IsNullOrEmpty(options.BrowserURL)
281281
? options.BrowserWSEndpoint
282282
: await GetWSEndpointAsync(options.BrowserURL).ConfigureAwait(false);
@@ -423,11 +423,6 @@ private async Task<IBrowser> ConnectBidiAsync(string browserWSEndpoint, ConnectO
423423

424424
private async Task<IBrowser> ConnectCdpAsync(string browserWSEndpoint, ConnectOptions options)
425425
{
426-
if (options.BlockList != null && options.Allowlist != null)
427-
{
428-
throw new PuppeteerException("Cannot specify both blocklist and allowlist");
429-
}
430-
431426
CdpConnection connection = null;
432427
try
433428
{

0 commit comments

Comments
 (0)