mirror of
https://github.com/NixOS/nix.git
synced 2025-11-22 02:09:36 +01:00
Merge pull request #14591 from NixOS/filetransfer-error-handling
libstore/filetransfer: Improve error handling
This commit is contained in:
commit
dfac44cdfb
1 changed files with 61 additions and 38 deletions
|
|
@ -151,15 +151,23 @@ struct curlFileTransfer : public FileTransfer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void failEx(std::exception_ptr ex)
|
void failEx(std::exception_ptr ex) noexcept
|
||||||
{
|
{
|
||||||
assert(!done);
|
assert(!done);
|
||||||
done = true;
|
done = true;
|
||||||
|
try {
|
||||||
|
std::rethrow_exception(ex);
|
||||||
|
} catch (nix::Error & e) {
|
||||||
|
/* Add more context to the error message. */
|
||||||
|
e.addTrace({}, "during %s of '%s'", Uncolored(request.verb()), request.uri.to_string());
|
||||||
|
} catch (...) {
|
||||||
|
/* Can't add more context to the error. */
|
||||||
|
}
|
||||||
callback.rethrow(ex);
|
callback.rethrow(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void fail(T && e)
|
void fail(T && e) noexcept
|
||||||
{
|
{
|
||||||
failEx(std::make_exception_ptr(std::forward<T>(e)));
|
failEx(std::make_exception_ptr(std::forward<T>(e)));
|
||||||
}
|
}
|
||||||
|
|
@ -168,32 +176,30 @@ struct curlFileTransfer : public FileTransfer
|
||||||
std::shared_ptr<FinishSink> decompressionSink;
|
std::shared_ptr<FinishSink> decompressionSink;
|
||||||
std::optional<StringSink> errorSink;
|
std::optional<StringSink> errorSink;
|
||||||
|
|
||||||
std::exception_ptr writeException;
|
std::exception_ptr callbackException;
|
||||||
|
|
||||||
size_t writeCallback(void * contents, size_t size, size_t nmemb)
|
size_t writeCallback(void * contents, size_t size, size_t nmemb) noexcept
|
||||||
{
|
try {
|
||||||
try {
|
size_t realSize = size * nmemb;
|
||||||
size_t realSize = size * nmemb;
|
result.bodySize += realSize;
|
||||||
result.bodySize += realSize;
|
|
||||||
|
|
||||||
if (!decompressionSink) {
|
if (!decompressionSink) {
|
||||||
decompressionSink = makeDecompressionSink(encoding, finalSink);
|
decompressionSink = makeDecompressionSink(encoding, finalSink);
|
||||||
if (!successfulStatuses.count(getHTTPStatus())) {
|
if (!successfulStatuses.count(getHTTPStatus())) {
|
||||||
// In this case we want to construct a TeeSink, to keep
|
// In this case we want to construct a TeeSink, to keep
|
||||||
// the response around (which we figure won't be big
|
// the response around (which we figure won't be big
|
||||||
// like an actual download should be) to improve error
|
// like an actual download should be) to improve error
|
||||||
// messages.
|
// messages.
|
||||||
errorSink = StringSink{};
|
errorSink = StringSink{};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(*decompressionSink)({(char *) contents, realSize});
|
|
||||||
|
|
||||||
return realSize;
|
|
||||||
} catch (...) {
|
|
||||||
writeException = std::current_exception();
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(*decompressionSink)({(char *) contents, realSize});
|
||||||
|
|
||||||
|
return realSize;
|
||||||
|
} catch (...) {
|
||||||
|
callbackException = std::current_exception();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t writeCallbackWrapper(void * contents, size_t size, size_t nmemb, void * userp)
|
static size_t writeCallbackWrapper(void * contents, size_t size, size_t nmemb, void * userp)
|
||||||
|
|
@ -209,8 +215,8 @@ struct curlFileTransfer : public FileTransfer
|
||||||
result.urls.push_back(effectiveUriCStr);
|
result.urls.push_back(effectiveUriCStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t headerCallback(void * contents, size_t size, size_t nmemb)
|
size_t headerCallback(void * contents, size_t size, size_t nmemb) noexcept
|
||||||
{
|
try {
|
||||||
size_t realSize = size * nmemb;
|
size_t realSize = size * nmemb;
|
||||||
std::string line((char *) contents, realSize);
|
std::string line((char *) contents, realSize);
|
||||||
printMsg(lvlVomit, "got header for '%s': %s", request.uri, trim(line));
|
printMsg(lvlVomit, "got header for '%s': %s", request.uri, trim(line));
|
||||||
|
|
@ -263,6 +269,15 @@ struct curlFileTransfer : public FileTransfer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return realSize;
|
return realSize;
|
||||||
|
} catch (...) {
|
||||||
|
#if LIBCURL_VERSION_NUM >= 0x075700
|
||||||
|
/* https://curl.se/libcurl/c/CURLOPT_HEADERFUNCTION.html:
|
||||||
|
You can also abort the transfer by returning CURL_WRITEFUNC_ERROR. */
|
||||||
|
callbackException = std::current_exception();
|
||||||
|
return CURL_WRITEFUNC_ERROR;
|
||||||
|
#else
|
||||||
|
return realSize;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t headerCallbackWrapper(void * contents, size_t size, size_t nmemb, void * userp)
|
static size_t headerCallbackWrapper(void * contents, size_t size, size_t nmemb, void * userp)
|
||||||
|
|
@ -270,14 +285,17 @@ struct curlFileTransfer : public FileTransfer
|
||||||
return ((TransferItem *) userp)->headerCallback(contents, size, nmemb);
|
return ((TransferItem *) userp)->headerCallback(contents, size, nmemb);
|
||||||
}
|
}
|
||||||
|
|
||||||
int progressCallback(curl_off_t dltotal, curl_off_t dlnow)
|
int progressCallback(curl_off_t dltotal, curl_off_t dlnow) noexcept
|
||||||
{
|
try {
|
||||||
try {
|
act.progress(dlnow, dltotal);
|
||||||
act.progress(dlnow, dltotal);
|
|
||||||
} catch (nix::Interrupted &) {
|
|
||||||
assert(getInterrupted());
|
|
||||||
}
|
|
||||||
return getInterrupted();
|
return getInterrupted();
|
||||||
|
} catch (nix::Interrupted &) {
|
||||||
|
assert(getInterrupted());
|
||||||
|
return 1;
|
||||||
|
} catch (...) {
|
||||||
|
/* Something unexpected has happened like logger throwing an exception. */
|
||||||
|
callbackException = std::current_exception();
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int progressCallbackWrapper(
|
static int progressCallbackWrapper(
|
||||||
|
|
@ -288,11 +306,14 @@ struct curlFileTransfer : public FileTransfer
|
||||||
return item.progressCallback(isUpload ? ultotal : dltotal, isUpload ? ulnow : dlnow);
|
return item.progressCallback(isUpload ? ultotal : dltotal, isUpload ? ulnow : dlnow);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int debugCallback(CURL * handle, curl_infotype type, char * data, size_t size, void * userptr)
|
static int debugCallback(CURL * handle, curl_infotype type, char * data, size_t size, void * userptr) noexcept
|
||||||
{
|
try {
|
||||||
if (type == CURLINFO_TEXT)
|
if (type == CURLINFO_TEXT)
|
||||||
vomit("curl: %s", chomp(std::string(data, size)));
|
vomit("curl: %s", chomp(std::string(data, size)));
|
||||||
return 0;
|
return 0;
|
||||||
|
} catch (...) {
|
||||||
|
/* Swallow the exception. Nothing left to do. */
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t readCallback(char * buffer, size_t size, size_t nitems) noexcept
|
size_t readCallback(char * buffer, size_t size, size_t nitems) noexcept
|
||||||
|
|
@ -302,6 +323,7 @@ struct curlFileTransfer : public FileTransfer
|
||||||
} catch (EndOfFile &) {
|
} catch (EndOfFile &) {
|
||||||
return 0;
|
return 0;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
callbackException = std::current_exception();
|
||||||
return CURL_READFUNC_ABORT;
|
return CURL_READFUNC_ABORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -333,6 +355,7 @@ struct curlFileTransfer : public FileTransfer
|
||||||
}
|
}
|
||||||
return CURL_SEEKFUNC_OK;
|
return CURL_SEEKFUNC_OK;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
callbackException = std::current_exception();
|
||||||
return CURL_SEEKFUNC_FAIL;
|
return CURL_SEEKFUNC_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -476,7 +499,7 @@ struct curlFileTransfer : public FileTransfer
|
||||||
try {
|
try {
|
||||||
decompressionSink->finish();
|
decompressionSink->finish();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
writeException = std::current_exception();
|
callbackException = std::current_exception();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -485,8 +508,8 @@ struct curlFileTransfer : public FileTransfer
|
||||||
httpStatus = 304;
|
httpStatus = 304;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (writeException)
|
if (callbackException)
|
||||||
failEx(writeException);
|
failEx(callbackException);
|
||||||
|
|
||||||
else if (code == CURLE_OK && successfulStatuses.count(httpStatus)) {
|
else if (code == CURLE_OK && successfulStatuses.count(httpStatus)) {
|
||||||
result.cached = httpStatus == 304;
|
result.cached = httpStatus == 304;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue