Skip to content

Commit 186e6e0

Browse files
anonrigUlisesGascon
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 a31f9bf commit 186e6e0

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

@@ -2847,123 +2848,6 @@ static void GetFormatOfExtensionlessFile(
28472848
return args.GetReturnValue().Set(EXTENSIONLESS_FORMAT_JAVASCRIPT);
28482849
}
28492850

2850-
static bool FileURLToPath(
2851-
Environment* env,
2852-
const ada::url_aggregator& file_url,
2853-
/* The linter can't detect the assign for result_file_path
2854-
So we need to ignore since it suggest to put const */
2855-
// NOLINTNEXTLINE(runtime/references)
2856-
std::string& result_file_path) {
2857-
if (file_url.type != ada::scheme::FILE) {
2858-
env->isolate()->ThrowException(ERR_INVALID_URL_SCHEME(env->isolate()));
2859-
2860-
return false;
2861-
}
2862-
2863-
std::string_view pathname = file_url.get_pathname();
2864-
#ifdef _WIN32
2865-
size_t first_percent = std::string::npos;
2866-
size_t pathname_size = pathname.size();
2867-
std::string pathname_escaped_slash;
2868-
2869-
for (size_t i = 0; i < pathname_size; i++) {
2870-
if (pathname[i] == '/') {
2871-
pathname_escaped_slash += '\\';
2872-
} else {
2873-
pathname_escaped_slash += pathname[i];
2874-
}
2875-
2876-
if (pathname[i] != '%') continue;
2877-
2878-
if (first_percent == std::string::npos) {
2879-
first_percent = i;
2880-
}
2881-
2882-
// just safe-guard against access the pathname
2883-
// outside the bounds
2884-
if ((i + 2) >= pathname_size) continue;
2885-
2886-
char third = pathname[i + 2] | 0x20;
2887-
2888-
bool is_slash = pathname[i + 1] == '2' && third == 102;
2889-
bool is_forward_slash = pathname[i + 1] == '5' && third == 99;
2890-
2891-
if (!is_slash && !is_forward_slash) continue;
2892-
2893-
env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
2894-
env->isolate(),
2895-
"File URL path must not include encoded \\ or / characters"));
2896-
2897-
return false;
2898-
}
2899-
2900-
std::string_view hostname = file_url.get_hostname();
2901-
std::string decoded_pathname = ada::unicode::percent_decode(
2902-
std::string_view(pathname_escaped_slash), first_percent);
2903-
2904-
if (hostname.size() > 0) {
2905-
// If hostname is set, then we have a UNC path
2906-
// Pass the hostname through domainToUnicode just in case
2907-
// it is an IDN using punycode encoding. We do not need to worry
2908-
// about percent encoding because the URL parser will have
2909-
// already taken care of that for us. Note that this only
2910-
// causes IDNs with an appropriate `xn--` prefix to be decoded.
2911-
result_file_path =
2912-
"\\\\" + ada::unicode::to_unicode(hostname) + decoded_pathname;
2913-
2914-
return true;
2915-
}
2916-
2917-
char letter = decoded_pathname[1] | 0x20;
2918-
char sep = decoded_pathname[2];
2919-
2920-
// a..z A..Z
2921-
if (letter < 'a' || letter > 'z' || sep != ':') {
2922-
env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
2923-
env->isolate(), "File URL path must be absolute"));
2924-
2925-
return false;
2926-
}
2927-
2928-
result_file_path = decoded_pathname.substr(1);
2929-
2930-
return true;
2931-
#else // _WIN32
2932-
std::string_view hostname = file_url.get_hostname();
2933-
2934-
if (hostname.size() > 0) {
2935-
std::string error_message =
2936-
std::string("File URL host must be \"localhost\" or empty on ") +
2937-
std::string(per_process::metadata.platform);
2938-
env->isolate()->ThrowException(
2939-
ERR_INVALID_FILE_URL_HOST(env->isolate(), error_message.c_str()));
2940-
2941-
return false;
2942-
}
2943-
2944-
size_t first_percent = std::string::npos;
2945-
for (size_t i = 0; (i + 2) < pathname.size(); i++) {
2946-
if (pathname[i] != '%') continue;
2947-
2948-
if (first_percent == std::string::npos) {
2949-
first_percent = i;
2950-
}
2951-
2952-
if (pathname[i + 1] == '2' && (pathname[i + 2] | 0x20) == 102) {
2953-
env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
2954-
env->isolate(),
2955-
"File URL path must not include encoded / characters"));
2956-
2957-
return false;
2958-
}
2959-
}
2960-
2961-
result_file_path = ada::unicode::percent_decode(pathname, first_percent);
2962-
2963-
return true;
2964-
#endif // _WIN32
2965-
}
2966-
29672851
BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile(
29682852
Environment* env, const std::string& file_path) {
29692853
THROW_IF_INSUFFICIENT_PERMISSIONS(
@@ -3051,7 +2935,9 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
30512935
return;
30522936
}
30532937

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

30562942
FromNamespacedPath(&initial_file_path);
30572943

@@ -3085,7 +2971,8 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
30852971
return;
30862972
}
30872973

3088-
if (!FileURLToPath(env, file_path_url.value(), initial_file_path)) return;
2974+
if (!node::url::FileURLToPath(env, file_path_url.value(), initial_file_path))
2975+
return;
30892976

30902977
FromNamespacedPath(&initial_file_path);
30912978

@@ -3112,7 +2999,8 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
31122999
std::string module_path;
31133000
std::string module_base;
31143001

3115-
if (!FileURLToPath(env, package_json_url.value(), module_path)) return;
3002+
if (!node::url::FileURLToPath(env, package_json_url.value(), module_path))
3003+
return;
31163004

31173005
if (args.Length() >= 3 && !args[2]->IsNullOrUndefined() &&
31183006
args[2]->IsString()) {
@@ -3127,7 +3015,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
31273015
return;
31283016
}
31293017

3130-
if (!FileURLToPath(env, base_url.value(), module_base)) return;
3018+
if (!node::url::FileURLToPath(env, base_url.value(), module_base)) return;
31313019
} else {
31323020
std::string err_arg_message =
31333021
"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)