aboutsummaryrefslogtreecommitdiff
path: root/src
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 /src
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.
Diffstat (limited to 'src')
-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 {