Skip to content

Commit 119cbf3

Browse files
authored
Fix for node issue 47889 (#368)
1 parent 12df648 commit 119cbf3

File tree

6 files changed

+70
-15
lines changed

6 files changed

+70
-15
lines changed

include/ada/url-inl.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,7 @@ size_t url::get_pathname_length() const noexcept { return path.size(); }
9696

9797
out.pathname_start = uint32_t(running_index);
9898

99-
if (!path.empty()) {
100-
running_index += path.size();
101-
}
99+
running_index += path.size();
102100

103101
if (query.has_value()) {
104102
out.search_start = uint32_t(running_index);

src/helpers.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,9 @@ ada_really_inline bool shorten_path(std::string& path,
114114
}
115115

116116
// Remove path’s last item, if any.
117-
if (!path.empty()) {
118-
path.erase(path.rfind('/'));
117+
size_t last_delimiter = path.rfind('/');
118+
if (last_delimiter != std::string::npos) {
119+
path.erase(last_delimiter);
119120
return true;
120121
}
121122

@@ -142,8 +143,8 @@ ada_really_inline bool shorten_path(std::string_view& path,
142143
size_t slash_loc = path.rfind('/');
143144
if (slash_loc != std::string_view::npos) {
144145
path.remove_suffix(path.size() - slash_loc);
146+
return true;
145147
}
146-
return true;
147148
}
148149

149150
return false;
@@ -507,8 +508,9 @@ ada_really_inline void parse_prepared_path(std::string_view input,
507508
input.substr(previous_location, new_location - previous_location);
508509
previous_location = new_location + 1;
509510
if (path_view == "..") {
510-
if (!path.empty()) {
511-
path.erase(path.rfind('/'));
511+
size_t last_delimiter = path.rfind('/');
512+
if (last_delimiter != std::string::npos) {
513+
path.erase(last_delimiter);
512514
}
513515
} else if (path_view != ".") {
514516
path += '/';
@@ -539,8 +541,8 @@ ada_really_inline void parse_prepared_path(std::string_view input,
539541
? path_buffer_tmp
540542
: path_view;
541543
if (unicode::is_double_dot_path_segment(path_buffer)) {
542-
helpers::shorten_path(path, type);
543-
if (location == std::string_view::npos) {
544+
if ((helpers::shorten_path(path, type) || special) &&
545+
location == std::string_view::npos) {
544546
path += '/';
545547
}
546548
} else if (unicode::is_single_dot_path_segment(path_buffer) &&

src/parser.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,8 @@ result_type parse_url(std::string_view user_input,
421421
url.password = base_url->password;
422422
url.host = base_url->host;
423423
url.port = base_url->port;
424+
// cloning the base path includes cloning the has_opaque_path flag
425+
url.has_opaque_path = base_url->has_opaque_path;
424426
url.path = base_url->path;
425427
url.query = base_url->query;
426428
} else {
@@ -430,6 +432,8 @@ result_type parse_url(std::string_view user_input,
430432
// update_base_hostname
431433
url.set_hostname(base_url->get_hostname());
432434
url.update_base_port(base_url->retrieve_base_port());
435+
// cloning the base path includes cloning the has_opaque_path flag
436+
url.has_opaque_path = base_url->has_opaque_path;
433437
url.update_base_pathname(base_url->get_pathname());
434438
url.update_base_search(base_url->get_search());
435439
}
@@ -861,7 +865,6 @@ result_type parse_url(std::string_view user_input,
861865
else if (input_position != input_size) {
862866
// Set url’s query to null.
863867
url.clear_search();
864-
865868
// If the code point substring from pointer to the end of input does
866869
// not start with a Windows drive letter, then shorten url’s path.
867870
if (!checkers::is_windows_drive_letter(file_view)) {

src/url_aggregator.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1653,8 +1653,9 @@ inline void url_aggregator::consume_prepared_path(std::string_view input) {
16531653
input.substr(previous_location, new_location - previous_location);
16541654
previous_location = new_location + 1;
16551655
if (path_view == "..") {
1656-
if (!path.empty()) {
1657-
path.erase(path.rfind('/'));
1656+
size_t last_delimiter = path.rfind('/');
1657+
if (last_delimiter != std::string::npos) {
1658+
path.erase(last_delimiter);
16581659
}
16591660
} else if (path_view != ".") {
16601661
path += '/';
@@ -1685,8 +1686,8 @@ inline void url_aggregator::consume_prepared_path(std::string_view input) {
16851686
? path_buffer_tmp
16861687
: path_view;
16871688
if (unicode::is_double_dot_path_segment(path_buffer)) {
1688-
helpers::shorten_path(path, type);
1689-
if (location == std::string_view::npos) {
1689+
if ((helpers::shorten_path(path, type) || special) &&
1690+
location == std::string_view::npos) {
16901691
path += '/';
16911692
}
16921693
} else if (unicode::is_single_dot_path_segment(path_buffer) &&

tests/basic_tests.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,3 +272,24 @@ TYPED_TEST(basic_tests, should_update_password_correctly) {
272272
"https://username:test@host:8000/path?query#fragment");
273273
SUCCEED();
274274
}
275+
276+
// https://github.com/nodejs/node/issues/47889
277+
TYPED_TEST(basic_tests, node_issue_47889) {
278+
auto urlbase = ada::parse<TypeParam>("a:b");
279+
ASSERT_EQ(urlbase->get_href(), "a:b");
280+
ASSERT_EQ(urlbase->get_protocol(), "a:");
281+
ASSERT_EQ(urlbase->get_pathname(), "b");
282+
ASSERT_TRUE(urlbase->has_opaque_path);
283+
ASSERT_TRUE(urlbase);
284+
auto expected_url = ada::parse<TypeParam>("a:b#");
285+
ASSERT_TRUE(expected_url);
286+
ASSERT_TRUE(expected_url->has_opaque_path);
287+
ASSERT_EQ(expected_url->get_href(), "a:b#");
288+
ASSERT_EQ(expected_url->get_pathname(), "b");
289+
auto url = ada::parse<TypeParam>("..#", &*urlbase);
290+
ASSERT_TRUE(url);
291+
ASSERT_TRUE(url->has_opaque_path);
292+
ASSERT_EQ(url->get_href(), "a:b#");
293+
ASSERT_EQ(url->get_pathname(), "b");
294+
SUCCEED();
295+
}

tests/wpt/ada_extra_urltestdata.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,5 +255,35 @@
255255
"pathname": "/%22quoted%22",
256256
"search": "",
257257
"hash": ""
258+
},
259+
{
260+
"input": "a:b#",
261+
"base": null,
262+
"href": "a:b#",
263+
"origin": null,
264+
"protocol": "a:",
265+
"username": "",
266+
"password": "",
267+
"host": "",
268+
"hostname": "",
269+
"port": "",
270+
"pathname": "b",
271+
"search": "",
272+
"hash": ""
273+
},
274+
{
275+
"input": "..#",
276+
"base": "a:b",
277+
"href": "a:b#",
278+
"origin": null,
279+
"protocol": "a:",
280+
"username": "",
281+
"password": "",
282+
"host": "",
283+
"hostname": "",
284+
"port": "",
285+
"pathname": "b",
286+
"search": "",
287+
"hash": ""
258288
}
259289
]

0 commit comments

Comments
 (0)