summaryrefslogtreecommitdiffstats
path: root/src/network/access/qrestreply.cpp
diff options
context:
space:
mode:
authorJuha Vuolle <juha.vuolle@qt.io>2024-01-19 11:33:39 +0200
committerJuha Vuolle <juha.vuolle@qt.io>2024-01-29 19:02:37 +0200
commit9ba5c7ff6aa42c5701cf950d2137467a2d178833 (patch)
tree59e5116c50e9a314cbec4a68267f719846f14e01 /src/network/access/qrestreply.cpp
parentbe6c651be4ccfa4f70009bcbb51bef39638e0fba (diff)
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 Pick-to: 6.7 Change-Id: Ib62d9cc2df41cac631396a84bb7ec4d2d54b0c8c Reviewed-by: Ivan Solovev <ivan.solovev@qt.io> Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Diffstat (limited to 'src/network/access/qrestreply.cpp')
-rw-r--r--src/network/access/qrestreply.cpp228
1 files changed, 58 insertions, 170 deletions
diff --git a/src/network/access/qrestreply.cpp b/src/network/access/qrestreply.cpp
index e9334a873cd..2cf8e19cb54 100644
--- a/src/network/access/qrestreply.cpp
+++ b/src/network/access/qrestreply.cpp
@@ -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;
-
-/*!
- Returns a pointer to the underlying QNetworkReply wrapped by this object.
-*/
-QNetworkReply *QRestReply::networkReply() const
{
- Q_D(const QRestReply);
- return d->networkReply;
+ delete d;
}
/*!
- Aborts the network operation immediately. The finished() signal
- will be emitted.
-
- \sa QRestAccessManager::abortRequests() QNetworkReply::abort()
+ Returns a pointer to the underlying QNetworkReply wrapped by this object.
*/
-void QRestReply::abort()
+QNetworkReply *QRestReply::networkReply() const
{
- 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"