diff options
-rw-r--r-- | indra/viewer_components/updater/llupdatedownloader.cpp | 104 | ||||
-rw-r--r-- | indra/viewer_components/updater/llupdatedownloader.h | 5 | ||||
-rw-r--r-- | indra/viewer_components/updater/llupdaterservice.cpp | 2 |
3 files changed, 77 insertions, 34 deletions
diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp index 59e929d99f..102f2f9eec 100644 --- a/indra/viewer_components/updater/llupdatedownloader.cpp +++ b/indra/viewer_components/updater/llupdatedownloader.cpp @@ -25,6 +25,7 @@ #include "linden_common.h" #include <stdexcept> +#include <boost/format.hpp> #include <boost/lexical_cast.hpp> #include <curl/curl.h> #include "lldir.h" @@ -47,6 +48,8 @@ public: bool isDownloading(void); void onHeader(void * header, size_t size); void onBody(void * header, size_t size); + void resume(void); + private: LLUpdateDownloader::Client & mClient; CURL * mCurl; @@ -54,8 +57,8 @@ private: llofstream mDownloadStream; std::string mDownloadRecordPath; - void initializeCurlGet(std::string const & url); - void resumeDownloading(LLSD const & downloadData); + void initializeCurlGet(std::string const & url, bool processHeader); + void resumeDownloading(size_t startByte); void run(void); void startDownloading(LLURI const & uri, std::string const & hash); void throwOnCurlError(CURLcode code); @@ -119,6 +122,12 @@ bool LLUpdateDownloader::isDownloading(void) } +void LLUpdateDownloader::resume(void) +{ + mImplementation->resume(); +} + + // LLUpdateDownloader::Implementation //----------------------------------------------------------------------------- @@ -183,6 +192,45 @@ bool LLUpdateDownloader::Implementation::isDownloading(void) return !isStopped(); } + +void LLUpdateDownloader::Implementation::resume(void) +{ + llifstream dataStream(mDownloadRecordPath); + if(!dataStream) { + mClient.downloadError("no download marker"); + return; + } + + LLSDSerialize parser; + parser.fromXMLDocument(mDownloadData, dataStream); + + if(!mDownloadData.asBoolean()) { + mClient.downloadError("no download information in marker"); + return; + } + + std::string filePath = mDownloadData["path"].asString(); + try { + if(LLFile::isfile(filePath)) { + llstat fileStatus; + LLFile::stat(filePath, &fileStatus); + if(fileStatus.st_size != mDownloadData["size"].asInteger()) { + resumeDownloading(fileStatus.st_size); + } else if(!validateDownload()) { + LLFile::remove(filePath); + download(LLURI(mDownloadData["url"].asString()), mDownloadData["hash"].asString()); + } else { + mClient.downloadComplete(mDownloadData); + } + } else { + download(LLURI(mDownloadData["url"].asString()), mDownloadData["hash"].asString()); + } + } catch(DownloadError & e) { + mClient.downloadError(e.what()); + } +} + + void LLUpdateDownloader::Implementation::onHeader(void * buffer, size_t size) { char const * headerPtr = reinterpret_cast<const char *> (buffer); @@ -221,10 +269,11 @@ void LLUpdateDownloader::Implementation::onBody(void * buffer, size_t size) void LLUpdateDownloader::Implementation::run(void) { CURLcode code = curl_easy_perform(mCurl); + LLFile::remove(mDownloadRecordPath); if(code == CURLE_OK) { if(validateDownload()) { LL_INFOS("UpdateDownload") << "download successful" << LL_ENDL; - mClient.downloadComplete(); + mClient.downloadComplete(mDownloadData); } else { LL_INFOS("UpdateDownload") << "download failed hash check" << LL_ENDL; std::string filePath = mDownloadData["path"].asString(); @@ -239,7 +288,7 @@ void LLUpdateDownloader::Implementation::run(void) } -void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & url) +void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & url, bool processHeader) { if(mCurl == 0) { mCurl = curl_easy_init(); @@ -253,42 +302,33 @@ void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & u throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_FOLLOWLOCATION, true)); throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_WRITEFUNCTION, &write_function)); throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_WRITEDATA, this)); - throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HEADERFUNCTION, &header_function)); - throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HEADERDATA, this)); + if(processHeader) { + throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HEADERFUNCTION, &header_function)); + throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HEADERDATA, this)); + } throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPGET, true)); throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_URL, url.c_str())); } -void LLUpdateDownloader::Implementation::resumeDownloading(LLSD const & downloadData) -{ -} - - -/* -bool LLUpdateDownloader::Implementation::shouldResumeOngoingDownload(LLURI const & uri, LLSD & downloadData) +void LLUpdateDownloader::Implementation::resumeDownloading(size_t startByte) { - if(!LLFile::isfile(mDownloadRecordPath)) return false; + initializeCurlGet(mDownloadData["url"].asString(), false); - llifstream dataStream(mDownloadRecordPath); - LLSDSerialize parser; - parser.fromXMLDocument(downloadData, dataStream); + // The header 'Range: bytes n-' will request the bytes remaining in the + // source begining with byte n and ending with the last byte. + boost::format rangeHeaderFormat("Range: bytes=%u-"); + rangeHeaderFormat % startByte; + curl_slist * headerList = 0; + headerList = curl_slist_append(headerList, rangeHeaderFormat.str().c_str()); + if(headerList == 0) throw DownloadError("cannot add Range header"); + throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_HTTPHEADER, headerList)); + curl_slist_free_all(headerList); - if(downloadData["url"].asString() != uri.asString()) return false; - - std::string downloadedFilePath = downloadData["path"].asString(); - if(LLFile::isfile(downloadedFilePath)) { - llstat fileStatus; - LLFile::stat(downloadedFilePath, &fileStatus); - downloadData["bytes_downloaded"] = LLSD(LLSD::Integer(fileStatus.st_size)); - return true; - } else { - return false; - } - - return true; + mDownloadStream.open(mDownloadData["path"].asString(), + std::ios_base::out | std::ios_base::binary | std::ios_base::app); + start(); } - */ void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri, std::string const & hash) @@ -310,7 +350,7 @@ void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri, std parser.toPrettyXML(mDownloadData, dataStream); mDownloadStream.open(filePath, std::ios_base::out | std::ios_base::binary); - initializeCurlGet(uri.asString()); + initializeCurlGet(uri.asString(), true); start(); } diff --git a/indra/viewer_components/updater/llupdatedownloader.h b/indra/viewer_components/updater/llupdatedownloader.h index 8754ea329c..7bfb430879 100644 --- a/indra/viewer_components/updater/llupdatedownloader.h +++ b/indra/viewer_components/updater/llupdatedownloader.h @@ -56,6 +56,9 @@ public: // Returns true if a download is in progress. bool isDownloading(void); + // Resume a partial download. + void resume(void); + private: boost::shared_ptr<Implementation> mImplementation; }; @@ -68,7 +71,7 @@ class LLUpdateDownloader::Client { public: // The download has completed successfully. - virtual void downloadComplete(void) = 0; + virtual void downloadComplete(LLSD const & data) = 0; // The download failed. virtual void downloadError(std::string const & message) = 0; diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp index 1e0c393539..dc48606cbc 100644 --- a/indra/viewer_components/updater/llupdaterservice.cpp +++ b/indra/viewer_components/updater/llupdaterservice.cpp @@ -99,7 +99,7 @@ public: virtual void upToDate(void); // LLUpdateDownloader::Client - void downloadComplete(void) { retry(); } + void downloadComplete(LLSD const & data) { retry(); } void downloadError(std::string const & message) { retry(); } bool onMainLoop(LLSD const & event); |