Merge pull request 'updatesvc: support alternate URL' (#222) from feature/updatesvc-alternate-url into release/v9.0.0

This commit is contained in:
Maxim Kadushkin
2025-04-04 07:39:42 +00:00
6 changed files with 60 additions and 11 deletions

View File

@ -330,14 +330,14 @@ void CSvcManager::init()
tstring ext = m_packageData->fileType == _T("iss") ? _T(".exe") : m_packageData->fileType == _T("msi") ? _T(".msi") : ARCHIVE_EXT;
m_pDownloader->downloadFile(m_packageData->packageUrl, generateTmpFileName(ext));
}
NS_Logger::WriteLog(_T("Received MSG_LoadUpdates, URL: ") + params[1]);
NS_Logger::WriteLog(_T("Received MSG_LoadUpdates, URL: ") + m_packageData->packageUrl);
break;
}
case MSG_RequestContentLenght: {
__GLOBAL_LOCK
if (m_pDownloader)
m_pDownloader->queryContentLenght(params[1]);
NS_Logger::WriteLog(_T("Received MSG_RequestContentLenght, URL: ") + params[1]);
m_pDownloader->queryContentLenght(m_packageData->packageUrl);
NS_Logger::WriteLog(_T("Received MSG_RequestContentLenght, URL: ") + m_packageData->packageUrl);
break;
}
case MSG_StopDownload: {
@ -469,6 +469,7 @@ void CSvcManager::onCompleteSlot(const int error, const tstring &filePath)
if (error == 0) {
switch (m_downloadMode) {
case Mode::CHECK_UPDATES: {
__GLOBAL_LOCK // isUrlAccessible may take a long time to execute
tstring out_json;
list<tstring> lst;
if (NS_File::readFile(filePath, lst)) {
@ -511,7 +512,10 @@ void CSvcManager::onCompleteSlot(const int error, const tstring &filePath)
}
}
#endif
m_packageData->packageUrl = package_type.value(_T("url")).toTString();
tstring url = package_type.value(_T("url")).toTString();
tstring url2 = package_type.value(_T("url2")).toTString();
NS_Logger::WriteLog(_T("Primary package URL: ") + url + _T("\nSecondary package URL: ") + url2);
m_packageData->packageUrl = ((url.empty() || !m_pDownloader->isUrlAccessible(url)) && !url2.empty()) ? url2 : url;
tstring hash = package_type.value(_T("md5")).toTString();
std::transform(hash.begin(), hash.end(), hash.begin(), ::tolower);
m_packageData->hash = hash;
@ -531,7 +535,10 @@ void CSvcManager::onCompleteSlot(const int error, const tstring &filePath)
m_packageData->version = svc_version;
m_packageData->fileType = _T("archive");
JsonObject package_type = win.value(_T("serviceArchive")).toObject();
m_packageData->packageUrl = package_type.value(_T("url")).toTString();
tstring url = package_type.value(_T("url")).toTString();
tstring url2 = package_type.value(_T("url2")).toTString();
NS_Logger::WriteLog(_T("Primary package URL: ") + url + _T("\nSecondary package URL: ") + url2);
m_packageData->packageUrl = ((url.empty() || !m_pDownloader->isUrlAccessible(url)) && !url2.empty()) ? url2 : url;
tstring hash = package_type.value(_T("md5")).toTString();
std::transform(hash.begin(), hash.end(), hash.begin(), ::tolower);
m_packageData->hash = hash;
@ -557,6 +564,7 @@ void CSvcManager::onCompleteSlot(const int error, const tstring &filePath)
} else {
// read error
}
__UNLOCK
m_socket->sendMessage(MSG_LoadCheckFinished, out_json);
break;
}

View File

@ -86,6 +86,23 @@ CDownloader::~CDownloader()
delete pimpl, pimpl = nullptr;
}
bool CDownloader::isUrlAccessible(const string &url)
{
if (url.empty())
return false;
CURLcode res = CURLE_FAILED_INIT;
if (CURL *curl = curl_easy_init()) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
return res == CURLE_OK;
}
void CDownloader::queryContentLenght(const string &url)
{
if (url.empty() || pimpl->m_lock)
@ -93,14 +110,18 @@ void CDownloader::queryContentLenght(const string &url)
pimpl->m_lock = true;
pimpl->m_future = std::async(std::launch::async, [=]() {
double fileSize = 0;
curl_off_t fileSize = 0;
CURLcode res = CURLE_FAILED_INIT;
if (CURL *curl = curl_easy_init()) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
res = curl_easy_perform(curl);
if (res == CURLE_OK)
curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &fileSize);
if (res == CURLE_OK) {
curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &fileSize);
if (fileSize < 0) fileSize = 0;
}
curl_easy_cleanup(curl);
}
int error = (res == CURLE_OK) ? 0 :
@ -137,6 +158,7 @@ void CDownloader::start()
if (CURL *curl = curl_easy_init()) {
pimpl->m_prev_percent = -1;
curl_easy_setopt(curl, CURLOPT_URL, pimpl->m_url.c_str());
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);

View File

@ -50,6 +50,7 @@ public:
CDownloader();
~CDownloader();
bool isUrlAccessible(const string &url);
void queryContentLenght(const string &url);
void downloadFile(const string &url, const string &filePath);
void start();

View File

@ -87,10 +87,16 @@ static int initConnection(const wstring &url, DWORD &dwFileSize, Connection &con
if (!WinHttpReceiveResponse(conn.hRequest, NULL))
return DNL_CONN_ERR;
DWORD dwSize = sizeof(DWORD);
if (!WinHttpQueryHeaders(conn.hRequest, WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwFileSize, &dwSize, WINHTTP_NO_HEADER_INDEX))
DWORD dwStatusCode = 0, dwSize = sizeof(DWORD);
if (!WinHttpQueryHeaders(conn.hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwStatusCode, &dwSize, WINHTTP_NO_HEADER_INDEX))
return DNL_CONN_ERR;
if (dwStatusCode >= HTTP_STATUS_BAD_REQUEST)
return DNL_CONN_ERR;
if (!WinHttpQueryHeaders(conn.hRequest, WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwFileSize, &dwSize, WINHTTP_NO_HEADER_INDEX))
dwFileSize = 0;
return DNL_OK;
}
@ -189,6 +195,17 @@ CDownloader::~CDownloader()
delete pimpl, pimpl = nullptr;
}
bool CDownloader::isUrlAccessible(const wstring &url)
{
if (url.empty())
return false;
DWORD dwFileSize = 0;
Connection conn;
int hr = initConnection(url, dwFileSize, conn);
return hr == DNL_OK;
}
void CDownloader::queryContentLenght(const wstring &url)
{
if (url.empty() || pimpl->m_lock)

View File

@ -50,6 +50,7 @@ public:
CDownloader();
~CDownloader();
bool isUrlAccessible(const wstring &url);
void queryContentLenght(const wstring &url);
void downloadFile(const wstring &url, const wstring &filePath);
void start();

View File

@ -820,7 +820,7 @@ void CUpdateManager::onLoadCheckFinished(const QString &json)
m_packageData->isInstallable = root.value("isInstallable").toBool();
clearTempFiles(m_packageData->isInstallable && isSavedPackageValid() ? m_savedPackageData->fileName : "");
if (m_packageData->packageUrl.empty() || !m_socket->sendMessage(MSG_RequestContentLenght, WStrToTStr(m_packageData->packageUrl))) {
if (m_packageData->packageUrl.empty() || !m_socket->sendMessage(MSG_RequestContentLenght)) {
m_packageData->fileSize = "--";
onCheckFinished(false, true, m_packageData->version, "");
}