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>
This commit is contained in:
parent
98b240d00a
commit
a80ed49b10
@ -109,6 +109,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest")
|
|||||||
\li \c put()
|
\li \c put()
|
||||||
\li \c head()
|
\li \c head()
|
||||||
\li \c deleteResource()
|
\li \c deleteResource()
|
||||||
|
\li \c sendCustomRequest()
|
||||||
\row
|
\row
|
||||||
\li No data
|
\li No data
|
||||||
\li X
|
\li X
|
||||||
@ -116,6 +117,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest")
|
|||||||
\li -
|
\li -
|
||||||
\li X
|
\li X
|
||||||
\li X
|
\li X
|
||||||
|
\li -
|
||||||
\row
|
\row
|
||||||
\li QByteArray
|
\li QByteArray
|
||||||
\li X
|
\li X
|
||||||
@ -123,6 +125,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest")
|
|||||||
\li X
|
\li X
|
||||||
\li -
|
\li -
|
||||||
\li -
|
\li -
|
||||||
|
\li X
|
||||||
\row
|
\row
|
||||||
\li QJsonObject *)
|
\li QJsonObject *)
|
||||||
\li X
|
\li X
|
||||||
@ -130,6 +133,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest")
|
|||||||
\li X
|
\li X
|
||||||
\li -
|
\li -
|
||||||
\li -
|
\li -
|
||||||
|
\li -
|
||||||
\row
|
\row
|
||||||
\li QJsonArray *)
|
\li QJsonArray *)
|
||||||
\li -
|
\li -
|
||||||
@ -137,6 +141,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest")
|
|||||||
\li X
|
\li X
|
||||||
\li -
|
\li -
|
||||||
\li -
|
\li -
|
||||||
|
\li -
|
||||||
\row
|
\row
|
||||||
\li QVariantMap **)
|
\li QVariantMap **)
|
||||||
\li -
|
\li -
|
||||||
@ -144,6 +149,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest")
|
|||||||
\li X
|
\li X
|
||||||
\li -
|
\li -
|
||||||
\li -
|
\li -
|
||||||
|
\li -
|
||||||
\row
|
\row
|
||||||
\li QHttpMultiPart
|
\li QHttpMultiPart
|
||||||
\li -
|
\li -
|
||||||
@ -151,6 +157,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest")
|
|||||||
\li X
|
\li X
|
||||||
\li -
|
\li -
|
||||||
\li -
|
\li -
|
||||||
|
\li X
|
||||||
\row
|
\row
|
||||||
\li QIODevice
|
\li QIODevice
|
||||||
\li X
|
\li X
|
||||||
@ -158,6 +165,7 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest")
|
|||||||
\li X
|
\li X
|
||||||
\li -
|
\li -
|
||||||
\li -
|
\li -
|
||||||
|
\li X
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
*) QJsonObject and QJsonArray are sent in \l QJsonDocument::Compact format,
|
*) QJsonObject and QJsonArray are sent in \l QJsonDocument::Compact format,
|
||||||
@ -476,6 +484,44 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest")
|
|||||||
QRestAccessManager::requestFinished()
|
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:
|
Memory management/object ownership:
|
||||||
- QRestAM is parent of QNAM and QRestReplies
|
- 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);
|
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,
|
QRestReply *QRestAccessManagerPrivate::createActiveRequest(QNetworkReply *networkReply,
|
||||||
const QObject *contextObject,
|
const QObject *contextObject,
|
||||||
QtPrivate::QSlotObjectBase *slot)
|
QtPrivate::QSlotObjectBase *slot)
|
||||||
|
@ -32,7 +32,6 @@ QRestReply *METHOD##WithDataImpl(const QNetworkRequest &request, DATA data,
|
|||||||
const QObject *context, QtPrivate::QSlotObjectBase *slot); \
|
const QObject *context, QtPrivate::QSlotObjectBase *slot); \
|
||||||
/* end */
|
/* end */
|
||||||
|
|
||||||
|
|
||||||
#define QREST_METHOD_NO_DATA(METHOD) \
|
#define QREST_METHOD_NO_DATA(METHOD) \
|
||||||
public: \
|
public: \
|
||||||
template <typename Functor, if_compatible_callback<Functor> = true> \
|
template <typename Functor, if_compatible_callback<Functor> = true> \
|
||||||
@ -52,6 +51,26 @@ QRestReply *METHOD##NoDataImpl(const QNetworkRequest &request,
|
|||||||
const QObject *context, QtPrivate::QSlotObjectBase *slot); \
|
const QObject *context, QtPrivate::QSlotObjectBase *slot); \
|
||||||
/* end */
|
/* 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 QRestAccessManagerPrivate;
|
||||||
class Q_NETWORK_EXPORT QRestAccessManager : public QObject
|
class Q_NETWORK_EXPORT QRestAccessManager : public QObject
|
||||||
{
|
{
|
||||||
@ -95,6 +114,9 @@ public:
|
|||||||
QREST_METHOD_WITH_DATA(put, const QByteArray &)
|
QREST_METHOD_WITH_DATA(put, const QByteArray &)
|
||||||
QREST_METHOD_WITH_DATA(put, QHttpMultiPart *)
|
QREST_METHOD_WITH_DATA(put, QHttpMultiPart *)
|
||||||
QREST_METHOD_WITH_DATA(put, QIODevice *)
|
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:
|
Q_SIGNALS:
|
||||||
#ifndef QT_NO_NETWORKPROXY
|
#ifndef QT_NO_NETWORKPROXY
|
||||||
@ -113,6 +135,7 @@ private:
|
|||||||
|
|
||||||
#undef QREST_METHOD_NO_DATA
|
#undef QREST_METHOD_NO_DATA
|
||||||
#undef QREST_METHOD_WITH_DATA
|
#undef QREST_METHOD_WITH_DATA
|
||||||
|
#undef QREST_METHOD_CUSTOM_WITH_DATA
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
@ -82,3 +82,10 @@ manager->deleteResource(request, this, [this](QRestReply *reply) {
|
|||||||
});
|
});
|
||||||
//! [8]
|
//! [8]
|
||||||
|
|
||||||
|
|
||||||
|
//! [9]
|
||||||
|
manager->sendCustomRequest(request, "MYMETHOD", myData, this, [this](QRestReply *reply) {
|
||||||
|
if (reply->isSuccess())
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
//! [9]
|
||||||
|
@ -151,6 +151,8 @@ bool HttpTestServer::readMethod(QTcpSocket *socket)
|
|||||||
method = Method::Post;
|
method = Method::Post;
|
||||||
else if (fragment == "DELETE")
|
else if (fragment == "DELETE")
|
||||||
method = Method::Delete;
|
method = Method::Delete;
|
||||||
|
else if (fragment == "FOOBAR") // used by custom verb/method tests
|
||||||
|
method = Method::Custom;
|
||||||
else
|
else
|
||||||
qWarning("Invalid operation %s", fragment.data());
|
qWarning("Invalid operation %s", fragment.data());
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ public:
|
|||||||
Put,
|
Put,
|
||||||
Post,
|
Post,
|
||||||
Delete,
|
Delete,
|
||||||
|
Custom,
|
||||||
} method = Method::Unknown;
|
} method = Method::Unknown;
|
||||||
|
|
||||||
// Parsing helpers for incoming data => HttpData
|
// Parsing helpers for incoming data => HttpData
|
||||||
|
@ -108,6 +108,7 @@ void tst_QRestAccessManager::networkRequestReply()
|
|||||||
const QByteArray methodPOST{"POST"_ba};
|
const QByteArray methodPOST{"POST"_ba};
|
||||||
const QByteArray methodGET{"GET"_ba};
|
const QByteArray methodGET{"GET"_ba};
|
||||||
const QByteArray methodPUT{"PUT"_ba};
|
const QByteArray methodPUT{"PUT"_ba};
|
||||||
|
const QByteArray methodCUSTOM{"FOOBAR"_ba};
|
||||||
|
|
||||||
// DELETE
|
// DELETE
|
||||||
manager.deleteResource(request, this, callback);
|
manager.deleteResource(request, this, callback);
|
||||||
@ -136,6 +137,22 @@ void tst_QRestAccessManager::networkRequestReply()
|
|||||||
VERIFY_REPLY_OK(methodGET);
|
VERIFY_REPLY_OK(methodGET);
|
||||||
QCOMPARE(serverSideRequest.body, ioDeviceData);
|
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
|
// POST
|
||||||
manager.post(request, byteArrayData, this, callback);
|
manager.post(request, byteArrayData, this, callback);
|
||||||
VERIFY_REPLY_OK(methodPOST);
|
VERIFY_REPLY_OK(methodPOST);
|
||||||
@ -206,6 +223,8 @@ void tst_QRestAccessManager::networkRequestReply()
|
|||||||
//manager.head(request, "f"_ba); // data not allowed
|
//manager.head(request, "f"_ba); // data not allowed
|
||||||
//manager.post(request, ""_ba, this, [](int param){}); // Wrong callback signature
|
//manager.post(request, ""_ba, this, [](int param){}); // Wrong callback signature
|
||||||
//manager.get(request, 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()
|
void tst_QRestAccessManager::abort()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user