Skip to content

Commit d3cb3e1

Browse files
committed
src: simplify legacy resolve functionality
1 parent f870bbc commit d3cb3e1

File tree

2 files changed

+88
-128
lines changed

2 files changed

+88
-128
lines changed

src/node_file.cc

Lines changed: 70 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -844,13 +844,13 @@ void AfterOpenFileHandle(uv_fs_t* req) {
844844

845845
// Reverse the logic applied by path.toNamespacedPath() to create a
846846
// namespace-prefixed path.
847-
void FromNamespacedPath(std::string* path) {
847+
void FromNamespacedPath(std::string& path) { // NOLINT(runtime/references)
848848
#ifdef _WIN32
849-
if (path->compare(0, 8, "\\\\?\\UNC\\", 8) == 0) {
850-
*path = path->substr(8);
851-
path->insert(0, "\\\\");
852-
} else if (path->compare(0, 4, "\\\\?\\", 4) == 0) {
853-
*path = path->substr(4);
849+
if (path.compare(0, 8, "\\\\?\\UNC\\", 8) == 0) {
850+
path = path.substr(8);
851+
path.insert(0, "\\\\");
852+
} else if (path.compare(0, 4, "\\\\?\\", 4) == 0) {
853+
path = path.substr(4);
854854
}
855855
#endif
856856
}
@@ -864,7 +864,7 @@ void AfterMkdirp(uv_fs_t* req) {
864864
std::string first_path(req_wrap->continuation_data()->first_path());
865865
if (first_path.empty())
866866
return req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
867-
FromNamespacedPath(&first_path);
867+
FromNamespacedPath(first_path);
868868
Local<Value> path;
869869
Local<Value> error;
870870
if (!StringBytes::Encode(req_wrap->env()->isolate(), first_path.c_str(),
@@ -1804,7 +1804,7 @@ static void MKDir(const FunctionCallbackInfo<Value>& args) {
18041804
!req_wrap_sync.continuation_data()->first_path().empty()) {
18051805
Local<Value> error;
18061806
std::string first_path(req_wrap_sync.continuation_data()->first_path());
1807-
FromNamespacedPath(&first_path);
1807+
FromNamespacedPath(first_path);
18081808
MaybeLocal<Value> path = StringBytes::Encode(env->isolate(),
18091809
first_path.c_str(),
18101810
UTF8, &error);
@@ -2732,67 +2732,52 @@ static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
27322732
static bool FileURLToPath(
27332733
Environment* env,
27342734
const ada::url_aggregator& file_url,
2735-
/* The linter can't detect the assign for result_file_path
2736-
So we need to ignore since it suggest to put const */
2737-
// NOLINTNEXTLINE(runtime/references)
2738-
std::string& result_file_path) {
2735+
std::string& result_file_path) { // NOLINT(runtime/references)
27392736
if (file_url.type != ada::scheme::FILE) {
2740-
env->isolate()->ThrowException(ERR_INVALID_URL_SCHEME(env->isolate()));
2741-
2737+
THROW_ERR_INVALID_URL_SCHEME(env);
27422738
return false;
27432739
}
27442740

27452741
std::string_view pathname = file_url.get_pathname();
27462742
#ifdef _WIN32
2747-
size_t first_percent = std::string::npos;
27482743
size_t pathname_size = pathname.size();
2749-
std::string pathname_escaped_slash;
2744+
std::string pathname_escaped_slash{};
2745+
pathname_escaped_slash.reserve(pathname_size);
27502746

27512747
for (size_t i = 0; i < pathname_size; i++) {
27522748
if (pathname[i] == '/') {
27532749
pathname_escaped_slash += '\\';
2754-
} else {
2755-
pathname_escaped_slash += pathname[i];
2750+
continue;
27562751
}
27572752

2758-
if (pathname[i] != '%') continue;
2759-
2760-
if (first_percent == std::string::npos) {
2761-
first_percent = i;
2762-
}
2763-
2764-
// just safe-guard against access the pathname
2765-
// outside the bounds
2766-
if ((i + 2) >= pathname_size) continue;
2767-
2768-
char third = pathname[i + 2] | 0x20;
2769-
2770-
bool is_slash = pathname[i + 1] == '2' && third == 102;
2771-
bool is_forward_slash = pathname[i + 1] == '5' && third == 99;
2753+
pathname_escaped_slash += pathname[i];
27722754

2773-
if (!is_slash && !is_forward_slash) continue;
2755+
if (pathname[i] == '%' && (i + 2) <= pathname_size) {
2756+
char third = pathname[i + 2] | 0x20;
2757+
bool is_slash = pathname[i + 1] == '2' && third == 102;
2758+
bool is_forward_slash = pathname[i + 1] == '5' && third == 99;
27742759

2775-
env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
2776-
env->isolate(),
2777-
"File URL path must not include encoded \\ or / characters"));
2778-
2779-
return false;
2760+
if (is_slash || is_forward_slash) {
2761+
THROW_ERR_INVALID_FILE_URL_PATH(
2762+
env, "File URL path must not include encoded \\ or / characters");
2763+
return false;
2764+
}
2765+
}
27802766
}
27812767

2782-
std::string_view hostname = file_url.get_hostname();
27832768
std::string decoded_pathname = ada::unicode::percent_decode(
2784-
std::string_view(pathname_escaped_slash), first_percent);
2769+
pathname_escaped_slash, pathname_escaped_slash.find('%'));
27852770

2786-
if (hostname.size() > 0) {
2771+
if (!file_url.has_empty_hostname()) {
27872772
// If hostname is set, then we have a UNC path
27882773
// Pass the hostname through domainToUnicode just in case
27892774
// it is an IDN using punycode encoding. We do not need to worry
27902775
// about percent encoding because the URL parser will have
27912776
// already taken care of that for us. Note that this only
27922777
// causes IDNs with an appropriate `xn--` prefix to be decoded.
2793-
result_file_path =
2794-
"\\\\" + ada::unicode::to_unicode(hostname) + decoded_pathname;
2795-
2778+
result_file_path = "\\\\" +
2779+
ada::unicode::to_unicode(file_url.get_hostname()) +
2780+
decoded_pathname;
27962781
return true;
27972782
}
27982783

@@ -2801,42 +2786,31 @@ static bool FileURLToPath(
28012786

28022787
// a..z A..Z
28032788
if (letter < 'a' || letter > 'z' || sep != ':') {
2804-
env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
2805-
env->isolate(), "File URL path must be absolute"));
2806-
2789+
THROW_ERR_INVALID_FILE_URL_PATH(env, "File URL path must be absolute");
28072790
return false;
28082791
}
28092792

28102793
result_file_path = decoded_pathname.substr(1);
28112794

28122795
return true;
28132796
#else // _WIN32
2814-
std::string_view hostname = file_url.get_hostname();
2815-
2816-
if (hostname.size() > 0) {
2797+
if (!file_url.has_empty_hostname()) {
28172798
std::string error_message =
2818-
std::string("File URL host must be \"localhost\" or empty on ") +
2799+
"File URL host must be \"localhost\" or empty on " +
28192800
std::string(per_process::metadata.platform);
2820-
env->isolate()->ThrowException(
2821-
ERR_INVALID_FILE_URL_HOST(env->isolate(), error_message.c_str()));
2822-
2801+
THROW_ERR_INVALID_FILE_URL_HOST(env, error_message.c_str());
28232802
return false;
28242803
}
28252804

2826-
size_t first_percent = std::string::npos;
2827-
for (size_t i = 0; (i + 2) < pathname.size(); i++) {
2828-
if (pathname[i] != '%') continue;
2829-
2830-
if (first_percent == std::string::npos) {
2831-
first_percent = i;
2832-
}
2833-
2834-
if (pathname[i + 1] == '2' && (pathname[i + 2] | 0x20) == 102) {
2835-
env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
2836-
env->isolate(),
2837-
"File URL path must not include encoded / characters"));
2805+
auto first_percent = pathname.find('%');
28382806

2839-
return false;
2807+
if (first_percent != std::string_view::npos) {
2808+
for (size_t i = first_percent; (i + 2) < pathname.size(); i++) {
2809+
if (pathname[i + 1] == '2' && (pathname[i + 2] | 0x20) == 102) {
2810+
THROW_ERR_INVALID_FILE_URL_PATH(
2811+
env, "File URL path must not include encoded / characters");
2812+
return false;
2813+
}
28402814
}
28412815
}
28422816

@@ -2847,16 +2821,16 @@ static bool FileURLToPath(
28472821
}
28482822

28492823
BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile(
2850-
Environment* env, const std::string& file_path) {
2824+
Environment* env, const std::string_view file_path) {
28512825
THROW_IF_INSUFFICIENT_PERMISSIONS(
28522826
env,
28532827
permission::PermissionScope::kFileSystemRead,
28542828
file_path,
2855-
BindingData::FilePathIsFileReturnType::kThrowInsufficientPermissions);
2829+
FilePathIsFileReturnType::kThrowInsufficientPermissions);
28562830

28572831
uv_fs_t req;
28582832

2859-
int rc = uv_fs_stat(env->event_loop(), &req, file_path.c_str(), nullptr);
2833+
int rc = uv_fs_stat(env->event_loop(), &req, file_path.data(), nullptr);
28602834

28612835
if (rc == 0) {
28622836
const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
@@ -2871,22 +2845,6 @@ BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile(
28712845
return BindingData::FilePathIsFileReturnType::kIsNotFile;
28722846
}
28732847

2874-
// the possible file extensions that should be tested
2875-
// 0-6: when packageConfig.main is defined
2876-
// 7-9: when packageConfig.main is NOT defined,
2877-
// or when the previous case didn't found the file
2878-
const std::array<std::string, 10> BindingData::legacy_main_extensions = {
2879-
"",
2880-
".js",
2881-
".json",
2882-
".node",
2883-
"/index.js",
2884-
"/index.json",
2885-
"/index.node",
2886-
".js",
2887-
".json",
2888-
".node"};
2889-
28902848
void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
28912849
CHECK_GE(args.Length(), 1);
28922850
CHECK(args[0]->IsString());
@@ -2898,38 +2856,32 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
28982856
ada::parse<ada::url_aggregator>(utf8_package_json_url.ToStringView());
28992857

29002858
if (!package_json_url) {
2901-
env->isolate()->ThrowException(
2902-
ERR_INVALID_URL(env->isolate(), "Invalid URL"));
2903-
2859+
THROW_ERR_INVALID_URL(env, "Invalid URL");
29042860
return;
29052861
}
29062862

29072863
ada::result<ada::url_aggregator> file_path_url;
29082864
std::string initial_file_path;
2909-
std::string file_path;
29102865

2911-
if (args.Length() >= 2 && !args[1]->IsNullOrUndefined() &&
2912-
args[1]->IsString()) {
2866+
if (args.Length() >= 2 && args[1]->IsString()) {
29132867
std::string package_config_main =
29142868
Utf8Value(env->isolate(), args[1].As<String>()).ToString();
29152869

2916-
file_path_url = ada::parse<ada::url_aggregator>(
2917-
std::string("./") + package_config_main, &package_json_url.value());
2870+
file_path_url = ada::parse<ada::url_aggregator>("./" + package_config_main,
2871+
&package_json_url.value());
29182872

29192873
if (!file_path_url) {
2920-
env->isolate()->ThrowException(
2921-
ERR_INVALID_URL(env->isolate(), "Invalid URL"));
2922-
2874+
THROW_ERR_INVALID_URL(env, "Invalid URL");
29232875
return;
29242876
}
29252877

2926-
if (!FileURLToPath(env, file_path_url.value(), initial_file_path)) return;
2878+
if (!FileURLToPath(env, *file_path_url, initial_file_path)) return;
29272879

2928-
FromNamespacedPath(&initial_file_path);
2880+
FromNamespacedPath(initial_file_path);
29292881

2930-
for (int i = 0; i < BindingData::legacy_main_extensions_with_main_end;
2931-
i++) {
2932-
file_path = initial_file_path + BindingData::legacy_main_extensions[i];
2882+
for (int i = 0; i < legacy_main_extensions_with_main_end; i++) {
2883+
auto file_path = initial_file_path +
2884+
std::string(BindingData::legacy_main_extensions[i]);
29332885

29342886
switch (FilePathIsFile(env, file_path)) {
29352887
case BindingData::FilePathIsFileReturnType::kIsFile:
@@ -2952,20 +2904,19 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
29522904
ada::parse<ada::url_aggregator>("./index", &package_json_url.value());
29532905

29542906
if (!file_path_url) {
2955-
env->isolate()->ThrowException(
2956-
ERR_INVALID_URL(env->isolate(), "Invalid URL"));
2957-
2907+
THROW_ERR_INVALID_URL(env, "Invalid URL");
29582908
return;
29592909
}
29602910

2961-
if (!FileURLToPath(env, file_path_url.value(), initial_file_path)) return;
2911+
if (!FileURLToPath(env, *file_path_url, initial_file_path)) return;
29622912

2963-
FromNamespacedPath(&initial_file_path);
2913+
FromNamespacedPath(initial_file_path);
29642914

2965-
for (int i = BindingData::legacy_main_extensions_with_main_end;
2966-
i < BindingData::legacy_main_extensions_package_fallback_end;
2915+
for (int i = legacy_main_extensions_with_main_end;
2916+
i < legacy_main_extensions_package_fallback_end;
29672917
i++) {
2968-
file_path = initial_file_path + BindingData::legacy_main_extensions[i];
2918+
auto file_path =
2919+
initial_file_path + std::string(BindingData::legacy_main_extensions[i]);
29692920

29702921
switch (FilePathIsFile(env, file_path)) {
29712922
case BindingData::FilePathIsFileReturnType::kIsFile:
@@ -2987,32 +2938,27 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
29872938

29882939
if (!FileURLToPath(env, package_json_url.value(), module_path)) return;
29892940

2990-
if (args.Length() >= 3 && !args[2]->IsNullOrUndefined() &&
2991-
args[2]->IsString()) {
2941+
if (args.Length() >= 3 && args[2]->IsString()) {
29922942
Utf8Value utf8_base_path(env->isolate(), args[2].As<String>());
29932943
auto base_url =
29942944
ada::parse<ada::url_aggregator>(utf8_base_path.ToStringView());
29952945

29962946
if (!base_url) {
2997-
env->isolate()->ThrowException(
2998-
ERR_INVALID_URL(env->isolate(), "Invalid URL"));
2999-
2947+
THROW_ERR_INVALID_URL(env->isolate(), "Invalid URL");
30002948
return;
30012949
}
30022950

30032951
if (!FileURLToPath(env, base_url.value(), module_base)) return;
3004-
} else {
3005-
std::string err_arg_message =
3006-
"The \"base\" argument must be of type string or an instance of URL.";
3007-
env->isolate()->ThrowException(
3008-
ERR_INVALID_ARG_TYPE(env->isolate(), err_arg_message.c_str()));
2952+
2953+
std::string err_module_message = "Cannot find package '" + module_path +
2954+
"' imported from " + module_base;
2955+
THROW_ERR_MODULE_NOT_FOUND(env, err_module_message.c_str());
30092956
return;
30102957
}
30112958

3012-
std::string err_module_message =
3013-
"Cannot find package '" + module_path + "' imported from " + module_base;
3014-
env->isolate()->ThrowException(
3015-
ERR_MODULE_NOT_FOUND(env->isolate(), err_module_message.c_str()));
2959+
THROW_ERR_INVALID_ARG_TYPE(
2960+
env,
2961+
"The \"base\" argument must be of type string or an instance of URL.");
30162962
}
30172963

30182964
void BindingData::MemoryInfo(MemoryTracker* tracker) const {

src/node_file.h

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,24 @@ class BindingData : public SnapshotableObject {
100100
private:
101101
InternalFieldInfo* internal_field_info_ = nullptr;
102102

103-
static FilePathIsFileReturnType FilePathIsFile(Environment* env,
104-
const std::string& file_path);
105-
106-
static const std::array<std::string, 10> legacy_main_extensions;
103+
static FilePathIsFileReturnType FilePathIsFile(
104+
Environment* env, const std::string_view file_path);
105+
106+
// the possible file extensions that should be tested
107+
// 0-6: when packageConfig.main is defined
108+
// 7-9: when packageConfig.main is NOT defined,
109+
// or when the previous case didn't found the file
110+
static constexpr std::array<std::string_view, 10> legacy_main_extensions = {
111+
"",
112+
".js",
113+
".json",
114+
".node",
115+
"/index.js",
116+
"/index.json",
117+
"/index.node",
118+
".js",
119+
".json",
120+
".node"};
107121
// define the final index of the algorithm resolution
108122
// when packageConfig.main is defined.
109123
static const uint8_t legacy_main_extensions_with_main_end = 7;

0 commit comments

Comments
 (0)