summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuha Vuolle <juha.vuolle@qt.io>2023-10-31 15:44:48 +0200
committerJuha Vuolle <juha.vuolle@qt.io>2023-12-08 15:53:36 +0200
commita80ed49b1049478957edca1cfbcd90f9f4b83cb3 (patch)
treecd094682c915c65ca5e3c7ad8ac5c500823fdae7
parent98b240d00a8e68c1d4f159d7ebb5f7802c442a8a (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>
-rw-r--r--src/network/access/qrestaccessmanager.cpp76
-rw-r--r--src/network/access/qrestaccessmanager.h25
-rw-r--r--src/network/doc/snippets/code/src_network_access_qrestaccessmanager.cpp7
-rw-r--r--tests/auto/network/access/qrestaccessmanager/httptestserver.cpp2
-rw-r--r--tests/auto/network/access/qrestaccessmanager/httptestserver_p.h1
-rw-r--r--tests/auto/network/access/qrestaccessmanager/tst_qrestaccessmanager.cpp19
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()