diff options
author | Richard Walters <rwalters@digitalstirling.com> | 2018-07-03 00:19:10 -0700 |
---|---|---|
committer | Richard Walters <rwalters@digitalstirling.com> | 2018-07-03 00:19:10 -0700 |
commit | ea77de493c75fc5b7fad10ef79b645e98d3f94e8 (patch) | |
tree | 832a12424c3b45f9756064c77e641da707b0bfe9 /src | |
parent | 22cfb83209a7da292a07b66945ca545cc0954524 (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.cpp | 91 |
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 { |