Prevent '%' in URL from causing crashes

We have a larger problem that passsing computed strings to the first
variable argument of many exception constructors is unsafe because that
first variable argument is interpreted not as a plain string, but format
string, and if it contains '%' boost::format will abort, since there are
no arguments to the format string.

In this particular instance '%' was used as part of an escape code in a
URL, which, when the download failed, caused Nix to abort displaying the
`FileTransferError`.
This commit is contained in:
John Ericson 2020-06-18 17:54:16 +00:00
parent 6c000eed80
commit 639e20dc3e

View file

@ -410,16 +410,13 @@ struct curlFileTransfer : public FileTransfer
auto exc = auto exc =
code == CURLE_ABORTED_BY_CALLBACK && _isInterrupted code == CURLE_ABORTED_BY_CALLBACK && _isInterrupted
? FileTransferError(Interrupted, fmt("%s of '%s' was interrupted", request.verb(), request.uri)) ? FileTransferError(Interrupted, "%s of '%s' was interrupted", request.verb(), request.uri)
: httpStatus != 0 : httpStatus != 0
? FileTransferError(err, ? FileTransferError(err, "unable to %s '%s': HTTP error %d%s",
fmt("unable to %s '%s': HTTP error %d", request.verb(), request.uri, httpStatus,
request.verb(), request.uri, httpStatus) code == CURLE_OK ? "" : fmt(" (curl error: %s)", curl_easy_strerror(code)))
+ (code == CURLE_OK ? "" : fmt(" (curl error: %s)", curl_easy_strerror(code))) : FileTransferError(err, "unable to %s '%s': %s (%d)",
) request.verb(), request.uri, curl_easy_strerror(code), code);
: FileTransferError(err,
fmt("unable to %s '%s': %s (%d)",
request.verb(), request.uri, curl_easy_strerror(code), code));
/* If this is a transient error, then maybe retry the /* If this is a transient error, then maybe retry the
download after a while. If we're writing to a download after a while. If we're writing to a
@ -675,7 +672,7 @@ struct curlFileTransfer : public FileTransfer
auto s3Res = s3Helper.getObject(bucketName, key); auto s3Res = s3Helper.getObject(bucketName, key);
FileTransferResult res; FileTransferResult res;
if (!s3Res.data) if (!s3Res.data)
throw FileTransferError(NotFound, fmt("S3 object '%s' does not exist", request.uri)); throw FileTransferError(NotFound, "S3 object '%s' does not exist", request.uri);
res.data = s3Res.data; res.data = s3Res.data;
callback(std::move(res)); callback(std::move(res));
#else #else