Make QRest* APIs non-owning and non-duplicating
Note: documentation will be updated in a follow-up commit This commit makes QRestReply and QRestAccessManager classes lighter, non-owning wrappers. Furthermore their APIs don't duplicate the wrapped QNetwork* APIs. This makes it easier to use / opt-in to these helpers in pre-existing applications which are based on QNetworkAccessManager and QNetworkReply. Since APIs are no longer duplicated, the QRest classes are more obviously a convenience _wrapper_, as opposed to being an alternative vertical stack. In practice this change consists of: - QRestAM never instantiates QNetworkAccessManager, but accepts it via constructor. It does not take ownership of the QNetworkAccessManager. - QRestReply accepts QNetworkReply via constructor. It does not take ownership of the QNetworkReply - Signals and most duplicated functions are removed from both QRestAM and QRR. - QRestReply is no longer a QObject - Since QRestAM doesn't have much to report anymore, the debug operator is dropped. Resulted from API-review Change-Id: Ib62d9cc2df41cac631396a84bb7ec4d2d54b0c8c Reviewed-by: Ivan Solovev <ivan.solovev@qt.io> Reviewed-by: Marc Mutz <marc.mutz@qt.io> (cherry picked from commit 9ba5c7ff6aa42c5701cf950d2137467a2d178833)
This commit is contained in:
parent
a57f89251c
commit
afc1f2a6cc
@ -599,20 +599,13 @@ Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest")
|
||||
\overload
|
||||
*/
|
||||
|
||||
/*
|
||||
Memory management/object ownership:
|
||||
- QRestAM is parent of QNAM and QRestReplies
|
||||
- QRestReplies are parents of QNetworkReplies
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs a QRestAccessManager and sets \a parent as the parent object.
|
||||
*/
|
||||
QRestAccessManager::QRestAccessManager(QObject *parent)
|
||||
QRestAccessManager::QRestAccessManager(QNetworkAccessManager *manager, QObject *parent)
|
||||
: QObject(*new QRestAccessManagerPrivate, parent)
|
||||
{
|
||||
Q_D(QRestAccessManager);
|
||||
d->ensureNetworkAccessManager();
|
||||
d->qnam = manager;
|
||||
if (!d->qnam)
|
||||
qCWarning(lcQrest, "QRestAccessManager: QNetworkAccesManager is nullptr");
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -622,95 +615,6 @@ QRestAccessManager::QRestAccessManager(QObject *parent)
|
||||
QRestAccessManager::~QRestAccessManager()
|
||||
= default;
|
||||
|
||||
/*!
|
||||
Returns whether QRestAccessManager is currently configured to automatically
|
||||
delete replies once they have finished. By default this is \c true.
|
||||
|
||||
\sa setDeletesRepliesOnFinished()
|
||||
*/
|
||||
bool QRestAccessManager::deletesRepliesOnFinished() const
|
||||
{
|
||||
Q_D(const QRestAccessManager);
|
||||
return d->deletesRepliesOnFinished;
|
||||
}
|
||||
|
||||
/*!
|
||||
Enables or disables automatic deletion of QRestReply instances
|
||||
once the request has finished, according to the provided
|
||||
\a autoDelete parameter. The deletion is done with deleteLater()
|
||||
so that using the replies in directly-connected slots or callbacks is safe.
|
||||
|
||||
\sa deletesRepliesOnFinished()
|
||||
*/
|
||||
void QRestAccessManager::setDeletesRepliesOnFinished(bool autoDelete)
|
||||
{
|
||||
Q_D(QRestAccessManager);
|
||||
d->deletesRepliesOnFinished = autoDelete;
|
||||
}
|
||||
|
||||
/*!
|
||||
Aborts all unfinished network requests. Calling this function is same
|
||||
as calling QRestReply::abort() for all individual unfinished requests.
|
||||
|
||||
\sa QRestReply::abort(), QNetworkReply::abort()
|
||||
*/
|
||||
void QRestAccessManager::abortRequests()
|
||||
{
|
||||
Q_D(QRestAccessManager);
|
||||
|
||||
// Make copy of the reply container, as it might get modified when
|
||||
// aborting individual requests if they finish immediately
|
||||
const auto requests = d->activeRequests;
|
||||
for (const auto &[req, _] : requests.asKeyValueRange())
|
||||
req->abort();
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets \a timeout used for transfers.
|
||||
|
||||
\sa QNetworkAccessManager::setTransferTimeout(), transferTimeout(),
|
||||
QNetworkRequestFactory::setTransferTimeout()
|
||||
*/
|
||||
void QRestAccessManager::setTransferTimeout(std::chrono::milliseconds timeout)
|
||||
{
|
||||
Q_D(QRestAccessManager);
|
||||
d->qnam->setTransferTimeout(timeout);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the timeout used for transfers.
|
||||
|
||||
\sa setTransferTimeout(), QNetworkAccessManager::transferTimeoutAsDuration(),
|
||||
QNetworkRequestFactory::transferTimeout()
|
||||
*/
|
||||
std::chrono::milliseconds QRestAccessManager::transferTimeout() const
|
||||
{
|
||||
Q_D(const QRestAccessManager);
|
||||
return d->qnam->transferTimeoutAsDuration();
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
/*!
|
||||
\fn QDebug QRestAccessManager::operator<<(QDebug debug,
|
||||
const QRestAccessManager &manager)
|
||||
|
||||
Writes \a manager into \a debug stream.
|
||||
|
||||
\sa {Debugging Techniques}
|
||||
*/
|
||||
QDebug operator<<(QDebug debug, const QRestAccessManager &manager)
|
||||
{
|
||||
const QDebugStateSaver saver(debug);
|
||||
debug.resetFormat().nospace();
|
||||
|
||||
debug << "QRestAccessManager(deletesRepliesOnFinished = " << manager.deletesRepliesOnFinished()
|
||||
<< ", transferTimeout = " << manager.transferTimeout()
|
||||
<< ", active requests = " << manager.d_func()->activeRequests.size()
|
||||
<< ")";
|
||||
return debug;
|
||||
}
|
||||
#endif // QT_NO_DEBUG_STREAM
|
||||
|
||||
/*!
|
||||
Returns the underlying QNetworkAccessManager instance. The instance
|
||||
can be used for accessing less-frequently used features and configurations.
|
||||
@ -734,7 +638,7 @@ QRestAccessManagerPrivate::~QRestAccessManagerPrivate()
|
||||
}
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
|
||||
const QJsonObject &data, const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
@ -743,7 +647,7 @@ QRestReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
|
||||
data, request, context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
|
||||
const QJsonArray &data, const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
@ -752,14 +656,14 @@ QRestReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
|
||||
data, request, context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
|
||||
const QVariantMap &data, const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
return postWithDataImpl(request, QJsonObject::fromVariantMap(data), context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
|
||||
const QByteArray &data, const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
@ -767,7 +671,7 @@ QRestReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
|
||||
return d->executeRequest([&]() { return d->qnam->post(request, data); }, context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
|
||||
QHttpMultiPart *data, const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
@ -775,7 +679,7 @@ QRestReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
|
||||
return d->executeRequest([&]() { return d->qnam->post(request, data); }, context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
|
||||
QIODevice *data, const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
@ -783,14 +687,14 @@ QRestReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
|
||||
return d->executeRequest([&]() { return d->qnam->post(request, data); }, context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::getNoDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::getNoDataImpl(const QNetworkRequest &request,
|
||||
const QObject *context, QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
Q_D(QRestAccessManager);
|
||||
return d->executeRequest([&]() { return d->qnam->get(request); }, context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::getWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::getWithDataImpl(const QNetworkRequest &request,
|
||||
const QByteArray &data, const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
@ -798,7 +702,7 @@ QRestReply *QRestAccessManager::getWithDataImpl(const QNetworkRequest &request,
|
||||
return d->executeRequest([&]() { return d->qnam->get(request, data); }, context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::getWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::getWithDataImpl(const QNetworkRequest &request,
|
||||
const QJsonObject &data, const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
@ -807,7 +711,7 @@ QRestReply *QRestAccessManager::getWithDataImpl(const QNetworkRequest &request,
|
||||
data, request, context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::getWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::getWithDataImpl(const QNetworkRequest &request,
|
||||
QIODevice *data, const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
@ -815,21 +719,21 @@ QRestReply *QRestAccessManager::getWithDataImpl(const QNetworkRequest &request,
|
||||
return d->executeRequest([&]() { return d->qnam->get(request, data); }, context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::deleteResourceNoDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::deleteResourceNoDataImpl(const QNetworkRequest &request,
|
||||
const QObject *context, QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
Q_D(QRestAccessManager);
|
||||
return d->executeRequest([&]() { return d->qnam->deleteResource(request); }, context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::headNoDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::headNoDataImpl(const QNetworkRequest &request,
|
||||
const QObject *context, QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
Q_D(QRestAccessManager);
|
||||
return d->executeRequest([&]() { return d->qnam->head(request); }, context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
|
||||
const QJsonObject &data, const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
@ -838,7 +742,7 @@ QRestReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
|
||||
data, request, context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
|
||||
const QJsonArray &data, const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
@ -847,14 +751,14 @@ QRestReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
|
||||
data, request, context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
|
||||
const QVariantMap &data, const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
return putWithDataImpl(request, QJsonObject::fromVariantMap(data), context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
|
||||
const QByteArray &data, const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
@ -862,7 +766,7 @@ QRestReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
|
||||
return d->executeRequest([&]() { return d->qnam->put(request, data); }, context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
|
||||
QHttpMultiPart *data, const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
@ -870,7 +774,7 @@ QRestReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
|
||||
return d->executeRequest([&]() { return d->qnam->put(request, data); }, context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request, QIODevice *data,
|
||||
QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request, QIODevice *data,
|
||||
const QObject *context, QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
Q_D(QRestAccessManager);
|
||||
@ -879,7 +783,7 @@ QRestReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
|
||||
|
||||
static const auto PATCH = "PATCH"_ba;
|
||||
|
||||
QRestReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request,
|
||||
const QJsonObject &data, const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
@ -889,7 +793,7 @@ QRestReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request
|
||||
data, request, context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request,
|
||||
const QJsonArray &data, const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
@ -899,14 +803,14 @@ QRestReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request
|
||||
data, request, context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request,
|
||||
const QVariantMap &data, const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
return patchWithDataImpl(request, QJsonObject::fromVariantMap(data), context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request,
|
||||
const QByteArray &data, const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
@ -915,7 +819,7 @@ QRestReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request
|
||||
context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request, QIODevice *data,
|
||||
QNetworkReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request, QIODevice *data,
|
||||
const QObject *context, QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
Q_D(QRestAccessManager);
|
||||
@ -923,7 +827,7 @@ QRestReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request
|
||||
context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request,
|
||||
const QByteArray& method, const QByteArray &data,
|
||||
const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
@ -933,7 +837,7 @@ QRestReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &reques
|
||||
context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request,
|
||||
const QByteArray& method, QIODevice *data,
|
||||
const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
@ -943,7 +847,7 @@ QRestReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &reques
|
||||
context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request,
|
||||
QNetworkReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request,
|
||||
const QByteArray& method, QHttpMultiPart *data,
|
||||
const QObject *context,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
@ -953,32 +857,31 @@ QRestReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &reques
|
||||
context, slot);
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManagerPrivate::createActiveRequest(QNetworkReply *networkReply,
|
||||
const QObject *contextObject,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
QNetworkReply *QRestAccessManagerPrivate::createActiveRequest(QNetworkReply *reply,
|
||||
const QObject *contextObject,
|
||||
QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
Q_Q(QRestAccessManager);
|
||||
Q_ASSERT(networkReply);
|
||||
auto restReply = new QRestReply(networkReply, q);
|
||||
Q_ASSERT(reply);
|
||||
QtPrivate::SlotObjSharedPtr slotPtr(QtPrivate::SlotObjUniquePtr{slot}); // adopts
|
||||
activeRequests.insert(restReply, CallerInfo{contextObject, slotPtr});
|
||||
activeRequests.insert(reply, CallerInfo{contextObject, slotPtr});
|
||||
// The signal connections below are made to 'q' to avoid stray signal
|
||||
// handling upon its destruction while requests were still in progress
|
||||
|
||||
// If context object is provided, use it with connect => context object lifecycle is considered
|
||||
const QObject *context = contextObject ? contextObject : q;
|
||||
QObject::connect(networkReply, &QNetworkReply::finished, context, [restReply, this]() {
|
||||
handleReplyFinished(restReply);
|
||||
QObject::connect(reply, &QNetworkReply::finished, q, [reply, this]() {
|
||||
handleReplyFinished(reply);
|
||||
});
|
||||
// Safe guard in case reply is destroyed before it's finished
|
||||
QObject::connect(restReply, &QRestReply::destroyed, q, [restReply, this]() {
|
||||
activeRequests.remove(restReply);
|
||||
QObject::connect(reply, &QObject::destroyed, q, [reply, this]() {
|
||||
activeRequests.remove(reply);
|
||||
});
|
||||
// If context object is destroyed, clean up any possible replies it had associated with it
|
||||
if (contextObject) {
|
||||
QObject::connect(contextObject, &QObject::destroyed, q, [restReply, this]() {
|
||||
activeRequests.remove(restReply);
|
||||
QObject::connect(contextObject, &QObject::destroyed, q, [reply, this]() {
|
||||
activeRequests.remove(reply);
|
||||
});
|
||||
}
|
||||
return restReply;
|
||||
return reply;
|
||||
}
|
||||
|
||||
void QRestAccessManagerPrivate::verifyThreadAffinity(const QObject *contextObject)
|
||||
@ -994,27 +897,17 @@ void QRestAccessManagerPrivate::verifyThreadAffinity(const QObject *contextObjec
|
||||
}
|
||||
}
|
||||
|
||||
void QRestAccessManagerPrivate::ensureNetworkAccessManager()
|
||||
QNetworkReply* QRestAccessManagerPrivate::warnNoAccessManager()
|
||||
{
|
||||
Q_Q(QRestAccessManager);
|
||||
if (!qnam) {
|
||||
qnam = new QNetworkAccessManager(q);
|
||||
connect(qnam, &QNetworkAccessManager::authenticationRequired, this,
|
||||
&QRestAccessManagerPrivate::handleAuthenticationRequired);
|
||||
#ifndef QT_NO_NETWORKPROXY
|
||||
QObject::connect(qnam, &QNetworkAccessManager::proxyAuthenticationRequired,
|
||||
q, &QRestAccessManager::proxyAuthenticationRequired);
|
||||
#endif
|
||||
}
|
||||
qCWarning(lcQrest, "QRestAccessManager: QNetworkAccessManager not set");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void QRestAccessManagerPrivate::handleReplyFinished(QRestReply *restReply)
|
||||
void QRestAccessManagerPrivate::handleReplyFinished(QNetworkReply *reply)
|
||||
{
|
||||
Q_Q(QRestAccessManager);
|
||||
|
||||
auto request = activeRequests.find(restReply);
|
||||
auto request = activeRequests.find(reply);
|
||||
if (request == activeRequests.end()) {
|
||||
qCWarning(lcQrest, "Unexpected reply received, ignoring");
|
||||
qCDebug(lcQrest, "QRestAccessManager: Unexpected reply received, ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1022,41 +915,14 @@ void QRestAccessManagerPrivate::handleReplyFinished(QRestReply *restReply)
|
||||
activeRequests.erase(request);
|
||||
|
||||
if (caller.slot) {
|
||||
// Callback was provided. If we have context object, use it.
|
||||
// For clarity: being here with a context object means it has not been destroyed
|
||||
// while the request has been in progress
|
||||
// Callback was provided
|
||||
QRestReply restReply(reply);
|
||||
void *argv[] = { nullptr, &restReply };
|
||||
// If we have context object, use it
|
||||
QObject *context = caller.contextObject
|
||||
? const_cast<QObject*>(caller.contextObject) : nullptr;
|
||||
? const_cast<QObject*>(caller.contextObject.get()) : nullptr;
|
||||
caller.slot->call(context, argv);
|
||||
}
|
||||
if (restReply->hasError())
|
||||
emit restReply->errorOccurred(restReply);
|
||||
emit restReply->finished(restReply);
|
||||
emit q->requestFinished(restReply);
|
||||
|
||||
if (deletesRepliesOnFinished)
|
||||
restReply->deleteLater();
|
||||
}
|
||||
|
||||
void QRestAccessManagerPrivate::handleAuthenticationRequired(QNetworkReply *networkReply,
|
||||
QAuthenticator *authenticator)
|
||||
{
|
||||
Q_Q(QRestAccessManager);
|
||||
QRestReply *restReply = restReplyFromNetworkReply(networkReply);
|
||||
if (restReply)
|
||||
emit q->authenticationRequired(restReply, authenticator);
|
||||
else
|
||||
qCWarning(lcQrest, "No matching QRestReply for authentication, ignoring.");
|
||||
}
|
||||
|
||||
QRestReply *QRestAccessManagerPrivate::restReplyFromNetworkReply(QNetworkReply *networkReply)
|
||||
{
|
||||
for (const auto &[restReply,_] : activeRequests.asKeyValueRange()) {
|
||||
if (restReply->networkReply() == networkReply)
|
||||
return restReply;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -6,8 +6,6 @@
|
||||
|
||||
#include <QtNetwork/qnetworkaccessmanager.h>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QDebug;
|
||||
@ -16,57 +14,57 @@ class QRestReply;
|
||||
#define QREST_METHOD_WITH_DATA(METHOD, DATA) \
|
||||
public: \
|
||||
template <typename Functor, if_compatible_callback<Functor> = true> \
|
||||
QRestReply *METHOD(const QNetworkRequest &request, DATA data, \
|
||||
QNetworkReply *METHOD(const QNetworkRequest &request, DATA data, \
|
||||
const ContextTypeForFunctor<Functor> *context, \
|
||||
Functor &&callback) \
|
||||
{ \
|
||||
return METHOD##WithDataImpl(request, data, context, \
|
||||
QtPrivate::makeCallableObject<CallbackPrototype>(std::forward<Functor>(callback))); \
|
||||
} \
|
||||
QRestReply *METHOD(const QNetworkRequest &request, DATA data) \
|
||||
QNetworkReply *METHOD(const QNetworkRequest &request, DATA data) \
|
||||
{ \
|
||||
return METHOD##WithDataImpl(request, data, nullptr, nullptr); \
|
||||
} \
|
||||
private: \
|
||||
QRestReply *METHOD##WithDataImpl(const QNetworkRequest &request, DATA data, \
|
||||
QNetworkReply *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> \
|
||||
QRestReply *METHOD(const QNetworkRequest &request, \
|
||||
QNetworkReply *METHOD(const QNetworkRequest &request, \
|
||||
const ContextTypeForFunctor<Functor> *context, \
|
||||
Functor &&callback) \
|
||||
{ \
|
||||
return METHOD##NoDataImpl(request, context, \
|
||||
QtPrivate::makeCallableObject<CallbackPrototype>(std::forward<Functor>(callback))); \
|
||||
} \
|
||||
QRestReply *METHOD(const QNetworkRequest &request) \
|
||||
QNetworkReply *METHOD(const QNetworkRequest &request) \
|
||||
{ \
|
||||
return METHOD##NoDataImpl(request, nullptr, nullptr); \
|
||||
} \
|
||||
private: \
|
||||
QRestReply *METHOD##NoDataImpl(const QNetworkRequest &request, \
|
||||
QNetworkReply *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, \
|
||||
QNetworkReply *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) \
|
||||
QNetworkReply *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, \
|
||||
QNetworkReply *customWithDataImpl(const QNetworkRequest& request, const QByteArray &method, \
|
||||
DATA data, const QObject* context, \
|
||||
QtPrivate::QSlotObjectBase *slot); \
|
||||
/* end */
|
||||
@ -75,27 +73,18 @@ class QRestAccessManagerPrivate;
|
||||
class Q_NETWORK_EXPORT QRestAccessManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
using CallbackPrototype = void(*)(QRestReply*);
|
||||
using CallbackPrototype = void(*)(QRestReply&);
|
||||
template <typename Functor>
|
||||
using ContextTypeForFunctor = typename QtPrivate::ContextTypeForFunctor<Functor>::ContextType;
|
||||
template <typename Functor>
|
||||
using if_compatible_callback = std::enable_if_t<
|
||||
QtPrivate::AreFunctionsCompatible<CallbackPrototype, Functor>::value, bool>;
|
||||
public:
|
||||
explicit QRestAccessManager(QObject *parent = nullptr);
|
||||
explicit QRestAccessManager(QNetworkAccessManager *manager, QObject *parent = nullptr);
|
||||
~QRestAccessManager() override;
|
||||
|
||||
QNetworkAccessManager *networkAccessManager() const;
|
||||
|
||||
bool deletesRepliesOnFinished() const;
|
||||
void setDeletesRepliesOnFinished(bool autoDelete);
|
||||
|
||||
void setTransferTimeout(std::chrono::milliseconds timeout);
|
||||
std::chrono::milliseconds transferTimeout() const;
|
||||
|
||||
void abortRequests();
|
||||
|
||||
QREST_METHOD_NO_DATA(deleteResource)
|
||||
QREST_METHOD_NO_DATA(head)
|
||||
QREST_METHOD_NO_DATA(get)
|
||||
@ -123,17 +112,7 @@ public:
|
||||
QREST_METHOD_CUSTOM_WITH_DATA(QIODevice *)
|
||||
QREST_METHOD_CUSTOM_WITH_DATA(QHttpMultiPart *)
|
||||
|
||||
Q_SIGNALS:
|
||||
#ifndef QT_NO_NETWORKPROXY
|
||||
void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator);
|
||||
#endif
|
||||
void authenticationRequired(QRestReply *reply, QAuthenticator *authenticator);
|
||||
void requestFinished(QRestReply *reply);
|
||||
|
||||
private:
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
friend Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QRestAccessManager &manager);
|
||||
#endif
|
||||
Q_DECLARE_PRIVATE(QRestAccessManager)
|
||||
Q_DISABLE_COPY(QRestAccessManager)
|
||||
};
|
||||
|
@ -34,30 +34,28 @@ public:
|
||||
QRestAccessManagerPrivate();
|
||||
~QRestAccessManagerPrivate() override;
|
||||
|
||||
void ensureNetworkAccessManager();
|
||||
|
||||
QRestReply *createActiveRequest(QNetworkReply *networkReply, const QObject *contextObject,
|
||||
QtPrivate::QSlotObjectBase *slot);
|
||||
|
||||
void removeActiveRequest(QRestReply *restReply);
|
||||
void handleReplyFinished(QRestReply *restReply);
|
||||
void handleAuthenticationRequired(QNetworkReply *networkReply, QAuthenticator *authenticator);
|
||||
QRestReply *restReplyFromNetworkReply(QNetworkReply *networkReply);
|
||||
QNetworkReply* createActiveRequest(QNetworkReply *reply, const QObject *contextObject,
|
||||
QtPrivate::QSlotObjectBase *slot);
|
||||
void handleReplyFinished(QNetworkReply *reply);
|
||||
|
||||
template<typename Functor>
|
||||
QRestReply *executeRequest(Functor requestOperation,
|
||||
QNetworkReply *executeRequest(Functor requestOperation,
|
||||
const QObject *context, QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
if (!qnam)
|
||||
return warnNoAccessManager();
|
||||
verifyThreadAffinity(context);
|
||||
QNetworkReply *reply = requestOperation();
|
||||
return createActiveRequest(reply, context, slot);
|
||||
}
|
||||
|
||||
template<typename Functor, typename Json>
|
||||
QRestReply *executeRequest(Functor requestOperation, Json jsonData,
|
||||
QNetworkReply *executeRequest(Functor requestOperation, Json jsonData,
|
||||
const QNetworkRequest &request,
|
||||
const QObject *context, QtPrivate::QSlotObjectBase *slot)
|
||||
{
|
||||
if (!qnam)
|
||||
return warnNoAccessManager();
|
||||
verifyThreadAffinity(context);
|
||||
QNetworkRequest req(request);
|
||||
if (!request.header(QNetworkRequest::ContentTypeHeader).isValid()) {
|
||||
@ -70,12 +68,14 @@ public:
|
||||
}
|
||||
|
||||
void verifyThreadAffinity(const QObject *contextObject);
|
||||
Q_DECL_COLD_FUNCTION
|
||||
QNetworkReply* warnNoAccessManager();
|
||||
|
||||
struct CallerInfo {
|
||||
const QObject *contextObject = nullptr;
|
||||
QPointer<const QObject> contextObject = nullptr;
|
||||
QtPrivate::SlotObjSharedPtr slot;
|
||||
};
|
||||
QHash<QRestReply*, CallerInfo> activeRequests;
|
||||
QHash<QNetworkReply*, CallerInfo> activeRequests;
|
||||
|
||||
QNetworkAccessManager *qnam = nullptr;
|
||||
bool deletesRepliesOnFinished = true;
|
||||
|
@ -35,121 +35,27 @@ Q_DECLARE_LOGGING_CATEGORY(lcQrest)
|
||||
\sa QRestAccessManager, QNetworkReply
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QRestReply::readyRead(QRestReply *reply)
|
||||
|
||||
This signal is emitted when \a reply has received new data.
|
||||
|
||||
\sa body(), bytesAvailable(), isFinished()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QRestReply::downloadProgress(qint64 bytesReceived,
|
||||
qint64 bytesTotal,
|
||||
QRestReply* reply)
|
||||
|
||||
This signal is emitted to indicate the progress of the download part of
|
||||
this network \a reply.
|
||||
|
||||
The \a bytesReceived parameter indicates the number of bytes received,
|
||||
while \a bytesTotal indicates the total number of bytes expected to be
|
||||
downloaded. If the number of bytes to be downloaded is not known, for
|
||||
instance due to a missing \c Content-Length header, \a bytesTotal
|
||||
will be -1.
|
||||
|
||||
See \l QNetworkReply::downloadProgress() documentation for more details.
|
||||
|
||||
\sa bytesAvailable(), readyRead(), uploadProgress()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QRestReply::uploadProgress(qint64 bytesSent, qint64 bytesTotal,
|
||||
QRestReply* reply)
|
||||
|
||||
This signal is emitted to indicate the progress of the upload part of
|
||||
\a reply.
|
||||
|
||||
The \a bytesSent parameter indicates the number of bytes already uploaded,
|
||||
while \a bytesTotal indicates the total number of bytes still to upload.
|
||||
|
||||
If the number of bytes to upload is not known, \a bytesTotal will be -1.
|
||||
|
||||
See \l QNetworkReply::uploadProgress() documentation for more details.
|
||||
|
||||
\sa QNetworkReply::uploadProgress(), downloadProgress()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QRestReply::finished(QRestReply *reply)
|
||||
|
||||
This signal is emitted when \a reply has finished processing. This
|
||||
signal is emitted also in cases when the reply finished due to network
|
||||
or protocol errors (the server did not reply with an HTTP status).
|
||||
|
||||
\sa isFinished(), httpStatus(), error()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QRestReply::errorOccurred(QRestReply *reply)
|
||||
|
||||
This signal is emitted if, while processing \a reply, an error occurs that
|
||||
is considered to be a network/protocol error. These errors are
|
||||
disctinct from HTTP error responses such as \c {500 Internal Server Error}.
|
||||
This signal is emitted together with the
|
||||
finished() signal, and often connecting to that is sufficient.
|
||||
|
||||
\sa finished(), isFinished(), httpStatus(), error()
|
||||
*/
|
||||
|
||||
QRestReply::QRestReply(QNetworkReply *reply, QObject *parent)
|
||||
: QObject(*new QRestReplyPrivate, parent)
|
||||
QRestReply::QRestReply(QNetworkReply *reply)
|
||||
: wrapped(reply)
|
||||
{
|
||||
Q_D(QRestReply);
|
||||
Q_ASSERT(reply);
|
||||
d->networkReply = reply;
|
||||
// Reparent so that destruction of QRestReply destroys QNetworkReply
|
||||
reply->setParent(this);
|
||||
|
||||
QObject::connect(reply, &QNetworkReply::readyRead, this, [this] {
|
||||
emit readyRead(this);
|
||||
});
|
||||
QObject::connect(reply, &QNetworkReply::downloadProgress, this,
|
||||
[this](qint64 bytesReceived, qint64 bytesTotal) {
|
||||
emit downloadProgress(bytesReceived, bytesTotal, this);
|
||||
});
|
||||
QObject::connect(reply, &QNetworkReply::uploadProgress, this,
|
||||
[this] (qint64 bytesSent, qint64 bytesTotal) {
|
||||
emit uploadProgress(bytesSent, bytesTotal, this);
|
||||
});
|
||||
if (!wrapped)
|
||||
qCWarning(lcQrest, "QRestReply: QNetworkReply is nullptr");
|
||||
}
|
||||
|
||||
/*!
|
||||
Destroys this QRestReply object.
|
||||
|
||||
\sa abort()
|
||||
*/
|
||||
QRestReply::~QRestReply()
|
||||
= default;
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a pointer to the underlying QNetworkReply wrapped by this object.
|
||||
*/
|
||||
QNetworkReply *QRestReply::networkReply() const
|
||||
{
|
||||
Q_D(const QRestReply);
|
||||
return d->networkReply;
|
||||
}
|
||||
|
||||
/*!
|
||||
Aborts the network operation immediately. The finished() signal
|
||||
will be emitted.
|
||||
|
||||
\sa QRestAccessManager::abortRequests() QNetworkReply::abort()
|
||||
*/
|
||||
void QRestReply::abort()
|
||||
{
|
||||
Q_D(QRestReply);
|
||||
d->networkReply->abort();
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -167,19 +73,24 @@ void QRestReply::abort()
|
||||
set to QJsonParseError::NoError to distinguish this case from an actual
|
||||
error.
|
||||
|
||||
\sa body(), text(), finished(), isFinished()
|
||||
\sa body(), text()
|
||||
*/
|
||||
std::optional<QJsonDocument> QRestReply::json(QJsonParseError *error)
|
||||
{
|
||||
Q_D(QRestReply);
|
||||
if (!isFinished()) {
|
||||
if (!wrapped) {
|
||||
if (error)
|
||||
*error = {0, QJsonParseError::ParseError::NoError};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!wrapped->isFinished()) {
|
||||
qCWarning(lcQrest, "Attempt to read json() of an unfinished reply, ignoring.");
|
||||
if (error)
|
||||
*error = {0, QJsonParseError::ParseError::NoError};
|
||||
return std::nullopt;
|
||||
}
|
||||
QJsonParseError parseError;
|
||||
const QByteArray data = d->networkReply->readAll();
|
||||
const QByteArray data = wrapped->readAll();
|
||||
const QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
|
||||
if (error)
|
||||
*error = parseError;
|
||||
@ -199,8 +110,7 @@ std::optional<QJsonDocument> QRestReply::json(QJsonParseError *error)
|
||||
*/
|
||||
QByteArray QRestReply::body()
|
||||
{
|
||||
Q_D(QRestReply);
|
||||
return d->networkReply->readAll();
|
||||
return wrapped ? wrapped->readAll() : QByteArray{};
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -221,15 +131,21 @@ QByteArray QRestReply::body()
|
||||
*/
|
||||
QString QRestReply::text()
|
||||
{
|
||||
Q_D(QRestReply);
|
||||
QString result;
|
||||
if (!wrapped)
|
||||
return result;
|
||||
|
||||
QByteArray data = d->networkReply->readAll();
|
||||
QByteArray data = wrapped->readAll();
|
||||
if (data.isEmpty())
|
||||
return result;
|
||||
|
||||
// Text decoding needs to persist decoding state across calls to this function,
|
||||
// so allocate decoder if not yet allocated.
|
||||
if (!d)
|
||||
d = new QRestReplyPrivate;
|
||||
|
||||
if (!d->decoder) {
|
||||
const QByteArray charset = d->contentCharset();
|
||||
const QByteArray charset = QRestReplyPrivate::contentCharset(wrapped);
|
||||
d->decoder = QStringDecoder(charset);
|
||||
if (!d->decoder->isValid()) { // the decoder may not support the mimetype's charset
|
||||
qCWarning(lcQrest, "text(): Charset \"%s\" is not supported", charset.constData());
|
||||
@ -259,8 +175,7 @@ QString QRestReply::text()
|
||||
*/
|
||||
int QRestReply::httpStatus() const
|
||||
{
|
||||
Q_D(const QRestReply);
|
||||
return d->networkReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
return wrapped ? wrapped->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() : 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -296,8 +211,16 @@ bool QRestReply::isHttpStatusSuccess() const
|
||||
*/
|
||||
bool QRestReply::hasError() const
|
||||
{
|
||||
Q_D(const QRestReply);
|
||||
return d->hasNonHttpError();
|
||||
if (!wrapped)
|
||||
return false;
|
||||
|
||||
const int status = httpStatus();
|
||||
if (status > 0) {
|
||||
// The HTTP status is set upon receiving the response headers, but the
|
||||
// connection might still fail later while receiving the body data.
|
||||
return wrapped->error() == QNetworkReply::RemoteHostClosedError;
|
||||
}
|
||||
return wrapped->error() != QNetworkReply::NoError;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -309,10 +232,9 @@ bool QRestReply::hasError() const
|
||||
*/
|
||||
QNetworkReply::NetworkError QRestReply::error() const
|
||||
{
|
||||
Q_D(const QRestReply);
|
||||
if (!hasError())
|
||||
return QNetworkReply::NetworkError::NoError;
|
||||
return d->networkReply->error();
|
||||
return wrapped->error();
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -322,32 +244,11 @@ QNetworkReply::NetworkError QRestReply::error() const
|
||||
*/
|
||||
QString QRestReply::errorString() const
|
||||
{
|
||||
Q_D(const QRestReply);
|
||||
if (hasError())
|
||||
return d->networkReply->errorString();
|
||||
return wrapped->errorString();
|
||||
return {};
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns whether the network request has finished.
|
||||
*/
|
||||
bool QRestReply::isFinished() const
|
||||
{
|
||||
Q_D(const QRestReply);
|
||||
return d->networkReply->isFinished();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the number of bytes available.
|
||||
|
||||
\sa body
|
||||
*/
|
||||
qint64 QRestReply::bytesAvailable() const
|
||||
{
|
||||
Q_D(const QRestReply);
|
||||
return d->networkReply->bytesAvailable();
|
||||
}
|
||||
|
||||
QRestReplyPrivate::QRestReplyPrivate()
|
||||
= default;
|
||||
|
||||
@ -377,38 +278,37 @@ static QLatin1StringView operationName(QNetworkAccessManager::Operation operatio
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn QDebug QRestReply::operator<<(QDebug debug, const QRestReply *reply)
|
||||
\fn QDebug QRestReply::operator<<(QDebug debug, const QRestReply &reply)
|
||||
|
||||
Writes the \a reply into the \a debug object for debugging purposes.
|
||||
|
||||
\sa {Debugging Techniques}
|
||||
*/
|
||||
QDebug operator<<(QDebug debug, const QRestReply *reply)
|
||||
QDebug operator<<(QDebug debug, const QRestReply &reply)
|
||||
{
|
||||
const QDebugStateSaver saver(debug);
|
||||
debug.resetFormat().nospace();
|
||||
if (!reply) {
|
||||
debug << "QRestReply(nullptr)";
|
||||
if (!reply.networkReply()) {
|
||||
debug << "QRestReply(no network reply)";
|
||||
return debug;
|
||||
}
|
||||
|
||||
debug << "QRestReply(isSuccess = " << reply->isSuccess()
|
||||
<< ", httpStatus = " << reply->httpStatus()
|
||||
<< ", isHttpStatusSuccess = " << reply->isHttpStatusSuccess()
|
||||
<< ", hasError = " << reply->hasError()
|
||||
<< ", errorString = " << reply->errorString()
|
||||
<< ", error = " << reply->error()
|
||||
<< ", isFinished = " << reply->isFinished()
|
||||
<< ", bytesAvailable = " << reply->bytesAvailable()
|
||||
<< ", url " << reply->networkReply()->url()
|
||||
<< ", operation = " << operationName(reply->networkReply()->operation())
|
||||
<< ", reply headers = " << reply->networkReply()->rawHeaderPairs()
|
||||
debug << "QRestReply(isSuccess = " << reply.isSuccess()
|
||||
<< ", httpStatus = " << reply.httpStatus()
|
||||
<< ", isHttpStatusSuccess = " << reply.isHttpStatusSuccess()
|
||||
<< ", hasError = " << reply.hasError()
|
||||
<< ", errorString = " << reply.errorString()
|
||||
<< ", error = " << reply.error()
|
||||
<< ", isFinished = " << reply.networkReply()->isFinished()
|
||||
<< ", bytesAvailable = " << reply.networkReply()->bytesAvailable()
|
||||
<< ", url " << reply.networkReply()->url()
|
||||
<< ", operation = " << operationName(reply.networkReply()->operation())
|
||||
<< ", reply headers = " << reply.networkReply()->rawHeaderPairs()
|
||||
<< ")";
|
||||
return debug;
|
||||
}
|
||||
#endif // QT_NO_DEBUG_STREAM
|
||||
|
||||
QByteArray QRestReplyPrivate::contentCharset() const
|
||||
QByteArray QRestReplyPrivate::contentCharset(const QNetworkReply* reply)
|
||||
{
|
||||
// Content-type consists of mimetype and optional parameters, of which one may be 'charset'
|
||||
// Example values and their combinations below are all valid, see RFC 7231 section 3.1.1.5
|
||||
@ -418,10 +318,10 @@ QByteArray QRestReplyPrivate::contentCharset() const
|
||||
// text/plain; charset=utf-8;version=1.7
|
||||
// text/plain; charset = utf-8
|
||||
// text/plain; charset ="utf-8"
|
||||
QByteArray contentTypeValue =
|
||||
networkReply->header(QNetworkRequest::KnownHeaders::ContentTypeHeader).toByteArray();
|
||||
// Default to the most commonly used UTF-8.
|
||||
QByteArray charset{"UTF-8"};
|
||||
const QByteArray contentTypeValue =
|
||||
reply->header(QNetworkRequest::KnownHeaders::ContentTypeHeader).toByteArray();
|
||||
|
||||
QList<QByteArray> parameters = contentTypeValue.split(';');
|
||||
if (parameters.size() >= 2) { // Need at least one parameter in addition to the mimetype itself
|
||||
@ -442,18 +342,6 @@ QByteArray QRestReplyPrivate::contentCharset() const
|
||||
return charset;
|
||||
}
|
||||
|
||||
// Returns true if there's an error that isn't appropriately indicated by the HTTP status
|
||||
bool QRestReplyPrivate::hasNonHttpError() const
|
||||
{
|
||||
const int status = networkReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
if (status > 0) {
|
||||
// The HTTP status is set upon receiving the response headers, but the
|
||||
// connection might still fail later while receiving the body data.
|
||||
return networkReply->error() == QNetworkReply::RemoteHostClosedError;
|
||||
}
|
||||
return networkReply->error() != QNetworkReply::NoError;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#include "moc_qrestreply.cpp"
|
||||
|
@ -6,7 +6,10 @@
|
||||
|
||||
#include <QtNetwork/qnetworkreply.h>
|
||||
|
||||
#include <QtCore/qpointer.h>
|
||||
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -17,53 +20,52 @@ class QJsonDocument;
|
||||
class QString;
|
||||
|
||||
class QRestReplyPrivate;
|
||||
class Q_NETWORK_EXPORT QRestReply : public QObject
|
||||
class QRestReply
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
~QRestReply() override;
|
||||
Q_NETWORK_EXPORT explicit QRestReply(QNetworkReply *reply);
|
||||
Q_NETWORK_EXPORT ~QRestReply();
|
||||
|
||||
QNetworkReply *networkReply() const;
|
||||
QRestReply(QRestReply &&other) noexcept
|
||||
: wrapped(std::move(other.wrapped)),
|
||||
d(std::exchange(other.d, nullptr))
|
||||
{
|
||||
}
|
||||
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QRestReply)
|
||||
void swap(QRestReply &other) noexcept
|
||||
{
|
||||
wrapped.swap(other.wrapped);
|
||||
std::swap(d, other.d);
|
||||
}
|
||||
|
||||
std::optional<QJsonDocument> json(QJsonParseError *error = nullptr);
|
||||
QByteArray body();
|
||||
QString text();
|
||||
Q_NETWORK_EXPORT QNetworkReply *networkReply() const;
|
||||
|
||||
Q_NETWORK_EXPORT std::optional<QJsonDocument> json(QJsonParseError *error = nullptr);
|
||||
Q_NETWORK_EXPORT QByteArray body();
|
||||
Q_NETWORK_EXPORT QString text();
|
||||
|
||||
bool isSuccess() const
|
||||
{
|
||||
return !hasError() && isHttpStatusSuccess();
|
||||
}
|
||||
int httpStatus() const;
|
||||
bool isHttpStatusSuccess() const;
|
||||
Q_NETWORK_EXPORT int httpStatus() const;
|
||||
Q_NETWORK_EXPORT bool isHttpStatusSuccess() const;
|
||||
|
||||
bool hasError() const;
|
||||
QNetworkReply::NetworkError error() const;
|
||||
QString errorString() const;
|
||||
|
||||
bool isFinished() const;
|
||||
qint64 bytesAvailable() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void abort();
|
||||
|
||||
Q_SIGNALS:
|
||||
void finished(QRestReply *reply);
|
||||
void errorOccurred(QRestReply *reply);
|
||||
void readyRead(QRestReply *reply);
|
||||
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal, QRestReply *reply);
|
||||
void uploadProgress(qint64 bytesSent, qint64 bytesTotal, QRestReply* reply);
|
||||
Q_NETWORK_EXPORT bool hasError() const;
|
||||
Q_NETWORK_EXPORT QNetworkReply::NetworkError error() const;
|
||||
Q_NETWORK_EXPORT QString errorString() const;
|
||||
|
||||
private:
|
||||
friend class QRestAccessManagerPrivate;
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
friend Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QRestReply *reply);
|
||||
friend Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QRestReply &reply);
|
||||
#endif
|
||||
explicit QRestReply(QNetworkReply *reply, QObject *parent = nullptr);
|
||||
Q_DECLARE_PRIVATE(QRestReply)
|
||||
Q_DISABLE_COPY_MOVE(QRestReply)
|
||||
QPointer<QNetworkReply> wrapped;
|
||||
QRestReplyPrivate *d = nullptr;
|
||||
Q_DISABLE_COPY(QRestReply)
|
||||
};
|
||||
|
||||
Q_DECLARE_SHARED(QRestReply)
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QRESTREPLY_H
|
||||
|
@ -15,27 +15,22 @@
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include "private/qobject_p.h"
|
||||
#include <QtNetwork/qnetworkreply.h>
|
||||
#include <QtCore/qjsondocument.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QNetworkReply;
|
||||
class QStringDecoder;
|
||||
|
||||
class QRestReplyPrivate : public QObjectPrivate
|
||||
class QRestReplyPrivate
|
||||
{
|
||||
public:
|
||||
QRestReplyPrivate();
|
||||
~QRestReplyPrivate() override;
|
||||
~QRestReplyPrivate();
|
||||
|
||||
QNetworkReply *networkReply = nullptr;
|
||||
std::optional<QStringDecoder> decoder;
|
||||
|
||||
QByteArray contentCharset() const;
|
||||
bool hasNonHttpError() const;
|
||||
static QByteArray contentCharset(const QNetworkReply *reply);
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user