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()))