From a609673ce8c942d91e14f24d1d8832951ab27964 Mon Sep 17 00:00:00 2001 From: Andrew Lindesay Date: Mon, 10 Sep 2018 22:30:39 +0200 Subject: [PATCH] Support : Fixes for Relative URL Handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When URLs combine a base URL with a relative part, the relative part's path component was being pre-processed. This removed any ".." from the path and in some cases in the unit test cases, the ".." should have been retained and then only later applied to the base URL. This changes fixes this so that the relative part is not pre-processed and is applied with it's path in a raw state. Completes Fixes for #14377 Change-Id: I9cebb8599889494e11f40a3b54c87ebca3ed1a21 Reviewed-on: https://review.haiku-os.org/529 Reviewed-by: Jérôme Duval --- headers/os/support/Url.h | 5 ++++- src/kits/support/Url.cpp | 48 +++++++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/headers/os/support/Url.h b/headers/os/support/Url.h index b6e37148d4..b3416f5c7b 100644 --- a/headers/os/support/Url.h +++ b/headers/os/support/Url.h @@ -100,7 +100,8 @@ public: private: void _ResetFields(); bool _ContainsDelimiter(const BString& url); - status_t _ExplodeUrlString(const BString& urlString); + status_t _ExplodeUrlString(const BString& urlString, + uint32 flags); BString _MergePath(const BString& relative) const; void _SetPathUnsafe(const BString& path); @@ -122,6 +123,8 @@ private: static bool _IsHostChar(char c); static bool _IsPortChar(char c); + static void _RemoveLastPathComponent(BString& path); + BString _UrlMimeType() const; private: diff --git a/src/kits/support/Url.cpp b/src/kits/support/Url.cpp index d625d4f0ec..35f12a6a0f 100644 --- a/src/kits/support/Url.cpp +++ b/src/kits/support/Url.cpp @@ -30,6 +30,11 @@ static const char* kArchivedUrl = "be:url string"; +/*! These flags can be combined to control the parse process. */ + +const uint32 PARSE_NO_MASK_BIT = 0x00000000; +const uint32 PARSE_RAW_PATH_MASK_BIT = 0x00000001; + BUrl::BUrl(const char* url) : @@ -126,7 +131,12 @@ BUrl::BUrl(const BUrl& base, const BString& location) { // This implements the algorithm in RFC3986, Section 5.2. - BUrl relative(location); + BUrl relative; + relative._ExplodeUrlString(location, PARSE_RAW_PATH_MASK_BIT); + // This parse will leave the path 'raw' so that it still carries any + // special sequences such as '..' and '.' in it. This way it can be + // later combined with the base. + if (relative.HasProtocol()) { SetProtocol(relative.Protocol()); if (relative.HasAuthority()) @@ -212,7 +222,7 @@ BUrl::~BUrl() BUrl& BUrl::SetUrlString(const BString& url) { - _ExplodeUrlString(url); + _ExplodeUrlString(url, PARSE_NO_MASK_BIT); return *this; } @@ -273,6 +283,18 @@ BUrl::SetPort(int port) } +void +BUrl::_RemoveLastPathComponent(BString& path) +{ + int32 outputLastSlashIdx = path.FindLast('/'); + + if (outputLastSlashIdx == B_ERROR) + path.Truncate(0); + else + path.Truncate(outputLastSlashIdx); +} + + BUrl& BUrl::SetPath(const BString& path) { @@ -309,13 +331,13 @@ BUrl::SetPath(const BString& path) // 2.C. if (input.StartsWith("/../")) { input.Remove(0, 3); - output.Truncate(output.FindLast('/')); + _RemoveLastPathComponent(output); continue; } if (input == "/..") { input.Remove(1, 2); - output.Truncate(output.FindLast('/')); + _RemoveLastPathComponent(output); continue; } @@ -971,7 +993,7 @@ char_offset_until_fn_false(const char* url, int32 len, int32 offset, * This function takes a URL in string-form and parses the components of the URL out. */ status_t -BUrl::_ExplodeUrlString(const BString& url) +BUrl::_ExplodeUrlString(const BString& url, uint32 flags) { _ResetFields(); @@ -1058,7 +1080,12 @@ BUrl::_ExplodeUrlString(const BString& url) { int end_path = char_offset_until_fn_false(url_c, length, offset, explode_is_path_char); - SetPath(BString(&url_c[offset], end_path - offset)); + BString path(&url_c[offset], end_path - offset); + + if ((flags & PARSE_RAW_PATH_MASK_BIT) == 0) + SetPath(path); + else + _SetPathUnsafe(path); state = EXPLODE_REQUEST; offset = end_path; break; @@ -1116,8 +1143,13 @@ BUrl::_MergePath(const BString& relative) const return result; } - BString result(fPath); - result.Truncate(result.FindLast("/") + 1); + int32 lastSlashIndex = fPath.FindLast("/"); + + if (lastSlashIndex == B_ERROR) + return relative; + + BString result; + result.SetTo(fPath, lastSlashIndex + 1); result << relative; return result;