fix(chromium): emulate navigator.userAgentData along with UA (#29159)
Fixes #28989, fixes #29139.
This commit is contained in:
parent
129f5bfdbe
commit
bc83d7084c
|
@ -1094,7 +1094,11 @@ class FrameSession {
|
|||
|
||||
async _updateUserAgent(): Promise<void> {
|
||||
const options = this._crPage._browserContext._options;
|
||||
await this._client.send('Emulation.setUserAgentOverride', { userAgent: options.userAgent || '', acceptLanguage: options.locale });
|
||||
await this._client.send('Emulation.setUserAgentOverride', {
|
||||
userAgent: options.userAgent || '',
|
||||
acceptLanguage: options.locale,
|
||||
userAgentMetadata: calculateUserAgentMetadata(options),
|
||||
});
|
||||
}
|
||||
|
||||
private async _setDefaultFontFamilies(session: CRSession) {
|
||||
|
@ -1257,3 +1261,48 @@ async function emulateTimezone(session: CRSession, timezoneId: string) {
|
|||
}
|
||||
|
||||
const contextDelegateSymbol = Symbol('delegate');
|
||||
|
||||
// Chromium reference: https://source.chromium.org/chromium/chromium/src/+/main:components/embedder_support/user_agent_utils.cc;l=434;drc=70a6711e08e9f9e0d8e4c48e9ba5cab62eb010c2
|
||||
function calculateUserAgentMetadata(options: channels.BrowserNewContextParams) {
|
||||
const ua = options.userAgent;
|
||||
if (!ua)
|
||||
return undefined;
|
||||
const metadata: Protocol.Emulation.UserAgentMetadata = {
|
||||
mobile: !!options.isMobile,
|
||||
model: '',
|
||||
architecture: 'x64',
|
||||
platform: 'Windows',
|
||||
platformVersion: '',
|
||||
};
|
||||
const androidMatch = ua.match(/Android (\d+(\.\d+)?(\.\d+)?)/);
|
||||
const iPhoneMatch = ua.match(/iPhone OS (\d+(_\d+)?)/);
|
||||
const iPadMatch = ua.match(/iPad; CPU OS (\d+(_\d+)?)/);
|
||||
const macOSMatch = ua.match(/Mac OS X (\d+(_\d+)?(_\d+)?)/);
|
||||
const windowsMatch = ua.match(/Windows\D+(\d+(\.\d+)?(\.\d+)?)/);
|
||||
if (androidMatch) {
|
||||
metadata.platform = 'Android';
|
||||
metadata.platformVersion = androidMatch[1];
|
||||
metadata.architecture = 'arm';
|
||||
} else if (iPhoneMatch) {
|
||||
metadata.platform = 'iOS';
|
||||
metadata.platformVersion = iPhoneMatch[1];
|
||||
metadata.architecture = 'arm';
|
||||
} else if (iPadMatch) {
|
||||
metadata.platform = 'iOS';
|
||||
metadata.platformVersion = iPadMatch[1];
|
||||
metadata.architecture = 'arm';
|
||||
} else if (macOSMatch) {
|
||||
metadata.platform = 'macOS';
|
||||
metadata.platformVersion = macOSMatch[1];
|
||||
if (!ua.includes('Intel'))
|
||||
metadata.architecture = 'arm';
|
||||
} else if (windowsMatch) {
|
||||
metadata.platform = 'Windows';
|
||||
metadata.platformVersion = windowsMatch[1];
|
||||
} else if (ua.toLowerCase().includes('linux')) {
|
||||
metadata.platform = 'Linux';
|
||||
}
|
||||
if (ua.includes('ARM'))
|
||||
metadata.architecture = 'arm';
|
||||
return metadata;
|
||||
}
|
||||
|
|
|
@ -106,3 +106,39 @@ it('custom user agent for download', async ({ server, contextFactory, browserVer
|
|||
const req = await serverRequest;
|
||||
expect(req.headers['user-agent']).toBe('MyCustomUA');
|
||||
});
|
||||
|
||||
it('should work for navigator.userAgentData and sec-ch-ua headers', async ({ playwright, browserName, browser, server }) => {
|
||||
it.skip(browserName !== 'chromium', 'This API is Chromium-only');
|
||||
|
||||
{
|
||||
const context = await browser.newContext();
|
||||
const page = await context.newPage();
|
||||
const [request] = await Promise.all([
|
||||
server.waitForRequest('/empty.html'),
|
||||
page.goto(server.EMPTY_PAGE),
|
||||
]);
|
||||
expect.soft(request.headers['sec-ch-ua']).toContain(`"Chromium"`);
|
||||
expect.soft(request.headers['sec-ch-ua-mobile']).toBe(`?0`);
|
||||
expect.soft(request.headers['sec-ch-ua-platform']).toBeTruthy();
|
||||
expect.soft(await page.evaluate(() => (window.navigator as any).userAgentData.toJSON())).toEqual(
|
||||
expect.objectContaining({ mobile: false })
|
||||
);
|
||||
await context.close();
|
||||
}
|
||||
|
||||
{
|
||||
const context = await browser.newContext(playwright.devices['Pixel 7']);
|
||||
const page = await context.newPage();
|
||||
const [request] = await Promise.all([
|
||||
server.waitForRequest('/empty.html'),
|
||||
page.goto(server.EMPTY_PAGE),
|
||||
]);
|
||||
expect.soft(request.headers['sec-ch-ua']).toContain(`"Chromium"`);
|
||||
expect.soft(request.headers['sec-ch-ua-mobile']).toBe(`?1`);
|
||||
expect.soft(request.headers['sec-ch-ua-platform']).toBe(`"Android"`);
|
||||
expect.soft(await page.evaluate(() => (window.navigator as any).userAgentData.toJSON())).toEqual(
|
||||
expect.objectContaining({ mobile: true, platform: 'Android' })
|
||||
);
|
||||
await context.close();
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue