Skip to content

Commit e1571f6

Browse files
kblokMeir017
authored andcommitted
Add browserUrl option to Puppeteer.ConnectAsync (#917)
1 parent 749b9a9 commit e1571f6

File tree

4 files changed

+98
-3
lines changed

4 files changed

+98
-3
lines changed

lib/PuppeteerSharp.Tests/ConnectionTests/ConnectionTests.cs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System;
2-
using System.Threading.Tasks;
1+
using System.Threading.Tasks;
32
using Xunit;
43
using Xunit.Abstractions;
54

@@ -34,6 +33,59 @@ public async Task ShouldCleanCallbackList()
3433
await Page.SetJavaScriptEnabledAsync(true);
3534
Assert.False(Page.Client.HasPendingCallbacks());
3635
}
36+
37+
[Fact]
38+
public async Task ShouldBeAbleToConnectUsingBrowserURLWithAndWithoutTrailingSlash()
39+
{
40+
var options = TestConstants.DefaultBrowserOptions();
41+
options.Args = new string[] { "--remote-debugging-port=21222" };
42+
var originalBrowser = await Puppeteer.LaunchAsync(options);
43+
var browserURL = "http://127.0.0.1:21222";
44+
45+
var browser1 = await Puppeteer.ConnectAsync(new ConnectOptions { BrowserURL = browserURL });
46+
var page1 = await browser1.NewPageAsync();
47+
Assert.Equal(56, await page1.EvaluateExpressionAsync<int>("7 * 8"));
48+
browser1.Disconnect();
49+
50+
var browser2 = await Puppeteer.ConnectAsync(new ConnectOptions { BrowserURL = browserURL + "/" });
51+
var page2 = await browser2.NewPageAsync();
52+
Assert.Equal(56, await page2.EvaluateExpressionAsync<int>("7 * 8"));
53+
browser2.Disconnect();
54+
await originalBrowser.CloseAsync();
55+
}
56+
57+
[Fact]
58+
public async Task ShouldThrowWhenUsingBothBrowserWSEndpointAndBrowserURL()
59+
{
60+
var options = TestConstants.DefaultBrowserOptions();
61+
options.Args = new string[] { "--remote-debugging-port=21222" };
62+
var originalBrowser = await Puppeteer.LaunchAsync(options);
63+
var browserURL = "http://127.0.0.1:21222";
64+
65+
await Assert.ThrowsAsync<PuppeteerException>(() => Puppeteer.ConnectAsync(new ConnectOptions
66+
{
67+
BrowserURL = browserURL,
68+
BrowserWSEndpoint = originalBrowser.WebSocketEndpoint
69+
}));
70+
71+
await originalBrowser.CloseAsync();
72+
}
73+
74+
[Fact]
75+
public async Task ShouldThrowWhenTryingToConnectToNonExistingBrowser()
76+
{
77+
var options = TestConstants.DefaultBrowserOptions();
78+
options.Args = new string[] { "--remote-debugging-port=21222" };
79+
var originalBrowser = await Puppeteer.LaunchAsync(options);
80+
var browserURL = "http://127.0.0.1:2122";
81+
82+
await Assert.ThrowsAsync<ChromiumProcessException>(() => Puppeteer.ConnectAsync(new ConnectOptions
83+
{
84+
BrowserURL = browserURL
85+
}));
86+
87+
await originalBrowser.CloseAsync();
88+
}
3789

3890
private async Task TheSourceOfTheProblems() => await Page.Client.SendAsync("ThisCommand.DoesNotExist");
3991
}

lib/PuppeteerSharp/ConnectOptions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ public class ConnectOptions : IBrowserOptions, IConnectionOptions
2727
/// </summary>
2828
public string BrowserWSEndpoint { get; set; }
2929

30+
/// <summary>
31+
/// A browser url to connect to, in format `http://${host}:${port}`.
32+
/// Use interchangeably with `browserWSEndpoint` to let Puppeteer fetch it from <see href="https://chromedevtools.github.io/devtools-protocol/#how-do-i-access-the-browser-target">metadata endpoin</see>.
33+
/// </summary>
34+
public string BrowserURL { get; set; }
35+
3036
/// <summary>
3137
/// Slows down Puppeteer operations by the specified amount of milliseconds. Useful so that you can see what is going on.
3238
/// </summary>

lib/PuppeteerSharp/Launcher.cs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using System.IO;
55
using Microsoft.Extensions.Logging;
66
using PuppeteerSharp.Messaging;
7+
using System.Net.Http;
8+
using Newtonsoft.Json;
79

810
namespace PuppeteerSharp
911
{
@@ -86,9 +88,18 @@ public async Task<Browser> ConnectAsync(ConnectOptions options)
8688
{
8789
EnsureSingleLaunchOrConnect();
8890

91+
if (!string.IsNullOrEmpty(options.BrowserURL) && !string.IsNullOrEmpty(options.BrowserWSEndpoint))
92+
{
93+
throw new PuppeteerException("Exactly one of browserWSEndpoint or browserURL must be passed to puppeteer.connect");
94+
}
95+
8996
try
9097
{
91-
var connection = await Connection.Create(options.BrowserWSEndpoint, options, _loggerFactory).ConfigureAwait(false);
98+
var browserWSEndpoint = string.IsNullOrEmpty(options.BrowserURL)
99+
? options.BrowserWSEndpoint
100+
: await GetWSEndpointAsync(options.BrowserURL).ConfigureAwait(false);
101+
102+
var connection = await Connection.Create(browserWSEndpoint, options, _loggerFactory).ConfigureAwait(false);
92103
var response = await connection.SendAsync<GetBrowserContextsResponse>("Target.getBrowserContexts");
93104
return await Browser
94105
.CreateAsync(connection, response.BrowserContextIds, options.IgnoreHTTPSErrors, options.DefaultViewport, null)
@@ -100,6 +111,25 @@ public async Task<Browser> ConnectAsync(ConnectOptions options)
100111
}
101112
}
102113

114+
private async Task<string> GetWSEndpointAsync(string browserURL)
115+
{
116+
try
117+
{
118+
if (Uri.TryCreate(new Uri(browserURL), "/json/version", out var endpointURL))
119+
{
120+
var client = new HttpClient();
121+
var data = await client.GetStringAsync(endpointURL).ConfigureAwait(false);
122+
return JsonConvert.DeserializeObject<WSEndpointResponse>(data).WebSocketDebuggerUrl;
123+
}
124+
125+
throw new PuppeteerException($"Invalid URL {browserURL}");
126+
}
127+
catch (Exception ex)
128+
{
129+
throw new PuppeteerException($"Failed to fetch browser webSocket url from {browserURL}.", ex);
130+
}
131+
}
132+
103133
/// <summary>
104134
/// Gets the executable path.
105135
/// </summary>
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 WSEndpointResponse
4+
{
5+
public string WebSocketDebuggerUrl { get; set; }
6+
}
7+
}

0 commit comments

Comments
 (0)