aboutsummaryrefslogtreecommitdiff
path: root/tests/unit
diff options
context:
space:
mode:
authoreldritch horrors <pennae@lix.systems>2024-05-29 20:51:37 +0200
committereldritch horrors <pennae@lix.systems>2024-05-29 22:35:29 +0000
commitdd4a2c17593283456884db18fa32ea01851fd2c5 (patch)
treec23a5b63a9b6c96b9dcf40f41371dd0ffae1ddde /tests/unit
parent71b32bb87cd48dbbd672c8ca6b041ed36f3bae11 (diff)
libstore: fix http abuses no longer working
while refactoring the curl wrapper we inadvertently broken the immutable flake protocol, because the immutable flake protocol accumulates headers across the entire redirect chain instead of using only the headers given in the final response of the chain. this is a problem because Some Known Providers Of Flake Infrastructure set rel=immutable link headers only in the penultimate entry of the redirect chain, and curl does not regard it as worth returning to us via its response header enumeration mechanisms. fixes https://git.lix.systems/lix-project/lix/issues/358 Change-Id: I645c3932b465cde848bd6a3565925a1e3cbcdda0
Diffstat (limited to 'tests/unit')
-rw-r--r--tests/unit/libstore/filetransfer.cc53
1 files changed, 48 insertions, 5 deletions
diff --git a/tests/unit/libstore/filetransfer.cc b/tests/unit/libstore/filetransfer.cc
index 684697c69..0e5c0965e 100644
--- a/tests/unit/libstore/filetransfer.cc
+++ b/tests/unit/libstore/filetransfer.cc
@@ -23,10 +23,19 @@
using namespace std::chrono_literals;
+namespace {
+
+struct Reply {
+ std::string status, headers;
+ std::function<std::string()> content;
+};
+
+}
+
namespace nix {
static std::tuple<uint16_t, AutoCloseFD>
-serveHTTP(std::string_view status, std::string_view headers, std::function<std::string()> content)
+serveHTTP(std::vector<Reply> replies)
{
AutoCloseFD listener(::socket(AF_INET6, SOCK_STREAM, 0));
if (!listener) {
@@ -52,7 +61,7 @@ serveHTTP(std::string_view status, std::string_view headers, std::function<std::
}
std::thread(
- [status, headers, content](AutoCloseFD socket, AutoCloseFD trigger) {
+ [replies, at{0}](AutoCloseFD socket, AutoCloseFD trigger) mutable {
while (true) {
pollfd pfds[2] = {
{
@@ -90,12 +99,14 @@ serveHTTP(std::string_view status, std::string_view headers, std::function<std::
}
};
+ const auto & reply = replies[at++ % replies.size()];
+
send("HTTP/1.1 ");
- send(status);
+ send(reply.status);
send("\r\n");
- send(headers);
+ send(reply.headers);
send("\r\n");
- send(content());
+ send(reply.content());
::shutdown(conn.get(), SHUT_RDWR);
}
},
@@ -110,6 +121,12 @@ serveHTTP(std::string_view status, std::string_view headers, std::function<std::
};
}
+static std::tuple<uint16_t, AutoCloseFD>
+serveHTTP(std::string status, std::string headers, std::function<std::string()> content)
+{
+ return serveHTTP({{{status, headers, content}}});
+}
+
TEST(FileTransfer, exceptionAbortsDownload)
{
struct Done
@@ -166,4 +183,30 @@ TEST(FileTransfer, NOT_ON_DARWIN(handlesContentEncoding))
ft->download(FileTransferRequest(fmt("http://[::1]:%d/index", port)), sink);
EXPECT_EQ(sink.s, original);
}
+
+TEST(FileTransfer, usesIntermediateLinkHeaders)
+{
+ auto [port, srv] = serveHTTP({
+ {"301 ok",
+ "location: /second\r\n"
+ "content-length: 0\r\n",
+ [] { return ""; }},
+ {"307 ok",
+ "location: /third\r\n"
+ "content-length: 0\r\n",
+ [] { return ""; }},
+ {"307 ok",
+ "location: /fourth\r\n"
+ "link: <http://foo>; rel=\"immutable\"\r\n"
+ "content-length: 0\r\n",
+ [] { return ""; }},
+ {"200 ok", "content-length: 1\r\n", [] { return "a"; }},
+ });
+ auto ft = makeFileTransfer();
+ FileTransferRequest req(fmt("http://[::1]:%d/first", port));
+ req.baseRetryTimeMs = 0;
+ auto result = ft->download(req);
+ ASSERT_EQ(result.immutableUrl, "http://foo");
+}
+
}