libstore/transfer: Warn by default instead of throw for destination changes

Fixes #1004

Change-Id: I2d583fbad40b3c95e37b70167a81c8fb492d5668
This commit is contained in:
Tom Hubrecht
2025-11-26 14:42:52 +01:00
parent 0c70cc6259
commit cb0f9b9590
2 changed files with 38 additions and 13 deletions
@@ -0,0 +1,10 @@
---
synopsis: "Warn instead of erroring when the final destination of a transfer changes in-flight"
cls: [4641]
issues: [fj#1004]
category: "Miscellany"
credits: [thubrecht]
---
Lix will now emit a warning during downloads where the final destination changes suddently mid-transfer instead of throwing an error.
This transfer behavior has been known to happen very rarely while fetching from some CDNs.
+28 -13
View File
@@ -1093,15 +1093,6 @@ struct curlFileTransfer : public FileTransfer
co_return result::current_exception();
}
void throwChangedTarget(std::string_view what, std::string_view from, std::string_view to)
{
if (!from.empty() && from != to) {
throw FileTransferError(
Misc, {}, "uri %s changed %s from %s to %s during transfer", uri, what, from, to
);
}
}
kj::Promise<Result<void>> prepareRetry(
const std::string & context,
const std::chrono::milliseconds & waitTime,
@@ -1135,17 +1126,41 @@ struct curlFileTransfer : public FileTransfer
kj::Promise<Result<void>> restartTransfer(const std::chrono::milliseconds & timeout)
try {
auto onChange =
[&](std::string_view what, std::string_view from, std::string_view to, bool throw_
) -> void {
if (!from.empty() && from != to) {
FileTransferError e = FileTransferError(
Misc,
{},
"uri %s changed %s from %s to %s during transfer",
uri,
what,
from,
to
);
if (throw_) {
throw e;
}
logWarning(e.info());
}
};
// use the effective URI of the previous transfer for retries. this avoids
// some silent corruption if a redirect changes between starting and retry
const auto & uri = metadata.effectiveUri.empty() ? this->uri : metadata.effectiveUri;
auto newMeta = TRY_AWAIT(startTransfer(uri, timeout, totalReceived));
throwChangedTarget("final destination", metadata.effectiveUri, newMeta.effectiveUri);
throwChangedTarget("ETag", metadata.etag, newMeta.etag);
throwChangedTarget(
onChange("final destination", metadata.effectiveUri, newMeta.effectiveUri, false);
onChange("ETag", metadata.etag, newMeta.etag, true);
onChange(
"immutable url",
metadata.immutableUrl.value_or(""),
newMeta.immutableUrl.value_or("")
newMeta.immutableUrl.value_or(""),
true
);
co_return result::success();
} catch (...) {