Skip to content

Commit

Permalink
Fix canonicalization of relative URI paths with leading slashes (#1430)
Browse files Browse the repository at this point in the history
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
  • Loading branch information
jviotti authored Jan 10, 2025
1 parent 55481f3 commit 4b04d73
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 4 deletions.
8 changes: 4 additions & 4 deletions src/uri/uri.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ static auto uri_parse(const std::string &data, UriUriA *uri) -> void {
uri_normalize(uri);
}

static auto canonicalize_path(const std::string &path, const bool is_relative)
static auto canonicalize_path(const std::string &path)
-> std::optional<std::string> {
// TODO: This is a hack, as this whole function works badly for
// relative paths with ".."
Expand Down Expand Up @@ -98,7 +98,7 @@ static auto canonicalize_path(const std::string &path, const bool is_relative)

// Reconstruct the canonical path
std::string canonical_path;
std::string separator = (is_relative && !has_leading_with_word) ? "/" : "";
std::string separator = "";

for (const auto &seg : segments) {
canonical_path += separator + seg;
Expand Down Expand Up @@ -430,8 +430,7 @@ auto URI::canonicalize() -> URI & {
// Clean Path form ".." and "."
const auto result_path{this->path()};
if (result_path.has_value()) {
const auto canonical_path{
canonicalize_path(result_path.value(), this->is_relative())};
const auto canonical_path{canonicalize_path(result_path.value())};
if (canonical_path.has_value()) {
this->path_ = canonical_path.value();
}
Expand Down Expand Up @@ -559,6 +558,7 @@ auto URI::try_resolve_from(const URI &base) -> URI & {
// TODO: This only handles a very specific case. We should generalize this
// function to perform proper base resolution on relative bases
} else if (this->is_fragment_only() && !base.fragment().has_value()) {
this->data = base.data;
this->path_ = base.path_;
this->userinfo_ = base.userinfo_;
this->host_ = base.host_;
Expand Down
31 changes: 31 additions & 0 deletions test/jsonschema/jsonschema_frame_2019_09_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2004,3 +2004,34 @@ TEST(JSONSchema_frame_2019_09, relative_base_uri_with_ref) {
EXPECT_STATIC_REFERENCE(frame, "/allOf/0/$ref", "common#foo", "common",
"foo");
}

TEST(JSONSchema_frame_2019_09, relative_id_leading_slash) {
const sourcemeta::jsontoolkit::JSON document =
sourcemeta::jsontoolkit::parse(R"JSON({
"$id": "/base",
"$schema": "https://json-schema.org/draft/2019-09/schema"
})JSON");

sourcemeta::jsontoolkit::Frame frame;
frame.analyse(document, sourcemeta::jsontoolkit::default_schema_walker,
sourcemeta::jsontoolkit::official_resolver);

EXPECT_EQ(frame.locations().size(), 3);
EXPECT_FRAME_STATIC_2019_09_RESOURCE(frame, "/base", "/base", "", "/base", "",
0);

// JSON Pointers

EXPECT_FRAME_STATIC_2019_09_POINTER(frame, "/base#/$id", "/base", "/$id",
"/base", "/$id", 0);
EXPECT_FRAME_STATIC_2019_09_POINTER(frame, "/base#/$schema", "/base",
"/$schema", "/base", "/$schema", 0);

// References

EXPECT_EQ(frame.references().size(), 1);

EXPECT_STATIC_REFERENCE(
frame, "/$schema", "https://json-schema.org/draft/2019-09/schema",
"https://json-schema.org/draft/2019-09/schema", std::nullopt);
}
6 changes: 6 additions & 0 deletions test/uri/uri_canonicalize_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ TEST(URI_canonicalize, example_relative_4) {
EXPECT_EQ(uri.recompose(), "foo/bar");
}

TEST(URI_canonicalize, example_relative_6) {
sourcemeta::jsontoolkit::URI uri{"/foo"};
uri.canonicalize();
EXPECT_EQ(uri.recompose(), "/foo");
}

TEST(URI_canonicalize, example_12) {
sourcemeta::jsontoolkit::URI uri{"#foo"};
uri.canonicalize();
Expand Down
7 changes: 7 additions & 0 deletions test/uri/uri_resolve_from_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ TEST(URI_try_resolve_from, pointer_fragment_on_relative_path) {
EXPECT_EQ(relative.recompose(), "foo#/bar");
}

TEST(URI_try_resolve_from, base_relative_path_leading_slash) {
const sourcemeta::jsontoolkit::URI base{"/foo"};
sourcemeta::jsontoolkit::URI relative{"#/bar"};
relative.try_resolve_from(base);
EXPECT_EQ(relative.recompose(), "/foo#/bar");
}

// RFC 3986, inspired from
// https://cr.openjdk.org/~dfuchs/writeups/updating-uri/A Section "Resolutuon"

Expand Down

4 comments on commit 4b04d73

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark (macos/llvm)

Benchmark suite Current: 4b04d73 Previous: 55481f3 Ratio
JSON_Array_Of_Objects_Unique 342.6489024557436 ns/iter 407.459216519292 ns/iter 0.84
JSON_Parse_1 21705.226241549248 ns/iter 25862.212085917818 ns/iter 0.84
JSON_Fast_Hash_Helm_Chart_Lock 51.44898973050822 ns/iter 57.95479504845729 ns/iter 0.89
JSON_Equality_Helm_Chart_Lock 131.93544163518078 ns/iter 154.35157276779012 ns/iter 0.85
Regex_Lower_S_Or_Upper_S_Asterisk 1.5694098007288662 ns/iter 1.7515113674257687 ns/iter 0.90
Regex_Caret_Lower_S_Or_Upper_S_Asterisk_Dollar 1.5747650687678212 ns/iter 1.7316679848811976 ns/iter 0.91
Regex_Period_Asterisk 1.5713696147351714 ns/iter 1.8475199273979472 ns/iter 0.85
Regex_Group_Period_Asterisk_Group 1.5720335801048975 ns/iter 1.6977302224322826 ns/iter 0.93
Regex_Period_Plus 1.8900372415409974 ns/iter 2.4910686245373266 ns/iter 0.76
Regex_Period 1.8855641136840815 ns/iter 2.165795449841771 ns/iter 0.87
Regex_Caret_Period_Plus_Dollar 1.8848963733772441 ns/iter 2.0989762475510423 ns/iter 0.90
Regex_Caret_Group_Period_Plus_Group_Dollar 1.8852162281215603 ns/iter 2.071488316107489 ns/iter 0.91
Regex_Caret_Period_Asterisk_Dollar 1.5692751711659874 ns/iter 1.7085505559815002 ns/iter 0.92
Regex_Caret_Group_Period_Asterisk_Group_Dollar 1.570022786134582 ns/iter 1.6682543585173972 ns/iter 0.94
Regex_Caret_X_Hyphen 6.30523988713433 ns/iter 6.564934534701128 ns/iter 0.96
Regex_Period_Md_Dollar 69.48670971486591 ns/iter 71.20947022637732 ns/iter 0.98
Regex_Caret_Slash_Period_Asterisk 6.710547224593167 ns/iter 7.5654015303254845 ns/iter 0.89
Regex_Caret_Period_Range_Dollar 2.0361345717246513 ns/iter 2.142386520023517 ns/iter 0.95
Regex_Nested_Backtrack 725.8954708932023 ns/iter 773.3462000510282 ns/iter 0.94
Pointer_Object_Traverse 15.247473910253499 ns/iter 15.725582600629465 ns/iter 0.97
Pointer_Object_Try_Traverse 31.508737475598654 ns/iter 35.45585758590162 ns/iter 0.89
Pointer_Push_Back_Pointer_To_Weak_Pointer 173.22369903074818 ns/iter 181.87580669859832 ns/iter 0.95

This comment was automatically generated by workflow using github-action-benchmark.

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark (linux/llvm)

Benchmark suite Current: 4b04d73 Previous: 55481f3 Ratio
JSON_Array_Of_Objects_Unique 445.1658283192557 ns/iter 443.41870124154434 ns/iter 1.00
JSON_Parse_1 29969.246862281914 ns/iter 30856.39630054861 ns/iter 0.97
JSON_Fast_Hash_Helm_Chart_Lock 54.69452167440643 ns/iter 54.717853651566976 ns/iter 1.00
JSON_Equality_Helm_Chart_Lock 145.74450222918298 ns/iter 150.29080986917077 ns/iter 0.97
Regex_Lower_S_Or_Upper_S_Asterisk 2.20022864160664 ns/iter 2.1813326640329915 ns/iter 1.01
Regex_Caret_Lower_S_Or_Upper_S_Asterisk_Dollar 2.193531428313369 ns/iter 2.1860155093271376 ns/iter 1.00
Regex_Period_Asterisk 2.2128287716203614 ns/iter 2.181417065696179 ns/iter 1.01
Regex_Group_Period_Asterisk_Group 2.191307434774555 ns/iter 2.182036349715757 ns/iter 1.00
Regex_Period_Plus 2.486323042170805 ns/iter 2.4914004008456194 ns/iter 1.00
Regex_Period 2.4859844836476954 ns/iter 2.506632647577241 ns/iter 0.99
Regex_Caret_Period_Plus_Dollar 2.2710142581093438 ns/iter 2.4887776977850873 ns/iter 0.91
Regex_Caret_Group_Period_Plus_Group_Dollar 2.2765616233953105 ns/iter 2.489922474578475 ns/iter 0.91
Regex_Caret_Period_Asterisk_Dollar 2.48695450832223 ns/iter 3.4192200934329176 ns/iter 0.73
Regex_Caret_Group_Period_Asterisk_Group_Dollar 2.4861893176483925 ns/iter 3.418952737835449 ns/iter 0.73
Regex_Caret_X_Hyphen 12.52856247108536 ns/iter 12.504706843113246 ns/iter 1.00
Regex_Period_Md_Dollar 73.70581651740909 ns/iter 74.05161340026288 ns/iter 1.00
Regex_Caret_Slash_Period_Asterisk 7.149466252312237 ns/iter 7.093413433351044 ns/iter 1.01
Regex_Caret_Period_Range_Dollar 2.4938970230158755 ns/iter 2.5058175069195956 ns/iter 1.00
Regex_Nested_Backtrack 491.679554149494 ns/iter 506.3542772193359 ns/iter 0.97
Pointer_Object_Traverse 44.788569441834994 ns/iter 44.90762013352479 ns/iter 1.00
Pointer_Object_Try_Traverse 53.193323097873595 ns/iter 52.26983470377153 ns/iter 1.02
Pointer_Push_Back_Pointer_To_Weak_Pointer 354.7159460770064 ns/iter 352.297219581662 ns/iter 1.01

This comment was automatically generated by workflow using github-action-benchmark.

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark (windows/msvc)

Benchmark suite Current: 4b04d73 Previous: 55481f3 Ratio
JSON_Array_Of_Objects_Unique 435.00737500011155 ns/iter 419.10147843102794 ns/iter 1.04
JSON_Parse_1 83702.96874998319 ns/iter 81309.16294643495 ns/iter 1.03
JSON_Fast_Hash_Helm_Chart_Lock 59.704940000006 ns/iter 56.79349107143342 ns/iter 1.05
JSON_Equality_Helm_Chart_Lock 228.0587357077244 ns/iter 214.83100000001087 ns/iter 1.06
Regex_Lower_S_Or_Upper_S_Asterisk 8.532138392856682 ns/iter 8.09690219599542 ns/iter 1.05
Regex_Caret_Lower_S_Or_Upper_S_Asterisk_Dollar 8.04193255338269 ns/iter 7.924672732480097 ns/iter 1.01
Regex_Period_Asterisk 8.327903534250876 ns/iter 7.952081473214482 ns/iter 1.05
Regex_Group_Period_Asterisk_Group 8.034918526784095 ns/iter 7.992249999999907 ns/iter 1.01
Regex_Period_Plus 8.135332999397985 ns/iter 7.929559786028484 ns/iter 1.03
Regex_Period 8.051205767629174 ns/iter 8.11947433035698 ns/iter 0.99
Regex_Caret_Period_Plus_Dollar 7.912025857533314 ns/iter 8.000271205356972 ns/iter 0.99
Regex_Caret_Group_Period_Plus_Group_Dollar 8.832472728425117 ns/iter 8.38834549826642 ns/iter 1.05
Regex_Caret_Period_Asterisk_Dollar 7.789064062500017 ns/iter 8.303265625000073 ns/iter 0.94
Regex_Caret_Group_Period_Asterisk_Group_Dollar 8.23741737394046 ns/iter 8.224844159711257 ns/iter 1.00
Regex_Caret_X_Hyphen 11.566604687502036 ns/iter 11.618403571428562 ns/iter 1.00
Regex_Period_Md_Dollar 142.00964767811402 ns/iter 145.94708723451558 ns/iter 0.97
Regex_Caret_Slash_Period_Asterisk 11.935163116364066 ns/iter 11.775487499999063 ns/iter 1.01
Regex_Caret_Period_Range_Dollar 8.964932102834474 ns/iter 9.086469602291999 ns/iter 0.99
Regex_Nested_Backtrack 586.6695535713365 ns/iter 588.6363392856911 ns/iter 1.00
Pointer_Object_Traverse 55.89243749998981 ns/iter 56.69698214285899 ns/iter 0.99
Pointer_Object_Try_Traverse 75.99424107141317 ns/iter 76.37816964285449 ns/iter 0.99
Pointer_Push_Back_Pointer_To_Weak_Pointer 191.31794565335926 ns/iter 175.17648494484808 ns/iter 1.09

This comment was automatically generated by workflow using github-action-benchmark.

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark (linux/gcc)

Benchmark suite Current: 4b04d73 Previous: 55481f3 Ratio
Pointer_Object_Traverse 50.18702809651256 ns/iter 44.323071200537065 ns/iter 1.13
Pointer_Object_Try_Traverse 24.622513914266523 ns/iter 22.409523536155056 ns/iter 1.10
Pointer_Push_Back_Pointer_To_Weak_Pointer 213.17270709021975 ns/iter 213.00843352003835 ns/iter 1.00
Regex_Lower_S_Or_Upper_S_Asterisk 3.1231955616085556 ns/iter 3.1354589423323262 ns/iter 1.00
Regex_Caret_Lower_S_Or_Upper_S_Asterisk_Dollar 3.130828609019674 ns/iter 3.1236844399220987 ns/iter 1.00
Regex_Period_Asterisk 3.122312645712708 ns/iter 3.1244189730837797 ns/iter 1.00
Regex_Group_Period_Asterisk_Group 3.122895313002317 ns/iter 3.124149829439447 ns/iter 1.00
Regex_Period_Plus 3.1273323382859193 ns/iter 3.1251358316953213 ns/iter 1.00
Regex_Period 3.126788947460779 ns/iter 3.1283836481291374 ns/iter 1.00
Regex_Caret_Period_Plus_Dollar 3.1316186871732135 ns/iter 3.1256782396702962 ns/iter 1.00
Regex_Caret_Group_Period_Plus_Group_Dollar 3.1233518534670113 ns/iter 3.1257985513587023 ns/iter 1.00
Regex_Caret_Period_Asterisk_Dollar 3.1290650749377256 ns/iter 3.126567055852649 ns/iter 1.00
Regex_Caret_Group_Period_Asterisk_Group_Dollar 3.126457674540122 ns/iter 3.1302327364697122 ns/iter 1.00
Regex_Caret_X_Hyphen 12.431149374894764 ns/iter 12.43179876404824 ns/iter 1.00
Regex_Period_Md_Dollar 89.25451018058364 ns/iter 89.63427958149308 ns/iter 1.00
Regex_Caret_Slash_Period_Asterisk 7.14604530308933 ns/iter 7.1531579424733405 ns/iter 1.00
Regex_Caret_Period_Range_Dollar 4.039906061789911 ns/iter 3.185703537765074 ns/iter 1.27
Regex_Nested_Backtrack 833.3509879230805 ns/iter 813.1069888583747 ns/iter 1.02
JSON_Array_Of_Objects_Unique 377.4044799985154 ns/iter 377.73481002123015 ns/iter 1.00
JSON_Parse_1 33185.93026466167 ns/iter 32810.163484040466 ns/iter 1.01
JSON_Fast_Hash_Helm_Chart_Lock 62.94871641328834 ns/iter 63.95427803930726 ns/iter 0.98
JSON_Equality_Helm_Chart_Lock 146.9782408346559 ns/iter 142.6291877626806 ns/iter 1.03

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.