From 2ad4ff803658033c800e409499bc10c99c96363c Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 31 Jan 2025 09:07:47 +0100 Subject: [PATCH] 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 --- .../extensionmanagerwidget.cpp | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.cpp b/src/plugins/extensionmanager/extensionmanagerwidget.cpp index 75aa4a723b7..01e59a7920e 100644 --- a/src/plugins/extensionmanager/extensionmanagerwidget.cpp +++ b/src/plugins/extensionmanager/extensionmanagerwidget.cpp @@ -665,6 +665,7 @@ void ExtensionManagerWidget::fetchAndInstallPlugin(const QUrl &url, const QStrin std::unique_ptr progressDialog; QByteArray packageData; QUrl url; + QString filename; }; Storage 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"(^(?Pattachment|inline)(?:\s*;\s*(?P.*))?$)"); + + 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()))