libstore: asyncify curl interface
Change-Id: I3fc93016b8ac5e59d9062d4f4aead19ae051a680
This commit is contained in:
@@ -85,7 +85,7 @@ try {
|
|||||||
FileTransferResult res;
|
FileTransferResult res;
|
||||||
std::string data;
|
std::string data;
|
||||||
try {
|
try {
|
||||||
auto [meta, content] = getFileTransfer()->download(url, headers);
|
auto [meta, content] = TRY_AWAIT(getFileTransfer()->download(url, headers));
|
||||||
res = std::move(meta);
|
res = std::move(meta);
|
||||||
data = content->drain();
|
data = content->drain();
|
||||||
} catch (FileTransferError & e) {
|
} catch (FileTransferError & e) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "lix/libstore/filetransfer.hh"
|
#include "lix/libstore/filetransfer.hh"
|
||||||
#include "lix/libstore/store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
#include "lix/libutil/archive.hh"
|
#include "lix/libutil/archive.hh"
|
||||||
|
#include "lix/libutil/async.hh"
|
||||||
#include "lix/libutil/compression.hh"
|
#include "lix/libutil/compression.hh"
|
||||||
#include "lix/libutil/strings.hh"
|
#include "lix/libutil/strings.hh"
|
||||||
|
|
||||||
@@ -34,9 +35,11 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData,
|
|||||||
a forked process. */
|
a forked process. */
|
||||||
auto fileTransfer = makeFileTransfer();
|
auto fileTransfer = makeFileTransfer();
|
||||||
|
|
||||||
auto fetch = [&](const std::string & url) {
|
// we also have to run the remainder of this function in a fresh thread so
|
||||||
|
// we can have an aio root. the existing root on the current thread is not
|
||||||
auto raw = fileTransfer->download(url).second;
|
// safe to use because that would badly interfere with the parent process.
|
||||||
|
auto fetch = [&](AsyncIoRoot & aio, const std::string & url) {
|
||||||
|
auto raw = aio.blockOn(fileTransfer->download(url)).second;
|
||||||
auto decompressor = makeDecompressionSource(
|
auto decompressor = makeDecompressionSource(
|
||||||
unpack && mainUrl.ends_with(".xz") ? "xz" : "none", *raw);
|
unpack && mainUrl.ends_with(".xz") ? "xz" : "none", *raw);
|
||||||
|
|
||||||
@@ -52,21 +55,33 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::async(std::launch::async, [&] {
|
||||||
|
AsyncIoRoot aio;
|
||||||
|
|
||||||
/* Try the hashed mirrors first. */
|
/* Try the hashed mirrors first. */
|
||||||
if (getAttr("outputHashMode") == "flat")
|
if (getAttr("outputHashMode") == "flat") {
|
||||||
for (auto hashedMirror : settings.hashedMirrors.get())
|
for (auto hashedMirror : settings.hashedMirrors.get()) {
|
||||||
try {
|
try {
|
||||||
if (!hashedMirror.ends_with("/")) hashedMirror += '/';
|
if (!hashedMirror.ends_with("/")) {
|
||||||
|
hashedMirror += '/';
|
||||||
|
}
|
||||||
std::optional<HashType> ht = parseHashTypeOpt(getAttr("outputHashAlgo"));
|
std::optional<HashType> ht = parseHashTypeOpt(getAttr("outputHashAlgo"));
|
||||||
Hash h = newHashAllowEmpty(getAttr("outputHash"), ht);
|
Hash h = newHashAllowEmpty(getAttr("outputHash"), ht);
|
||||||
fetch(hashedMirror + printHashType(h.type) + "/" + h.to_string(Base::Base16, false));
|
fetch(
|
||||||
|
aio,
|
||||||
|
hashedMirror + printHashType(h.type) + "/"
|
||||||
|
+ h.to_string(Base::Base16, false)
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
debug(e.what());
|
debug(e.what());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Otherwise try the specified URL. */
|
/* Otherwise try the specified URL. */
|
||||||
fetch(mainUrl);
|
fetch(aio, mainUrl);
|
||||||
|
}).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "lix/libstore/store-api.hh"
|
#include "lix/libstore/store-api.hh"
|
||||||
#include "lix/libstore/s3.hh"
|
#include "lix/libstore/s3.hh"
|
||||||
#include "lix/libutil/regex.hh"
|
#include "lix/libutil/regex.hh"
|
||||||
|
#include "lix/libutil/result.hh"
|
||||||
#include "lix/libutil/signals.hh"
|
#include "lix/libutil/signals.hh"
|
||||||
#include "lix/libutil/strings.hh"
|
#include "lix/libutil/strings.hh"
|
||||||
#include "lix/libutil/thread-name.hh"
|
#include "lix/libutil/thread-name.hh"
|
||||||
@@ -692,9 +693,13 @@ struct curlFileTransfer : public FileTransfer
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void upload(const std::string & uri, std::string data, const Headers & headers) override
|
kj::Promise<Result<void>>
|
||||||
{
|
upload(const std::string & uri, std::string data, const Headers & headers) override
|
||||||
enqueueFileTransfer(uri, headers, std::move(data), false);
|
try {
|
||||||
|
TRY_AWAIT(enqueueFileTransfer(uri, headers, std::move(data), false));
|
||||||
|
co_return result::success();
|
||||||
|
} catch (...) {
|
||||||
|
co_return result::current_exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::pair<FileTransferResult, box_ptr<Source>>> tryEagerTransfers(
|
std::optional<std::pair<FileTransferResult, box_ptr<Source>>> tryEagerTransfers(
|
||||||
@@ -784,20 +789,22 @@ struct curlFileTransfer : public FileTransfer
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<FileTransferResult, box_ptr<Source>> enqueueFileTransfer(
|
kj::Promise<Result<std::pair<FileTransferResult, box_ptr<Source>>>> enqueueFileTransfer(
|
||||||
const std::string & uri,
|
const std::string & uri,
|
||||||
const Headers & headers,
|
const Headers & headers,
|
||||||
std::optional<std::string> data,
|
std::optional<std::string> data,
|
||||||
bool noBody
|
bool noBody
|
||||||
)
|
)
|
||||||
{
|
try {
|
||||||
if (auto eager = tryEagerTransfers(uri, headers, data, noBody)) {
|
if (auto eager = tryEagerTransfers(uri, headers, data, noBody)) {
|
||||||
return std::move(*eager);
|
co_return std::move(*eager);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto source = make_box_ptr<TransferSource>(*this, uri, headers, std::move(data), noBody);
|
auto source = make_box_ptr<TransferSource>(*this, uri, headers, std::move(data), noBody);
|
||||||
source->awaitData();
|
source->awaitData();
|
||||||
return {source->metadata, std::move(source)};
|
co_return {source->metadata, std::move(source)};
|
||||||
|
} catch (...) {
|
||||||
|
co_return result::current_exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TransferSource : Source
|
struct TransferSource : Source
|
||||||
@@ -972,21 +979,23 @@ struct curlFileTransfer : public FileTransfer
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool exists(const std::string & uri, const Headers & headers) override
|
kj::Promise<Result<bool>> exists(const std::string & uri, const Headers & headers) override
|
||||||
{
|
|
||||||
try {
|
try {
|
||||||
enqueueFileTransfer(uri, headers, std::nullopt, true);
|
try {
|
||||||
return true;
|
TRY_AWAIT(enqueueFileTransfer(uri, headers, std::nullopt, true));
|
||||||
|
co_return true;
|
||||||
} catch (FileTransferError & e) {
|
} catch (FileTransferError & e) {
|
||||||
/* S3 buckets return 403 if a file doesn't exist and the
|
/* S3 buckets return 403 if a file doesn't exist and the
|
||||||
bucket is unlistable, so treat 403 as 404. */
|
bucket is unlistable, so treat 403 as 404. */
|
||||||
if (e.error == FileTransfer::NotFound || e.error == FileTransfer::Forbidden)
|
if (e.error == FileTransfer::NotFound || e.error == FileTransfer::Forbidden)
|
||||||
return false;
|
co_return false;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
} catch (...) {
|
||||||
|
co_return result::current_exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<FileTransferResult, box_ptr<Source>>
|
kj::Promise<Result<std::pair<FileTransferResult, box_ptr<Source>>>>
|
||||||
download(const std::string & uri, const Headers & headers) override
|
download(const std::string & uri, const Headers & headers) override
|
||||||
{
|
{
|
||||||
return enqueueFileTransfer(uri, headers, std::nullopt, false);
|
return enqueueFileTransfer(uri, headers, std::nullopt, false);
|
||||||
|
|||||||
@@ -4,10 +4,12 @@
|
|||||||
#include "lix/libutil/box_ptr.hh"
|
#include "lix/libutil/box_ptr.hh"
|
||||||
#include "lix/libutil/ref.hh"
|
#include "lix/libutil/ref.hh"
|
||||||
#include "lix/libutil/logging.hh"
|
#include "lix/libutil/logging.hh"
|
||||||
|
#include "lix/libutil/result.hh"
|
||||||
#include "lix/libutil/serialise.hh"
|
#include "lix/libutil/serialise.hh"
|
||||||
#include "lix/libutil/types.hh"
|
#include "lix/libutil/types.hh"
|
||||||
#include "lix/libutil/config.hh"
|
#include "lix/libutil/config.hh"
|
||||||
|
|
||||||
|
#include <kj/async.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <future>
|
#include <future>
|
||||||
|
|
||||||
@@ -40,7 +42,7 @@ struct FileTransfer
|
|||||||
/**
|
/**
|
||||||
* Upload some data. May throw a FileTransferError exception.
|
* Upload some data. May throw a FileTransferError exception.
|
||||||
*/
|
*/
|
||||||
virtual void
|
virtual kj::Promise<Result<void>>
|
||||||
upload(const std::string & uri, std::string data, const Headers & headers = {}) = 0;
|
upload(const std::string & uri, std::string data, const Headers & headers = {}) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,7 +55,8 @@ struct FileTransfer
|
|||||||
*
|
*
|
||||||
* S3 objects are downloaded completely to answer this request.
|
* S3 objects are downloaded completely to answer this request.
|
||||||
*/
|
*/
|
||||||
virtual bool exists(const std::string & uri, const Headers & headers = {}) = 0;
|
virtual kj::Promise<Result<bool>>
|
||||||
|
exists(const std::string & uri, const Headers & headers = {}) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download a file, returning its contents through a source. Will not return
|
* Download a file, returning its contents through a source. Will not return
|
||||||
@@ -62,7 +65,7 @@ struct FileTransfer
|
|||||||
* thrown by the returned source. The source will only throw errors detected
|
* thrown by the returned source. The source will only throw errors detected
|
||||||
* during the transfer itself (decompression errors, connection drops, etc).
|
* during the transfer itself (decompression errors, connection drops, etc).
|
||||||
*/
|
*/
|
||||||
virtual std::pair<FileTransferResult, box_ptr<Source>>
|
virtual kj::Promise<Result<std::pair<FileTransferResult, box_ptr<Source>>>>
|
||||||
download(const std::string & uri, const Headers & headers = {}) = 0;
|
download(const std::string & uri, const Headers & headers = {}) = 0;
|
||||||
|
|
||||||
enum Error { NotFound, Forbidden, Misc, Transient, Interrupted };
|
enum Error { NotFound, Forbidden, Misc, Transient, Interrupted };
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ protected:
|
|||||||
checkEnabled();
|
checkEnabled();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
co_return getFileTransfer()->exists(makeURI(path));
|
co_return TRY_AWAIT(getFileTransfer()->exists(makeURI(path)));
|
||||||
} catch (FileTransferError & e) {
|
} catch (FileTransferError & e) {
|
||||||
maybeDisable();
|
maybeDisable();
|
||||||
throw;
|
throw;
|
||||||
@@ -142,7 +142,9 @@ protected:
|
|||||||
try {
|
try {
|
||||||
auto data = StreamToSourceAdapter(istream).drain();
|
auto data = StreamToSourceAdapter(istream).drain();
|
||||||
try {
|
try {
|
||||||
getFileTransfer()->upload(makeURI(path), std::move(data), {{"Content-Type", mimeType}});
|
TRY_AWAIT(getFileTransfer()->upload(
|
||||||
|
makeURI(path), std::move(data), {{"Content-Type", mimeType}}
|
||||||
|
));
|
||||||
} catch (FileTransferError & e) {
|
} catch (FileTransferError & e) {
|
||||||
throw UploadToHTTP(
|
throw UploadToHTTP(
|
||||||
"while uploading to HTTP binary cache at '%s': %s", cacheUri, e.msg()
|
"while uploading to HTTP binary cache at '%s': %s", cacheUri, e.msg()
|
||||||
@@ -175,7 +177,9 @@ protected:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return {make_box_ptr<HttpFile>(getFileTransfer()->download(makeURI(path)).second)};
|
co_return make_box_ptr<HttpFile>(
|
||||||
|
TRY_AWAIT(getFileTransfer()->download(makeURI(path))).second
|
||||||
|
);
|
||||||
} catch (FileTransferError & e) {
|
} catch (FileTransferError & e) {
|
||||||
if (e.error == FileTransfer::NotFound || e.error == FileTransfer::Forbidden)
|
if (e.error == FileTransfer::NotFound || e.error == FileTransfer::Forbidden)
|
||||||
throw NoSuchBinaryCacheFile("file '%s' does not exist in binary cache '%s'", path, getUri());
|
throw NoSuchBinaryCacheFile("file '%s' does not exist in binary cache '%s'", path, getUri());
|
||||||
@@ -183,7 +187,7 @@ protected:
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return {result::current_exception()};
|
co_return result::current_exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+1
-1
@@ -100,7 +100,7 @@ std::tuple<StorePath, Hash> prefetchFile(
|
|||||||
|
|
||||||
FdSink sink(fd.get());
|
FdSink sink(fd.get());
|
||||||
|
|
||||||
getFileTransfer()->download(url).second->drainInto(sink);
|
aio.blockOn(getFileTransfer()->download(url)).second->drainInto(sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Optionally unpack the file. */
|
/* Optionally unpack the file. */
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ struct CmdUpgradeNix : MixDryRun, EvalCommand
|
|||||||
Activity act(*logger, lvlInfo, actUnknown, "querying latest Nix version");
|
Activity act(*logger, lvlInfo, actUnknown, "querying latest Nix version");
|
||||||
|
|
||||||
// FIXME: use nixos.org?
|
// FIXME: use nixos.org?
|
||||||
auto [res, content] = getFileTransfer()->download(storePathsUrl);
|
auto [res, content] = aio().blockOn(getFileTransfer()->download(storePathsUrl));
|
||||||
auto data = content->drain();
|
auto data = content->drain();
|
||||||
|
|
||||||
auto evaluator = std::make_unique<Evaluator>(aio(), SearchPath{}, store);
|
auto evaluator = std::make_unique<Evaluator>(aio(), SearchPath{}, store);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "lix/libstore/filetransfer.hh"
|
#include "lix/libstore/filetransfer.hh"
|
||||||
|
#include "lix/libutil/async.hh"
|
||||||
#include "lix/libutil/compression.hh"
|
#include "lix/libutil/compression.hh"
|
||||||
#include "lix/libutil/error.hh"
|
#include "lix/libutil/error.hh"
|
||||||
#include "lix/libutil/signals.hh"
|
#include "lix/libutil/signals.hh"
|
||||||
@@ -206,12 +207,16 @@ TEST(FileTransfer, exceptionAbortsDownload)
|
|||||||
struct Done : BaseException
|
struct Done : BaseException
|
||||||
{};
|
{};
|
||||||
|
|
||||||
|
AsyncIoRoot aio;
|
||||||
auto ft = makeFileTransfer();
|
auto ft = makeFileTransfer();
|
||||||
|
|
||||||
LambdaSink broken([](auto block) { throw Done(); });
|
LambdaSink broken([](auto block) { throw Done(); });
|
||||||
|
|
||||||
auto [port, srv] = serveHTTP({{"200 ok", "", [](int) { return "foo"; }}});
|
auto [port, srv] = serveHTTP({{"200 ok", "", [](int) { return "foo"; }}});
|
||||||
ASSERT_THROW(ft->download(fmt("http://[::1]:%d/index", port)).second->drainInto(broken), Done);
|
ASSERT_THROW(
|
||||||
|
aio.blockOn(ft->download(fmt("http://[::1]:%d/index", port))).second->drainInto(broken),
|
||||||
|
Done
|
||||||
|
);
|
||||||
|
|
||||||
// makeFileTransfer returns a ref<>, which cannot be cleared. since we also
|
// makeFileTransfer returns a ref<>, which cannot be cleared. since we also
|
||||||
// can't default-construct it we'll have to overwrite it instead, but we'll
|
// can't default-construct it we'll have to overwrite it instead, but we'll
|
||||||
@@ -228,19 +233,21 @@ TEST(FileTransfer, exceptionAbortsDownload)
|
|||||||
TEST(FileTransfer, exceptionAbortsRead)
|
TEST(FileTransfer, exceptionAbortsRead)
|
||||||
{
|
{
|
||||||
auto [port, srv] = serveHTTP("200 ok", "content-length: 0\r\n", [] { return ""; });
|
auto [port, srv] = serveHTTP("200 ok", "content-length: 0\r\n", [] { return ""; });
|
||||||
|
AsyncIoRoot aio;
|
||||||
auto ft = makeFileTransfer();
|
auto ft = makeFileTransfer();
|
||||||
char buf[10] = "";
|
char buf[10] = "";
|
||||||
ASSERT_THROW(ft->download(fmt("http://[::1]:%d/index", port)).second->read(buf, 10), EndOfFile);
|
ASSERT_THROW(
|
||||||
|
aio.blockOn(ft->download(fmt("http://[::1]:%d/index", port))).second->read(buf, 10),
|
||||||
|
EndOfFile
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileTransfer, NOT_ON_DARWIN(reportsSetupErrors))
|
TEST(FileTransfer, NOT_ON_DARWIN(reportsSetupErrors))
|
||||||
{
|
{
|
||||||
auto [port, srv] = serveHTTP("404 not found", "", [] { return ""; });
|
auto [port, srv] = serveHTTP("404 not found", "", [] { return ""; });
|
||||||
|
AsyncIoRoot aio;
|
||||||
auto ft = makeFileTransfer();
|
auto ft = makeFileTransfer();
|
||||||
ASSERT_THROW(
|
ASSERT_THROW(aio.blockOn(ft->download(fmt("http://[::1]:%d/index", port))), FileTransferError);
|
||||||
ft->download(fmt("http://[::1]:%d/index", port)),
|
|
||||||
FileTransferError
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileTransfer, NOT_ON_DARWIN(defersFailures))
|
TEST(FileTransfer, NOT_ON_DARWIN(defersFailures))
|
||||||
@@ -253,8 +260,9 @@ TEST(FileTransfer, NOT_ON_DARWIN(defersFailures))
|
|||||||
// might only do so once its internal buffer has already been filled.)
|
// might only do so once its internal buffer has already been filled.)
|
||||||
return std::string(1024 * 1024, ' ');
|
return std::string(1024 * 1024, ' ');
|
||||||
});
|
});
|
||||||
|
AsyncIoRoot aio;
|
||||||
auto ft = makeFileTransfer(0);
|
auto ft = makeFileTransfer(0);
|
||||||
auto src = ft->download(fmt("http://[::1]:%d/index", port)).second;
|
auto src = aio.blockOn(ft->download(fmt("http://[::1]:%d/index", port))).second;
|
||||||
ASSERT_THROW(src->drain(), FileTransferError);
|
ASSERT_THROW(src->drain(), FileTransferError);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,10 +272,11 @@ TEST(FileTransfer, NOT_ON_DARWIN(handlesContentEncoding))
|
|||||||
std::string compressed = compress("gzip", original);
|
std::string compressed = compress("gzip", original);
|
||||||
|
|
||||||
auto [port, srv] = serveHTTP("200 ok", "content-encoding: gzip\r\n", [&] { return compressed; });
|
auto [port, srv] = serveHTTP("200 ok", "content-encoding: gzip\r\n", [&] { return compressed; });
|
||||||
|
AsyncIoRoot aio;
|
||||||
auto ft = makeFileTransfer();
|
auto ft = makeFileTransfer();
|
||||||
|
|
||||||
StringSink sink;
|
StringSink sink;
|
||||||
ft->download(fmt("http://[::1]:%d/index", port)).second->drainInto(sink);
|
aio.blockOn(ft->download(fmt("http://[::1]:%d/index", port))).second->drainInto(sink);
|
||||||
EXPECT_EQ(sink.s, original);
|
EXPECT_EQ(sink.s, original);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,8 +298,9 @@ TEST(FileTransfer, usesIntermediateLinkHeaders)
|
|||||||
[] { return ""; }},
|
[] { return ""; }},
|
||||||
{"200 ok", "content-length: 1\r\n", [] { return "a"; }},
|
{"200 ok", "content-length: 1\r\n", [] { return "a"; }},
|
||||||
});
|
});
|
||||||
|
AsyncIoRoot aio;
|
||||||
auto ft = makeFileTransfer(0);
|
auto ft = makeFileTransfer(0);
|
||||||
auto [result, _data] = ft->download(fmt("http://[::1]:%d/first", port));
|
auto [result, _data] = aio.blockOn(ft->download(fmt("http://[::1]:%d/first", port)));
|
||||||
ASSERT_EQ(result.immutableUrl, "http://foo");
|
ASSERT_EQ(result.immutableUrl, "http://foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,9 +313,10 @@ TEST(FileTransfer, stalledReaderDoesntBlockOthers)
|
|||||||
return round < 100 ? std::optional(std::string(1'000'000, ' ')) : std::nullopt;
|
return round < 100 ? std::optional(std::string(1'000'000, ' ')) : std::nullopt;
|
||||||
}},
|
}},
|
||||||
});
|
});
|
||||||
|
AsyncIoRoot aio;
|
||||||
auto ft = makeFileTransfer(0);
|
auto ft = makeFileTransfer(0);
|
||||||
auto [_result1, data1] = ft->download(fmt("http://[::1]:%d", port));
|
auto [_result1, data1] = aio.blockOn(ft->download(fmt("http://[::1]:%d", port)));
|
||||||
auto [_result2, data2] = ft->download(fmt("http://[::1]:%d", port));
|
auto [_result2, data2] = aio.blockOn(ft->download(fmt("http://[::1]:%d", port)));
|
||||||
auto drop = [](Source & source, size_t size) {
|
auto drop = [](Source & source, size_t size) {
|
||||||
char buf[1000];
|
char buf[1000];
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
@@ -342,8 +353,9 @@ TEST(FileTransfer, retries)
|
|||||||
[] { return "b"; },
|
[] { return "b"; },
|
||||||
{"Range: bytes=1-"}},
|
{"Range: bytes=1-"}},
|
||||||
});
|
});
|
||||||
|
AsyncIoRoot aio;
|
||||||
auto ft = makeFileTransfer(0);
|
auto ft = makeFileTransfer(0);
|
||||||
auto [result, data] = ft->download(fmt("http://[::1]:%d", port));
|
auto [result, data] = aio.blockOn(ft->download(fmt("http://[::1]:%d", port)));
|
||||||
ASSERT_EQ(data->drain(), "ab");
|
ASSERT_EQ(data->drain(), "ab");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,8 +364,9 @@ TEST(FileTransfer, doesntRetrySetupForever)
|
|||||||
auto [port, srv] = serveHTTP({
|
auto [port, srv] = serveHTTP({
|
||||||
{"429 try again later", "content-length: 0\r\n", [] { return ""; }},
|
{"429 try again later", "content-length: 0\r\n", [] { return ""; }},
|
||||||
});
|
});
|
||||||
|
AsyncIoRoot aio;
|
||||||
auto ft = makeFileTransfer(0);
|
auto ft = makeFileTransfer(0);
|
||||||
ASSERT_THROW(ft->download(fmt("http://[::1]:%d", port)), FileTransferError);
|
ASSERT_THROW(aio.blockOn(ft->download(fmt("http://[::1]:%d", port))), FileTransferError);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileTransfer, doesntRetryTransferForever)
|
TEST(FileTransfer, doesntRetryTransferForever)
|
||||||
@@ -374,12 +387,16 @@ TEST(FileTransfer, doesntRetryTransferForever)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
auto [port, srv] = serveHTTP(replies);
|
auto [port, srv] = serveHTTP(replies);
|
||||||
|
AsyncIoRoot aio;
|
||||||
auto ft = makeFileTransfer(0);
|
auto ft = makeFileTransfer(0);
|
||||||
ASSERT_THROW(ft->download(fmt("http://[::1]:%d", port)).second->drain(), FileTransferError);
|
ASSERT_THROW(
|
||||||
|
aio.blockOn(ft->download(fmt("http://[::1]:%d", port))).second->drain(), FileTransferError
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileTransfer, doesntRetryUploads)
|
TEST(FileTransfer, doesntRetryUploads)
|
||||||
{
|
{
|
||||||
|
AsyncIoRoot aio;
|
||||||
auto ft = makeFileTransfer(0);
|
auto ft = makeFileTransfer(0);
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -387,14 +404,16 @@ TEST(FileTransfer, doesntRetryUploads)
|
|||||||
{"429 try again later", "", [] { return ""; }},
|
{"429 try again later", "", [] { return ""; }},
|
||||||
{"200 ok", "", [] { return ""; }},
|
{"200 ok", "", [] { return ""; }},
|
||||||
});
|
});
|
||||||
ASSERT_THROW(ft->upload(fmt("http://[::1]:%d", port), ""), FileTransferError);
|
ASSERT_THROW(aio.blockOn(ft->upload(fmt("http://[::1]:%d", port), "")), FileTransferError);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto [port, srv] = serveHTTP({
|
auto [port, srv] = serveHTTP({
|
||||||
{"429 try again later", "", [] { return ""; }},
|
{"429 try again later", "", [] { return ""; }},
|
||||||
{"200 ok", "", [] { return ""; }},
|
{"200 ok", "", [] { return ""; }},
|
||||||
});
|
});
|
||||||
ASSERT_THROW(ft->upload(fmt("http://[::1]:%d", port), "foo"), FileTransferError);
|
ASSERT_THROW(
|
||||||
|
aio.blockOn(ft->upload(fmt("http://[::1]:%d", port), "foo")), FileTransferError
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,12 +438,16 @@ TEST(FileTransfer, DISABLED_interrupt)
|
|||||||
verbosity = lvlDebug;
|
verbosity = lvlDebug;
|
||||||
logger = new InterruptingLogger;
|
logger = new InterruptingLogger;
|
||||||
|
|
||||||
|
AsyncIoRoot aio;
|
||||||
auto ft = makeFileTransfer(0);
|
auto ft = makeFileTransfer(0);
|
||||||
auto [port, srv] = serveHTTP({
|
auto [port, srv] = serveHTTP({
|
||||||
{"200 ok", "content-length: 10\r\n", [] { return "0123456789"; }},
|
{"200 ok", "content-length: 10\r\n", [] { return "0123456789"; }},
|
||||||
});
|
});
|
||||||
|
|
||||||
ASSERT_THROW(ft->download(fmt("http://[::1]:%d/index", port)).second->drain(), FileTransferError);
|
ASSERT_THROW(
|
||||||
|
aio.blockOn(ft->download(fmt("http://[::1]:%d/index", port))).second->drain(),
|
||||||
|
FileTransferError
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FileTransfer, setupErrorsAreMetadata)
|
TEST(FileTransfer, setupErrorsAreMetadata)
|
||||||
@@ -432,8 +455,9 @@ TEST(FileTransfer, setupErrorsAreMetadata)
|
|||||||
auto [port, srv] = serveHTTP({
|
auto [port, srv] = serveHTTP({
|
||||||
{"404 try again later", "content-length: 1\r\n", [] { return "X"; }},
|
{"404 try again later", "content-length: 1\r\n", [] { return "X"; }},
|
||||||
});
|
});
|
||||||
|
AsyncIoRoot aio;
|
||||||
auto ft = makeFileTransfer(0);
|
auto ft = makeFileTransfer(0);
|
||||||
ASSERT_THROW(ft->upload(fmt("http://[::1]:%d", port), ""), FileTransferError);
|
ASSERT_THROW(aio.blockOn(ft->upload(fmt("http://[::1]:%d", port), "")), FileTransferError);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user