aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Walters <rwalters@digitalstirling.com>2018-07-03 00:19:10 -0700
committerRichard Walters <rwalters@digitalstirling.com>2018-07-03 00:19:10 -0700
commitea77de493c75fc5b7fad10ef79b645e98d3f94e8 (patch)
tree832a12424c3b45f9756064c77e641da707b0bfe9
parent22cfb83209a7da292a07b66945ca545cc0954524 (diff)
Complete rewrite of NormalizePath
The former algorithm was based on the pseuocode from the RFC, which is hard to follow, more suitable when the path is in a single string, not a sequence of segments. The new algorithm uses two flags: * isAbsolute - recognize that if the path starts out as an absolute path, it needs to stay that way. * atDirectoryLevel - recognize that if we encounter a "." or "..", then it will be reduced by simply discarding it or going back/up one stop, but then we will be in a "directory" context, meaning that should we end the path at this point, there needs to be an empty-string segment to mark that the end of the path is reaching into a directory, not just referring to the directory.
-rw-r--r--src/Uri.cpp91
1 files changed, 32 insertions, 59 deletions
diff --git a/src/Uri.cpp b/src/Uri.cpp
index e29e517..721442e 100644
--- a/src/Uri.cpp
+++ b/src/Uri.cpp
@@ -737,72 +737,45 @@ namespace Uri {
}
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);
+ bool isAbsolute = (
+ !oldPath.empty()
+ && oldPath[0].empty()
+ );
+ bool atDirectoryLevel = false;
+ for (const auto segment: oldPath) {
+ if (segment == ".") {
+ atDirectoryLevel = true;
+ } else if (segment == "..") {
if (!impl_->path.empty()) {
- 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] == "") {
- 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());
+ if (
+ !isAbsolute
+ || (impl_->path.size() > 1)
+ ) {
+ impl_->path.pop_back();
}
}
+ atDirectoryLevel = true;
+ } else {
+ if (
+ !atDirectoryLevel
+ || !segment.empty()
+ ) {
+ impl_->path.push_back(segment);
+ }
+ atDirectoryLevel = segment.empty();
}
}
+ if (
+ atDirectoryLevel
+ && (
+ !impl_->path.empty()
+ && !impl_->path.back().empty()
+ )
+ ) {
+ impl_->path.push_back("");
+ }
}
Uri Uri::Resolve(const Uri& relativeReference) const {