30 size_t bufferSizeToUse,
33 :
Thread (
"DownloadTask thread"),
34 fileStream (outputStreamToUse),
36 bufferSize (bufferSizeToUse),
38 listener (listenerToUse)
40 jassert (fileStream !=
nullptr);
41 jassert (stream !=
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)
100 std::unique_ptr<FileOutputStream> fileStream;
101 const std::unique_ptr<WebInputStream> stream;
102 const size_t bufferSize;
110URL::DownloadTask::Listener::~Listener() {}
114 const File& targetFileToUse,
115 const String& extraHeadersToUse,
116 Listener* listenerToUse,
119 const size_t bufferSize = 0x8000;
122 if (
auto outputStream = std::unique_ptr<FileOutputStream> (targetFileToUse.
createOutputStream (bufferSize)))
124 std::unique_ptr<WebInputStream> stream (
new WebInputStream (urlToUse, usePostRequest));
125 stream->withExtraHeaders (extraHeadersToUse);
127 if (stream->connect (
nullptr))
128 return new FallbackDownloadTask (outputStream.release(), bufferSize, stream.release(), listenerToUse);
134URL::DownloadTask::DownloadTask() {}
147 if (localFile ==
File())
154 while (! localFile.
isRoot())
174 url =
"file://" + url;
195 else if (nextAmp > 0 && equalsPos < nextAmp)
209URL::URL (
const String& u,
int) : url (u) {}
218 return url == other.url
219 && postData == other.postData
220 && parameterNames == other.parameterNames
221 && parameterValues == other.parameterValues
222 && filesToUpload == other.filesToUpload;
225bool URL::operator!= (
const URL& other)
const
232 static String getMangledParameters (
const URL& url)
234 jassert (url.getParameterNames().size() == url.getParameterValues().size());
237 for (
int i = 0; i < url.getParameterNames().size(); ++i)
242 auto val = url.getParameterValues()[i];
246 if (val.isNotEmpty())
253 static int findEndOfScheme (
const String& url)
258 || url[i] ==
'+' || url[i] ==
'-' || url[i] ==
'.')
261 return url.substring (i).startsWith (
"://") ? i + 1 : 0;
264 static int findStartOfNetLocation (
const String& url)
266 int start = findEndOfScheme (url);
268 while (url[start] ==
'/')
274 static int findStartOfPath (
const String& url)
276 return url.indexOfChar (findStartOfNetLocation (url),
'/') + 1;
279 static void concatenatePaths (String& path,
const String& suffix)
281 if (! path.endsWithChar (
'/'))
284 if (suffix.startsWithChar (
'/'))
285 path += suffix.substring (1);
290 static String removeLastPathSection (
const String& url)
292 auto startOfPath = findStartOfPath (url);
293 auto lastSlash = url.lastIndexOfChar (
'/');
295 if (lastSlash > startOfPath && lastSlash == url.length() - 1)
296 return removeLastPathSection (url.dropLastCharacters (1));
301 return url.substring (0, std::max (startOfPath, lastSlash));
305void URL::addParameter (
const String& name,
const String& value)
307 parameterNames.
add (name);
308 parameterValues.
add (value);
313 if (includeGetParameters)
321 return url.isEmpty();
327 return url.isNotEmpty();
332 return getDomainInternal (
false);
337 auto startOfPath = URLHelpers::findStartOfPath (url);
338 auto subPath = startOfPath <= 0 ?
String()
339 : url.substring (startOfPath);
341 if (includeGetParameters)
349 if (parameterNames.
size() > 0)
350 return "?" + URLHelpers::getMangledParameters (*
this);
357 return url.
substring (0, URLHelpers::findEndOfScheme (url) - 1);
368 return fileFromFileSchemeURL (*
this);
377File URL::fileFromFileSchemeURL (
const URL& fileURL)
379 if (! fileURL.isLocalFile())
388 bool isUncPath = (! fileURL.url.startsWith (
"file:///"));
395 for (
auto urlElement : urlElements)
400 path =
"\\\\" + path;
408 auto colonPos = url.indexOfChar (URLHelpers::findStartOfNetLocation (url),
':');
410 return colonPos > 0 ? url.substring (colonPos + 1).getIntValue() : 0;
424 auto startOfPath = URLHelpers::findStartOfPath (url);
429 URLHelpers::concatenatePaths (u.url, newPath);
436 u.url = URLHelpers::removeLastPathSection (u.url);
443 URLHelpers::concatenatePaths (u.url, subPath);
447void URL::createHeadersAndPostData (
String& headers,
MemoryBlock& postDataToWrite)
const
451 if (filesToUpload.
size() > 0)
454 jassert (postData.
getSize() == 0);
458 headers <<
"Content-Type: multipart/form-data; boundary=" << boundary <<
"\r\n";
460 data <<
"--" << boundary;
462 for (
int i = 0; i < parameterNames.
size(); ++i)
464 data <<
"\r\nContent-Disposition: form-data; name=\"" << parameterNames[i]
465 <<
"\"\r\n\r\n" << parameterValues[i]
466 <<
"\r\n--" << boundary;
469 for (
auto* f : filesToUpload)
471 data <<
"\r\nContent-Disposition: form-data; name=\"" << f->parameterName
472 <<
"\"; filename=\"" << f->filename <<
"\"\r\n";
474 if (f->mimeType.isNotEmpty())
475 data <<
"Content-Type: " << f->mimeType <<
"\r\n";
477 data <<
"Content-Transfer-Encoding: binary\r\n\r\n";
479 if (f->data !=
nullptr)
484 data <<
"\r\n--" << boundary;
491 data << URLHelpers::getMangledParameters (*
this)
496 headers <<
"Content-Type: application/x-www-form-urlencoded\r\n";
498 headers <<
"Content-length: " << (int) data.getDataSize() <<
"\r\n";
505 for (
auto* protocol : {
"http:",
"https:",
"ftp:" })
515 return topLevelDomain.
isNotEmpty() && topLevelDomain.length() <= 3;
520 auto atSign = possibleEmailAddress.
indexOfChar (
'@');
527String URL::getDomainInternal (
bool ignorePort)
const
529 auto start = URLHelpers::findStartOfNetLocation (url);
530 auto end1 = url.indexOfChar (start,
'/');
531 auto end2 = ignorePort ? -1 : url.indexOfChar (start,
':');
533 auto end = (end1 < 0 && end2 < 0) ? std::numeric_limits<int>::max()
534 : ((end1 < 0 || end2 < 0) ? jmax (end1, end2)
535 : jmin (end1, end2));
536 return url.substring (start, end);
540URL::Bookmark::Bookmark (
void* bookmarkToUse) : data (bookmarkToUse)
544URL::Bookmark::~Bookmark()
546 [(NSData*) data release];
549void setURLBookmark (URL& u,
void* bookmark)
551 u.bookmark =
new URL::Bookmark (bookmark);
554void* getURLBookmark (URL& u)
556 if (u.bookmark.get() ==
nullptr)
559 return u.bookmark.get()->data;
565template <
typename Stream>
570 : Stream (getLocalFileAccess (urlToUse)),
578 if (NSData* bookmark = (NSData*) getURLBookmark (url))
580 BOOL isBookmarkStale =
false;
581 NSError* error = nil;
583 auto nsURL = [NSURL URLByResolvingBookmarkData: bookmark
586 bookmarkDataIsStale: &isBookmarkStale
592 updateStaleBookmark (nsURL, url);
594 [nsURL stopAccessingSecurityScopedResource];
598 auto desc = [error localizedDescription];
607 bool securityAccessSucceeded =
false;
609 File getLocalFileAccess (
URL& urlToUse)
611 if (NSData* bookmark = (NSData*) getURLBookmark (urlToUse))
613 BOOL isBookmarkStale =
false;
614 NSError* error = nil;
616 auto nsURL = [NSURL URLByResolvingBookmarkData: bookmark
619 bookmarkDataIsStale: &isBookmarkStale
624 securityAccessSucceeded = [nsURL startAccessingSecurityScopedResource];
627 updateStaleBookmark (nsURL, urlToUse);
632 auto desc = [error localizedDescription];
640 void updateStaleBookmark (NSURL* nsURL,
URL& juceUrl)
642 NSError* error = nil;
644 NSData* bookmark = [nsURL bookmarkDataWithOptions: NSURLBookmarkCreationSuitableForBookmarkFile
645 includingResourceValuesForKeys: nil
650 setURLBookmark (juceUrl, (
void*) bookmark);
660 void* progressCallbackContext,
665 int numRedirectsToFollow,
666 String httpRequestCmd)
const
678 auto wi = std::make_unique<WebInputStream> (*
this, usePostCommand);
683 : callback (progressCallbackToUse), data (progressCallbackContextToUse)
686 bool postDataSendProgress (
WebInputStream&,
int bytesSent,
int totalBytes)
override
688 return callback (data, bytesSent, totalBytes);
695 std::unique_ptr<ProgressCallbackCaller> callbackCaller
696 (progressCallback !=
nullptr ?
new ProgressCallbackCaller (progressCallback, progressCallbackContext) :
nullptr);
699 wi->withExtraHeaders (headers);
702 wi->withConnectionTimeout (timeOutMs);
705 wi->withCustomRequestCommand (httpRequestCmd);
707 wi->withNumRedirectsToFollow (numRedirectsToFollow);
709 bool success = wi->connect (callbackCaller.get());
711 if (statusCode !=
nullptr)
712 *statusCode = wi->getStatusCode();
714 if (responseHeaders !=
nullptr)
715 *responseHeaders = wi->getResponseHeaders();
717 if (! success || wi->isError())
740 return juce_CreateContentURIOutputStream (*
this);
754 in->readIntoMemoryBlock (destData);
767 return in->readEntireStreamAsString();
779 const String& parameterValue)
const
782 u.addParameter (parameterName, parameterValue);
790 for (
int i = 0; i < parametersToAdd.
size(); ++i)
791 u.addParameter (parametersToAdd.
getAllKeys()[i],
805 u.postData = newPostData;
809URL::Upload::Upload (
const String& param,
const String& name,
811 : parameterName (param), filename (name), mimeType (mime), file (f), data (mb)
813 jassert (mimeType.isNotEmpty());
816URL URL::withUpload (Upload*
const f)
const
820 for (
int i = u.filesToUpload.size(); --i >= 0;)
821 if (u.filesToUpload.getObjectPointerUnchecked(i)->parameterName == f->parameterName)
822 u.filesToUpload.remove (i);
824 u.filesToUpload.add (f);
829 const String& mimeType)
const
831 return withUpload (
new Upload (parameterName, fileToUpload.
getFileName(),
832 mimeType, fileToUpload,
nullptr));
838 return withUpload (
new Upload (parameterName, filename, mimeType,
File(),
847 if (! result.containsChar (
'%'))
852 Array<char> utf8 (result.toRawUTF8(), (
int) result.getNumBytesAsUTF8());
854 for (
int i = 0; i < utf8.
size(); ++i)
861 if (hexDigit1 >= 0 && hexDigit2 >= 0)
863 utf8.
set (i, (
char) ((hexDigit1 << 4) + hexDigit2));
874 String legalChars (isParameter ?
"_-.~"
877 if (roundBracketsAreLegal)
882 for (
int i = 0; i < utf8.
size(); ++i)
890 utf8.
insert (++i,
"0123456789ABCDEF" [((uint8) c) >> 4]);
891 utf8.
insert (++i,
"0123456789ABCDEF" [c & 15]);
903 if (u.containsChar (
'@') && ! u.containsChar (
':'))
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.
An output stream that writes into a local file.
Represents a local file or directory.
FileOutputStream * createOutputStream(size_t bufferSize=0x8000) const
Creates a stream to write to this file.
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...
FileInputStream * createInputStream() const
Creates a stream to read from this file.
File getParentDirectory() const
Returns the directory that contains this file or directory.
bool deleteFile() const
Deletes a file.
static StringRef getSeparatorString()
The system-specific file separator character, as a string.
ElementType * get() const noexcept
Returns a raw pointer to the allocated data.
A class to hold a resizable block of raw data.
size_t getSize() const noexcept
Returns the block's current allocated size, in bytes.
Writes data to an internal memory buffer, which grows as required.
The base class for streams that write data to some kind of destination.
virtual void flush()=0
If the stream is using a buffer, this will ensure it gets written out to the destination.
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 containsIgnoreCase(StringRef text) const noexcept
Tests whether the string contains another substring.
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.
void startThread()
Starts the thread running.
bool waitForThreadToExit(int timeOutMilliseconds) const
Waits for the thread to stop.
Thread(const String &threadName, size_t threadStackSize=0)
Creates a thread.
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.
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.
OutputStream * createOutputStream() const
Attempts to open an output stream to a URL for writing.
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.
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.
String toString(bool includeGetParameters) const
Returns a string version of the URL.
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.
InputStream * createInputStream(bool doPostLikeRequest, OpenStreamProgressCallback *progressCallback=nullptr, void *progressCallbackContext=nullptr, String extraHeaders={}, int connectionTimeOutMs=0, StringPairArray *responseHeaders=nullptr, int *statusCode=nullptr, int numRedirectsToFollow=5, String httpRequestCmd={}) const
Attempts to open a stream that can read from this URL.
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.
bool(void *context, int bytesSent, int totalBytes) OpenStreamProgressCallback
This callback function can be used by the createInputStream() method.
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.
void run() override
Must be implemented to perform the thread's actual code.
Used to receive callbacks for download progress.
virtual void finished(URL::DownloadTask *task, bool success)=0
Called when the download has finished.
virtual void progress(URL::DownloadTask *task, int64 bytesDownloaded, int64 totalLength)
Called periodically by the OS to indicate download progress.