Skip to content

Commit

Permalink
fs,url: refactor FileURLToPath method
Browse files Browse the repository at this point in the history
PR-URL: nodejs#50090
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
  • Loading branch information
anonrig authored and alexfernandez committed Nov 1, 2023
1 parent 7355137 commit b877f52
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 85 deletions.
78 changes: 37 additions & 41 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2869,45 +2869,41 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
CHECK(args[0]->IsString());

Environment* env = Environment::GetCurrent(args);
auto isolate = env->isolate();

Utf8Value utf8_package_json_url(env->isolate(), args[0].As<String>());
Utf8Value utf8_package_json_url(isolate, args[0]);
auto package_json_url =
ada::parse<ada::url_aggregator>(utf8_package_json_url.ToStringView());

if (!package_json_url) {
env->isolate()->ThrowException(
ERR_INVALID_URL(env->isolate(), "Invalid URL"));

THROW_ERR_INVALID_URL(isolate, "Invalid URL");
return;
}

ada::result<ada::url_aggregator> file_path_url;
std::string initial_file_path;
std::optional<std::string> initial_file_path;
std::string file_path;

if (args.Length() >= 2 && !args[1]->IsNullOrUndefined() &&
args[1]->IsString()) {
std::string package_config_main =
Utf8Value(env->isolate(), args[1].As<String>()).ToString();
if (args.Length() >= 2 && args[1]->IsString()) {
auto package_config_main = Utf8Value(isolate, args[1]).ToString();

file_path_url = ada::parse<ada::url_aggregator>(
std::string("./") + package_config_main, &package_json_url.value());

if (!file_path_url) {
env->isolate()->ThrowException(
ERR_INVALID_URL(env->isolate(), "Invalid URL"));

THROW_ERR_INVALID_URL(isolate, "Invalid URL");
return;
}

if (!node::url::FileURLToPath(
env, file_path_url.value(), initial_file_path))
initial_file_path = node::url::FileURLToPath(env, *file_path_url);
if (!initial_file_path.has_value()) {
return;
}

FromNamespacedPath(&initial_file_path);
FromNamespacedPath(&initial_file_path.value());

for (int i = 0; i < legacy_main_extensions_with_main_end; i++) {
file_path = initial_file_path + std::string(legacy_main_extensions[i]);
file_path = *initial_file_path + std::string(legacy_main_extensions[i]);

switch (FilePathIsFile(env, file_path)) {
case BindingData::FilePathIsFileReturnType::kIsFile:
Expand All @@ -2930,21 +2926,21 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
ada::parse<ada::url_aggregator>("./index", &package_json_url.value());

if (!file_path_url) {
env->isolate()->ThrowException(
ERR_INVALID_URL(env->isolate(), "Invalid URL"));

THROW_ERR_INVALID_URL(isolate, "Invalid URL");
return;
}

if (!node::url::FileURLToPath(env, file_path_url.value(), initial_file_path))
initial_file_path = node::url::FileURLToPath(env, *file_path_url);
if (!initial_file_path.has_value()) {
return;
}

FromNamespacedPath(&initial_file_path);
FromNamespacedPath(&initial_file_path.value());

for (int i = legacy_main_extensions_with_main_end;
i < legacy_main_extensions_package_fallback_end;
i++) {
file_path = initial_file_path + std::string(legacy_main_extensions[i]);
file_path = *initial_file_path + std::string(legacy_main_extensions[i]);

switch (FilePathIsFile(env, file_path)) {
case BindingData::FilePathIsFileReturnType::kIsFile:
Expand All @@ -2961,39 +2957,39 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
}
}

std::string module_path;
std::string module_base;
std::optional<std::string> module_path =
node::url::FileURLToPath(env, *package_json_url);
std::optional<std::string> module_base;

if (!node::url::FileURLToPath(env, package_json_url.value(), module_path))
if (!module_path.has_value()) {
return;
}

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

if (!base_url) {
env->isolate()->ThrowException(
ERR_INVALID_URL(env->isolate(), "Invalid URL"));

THROW_ERR_INVALID_URL(isolate, "Invalid URL");
return;
}

if (!node::url::FileURLToPath(env, base_url.value(), module_base)) return;
module_base = node::url::FileURLToPath(env, *base_url);
if (!module_base.has_value()) {
return;
}
} else {
std::string err_arg_message =
"The \"base\" argument must be of type string or an instance of URL.";
env->isolate()->ThrowException(
ERR_INVALID_ARG_TYPE(env->isolate(), err_arg_message.c_str()));
THROW_ERR_INVALID_ARG_TYPE(
isolate,
"The \"base\" argument must be of type string or an instance of URL.");
return;
}

env->isolate()->ThrowException(
ERR_MODULE_NOT_FOUND(env->isolate(),
"Cannot find package '%s' imported from %s",
module_path,
module_base));
THROW_ERR_MODULE_NOT_FOUND(isolate,
"Cannot find package '%s' imported from %s",
*module_path,
*module_base);
}

void BindingData::MemoryInfo(MemoryTracker* tracker) const {
Expand Down
59 changes: 21 additions & 38 deletions src/node_url.cc
Original file line number Diff line number Diff line change
Expand Up @@ -437,16 +437,11 @@ std::string FromFilePath(std::string_view file_path) {
return ada::href_from_file(escaped_file_path);
}

bool FileURLToPath(Environment* env,
const ada::url_aggregator& file_url,
/* The linter can't detect the assign for result_file_path
So we need to ignore since it suggest to put const */
// NOLINTNEXTLINE(runtime/references)
std::string& result_file_path) {
std::optional<std::string> FileURLToPath(Environment* env,
const ada::url_aggregator& file_url) {
if (file_url.type != ada::scheme::FILE) {
env->isolate()->ThrowException(ERR_INVALID_URL_SCHEME(env->isolate()));

return false;
THROW_ERR_INVALID_URL_SCHEME(env->isolate());
return std::nullopt;
}

std::string_view pathname = file_url.get_pathname();
Expand Down Expand Up @@ -479,11 +474,10 @@ bool FileURLToPath(Environment* env,

if (!is_slash && !is_forward_slash) continue;

env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
THROW_ERR_INVALID_FILE_URL_PATH(
env->isolate(),
"File URL path must not include encoded \\ or / characters"));

return false;
"File URL path must not include encoded \\ or / characters");
return std::nullopt;
}

std::string_view hostname = file_url.get_hostname();
Expand All @@ -497,37 +491,29 @@ bool FileURLToPath(Environment* env,
// about percent encoding because the URL parser will have
// already taken care of that for us. Note that this only
// causes IDNs with an appropriate `xn--` prefix to be decoded.
result_file_path =
"\\\\" + ada::unicode::to_unicode(hostname) + decoded_pathname;

return true;
return "\\\\" + ada::unicode::to_unicode(hostname) + decoded_pathname;
}

char letter = decoded_pathname[1] | 0x20;
char sep = decoded_pathname[2];

// a..z A..Z
if (letter < 'a' || letter > 'z' || sep != ':') {
env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
env->isolate(), "File URL path must be absolute"));

return false;
THROW_ERR_INVALID_FILE_URL_PATH(env->isolate(),
"File URL path must be absolute");
return std::nullopt;
}

result_file_path = decoded_pathname.substr(1);

return true;
return decoded_pathname.substr(1);
#else // _WIN32
std::string_view hostname = file_url.get_hostname();

if (hostname.size() > 0) {
std::string error_message =
std::string("File URL host must be \"localhost\" or empty on ") +
std::string(per_process::metadata.platform);
env->isolate()->ThrowException(
ERR_INVALID_FILE_URL_HOST(env->isolate(), error_message.c_str()));

return false;
THROW_ERR_INVALID_FILE_URL_HOST(
env->isolate(),
"File URL host must be \"localhost\" or empty on ",
std::string(per_process::metadata.platform));
return std::nullopt;
}

size_t first_percent = std::string::npos;
Expand All @@ -539,17 +525,14 @@ bool FileURLToPath(Environment* env,
}

if (pathname[i + 1] == '2' && (pathname[i + 2] | 0x20) == 102) {
env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
THROW_ERR_INVALID_FILE_URL_PATH(
env->isolate(),
"File URL path must not include encoded / characters"));

return false;
"File URL path must not include encoded / characters");
return std::nullopt;
}
}

result_file_path = ada::unicode::percent_decode(pathname, first_percent);

return true;
return ada::unicode::percent_decode(pathname, first_percent);
#endif // _WIN32
}

Expand Down
10 changes: 4 additions & 6 deletions src/node_url.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "v8-fast-api-calls.h"
#include "v8.h"

#include <optional>
#include <string>

namespace node {
Expand Down Expand Up @@ -82,12 +83,9 @@ class BindingData : public SnapshotableObject {
};

std::string FromFilePath(std::string_view file_path);
bool FileURLToPath(Environment* env,
const ada::url_aggregator& file_url,
/* The linter can't detect the assign for result_file_path
So we need to ignore since it suggest to put const */
// NOLINTNEXTLINE(runtime/references)
std::string& result_file_path);
std::optional<std::string> FileURLToPath(Environment* env,
const ada::url_aggregator& file_url);

} // namespace url

} // namespace node
Expand Down

0 comments on commit b877f52

Please sign in to comment.