aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/filetransfer.cc
diff options
context:
space:
mode:
authorJohn Ericson <John.Ericson@Obsidian.Systems>2022-03-10 17:03:16 +0000
committerJohn Ericson <John.Ericson@Obsidian.Systems>2022-03-10 17:10:15 +0000
commite5c42bba9bf76d00fb15ec9a179bf91aa81c38c6 (patch)
tree7597549f36313859d15cb4ae80c04af955c9a223 /src/libstore/filetransfer.cc
parent1ef88da3503b88f289a15786dfd48821cf5b6502 (diff)
parent4d98143914120d0163f5c50f30ce8a5289433f8f (diff)
Merge remote-tracking branch 'upstream/master' into indexed-store-path-outputs
Diffstat (limited to 'src/libstore/filetransfer.cc')
-rw-r--r--src/libstore/filetransfer.cc65
1 files changed, 38 insertions, 27 deletions
diff --git a/src/libstore/filetransfer.cc b/src/libstore/filetransfer.cc
index 2cf35ec83..c46262299 100644
--- a/src/libstore/filetransfer.cc
+++ b/src/libstore/filetransfer.cc
@@ -33,12 +33,12 @@ FileTransferSettings fileTransferSettings;
static GlobalConfig::Register rFileTransferSettings(&fileTransferSettings);
-std::string resolveUri(const std::string & uri)
+std::string resolveUri(std::string_view uri)
{
if (uri.compare(0, 8, "channel:") == 0)
- return "https://nixos.org/channels/" + std::string(uri, 8) + "/nixexprs.tar.xz";
+ return "https://nixos.org/channels/" + std::string(uri.substr(8)) + "/nixexprs.tar.xz";
else
- return uri;
+ return std::string(uri);
}
struct curlFileTransfer : public FileTransfer
@@ -106,7 +106,7 @@ struct curlFileTransfer : public FileTransfer
this->request.dataCallback(data);
}
} else
- this->result.data->append(data);
+ this->result.data.append(data);
})
{
if (!request.expectedETag.empty())
@@ -128,7 +128,7 @@ struct curlFileTransfer : public FileTransfer
if (requestHeaders) curl_slist_free_all(requestHeaders);
try {
if (!done)
- fail(FileTransferError(Interrupted, nullptr, "download of '%s' was interrupted", request.uri));
+ fail(FileTransferError(Interrupted, {}, "download of '%s' was interrupted", request.uri));
} catch (...) {
ignoreException();
}
@@ -195,17 +195,17 @@ struct curlFileTransfer : public FileTransfer
std::smatch match;
if (std::regex_match(line, match, statusLine)) {
result.etag = "";
- result.data = std::make_shared<std::string>();
+ result.data.clear();
result.bodySize = 0;
- statusMsg = trim(match[1]);
+ statusMsg = trim(match.str(1));
acceptRanges = false;
encoding = "";
} else {
auto i = line.find(':');
- if (i != string::npos) {
- string name = toLower(trim(string(line, 0, i)));
+ if (i != std::string::npos) {
+ std::string name = toLower(trim(line.substr(0, i)));
if (name == "etag") {
- result.etag = trim(string(line, i + 1));
+ result.etag = trim(line.substr(i + 1));
/* Hack to work around a GitHub bug: it sends
ETags, but ignores If-None-Match. So if we get
the expected ETag on a 200 response, then shut
@@ -218,8 +218,8 @@ struct curlFileTransfer : public FileTransfer
return 0;
}
} else if (name == "content-encoding")
- encoding = trim(string(line, i + 1));
- else if (name == "accept-ranges" && toLower(trim(std::string(line, i + 1))) == "bytes")
+ encoding = trim(line.substr(i + 1));
+ else if (name == "accept-ranges" && toLower(trim(line.substr(i + 1))) == "bytes")
acceptRanges = true;
}
}
@@ -340,7 +340,7 @@ struct curlFileTransfer : public FileTransfer
if (writtenToSink)
curl_easy_setopt(req, CURLOPT_RESUME_FROM_LARGE, writtenToSink);
- result.data = std::make_shared<std::string>();
+ result.data.clear();
result.bodySize = 0;
}
@@ -434,21 +434,21 @@ struct curlFileTransfer : public FileTransfer
attempt++;
- std::shared_ptr<std::string> response;
+ std::optional<std::string> response;
if (errorSink)
- response = errorSink->s;
+ response = std::move(errorSink->s);
auto exc =
code == CURLE_ABORTED_BY_CALLBACK && _isInterrupted
- ? FileTransferError(Interrupted, response, "%s of '%s' was interrupted", request.verb(), request.uri)
+ ? FileTransferError(Interrupted, std::move(response), "%s of '%s' was interrupted", request.verb(), request.uri)
: httpStatus != 0
? FileTransferError(err,
- response,
+ std::move(response),
fmt("unable to %s '%s': HTTP error %d ('%s')",
request.verb(), request.uri, httpStatus, statusMsg)
+ (code == CURLE_OK ? "" : fmt(" (curl error: %s)", curl_easy_strerror(code)))
)
: FileTransferError(err,
- response,
+ std::move(response),
fmt("unable to %s '%s': %s (%d)",
request.verb(), request.uri, curl_easy_strerror(code), code));
@@ -544,6 +544,8 @@ struct curlFileTransfer : public FileTransfer
stopWorkerThread();
});
+ unshareFilesystem();
+
std::map<CURL *, std::shared_ptr<TransferItem>> items;
bool quit = false;
@@ -702,8 +704,8 @@ struct curlFileTransfer : public FileTransfer
auto s3Res = s3Helper.getObject(bucketName, key);
FileTransferResult res;
if (!s3Res.data)
- throw FileTransferError(NotFound, nullptr, "S3 object '%s' does not exist", request.uri);
- res.data = s3Res.data;
+ throw FileTransferError(NotFound, {}, "S3 object '%s' does not exist", request.uri);
+ res.data = std::move(*s3Res.data);
callback(std::move(res));
#else
throw nix::Error("cannot download '%s' because Nix is not built with S3 support", request.uri);
@@ -716,15 +718,24 @@ struct curlFileTransfer : public FileTransfer
}
};
+ref<curlFileTransfer> makeCurlFileTransfer()
+{
+ return make_ref<curlFileTransfer>();
+}
+
ref<FileTransfer> getFileTransfer()
{
- static ref<FileTransfer> fileTransfer = makeFileTransfer();
+ static ref<curlFileTransfer> fileTransfer = makeCurlFileTransfer();
+
+ if (fileTransfer->state_.lock()->quit)
+ fileTransfer = makeCurlFileTransfer();
+
return fileTransfer;
}
ref<FileTransfer> makeFileTransfer()
{
- return make_ref<curlFileTransfer>();
+ return makeCurlFileTransfer();
}
std::future<FileTransferResult> FileTransfer::enqueueFileTransfer(const FileTransferRequest & request)
@@ -848,25 +859,25 @@ void FileTransfer::download(FileTransferRequest && request, Sink & sink)
}
template<typename... Args>
-FileTransferError::FileTransferError(FileTransfer::Error error, std::shared_ptr<string> response, const Args & ... args)
+FileTransferError::FileTransferError(FileTransfer::Error error, std::optional<std::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))
+ if (response && (response->size() < 1024 || response->find("<html>") != std::string::npos))
err.msg = hintfmt("%1%\n\nresponse body:\n\n%2%", normaltxt(hf.str()), chomp(*response));
else
err.msg = hf;
}
-bool isUri(const string & s)
+bool isUri(std::string_view s)
{
if (s.compare(0, 8, "channel:") == 0) return true;
size_t pos = s.find("://");
- if (pos == string::npos) return false;
- string scheme(s, 0, pos);
+ if (pos == std::string::npos) return false;
+ std::string scheme(s, 0, pos);
return scheme == "http" || scheme == "https" || scheme == "file" || scheme == "channel" || scheme == "git" || scheme == "s3" || scheme == "ssh";
}