Skip to content

Commit 98b1be0

Browse files
addaleaxsxa
authored andcommitted
src: return proper URLs from node_api_get_module_file_name
Using `file://${path}` does not properly escape special URL characters. PR-URL: #41758 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Tobias Nießen <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: Michael Dawson <[email protected]>
1 parent ecb5980 commit 98b1be0

File tree

2 files changed

+41
-9
lines changed

2 files changed

+41
-9
lines changed

src/node_api.cc

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "node_buffer.h"
1010
#include "node_errors.h"
1111
#include "node_internals.h"
12+
#include "node_url.h"
1213
#include "threadpoolwork-inl.h"
1314
#include "tracing/traced_value.h"
1415
#include "util-inl.h"
@@ -589,13 +590,13 @@ void napi_module_register_by_symbol(v8::Local<v8::Object> exports,
589590
if (module->ToObject(context).ToLocal(&modobj) &&
590591
modobj->Get(context, node_env->filename_string()).ToLocal(&filename_js) &&
591592
filename_js->IsString()) {
592-
node::Utf8Value filename(node_env->isolate(), filename_js); // Cast
593+
node::Utf8Value filename(node_env->isolate(), filename_js);
593594

594595
// Turn the absolute path into a URL. Currently the absolute path is always
595596
// a file system path.
596597
// TODO(gabrielschulhof): Pass the `filename` through unchanged if/when we
597598
// receive it as a URL already.
598-
module_filename = std::string("file://") + (*filename);
599+
module_filename = node::url::URL::FromFilePath(filename.ToString()).href();
599600
}
600601

601602
// Create a new napi_env for this specific module.

test/node-api/test_general/test.js

+38-7
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,46 @@
11
'use strict';
22

33
const common = require('../../common');
4+
const tmpdir = require('../../common/tmpdir');
5+
const child_process = require('child_process');
6+
const fs = require('fs');
7+
const path = require('path');
8+
const url = require('url');
49
const filename = require.resolve(`./build/${common.buildType}/test_general`);
510
const test_general = require(filename);
611
const assert = require('assert');
712

8-
// TODO(gabrielschulhof): This test may need updating if/when the filename
9-
// becomes a full-fledged URL.
10-
assert.strictEqual(test_general.filename, `file://${filename}`);
13+
tmpdir.refresh();
1114

12-
const [ major, minor, patch, release ] = test_general.testGetNodeVersion();
13-
assert.strictEqual(process.version.split('-')[0],
14-
`v${major}.${minor}.${patch}`);
15-
assert.strictEqual(release, process.release.name);
15+
{
16+
// TODO(gabrielschulhof): This test may need updating if/when the filename
17+
// becomes a full-fledged URL.
18+
assert.strictEqual(test_general.filename, url.pathToFileURL(filename).href);
19+
}
20+
21+
{
22+
const urlTestDir = path.join(tmpdir.path, 'foo%#bar');
23+
const urlTestFile = path.join(urlTestDir, path.basename(filename));
24+
fs.mkdirSync(urlTestDir, { recursive: true });
25+
fs.copyFileSync(filename, urlTestFile);
26+
// Use a child process as indirection so that the native module is not loaded
27+
// into this process and can be removed here.
28+
const reportedFilename = child_process.spawnSync(
29+
process.execPath,
30+
['-p', `require(${JSON.stringify(urlTestFile)}).filename`],
31+
{ encoding: 'utf8' }).stdout.trim();
32+
assert.doesNotMatch(reportedFilename, /foo%#bar/);
33+
assert.strictEqual(reportedFilename, url.pathToFileURL(urlTestFile).href);
34+
fs.rmSync(urlTestDir, {
35+
force: true,
36+
recursive: true,
37+
maxRetries: 256
38+
});
39+
}
40+
41+
{
42+
const [ major, minor, patch, release ] = test_general.testGetNodeVersion();
43+
assert.strictEqual(process.version.split('-')[0],
44+
`v${major}.${minor}.${patch}`);
45+
assert.strictEqual(release, process.release.name);
46+
}

0 commit comments

Comments
 (0)