diff --git a/indra/viewer_components/updater/llupdatechecker.cpp b/indra/viewer_components/updater/llupdatechecker.cpp
index 2c60636122ee0a05e7ccb8c30cdf41d1f85ad530..d31244cc9bdbe3b037c5499911eeca5528c763d3 100644
--- a/indra/viewer_components/updater/llupdatechecker.cpp
+++ b/indra/viewer_components/updater/llupdatechecker.cpp
@@ -24,21 +24,35 @@
  */
 
 #include "linden_common.h"
+#include <stdexcept>
 #include <boost/format.hpp>
 #include "llhttpclient.h"
 #include "llsd.h"
 #include "llupdatechecker.h"
 #include "lluri.h"
 
+
 #if LL_WINDOWS
 #pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
 #endif
 
+
+class LLUpdateChecker::CheckError:
+	public std::runtime_error
+{
+public:
+	CheckError(const char * message):
+		std::runtime_error(message)
+	{
+		; // No op.
+	}
+};
+
+
 class LLUpdateChecker::Implementation:
 	public LLHTTPClient::Responder
 {
 public:
-	
 	Implementation(Client & client);
 	~Implementation();
 	void check(std::string const & protocolVersion, std::string const & hostUrl, 
@@ -50,9 +64,8 @@ class LLUpdateChecker::Implementation:
 						   const LLSD& content);
 	virtual void error(U32 status, const std::string & reason);
 	
-private:
-	std::string buildUrl(std::string const & protocolVersion, std::string const & hostUrl, 
-						 std::string const & servicePath, std::string channel, std::string version);
+private:	
+	static const char * sProtocolVersion;
 	
 	Client & mClient;
 	LLHTTPClient mHttpClient;
@@ -60,6 +73,9 @@ class LLUpdateChecker::Implementation:
 	LLHTTPClient::ResponderPtr mMe; 
 	std::string mVersion;
 	
+	std::string buildUrl(std::string const & protocolVersion, std::string const & hostUrl, 
+						 std::string const & servicePath, std::string channel, std::string version);
+
 	LOG_CLASS(LLUpdateChecker::Implementation);
 };
 
@@ -88,6 +104,9 @@ void LLUpdateChecker::check(std::string const & protocolVersion, std::string con
 //-----------------------------------------------------------------------------
 
 
+const char * LLUpdateChecker::Implementation::sProtocolVersion = "v1.0";
+
+
 LLUpdateChecker::Implementation::Implementation(LLUpdateChecker::Client & client):
 	mClient(client),
 	mInProgress(false),
@@ -106,7 +125,9 @@ LLUpdateChecker::Implementation::~Implementation()
 void LLUpdateChecker::Implementation::check(std::string const & protocolVersion, std::string const & hostUrl, 
 											std::string const & servicePath, std::string channel, std::string version)
 {
-	// llassert(!mInProgress);
+	llassert(!mInProgress);
+	
+	if(protocolVersion != sProtocolVersion) throw CheckError("unsupported protocol");
 		
 	mInProgress = true;
 	mVersion = version;
@@ -135,11 +156,11 @@ void LLUpdateChecker::Implementation::completed(U32 status,
 	} else if(content["required"].asBoolean()) {
 		LL_INFOS("UpdateCheck") << "version invalid" << llendl;
 		LLURI uri(content["url"].asString());
-		mClient.requiredUpdate(content["version"].asString(), uri);
+		mClient.requiredUpdate(content["version"].asString(), uri, content["hash"].asString());
 	} else {
 		LL_INFOS("UpdateCheck") << "newer version " << content["version"].asString() << " available" << llendl;
 		LLURI uri(content["url"].asString());
-		mClient.optionalUpdate(content["version"].asString(), uri);
+		mClient.optionalUpdate(content["version"].asString(), uri, content["hash"].asString());
 	}
 }
 
diff --git a/indra/viewer_components/updater/llupdatechecker.h b/indra/viewer_components/updater/llupdatechecker.h
index 58aaee4e3d541ab3d3a71c818897fc802d952aab..cea1f13647dc2275182691c6ac022ab89d075b7d 100644
--- a/indra/viewer_components/updater/llupdatechecker.h
+++ b/indra/viewer_components/updater/llupdatechecker.h
@@ -38,6 +38,9 @@ class LLUpdateChecker {
 	class Client;
 	class Implementation;
 	
+	// An exception that may be raised on check errors.
+	class CheckError;
+	
 	LLUpdateChecker(Client & client);
 	
 	// Check status of current app on the given host for the channel and version provided.
@@ -62,10 +65,14 @@ class LLUpdateChecker::Client
 	virtual void error(std::string const & message) = 0;
 	
 	// A newer version is available, but the current version may still be used.
-	virtual void optionalUpdate(std::string const & newVersion, LLURI const & uri) = 0;
+	virtual void optionalUpdate(std::string const & newVersion,
+								LLURI const & uri,
+								std::string const & hash) = 0;
 	
 	// A newer version is available, and the current version is no longer valid. 
-	virtual void requiredUpdate(std::string const & newVersion, LLURI const & uri) = 0;
+	virtual void requiredUpdate(std::string const & newVersion,
+								LLURI const & uri,
+								std::string const & hash) = 0;
 	
 	// The checked version is up to date; no newer version exists.
 	virtual void upToDate(void) = 0;
diff --git a/indra/viewer_components/updater/llupdatedownloader.cpp b/indra/viewer_components/updater/llupdatedownloader.cpp
index 087d79f8041fe91a66a1161af0ee6e12e242c311..102f2f9eec22411830633571b3fc18ca6a537a40 100644
--- a/indra/viewer_components/updater/llupdatedownloader.cpp
+++ b/indra/viewer_components/updater/llupdatedownloader.cpp
@@ -24,10 +24,13 @@
  */
 
 #include "linden_common.h"
+#include <stdexcept>
+#include <boost/format.hpp>
 #include <boost/lexical_cast.hpp>
 #include <curl/curl.h>
 #include "lldir.h"
 #include "llfile.h"
+#include "llmd5.h"
 #include "llsd.h"
 #include "llsdserialize.h"
 #include "llthread.h"
@@ -41,33 +44,59 @@ class LLUpdateDownloader::Implementation:
 	Implementation(LLUpdateDownloader::Client & client);
 	~Implementation();
 	void cancel(void);
-	void download(LLURI const & uri);
+	void download(LLURI const & uri, std::string const & hash);
 	bool isDownloading(void);
 	void onHeader(void * header, size_t size);
 	void onBody(void * header, size_t size);
-private:
-	static const char * sSecondLifeUpdateRecord;
+	void resume(void);
 	
+private:
 	LLUpdateDownloader::Client & mClient;
 	CURL * mCurl;
+	LLSD mDownloadData;
 	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);
-	bool shouldResumeOngoingDownload(LLURI const & uri, LLSD & downloadData);
-	void startDownloading(LLURI const & uri);
+	void startDownloading(LLURI const & uri, std::string const & hash);
+	void throwOnCurlError(CURLcode code);
+	bool validateDownload(void);
 
 	LOG_CLASS(LLUpdateDownloader::Implementation);
 };
 
 
+namespace {
+	class DownloadError:
+		public std::runtime_error
+	{
+	public:
+		DownloadError(const char * message):
+			std::runtime_error(message)
+		{
+			; // No op.
+		}
+	};
+
+		
+	const char * gSecondLifeUpdateRecord = "SecondLifeUpdateDownload.xml";
+};
+
+
 
 // LLUpdateDownloader
 //-----------------------------------------------------------------------------
 
 
+
+std::string LLUpdateDownloader::downloadMarkerPath(void)
+{
+	return gDirUtilp->getExpandedFilename(LL_PATH_LOGS, gSecondLifeUpdateRecord);
+}
+
+
 LLUpdateDownloader::LLUpdateDownloader(Client & client):
 	mImplementation(new LLUpdateDownloader::Implementation(client))
 {
@@ -81,9 +110,9 @@ void LLUpdateDownloader::cancel(void)
 }
 
 
-void LLUpdateDownloader::download(LLURI const & uri)
+void LLUpdateDownloader::download(LLURI const & uri, std::string const & hash)
 {
-	mImplementation->download(uri);
+	mImplementation->download(uri, hash);
 }
 
 
@@ -93,6 +122,12 @@ bool LLUpdateDownloader::isDownloading(void)
 }
 
 
+void LLUpdateDownloader::resume(void)
+{
+	mImplementation->resume();
+}
+
+
 
 // LLUpdateDownloader::Implementation
 //-----------------------------------------------------------------------------
@@ -106,6 +141,7 @@ namespace {
 		return bytes;
 	}
 
+
 	size_t header_function(void * data, size_t blockSize, size_t blocks, void * downloader)
 	{
 		size_t bytes = blockSize * blocks;
@@ -115,15 +151,11 @@ namespace {
 }
 
 
-const char * LLUpdateDownloader::Implementation::sSecondLifeUpdateRecord =
-	"SecondLifeUpdateDownload.xml";
-
-
 LLUpdateDownloader::Implementation::Implementation(LLUpdateDownloader::Client & client):
 	LLThread("LLUpdateDownloader"),
 	mClient(client),
 	mCurl(0),
-	mDownloadRecordPath(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, sSecondLifeUpdateRecord))
+	mDownloadRecordPath(LLUpdateDownloader::downloadMarkerPath())
 {
 	CURLcode code = curl_global_init(CURL_GLOBAL_ALL); // Just in case.
 	llassert(code = CURLE_OK); // TODO: real error handling here. 
@@ -142,13 +174,15 @@ void LLUpdateDownloader::Implementation::cancel(void)
 }
 	
 
-void LLUpdateDownloader::Implementation::download(LLURI const & uri)
+void LLUpdateDownloader::Implementation::download(LLURI const & uri, std::string const & hash)
 {
-	LLSD downloadData;
-	if(shouldResumeOngoingDownload(uri, downloadData)){
-		startDownloading(uri); // TODO: Implement resume.
-	} else {
-		startDownloading(uri);
+	if(isDownloading()) mClient.downloadError("download in progress");
+	
+	mDownloadData = LLSD();
+	try {
+		startDownloading(uri, hash);
+	} catch(DownloadError const & e) {
+		mClient.downloadError(e.what());
 	}
 }
 
@@ -158,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);
@@ -173,14 +246,10 @@ void LLUpdateDownloader::Implementation::onHeader(void * buffer, size_t size)
 			size_t size = boost::lexical_cast<size_t>(contentLength);
 			LL_INFOS("UpdateDownload") << "download size is " << size << LL_ENDL;
 			
-			LLSD downloadData;
-			llifstream idataStream(mDownloadRecordPath);
-			LLSDSerialize parser;
-			parser.fromXMLDocument(downloadData, idataStream);
-			idataStream.close();
-			downloadData["size"] = LLSD(LLSD::Integer(size));
+			mDownloadData["size"] = LLSD(LLSD::Integer(size));
 			llofstream odataStream(mDownloadRecordPath);
-			parser.toPrettyXML(downloadData, odataStream);
+			LLSDSerialize parser;
+			parser.toPrettyXML(mDownloadData, odataStream);
 		} catch (std::exception const & e) {
 			LL_WARNS("UpdateDownload") << "unable to read content length (" 
 				<< e.what() << ")" << LL_ENDL;
@@ -200,17 +269,26 @@ 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) {
-		LL_INFOS("UpdateDownload") << "download successful" << LL_ENDL;
-		mClient.downloadComplete();
+		if(validateDownload()) {
+			LL_INFOS("UpdateDownload") << "download successful" << LL_ENDL;
+			mClient.downloadComplete(mDownloadData);
+		} else {
+			LL_INFOS("UpdateDownload") << "download failed hash check" << LL_ENDL;
+			std::string filePath = mDownloadData["path"].asString();
+			if(filePath.size() != 0) LLFile::remove(filePath);
+			mClient.downloadError("failed hash check");
+		}
 	} else {
-		LL_WARNS("UpdateDownload") << "download failed with error " << code << LL_ENDL;
+		LL_WARNS("UpdateDownload") << "download failed with error '" << 
+			curl_easy_strerror(code) << "'" << LL_ENDL;
 		mClient.downloadError("curl error");
 	}
 }
 
 
-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();
@@ -218,64 +296,93 @@ void LLUpdateDownloader::Implementation::initializeCurlGet(std::string const & u
 		curl_easy_reset(mCurl);
 	}
 	
-	llassert(mCurl != 0); // TODO: real error handling here.
+	if(mCurl == 0) throw DownloadError("failed to initialize curl");
 	
-	CURLcode code;
-	code = curl_easy_setopt(mCurl, CURLOPT_NOSIGNAL, true);
-	code = curl_easy_setopt(mCurl, CURLOPT_FOLLOWLOCATION, true);
-	code = curl_easy_setopt(mCurl, CURLOPT_WRITEFUNCTION, &write_function);
-	code = curl_easy_setopt(mCurl, CURLOPT_WRITEDATA, this);
-	code = curl_easy_setopt(mCurl, CURLOPT_HEADERFUNCTION, &header_function);
-	code = curl_easy_setopt(mCurl, CURLOPT_HEADERDATA, this);
-	code = curl_easy_setopt(mCurl, CURLOPT_HTTPGET, true);
-	code = curl_easy_setopt(mCurl, CURLOPT_URL, url.c_str());
-}
-
-
-void LLUpdateDownloader::Implementation::resumeDownloading(LLSD const & downloadData)
-{
+	throwOnCurlError(curl_easy_setopt(mCurl, CURLOPT_NOSIGNAL, true));
+	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));
+	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()));
 }
 
 
-bool LLUpdateDownloader::Implementation::shouldResumeOngoingDownload(LLURI const & uri, LLSD & downloadData)
+void LLUpdateDownloader::Implementation::resumeDownloading(size_t startByte)
 {
-	if(!LLFile::isfile(mDownloadRecordPath)) return false;
-	
-	llifstream dataStream(mDownloadRecordPath);
-	LLSDSerialize parser;
-	parser.fromXMLDocument(downloadData, dataStream);
+	initializeCurlGet(mDownloadData["url"].asString(), false);
 	
-	if(downloadData["url"].asString() != uri.asString()) return false;
+	// 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);
 	
-	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)
+void LLUpdateDownloader::Implementation::startDownloading(LLURI const & uri, std::string const & hash)
 {
-	LLSD downloadData;
-	downloadData["url"] = uri.asString();
+	mDownloadData["url"] = uri.asString();
+	mDownloadData["hash"] = hash;
 	LLSD path = uri.pathArray();
+	if(path.size() == 0) throw DownloadError("no file path");
 	std::string fileName = path[path.size() - 1].asString();
 	std::string filePath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, fileName);
-	LL_INFOS("UpdateDownload") << "downloading " << filePath << LL_ENDL;
-	LL_INFOS("UpdateDownload") << "from " << uri.asString() << LL_ENDL;
-	downloadData["path"] = filePath;
+	mDownloadData["path"] = filePath;
+
+	LL_INFOS("UpdateDownload") << "downloading " << filePath
+		<< " from " << uri.asString() << LL_ENDL;
+	LL_INFOS("UpdateDownload") << "hash of file is " << hash << LL_ENDL;
+		
 	llofstream dataStream(mDownloadRecordPath);
 	LLSDSerialize parser;
-	parser.toPrettyXML(downloadData, dataStream);
+	parser.toPrettyXML(mDownloadData, dataStream);
 	
 	mDownloadStream.open(filePath, std::ios_base::out | std::ios_base::binary);
-	initializeCurlGet(uri.asString());
+	initializeCurlGet(uri.asString(), true);
 	start();
 }
+
+
+void LLUpdateDownloader::Implementation::throwOnCurlError(CURLcode code)
+{
+	if(code != CURLE_OK) {
+		const char * errorString = curl_easy_strerror(code);
+		if(errorString != 0) {
+			throw DownloadError(curl_easy_strerror(code));
+		} else {
+			throw DownloadError("unknown curl error");
+		}
+	} else {
+		; // No op.
+	}
+}
+
+
+bool LLUpdateDownloader::Implementation::validateDownload(void)
+{
+	std::string filePath = mDownloadData["path"].asString();
+	llifstream fileStream(filePath);
+	if(!fileStream) return false;
+
+	std::string hash = mDownloadData["hash"].asString();
+	if(hash.size() != 0) {
+		LL_INFOS("UpdateDownload") << "checking hash..." << LL_ENDL;
+		char digest[33];
+		LLMD5(fileStream).hex_digest(digest);
+		return hash == digest;
+	} else {
+		return true; // No hash check provided.
+	}
+}
diff --git a/indra/viewer_components/updater/llupdatedownloader.h b/indra/viewer_components/updater/llupdatedownloader.h
index 395d19d6bfd07727f8cd5c8484612ca388e574b8..dc8ecc378adc872103e80f9d463002cf6d50ad91 100644
--- a/indra/viewer_components/updater/llupdatedownloader.h
+++ b/indra/viewer_components/updater/llupdatedownloader.h
@@ -27,7 +27,6 @@
 #define LL_UPDATE_DOWNLOADER_H
 
 
-#include <stdexcept>
 #include <string>
 #include <boost/shared_ptr.hpp>
 #include "lluri.h"
@@ -39,24 +38,27 @@
 class LLUpdateDownloader
 {
 public:
-	class BusyError;
 	class Client;
 	class Implementation;
 	
+	// Returns the path to the download marker file containing details of the
+	// latest download.
+	static std::string downloadMarkerPath(void);
+	
 	LLUpdateDownloader(Client & client);
 	
 	// Cancel any in progress download; a no op if none is in progress.
 	void cancel(void);
 	
 	// Start a new download.
-	//
-	// This method will throw a BusyException instance if a download is already
-	// in progress.
-	void download(LLURI const & uri);
+	void download(LLURI const & uri, std::string const & hash);
 	
 	// Returns true if a download is in progress.
 	bool isDownloading(void);
 	
+	// Resume a partial download.
+	void resume(void);
+	
 private:
 	boost::shared_ptr<Implementation> mImplementation;
 };
@@ -69,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 e865552fb30f10f32bd2e2a635c9c0f67c3bda6f..dc48606cbc89b5b136c4594633d4bb0c679bc1e9 100644
--- a/indra/viewer_components/updater/llupdaterservice.cpp
+++ b/indra/viewer_components/updater/llupdaterservice.cpp
@@ -90,12 +90,16 @@ class LLUpdaterServiceImpl :
 	
 	// LLUpdateChecker::Client:
 	virtual void error(std::string const & message);
-	virtual void optionalUpdate(std::string const & newVersion, LLURI const & uri);
-	virtual void requiredUpdate(std::string const & newVersion, LLURI const & uri);
+	virtual void optionalUpdate(std::string const & newVersion,
+								LLURI const & uri,
+								std::string const & hash);
+	virtual void requiredUpdate(std::string const & newVersion,
+								LLURI const & uri,
+								std::string const & hash);
 	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);	
@@ -195,14 +199,18 @@ void LLUpdaterServiceImpl::error(std::string const & message)
 	retry();
 }
 
-void LLUpdaterServiceImpl::optionalUpdate(std::string const & newVersion, LLURI const & uri)
+void LLUpdaterServiceImpl::optionalUpdate(std::string const & newVersion,
+										  LLURI const & uri,
+										  std::string const & hash)
 {
-	mUpdateDownloader.download(uri);
+	mUpdateDownloader.download(uri, hash);
 }
 
-void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion, LLURI const & uri)
+void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion,
+										  LLURI const & uri,
+										  std::string const & hash)
 {
-	mUpdateDownloader.download(uri);
+	mUpdateDownloader.download(uri, hash);
 }
 
 void LLUpdaterServiceImpl::upToDate(void)
diff --git a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp
index 958526e35ba2401cfcc78cdc5aaa5535c68b8de9..20d0f8fa09330db41b7e333f657d738838611fdb 100644
--- a/indra/viewer_components/updater/tests/llupdaterservice_test.cpp
+++ b/indra/viewer_components/updater/tests/llupdaterservice_test.cpp
@@ -64,7 +64,7 @@ void LLUpdateChecker::check(std::string const & protocolVersion, std::string con
 								  std::string const & servicePath, std::string channel, std::string version)
 {}
 LLUpdateDownloader::LLUpdateDownloader(Client & ) {}
-void LLUpdateDownloader::download(LLURI const & ){}
+void LLUpdateDownloader::download(LLURI const & , std::string const &){}
 
 /*****************************************************************************
 *   TUT