Skip to content

Commit e5ddc77

Browse files
authored
Merge branch 'nodejs:main' into main
2 parents 685eef7 + 7ae193d commit e5ddc77

10 files changed

+168
-86
lines changed

lib/internal/process/execution.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ function tryGetCwd() {
4949

5050
let evalIndex = 0;
5151
function getEvalModuleUrl() {
52-
return pathToFileURL(`${process.cwd()}/[eval${++evalIndex}]`).href;
52+
return `${pathToFileURL(process.cwd())}/[eval${++evalIndex}]`;
5353
}
5454

5555
/**

lib/internal/url.js

+57-37
Original file line numberDiff line numberDiff line change
@@ -1498,44 +1498,75 @@ function fileURLToPath(path, options = kEmptyObject) {
14981498
return (windows ?? isWindows) ? getPathFromURLWin32(path) : getPathFromURLPosix(path);
14991499
}
15001500

1501-
// The following characters are percent-encoded when converting from file path
1502-
// to URL:
1503-
// - %: The percent character is the only character not encoded by the
1504-
// `pathname` setter.
1505-
// - \: Backslash is encoded on non-windows platforms since it's a valid
1506-
// character but the `pathname` setters replaces it by a forward slash.
1507-
// - LF: The newline character is stripped out by the `pathname` setter.
1508-
// (See whatwg/url#419)
1509-
// - CR: The carriage return character is also stripped out by the `pathname`
1510-
// setter.
1511-
// - TAB: The tab character is also stripped out by the `pathname` setter.
1501+
// RFC1738 defines the following chars as "unsafe" for URLs
1502+
// @see https://www.ietf.org/rfc/rfc1738.txt 2.2. URL Character Encoding Issues
15121503
const percentRegEx = /%/g;
1513-
const backslashRegEx = /\\/g;
15141504
const newlineRegEx = /\n/g;
15151505
const carriageReturnRegEx = /\r/g;
15161506
const tabRegEx = /\t/g;
1517-
const questionRegex = /\?/g;
1507+
const quoteRegEx = /"/g;
15181508
const hashRegex = /#/g;
1509+
const spaceRegEx = / /g;
1510+
const questionMarkRegex = /\?/g;
1511+
const openSquareBracketRegEx = /\[/g;
1512+
const backslashRegEx = /\\/g;
1513+
const closeSquareBracketRegEx = /]/g;
1514+
const caretRegEx = /\^/g;
1515+
const verticalBarRegEx = /\|/g;
1516+
const tildeRegEx = /~/g;
15191517

15201518
function encodePathChars(filepath, options = kEmptyObject) {
1521-
const windows = options?.windows;
1522-
if (StringPrototypeIndexOf(filepath, '%') !== -1)
1519+
if (StringPrototypeIncludes(filepath, '%')) {
15231520
filepath = RegExpPrototypeSymbolReplace(percentRegEx, filepath, '%25');
1524-
// In posix, backslash is a valid character in paths:
1525-
if (!(windows ?? isWindows) && StringPrototypeIndexOf(filepath, '\\') !== -1)
1526-
filepath = RegExpPrototypeSymbolReplace(backslashRegEx, filepath, '%5C');
1527-
if (StringPrototypeIndexOf(filepath, '\n') !== -1)
1521+
}
1522+
1523+
if (StringPrototypeIncludes(filepath, '\t')) {
1524+
filepath = RegExpPrototypeSymbolReplace(tabRegEx, filepath, '%09');
1525+
}
1526+
if (StringPrototypeIncludes(filepath, '\n')) {
15281527
filepath = RegExpPrototypeSymbolReplace(newlineRegEx, filepath, '%0A');
1529-
if (StringPrototypeIndexOf(filepath, '\r') !== -1)
1528+
}
1529+
if (StringPrototypeIncludes(filepath, '\r')) {
15301530
filepath = RegExpPrototypeSymbolReplace(carriageReturnRegEx, filepath, '%0D');
1531-
if (StringPrototypeIndexOf(filepath, '\t') !== -1)
1532-
filepath = RegExpPrototypeSymbolReplace(tabRegEx, filepath, '%09');
1531+
}
1532+
if (StringPrototypeIncludes(filepath, ' ')) {
1533+
filepath = RegExpPrototypeSymbolReplace(spaceRegEx, filepath, '%20');
1534+
}
1535+
if (StringPrototypeIncludes(filepath, '"')) {
1536+
filepath = RegExpPrototypeSymbolReplace(quoteRegEx, filepath, '%22');
1537+
}
1538+
if (StringPrototypeIncludes(filepath, '#')) {
1539+
filepath = RegExpPrototypeSymbolReplace(hashRegex, filepath, '%23');
1540+
}
1541+
if (StringPrototypeIncludes(filepath, '?')) {
1542+
filepath = RegExpPrototypeSymbolReplace(questionMarkRegex, filepath, '%3F');
1543+
}
1544+
if (StringPrototypeIncludes(filepath, '[')) {
1545+
filepath = RegExpPrototypeSymbolReplace(openSquareBracketRegEx, filepath, '%5B');
1546+
}
1547+
// Back-slashes must be special-cased on Windows, where they are treated as path separator.
1548+
if (!options.windows && StringPrototypeIncludes(filepath, '\\')) {
1549+
filepath = RegExpPrototypeSymbolReplace(backslashRegEx, filepath, '%5C');
1550+
}
1551+
if (StringPrototypeIncludes(filepath, ']')) {
1552+
filepath = RegExpPrototypeSymbolReplace(closeSquareBracketRegEx, filepath, '%5D');
1553+
}
1554+
if (StringPrototypeIncludes(filepath, '^')) {
1555+
filepath = RegExpPrototypeSymbolReplace(caretRegEx, filepath, '%5E');
1556+
}
1557+
if (StringPrototypeIncludes(filepath, '|')) {
1558+
filepath = RegExpPrototypeSymbolReplace(verticalBarRegEx, filepath, '%7C');
1559+
}
1560+
if (StringPrototypeIncludes(filepath, '~')) {
1561+
filepath = RegExpPrototypeSymbolReplace(tildeRegEx, filepath, '%7E');
1562+
}
1563+
15331564
return filepath;
15341565
}
15351566

15361567
function pathToFileURL(filepath, options = kEmptyObject) {
1537-
const windows = options?.windows;
1538-
if ((windows ?? isWindows) && StringPrototypeStartsWith(filepath, '\\\\')) {
1568+
const windows = options?.windows ?? isWindows;
1569+
if (windows && StringPrototypeStartsWith(filepath, '\\\\')) {
15391570
const outURL = new URL('file://');
15401571
// UNC path format: \\server\share\resource
15411572
// Handle extended UNC path and standard UNC path
@@ -1566,20 +1597,9 @@ function pathToFileURL(filepath, options = kEmptyObject) {
15661597
);
15671598
return outURL;
15681599
}
1569-
let resolved = (windows ?? isWindows) ? path.win32.resolve(filepath) : path.posix.resolve(filepath);
1570-
1571-
// Call encodePathChars first to avoid encoding % again for ? and #.
1572-
resolved = encodePathChars(resolved, { windows });
1600+
const resolved = windows ? path.win32.resolve(filepath) : path.posix.resolve(filepath);
15731601

1574-
// Question and hash character should be included in pathname.
1575-
// Therefore, encoding is required to eliminate parsing them in different states.
1576-
// This is done as an optimization to not creating a URL instance and
1577-
// later triggering pathname setter, which impacts performance
1578-
if (StringPrototypeIndexOf(resolved, '?') !== -1)
1579-
resolved = RegExpPrototypeSymbolReplace(questionRegex, resolved, '%3F');
1580-
if (StringPrototypeIndexOf(resolved, '#') !== -1)
1581-
resolved = RegExpPrototypeSymbolReplace(hashRegex, resolved, '%23');
1582-
return new URL(`file://${resolved}`);
1602+
return new URL(`file://${encodePathChars(resolved, { windows })}`);
15831603
}
15841604

15851605
function toPathIfFileURL(fileURLOrPath) {

src/node_file.cc

+75-40
Original file line numberDiff line numberDiff line change
@@ -3127,6 +3127,55 @@ static void GetFormatOfExtensionlessFile(
31273127
return args.GetReturnValue().Set(EXTENSIONLESS_FORMAT_JAVASCRIPT);
31283128
}
31293129

3130+
#ifdef _WIN32
3131+
std::wstring ConvertToWideString(const std::string& str) {
3132+
int size_needed = MultiByteToWideChar(
3133+
CP_UTF8, 0, &str[0], static_cast<int>(str.size()), nullptr, 0);
3134+
std::wstring wstrTo(size_needed, 0);
3135+
MultiByteToWideChar(CP_UTF8,
3136+
0,
3137+
&str[0],
3138+
static_cast<int>(str.size()),
3139+
&wstrTo[0],
3140+
size_needed);
3141+
return wstrTo;
3142+
}
3143+
3144+
#define BufferValueToPath(str) \
3145+
std::filesystem::path(ConvertToWideString(str.ToString()))
3146+
3147+
std::string ConvertWideToUTF8(const std::wstring& wstr) {
3148+
if (wstr.empty()) return std::string();
3149+
3150+
int size_needed = WideCharToMultiByte(CP_UTF8,
3151+
0,
3152+
&wstr[0],
3153+
static_cast<int>(wstr.size()),
3154+
nullptr,
3155+
0,
3156+
nullptr,
3157+
nullptr);
3158+
std::string strTo(size_needed, 0);
3159+
WideCharToMultiByte(CP_UTF8,
3160+
0,
3161+
&wstr[0],
3162+
static_cast<int>(wstr.size()),
3163+
&strTo[0],
3164+
size_needed,
3165+
nullptr,
3166+
nullptr);
3167+
return strTo;
3168+
}
3169+
3170+
#define PathToString(path) ConvertWideToUTF8(path.wstring());
3171+
3172+
#else // _WIN32
3173+
3174+
#define BufferValueToPath(str) std::filesystem::path(str.ToStringView());
3175+
#define PathToString(path) path.native();
3176+
3177+
#endif // _WIN32
3178+
31303179
static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
31313180
Environment* env = Environment::GetCurrent(args);
31323181
Isolate* isolate = env->isolate();
@@ -3139,15 +3188,15 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
31393188
THROW_IF_INSUFFICIENT_PERMISSIONS(
31403189
env, permission::PermissionScope::kFileSystemRead, src.ToStringView());
31413190

3142-
auto src_path = std::filesystem::path(src.ToU8StringView());
3191+
auto src_path = BufferValueToPath(src);
31433192

31443193
BufferValue dest(isolate, args[1]);
31453194
CHECK_NOT_NULL(*dest);
31463195
ToNamespacedPath(env, &dest);
31473196
THROW_IF_INSUFFICIENT_PERMISSIONS(
31483197
env, permission::PermissionScope::kFileSystemWrite, dest.ToStringView());
31493198

3150-
auto dest_path = std::filesystem::path(dest.ToU8StringView());
3199+
auto dest_path = BufferValueToPath(dest);
31513200
bool dereference = args[2]->IsTrue();
31523201
bool recursive = args[3]->IsTrue();
31533202

@@ -3176,47 +3225,41 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
31763225
(src_status.type() == std::filesystem::file_type::directory) ||
31773226
(dereference && src_status.type() == std::filesystem::file_type::symlink);
31783227

3228+
auto src_path_str = PathToString(src_path);
3229+
auto dest_path_str = PathToString(dest_path);
3230+
31793231
if (!error_code) {
31803232
// Check if src and dest are identical.
31813233
if (std::filesystem::equivalent(src_path, dest_path)) {
3182-
std::u8string message =
3183-
u8"src and dest cannot be the same " + dest_path.u8string();
3184-
return THROW_ERR_FS_CP_EINVAL(
3185-
env, reinterpret_cast<const char*>(message.c_str()));
3234+
std::string message = "src and dest cannot be the same %s";
3235+
return THROW_ERR_FS_CP_EINVAL(env, message.c_str(), dest_path_str);
31863236
}
31873237

31883238
const bool dest_is_dir =
31893239
dest_status.type() == std::filesystem::file_type::directory;
3190-
31913240
if (src_is_dir && !dest_is_dir) {
3192-
std::u8string message = u8"Cannot overwrite non-directory " +
3193-
src_path.u8string() + u8" with directory " +
3194-
dest_path.u8string();
3241+
std::string message =
3242+
"Cannot overwrite non-directory %s with directory %s";
31953243
return THROW_ERR_FS_CP_DIR_TO_NON_DIR(
3196-
env, reinterpret_cast<const char*>(message.c_str()));
3244+
env, message.c_str(), src_path_str, dest_path_str);
31973245
}
31983246

31993247
if (!src_is_dir && dest_is_dir) {
3200-
std::u8string message = u8"Cannot overwrite directory " +
3201-
dest_path.u8string() + u8" with non-directory " +
3202-
src_path.u8string();
3248+
std::string message =
3249+
"Cannot overwrite directory %s with non-directory %s";
32033250
return THROW_ERR_FS_CP_NON_DIR_TO_DIR(
3204-
env, reinterpret_cast<const char*>(message.c_str()));
3251+
env, message.c_str(), dest_path_str, src_path_str);
32053252
}
32063253
}
32073254

3208-
std::u8string dest_path_str = dest_path.u8string();
3209-
std::u8string src_path_str = src_path.u8string();
32103255
if (!src_path_str.ends_with(std::filesystem::path::preferred_separator)) {
32113256
src_path_str += std::filesystem::path::preferred_separator;
32123257
}
32133258
// Check if dest_path is a subdirectory of src_path.
32143259
if (src_is_dir && dest_path_str.starts_with(src_path_str)) {
3215-
std::u8string message = u8"Cannot copy " + src_path.u8string() +
3216-
u8" to a subdirectory of self " +
3217-
dest_path.u8string();
3260+
std::string message = "Cannot copy %s to a subdirectory of self %s";
32183261
return THROW_ERR_FS_CP_EINVAL(
3219-
env, reinterpret_cast<const char*>(message.c_str()));
3262+
env, message.c_str(), src_path_str, dest_path_str);
32203263
}
32213264

32223265
auto dest_parent = dest_path.parent_path();
@@ -3227,11 +3270,9 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
32273270
dest_parent.parent_path() != dest_parent) {
32283271
if (std::filesystem::equivalent(
32293272
src_path, dest_path.parent_path(), error_code)) {
3230-
std::u8string message = u8"Cannot copy " + src_path.u8string() +
3231-
u8" to a subdirectory of self " +
3232-
dest_path.u8string();
3273+
std::string message = "Cannot copy %s to a subdirectory of self %s";
32333274
return THROW_ERR_FS_CP_EINVAL(
3234-
env, reinterpret_cast<const char*>(message.c_str()));
3275+
env, message.c_str(), src_path_str, dest_path_str);
32353276
}
32363277

32373278
// If equivalent fails, it's highly likely that dest_parent does not exist
@@ -3243,29 +3284,23 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
32433284
}
32443285

32453286
if (src_is_dir && !recursive) {
3246-
std::u8string message =
3247-
u8"Recursive option not enabled, cannot copy a directory: " +
3248-
src_path.u8string();
3249-
return THROW_ERR_FS_EISDIR(env,
3250-
reinterpret_cast<const char*>(message.c_str()));
3287+
std::string message =
3288+
"Recursive option not enabled, cannot copy a directory: %s";
3289+
return THROW_ERR_FS_EISDIR(env, message.c_str(), src_path_str);
32513290
}
32523291

32533292
switch (src_status.type()) {
32543293
case std::filesystem::file_type::socket: {
3255-
std::u8string message = u8"Cannot copy a socket file: " + dest_path_str;
3256-
return THROW_ERR_FS_CP_SOCKET(
3257-
env, reinterpret_cast<const char*>(message.c_str()));
3294+
std::string message = "Cannot copy a socket file: %s";
3295+
return THROW_ERR_FS_CP_SOCKET(env, message.c_str(), dest_path_str);
32583296
}
32593297
case std::filesystem::file_type::fifo: {
3260-
std::u8string message = u8"Cannot copy a FIFO pipe: " + dest_path_str;
3261-
return THROW_ERR_FS_CP_FIFO_PIPE(
3262-
env, reinterpret_cast<const char*>(message.c_str()));
3298+
std::string message = "Cannot copy a FIFO pipe: %s";
3299+
return THROW_ERR_FS_CP_FIFO_PIPE(env, message.c_str(), dest_path_str);
32633300
}
32643301
case std::filesystem::file_type::unknown: {
3265-
std::u8string message =
3266-
u8"Cannot copy an unknown file type: " + dest_path_str;
3267-
return THROW_ERR_FS_CP_UNKNOWN(
3268-
env, reinterpret_cast<const char*>(message.c_str()));
3302+
std::string message = "Cannot copy an unknown file type: %s";
3303+
return THROW_ERR_FS_CP_UNKNOWN(env, message.c_str(), dest_path_str);
32693304
}
32703305
default:
32713306
break;

test/fixtures/wpt/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Last update:
1212

1313
- common: https://github.com/web-platform-tests/wpt/tree/dbd648158d/common
1414
- compression: https://github.com/web-platform-tests/wpt/tree/da8d6860b2/compression
15-
- console: https://github.com/web-platform-tests/wpt/tree/767ae35464/console
15+
- console: https://github.com/web-platform-tests/wpt/tree/e48251b778/console
1616
- dom/abort: https://github.com/web-platform-tests/wpt/tree/0143fe244b/dom/abort
1717
- dom/events: https://github.com/web-platform-tests/wpt/tree/0a811c5161/dom/events
1818
- encoding: https://github.com/web-platform-tests/wpt/tree/1ac8deee08/encoding

test/fixtures/wpt/console/console-countReset-logging-manual.html

+5-1
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,25 @@
2424
console.count();
2525
console.countReset();
2626
console.count();
27+
console.countReset();
2728

2829
console.count(undefined);
2930
console.countReset(undefined);
3031
console.count(undefined);
32+
console.countReset(undefined);
3133

3234
console.count("default");
3335
console.countReset("default");
3436
console.count("default");
37+
console.countReset("default");
3538

3639
console.count({toString() {return "default"}});
3740
console.countReset({toString() {return "default"}});
3841
console.count({toString() {return "default"}});
42+
console.countReset({toString() {return "default"}});
3943

4044
console.count("a label");
41-
console.countReset();
45+
console.countReset("a label");
4246
console.count("a label");
4347

4448
console.countReset("b"); // should produce a warning
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// META: global=window,dedicatedworker,shadowrealm
2+
"use strict";
3+
// https://console.spec.whatwg.org/
4+
5+
test(() => {
6+
console.log(new Array(10000000).fill("x"));
7+
console.log(new Uint8Array(10000000));
8+
}, "Logging large arrays works");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// META: global=window,dedicatedworker,shadowrealm
2+
"use strict";
3+
// https://console.spec.whatwg.org/
4+
5+
test(() => {
6+
console.log(Symbol());
7+
console.log(Symbol("abc"));
8+
console.log(Symbol.for("def"));
9+
console.log(Symbol.isConcatSpreadable);
10+
}, "Logging a symbol doesn't throw");

test/fixtures/wpt/versions.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"path": "compression"
99
},
1010
"console": {
11-
"commit": "767ae354642bee1e4d90b28df4480475b9260e14",
11+
"commit": "e48251b77834f9689e9df3f49b93b3387dee72d6",
1212
"path": "console"
1313
},
1414
"dom/abort": {

test/parallel/test-fs-cp.mjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ tmpdir.refresh();
2525

2626
let dirc = 0;
2727
function nextdir(dirname) {
28-
return tmpdir.resolve(dirname || `copy_${++dirc}`);
28+
return tmpdir.resolve(dirname || `copy_%${++dirc}`);
2929
}
3030

3131
// Synchronous implementation of copy.

0 commit comments

Comments
 (0)