diff --git a/modules/juce_core/files/juce_File.cpp b/modules/juce_core/files/juce_File.cpp index 70f87f594b..e07968b192 100644 --- a/modules/juce_core/files/juce_File.cpp +++ b/modules/juce_core/files/juce_File.cpp @@ -1197,6 +1197,28 @@ public: expect (demoFolder.deleteRecursively()); expect (! demoFolder.exists()); + + { + URL url ("https://audio.dev/foo/bar/"); + expectEquals (url.toString (false), String ("https://audio.dev/foo/bar/")); + expectEquals (url.getChildURL ("x").toString (false), String ("https://audio.dev/foo/bar/x")); + expectEquals (url.getParentURL().toString (false), String ("https://audio.dev/foo")); + expectEquals (url.getParentURL().getParentURL().toString (false), String ("https://audio.dev/")); + expectEquals (url.getParentURL().getParentURL().getParentURL().toString (false), String ("https://audio.dev/")); + expectEquals (url.getParentURL().getChildURL ("x").toString (false), String ("https://audio.dev/foo/x")); + expectEquals (url.getParentURL().getParentURL().getParentURL().getChildURL ("x").toString (false), String ("https://audio.dev/x")); + } + + { + URL url ("https://audio.dev/foo/bar"); + expectEquals (url.toString (false), String ("https://audio.dev/foo/bar")); + expectEquals (url.getChildURL ("x").toString (false), String ("https://audio.dev/foo/bar/x")); + expectEquals (url.getParentURL().toString (false), String ("https://audio.dev/foo")); + expectEquals (url.getParentURL().getParentURL().toString (false), String ("https://audio.dev/")); + expectEquals (url.getParentURL().getParentURL().getParentURL().toString (false), String ("https://audio.dev/")); + expectEquals (url.getParentURL().getChildURL ("x").toString (false), String ("https://audio.dev/foo/x")); + expectEquals (url.getParentURL().getParentURL().getParentURL().getChildURL ("x").toString (false), String ("https://audio.dev/x")); + } } }; diff --git a/modules/juce_core/network/juce_URL.cpp b/modules/juce_core/network/juce_URL.cpp index 72d2536ecd..26169129a5 100644 --- a/modules/juce_core/network/juce_URL.cpp +++ b/modules/juce_core/network/juce_URL.cpp @@ -135,7 +135,7 @@ URL::DownloadTask::DownloadTask() {} URL::DownloadTask::~DownloadTask() {} //============================================================================== -URL::URL() noexcept {} +URL::URL() {} URL::URL (const String& u) : url (u) { @@ -171,7 +171,6 @@ URL::URL (File localFile) url = "/" + url; } - url = "file://" + url; jassert (isWellFormed()); @@ -287,6 +286,20 @@ namespace URLHelpers else path += suffix; } + + static String removeLastPathSection (const String& url) + { + auto startOfPath = findStartOfPath (url); + auto lastSlash = url.lastIndexOfChar ('/'); + + if (lastSlash > startOfPath && lastSlash == url.length() - 1) + return removeLastPathSection (url.dropLastCharacters (1)); + + if (lastSlash < 0) + return url; + + return url.substring (0, std::max (startOfPath, lastSlash)); + } } void URL::addParameter (const String& name, const String& value) @@ -344,10 +357,10 @@ String URL::getScheme() const return url.substring (0, URLHelpers::findEndOfScheme (url) - 1); } -#ifndef JUCE_ANDROID +#if ! JUCE_ANDROID bool URL::isLocalFile() const { - return (getScheme() == "file"); + return getScheme() == "file"; } File URL::getLocalFile() const @@ -371,7 +384,7 @@ File URL::fileFromFileSchemeURL (const URL& fileURL) auto path = removeEscapeChars (fileURL.getDomainInternal (true)).replace ("+", "%2B"); - #ifdef JUCE_WINDOWS + #if JUCE_WINDOWS bool isUncPath = (! fileURL.url.startsWith ("file:///")); #else path = File::getSeparatorString() + path; @@ -382,7 +395,7 @@ File URL::fileFromFileSchemeURL (const URL& fileURL) for (auto urlElement : urlElements) path += File::getSeparatorString() + removeEscapeChars (urlElement.replace ("+", "%2B")); - #ifdef JUCE_WINDOWS + #if JUCE_WINDOWS if (isUncPath) path = "\\\\" + path; #endif @@ -406,10 +419,10 @@ URL URL::withNewDomainAndPath (const String& newURL) const URL URL::withNewSubPath (const String& newPath) const { - const int startOfPath = URLHelpers::findStartOfPath (url); - URL u (*this); + auto startOfPath = URLHelpers::findStartOfPath (url); + if (startOfPath > 0) u.url = url.substring (0, startOfPath); @@ -417,6 +430,13 @@ URL URL::withNewSubPath (const String& newPath) const return u; } +URL URL::getParentURL() const +{ + URL u (*this); + u.url = URLHelpers::removeLastPathSection (u.url); + return u; +} + URL URL::getChildURL (const String& subPath) const { URL u (*this); @@ -482,18 +502,15 @@ void URL::createHeadersAndPostData (String& headers, MemoryBlock& postDataToWrit //============================================================================== bool URL::isProbablyAWebsiteURL (const String& possibleURL) { - static const char* validProtocols[] = { "http:", "ftp:", "https:" }; - - for (auto* protocol : validProtocols) + for (auto* protocol : { "http:", "https:", "ftp:" }) if (possibleURL.startsWithIgnoreCase (protocol)) return true; - if (possibleURL.containsChar ('@') - || possibleURL.containsChar (' ')) + if (possibleURL.containsChar ('@') || possibleURL.containsChar (' ')) return false; - const String topLevelDomain (possibleURL.upToFirstOccurrenceOf ("/", false, false) - .fromLastOccurrenceOf (".", false, false)); + auto topLevelDomain = possibleURL.upToFirstOccurrenceOf ("/", false, false) + .fromLastOccurrenceOf (".", false, false); return topLevelDomain.isNotEmpty() && topLevelDomain.length() <= 3; } @@ -520,8 +537,7 @@ String URL::getDomainInternal (bool ignorePort) const } #if JUCE_IOS -URL::Bookmark::Bookmark (void* bookmarkToUse) - : data (bookmarkToUse) +URL::Bookmark::Bookmark (void* bookmarkToUse) : data (bookmarkToUse) { } @@ -612,12 +628,10 @@ private: return urlToUse.getLocalFile(); } - else - { - auto desc = [error localizedDescription]; - ignoreUnused (desc); - jassertfalse; - } + + auto desc = [error localizedDescription]; + ignoreUnused (desc); + jassertfalse; } return urlToUse.getLocalFile(); @@ -659,10 +673,9 @@ InputStream* URL::createInputStream (bool usePostCommand, #else return getLocalFile().createInputStream(); #endif - } - std::unique_ptr wi (new WebInputStream (*this, usePostCommand)); + auto wi = std::make_unique (*this, usePostCommand); struct ProgressCallbackCaller : public WebInputStream::Listener { diff --git a/modules/juce_core/network/juce_URL.h b/modules/juce_core/network/juce_URL.h index 8660339514..6e60882222 100644 --- a/modules/juce_core/network/juce_URL.h +++ b/modules/juce_core/network/juce_URL.h @@ -39,7 +39,7 @@ class JUCE_API URL public: //============================================================================== /** Creates an empty URL. */ - URL() noexcept; + URL(); /** Creates a URL from a string. This will parse any embedded parameters after a '?' character and store them @@ -148,6 +148,11 @@ public: */ URL withNewSubPath (const String& newPath) const; + /** Attempts to return a URL which is the parent folder containing this URL. + If there isn't a parent, this method will just return a copy of this URL. + */ + URL getParentURL() const; + /** Returns a new URL that refers to a sub-path relative to this one. E.g. if the URL is "http://www.xyz.com/foo" and you call this with "bar", it'll return "http://www.xyz.com/foo/bar". Note that there's no way for @@ -263,7 +268,7 @@ public: URL withPOSTData (const MemoryBlock& postData) const; /** Returns the data that was set using withPOSTData(). */ - String getPostData() const noexcept { return postData.toString(); } + String getPostData() const { return postData.toString(); } /** Returns the data that was set using withPOSTData() as MemoryBlock. */ const MemoryBlock& getPostDataAsMemoryBlock() const noexcept { return postData; } @@ -338,12 +343,12 @@ public: InputStream* createInputStream (bool doPostLikeRequest, OpenStreamProgressCallback* progressCallback = nullptr, void* progressCallbackContext = nullptr, - String extraHeaders = String(), + String extraHeaders = {}, int connectionTimeOutMs = 0, StringPairArray* responseHeaders = nullptr, int* statusCode = nullptr, int numRedirectsToFollow = 5, - String httpRequestCmd = String()) const; + String httpRequestCmd = {}) const; /** Attempts to open an output stream to a URL for writing