EM: Take filename from content-disposition

This allows us to get the real filename even from urls that do redirection.
Our unzip routine on Windows fails if the filename does not end in .zip
which this patch fixes as well by naming the file as intended.

Change-Id: I29746e67ce91953e1fee26d697a7f251527c54c4
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
Marcus Tillmanns
2025-01-31 09:07:47 +01:00
parent 15aa8e6246
commit 2ad4ff8036

View File

@@ -665,6 +665,7 @@ void ExtensionManagerWidget::fetchAndInstallPlugin(const QUrl &url, const QStrin
std::unique_ptr<QProgressDialog> progressDialog;
QByteArray packageData;
QUrl url;
QString filename;
};
Storage<StorageStruct> storage;
@@ -677,6 +678,37 @@ void ExtensionManagerWidget::fetchAndInstallPlugin(const QUrl &url, const QStrin
storage->progressDialog->close();
if (result == DoneWith::Success) {
storage->packageData = query.reply()->readAll();
QString contentDispo = QString::fromUtf8(
query.reply()->headers().value(QHttpHeaders::WellKnownHeader::ContentDisposition));
if (contentDispo.isEmpty())
return;
// Example: `content-disposition: attachment; filename=project-build-windows-.7z`
// see also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
static QRegularExpression re(
R"(^(?P<disposition>attachment|inline)(?:\s*;\s*(?P<paramlist>.*))?$)");
QRegularExpressionMatch matches = re.match(contentDispo);
if (!matches.hasMatch())
return;
const QString disposition = matches.captured("disposition");
if (disposition != "attachment")
return;
const QString paramlist = matches.captured("paramlist");
// Parse the "filename" parameter from the Content-Disposition header
static QRegularExpression reParam(
R"(filename\*?=['"]?(?:UTF-\d['"]*)?([^;\r\n"']*)['"]?;?)");
QRegularExpressionMatch match = reParam.match(paramlist);
if (!match.hasMatch())
return;
storage->filename = match.captured(1);
} else {
QMessageBox::warning(
ICore::dialogParent(),
@@ -690,8 +722,9 @@ void ExtensionManagerWidget::fetchAndInstallPlugin(const QUrl &url, const QStrin
if (storage->packageData.isEmpty())
return false;
const FilePath source = FilePath::fromUrl(storage->url);
TempFileSaver saver(
TemporaryDirectory::masterDirectoryPath() + "/XXXXXX-" + source.fileName());
const QString filename = storage->filename.isEmpty() ? source.fileName()
: storage->filename;
TempFileSaver saver(TemporaryDirectory::masterDirectoryPath() + "/XXXXXX-" + filename);
saver.write(storage->packageData);
if (saver.finalize(ICore::dialogParent()))