diff options
author | Juha Vuolle <juha.vuolle@qt.io> | 2023-10-31 15:44:48 +0200 |
---|---|---|
committer | Juha Vuolle <juha.vuolle@qt.io> | 2023-12-08 15:53:36 +0200 |
commit | a80ed49b1049478957edca1cfbcd90f9f4b83cb3 (patch) | |
tree | cd094682c915c65ca5e3c7ad8ac5c500823fdae7 | |
parent | 98b240d00a8e68c1d4f159d7ebb5f7802c442a8a (diff) |
QRestAM custom HTTP 'method' support
This commit adds support for sending custom, non-standard, HTTP
methods / verbs.
Fixes: QTBUG-116262
Change-Id: I77addb389a7e4346b63526176bf8323696a7a337
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
6 files changed, 129 insertions, 1 deletions
diff --git a/src/network/access/qrestaccessmanager.cpp b/src/network/access/qrestaccessmanager.cpp index 59f7151d59..2a2c1247d8 100644 --- a/src/network/access/qrestaccessmanager.cpp +++ b/src/network/access/qrestaccessmanager.cpp @@ -109,6 +109,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest") \li \c put() \li \c head() \li \c deleteResource() + \li \c sendCustomRequest() \row \li No data \li X @@ -116,6 +117,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest") \li - \li X \li X + \li - \row \li QByteArray \li X @@ -123,6 +125,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest") \li X \li - \li - + \li X \row \li QJsonObject *) \li X @@ -130,6 +133,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest") \li X \li - \li - + \li - \row \li QJsonArray *) \li - @@ -137,6 +141,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest") \li X \li - \li - + \li - \row \li QVariantMap **) \li - @@ -144,6 +149,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest") \li X \li - \li - + \li - \row \li QHttpMultiPart \li - @@ -151,6 +157,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest") \li X \li - \li - + \li X \row \li QIODevice \li X @@ -158,6 +165,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest") \li X \li - \li - + \li X \endtable *) QJsonObject and QJsonArray are sent in \l QJsonDocument::Compact format, @@ -476,6 +484,44 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest") QRestAccessManager::requestFinished() */ +/*! + \fn template<typename Functor, if_compatible_callback<Functor>> QRestReply *QRestAccessManager::sendCustomRequest( + const QNetworkRequest& request, const QByteArray &method, const QByteArray &data, + const ContextTypeForFunctor<Functor> *context, + Functor &&callback) + + Issues \a request based HTTP request with custom \a method and the + provided \a data. + + The optional \a callback and \a context object can be provided for + handling the request completion as illustrated below: + + \snippet code/src_network_access_qrestaccessmanager.cpp 9 + + Alternatively the signals of the returned QRestReply* object can be + used. For further information see + \l {Issuing Network Requests and Handling Replies}. + +*/ + +/*! + \fn template<typename Functor, if_compatible_callback<Functor>> QRestReply *QRestAccessManager::sendCustomRequest( + const QNetworkRequest& request, const QByteArray &method, QIODevice *data, + const ContextTypeForFunctor<Functor> *context, + Functor &&callback) + + \overload +*/ + +/*! + \fn template<typename Functor, if_compatible_callback<Functor>> QRestReply *QRestAccessManager::sendCustomRequest( + const QNetworkRequest& request, const QByteArray &method, QHttpMultiPart *data, + const ContextTypeForFunctor<Functor> *context, + Functor &&callback) + + \overload +*/ + /* Memory management/object ownership: - QRestAM is parent of QNAM and QRestReplies @@ -754,6 +800,36 @@ QRestReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request, return d->executeRequest([&]() { return d->qnam->put(request, data); }, context, slot); } +QRestReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request, + const QByteArray& method, const QByteArray &data, + const QObject *context, + QtPrivate::QSlotObjectBase *slot) +{ + Q_D(QRestAccessManager); + return d->executeRequest([&]() { return d->qnam->sendCustomRequest(request, method, data); }, + context, slot); +} + +QRestReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request, + const QByteArray& method, QIODevice *data, + const QObject *context, + QtPrivate::QSlotObjectBase *slot) +{ + Q_D(QRestAccessManager); + return d->executeRequest([&]() { return d->qnam->sendCustomRequest(request, method, data); }, + context, slot); +} + +QRestReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request, + const QByteArray& method, QHttpMultiPart *data, + const QObject *context, + QtPrivate::QSlotObjectBase *slot) +{ + Q_D(QRestAccessManager); + return d->executeRequest([&]() { return d->qnam->sendCustomRequest(request, method, data); }, + context, slot); +} + QRestReply *QRestAccessManagerPrivate::createActiveRequest(QNetworkReply *networkReply, const QObject *contextObject, QtPrivate::QSlotObjectBase *slot) diff --git a/src/network/access/qrestaccessmanager.h b/src/network/access/qrestaccessmanager.h index cfb083a96d..3ff23bee90 100644 --- a/src/network/access/qrestaccessmanager.h +++ b/src/network/access/qrestaccessmanager.h @@ -32,7 +32,6 @@ QRestReply *METHOD##WithDataImpl(const QNetworkRequest &request, DATA data, const QObject *context, QtPrivate::QSlotObjectBase *slot); \ /* end */ - #define QREST_METHOD_NO_DATA(METHOD) \ public: \ template <typename Functor, if_compatible_callback<Functor> = true> \ @@ -52,6 +51,26 @@ QRestReply *METHOD##NoDataImpl(const QNetworkRequest &request, const QObject *context, QtPrivate::QSlotObjectBase *slot); \ /* end */ +#define QREST_METHOD_CUSTOM_WITH_DATA(DATA) \ +public: \ +template <typename Functor, if_compatible_callback<Functor> = true> \ +QRestReply *sendCustomRequest(const QNetworkRequest& request, const QByteArray &method, DATA data, \ + const ContextTypeForFunctor<Functor> *context, \ + Functor &&callback) \ +{ \ + return customWithDataImpl(request, method, data, context, \ + QtPrivate::makeCallableObject<CallbackPrototype>(std::forward<Functor>(callback))); \ +} \ +QRestReply *sendCustomRequest(const QNetworkRequest& request, const QByteArray &method, DATA data) \ +{ \ + return customWithDataImpl(request, method, data, nullptr, nullptr); \ +} \ +private: \ +QRestReply *customWithDataImpl(const QNetworkRequest& request, const QByteArray &method, \ + DATA data, const QObject* context, \ + QtPrivate::QSlotObjectBase *slot); \ +/* end */ + class QRestAccessManagerPrivate; class Q_NETWORK_EXPORT QRestAccessManager : public QObject { @@ -95,6 +114,9 @@ public: QREST_METHOD_WITH_DATA(put, const QByteArray &) QREST_METHOD_WITH_DATA(put, QHttpMultiPart *) QREST_METHOD_WITH_DATA(put, QIODevice *) + QREST_METHOD_CUSTOM_WITH_DATA(const QByteArray &) + QREST_METHOD_CUSTOM_WITH_DATA(QIODevice *) + QREST_METHOD_CUSTOM_WITH_DATA(QHttpMultiPart *) Q_SIGNALS: #ifndef QT_NO_NETWORKPROXY @@ -113,6 +135,7 @@ private: #undef QREST_METHOD_NO_DATA #undef QREST_METHOD_WITH_DATA +#undef QREST_METHOD_CUSTOM_WITH_DATA QT_END_NAMESPACE diff --git a/src/network/doc/snippets/code/src_network_access_qrestaccessmanager.cpp b/src/network/doc/snippets/code/src_network_access_qrestaccessmanager.cpp index 89c7348483..20bb5d521d 100644 --- a/src/network/doc/snippets/code/src_network_access_qrestaccessmanager.cpp +++ b/src/network/doc/snippets/code/src_network_access_qrestaccessmanager.cpp @@ -82,3 +82,10 @@ manager->deleteResource(request, this, [this](QRestReply *reply) { }); //! [8] + +//! [9] +manager->sendCustomRequest(request, "MYMETHOD", myData, this, [this](QRestReply *reply) { + if (reply->isSuccess()) + // ... +}); +//! [9] diff --git a/tests/auto/network/access/qrestaccessmanager/httptestserver.cpp b/tests/auto/network/access/qrestaccessmanager/httptestserver.cpp index ac58834812..dfa2b45063 100644 --- a/tests/auto/network/access/qrestaccessmanager/httptestserver.cpp +++ b/tests/auto/network/access/qrestaccessmanager/httptestserver.cpp @@ -151,6 +151,8 @@ bool HttpTestServer::readMethod(QTcpSocket *socket) method = Method::Post; else if (fragment == "DELETE") method = Method::Delete; + else if (fragment == "FOOBAR") // used by custom verb/method tests + method = Method::Custom; else qWarning("Invalid operation %s", fragment.data()); diff --git a/tests/auto/network/access/qrestaccessmanager/httptestserver_p.h b/tests/auto/network/access/qrestaccessmanager/httptestserver_p.h index dd4b9024a0..d1819fcc21 100644 --- a/tests/auto/network/access/qrestaccessmanager/httptestserver_p.h +++ b/tests/auto/network/access/qrestaccessmanager/httptestserver_p.h @@ -56,6 +56,7 @@ public: Put, Post, Delete, + Custom, } method = Method::Unknown; // Parsing helpers for incoming data => HttpData diff --git a/tests/auto/network/access/qrestaccessmanager/tst_qrestaccessmanager.cpp b/tests/auto/network/access/qrestaccessmanager/tst_qrestaccessmanager.cpp index 50c01b4239..f66968bf1c 100644 --- a/tests/auto/network/access/qrestaccessmanager/tst_qrestaccessmanager.cpp +++ b/tests/auto/network/access/qrestaccessmanager/tst_qrestaccessmanager.cpp @@ -108,6 +108,7 @@ void tst_QRestAccessManager::networkRequestReply() const QByteArray methodPOST{"POST"_ba}; const QByteArray methodGET{"GET"_ba}; const QByteArray methodPUT{"PUT"_ba}; + const QByteArray methodCUSTOM{"FOOBAR"_ba}; // DELETE manager.deleteResource(request, this, callback); @@ -136,6 +137,22 @@ void tst_QRestAccessManager::networkRequestReply() VERIFY_REPLY_OK(methodGET); QCOMPARE(serverSideRequest.body, ioDeviceData); + // CUSTOM + manager.sendCustomRequest(request, methodCUSTOM, byteArrayData, this, callback); + VERIFY_REPLY_OK(methodCUSTOM); + QCOMPARE(serverSideRequest.body, byteArrayData); + + manager.sendCustomRequest(request, methodCUSTOM, &bufferIoDevice, this, callback); + VERIFY_REPLY_OK(methodCUSTOM); + QCOMPARE(serverSideRequest.body, ioDeviceData); + + multiPart.reset(new QHttpMultiPart(QHttpMultiPart::FormDataType)); + multiPart->append(part); + manager.sendCustomRequest(request, methodCUSTOM, multiPart.get(), this, callback); + VERIFY_REPLY_OK(methodCUSTOM); + QVERIFY(serverSideRequest.body.contains("--boundary"_ba)); + QVERIFY(serverSideRequest.body.contains("multipart_text"_ba)); + // POST manager.post(request, byteArrayData, this, callback); VERIFY_REPLY_OK(methodPOST); @@ -206,6 +223,8 @@ void tst_QRestAccessManager::networkRequestReply() //manager.head(request, "f"_ba); // data not allowed //manager.post(request, ""_ba, this, [](int param){}); // Wrong callback signature //manager.get(request, this, [](int param){}); // Wrong callback signature + //manager.sendCustomRequest(request, this, [](){}); // No verb && no data + //manager.sendCustomRequest(request, "FOOBAR", this, [](){}); // No verb || no data } void tst_QRestAccessManager::abort() |