From 60bb819e2e839d691dec6915d592d4a2c66d1de2 Mon Sep 17 00:00:00 2001 From: Vladimir Golovnev Date: Mon, 12 Feb 2024 09:07:09 +0300 Subject: [PATCH] Allow WebAPI to specify filename and mime type for result data PR #20377. --- src/webui/api/apicontroller.cpp | 23 ++++++++++++++++------- src/webui/api/apicontroller.h | 20 ++++++++++++++------ src/webui/api/torrentscontroller.cpp | 2 +- src/webui/webapplication.cpp | 17 ++++++++++++----- 4 files changed, 43 insertions(+), 19 deletions(-) diff --git a/src/webui/api/apicontroller.cpp b/src/webui/api/apicontroller.cpp index 2d0aeb8aa..3792029a7 100644 --- a/src/webui/api/apicontroller.cpp +++ b/src/webui/api/apicontroller.cpp @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2018, 2022 Vladimir Golovnev + * Copyright (C) 2018-2024 Vladimir Golovnev * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -37,12 +37,19 @@ #include "apierror.h" +void APIResult::clear() +{ + data.clear(); + mimeType.clear(); + filename.clear(); +} + APIController::APIController(IApplication *app, QObject *parent) : ApplicationComponent(app, parent) { } -QVariant APIController::run(const QString &action, const StringMap ¶ms, const DataMap &data) +APIResult APIController::run(const QString &action, const StringMap ¶ms, const DataMap &data) { m_result.clear(); // clear result m_params = params; @@ -79,20 +86,22 @@ void APIController::requireParams(const QVector &requiredParams) const void APIController::setResult(const QString &result) { - m_result = result; + m_result.data = result; } void APIController::setResult(const QJsonArray &result) { - m_result = QJsonDocument(result); + m_result.data = QJsonDocument(result); } void APIController::setResult(const QJsonObject &result) { - m_result = QJsonDocument(result); + m_result.data = QJsonDocument(result); } -void APIController::setResult(const QByteArray &result) +void APIController::setResult(const QByteArray &result, const QString &mimeType, const QString &filename) { - m_result = result; + m_result.data = result; + m_result.mimeType = mimeType; + m_result.filename = filename; } diff --git a/src/webui/api/apicontroller.h b/src/webui/api/apicontroller.h index b81f7b642..2d29e3f2e 100644 --- a/src/webui/api/apicontroller.h +++ b/src/webui/api/apicontroller.h @@ -1,6 +1,6 @@ /* * Bittorrent Client using Qt and libtorrent. - * Copyright (C) 2018, 2022 Vladimir Golovnev + * Copyright (C) 2018-2024 Vladimir Golovnev * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -30,15 +30,23 @@ #include #include +#include #include #include "base/applicationcomponent.h" -class QString; - using DataMap = QHash; using StringMap = QHash; +struct APIResult +{ + QVariant data; + QString mimeType; + QString filename; + + void clear(); +}; + class APIController : public ApplicationComponent { Q_OBJECT @@ -47,7 +55,7 @@ class APIController : public ApplicationComponent public: explicit APIController(IApplication *app, QObject *parent = nullptr); - QVariant run(const QString &action, const StringMap ¶ms, const DataMap &data = {}); + APIResult run(const QString &action, const StringMap ¶ms, const DataMap &data = {}); protected: const StringMap ¶ms() const; @@ -57,10 +65,10 @@ protected: void setResult(const QString &result); void setResult(const QJsonArray &result); void setResult(const QJsonObject &result); - void setResult(const QByteArray &result); + void setResult(const QByteArray &result, const QString &mimeType = {}, const QString &filename = {}); private: StringMap m_params; DataMap m_data; - QVariant m_result; + APIResult m_result; }; diff --git a/src/webui/api/torrentscontroller.cpp b/src/webui/api/torrentscontroller.cpp index 242a4a34a..8dd5c8319 100644 --- a/src/webui/api/torrentscontroller.cpp +++ b/src/webui/api/torrentscontroller.cpp @@ -1442,5 +1442,5 @@ void TorrentsController::exportAction() if (!result) throw APIError(APIErrorType::Conflict, tr("Unable to export torrent file. Error: %1").arg(result.error())); - setResult(result.value()); + setResult(result.value(), u"application/x-bittorrent"_s, (id.toString() + u".torrent")); } diff --git a/src/webui/webapplication.cpp b/src/webui/webapplication.cpp index 85b3ed724..b615728ca 100644 --- a/src/webui/webapplication.cpp +++ b/src/webui/webapplication.cpp @@ -352,18 +352,25 @@ void WebApplication::doProcessRequest() try { - const QVariant result = controller->run(action, m_params, data); - switch (result.userType()) + const APIResult result = controller->run(action, m_params, data); + switch (result.data.userType()) { case QMetaType::QJsonDocument: - print(result.toJsonDocument().toJson(QJsonDocument::Compact), Http::CONTENT_TYPE_JSON); + print(result.data.toJsonDocument().toJson(QJsonDocument::Compact), Http::CONTENT_TYPE_JSON); break; case QMetaType::QByteArray: - print(result.toByteArray(), Http::CONTENT_TYPE_TXT); + { + const auto resultData = result.data.toByteArray(); + print(resultData, (!result.mimeType.isEmpty() ? result.mimeType : Http::CONTENT_TYPE_TXT)); + if (!result.filename.isEmpty()) + { + setHeader({u"Content-Disposition"_s, u"attachment; filename=\"%1\""_s.arg(result.filename)}); + } + } break; case QMetaType::QString: default: - print(result.toString(), Http::CONTENT_TYPE_TXT); + print(result.data.toString(), Http::CONTENT_TYPE_TXT); break; } }