Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qrestreply.cpp
Go to the documentation of this file.
1
// Copyright (C) 2023 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:critical reason:data-parser
4
5
#
include
"qrestreply.h"
6
#
include
"qrestreply_p.h"
7
8
#
include
<
QtNetwork
/
private
/
qnetworkreply_p
.
h
>
9
#
include
<
QtNetwork
/
private
/
qrestaccessmanager_p
.
h
>
10
#
include
<
QtNetwork
/
private
/
qtcontenttypeparser_p
.
h
>
11
12
#
include
<
QtCore
/
qbytearrayview
.
h
>
13
#
include
<
QtCore
/
qjsondocument
.
h
>
14
#
include
<
QtCore
/
qlatin1stringmatcher
.
h
>
15
#
include
<
QtCore
/
qlatin1stringview
.
h
>
16
#
include
<
QtCore
/
qloggingcategory
.
h
>
17
#
include
<
QtCore
/
qstringconverter
.
h
>
18
19
#
include
<
QtCore
/
qxpfunctional
.
h
>
20
21
QT_BEGIN_NAMESPACE
22
23
using
namespace
Qt::StringLiterals;
24
25
/*!
26
\class QRestReply
27
\since 6.7
28
\brief QRestReply is a convenience wrapper for QNetworkReply.
29
30
\reentrant
31
\ingroup network
32
\inmodule QtNetwork
33
34
QRestReply wraps a QNetworkReply and provides convenience methods for data
35
and status handling. The methods provide convenience for typical RESTful
36
client applications.
37
38
QRestReply doesn't take ownership of the wrapped QNetworkReply, and the
39
lifetime and ownership of the reply is as defined by QNetworkAccessManager
40
documentation.
41
42
QRestReply object is not copyable, but is movable.
43
44
\sa QRestAccessManager, QNetworkReply, QNetworkAccessManager,
45
QNetworkAccessManager::setAutoDeleteReplies()
46
*/
47
48
/*!
49
Creates a QRestReply and initializes the wrapped QNetworkReply to \a reply.
50
*/
51
QRestReply
::QRestReply(QNetworkReply *reply)
52
: wrapped(reply)
53
{
54
if
(!wrapped)
55
qCWarning(lcQrest,
"QRestReply: QNetworkReply is nullptr"
);
56
}
57
58
/*!
59
Destroys this QRestReply object.
60
*/
61
QRestReply
::~
QRestReply
()
62
{
63
delete
d;
64
}
65
66
/*!
67
\fn QRestReply::QRestReply(QRestReply &&other) noexcept
68
69
Move-constructs the reply from \a other.
70
71
\note The moved-from object \a other is placed in a
72
partially-formed state, in which the only valid operations are
73
destruction and assignment of a new value.
74
*/
75
76
/*!
77
\fn QRestReply &QRestReply::operator=(QRestReply &&other) noexcept
78
79
Move-assigns \a other and returns a reference to this reply.
80
81
\note The moved-from object \a other is placed in a
82
partially-formed state, in which the only valid operations are
83
destruction and assignment of a new value.
84
*/
85
86
/*!
87
Returns a pointer to the underlying QNetworkReply wrapped by this object.
88
*/
89
QNetworkReply *
QRestReply
::networkReply()
const
90
{
91
return
wrapped;
92
}
93
94
/*!
95
Returns the received data as a QJsonDocument.
96
97
The returned value is wrapped in \c std::optional. If the conversion
98
from the received data fails (empty data or JSON parsing error),
99
\nullopt is returned, and \a error is filled with details.
100
101
Calling this function consumes the received data, and any further calls
102
to get response data will return empty.
103
104
This function returns \c {std::nullopt} and will not consume
105
any data if the reply is not finished. If \a error is passed, it will be
106
set to QJsonParseError::NoError to distinguish this case from an actual
107
error.
108
109
\sa readBody(), readText()
110
*/
111
std
::optional<QJsonDocument>
QRestReply
::readJson(QJsonParseError *error)
112
{
113
if
(!wrapped) {
114
if
(error)
115
*error = {0, QJsonParseError::ParseError::NoError};
116
return
std
::nullopt;
117
}
118
119
if
(!wrapped->isFinished()) {
120
qCWarning(lcQrest,
"readJson() called on an unfinished reply, ignoring"
);
121
if
(error)
122
*error = {0, QJsonParseError::ParseError::NoError};
123
return
std
::nullopt;
124
}
125
QJsonParseError parseError;
126
const
QByteArray
data = wrapped->readAll();
127
const
QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
128
if
(error)
129
*error = parseError;
130
if
(parseError.error)
131
return
std
::nullopt;
132
return
doc;
133
}
134
135
/*!
136
Returns the received data as a QByteArray.
137
138
Calling this function consumes the data received so far, and any further
139
calls to get response data will return empty until further data has been
140
received.
141
142
\sa readJson(), readText(), QNetworkReply::bytesAvailable(),
143
QNetworkReply::readyRead()
144
*/
145
QByteArray
QRestReply
::readBody()
146
{
147
return
wrapped ? wrapped->readAll() : QByteArray{};
148
}
149
150
/*!
151
Returns the received data as a QString.
152
153
The received data is decoded into a QString (UTF-16). If available, the decoding
154
uses the \e Content-Type header's \e charset parameter to determine the
155
source encoding. If the encoding information is not available or not supported
156
by \l QStringConverter, UTF-8 is used by default.
157
158
Calling this function consumes the data received so far. Returns
159
a default constructed value if no new data is available, or if the
160
decoding is not supported by \l QStringConverter, or if the decoding
161
has errors (for example invalid characters).
162
163
\sa readJson(), readBody(), QNetworkReply::readyRead()
164
*/
165
QString
QRestReply
::readText()
166
{
167
QString result;
168
if
(!wrapped)
169
return
result;
170
171
QByteArray
data = wrapped->readAll();
172
if
(data.isEmpty())
173
return
result;
174
175
// Text decoding needs to persist decoding state across calls to this function,
176
// so allocate decoder if not yet allocated.
177
if
(!d)
178
d =
new
QRestReplyPrivate
;
179
180
if
(!d->decoder) {
181
const
QByteArray
charset = QRestReplyPrivate::contentCharset(wrapped);
182
d->decoder.emplace(charset.constData());
183
if
(!d->decoder->isValid()) {
// the decoder may not support the mimetype's charset
184
qCWarning(lcQrest,
"readText(): Charset \"%s\" is not supported"
, charset.constData());
185
return
result;
186
}
187
}
188
// Check if the decoder already had an error, or has errors after decoding current data chunk
189
if
(d->decoder->hasError() || (result = (*d->decoder)(data), d->decoder->hasError())) {
190
qCWarning(lcQrest,
"readText(): Decoding error occurred"
);
191
return
{};
192
}
193
return
result;
194
}
195
196
/*!
197
Returns the HTTP status received in the server response.
198
The value is \e 0 if not available (the status line has not been received,
199
yet).
200
201
\note The HTTP status is reported as indicated by the received HTTP
202
response. An error() may occur after receiving the status, for instance
203
due to network disconnection while receiving a long response.
204
These potential subsequent errors are not represented by the reported
205
HTTP status.
206
207
\sa isSuccess(), hasError(), error()
208
*/
209
int
QRestReply
::
httpStatus
()
const
210
{
211
return
wrapped ? wrapped->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() : 0;
212
}
213
214
/*!
215
\fn bool QRestReply::isSuccess() const
216
217
Returns whether the HTTP status is between 200..299 and no
218
further errors have occurred while receiving the response (for example,
219
abrupt disconnection while receiving the body data). This function
220
is a convenient way to check whether the response is considered successful.
221
222
\sa httpStatus(), hasError(), error()
223
*/
224
225
/*!
226
Returns whether the HTTP status is between 200..299.
227
228
\sa isSuccess(), httpStatus(), hasError(), error()
229
*/
230
bool
QRestReply
::
isHttpStatusSuccess
()
const
231
{
232
const
int
status = httpStatus();
233
return
status >= 200 && status < 300;
234
}
235
236
/*!
237
Returns whether an error has occurred. This includes errors such as
238
network and protocol errors, but excludes cases where the server
239
successfully responded with an HTTP error status (for example
240
\c {500 Internal Server Error}). Use \l httpStatus() or
241
\l isHttpStatusSuccess() to get the HTTP status information.
242
243
\sa httpStatus(), isSuccess(), error(), errorString()
244
*/
245
bool
QRestReply
::
hasError
()
const
246
{
247
if
(!wrapped)
248
return
false
;
249
250
const
int
status = httpStatus();
251
if
(status > 0) {
252
// The HTTP status is set upon receiving the response headers, but the
253
// connection might still fail later while receiving the body data.
254
return
wrapped->error() == QNetworkReply::RemoteHostClosedError;
255
}
256
return
wrapped->error() != QNetworkReply::NoError;
257
}
258
259
/*!
260
Returns the last error, if any. The errors include
261
errors such as network and protocol errors, but exclude
262
cases when the server successfully responded with an HTTP status.
263
264
\sa httpStatus(), isSuccess(), hasError(), errorString()
265
*/
266
QNetworkReply::NetworkError
QRestReply
::error()
const
267
{
268
if
(!hasError())
269
return
QNetworkReply::NetworkError::NoError;
270
return
wrapped->error();
271
}
272
273
/*!
274
Returns a human-readable description of the last network error.
275
276
\sa httpStatus(), isSuccess(), hasError(), error()
277
*/
278
QString
QRestReply
::errorString()
const
279
{
280
if
(hasError())
281
return
wrapped->errorString();
282
return
{};
283
}
284
285
QRestReplyPrivate
::
QRestReplyPrivate
()
286
=
default
;
287
288
QRestReplyPrivate
::~
QRestReplyPrivate
()
289
=
default
;
290
291
#
ifndef
QT_NO_DEBUG_STREAM
292
static
QLatin1StringView
operationName
(QNetworkAccessManager::Operation operation)
293
{
294
switch
(operation) {
295
case
QNetworkAccessManager::Operation::GetOperation:
296
return
"GET"_L1
;
297
case
QNetworkAccessManager::Operation::HeadOperation:
298
return
"HEAD"_L1
;
299
case
QNetworkAccessManager::Operation::PostOperation:
300
return
"POST"_L1
;
301
case
QNetworkAccessManager::Operation::PutOperation:
302
return
"PUT"_L1
;
303
case
QNetworkAccessManager::Operation::DeleteOperation:
304
return
"DELETE"_L1
;
305
case
QNetworkAccessManager::Operation::CustomOperation:
306
return
"CUSTOM"_L1
;
307
case
QNetworkAccessManager::Operation::UnknownOperation:
308
return
"UNKNOWN"_L1
;
309
}
310
Q_UNREACHABLE_RETURN({});
311
}
312
313
/*!
314
\fn QDebug QRestReply::operator<<(QDebug debug, const QRestReply &reply)
315
316
Writes the \a reply into the \a debug object for debugging purposes.
317
318
\sa {Debugging Techniques}
319
*/
320
QDebug operator<<(QDebug debug,
const
QRestReply
&reply)
321
{
322
const
QDebugStateSaver saver(debug);
323
debug.resetFormat().nospace();
324
if
(!reply.networkReply()) {
325
debug <<
"QRestReply(no network reply)"
;
326
return
debug;
327
}
328
debug <<
"QRestReply(isSuccess = "
<< reply.isSuccess()
329
<<
", httpStatus = "
<< reply.httpStatus()
330
<<
", isHttpStatusSuccess = "
<< reply.isHttpStatusSuccess()
331
<<
", hasError = "
<< reply.hasError()
332
<<
", errorString = "
<< reply.errorString()
333
<<
", error = "
<< reply.error()
334
<<
", isFinished = "
<< reply.networkReply()->isFinished()
335
<<
", bytesAvailable = "
<< reply.networkReply()->bytesAvailable()
336
<<
", url "
<< reply.networkReply()->url()
337
<<
", operation = "
<< operationName(reply.networkReply()->operation())
338
<<
", reply headers = "
<< reply.networkReply()->headers()
339
<<
")"
;
340
return
debug;
341
}
342
#
endif
// QT_NO_DEBUG_STREAM
343
344
QByteArray
QRestReplyPrivate
::
contentCharset
(
const
QNetworkReply* reply)
345
{
346
// Content-type consists of mimetype and optional parameters, of which one may be 'charset'
347
// Example values and their combinations below are all valid, see RFC 7231 section 3.1.1.5
348
// and RFC 2045 section 5.1
349
//
350
// text/plain; charset=utf-8
351
// text/plain; charset=utf-8;version=1.7
352
// text/plain; charset = utf-8
353
// text/plain; charset ="utf-8"
354
355
const
QByteArray
contentTypeValue =
356
reply->headers().value(QHttpHeaders::WellKnownHeader::ContentType).toByteArray();
357
358
const
auto
r = QtContentTypeParser::parse_content_type(contentTypeValue);
359
if
(r && !r.charset.empty())
360
return
QByteArrayView(r.charset).toByteArray();
361
else
362
return
"UTF-8"_ba
;
// Default to the most commonly used UTF-8.
363
}
364
365
QT_END_NAMESPACE
QByteArray::FromBase64Result
\inmodule QtCore
Definition
qbytearray.h:824
QRestReplyPrivate
Definition
qrestreply_p.h:29
QRestReplyPrivate::contentCharset
static QByteArray contentCharset(const QNetworkReply *reply)
Definition
qrestreply.cpp:344
QRestReplyPrivate::~QRestReplyPrivate
~QRestReplyPrivate()
QRestReplyPrivate::QRestReplyPrivate
QRestReplyPrivate()
QRestReply
QRestReply is a convenience wrapper for QNetworkReply.
Definition
qrestreply.h:25
QRestReply::httpStatus
Q_NETWORK_EXPORT int httpStatus() const
Returns the HTTP status received in the server response.
Definition
qrestreply.cpp:209
QRestReply::isHttpStatusSuccess
Q_NETWORK_EXPORT bool isHttpStatusSuccess() const
Returns whether the HTTP status is between 200..299.
Definition
qrestreply.cpp:230
QRestReply::hasError
Q_NETWORK_EXPORT bool hasError() const
Returns whether an error has occurred.
Definition
qrestreply.cpp:245
QRestReply::~QRestReply
Q_NETWORK_EXPORT ~QRestReply()
Destroys this QRestReply object.
Definition
qrestreply.cpp:61
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
std
[33]
Definition
src_corelib_tools_qhash.cpp:421
operationName
static QLatin1StringView operationName(QNetworkAccessManager::Operation operation)
Definition
qrestreply.cpp:292
qtbase
src
network
access
qrestreply.cpp
Generated on
for Qt by
1.18.0