From febf3569b1242186ab8b2e9b56283059416a99a7 Mon Sep 17 00:00:00 2001 From: Michael Sternberg Date: Mon, 30 Sep 2024 21:56:56 -0500 Subject: [PATCH] Improve relative path resolution (retry) --- lib/utils/peoples_url_parser.cpp | 3 +- lib/utils/utils.cpp | 47 +++++++++++++++++++------------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/lib/utils/peoples_url_parser.cpp b/lib/utils/peoples_url_parser.cpp index 3dbb08909..eeb9a4ad4 100644 --- a/lib/utils/peoples_url_parser.cpp +++ b/lib/utils/peoples_url_parser.cpp @@ -26,6 +26,7 @@ #include #include "../../include/debug.h" +#include "utils.h" #include "string_utils.h" @@ -92,7 +93,7 @@ void PeoplesUrlParser::cleanPath() { // while(mstr::endsWith(path,"/")) { // path=mstr::dropLast(path, 1); // } - mstr::replaceAll(path, "//", "/"); + path = util_get_canonical_path(path); } void PeoplesUrlParser::processPath() { diff --git a/lib/utils/utils.cpp b/lib/utils/utils.cpp index efb28588c..cbf2e60b2 100644 --- a/lib/utils/utils.cpp +++ b/lib/utils/utils.cpp @@ -790,16 +790,19 @@ void util_replaceAll(std::string &str, const std::string &from, const std::strin } /** - * Resolve prefix containing relative references (../ or ./) + * Resolve path containing relative references (../ or ./) * to canonical path. - * @param prefix FujiNet path such as TNFS://myhost/path/to/here/ + * @param path FujiNet path such as TNFS://myhost/path/to/here/ + * or tnfs://myhost/some/filename.ext */ -std::string util_get_canonical_path(std::string prefix) +std::string util_get_canonical_path(std::string path) { + bool is_last_slash = (path.back() == '/') ? true : false; + std::size_t proto_host_len; // stack to store the file's names. - std::stack st; + std::stack st; // temporary string which stores the extracted // directory name or commands("." / "..") @@ -811,20 +814,26 @@ std::string util_get_canonical_path(std::string prefix) std::string res; // advance beyond protocol and hostname - proto_host_len = prefix.find("://"); + proto_host_len = path.find("://"); - if (proto_host_len > 0) + // If protocol delimiter "://" is found, skip over the protocol + if (proto_host_len < std::string::npos) { - proto_host_len += 3; - proto_host_len = prefix.find("/", proto_host_len) + 1; + proto_host_len += 3; // "://" is 3 chars + proto_host_len = path.find("/", proto_host_len) + 1; + res.append(path.substr(0, proto_host_len)); + } + else + { + proto_host_len = 0; // no protocol prefix and hostname + // Preserve an absolute path if one is provided in the input + if (!path.empty() && path[0] == '/') + res = "/"; } - res.append(prefix.substr(0, proto_host_len)); - - int len_prefix = prefix.length(); + int len_path = path.length(); - // for (int i = proto_host_len-1; i < len_prefix; i++) - for (int i = proto_host_len; i < len_prefix; i++) + for (int i = proto_host_len; i < len_path; i++) { // we will clear the temporary string // every time to accommodate new directory @@ -832,14 +841,14 @@ std::string util_get_canonical_path(std::string prefix) dir.clear(); // skip all the multiple '/' Eg. "/////"" - while (prefix[i] == '/') + while (path[i] == '/') i++; // stores directory's name("a", "b" etc.) // or commands("."/"..") into dir - while (i < len_prefix && prefix[i] != '/') + while (i < len_path && path[i] != '/') { - dir.push_back(prefix[i]); + dir.push_back(path[i]); i++; } @@ -865,7 +874,7 @@ std::string util_get_canonical_path(std::string prefix) // a temporary stack (st1) which will contain // the reverse of original stack(st). - std::stack st1; + std::stack st1; while (!st.empty()) { st1.push(st.top()); @@ -888,7 +897,7 @@ std::string util_get_canonical_path(std::string prefix) } // Append trailing slash if not already there - if ((res.length() > 0) && (res[res.length() - 1] != '/')) + if ((res.length() > 0) && (res.back() != '/') && is_last_slash) res.append("/"); return res; @@ -1058,4 +1067,4 @@ char* util_strndup(const char* s, size_t n) { int get_value_or_default(const std::map& map, int key, int default_value) { auto it = map.find(key); return it != map.end() ? it->second : default_value; -} \ No newline at end of file +}