Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions src/PlaywrightNative.Tests/OfficialClientCertificateExtras.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,13 @@ public async ValueTask DisposeAsync()
internal sealed class OfficialTlsSniRejectServer : IAsyncDisposable
{
private readonly TcpListener _listener;
private readonly X509Certificate2 _cert;
private readonly CancellationTokenSource _cts = new();
private readonly Task _acceptLoop;
private readonly SslProtocols _protocol;

private OfficialTlsSniRejectServer(TcpListener listener, X509Certificate2 cert, SslProtocols protocol)
private OfficialTlsSniRejectServer(TcpListener listener, SslProtocols protocol)
{
_listener = listener;
_cert = cert;
_protocol = protocol;
Port = ((IPEndPoint)listener.LocalEndpoint).Port;
_acceptLoop = AcceptLoopAsync();
Expand All @@ -133,12 +131,9 @@ private OfficialTlsSniRejectServer(TcpListener listener, X509Certificate2 cert,

internal static OfficialTlsSniRejectServer Start(SslProtocols protocol)
{
X509Certificate2 cert = OfficialClientCertificateServer.LoadPem(
OfficialClientCertificateServer.Asset("client-certificates/server/server_cert.pem"),
OfficialClientCertificateServer.Asset("client-certificates/server/server_key.pem"));
TcpListener listener = new(IPAddress.Loopback, 0);
listener.Start();
return new OfficialTlsSniRejectServer(listener, cert, protocol);
return new OfficialTlsSniRejectServer(listener, protocol);
}

public async ValueTask DisposeAsync()
Expand All @@ -161,7 +156,6 @@ public async ValueTask DisposeAsync()
}

_cts.Dispose();
_cert.Dispose();
}

private async Task AcceptLoopAsync()
Expand Down Expand Up @@ -198,9 +192,12 @@ private async Task HandleAsync(TcpClient client)
await using (NetworkStream stream = client.GetStream())
await using (SslStream ssl = new(stream, leaveInnerStreamOpen: false))
{
// Upstream rejects from SNICallback, after the ClientHello
// arrives. SslStream only runs the selection callback when no
// ServerCertificate is set; setting both throws before the
// handshake reads anything.
SslServerAuthenticationOptions options = new()
{
ServerCertificate = _cert,
ClientCertificateRequired = true,
EnabledSslProtocols = _protocol,
CertificateRevocationCheckMode = X509RevocationMode.NoCheck,
Expand Down
16 changes: 14 additions & 2 deletions src/PlaywrightNative/Helpers/ScreenshotDecorations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Playwright;
using PlaywrightNative.Chromium;
using PlaywrightNative.WebKit;

namespace PlaywrightNative.Helpers
Expand Down Expand Up @@ -404,7 +405,7 @@ private static async Task InjectStyleAsync(IPage page, string css, List<IElement

foreach (IFrame frame in frames)
{
if (frame == null || frame.ParentFrame == null || frame.IsDetached)
if (frame == null || frame.ParentFrame == null || frame.IsDetached || LacksExistingContext(frame))
{
continue;
}
Expand Down Expand Up @@ -457,7 +458,7 @@ private static async Task EvaluateInFramesAsync(IPage page, string expression)

foreach (IFrame frame in frames)
{
if (frame == null || frame.IsDetached)
if (frame == null || frame.IsDetached || (frame.ParentFrame != null && LacksExistingContext(frame)))
{
continue;
}
Expand Down Expand Up @@ -518,6 +519,17 @@ private static async Task EvaluateInWebKitUtilityAsync(WKPage page, string expre
}
}

/// <summary>
/// Upstream decorates frames with <c>nonStallingEvaluateInExistingContext</c>:
/// a Chromium child frame whose document has no live execution context yet
/// (a stalled subframe navigation) is skipped instead of waiting for one.
/// </summary>
/// <param name="frame">The frame to decorate.</param>
/// <returns><see langword="true"/> when evaluating would wait for a new context.</returns>
private static bool LacksExistingContext(IFrame frame)
=> frame is ChromiumFrame chromium
&& (chromium.Frame.ExecutionContext == null || chromium.Frame.ExecutionContext.Destroyed.IsCompleted);

private static Task FinishAnimationsAsync(IPage page)
{
// Must share EvaluateInFramesAsync with RestoreAnimationsJs so
Expand Down
Loading