Browse Source

Tweaked URL::addEscapeChars() to make its character substitutions more compliant with RFC3986

tags/2021-05-28
jules 7 years ago
parent
commit
23cdad6a80
2 changed files with 38 additions and 52 deletions
  1. +26
    -28
      modules/juce_core/network/juce_URL.cpp
  2. +12
    -24
      modules/juce_core/network/juce_URL.h

+ 26
- 28
modules/juce_core/network/juce_URL.cpp View File

@@ -130,7 +130,7 @@ URL::DownloadTask* URL::DownloadTask::createFallbackDownloader (const URL& urlTo
return nullptr; return nullptr;
} }
URL::DownloadTask::DownloadTask() : contentLength (-1), downloaded (0), finished (false), error (false), httpCode (-1) {}
URL::DownloadTask::DownloadTask() {}
URL::DownloadTask::~DownloadTask() {} URL::DownloadTask::~DownloadTask() {}
//============================================================================== //==============================================================================
@@ -250,6 +250,7 @@ namespace URLHelpers
static int findStartOfNetLocation (const String& url) static int findStartOfNetLocation (const String& url)
{ {
int start = findEndOfScheme (url); int start = findEndOfScheme (url);
while (url[start] == '/') while (url[start] == '/')
++start; ++start;
@@ -305,8 +306,8 @@ String URL::getDomain() const
const int end2 = url.indexOfChar (start, ':'); const int end2 = url.indexOfChar (start, ':');
const int end = (end1 < 0 && end2 < 0) ? std::numeric_limits<int>::max() const int end = (end1 < 0 && end2 < 0) ? std::numeric_limits<int>::max()
: ((end1 < 0 || end2 < 0) ? jmax (end1, end2)
: jmin (end1, end2));
: ((end1 < 0 || end2 < 0) ? jmax (end1, end2)
: jmin (end1, end2));
return url.substring (start, end); return url.substring (start, end);
} }
@@ -325,7 +326,7 @@ String URL::getScheme() const
int URL::getPort() const int URL::getPort() const
{ {
const int colonPos = url.indexOfChar (URLHelpers::findStartOfNetLocation (url), ':');
auto colonPos = url.indexOfChar (URLHelpers::findStartOfNetLocation (url), ':');
return colonPos > 0 ? url.substring (colonPos + 1).getIntValue() : 0; return colonPos > 0 ? url.substring (colonPos + 1).getIntValue() : 0;
} }
@@ -366,7 +367,7 @@ void URL::createHeadersAndPostData (String& headers, MemoryBlock& postDataToWrit
// (this doesn't currently support mixing custom post-data with uploads..) // (this doesn't currently support mixing custom post-data with uploads..)
jassert (postData.getSize() == 0); jassert (postData.getSize() == 0);
const String boundary (String::toHexString (Random::getSystemRandom().nextInt64()));
auto boundary = String::toHexString (Random::getSystemRandom().nextInt64());
headers << "Content-Type: multipart/form-data; boundary=" << boundary << "\r\n"; headers << "Content-Type: multipart/form-data; boundary=" << boundary << "\r\n";
@@ -379,22 +380,20 @@ void URL::createHeadersAndPostData (String& headers, MemoryBlock& postDataToWrit
<< "\r\n--" << boundary; << "\r\n--" << boundary;
} }
for (int i = 0; i < filesToUpload.size(); ++i)
for (auto* f : filesToUpload)
{ {
const Upload& f = *filesToUpload.getObjectPointerUnchecked(i);
data << "\r\nContent-Disposition: form-data; name=\"" << f.parameterName
<< "\"; filename=\"" << f.filename << "\"\r\n";
data << "\r\nContent-Disposition: form-data; name=\"" << f->parameterName
<< "\"; filename=\"" << f->filename << "\"\r\n";
if (f.mimeType.isNotEmpty())
data << "Content-Type: " << f.mimeType << "\r\n";
if (f->mimeType.isNotEmpty())
data << "Content-Type: " << f->mimeType << "\r\n";
data << "Content-Transfer-Encoding: binary\r\n\r\n"; data << "Content-Transfer-Encoding: binary\r\n\r\n";
if (f.data != nullptr)
data << *f.data;
if (f->data != nullptr)
data << *f->data;
else else
data << f.file;
data << f->file;
data << "\r\n--" << boundary; data << "\r\n--" << boundary;
} }
@@ -419,8 +418,8 @@ bool URL::isProbablyAWebsiteURL (const String& possibleURL)
{ {
static const char* validProtocols[] = { "http:", "ftp:", "https:" }; static const char* validProtocols[] = { "http:", "ftp:", "https:" };
for (int i = 0; i < numElementsInArray (validProtocols); ++i)
if (possibleURL.startsWithIgnoreCase (validProtocols[i]))
for (auto* protocol : validProtocols)
if (possibleURL.startsWithIgnoreCase (protocol))
return true; return true;
if (possibleURL.containsChar ('@') if (possibleURL.containsChar ('@')
@@ -435,7 +434,7 @@ bool URL::isProbablyAWebsiteURL (const String& possibleURL)
bool URL::isProbablyAnEmailAddress (const String& possibleEmailAddress) bool URL::isProbablyAnEmailAddress (const String& possibleEmailAddress)
{ {
const int atSign = possibleEmailAddress.indexOfChar ('@');
auto atSign = possibleEmailAddress.indexOfChar ('@');
return atSign > 0 return atSign > 0
&& possibleEmailAddress.lastIndexOfChar ('.') > (atSign + 1) && possibleEmailAddress.lastIndexOfChar ('.') > (atSign + 1)
@@ -504,8 +503,7 @@ WebInputStream* URL::createInputStream (const bool usePostCommand,
} }
//============================================================================== //==============================================================================
bool URL::readEntireBinaryStream (MemoryBlock& destData,
const bool usePostCommand) const
bool URL::readEntireBinaryStream (MemoryBlock& destData, bool usePostCommand) const
{ {
const ScopedPointer<InputStream> in (createInputStream (usePostCommand)); const ScopedPointer<InputStream> in (createInputStream (usePostCommand));
@@ -518,7 +516,7 @@ bool URL::readEntireBinaryStream (MemoryBlock& destData,
return false; return false;
} }
String URL::readEntireTextStream (const bool usePostCommand) const
String URL::readEntireTextStream (bool usePostCommand) const
{ {
const ScopedPointer<InputStream> in (createInputStream (usePostCommand)); const ScopedPointer<InputStream> in (createInputStream (usePostCommand));
@@ -528,7 +526,7 @@ String URL::readEntireTextStream (const bool usePostCommand) const
return {}; return {};
} }
XmlElement* URL::readEntireXmlStream (const bool usePostCommand) const
XmlElement* URL::readEntireXmlStream (bool usePostCommand) const
{ {
return XmlDocument::parse (readEntireTextStream (usePostCommand)); return XmlDocument::parse (readEntireTextStream (usePostCommand));
} }
@@ -601,7 +599,7 @@ URL URL::withDataToUpload (const String& parameterName, const String& filename,
//============================================================================== //==============================================================================
String URL::removeEscapeChars (const String& s) String URL::removeEscapeChars (const String& s)
{ {
String result (s.replaceCharacter ('+', ' '));
auto result = s.replaceCharacter ('+', ' ');
if (! result.containsChar ('%')) if (! result.containsChar ('%'))
return result; return result;
@@ -628,9 +626,9 @@ String URL::removeEscapeChars (const String& s)
return String::fromUTF8 (utf8.getRawDataPointer(), utf8.size()); return String::fromUTF8 (utf8.getRawDataPointer(), utf8.size());
} }
String URL::addEscapeChars (const String& s, const bool isParameter, bool roundBracketsAreLegal)
String URL::addEscapeChars (const String& s, bool isParameter, bool roundBracketsAreLegal)
{ {
String legalChars (isParameter ? "_-.*!'"
String legalChars (isParameter ? "_-.~"
: ",$_-.*!'"); : ",$_-.*!'");
if (roundBracketsAreLegal) if (roundBracketsAreLegal)
@@ -640,7 +638,7 @@ String URL::addEscapeChars (const String& s, const bool isParameter, bool roundB
for (int i = 0; i < utf8.size(); ++i) for (int i = 0; i < utf8.size(); ++i)
{ {
const char c = utf8.getUnchecked(i);
auto c = utf8.getUnchecked(i);
if (! (CharacterFunctions::isLetterOrDigit (c) if (! (CharacterFunctions::isLetterOrDigit (c)
|| legalChars.containsChar ((juce_wchar) c))) || legalChars.containsChar ((juce_wchar) c)))
@@ -657,12 +655,12 @@ String URL::addEscapeChars (const String& s, const bool isParameter, bool roundB
//============================================================================== //==============================================================================
bool URL::launchInDefaultBrowser() const bool URL::launchInDefaultBrowser() const
{ {
String u (toString (true));
auto u = toString (true);
if (u.containsChar ('@') && ! u.containsChar (':')) if (u.containsChar ('@') && ! u.containsChar (':'))
u = "mailto:" + u; u = "mailto:" + u;
return Process::openDocument (u, String());
return Process::openDocument (u, {});
} }
} // namespace juce } // namespace juce

+ 12
- 24
modules/juce_core/network/juce_URL.h View File

@@ -47,13 +47,13 @@ public:
URL (const String& url); URL (const String& url);
/** Creates a copy of another URL. */ /** Creates a copy of another URL. */
URL (const URL& other);
URL (const URL&);
/** Destructor. */ /** Destructor. */
~URL(); ~URL();
/** Copies this URL from another one. */ /** Copies this URL from another one. */
URL& operator= (const URL& other);
URL& operator= (const URL&);
/** Compares two URLs. /** Compares two URLs.
All aspects of the URLs must be identical for them to match, including any parameters, All aspects of the URLs must be identical for them to match, including any parameters,
@@ -78,19 +78,16 @@ public:
bool isWellFormed() const; bool isWellFormed() const;
/** Returns just the domain part of the URL. /** Returns just the domain part of the URL.
E.g. for "http://www.xyz.com/foobar", this will return "www.xyz.com". E.g. for "http://www.xyz.com/foobar", this will return "www.xyz.com".
*/ */
String getDomain() const; String getDomain() const;
/** Returns the path part of the URL. /** Returns the path part of the URL.
E.g. for "http://www.xyz.com/foo/bar?x=1", this will return "foo/bar". E.g. for "http://www.xyz.com/foo/bar?x=1", this will return "foo/bar".
*/ */
String getSubPath() const; String getSubPath() const;
/** Returns the scheme of the URL. /** Returns the scheme of the URL.
E.g. for "http://www.xyz.com/foobar", this will return "http". (It won't E.g. for "http://www.xyz.com/foobar", this will return "http". (It won't
include the colon). include the colon).
*/ */
@@ -102,7 +99,6 @@ public:
int getPort() const; int getPort() const;
/** Returns a new version of this URL with a different domain and path. /** Returns a new version of this URL with a different domain and path.
E.g. if the URL is "http://www.xyz.com/foo?x=1" and you call this with E.g. if the URL is "http://www.xyz.com/foo?x=1" and you call this with
"abc.com/zzz", it'll return "http://abc.com/zzz?x=1". "abc.com/zzz", it'll return "http://abc.com/zzz?x=1".
@see withNewSubPath @see withNewSubPath
@@ -110,7 +106,6 @@ public:
URL withNewDomainAndPath (const String& newFullPath) const; URL withNewDomainAndPath (const String& newFullPath) const;
/** Returns a new version of this URL with a different sub-path. /** Returns a new version of this URL with a different sub-path.
E.g. if the URL is "http://www.xyz.com/foo?x=1" and you call this with E.g. if the URL is "http://www.xyz.com/foo?x=1" and you call this with
"bar", it'll return "http://www.xyz.com/bar?x=1". "bar", it'll return "http://www.xyz.com/bar?x=1".
@see withNewDomainAndPath @see withNewDomainAndPath
@@ -118,7 +113,6 @@ public:
URL withNewSubPath (const String& newPath) const; URL withNewSubPath (const String& newPath) const;
/** Returns a new URL that refers to a sub-path relative to this one. /** 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 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 "bar", it'll return "http://www.xyz.com/foo/bar". Note that there's no way for
this method to know whether the original URL is a file or directory, so it's this method to know whether the original URL is a file or directory, so it's
@@ -134,7 +128,6 @@ public:
/** Returns a copy of this URL, with a GET or POST parameter added to the end. /** Returns a copy of this URL, with a GET or POST parameter added to the end.
Any control characters in the value will be encoded. Any control characters in the value will be encoded.
e.g. calling "withParameter ("amount", "some fish") for the url "www.fish.com" e.g. calling "withParameter ("amount", "some fish") for the url "www.fish.com"
would produce a new url whose toString(true) method would return would produce a new url whose toString(true) method would return
"www.fish.com?amount=some+fish". "www.fish.com?amount=some+fish".
@@ -241,20 +234,17 @@ public:
//============================================================================== //==============================================================================
/** Tries to launch the system's default browser to open the URL. /** Tries to launch the system's default browser to open the URL.
Returns true if this seems to have worked. Returns true if this seems to have worked.
*/ */
bool launchInDefaultBrowser() const; bool launchInDefaultBrowser() const;
//============================================================================== //==============================================================================
/** Takes a guess as to whether a string might be a valid website address. /** Takes a guess as to whether a string might be a valid website address.
This isn't foolproof! This isn't foolproof!
*/ */
static bool isProbablyAWebsiteURL (const String& possibleURL); static bool isProbablyAWebsiteURL (const String& possibleURL);
/** Takes a guess as to whether a string might be a valid email address. /** Takes a guess as to whether a string might be a valid email address.
This isn't foolproof! This isn't foolproof!
*/ */
static bool isProbablyAnEmailAddress (const String& possibleEmailAddress); static bool isProbablyAnEmailAddress (const String& possibleEmailAddress);
@@ -319,7 +309,6 @@ public:
//============================================================================== //==============================================================================
/** Represents a download task. /** Represents a download task.
Returned by downloadToFile to allow querying and controling the download task. Returned by downloadToFile to allow querying and controling the download task.
*/ */
class DownloadTask class DownloadTask
@@ -346,34 +335,32 @@ public:
/** Returns the total length of the download task. This may return -1 if the length /** Returns the total length of the download task. This may return -1 if the length
was not returned by the server. */ was not returned by the server. */
inline int64 getTotalLength() const { return contentLength; }
int64 getTotalLength() const { return contentLength; }
/** Returns the number of bytes that have been downloaded so far. */ /** Returns the number of bytes that have been downloaded so far. */
inline int64 getLengthDownloaded() const { return downloaded; }
int64 getLengthDownloaded() const { return downloaded; }
/** Returns true if the download finished or there was an error. */ /** Returns true if the download finished or there was an error. */
inline bool isFinished() const { return finished; }
/** Returns the status code of the server's response. This will only be valid
after the download has finished.
bool isFinished() const { return finished; }
/** Returns the status code of the server's response.
This will only be valid after the download has finished.
@see isFinished @see isFinished
*/ */
inline int statusCode() const { return httpCode; }
int statusCode() const { return httpCode; }
/** Returns true if there was an error. */ /** Returns true if there was an error. */
inline bool hadError() const { return error; } inline bool hadError() const { return error; }
protected: protected:
int64 contentLength, downloaded;
bool finished, error;
int httpCode;
int64 contentLength = -1, downloaded = 0;
bool finished = false, error = false;
int httpCode = -1;
DownloadTask(); DownloadTask();
private: private:
friend class URL; friend class URL;
static DownloadTask* createFallbackDownloader (const URL&, const File&, const String&, Listener*, bool); static DownloadTask* createFallbackDownloader (const URL&, const File&, const String&, Listener*, bool);
public: public:
@@ -381,6 +368,7 @@ public:
/** internal **/ /** internal **/
static void juce_iosURLSessionNotify (const String&); static void juce_iosURLSessionNotify (const String&);
#endif #endif
private: private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DownloadTask) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DownloadTask)
}; };


Loading…
Cancel
Save