diff options
Diffstat (limited to 'src/libstore/download.cc')
-rw-r--r-- | src/libstore/download.cc | 54 |
1 files changed, 38 insertions, 16 deletions
diff --git a/src/libstore/download.cc b/src/libstore/download.cc index 9cc433228141..5cb2b497a50a 100644 --- a/src/libstore/download.cc +++ b/src/libstore/download.cc @@ -8,6 +8,7 @@ #include <curl/curl.h> #include <iostream> +#include <thread> namespace nix { @@ -194,9 +195,17 @@ struct CurlDownloader : public Downloader if (res != CURLE_OK) { Error err = httpStatus == 404 ? NotFound : - httpStatus == 403 ? Forbidden : Misc; - throw DownloadError(err, format("unable to download ‘%1%’: %2% (%3%)") - % url % curl_easy_strerror(res) % res); + httpStatus == 403 ? Forbidden : + (httpStatus == 408 || httpStatus == 500 || httpStatus == 503 + || httpStatus == 504 || httpStatus == 522 || httpStatus == 524 + || res == CURLE_COULDNT_RESOLVE_HOST) ? Transient : + Misc; + if (res == CURLE_HTTP_RETURNED_ERROR && httpStatus != -1) + throw DownloadError(err, format("unable to download ‘%s’: HTTP error %d") + % url % httpStatus); + else + throw DownloadError(err, format("unable to download ‘%s’: %s (%d)") + % url % curl_easy_strerror(res) % res); } char *effectiveUrlCStr; @@ -211,15 +220,27 @@ struct CurlDownloader : public Downloader DownloadResult download(string url, const DownloadOptions & options) override { - DownloadResult res; - if (fetch(resolveUri(url), options)) { - res.cached = false; - res.data = data; - } else - res.cached = true; - res.effectiveUrl = effectiveUrl; - res.etag = etag; - return res; + size_t attempt = 0; + + while (true) { + try { + DownloadResult res; + if (fetch(resolveUri(url), options)) { + res.cached = false; + res.data = data; + } else + res.cached = true; + res.effectiveUrl = effectiveUrl; + res.etag = etag; + return res; + } catch (DownloadError & e) { + attempt++; + if (e.error != Transient || attempt >= options.tries) throw; + auto ms = options.baseRetryTimeMs * (1 << (attempt - 1)); + printMsg(lvlError, format("warning: %s; retrying in %d ms") % e.what() % ms); + std::this_thread::sleep_for(std::chrono::milliseconds(ms)); + } + } } }; @@ -228,7 +249,7 @@ ref<Downloader> makeDownloader() return make_ref<CurlDownloader>(); } -Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpack, const Hash & expectedHash) +Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpack, string name, const Hash & expectedHash) { string ignored; return downloadCached(store, url_, unpack, ignored, expectedHash); @@ -238,9 +259,10 @@ Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpa { auto url = resolveUri(url_); - string name; - auto p = url.rfind('/'); - if (p != string::npos) name = string(url, p + 1); + if (name == "") { + auto p = url.rfind('/'); + if (p != string::npos) name = string(url, p + 1); + } Path expectedStorePath; if (expectedHash) { |