Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: make navigator not runtime-lookup process.version, arch, or platform #53765

Merged
merged 1 commit into from
Jul 15, 2024
Merged
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
67 changes: 34 additions & 33 deletions lib/internal/navigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,8 @@ const {
StringPrototypeSlice,
StringPrototypeToUpperCase,
Symbol,
globalThis,
} = primordials;

const {
Intl,
} = globalThis;

const {
ERR_ILLEGAL_CONSTRUCTOR,
} = require('internal/errors').codes;
Expand All @@ -27,60 +22,67 @@ const {
} = internalBinding('os');

const kInitialize = Symbol('kInitialize');
const nodeVersion = process.version;

const {
platform,
arch,
version: nodeVersion,
} = require('internal/process/per_thread');

const {
language,
} = internalBinding('config');

/**
* @param {object} process
* @param {string} process.platform
* @param {string} process.arch
* @param {string} arch
* @param {string} platform
* @returns {string}
*/
function getNavigatorPlatform(process) {
if (process.platform === 'darwin') {
function getNavigatorPlatform(arch, platform) {
if (platform === 'darwin') {
// On macOS, modern browsers return 'MacIntel' even if running on Apple Silicon.
return 'MacIntel';
} else if (process.platform === 'win32') {
} else if (platform === 'win32') {
// On Windows, modern browsers return 'Win32' even if running on a 64-bit version of Windows.
// https://developer.mozilla.org/en-US/docs/Web/API/Navigator/platform#usage_notes
return 'Win32';
} else if (process.platform === 'linux') {
if (process.arch === 'ia32') {
} else if (platform === 'linux') {
if (arch === 'ia32') {
return 'Linux i686';
} else if (process.arch === 'x64') {
} else if (arch === 'x64') {
return 'Linux x86_64';
}
return `Linux ${process.arch}`;
} else if (process.platform === 'freebsd') {
if (process.arch === 'ia32') {
return `Linux ${arch}`;
} else if (platform === 'freebsd') {
if (arch === 'ia32') {
return 'FreeBSD i386';
} else if (process.arch === 'x64') {
} else if (arch === 'x64') {
return 'FreeBSD amd64';
}
return `FreeBSD ${process.arch}`;
} else if (process.platform === 'openbsd') {
if (process.arch === 'ia32') {
return `FreeBSD ${arch}`;
} else if (platform === 'openbsd') {
if (arch === 'ia32') {
return 'OpenBSD i386';
} else if (process.arch === 'x64') {
} else if (arch === 'x64') {
return 'OpenBSD amd64';
}
return `OpenBSD ${process.arch}`;
} else if (process.platform === 'sunos') {
if (process.arch === 'ia32') {
return `OpenBSD ${arch}`;
} else if (platform === 'sunos') {
if (arch === 'ia32') {
return 'SunOS i86pc';
}
return `SunOS ${process.arch}`;
} else if (process.platform === 'aix') {
return `SunOS ${arch}`;
} else if (platform === 'aix') {
return 'AIX';
}
return `${StringPrototypeToUpperCase(process.platform[0])}${StringPrototypeSlice(process.platform, 1)} ${process.arch}`;
return `${StringPrototypeToUpperCase(platform[0])}${StringPrototypeSlice(platform, 1)} ${arch}`;
}

class Navigator {
// Private properties are used to avoid brand validations.
#availableParallelism;
#userAgent;
#platform;
#language;
#languages;

constructor() {
Expand All @@ -102,8 +104,7 @@ class Navigator {
* @return {string}
*/
get language() {
this.#language ??= Intl?.Collator().resolvedOptions().locale || 'en-US';
return this.#language;
return language;
}

/**
Expand All @@ -126,7 +127,7 @@ class Navigator {
* @return {string}
*/
get platform() {
this.#platform ??= getNavigatorPlatform(process);
this.#platform ??= getNavigatorPlatform(arch, platform);
return this.#platform;
}
}
Expand Down
10 changes: 9 additions & 1 deletion lib/internal/process/per_thread.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ const {
validateNumber,
validateObject,
} = require('internal/validators');
const { getValidatedPath } = require('internal/fs/utils');

const constants = internalBinding('constants').os.signals;

let getValidatedPath; // We need to lazy load it because of the circular dependency.

const kInternal = Symbol('internal properties');

function assert(x, msg) {
Expand Down Expand Up @@ -253,6 +255,7 @@ function wrapProcessMethods(binding) {
*/
function loadEnvFile(path = undefined) { // Provide optional value so that `loadEnvFile.length` returns 0
if (path != null) {
getValidatedPath ??= require('internal/fs/utils').getValidatedPath;
path = getValidatedPath(path);
_loadEnvFile(path);
} else {
Expand Down Expand Up @@ -421,11 +424,16 @@ function toggleTraceCategoryState(asyncHooksEnabled) {
}
}

const { arch, platform, version } = process;

module.exports = {
toggleTraceCategoryState,
assert,
buildAllowedFlags,
wrapProcessMethods,
hrtime,
hrtimeBigInt,
arch,
platform,
version,
};
5 changes: 5 additions & 0 deletions lib/internal/process/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ const {
globalThis,
} = primordials;

const {
Intl,
} = globalThis;

const {
getOptionValue,
refreshOptions,
Expand Down Expand Up @@ -327,6 +331,7 @@ function setupNavigator() {

// https://html.spec.whatwg.org/multipage/system-state.html#the-navigator-object
exposeLazyInterfaces(globalThis, 'internal/navigator', ['Navigator']);
internalBinding('config').language = Intl?.Collator().resolvedOptions().locale || 'en-US';
defineReplaceableLazyAttribute(globalThis, 'internal/navigator', ['navigator'], false);
}

Expand Down
6 changes: 5 additions & 1 deletion lib/internal/url.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ const {
isWindows,
} = require('internal/util');

const {
platform,
} = require('internal/process/per_thread');

const {
markTransferMode,
} = require('internal/worker/js_transferable');
Expand Down Expand Up @@ -1469,7 +1473,7 @@ function getPathFromURLWin32(url) {

function getPathFromURLPosix(url) {
if (url.hostname !== '') {
throw new ERR_INVALID_FILE_URL_HOST(process.platform);
throw new ERR_INVALID_FILE_URL_HOST(platform);
}
const pathname = url.pathname;
for (let n = 0; n < pathname.length; n++) {
Expand Down
64 changes: 46 additions & 18 deletions test/parallel/test-navigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,36 @@

'use strict';

const common = require('../common');
/* eslint node-core/require-common-first: 0 */

const assert = require('assert');

{

// Ensures `navigator` has not been evaluated yet
assert.strictEqual(require.resolve('../common') in require.cache, false);

const { version, platform, arch } = process;
try {
let called = false;
Object.defineProperty(process, 'arch', { get() { called += 'arch|'; return arch; } });
Object.defineProperty(process, 'platform', { get() { called = 'platform|'; return platform; } });
Object.defineProperty(process, 'version', { get() { called = 'version|'; return version; } });

navigator; // eslint-disable-line no-unused-expressions

assert.strictEqual(
called,
false
);
} finally {
Object.defineProperty(process, 'arch', { value: arch });
Object.defineProperty(process, 'platform', { value: platform });
Object.defineProperty(process, 'version', { value: version });
}
}

const common = require('../common');
const { getNavigatorPlatform } = require('internal/navigator');
const { execFile } = require('child_process');

Expand Down Expand Up @@ -57,23 +85,23 @@ if (process.platform === 'darwin') {
assert.strictEqual(navigator.platform, `${process.platform[0].toUpperCase()}${process.platform.slice(1)} ${process.arch}`);
}

assert.strictEqual(getNavigatorPlatform({ arch: 'x64', platform: 'darwin' }), 'MacIntel');
assert.strictEqual(getNavigatorPlatform({ arch: 'arm64', platform: 'darwin' }), 'MacIntel');
assert.strictEqual(getNavigatorPlatform({ arch: 'ia32', platform: 'linux' }), 'Linux i686');
assert.strictEqual(getNavigatorPlatform({ arch: 'x64', platform: 'linux' }), 'Linux x86_64');
assert.strictEqual(getNavigatorPlatform({ arch: 'arm64', platform: 'linux' }), 'Linux arm64');
assert.strictEqual(getNavigatorPlatform({ arch: 'x64', platform: 'win32' }), 'Win32');
assert.strictEqual(getNavigatorPlatform({ arch: 'arm64', platform: 'win32' }), 'Win32');
assert.strictEqual(getNavigatorPlatform({ arch: 'ia32', platform: 'freebsd' }), 'FreeBSD i386');
assert.strictEqual(getNavigatorPlatform({ arch: 'x64', platform: 'freebsd' }), 'FreeBSD amd64');
assert.strictEqual(getNavigatorPlatform({ arch: 'arm64', platform: 'freebsd' }), 'FreeBSD arm64');
assert.strictEqual(getNavigatorPlatform({ arch: 'ia32', platform: 'openbsd' }), 'OpenBSD i386');
assert.strictEqual(getNavigatorPlatform({ arch: 'x64', platform: 'openbsd' }), 'OpenBSD amd64');
assert.strictEqual(getNavigatorPlatform({ arch: 'arm64', platform: 'openbsd' }), 'OpenBSD arm64');
assert.strictEqual(getNavigatorPlatform({ arch: 'ia32', platform: 'sunos' }), 'SunOS i86pc');
assert.strictEqual(getNavigatorPlatform({ arch: 'x64', platform: 'sunos' }), 'SunOS x64');
assert.strictEqual(getNavigatorPlatform({ arch: 'ppc', platform: 'aix' }), 'AIX');
assert.strictEqual(getNavigatorPlatform({ arch: 'x64', platform: 'reactos' }), 'Reactos x64');
assert.strictEqual(getNavigatorPlatform('x64', 'darwin'), 'MacIntel');
assert.strictEqual(getNavigatorPlatform('arm64', 'darwin'), 'MacIntel');
assert.strictEqual(getNavigatorPlatform('ia32', 'linux'), 'Linux i686');
assert.strictEqual(getNavigatorPlatform('x64', 'linux'), 'Linux x86_64');
assert.strictEqual(getNavigatorPlatform('arm64', 'linux'), 'Linux arm64');
assert.strictEqual(getNavigatorPlatform('x64', 'win32'), 'Win32');
assert.strictEqual(getNavigatorPlatform('arm64', 'win32'), 'Win32');
assert.strictEqual(getNavigatorPlatform('ia32', 'freebsd'), 'FreeBSD i386');
assert.strictEqual(getNavigatorPlatform('x64', 'freebsd'), 'FreeBSD amd64');
assert.strictEqual(getNavigatorPlatform('arm64', 'freebsd'), 'FreeBSD arm64');
assert.strictEqual(getNavigatorPlatform('ia32', 'openbsd'), 'OpenBSD i386');
assert.strictEqual(getNavigatorPlatform('x64', 'openbsd'), 'OpenBSD amd64');
assert.strictEqual(getNavigatorPlatform('arm64', 'openbsd'), 'OpenBSD arm64');
assert.strictEqual(getNavigatorPlatform('ia32', 'sunos'), 'SunOS i86pc');
assert.strictEqual(getNavigatorPlatform('x64', 'sunos'), 'SunOS x64');
assert.strictEqual(getNavigatorPlatform('ppc', 'aix'), 'AIX');
assert.strictEqual(getNavigatorPlatform('x64', 'reactos'), 'Reactos x64');

assert.strictEqual(typeof navigator.language, 'string');
assert.strictEqual(navigator.language.length !== 0, true);
Expand Down
Loading