30 size_t bufferSizeToUse,
33 :
Thread (
"DownloadTask thread"),
34 fileStream (std::move (outputStreamToUse)),
35 stream (std::move (streamToUse)),
36 bufferSize (bufferSizeToUse),
38 listener (listenerToUse)
40 jassert (fileStream !=
nullptr);
43 targetLocation = fileStream->getFile();
44 contentLength = stream->getTotalLength();
45 httpCode = stream->getStatusCode();
62 if (listener !=
nullptr)
63 listener->
progress (
this, downloaded, contentLength);
65 auto max = (
int)
jmin ((
int64) bufferSize, contentLength < 0 ? std::numeric_limits<int64>::max()
66 :
static_cast<int64> (contentLength - downloaded));
68 auto actual = stream->read (buffer.
get(), max);
73 if (! fileStream->write (buffer.
get(),
static_cast<size_t> (actual)))
81 if (downloaded == contentLength)
90 if (contentLength > 0 && downloaded < contentLength)
102 const size_t bufferSize;
113 const File& targetFileToUse,
116 const size_t bufferSize = 0x8000;
122 stream->withExtraHeaders (options.extraHeaders);
124 if (stream->connect (
nullptr))
134URL::DownloadTask::DownloadTask() {}
147 if (localFile ==
File())
154 while (! localFile.
isRoot())
174 url =
"file://" + url;
203 else if (nextAmp > 0 && equalsPos < nextAmp)
206 equalsPos < 0 ? String() :
removeEscapeChars (url.substring (equalsPos + 1, nextAmp)));
217URL::URL (
const String& u,
int) : url (u) {}
226 return url == other.url
227 && postData == other.postData
228 && parameterNames == other.parameterNames
229 && parameterValues == other.parameterValues
230 && filesToUpload == other.filesToUpload;
233bool URL::operator!= (
const URL& other)
const
240 static String getMangledParameters (
const URL& url)
242 jassert (url.getParameterNames().size() == url.getParameterValues().size());
245 for (
int i = 0; i < url.getParameterNames().size(); ++i)
250 auto val = url.getParameterValues()[i];
254 if (val.isNotEmpty())
261 static int findEndOfScheme (
const String& url)
266 || url[i] ==
'+' || url[i] ==
'-' || url[i] ==
'.')
269 return url.substring (i).startsWith (
"://") ? i + 1 : 0;
272 static int findStartOfNetLocation (
const String& url)
274 int start = findEndOfScheme (url);
276 while (url[start] ==
'/')
282 static int findStartOfPath (
const String& url)
284 return url.indexOfChar (findStartOfNetLocation (url),
'/') + 1;
287 static void concatenatePaths (String& path,
const String& suffix)
289 if (! path.endsWithChar (
'/'))
292 if (suffix.startsWithChar (
'/'))
293 path += suffix.substring (1);
298 static String removeLastPathSection (
const String& url)
300 auto startOfPath = findStartOfPath (url);
301 auto lastSlash = url.lastIndexOfChar (
'/');
303 if (lastSlash > startOfPath && lastSlash == url.length() - 1)
304 return removeLastPathSection (url.dropLastCharacters (1));
309 return url.substring (0,
std::max (startOfPath, lastSlash));
313void URL::addParameter (
const String& name,
const String& value)
315 parameterNames.
add (name);
316 parameterValues.
add (value);
321 if (includeGetParameters)
329 return url.isEmpty();
335 return url.isNotEmpty();
340 return getDomainInternal (
false);
345 auto startOfPath = URLHelpers::findStartOfPath (url);
346 auto subPath = startOfPath <= 0 ?
String()
347 : url.substring (startOfPath);
349 if (includeGetParameters)
359 if (parameterNames.
size() > 0)
360 result +=
"?" + URLHelpers::getMangledParameters (*
this);
378 return url.
substring (0, URLHelpers::findEndOfScheme (url) - 1);
389 return fileFromFileSchemeURL (*
this);
398URL::ParameterHandling URL::toHandling (
bool usePostData)
400 return usePostData ? ParameterHandling::inPostData : ParameterHandling::inAddress;
403File URL::fileFromFileSchemeURL (
const URL& fileURL)
405 if (! fileURL.isLocalFile())
414 bool isUncPath = (! fileURL.url.startsWith (
"file:///"));
421 for (
auto urlElement : urlElements)
426 path =
"\\\\" + path;
434 auto colonPos = url.
indexOfChar (URLHelpers::findStartOfNetLocation (url),
':');
436 return colonPos > 0 ? url.substring (colonPos + 1).getIntValue() : 0;
450 auto startOfPath = URLHelpers::findStartOfPath (url);
455 URLHelpers::concatenatePaths (u.url, newPath);
462 u.url = URLHelpers::removeLastPathSection (u.url);
469 URLHelpers::concatenatePaths (u.url, subPath);
473bool URL::hasBodyDataToSend()
const
475 return filesToUpload.
size() > 0 || ! postData.
isEmpty();
478void URL::createHeadersAndPostData (String& headers,
479 MemoryBlock& postDataToWrite,
480 bool addParametersToBody)
const
482 MemoryOutputStream data (postDataToWrite,
false);
484 if (filesToUpload.
size() > 0)
491 headers <<
"Content-Type: multipart/form-data; boundary=" << boundary <<
"\r\n";
493 data <<
"--" << boundary;
495 for (
int i = 0; i < parameterNames.
size(); ++i)
497 data <<
"\r\nContent-Disposition: form-data; name=\"" << parameterNames[i]
498 <<
"\"\r\n\r\n" << parameterValues[i]
499 <<
"\r\n--" << boundary;
502 for (
auto* f : filesToUpload)
504 data <<
"\r\nContent-Disposition: form-data; name=\"" << f->parameterName
505 <<
"\"; filename=\"" << f->filename <<
"\"\r\n";
507 if (f->mimeType.isNotEmpty())
508 data <<
"Content-Type: " << f->mimeType <<
"\r\n";
510 data <<
"Content-Transfer-Encoding: binary\r\n\r\n";
512 if (f->data !=
nullptr)
517 data <<
"\r\n--" << boundary;
524 if (addParametersToBody)
525 data << URLHelpers::getMangledParameters (*
this);
530 if (! headers.containsIgnoreCase (
"Content-Type"))
531 headers <<
"Content-Type: application/x-www-form-urlencoded\r\n";
533 headers <<
"Content-length: " << (
int)
data.getDataSize() <<
"\r\n";
540 for (
auto* protocol : {
"http:",
"https:",
"ftp:" })
550 return topLevelDomain.
isNotEmpty() && topLevelDomain.length() <= 3;
555 auto atSign = possibleEmailAddress.
indexOfChar (
'@');
562String URL::getDomainInternal (
bool ignorePort)
const
564 auto start = URLHelpers::findStartOfNetLocation (url);
565 auto end1 = url.indexOfChar (start,
'/');
566 auto end2 = ignorePort ? -1 : url.indexOfChar (start,
':');
568 auto end = (end1 < 0 && end2 < 0) ? std::numeric_limits<int>::max()
569 : ((end1 < 0 || end2 < 0) ?
jmax (end1, end2)
570 :
jmin (end1, end2));
571 return url.substring (start,
end);
575URL::Bookmark::Bookmark (
void* bookmarkToUse) : data (bookmarkToUse)
579URL::Bookmark::~Bookmark()
581 [(NSData*) data release];
584void setURLBookmark (URL& u,
void* bookmark)
586 u.bookmark =
new URL::Bookmark (bookmark);
589void* getURLBookmark (URL& u)
591 if (u.bookmark.get() ==
nullptr)
594 return u.bookmark.get()->data;
597template <
typename Stream>
struct iOSFileStreamWrapperFlush {
static void flush (Stream*) {} };
598template <>
struct iOSFileStreamWrapperFlush<FileOutputStream> {
static void flush (OutputStream* o) { o->flush(); } };
600template <
typename Stream>
601class iOSFileStreamWrapper final :
public Stream
604 iOSFileStreamWrapper (URL& urlToUse)
605 : Stream (getLocalFileAccess (urlToUse)),
609 ~iOSFileStreamWrapper()
611 iOSFileStreamWrapperFlush<Stream>::flush (
this);
613 if (NSData* bookmark = (NSData*) getURLBookmark (url))
615 BOOL isBookmarkStale =
false;
616 NSError* error = nil;
618 auto nsURL = [NSURL URLByResolvingBookmarkData: bookmark
621 bookmarkDataIsStale: &isBookmarkStale
627 updateStaleBookmark (nsURL, url);
629 [nsURL stopAccessingSecurityScopedResource];
633 [[maybe_unused]]
auto desc = [error localizedDescription];
641 bool securityAccessSucceeded =
false;
643 File getLocalFileAccess (URL& urlToUse)
645 if (NSData* bookmark = (NSData*) getURLBookmark (urlToUse))
647 BOOL isBookmarkStale =
false;
648 NSError* error = nil;
650 auto nsURL = [NSURL URLByResolvingBookmarkData: bookmark
653 bookmarkDataIsStale: &isBookmarkStale
658 securityAccessSucceeded = [nsURL startAccessingSecurityScopedResource];
661 updateStaleBookmark (nsURL, urlToUse);
663 return urlToUse.getLocalFile();
666 [[maybe_unused]]
auto desc = [error localizedDescription];
670 return urlToUse.getLocalFile();
673 void updateStaleBookmark (NSURL* nsURL, URL& juceUrl)
675 NSError* error = nil;
677 NSData* bookmark = [nsURL bookmarkDataWithOptions: NSURLBookmarkCreationSuitableForBookmarkFile
678 includingResourceValuesForKeys: nil
683 setURLBookmark (juceUrl, (
void*) bookmark);
690template <
typename Member,
typename Item>
691static URL::InputStreamOptions with (URL::InputStreamOptions options, Member&& member, Item&& item)
701 return with (*
this, &InputStreamOptions::progressCallback, std::move (cb));
706 return with (*
this, &InputStreamOptions::extraHeaders, headers);
711 return with (*
this, &InputStreamOptions::connectionTimeOutMs, timeout);
716 return with (*
this, &InputStreamOptions::responseHeaders, headers);
721 return with (*
this, &InputStreamOptions::statusCode, status);
726 return with (*
this, &InputStreamOptions::numRedirectsToFollow, numRedirects);
731 return with (*
this, &InputStreamOptions::httpRequestCmd, cmd);
747 auto webInputStream = [&]
749 const auto usePost = options.getParameterHandling() == ParameterHandling::inPostData;
752 auto extraHeaders = options.getExtraHeaders();
754 if (extraHeaders.isNotEmpty())
755 stream->withExtraHeaders (extraHeaders);
757 auto timeout = options.getConnectionTimeoutMs();
760 stream->withConnectionTimeout (timeout);
762 auto requestCmd = options.getHttpRequestCmd();
764 if (requestCmd.isNotEmpty())
765 stream->withCustomRequestCommand (requestCmd);
767 stream->withNumRedirectsToFollow (options.getNumRedirectsToFollow());
774 ProgressCallbackCaller (
std::function<
bool (
int,
int)> progressCallbackToUse)
775 : callback (std::move (progressCallbackToUse))
779 bool postDataSendProgress (
WebInputStream&,
int bytesSent,
int totalBytes)
override
781 return callback (bytesSent, totalBytes);
789 if (
auto progressCallback = options.getProgressCallback())
795 auto success = webInputStream->connect (callbackCaller.get());
797 if (
auto* status = options.getStatusCode())
798 *status = webInputStream->getStatusCode();
800 if (
auto* responseHeaders = options.getResponseHeaders())
801 *responseHeaders = webInputStream->getResponseHeaders();
803 if (! success || webInputStream->isError())
807 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE (
"-Wredundant-move")
808 return std::move (webInputStream);
809 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
840 in->readIntoMemoryBlock (destData);
853 return in->readEntireStreamAsString();
865 const String& parameterValue)
const
868 u.addParameter (parameterName, parameterValue);
876 for (
int i = 0; i < parametersToAdd.
size(); ++i)
877 u.addParameter (parametersToAdd.
getAllKeys()[i],
887 u.anchor = anchorToAdd;
899 u.postData = newPostData;
903URL::Upload::Upload (
const String& param,
const String& name,
905 : parameterName (param), filename (name), mimeType (mime), file (f), data (mb)
907 jassert (mimeType.isNotEmpty());
910URL URL::withUpload (Upload*
const f)
const
914 for (
int i = u.filesToUpload.size(); --i >= 0;)
915 if (u.filesToUpload.getObjectPointerUnchecked (i)->parameterName == f->parameterName)
916 u.filesToUpload.remove (i);
918 u.filesToUpload.add (f);
923 const String& mimeType)
const
925 return withUpload (
new Upload (parameterName, fileToUpload.
getFileName(),
926 mimeType, fileToUpload,
nullptr));
932 return withUpload (
new Upload (parameterName, filename, mimeType,
File(),
941 if (! result.containsChar (
'%'))
946 Array<char> utf8 (result.toRawUTF8(), (
int) result.getNumBytesAsUTF8());
948 for (
int i = 0; i < utf8.
size(); ++i)
955 if (hexDigit1 >= 0 && hexDigit2 >= 0)
957 utf8.
set (i, (
char) ((hexDigit1 << 4) + hexDigit2));
968 String legalChars (isParameter ?
"_-.~"
971 if (roundBracketsAreLegal)
976 for (
int i = 0; i < utf8.
size(); ++i)
984 utf8.
insert (++i,
"0123456789ABCDEF" [((
uint8) c) >> 4]);
985 utf8.
insert (++i,
"0123456789ABCDEF" [c & 15]);
997 if (u.containsChar (
'@') && ! u.containsChar (
':'))
1005 OpenStreamProgressCallback* cb,
1011 int numRedirectsToFollow,
1012 String httpRequestCmd)
const
1017 callback = [context, cb] (
int sent,
int total) {
return cb (context, sent, total); };
1020 .withProgressCallback (std::move (callback))
1021 .withExtraHeaders (headers)
1022 .withConnectionTimeoutMs (timeOutMs)
1023 .withResponseHeaders (responseHeaders)
1024 .withStatusCode (statusCode)
1025 .withNumRedirectsToFollow (numRedirectsToFollow)
1026 .withHttpRequestCmd (httpRequestCmd));
1032 bool usePostCommand)
1035 .withListener (listener)
1036 .withUsePost (usePostCommand);
static AndroidDocument fromDocument(const URL &documentUrl)
Create an AndroidDocument representing a single document.
std::unique_ptr< OutputStream > createOutputStream() const
Creates a stream for writing to this document.
Holds a resizable array of primitive or copy-by-value objects.
ElementType getUnchecked(int index) const
Returns one of the elements in the array, without checking the index passed in.
int size() const noexcept
Returns the current number of elements in the array.
void removeRange(int startIndex, int numberToRemove)
Removes a range of elements from the array.
void insert(int indexToInsertAt, ParameterType newElement)
Inserts a new element into the array at a given position.
ElementType * getRawDataPointer() noexcept
Returns a pointer to the actual array data.
void set(int indexToChange, ParameterType newValue)
Replaces an element with a new value.
static int getHexDigitValue(juce_wchar digit) noexcept
Returns 0 to 16 for '0' to 'F", or -1 for characters that aren't a legal hex digit.
static bool isLetterOrDigit(char character) noexcept
Checks whether a character is alphabetic or numeric.
Represents a local file or directory.
std::unique_ptr< FileOutputStream > createOutputStream(size_t bufferSize=0x8000) const
Creates a stream to write to this file.
static StringRef getSeparatorString()
The system-specific file separator character, as a string.
const String & getFullPathName() const noexcept
Returns the complete, absolute path of this file.
String getFileName() const
Returns the last section of the pathname.
bool isRoot() const
Checks whether the path of this file represents the root of a file system, irrespective of its existe...
File getParentDirectory() const
Returns the directory that contains this file or directory.
std::unique_ptr< FileInputStream > createInputStream() const
Creates a stream to read from this file.
bool deleteFile() const
Deletes a file.
Very simple container class to hold a pointer to some data on the heap.
ElementType * get() const noexcept
Returns a raw pointer to the allocated data.
A class to hold a resizable block of raw data.
bool isEmpty() const noexcept
Returns true if the memory block has zero size.
static bool JUCE_CALLTYPE openDocument(const String &documentURL, const String ¶meters)
Tries to launch the OS's default reader application for a given file or URL.
static Random & getSystemRandom() noexcept
The overhead of creating a new Random object is fairly small, but if you want to avoid it,...
int size() const noexcept
Returns the current number of objects in the array.
static StringArray fromTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
Returns an array containing the tokens in a given string.
int size() const noexcept
Returns the number of strings in the array.
void add(String stringToAdd)
Appends a string at the end of the array.
A container for holding a set of strings which are keyed by another string.
const StringArray & getAllValues() const noexcept
Returns a list of all values in the array.
int size() const noexcept
Returns the number of strings in the array.
const StringArray & getAllKeys() const noexcept
Returns a list of all keys in the array.
int indexOfChar(juce_wchar characterToLookFor) const noexcept
Searches for a character inside this string.
String upToFirstOccurrenceOf(StringRef substringToEndWith, bool includeSubStringInResult, bool ignoreCase) const
Returns the start of this string, up to the first occurrence of a substring.
bool endsWithChar(juce_wchar character) const noexcept
Tests whether the string ends with a particular character.
const char * toRawUTF8() const
Returns a pointer to a UTF-8 version of this string.
bool startsWithChar(juce_wchar character) const noexcept
Tests whether the string begins with a particular character.
bool startsWith(StringRef text) const noexcept
Tests whether the string begins with another string.
bool containsChar(juce_wchar character) const noexcept
Tests whether the string contains a particular character.
bool startsWithIgnoreCase(StringRef text) const noexcept
Tests whether the string begins with another string.
size_t getNumBytesAsUTF8() const noexcept
Returns the number of bytes required to represent this string as UTF8.
static String toHexString(IntegerType number)
Returns a string representing this numeric value in hexadecimal.
int lastIndexOfChar(juce_wchar character) const noexcept
Searches for a character inside this string (working backwards from the end of the string).
String replace(StringRef stringToReplace, StringRef stringToInsertInstead, bool ignoreCase=false) const
Replaces all occurrences of a substring with another string.
String replaceCharacter(juce_wchar characterToReplace, juce_wchar characterToInsertInstead) const
Returns a string with all occurrences of a character replaced with a different one.
String substring(int startIndex, int endIndex) const
Returns a subsection of the string.
String fromLastOccurrenceOf(StringRef substringToFind, bool includeSubStringInResult, bool ignoreCase) const
Returns a section of the string starting from the last occurrence of a given substring.
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
Creates a String from a UTF-8 encoded buffer.
bool isNotEmpty() const noexcept
Returns true if the string contains at least one character.
String fromFirstOccurrenceOf(StringRef substringToStartFrom, bool includeSubStringInResult, bool ignoreCase) const
Returns a section of the string starting from a given substring.
bool waitForThreadToExit(int timeOutMilliseconds) const
Waits for the thread to stop.
bool startThread()
Attempts to start a new thread with default ('Priority::normal') priority.
bool threadShouldExit() const
Checks whether the thread has been told to stop running.
void signalThreadShouldExit()
Sets a flag to tell the thread it should stop.
Holds options that can be specified when starting a new download with downloadToFile().
auto withExtraHeaders(String value) const
Specifies headers to add to the request.
Represents a download task.
virtual ~DownloadTask()
Releases the resources of the download task, unregisters the listener and cancels the download if nec...
Represents a URL and has a bunch of useful functions to manipulate it.
URL withParameter(const String ¶meterName, const String ¶meterValue) const
Returns a copy of this URL, with a GET or POST parameter added to the end.
static URL createWithoutParsing(const String &url)
Returns a URL without attempting to remove any embedded parameters from the string.
File getLocalFile() const
Returns the file path of the local file to which this URL refers to.
bool isWellFormed() const
True if it seems to be valid.
bool readEntireBinaryStream(MemoryBlock &destData, bool usePostCommand=false) const
Tries to download the entire contents of this URL into a binary data block.
int getPort() const
Attempts to read a port number from the URL.
URL withDataToUpload(const String ¶meterName, const String &filename, const MemoryBlock &fileContentToUpload, const String &mimeType) const
Returns a copy of this URL, with a file-upload type parameter added to it.
String getFileName() const
Returns the file name.
URL getChildURL(const String &subPath) const
Returns a new URL that refers to a sub-path relative to this one.
static String removeEscapeChars(const String &stringToRemoveEscapeCharsFrom)
Replaces any escape character sequences in a string with their original character codes.
String getAnchorString() const
If any anchor is set, returns URL-encoded anchor, including the "#" prefix.
static String addEscapeChars(const String &stringToAddEscapeCharsTo, bool isParameter, bool roundBracketsAreLegal=true)
Adds escape sequences to a string to encode any characters that aren't legal in a URL.
URL withAnchor(const String &anchor) const
Returns a copy of this URL, with an anchor added to the end of the URL.
String toString(bool includeGetParameters) const
Returns a string version of the URL.
std::unique_ptr< OutputStream > createOutputStream() const
Attempts to open an output stream to a URL for writing.
String getSubPath(bool includeGetParameters=false) const
Returns the path part of the URL.
URL getParentURL() const
Attempts to return a URL which is the parent folder containing this URL.
String getQueryString() const
If any parameters are set, returns these URL-encoded, including the "?" prefix.
URL withNewSubPath(const String &newPath) const
Returns a new version of this URL with a different sub-path.
static bool isProbablyAnEmailAddress(const String &possibleEmailAddress)
Takes a guess as to whether a string might be a valid email address.
URL withNewDomainAndPath(const String &newFullPath) const
Returns a new version of this URL with a different domain and path.
String readEntireTextStream(bool usePostCommand=false) const
Tries to download the entire contents of this URL as a string.
bool isEmpty() const noexcept
Returns true if the URL is an empty string.
static bool isProbablyAWebsiteURL(const String &possibleURL)
Takes a guess as to whether a string might be a valid website address.
std::unique_ptr< InputStream > createInputStream(const InputStreamOptions &options) const
Attempts to open a stream that can read from this URL.
std::unique_ptr< DownloadTask > downloadToFile(const File &targetLocation, String extraHeaders=String(), DownloadTaskListener *listener=nullptr, bool usePostCommand=false)
This function is replaced by a new overload accepting a DownloadTaskOptions argument.
String getDomain() const
Returns just the domain part of the URL.
bool isLocalFile() const
Returns true if this URL refers to a local file.
URL withFileToUpload(const String ¶meterName, const File &fileToUpload, const String &mimeType) const
Returns a copy of this URL, with a file-upload type parameter added to it.
URL withPOSTData(const String &postData) const
Returns a copy of this URL, with a block of data to send as the POST data.
URL withParameters(const StringPairArray ¶metersToAdd) const
Returns a copy of this URL, with a set of GET or POST parameters added.
std::unique_ptr< XmlElement > readEntireXmlStream(bool usePostCommand=false) const
Tries to download the entire contents of this URL and parse it as XML.
String getScheme() const
Returns the scheme of the URL.
bool operator==(const URL &) const
Compares two URLs.
bool launchInDefaultBrowser() const
Tries to launch the system's default browser to open the URL.
URL()
Creates an empty URL.
wchar_t juce_wchar
A platform-independent 32-bit unicode character type.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
RangedDirectoryIterator end(const RangedDirectoryIterator &)
Returns a default-constructed sentinel value.
std::unique_ptr< XmlElement > parseXML(const String &textToParse)
Attempts to parse some XML text, returning a new XmlElement if it was valid.
unsigned char uint8
A platform-independent 8-bit unsigned integer type.
long long int64
A platform-independent 64-bit integer type.
void run() override
Must be implemented to perform the thread's actual code.
Used to receive callbacks for download progress.
virtual void finished(DownloadTask *task, bool success)=0
Called when the download has finished.
virtual void progress(DownloadTask *task, int64 bytesDownloaded, int64 totalLength)
Called periodically by the OS to indicate download progress.