forked from lix-project/lix
Merge pull request #3714 from obsidiansystems/add-body-to-network-errors
Add response body to network errors
This commit is contained in:
commit
0951330680
|
@ -124,7 +124,7 @@ struct curlFileTransfer : public FileTransfer
|
||||||
if (requestHeaders) curl_slist_free_all(requestHeaders);
|
if (requestHeaders) curl_slist_free_all(requestHeaders);
|
||||||
try {
|
try {
|
||||||
if (!done)
|
if (!done)
|
||||||
fail(FileTransferError(Interrupted, "download of '%s' was interrupted", request.uri));
|
fail(FileTransferError(Interrupted, nullptr, "download of '%s' was interrupted", request.uri));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
ignoreException();
|
ignoreException();
|
||||||
}
|
}
|
||||||
|
@ -145,6 +145,7 @@ struct curlFileTransfer : public FileTransfer
|
||||||
|
|
||||||
LambdaSink finalSink;
|
LambdaSink finalSink;
|
||||||
std::shared_ptr<CompressionSink> decompressionSink;
|
std::shared_ptr<CompressionSink> decompressionSink;
|
||||||
|
std::optional<StringSink> errorSink;
|
||||||
|
|
||||||
std::exception_ptr writeException;
|
std::exception_ptr writeException;
|
||||||
|
|
||||||
|
@ -154,9 +155,19 @@ struct curlFileTransfer : public FileTransfer
|
||||||
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())) {
|
||||||
|
// In this case we want to construct a TeeSink, to keep
|
||||||
|
// the response around (which we figure won't be big
|
||||||
|
// like an actual download should be) to improve error
|
||||||
|
// messages.
|
||||||
|
errorSink = StringSink { };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorSink)
|
||||||
|
(*errorSink)((unsigned char *) contents, realSize);
|
||||||
(*decompressionSink)((unsigned char *) contents, realSize);
|
(*decompressionSink)((unsigned char *) contents, realSize);
|
||||||
|
|
||||||
return realSize;
|
return realSize;
|
||||||
|
@ -412,16 +423,21 @@ struct curlFileTransfer : public FileTransfer
|
||||||
|
|
||||||
attempt++;
|
attempt++;
|
||||||
|
|
||||||
|
std::shared_ptr<std::string> response;
|
||||||
|
if (errorSink)
|
||||||
|
response = errorSink->s;
|
||||||
auto exc =
|
auto exc =
|
||||||
code == CURLE_ABORTED_BY_CALLBACK && _isInterrupted
|
code == CURLE_ABORTED_BY_CALLBACK && _isInterrupted
|
||||||
? FileTransferError(Interrupted, fmt("%s of '%s' was interrupted", request.verb(), request.uri))
|
? FileTransferError(Interrupted, response, "%s of '%s' was interrupted", request.verb(), request.uri)
|
||||||
: httpStatus != 0
|
: httpStatus != 0
|
||||||
? FileTransferError(err,
|
? FileTransferError(err,
|
||||||
|
response,
|
||||||
fmt("unable to %s '%s': HTTP error %d ('%s')",
|
fmt("unable to %s '%s': HTTP error %d ('%s')",
|
||||||
request.verb(), request.uri, httpStatus, statusMsg)
|
request.verb(), request.uri, httpStatus, statusMsg)
|
||||||
+ (code == CURLE_OK ? "" : fmt(" (curl error: %s)", curl_easy_strerror(code)))
|
+ (code == CURLE_OK ? "" : fmt(" (curl error: %s)", curl_easy_strerror(code)))
|
||||||
)
|
)
|
||||||
: FileTransferError(err,
|
: FileTransferError(err,
|
||||||
|
response,
|
||||||
fmt("unable to %s '%s': %s (%d)",
|
fmt("unable to %s '%s': %s (%d)",
|
||||||
request.verb(), request.uri, curl_easy_strerror(code), code));
|
request.verb(), request.uri, curl_easy_strerror(code), code));
|
||||||
|
|
||||||
|
@ -679,7 +695,7 @@ struct curlFileTransfer : public FileTransfer
|
||||||
auto s3Res = s3Helper.getObject(bucketName, key);
|
auto s3Res = s3Helper.getObject(bucketName, key);
|
||||||
FileTransferResult res;
|
FileTransferResult res;
|
||||||
if (!s3Res.data)
|
if (!s3Res.data)
|
||||||
throw FileTransferError(NotFound, fmt("S3 object '%s' does not exist", request.uri));
|
throw FileTransferError(NotFound, nullptr, "S3 object '%s' does not exist", request.uri);
|
||||||
res.data = s3Res.data;
|
res.data = s3Res.data;
|
||||||
callback(std::move(res));
|
callback(std::move(res));
|
||||||
#else
|
#else
|
||||||
|
@ -824,6 +840,21 @@ void FileTransfer::download(FileTransferRequest && request, Sink & sink)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
FileTransferError::FileTransferError(FileTransfer::Error error, std::shared_ptr<string> response, const Args & ... args)
|
||||||
|
: Error(args...), error(error), response(response)
|
||||||
|
{
|
||||||
|
const auto hf = hintfmt(args...);
|
||||||
|
// FIXME: Due to https://github.com/NixOS/nix/issues/3841 we don't know how
|
||||||
|
// to print different messages for different verbosity levels. For now
|
||||||
|
// we add some heuristics for detecting when we want to show the response.
|
||||||
|
if (response && (response->size() < 1024 || response->find("<html>") != string::npos)) {
|
||||||
|
err.hint = hintfmt("%1%\n\nresponse body:\n\n%2%", normaltxt(hf.str()), *response);
|
||||||
|
} else {
|
||||||
|
err.hint = hf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool isUri(const string & s)
|
bool isUri(const string & s)
|
||||||
{
|
{
|
||||||
if (s.compare(0, 8, "channel:") == 0) return true;
|
if (s.compare(0, 8, "channel:") == 0) return true;
|
||||||
|
|
|
@ -103,10 +103,12 @@ class FileTransferError : public Error
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FileTransfer::Error error;
|
FileTransfer::Error error;
|
||||||
|
std::shared_ptr<string> response; // intentionally optional
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
FileTransferError(FileTransfer::Error error, const Args & ... args)
|
FileTransferError(FileTransfer::Error error, std::shared_ptr<string> response, const Args & ... args);
|
||||||
: Error(args...), error(error)
|
|
||||||
{ }
|
virtual const char* sname() const override { return "FileTransferError"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
bool isUri(const string & s);
|
bool isUri(const string & s);
|
||||||
|
|
Loading…
Reference in a new issue