Skip to content

Commit de2ac96

Browse files
authored
Bidi setUserAgent (#3020)
1 parent 6b3aa50 commit de2ac96

File tree

4 files changed

+125
-20
lines changed

4 files changed

+125
-20
lines changed

lib/PuppeteerSharp.Nunit/TestExpectations/TestExpectations.local.json

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,21 +1012,6 @@
10121012
"FAIL"
10131013
]
10141014
},
1015-
{
1016-
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
1017-
"testIdPattern": "[page.spec] *Page.setUserAgent*",
1018-
"platforms": [
1019-
"darwin",
1020-
"linux",
1021-
"win32"
1022-
],
1023-
"parameters": [
1024-
"webDriverBiDi"
1025-
],
1026-
"expectations": [
1027-
"FAIL"
1028-
]
1029-
},
10301015
{
10311016
"comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one",
10321017
"testIdPattern": "[page.spec] *Page.url*",

lib/PuppeteerSharp/Bidi/BidiHttpRequest.cs

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,17 @@ private BidiHttpRequest(Request request, BidiFrame frame, BidiHttpRequest redire
6262
internal bool HasInternalHeaderOverwrite => ExtraHttpHeaders.Values.Count != 0 || UserAgentHeaders.Values.Count != 0;
6363

6464
/// <inheritdoc />
65-
public override Task ContinueAsync(Payload payloadOverrides = null, int? priority = null) => throw new NotImplementedException();
65+
public override async Task ContinueAsync(Payload payloadOverrides = null, int? priority = null)
66+
{
67+
// Merge the original request headers with extra headers and user agent headers
68+
var mergedHeaders = GetMergedHeaders(payloadOverrides?.Headers);
69+
var bidiHeaders = ConvertToBidiHeaders(mergedHeaders);
70+
71+
await _request.ContinueRequestAsync(
72+
url: payloadOverrides?.Url,
73+
method: payloadOverrides?.Method?.ToString(),
74+
headers: bidiHeaders?.Count > 0 ? bidiHeaders : null).ConfigureAwait(false);
75+
}
6676

6777
/// <inheritdoc />
6878
public override Task RespondAsync(ResponseData response, int? priority = null) => throw new NotImplementedException();
@@ -80,14 +90,67 @@ internal static BidiHttpRequest From(Request bidiRequest, BidiFrame frame, BidiH
8090
return request;
8191
}
8292

83-
internal override Task FinalizeInterceptionsAsync()
93+
internal override async Task FinalizeInterceptionsAsync()
8494
{
85-
// TODO: Implement this
86-
return Task.CompletedTask;
95+
foreach (var handler in _interception.Handlers)
96+
{
97+
await handler().ConfigureAwait(false);
98+
}
99+
100+
_interception.Handlers.Clear();
87101
}
88102

89103
internal override void EnqueueInterceptionAction(Func<IRequest, Task> pendingHandler) => throw new NotImplementedException();
90104

105+
private static List<WebDriverBiDi.Network.Header> ConvertToBidiHeaders(Dictionary<string, string> headers)
106+
{
107+
if (headers == null || headers.Count == 0)
108+
{
109+
return null;
110+
}
111+
112+
var bidiHeaders = new List<WebDriverBiDi.Network.Header>();
113+
foreach (var kvp in headers)
114+
{
115+
bidiHeaders.Add(new WebDriverBiDi.Network.Header(kvp.Key, kvp.Value));
116+
}
117+
118+
return bidiHeaders;
119+
}
120+
121+
private Dictionary<string, string> GetMergedHeaders(Dictionary<string, string> overrideHeaders)
122+
{
123+
// Start with the original request headers
124+
var headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
125+
foreach (var header in _request.Headers)
126+
{
127+
headers[header.Name.ToLowerInvariant()] = header.Value.Value;
128+
}
129+
130+
// Add extra HTTP headers from the page
131+
foreach (var kvp in ExtraHttpHeaders)
132+
{
133+
headers[kvp.Key.ToLowerInvariant()] = kvp.Value;
134+
}
135+
136+
// Add user agent headers from the page
137+
foreach (var kvp in UserAgentHeaders)
138+
{
139+
headers[kvp.Key.ToLowerInvariant()] = kvp.Value;
140+
}
141+
142+
// Apply any override headers from the payload
143+
if (overrideHeaders != null)
144+
{
145+
foreach (var kvp in overrideHeaders)
146+
{
147+
headers[kvp.Key.ToLowerInvariant()] = kvp.Value;
148+
}
149+
}
150+
151+
return headers;
152+
}
153+
91154
private void Initialize()
92155
{
93156
_request.Redirect += (sender, e) =>

lib/PuppeteerSharp/Bidi/BidiPage.cs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public class BidiPage : Page
4242
private InternalNetworkConditions _emulatedNetworkConditions;
4343
private TaskCompletionSource<bool> _closedTcs;
4444
private string _requestInterception;
45+
private string _userAgentInterception;
4546

4647
private BidiPage(BidiBrowserContext browserContext, BrowsingContext browsingContext) : base(browserContext.ScreenshotTaskQueue)
4748
{
@@ -287,7 +288,45 @@ public override async Task SetCacheEnabledAsync(bool enabled = true)
287288
public override Task EmulateMediaFeaturesAsync(IEnumerable<MediaFeatureValue> features) => throw new NotImplementedException();
288289

289290
/// <inheritdoc />
290-
public override Task SetUserAgentAsync(string userAgent, UserAgentMetadata userAgentData = null) => throw new NotImplementedException();
291+
public override async Task SetUserAgentAsync(string userAgent, UserAgentMetadata userAgentData = null)
292+
{
293+
if (!BidiBrowser.CdpSupported && userAgentData != null)
294+
{
295+
throw new PuppeteerException("Current Browser does not support `userAgentMetadata`");
296+
}
297+
298+
var enable = !string.IsNullOrEmpty(userAgent);
299+
300+
// Update the UserAgentHeaders dictionary
301+
UserAgentHeaders.Clear();
302+
if (enable)
303+
{
304+
UserAgentHeaders["User-Agent"] = userAgent;
305+
}
306+
307+
// Toggle network interception for BeforeRequestSent phase
308+
_userAgentInterception = await ToggleInterceptionAsync(
309+
[InterceptPhase.BeforeRequestSent],
310+
_userAgentInterception,
311+
enable).ConfigureAwait(false);
312+
313+
// Override navigator.userAgent in JavaScript for all frames
314+
var overrideNavigatorUserAgent = @"(userAgent) => {
315+
Object.defineProperty(navigator, 'userAgent', {
316+
value: userAgent,
317+
configurable: true,
318+
});
319+
}";
320+
321+
var frames = Frames;
322+
var tasks = new List<Task>(frames.Length);
323+
foreach (var frame in frames)
324+
{
325+
tasks.Add(frame.EvaluateFunctionAsync(overrideNavigatorUserAgent, userAgent));
326+
}
327+
328+
await Task.WhenAll(tasks).ConfigureAwait(false);
329+
}
291330

292331
/// <inheritdoc />
293332
public override async Task SetViewportAsync(ViewPortOptions viewport)

lib/PuppeteerSharp/Bidi/Core/Request.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
// * SOFTWARE.
2222

2323
using System;
24+
using System.Collections.Generic;
25+
using System.Threading.Tasks;
2426
using WebDriverBiDi.Network;
2527

2628
namespace PuppeteerSharp.Bidi.Core;
@@ -74,6 +76,8 @@ public Request LastRedirect
7476

7577
public string Url => _eventArgs.Request.Url;
7678

79+
public IList<ReadOnlyHeader> Headers => _eventArgs.Request.Headers;
80+
7781
public WebDriverBiDi.Network.ResponseData Response => _response;
7882

7983
public bool HasError => _error != null;
@@ -90,6 +94,20 @@ public void Dispose()
9094
IsDisposed = true;
9195
}
9296

97+
internal async Task ContinueRequestAsync(
98+
string url = null,
99+
string method = null,
100+
List<Header> headers = null)
101+
{
102+
var commandParams = new ContinueRequestCommandParameters(Id)
103+
{
104+
Url = url,
105+
Method = method,
106+
Headers = headers,
107+
};
108+
await Session.Driver.Network.ContinueRequestAsync(commandParams).ConfigureAwait(false);
109+
}
110+
93111
private void Initialize()
94112
{
95113
_browsingContext.Closed += (sender, args) =>

0 commit comments

Comments
 (0)