Skip to content

Commit 4345ee2

Browse files
anonrigtargos
authored andcommitted
fs,url: move FileURLToPath to node_url
PR-URL: #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>
1 parent ab9cad8 commit 4345ee2

File tree

3 files changed

+133
-122
lines changed

3 files changed

+133
-122
lines changed

src/node_file.cc

+9-121
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "node_metadata.h"
3030
#include "node_process-inl.h"
3131
#include "node_stat_watcher.h"
32+
#include "node_url.h"
3233
#include "permission/permission.h"
3334
#include "util-inl.h"
3435

@@ -2812,123 +2813,6 @@ static void GetFormatOfExtensionlessFile(
28122813
return args.GetReturnValue().Set(EXTENSIONLESS_FORMAT_JAVASCRIPT);
28132814
}
28142815

2815-
static bool FileURLToPath(
2816-
Environment* env,
2817-
const ada::url_aggregator& file_url,
2818-
/* The linter can't detect the assign for result_file_path
2819-
So we need to ignore since it suggest to put const */
2820-
// NOLINTNEXTLINE(runtime/references)
2821-
std::string& result_file_path) {
2822-
if (file_url.type != ada::scheme::FILE) {
2823-
env->isolate()->ThrowException(ERR_INVALID_URL_SCHEME(env->isolate()));
2824-
2825-
return false;
2826-
}
2827-
2828-
std::string_view pathname = file_url.get_pathname();
2829-
#ifdef _WIN32
2830-
size_t first_percent = std::string::npos;
2831-
size_t pathname_size = pathname.size();
2832-
std::string pathname_escaped_slash;
2833-
2834-
for (size_t i = 0; i < pathname_size; i++) {
2835-
if (pathname[i] == '/') {
2836-
pathname_escaped_slash += '\\';
2837-
} else {
2838-
pathname_escaped_slash += pathname[i];
2839-
}
2840-
2841-
if (pathname[i] != '%') continue;
2842-
2843-
if (first_percent == std::string::npos) {
2844-
first_percent = i;
2845-
}
2846-
2847-
// just safe-guard against access the pathname
2848-
// outside the bounds
2849-
if ((i + 2) >= pathname_size) continue;
2850-
2851-
char third = pathname[i + 2] | 0x20;
2852-
2853-
bool is_slash = pathname[i + 1] == '2' && third == 102;
2854-
bool is_forward_slash = pathname[i + 1] == '5' && third == 99;
2855-
2856-
if (!is_slash && !is_forward_slash) continue;
2857-
2858-
env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
2859-
env->isolate(),
2860-
"File URL path must not include encoded \\ or / characters"));
2861-
2862-
return false;
2863-
}
2864-
2865-
std::string_view hostname = file_url.get_hostname();
2866-
std::string decoded_pathname = ada::unicode::percent_decode(
2867-
std::string_view(pathname_escaped_slash), first_percent);
2868-
2869-
if (hostname.size() > 0) {
2870-
// If hostname is set, then we have a UNC path
2871-
// Pass the hostname through domainToUnicode just in case
2872-
// it is an IDN using punycode encoding. We do not need to worry
2873-
// about percent encoding because the URL parser will have
2874-
// already taken care of that for us. Note that this only
2875-
// causes IDNs with an appropriate `xn--` prefix to be decoded.
2876-
result_file_path =
2877-
"\\\\" + ada::unicode::to_unicode(hostname) + decoded_pathname;
2878-
2879-
return true;
2880-
}
2881-
2882-
char letter = decoded_pathname[1] | 0x20;
2883-
char sep = decoded_pathname[2];
2884-
2885-
// a..z A..Z
2886-
if (letter < 'a' || letter > 'z' || sep != ':') {
2887-
env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
2888-
env->isolate(), "File URL path must be absolute"));
2889-
2890-
return false;
2891-
}
2892-
2893-
result_file_path = decoded_pathname.substr(1);
2894-
2895-
return true;
2896-
#else // _WIN32
2897-
std::string_view hostname = file_url.get_hostname();
2898-
2899-
if (hostname.size() > 0) {
2900-
std::string error_message =
2901-
std::string("File URL host must be \"localhost\" or empty on ") +
2902-
std::string(per_process::metadata.platform);
2903-
env->isolate()->ThrowException(
2904-
ERR_INVALID_FILE_URL_HOST(env->isolate(), error_message.c_str()));
2905-
2906-
return false;
2907-
}
2908-
2909-
size_t first_percent = std::string::npos;
2910-
for (size_t i = 0; (i + 2) < pathname.size(); i++) {
2911-
if (pathname[i] != '%') continue;
2912-
2913-
if (first_percent == std::string::npos) {
2914-
first_percent = i;
2915-
}
2916-
2917-
if (pathname[i + 1] == '2' && (pathname[i + 2] | 0x20) == 102) {
2918-
env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
2919-
env->isolate(),
2920-
"File URL path must not include encoded / characters"));
2921-
2922-
return false;
2923-
}
2924-
}
2925-
2926-
result_file_path = ada::unicode::percent_decode(pathname, first_percent);
2927-
2928-
return true;
2929-
#endif // _WIN32
2930-
}
2931-
29322816
BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile(
29332817
Environment* env, const std::string& file_path) {
29342818
THROW_IF_INSUFFICIENT_PERMISSIONS(
@@ -3016,7 +2900,9 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
30162900
return;
30172901
}
30182902

3019-
if (!FileURLToPath(env, file_path_url.value(), initial_file_path)) return;
2903+
if (!node::url::FileURLToPath(
2904+
env, file_path_url.value(), initial_file_path))
2905+
return;
30202906

30212907
FromNamespacedPath(&initial_file_path);
30222908

@@ -3050,7 +2936,8 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
30502936
return;
30512937
}
30522938

3053-
if (!FileURLToPath(env, file_path_url.value(), initial_file_path)) return;
2939+
if (!node::url::FileURLToPath(env, file_path_url.value(), initial_file_path))
2940+
return;
30542941

30552942
FromNamespacedPath(&initial_file_path);
30562943

@@ -3077,7 +2964,8 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
30772964
std::string module_path;
30782965
std::string module_base;
30792966

3080-
if (!FileURLToPath(env, package_json_url.value(), module_path)) return;
2967+
if (!node::url::FileURLToPath(env, package_json_url.value(), module_path))
2968+
return;
30812969

30822970
if (args.Length() >= 3 && !args[2]->IsNullOrUndefined() &&
30832971
args[2]->IsString()) {
@@ -3092,7 +2980,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
30922980
return;
30932981
}
30942982

3095-
if (!FileURLToPath(env, base_url.value(), module_base)) return;
2983+
if (!node::url::FileURLToPath(env, base_url.value(), module_base)) return;
30962984
} else {
30972985
std::string err_arg_message =
30982986
"The \"base\" argument must be of type string or an instance of URL.";

src/node_url.cc

+118
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include "node_errors.h"
55
#include "node_external_reference.h"
66
#include "node_i18n.h"
7+
#include "node_metadata.h"
8+
#include "node_process-inl.h"
79
#include "util-inl.h"
810
#include "v8-fast-api-calls.h"
911
#include "v8.h"
@@ -435,6 +437,122 @@ std::string FromFilePath(std::string_view file_path) {
435437
return ada::href_from_file(escaped_file_path);
436438
}
437439

440+
bool FileURLToPath(Environment* env,
441+
const ada::url_aggregator& file_url,
442+
/* The linter can't detect the assign for result_file_path
443+
So we need to ignore since it suggest to put const */
444+
// NOLINTNEXTLINE(runtime/references)
445+
std::string& result_file_path) {
446+
if (file_url.type != ada::scheme::FILE) {
447+
env->isolate()->ThrowException(ERR_INVALID_URL_SCHEME(env->isolate()));
448+
449+
return false;
450+
}
451+
452+
std::string_view pathname = file_url.get_pathname();
453+
#ifdef _WIN32
454+
size_t first_percent = std::string::npos;
455+
size_t pathname_size = pathname.size();
456+
std::string pathname_escaped_slash;
457+
458+
for (size_t i = 0; i < pathname_size; i++) {
459+
if (pathname[i] == '/') {
460+
pathname_escaped_slash += '\\';
461+
} else {
462+
pathname_escaped_slash += pathname[i];
463+
}
464+
465+
if (pathname[i] != '%') continue;
466+
467+
if (first_percent == std::string::npos) {
468+
first_percent = i;
469+
}
470+
471+
// just safe-guard against access the pathname
472+
// outside the bounds
473+
if ((i + 2) >= pathname_size) continue;
474+
475+
char third = pathname[i + 2] | 0x20;
476+
477+
bool is_slash = pathname[i + 1] == '2' && third == 102;
478+
bool is_forward_slash = pathname[i + 1] == '5' && third == 99;
479+
480+
if (!is_slash && !is_forward_slash) continue;
481+
482+
env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
483+
env->isolate(),
484+
"File URL path must not include encoded \\ or / characters"));
485+
486+
return false;
487+
}
488+
489+
std::string_view hostname = file_url.get_hostname();
490+
std::string decoded_pathname = ada::unicode::percent_decode(
491+
std::string_view(pathname_escaped_slash), first_percent);
492+
493+
if (hostname.size() > 0) {
494+
// If hostname is set, then we have a UNC path
495+
// Pass the hostname through domainToUnicode just in case
496+
// it is an IDN using punycode encoding. We do not need to worry
497+
// about percent encoding because the URL parser will have
498+
// already taken care of that for us. Note that this only
499+
// causes IDNs with an appropriate `xn--` prefix to be decoded.
500+
result_file_path =
501+
"\\\\" + ada::unicode::to_unicode(hostname) + decoded_pathname;
502+
503+
return true;
504+
}
505+
506+
char letter = decoded_pathname[1] | 0x20;
507+
char sep = decoded_pathname[2];
508+
509+
// a..z A..Z
510+
if (letter < 'a' || letter > 'z' || sep != ':') {
511+
env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
512+
env->isolate(), "File URL path must be absolute"));
513+
514+
return false;
515+
}
516+
517+
result_file_path = decoded_pathname.substr(1);
518+
519+
return true;
520+
#else // _WIN32
521+
std::string_view hostname = file_url.get_hostname();
522+
523+
if (hostname.size() > 0) {
524+
std::string error_message =
525+
std::string("File URL host must be \"localhost\" or empty on ") +
526+
std::string(per_process::metadata.platform);
527+
env->isolate()->ThrowException(
528+
ERR_INVALID_FILE_URL_HOST(env->isolate(), error_message.c_str()));
529+
530+
return false;
531+
}
532+
533+
size_t first_percent = std::string::npos;
534+
for (size_t i = 0; (i + 2) < pathname.size(); i++) {
535+
if (pathname[i] != '%') continue;
536+
537+
if (first_percent == std::string::npos) {
538+
first_percent = i;
539+
}
540+
541+
if (pathname[i + 1] == '2' && (pathname[i + 2] | 0x20) == 102) {
542+
env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
543+
env->isolate(),
544+
"File URL path must not include encoded / characters"));
545+
546+
return false;
547+
}
548+
}
549+
550+
result_file_path = ada::unicode::percent_decode(pathname, first_percent);
551+
552+
return true;
553+
#endif // _WIN32
554+
}
555+
438556
} // namespace url
439557

440558
} // namespace node

src/node_url.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,12 @@ class BindingData : public SnapshotableObject {
8282
};
8383

8484
std::string FromFilePath(std::string_view file_path);
85-
85+
bool FileURLToPath(Environment* env,
86+
const ada::url_aggregator& file_url,
87+
/* The linter can't detect the assign for result_file_path
88+
So we need to ignore since it suggest to put const */
89+
// NOLINTNEXTLINE(runtime/references)
90+
std::string& result_file_path);
8691
} // namespace url
8792

8893
} // namespace node

0 commit comments

Comments
 (0)