diff --git a/modules/juce_core/native/juce_android_Network.cpp b/modules/juce_core/native/juce_android_Network.cpp index dcd0abc191..cdc67e62c8 100644 --- a/modules/juce_core/native/juce_android_Network.cpp +++ b/modules/juce_core/native/juce_android_Network.cpp @@ -554,9 +554,9 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl) }; -std::unique_ptr URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost) +std::unique_ptr URL::downloadToFile (const File& targetLocation, const DownloadTaskOptions& options) { - return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, extraHeaders, listener, shouldUsePost); + return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, options); } //============================================================================== diff --git a/modules/juce_core/native/juce_curl_Network.cpp b/modules/juce_core/native/juce_curl_Network.cpp index b021103e85..bbff6ca3c3 100644 --- a/modules/juce_core/native/juce_curl_Network.cpp +++ b/modules/juce_core/native/juce_curl_Network.cpp @@ -648,9 +648,9 @@ public: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl) }; -std::unique_ptr URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost) +std::unique_ptr URL::downloadToFile (const File& targetLocation, const DownloadTaskOptions& options) { - return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, extraHeaders, listener, shouldUsePost); + return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, options); } } // namespace juce diff --git a/modules/juce_core/native/juce_linux_Network.cpp b/modules/juce_core/native/juce_linux_Network.cpp index 0e410a5b6d..7c084fccf4 100644 --- a/modules/juce_core/native/juce_linux_Network.cpp +++ b/modules/juce_core/native/juce_linux_Network.cpp @@ -607,9 +607,9 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl) }; -std::unique_ptr URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost) +std::unique_ptr URL::downloadToFile (const File& targetLocation, const DownloadTaskOptions& options) { - return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, extraHeaders, listener, shouldUsePost); + return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, options); } #endif diff --git a/modules/juce_core/native/juce_mac_Network.mm b/modules/juce_core/native/juce_mac_Network.mm index bf87acc0ee..6c7de63cc9 100644 --- a/modules/juce_core/native/juce_mac_Network.mm +++ b/modules/juce_core/native/juce_mac_Network.mm @@ -412,10 +412,8 @@ struct BackgroundDownloadTask : public URL::DownloadTask { BackgroundDownloadTask (const URL& urlToUse, const File& targetLocationToUse, - String extraHeadersToUse, - URL::DownloadTask::Listener* listenerToUse, - bool shouldUsePostRequest) - : listener (listenerToUse), + const URL::DownloadTaskOptions& options) + : listener (options.listener), uniqueIdentifier (String (urlToUse.toString (true).hashCode64()) + String (Random().nextInt64())) { targetLocation = targetLocationToUse; @@ -429,11 +427,11 @@ struct BackgroundDownloadTask : public URL::DownloadTask auto nsUrl = [NSURL URLWithString: juceStringToNS (urlToUse.toString (true))]; NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL: nsUrl]; - if (shouldUsePostRequest) + if (options.usePost) [request setHTTPMethod: @"POST"]; StringArray headerLines; - headerLines.addLines (extraHeadersToUse); + headerLines.addLines (options.extraHeaders); headerLines.removeEmptyStrings (true); for (int i = 0; i < headerLines.size(); ++i) @@ -445,10 +443,14 @@ struct BackgroundDownloadTask : public URL::DownloadTask [request addValue: juceStringToNS (value) forHTTPHeaderField: juceStringToNS (key)]; } - session = - [NSURLSession sessionWithConfiguration: [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier: juceStringToNS (uniqueIdentifier)] - delegate: delegate - delegateQueue: nullptr]; + auto* configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier: juceStringToNS (uniqueIdentifier)]; + + if (options.sharedContainer.isNotEmpty()) + [configuration setSharedContainerIdentifier: juceStringToNS (options.sharedContainer)]; + + session = [NSURLSession sessionWithConfiguration: configuration + delegate: delegate + delegateQueue: nullptr]; if (session != nullptr) downloadTask = [session downloadTaskWithRequest:request]; @@ -648,9 +650,9 @@ struct BackgroundDownloadTask : public URL::DownloadTask HashMap BackgroundDownloadTask::activeSessions; -std::unique_ptr URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool usePostRequest) +std::unique_ptr URL::downloadToFile (const File& targetLocation, const DownloadTaskOptions& options) { - std::unique_ptr downloadTask (new BackgroundDownloadTask (*this, targetLocation, extraHeaders, listener, usePostRequest)); + auto downloadTask = std::make_unique (*this, targetLocation, options); if (downloadTask->initOK() && downloadTask->connect()) return downloadTask; @@ -663,9 +665,9 @@ void URL::DownloadTask::juce_iosURLSessionNotify (const String& identifier) BackgroundDownloadTask::invokeNotify (identifier); } #else -std::unique_ptr URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool usePost) +std::unique_ptr URL::downloadToFile (const File& targetLocation, const DownloadTaskOptions& options) { - return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, extraHeaders, listener, usePost); + return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, options); } #endif @@ -929,9 +931,9 @@ private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (URLConnectionState) }; -std::unique_ptr URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost) +std::unique_ptr URL::downloadToFile (const File& targetLocation, const DownloadTaskOptions& options) { - return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, extraHeaders, listener, shouldUsePost); + return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, options); } JUCE_END_IGNORE_WARNINGS_GCC_LIKE diff --git a/modules/juce_core/native/juce_win32_Network.cpp b/modules/juce_core/native/juce_win32_Network.cpp index 2e66df1f9e..a2bceef5dd 100644 --- a/modules/juce_core/native/juce_win32_Network.cpp +++ b/modules/juce_core/native/juce_win32_Network.cpp @@ -650,9 +650,9 @@ bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& targetEmailA return mapiSendMail (0, 0, &message, MAPI_DIALOG | MAPI_LOGON_UI, 0) == SUCCESS_SUCCESS; } -std::unique_ptr URL::downloadToFile (const File& targetLocation, String extraHeaders, DownloadTask::Listener* listener, bool shouldUsePost) +std::unique_ptr URL::downloadToFile (const File& targetLocation, const DownloadTaskOptions& options) { - return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, extraHeaders, listener, shouldUsePost); + return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, options); } } // namespace juce diff --git a/modules/juce_core/network/juce_URL.cpp b/modules/juce_core/network/juce_URL.cpp index 98159340f3..1a1ba00438 100644 --- a/modules/juce_core/network/juce_URL.cpp +++ b/modules/juce_core/network/juce_URL.cpp @@ -106,29 +106,26 @@ struct FallbackDownloadTask : public URL::DownloadTask, JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FallbackDownloadTask) }; -void URL::DownloadTask::Listener::progress (DownloadTask*, int64, int64) {} -URL::DownloadTask::Listener::~Listener() {} +void URL::DownloadTaskListener::progress (DownloadTask*, int64, int64) {} //============================================================================== std::unique_ptr URL::DownloadTask::createFallbackDownloader (const URL& urlToUse, const File& targetFileToUse, - const String& extraHeadersToUse, - Listener* listenerToUse, - bool usePostRequest) + const DownloadTaskOptions& options) { const size_t bufferSize = 0x8000; targetFileToUse.deleteFile(); if (auto outputStream = targetFileToUse.createOutputStream (bufferSize)) { - auto stream = std::make_unique (urlToUse, usePostRequest); - stream->withExtraHeaders (extraHeadersToUse); + auto stream = std::make_unique (urlToUse, options.usePost); + stream->withExtraHeaders (options.extraHeaders); if (stream->connect (nullptr)) return std::make_unique (std::move (outputStream), bufferSize, std::move (stream), - listenerToUse); + options.listener); } return nullptr; @@ -1005,4 +1002,15 @@ std::unique_ptr URL::createInputStream (bool usePostCommand, .withHttpRequestCmd (httpRequestCmd)); } +std::unique_ptr URL::downloadToFile (const File& targetLocation, + String extraHeaders, + DownloadTask::Listener* listener, + bool usePostCommand) +{ + auto options = DownloadTaskOptions().withExtraHeaders (std::move (extraHeaders)) + .withListener (listener) + .withUsePost (usePostCommand); + return downloadToFile (targetLocation, std::move (options)); +} + } // namespace juce diff --git a/modules/juce_core/network/juce_URL.h b/modules/juce_core/network/juce_URL.h index 367a0bb4d6..2280d0e184 100644 --- a/modules/juce_core/network/juce_URL.h +++ b/modules/juce_core/network/juce_URL.h @@ -428,6 +428,64 @@ public: std::unique_ptr createOutputStream() const; //============================================================================== + class DownloadTask; + + /** Used to receive callbacks for download progress. */ + struct JUCE_API DownloadTaskListener + { + virtual ~DownloadTaskListener() = default; + + /** Called when the download has finished. Be aware that this callback may + come on an arbitrary thread. + */ + virtual void finished (DownloadTask* task, bool success) = 0; + + /** Called periodically by the OS to indicate download progress. + + Beware that this callback may come on an arbitrary thread. + */ + virtual void progress (DownloadTask* task, int64 bytesDownloaded, int64 totalLength); + }; + + /** Holds options that will can be specified when starting a new download + with downloadToFile(). + */ + class DownloadTaskOptions + { + public: + String extraHeaders; + String sharedContainer; + DownloadTaskListener* listener = nullptr; + bool usePost = false; + + /** Specifies headers to add to the request. */ + auto withExtraHeaders (String value) const { return with (&DownloadTaskOptions::extraHeaders, std::move (value)); } + + /** On iOS, specifies the container where the downloaded file will be stored. + + If you initiate a download task from inside an app extension on iOS, + you must supply this option. + + This is currently unused on other platforms. + */ + auto withSharedContainer (String value) const { return with (&DownloadTaskOptions::sharedContainer, std::move (value)); } + + /** Specifies an observer for the download task. */ + auto withListener (DownloadTaskListener* value) const { return with (&DownloadTaskOptions::listener, std::move (value)); } + + /** Specifies whether a post command should be used. */ + auto withUsePost (bool value) const { return with (&DownloadTaskOptions::usePost, value); } + + private: + template + DownloadTaskOptions with (Member&& member, Value&& value) const + { + auto copy = *this; + copy.*member = std::forward (value); + return copy; + } + }; + /** Represents a download task. Returned by downloadToFile() to allow querying and controlling the download task. @@ -435,22 +493,7 @@ public: class JUCE_API DownloadTask { public: - /** Used to receive callbacks for download progress. */ - struct JUCE_API Listener - { - virtual ~Listener(); - - /** Called when the download has finished. Be aware that this callback may - come on an arbitrary thread. - */ - virtual void finished (URL::DownloadTask* task, bool success) = 0; - - /** Called periodically by the OS to indicate download progress. - - Beware that this callback may come on an arbitrary thread. - */ - virtual void progress (URL::DownloadTask* task, int64 bytesDownloaded, int64 totalLength); - }; + using Listener = DownloadTaskListener; /** Releases the resources of the download task, unregisters the listener and cancels the download if necessary. @@ -493,7 +536,7 @@ public: private: friend class URL; - static std::unique_ptr createFallbackDownloader (const URL&, const File&, const String&, Listener*, bool); + static std::unique_ptr createFallbackDownloader (const URL&, const File&, const DownloadTaskOptions&); public: #if JUCE_IOS @@ -505,6 +548,13 @@ public: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DownloadTask) }; + /** This function is replaced by a new overload accepting a DownloadTaskOptions argument. */ + [[deprecated ("Use the overload with a DownloadTaskOptions argument instead")]] + std::unique_ptr downloadToFile (const File& targetLocation, + String extraHeaders = String(), + DownloadTaskListener* listener = nullptr, + bool usePostCommand = false); + /** Download the URL to a file. This method attempts to download the URL to a given file location. @@ -515,9 +565,7 @@ public: network re-connections and continuing your download while your app is suspended. */ std::unique_ptr downloadToFile (const File& targetLocation, - String extraHeaders = String(), - DownloadTask::Listener* listener = nullptr, - bool usePostCommand = false); + const DownloadTaskOptions& options); //============================================================================== /** Tries to download the entire contents of this URL into a binary data block.