Skip to content

Commit 6e3b164

Browse files
authored
Fix cache disabling should stick when toggling request interception (#1110)
* Fix cache disabling should stick when toggling request interception * Remove call to Security.setOverrideCertificateError * Fix race
1 parent 673e9b9 commit 6e3b164

File tree

5 files changed

+98
-77
lines changed

5 files changed

+98
-77
lines changed

lib/PuppeteerSharp.Tests/PageTests/SetCacheEnabledTests.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,22 @@ await Task.WhenAll(
3434

3535
Assert.True(string.IsNullOrEmpty(waitForRequestTask.Result));
3636
}
37+
38+
[Fact]
39+
public async Task ShouldStayDisabledWhenTogglingRequestInterceptionOnOff()
40+
{
41+
await Page.SetCacheEnabledAsync(false);
42+
await Page.SetRequestInterceptionAsync(true);
43+
await Page.SetRequestInterceptionAsync(false);
44+
45+
await Page.GoToAsync(TestConstants.ServerUrl + "/cached/one-style.html");
46+
var waitForRequestTask = Server.WaitForRequest<string>("/cached/one-style.html", (request) => request.Headers["if-modified-since"]);
47+
48+
await Task.WhenAll(
49+
waitForRequestTask,
50+
Page.ReloadAsync());
51+
52+
Assert.True(string.IsNullOrEmpty(waitForRequestTask.Result));
53+
}
3754
}
3855
}

lib/PuppeteerSharp/FrameManager.cs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@ internal class FrameManager
2222
private readonly List<string> _isolatedWorlds = new List<string>();
2323
private const string UtilityWorldName = "__puppeteer_utility_world__";
2424

25-
private FrameManager(CDPSession client, Page page, NetworkManager networkManager, TimeoutSettings timeoutSettings)
25+
private FrameManager(CDPSession client, Page page, bool ignoreHTTPSErrors, TimeoutSettings timeoutSettings)
2626
{
2727
Client = client;
2828
Page = page;
2929
_frames = new ConcurrentDictionary<string, Frame>();
3030
_contextIdToContext = new Dictionary<int, ExecutionContext>();
3131
_logger = Client.Connection.LoggerFactory.CreateLogger<FrameManager>();
32-
NetworkManager = networkManager;
32+
NetworkManager = new NetworkManager(client, ignoreHTTPSErrors);
33+
NetworkManager.FrameManager = this;
3334
TimeoutSettings = timeoutSettings;
3435
_asyncFrames = new AsyncDictionaryHelper<string, Frame>(_frames, "Frame {0} not found");
3536

@@ -55,12 +56,25 @@ private FrameManager(CDPSession client, Page page, NetworkManager networkManager
5556
internal static async Task<FrameManager> CreateFrameManagerAsync(
5657
CDPSession client,
5758
Page page,
58-
NetworkManager networkManager,
59-
FrameTree frameTree,
59+
bool ignoreHTTPSErrors,
6060
TimeoutSettings timeoutSettings)
6161
{
62-
var frameManager = new FrameManager(client, page, networkManager, timeoutSettings);
63-
await frameManager.HandleFrameTreeAsync(frameTree).ConfigureAwait(false);
62+
var frameManager = new FrameManager(client, page, ignoreHTTPSErrors, timeoutSettings);
63+
var getFrameTreeTask = client.SendAsync<PageGetFrameTreeResponse>("Page.getFrameTree");
64+
65+
await Task.WhenAll(
66+
client.SendAsync("Page.enable"),
67+
getFrameTreeTask).ConfigureAwait(false);
68+
69+
await frameManager.HandleFrameTreeAsync(new FrameTree(getFrameTreeTask.Result.FrameTree)).ConfigureAwait(false);
70+
71+
await Task.WhenAll(
72+
client.SendAsync("Page.setLifecycleEventsEnabled", new PageSetLifecycleEventsEnabledRequest { Enabled = true }),
73+
client.SendAsync("Runtime.enable"),
74+
frameManager.NetworkManager.InitializeAsync()).ConfigureAwait(false);
75+
76+
await frameManager.EnsureSecondaryDOMWorldAsync().ConfigureAwait(false);
77+
6478
return frameManager;
6579
}
6680

@@ -386,9 +400,9 @@ private async Task HandleFrameTreeAsync(FrameTree frameTree)
386400
}
387401
}
388402

389-
internal Task EnsureSecondaryDOMWorldAsync() => EnsureSecondaryDOMWorldAsync(UtilityWorldName);
403+
private Task EnsureSecondaryDOMWorldAsync() => EnsureSecondaryDOMWorldAsync(UtilityWorldName);
390404

391-
internal async Task EnsureSecondaryDOMWorldAsync(string name)
405+
private async Task EnsureSecondaryDOMWorldAsync(string name)
392406
{
393407
if (_isolatedWorlds.Contains(name))
394408
{
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace PuppeteerSharp.Messaging
2+
{
3+
internal class SecuritySetIgnoreCertificateErrorsRequest
4+
{
5+
public bool Ignore { get; set; }
6+
}
7+
}

lib/PuppeteerSharp/NetworkManager.cs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@ internal class NetworkManager
2525
private List<string> _attemptedAuthentications = new List<string>();
2626
private bool _userRequestInterceptionEnabled;
2727
private bool _protocolRequestInterceptionEnabled;
28-
28+
private bool _ignoreHTTPSErrors;
29+
private bool _userCacheDisabled;
2930
#endregion
3031

31-
internal NetworkManager(CDPSession client)
32+
internal NetworkManager(CDPSession client, bool ignoreHTTPSErrors)
3233
{
3334
FrameManager = null;
3435
_client = client;
36+
_ignoreHTTPSErrors = ignoreHTTPSErrors;
3537
_client.MessageReceived += Client_MessageReceived;
3638
_logger = _client.Connection.LoggerFactory.CreateLogger<NetworkManager>();
3739
}
@@ -47,6 +49,18 @@ internal NetworkManager(CDPSession client)
4749

4850
#region Public Methods
4951

52+
internal async Task InitializeAsync()
53+
{
54+
await _client.SendAsync("Network.enable").ConfigureAwait(false);
55+
if (_ignoreHTTPSErrors)
56+
{
57+
await _client.SendAsync("Security.setIgnoreCertificateErrors", new SecuritySetIgnoreCertificateErrorsRequest
58+
{
59+
Ignore = true
60+
}).ConfigureAwait(false);
61+
}
62+
}
63+
5064
internal Task AuthenticateAsync(Credentials credentials)
5165
{
5266
_credentials = credentials;
@@ -89,6 +103,12 @@ internal Task SetUserAgentAsync(string userAgent)
89103
UserAgent = userAgent
90104
});
91105

106+
internal Task SetCacheEnabledAsync(bool enabled)
107+
{
108+
_userCacheDisabled = !enabled;
109+
return UpdateProtocolCacheDisabledAsync();
110+
}
111+
92112
internal Task SetRequestInterceptionAsync(bool value)
93113
{
94114
_userRequestInterceptionEnabled = value;
@@ -99,6 +119,12 @@ internal Task SetRequestInterceptionAsync(bool value)
99119

100120
#region Private Methods
101121

122+
private Task UpdateProtocolCacheDisabledAsync()
123+
=> _client.SendAsync("Network.setCacheDisabled", new NetworkSetCacheDisabledRequest
124+
{
125+
CacheDisabled = _userCacheDisabled || _protocolRequestInterceptionEnabled
126+
});
127+
102128
private async void Client_MessageReceived(object sender, MessageEventArgs e)
103129
{
104130
try
@@ -365,10 +391,7 @@ private async Task UpdateProtocolRequestInterceptionAsync()
365391
Array.Empty<object>();
366392

367393
await Task.WhenAll(
368-
_client.SendAsync("Network.setCacheDisabled", new NetworkSetCacheDisabledRequest
369-
{
370-
CacheDisabled = enabled
371-
}),
394+
UpdateProtocolCacheDisabledAsync(),
372395
_client.SendAsync("Network.setRequestInterception", new NetworkSetRequestInterceptionRequest
373396
{
374397
Patterns = patterns

lib/PuppeteerSharp/Page.cs

Lines changed: 23 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ namespace PuppeteerSharp
3636
[DebuggerDisplay("Page {Url}")]
3737
public class Page : IDisposable
3838
{
39-
private readonly bool _ignoreHTTPSErrors;
40-
private NetworkManager _networkManager;
4139
private readonly TaskQueue _screenshotTaskQueue;
4240
private readonly EmulationManager _emulationManager;
4341
private readonly Dictionary<string, Delegate> _pageBindings;
@@ -59,7 +57,6 @@ public class Page : IDisposable
5957
private Page(
6058
CDPSession client,
6159
Target target,
62-
bool ignoreHTTPSErrors,
6360
TaskQueue screenshotTaskQueue)
6461
{
6562
Client = client;
@@ -76,7 +73,6 @@ private Page(
7673
_workers = new Dictionary<string, Worker>();
7774
_logger = Client.Connection.LoggerFactory.CreateLogger<Page>();
7875
Accessibility = new Accessibility(client);
79-
_ignoreHTTPSErrors = ignoreHTTPSErrors;
8076

8177
_screenshotTaskQueue = screenshotTaskQueue;
8278

@@ -92,8 +88,6 @@ private Page(
9288
_closeCompletedTcs.TrySetResult(true);
9389
}
9490
});
95-
96-
Client.MessageReceived += Client_MessageReceived;
9791
}
9892

9993
internal CDPSession Client { get; }
@@ -521,14 +515,14 @@ public async Task<JSHandle> QueryObjectsAsync(JSHandle prototypeHandle)
521515
/// <returns>The request interception task.</returns>
522516
/// <param name="value">Whether to enable request interception..</param>
523517
public Task SetRequestInterceptionAsync(bool value)
524-
=> _networkManager.SetRequestInterceptionAsync(value);
518+
=> FrameManager.NetworkManager.SetRequestInterceptionAsync(value);
525519

526520
/// <summary>
527521
/// Set offline mode for the page.
528522
/// </summary>
529523
/// <returns>Result task</returns>
530524
/// <param name="value">When <c>true</c> enables offline mode for the page.</param>
531-
public Task SetOfflineModeAsync(bool value) => _networkManager.SetOfflineModeAsync(value);
525+
public Task SetOfflineModeAsync(bool value) => FrameManager.NetworkManager.SetOfflineModeAsync(value);
532526

533527
/// <summary>
534528
/// Returns the page's cookies
@@ -1120,7 +1114,7 @@ public Task CloseAsync(PageCloseOptions options = null)
11201114
/// <param name="enabled">sets the <c>enabled</c> state of the cache</param>
11211115
/// <returns>Task</returns>
11221116
public Task SetCacheEnabledAsync(bool enabled = true)
1123-
=> Client.SendAsync("Network.setCacheDisabled", new NetworkSetCacheDisabledRequest { CacheDisabled = !enabled });
1117+
=> FrameManager.NetworkManager.SetCacheEnabledAsync(enabled);
11241118

11251119
/// <summary>
11261120
/// Fetches an element with <paramref name="selector"/>, scrolls it into view if needed, and then uses <see cref="Page.Mouse"/> to click in the center of the element.
@@ -1227,15 +1221,15 @@ public Task<T> EvaluateFunctionAsync<T>(string script, params object[] args)
12271221
/// <param name="userAgent">Specific user agent to use in this page</param>
12281222
/// <returns>Task</returns>
12291223
public Task SetUserAgentAsync(string userAgent)
1230-
=> _networkManager.SetUserAgentAsync(userAgent);
1224+
=> FrameManager.NetworkManager.SetUserAgentAsync(userAgent);
12311225

12321226
/// <summary>
12331227
/// Sets extra HTTP headers that will be sent with every request the page initiates
12341228
/// </summary>
12351229
/// <param name="headers">Additional http headers to be sent with every request</param>
12361230
/// <returns>Task</returns>
12371231
public Task SetExtraHttpHeadersAsync(Dictionary<string, string> headers)
1238-
=> _networkManager.SetExtraHTTPHeadersAsync(headers);
1232+
=> FrameManager.NetworkManager.SetExtraHTTPHeadersAsync(headers);
12391233

12401234
/// <summary>
12411235
/// Provide credentials for http authentication <see href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication"/>
@@ -1245,7 +1239,7 @@ public Task SetExtraHttpHeadersAsync(Dictionary<string, string> headers)
12451239
/// <remarks>
12461240
/// To disable authentication, pass <c>null</c>
12471241
/// </remarks>
1248-
public Task AuthenticateAsync(Credentials credentials) => _networkManager.AuthenticateAsync(credentials);
1242+
public Task AuthenticateAsync(Credentials credentials) => FrameManager.NetworkManager.AuthenticateAsync(credentials);
12491243

12501244
/// <summary>
12511245
/// Reloads the page
@@ -1432,15 +1426,15 @@ void requestEventListener(object sender, RequestEventArgs e)
14321426
if (predicate(e.Request))
14331427
{
14341428
requestTcs.TrySetResult(e.Request);
1435-
_networkManager.Request -= requestEventListener;
1429+
FrameManager.NetworkManager.Request -= requestEventListener;
14361430
}
14371431
}
14381432

1439-
_networkManager.Request += requestEventListener;
1433+
FrameManager.NetworkManager.Request += requestEventListener;
14401434

14411435
return await requestTcs.Task.WithTimeout(timeout, t =>
14421436
{
1443-
_networkManager.Request -= requestEventListener;
1437+
FrameManager.NetworkManager.Request -= requestEventListener;
14441438
return new TimeoutException($"Timeout Exceeded: {t.TotalMilliseconds}ms exceeded");
14451439
}).ConfigureAwait(false);
14461440
}
@@ -1486,11 +1480,11 @@ void responseEventListener(object sender, ResponseCreatedEventArgs e)
14861480
if (predicate(e.Response))
14871481
{
14881482
responseTcs.TrySetResult(e.Response);
1489-
_networkManager.Response -= responseEventListener;
1483+
FrameManager.NetworkManager.Response -= responseEventListener;
14901484
}
14911485
}
14921486

1493-
_networkManager.Response += responseEventListener;
1487+
FrameManager.NetworkManager.Response += responseEventListener;
14941488

14951489
return await responseTcs.Task.WithTimeout(timeout).ConfigureAwait(false);
14961490
}
@@ -1538,10 +1532,8 @@ internal static async Task<Page> CreateAsync(
15381532
ViewPortOptions defaultViewPort,
15391533
TaskQueue screenshotTaskQueue)
15401534
{
1541-
await client.SendAsync("Page.enable", null).ConfigureAwait(false);
1542-
var result = await client.SendAsync<PageGetFrameTreeResponse>("Page.getFrameTree").ConfigureAwait(false);
1543-
var page = new Page(client, target, ignoreHTTPSErrors, screenshotTaskQueue);
1544-
await page.InitializeAsync(new FrameTree(result.FrameTree)).ConfigureAwait(false);
1535+
var page = new Page(client, target, screenshotTaskQueue);
1536+
await page.InitializeAsync(ignoreHTTPSErrors).ConfigureAwait(false);
15451537

15461538
await Task.WhenAll(
15471539
client.SendAsync("Target.setAutoAttach", new TargetSetAutoAttachRequest
@@ -1561,16 +1553,6 @@ await Task.WhenAll(
15611553
client.SendAsync("Log.enable", null)
15621554
).ConfigureAwait(false);
15631555

1564-
await page.FrameManager.EnsureSecondaryDOMWorldAsync().ConfigureAwait(false);
1565-
1566-
if (ignoreHTTPSErrors)
1567-
{
1568-
await client.SendAsync("Security.setOverrideCertificateErrors", new SecuritySetOverrideCertificateErrorsRequest
1569-
{
1570-
Override = true
1571-
}).ConfigureAwait(false);
1572-
}
1573-
15741556
if (defaultViewPort != null)
15751557
{
15761558
await page.SetViewportAsync(defaultViewPort).ConfigureAwait(false);
@@ -1579,20 +1561,20 @@ await Task.WhenAll(
15791561
return page;
15801562
}
15811563

1582-
private async Task InitializeAsync(FrameTree frameTree)
1564+
private async Task InitializeAsync(bool ignoreHTTPSErrors)
15831565
{
1584-
_networkManager = new NetworkManager(Client);
1585-
FrameManager = await FrameManager.CreateFrameManagerAsync(Client, this, _networkManager, frameTree, _timeoutSettings).ConfigureAwait(false);
1586-
_networkManager.FrameManager = FrameManager;
1566+
FrameManager = await FrameManager.CreateFrameManagerAsync(Client, this, ignoreHTTPSErrors, _timeoutSettings).ConfigureAwait(false);
1567+
var networkManager = FrameManager.NetworkManager;
15871568

1569+
Client.MessageReceived += Client_MessageReceived;
15881570
FrameManager.FrameAttached += (sender, e) => FrameAttached?.Invoke(this, e);
15891571
FrameManager.FrameDetached += (sender, e) => FrameDetached?.Invoke(this, e);
15901572
FrameManager.FrameNavigated += (sender, e) => FrameNavigated?.Invoke(this, e);
15911573

1592-
_networkManager.Request += (sender, e) => Request?.Invoke(this, e);
1593-
_networkManager.RequestFailed += (sender, e) => RequestFailed?.Invoke(this, e);
1594-
_networkManager.Response += (sender, e) => Response?.Invoke(this, e);
1595-
_networkManager.RequestFinished += (sender, e) => RequestFinished?.Invoke(this, e);
1574+
networkManager.Request += (sender, e) => Request?.Invoke(this, e);
1575+
networkManager.RequestFailed += (sender, e) => RequestFailed?.Invoke(this, e);
1576+
networkManager.Response += (sender, e) => Response?.Invoke(this, e);
1577+
networkManager.RequestFinished += (sender, e) => RequestFinished?.Invoke(this, e);
15961578
}
15971579

15981580
private async Task<Response> GoAsync(int delta, NavigationOptions options)
@@ -1822,17 +1804,14 @@ private async void Client_MessageReceived(object sender, MessageEventArgs e)
18221804
Load?.Invoke(this, EventArgs.Empty);
18231805
break;
18241806
case "Runtime.consoleAPICalled":
1825-
await OnConsoleAPI(e.MessageData.ToObject<PageConsoleResponse>(true)).ConfigureAwait(false);
1807+
await OnConsoleAPIAsync(e.MessageData.ToObject<PageConsoleResponse>(true)).ConfigureAwait(false);
18261808
break;
18271809
case "Page.javascriptDialogOpening":
18281810
OnDialog(e.MessageData.ToObject<PageJavascriptDialogOpeningResponse>(true));
18291811
break;
18301812
case "Runtime.exceptionThrown":
18311813
HandleException(e.MessageData.ToObject<RuntimeExceptionThrownResponse>(true).ExceptionDetails);
18321814
break;
1833-
case "Security.certificateError":
1834-
await OnCertificateError(e.MessageData.ToObject<CertificateErrorResponse>(true)).ConfigureAwait(false);
1835-
break;
18361815
case "Inspector.targetCrashed":
18371816
OnTargetCrashed();
18381817
break;
@@ -1994,25 +1973,6 @@ private void OnTargetCrashed()
19941973
private void EmitMetrics(PerformanceMetricsResponse metrics)
19951974
=> Metrics?.Invoke(this, new MetricEventArgs(metrics.Title, BuildMetricsObject(metrics.Metrics)));
19961975

1997-
private async Task OnCertificateError(CertificateErrorResponse e)
1998-
{
1999-
if (_ignoreHTTPSErrors)
2000-
{
2001-
try
2002-
{
2003-
await Client.SendAsync("Security.handleCertificateError", new SecurityHandleCertificateErrorResponse
2004-
{
2005-
EventId = e.EventId,
2006-
Action = "continue"
2007-
}).ConfigureAwait(false);
2008-
}
2009-
catch (PuppeteerException ex)
2010-
{
2011-
_logger.LogError(ex.ToString());
2012-
}
2013-
}
2014-
}
2015-
20161976
private void HandleException(EvaluateExceptionResponseDetails exceptionDetails)
20171977
=> PageError?.Invoke(this, new PageErrorEventArgs(GetExceptionMessage(exceptionDetails)));
20181978

@@ -2041,7 +2001,7 @@ private void OnDialog(PageJavascriptDialogOpeningResponse message)
20412001
Dialog?.Invoke(this, new DialogEventArgs(dialog));
20422002
}
20432003

2044-
private Task OnConsoleAPI(PageConsoleResponse message)
2004+
private Task OnConsoleAPIAsync(PageConsoleResponse message)
20452005
{
20462006
if (message.ExecutionContextId == 0)
20472007
{

0 commit comments

Comments
 (0)