diff --git a/lix/libstore/filetransfer.cc b/lix/libstore/filetransfer.cc index d960f6878..511244479 100644 --- a/lix/libstore/filetransfer.cc +++ b/lix/libstore/filetransfer.cc @@ -509,6 +509,14 @@ struct curlFileTransfer : public FileTransfer std::map> items; + // clear all current transfers in case of an early exit, as can happen + // via Interrupted if the interruption occured right before a log call + KJ_DEFER({ + for (auto & [_, item] : items) { + item->finish(CURLE_ABORTED_BY_CALLBACK); + } + }); + bool quit = false; // NOTE: we will need to use CURLMOPT_TIMERFUNCTION to integrate this @@ -593,10 +601,15 @@ struct curlFileTransfer : public FileTransfer } catch (nix::Interrupted & e) { } catch (std::exception & e) { printError("unexpected error in download thread: %s", e.what()); + } catch (...) { + printError("unexpected error in download thread"); } { auto state(state_.lock()); + for (auto & item : state->incoming) { + item->finish(CURLE_ABORTED_BY_CALLBACK); + } state->incoming.clear(); state->quit = true; } diff --git a/tests/unit/libstore/filetransfer.cc b/tests/unit/libstore/filetransfer.cc index e998aaaf7..52369ee11 100644 --- a/tests/unit/libstore/filetransfer.cc +++ b/tests/unit/libstore/filetransfer.cc @@ -1,11 +1,13 @@ #include "lix/libstore/filetransfer.hh" #include "lix/libutil/compression.hh" +#include "lix/libutil/signals.hh" #include "lix/libutil/thread-name.hh" #include #include #include #include +#include #include #include #include @@ -395,4 +397,33 @@ TEST(FileTransfer, doesntRetryUploads) } } +// this test does not work unless run alone. we can't fork because that breaks +// the file transfer thread, restoring state is insufficient and very fragile. +TEST(FileTransfer, DISABLED_interrupt) +{ + struct InterruptingLogger : Logger + { + void log(Verbosity lvl, std::string_view s) override + { + if (s.starts_with("finished") && s.ends_with("body = 10 bytes")) { + triggerInterrupt(); + checkInterrupt(); + } + } + void logEI(const ErrorInfo & ei) override + { + } + }; + + verbosity = lvlDebug; + logger = new InterruptingLogger; + + auto ft = makeFileTransfer(0); + auto [port, srv] = serveHTTP({ + {"200 ok", "content-length: 10\r\n", [] { return "0123456789"; }}, + }); + + ASSERT_THROW(ft->download(fmt("http://[::1]:%d/index", port)).second->drain(), FileTransferError); +} + }