diff options
-rw-r--r-- | include/Uri/Uri.hpp | 8 | ||||
-rw-r--r-- | src/Uri.cpp | 69 | ||||
-rw-r--r-- | test/src/UriTests.cpp | 19 |
3 files changed, 96 insertions, 0 deletions
diff --git a/include/Uri/Uri.hpp b/include/Uri/Uri.hpp index 8be3dd0..afdb631 100644 --- a/include/Uri/Uri.hpp +++ b/include/Uri/Uri.hpp @@ -163,6 +163,14 @@ namespace Uri { */ std::string GetFragment() const; + /** + * This method applies the "remove_dot_segments" routine talked about + * in RFC 3986 (https://tools.ietf.org/html/rfc3986) to the path + * segments of the URI, in order to normalize the path + * (apply and remove "." and ".." segments). + */ + void NormalizePath(); + // Private properties private: /** diff --git a/src/Uri.cpp b/src/Uri.cpp index 77e561a..0153e5f 100644 --- a/src/Uri.cpp +++ b/src/Uri.cpp @@ -702,4 +702,73 @@ namespace Uri { return impl_->fragment; } + void Uri::NormalizePath() { + /* + * This is a straight-up implementation of the + * algorithm from section 5.2.4 of + * RFC 3986 (https://tools.ietf.org/html/rfc3986). + */ + // Step 1 + auto oldPath = std::move(impl_->path); + impl_->path.clear(); + // Step 2 + while (!oldPath.empty()) { + // Step 2A + if ( + (oldPath[0] == ".") + || (oldPath[0] == "..") + ) { + oldPath.erase(oldPath.begin()); + } else + + // Step 2B + if ( + (oldPath.size() >= 2) + && (oldPath[0] == "") + && (oldPath[1] == ".") + ) { + oldPath.erase(oldPath.begin() + 1); + } else + + // Step 2C + if ( + (oldPath.size() >= 2) + && (oldPath[0] == "") + && (oldPath[1] == "..") + ) { + oldPath.erase(oldPath.begin() + 1); + impl_->path.pop_back(); + } else + + // Step 2D + if ( + (oldPath.size() == 1) + && ( + (oldPath[0] == ".") + || (oldPath[0] == "..") + ) + ) { + oldPath.erase(oldPath.begin()); + } else + + // Step 2E + { + if (oldPath[0] == "") { + if (impl_->path.empty()) { + impl_->path.push_back(""); + } + oldPath.erase(oldPath.begin()); + } + if (!oldPath.empty()) { + impl_->path.push_back(oldPath[0]); + if (oldPath.size() > 1) { + oldPath[0] = ""; + } else { + oldPath.erase(oldPath.begin()); + } + } + } + } + } + } diff --git a/test/src/UriTests.cpp b/test/src/UriTests.cpp index 4242885..cbc8b8a 100644 --- a/test/src/UriTests.cpp +++ b/test/src/UriTests.cpp @@ -584,3 +584,22 @@ TEST(UriTests, ParseFromStringPathsWithPercentEncodedCharacters) { ++index; } } + +TEST(UriTests, NormalizePath) { + struct TestVector { + std::string uriString; + std::vector< std::string > normalizedPathSegments; + }; + const std::vector< TestVector > testVectors{ + {"/a/b/c/./../../g", {"", "a", "g"}}, + {"mid/content=5/../6", {"mid", "6"}}, + }; + size_t index = 0; + for (const auto& testVector : testVectors) { + Uri::Uri uri; + ASSERT_TRUE(uri.ParseFromString(testVector.uriString)) << index; + uri.NormalizePath(); + ASSERT_EQ(testVector.normalizedPathSegments, uri.GetPath()); + ++index; + } +} |