26struct FallbackDownloadTask :
public URL::DownloadTask,
29 FallbackDownloadTask (FileOutputStream* outputStreamToUse,
30 size_t bufferSizeToUse,
31 WebInputStream* streamToUse,
32 URL::DownloadTask::Listener* listenerToUse)
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();
50 ~FallbackDownloadTask()
override
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)
96 listener->finished (
this, ! error);
100 std::unique_ptr<FileOutputStream> fileStream;
101 const std::unique_ptr<WebInputStream> stream;
102 const size_t bufferSize;
103 HeapBlock<char> buffer;
104 URL::DownloadTask::Listener*
const listener;
106 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FallbackDownloadTask)
110URL::DownloadTask::Listener::~Listener() {}
119 const size_t bufferSize = 0x8000;
127 if (stream->connect (
nullptr))
134URL::DownloadTask::DownloadTask() {}
174 url =
"file://" + url;
195 else if (nextAmp > 0 && equalsPos < nextAmp)
198 equalsPos < 0 ? String() :
removeEscapeChars (url.substring (equalsPos + 1, 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);
327 return url.isNotEmpty();
332 return getDomainInternal (
false);
337 auto startOfPath = URLHelpers::findStartOfPath (url);
349 if (parameterNames.
size() > 0)
350 return "?" + URLHelpers::getMangledParameters (*
this);
357 return url.
substring (0, URLHelpers::findEndOfScheme (url) - 1);
368 return fileFromFileSchemeURL (*
this);
385 auto path =
removeEscapeChars (fileURL.getDomainInternal (
true)).replace (
"+",
"%2B");
388 bool isUncPath = (! fileURL.url.
startsWith (
"file:///"));
395 for (
auto urlElement : urlElements)
396 path += File::getSeparatorString() +
removeEscapeChars (urlElement.replace (
"+",
"%2B"));
400 path =
"\\\\" + path;
408 auto colonPos = url.indexOfChar (URLHelpers::findStartOfNetLocation (url),
':');
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);
451 if (filesToUpload.
size() > 0)
454 jassert (postData.
getSize() == 0);
458 headers <<
"Content-Type: multipart/form-data; boundary=" <<
boundary <<
"\r\n";
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]
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:" })
513 .fromLastOccurrenceOf (
".",
false,
false);
529 auto start = URLHelpers::findStartOfNetLocation (url);
530 auto end1 = url.indexOfChar (start,
'/');
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;
562template <
typename Stream>
struct iOSFileStreamWrapperFlush {
static void flush (
Stream*) {} };
563template <>
struct iOSFileStreamWrapperFlush<FileOutputStream> {
static void flush (OutputStream*
o) {
o->flush(); } };
565template <
typename Stream>
566class iOSFileStreamWrapper :
public Stream
576 iOSFileStreamWrapperFlush<Stream>::flush (
this);
711 if (statusCode !=
nullptr)
712 *statusCode =
wi->getStatusCode();
767 return in->readEntireStreamAsString();
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(),
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)
882 for (
int i = 0; i <
utf8.
size(); ++i)
903 if (u.containsChar (
'@') && ! u.containsChar (
':'))
ElementType getUnchecked(int index) const
bool isEmpty() const noexcept
int size() const noexcept
void removeRange(int startIndex, int numberToRemove)
void insert(int indexToInsertAt, ParameterType newElement)
ElementType * getRawDataPointer() noexcept
void set(int indexToChange, ParameterType newValue)
ElementType * data() noexcept
static int getHexDigitValue(juce_wchar digit) noexcept
static bool isLetterOrDigit(char character) noexcept
FileInputStream * createInputStream() const
static StringRef getSeparatorString()
size_t getSize() const noexcept
static bool JUCE_CALLTYPE openDocument(const String &documentURL, const String ¶meters)
static Random & getSystemRandom() noexcept
int size() const noexcept
static StringArray fromTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
int size() const noexcept
void add(String stringToAdd)
int indexOfChar(juce_wchar characterToLookFor) const noexcept
String upToFirstOccurrenceOf(StringRef substringToEndWith, bool includeSubStringInResult, bool ignoreCase) const
const char * toRawUTF8() const
bool containsIgnoreCase(StringRef text) const noexcept
bool startsWithChar(juce_wchar character) const noexcept
bool startsWith(StringRef text) const noexcept
size_t getNumBytesAsUTF8() const noexcept
static String toHexString(IntegerType number)
String replaceCharacter(juce_wchar characterToReplace, juce_wchar characterToInsertInstead) const
String substring(int startIndex, int endIndex) const
String fromLastOccurrenceOf(StringRef substringToFind, bool includeSubStringInResult, bool ignoreCase) const
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
String fromFirstOccurrenceOf(StringRef substringToStartFrom, bool includeSubStringInResult, bool ignoreCase) const
bool waitForThreadToExit(int timeOutMilliseconds) const
Thread(const String &threadName, size_t threadStackSize=0)
bool threadShouldExit() const
void signalThreadShouldExit()
URL withParameter(const String ¶meterName, const String ¶meterValue) const
static URL createWithoutParsing(const String &url)
File getLocalFile() const
bool isWellFormed() const
bool readEntireBinaryStream(MemoryBlock &destData, bool usePostCommand=false) const
OutputStream * createOutputStream() const
URL withDataToUpload(const String ¶meterName, const String &filename, const MemoryBlock &fileContentToUpload, const String &mimeType) const
String getFileName() const
URL getChildURL(const String &subPath) const
static String removeEscapeChars(const String &stringToRemoveEscapeCharsFrom)
static String addEscapeChars(const String &stringToAddEscapeCharsTo, bool isParameter, bool roundBracketsAreLegal=true)
String toString(bool includeGetParameters) const
String getSubPath(bool includeGetParameters=false) const
String getQueryString() const
URL withNewSubPath(const String &newPath) const
static bool isProbablyAnEmailAddress(const String &possibleEmailAddress)
URL withNewDomainAndPath(const String &newFullPath) const
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
String readEntireTextStream(bool usePostCommand=false) const
bool isEmpty() const noexcept
static bool isProbablyAWebsiteURL(const String &possibleURL)
bool(void *context, int bytesSent, int totalBytes) OpenStreamProgressCallback
URL withFileToUpload(const String ¶meterName, const File &fileToUpload, const String &mimeType) const
URL withPOSTData(const String &postData) const
URL withParameters(const StringPairArray ¶metersToAdd) const
std::unique_ptr< XmlElement > readEntireXmlStream(bool usePostCommand=false) const
bool operator==(const URL &) const
bool launchInDefaultBrowser() const
virtual void progress(URL::DownloadTask *task, int64 bytesDownloaded, int64 totalLength)