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
4#include "qrestaccessmanager.h"
5#include "qrestaccessmanager_p.h"
6#include "qrestreply.h"
7
8#include <QtNetwork/qhttpmultipart.h>
9#include <QtNetwork/qnetworkaccessmanager.h>
10#include <QtNetwork/qnetworkreply.h>
11
12#include <QtCore/qjsondocument.h>
13#include <QtCore/qjsonobject.h>
14#include <QtCore/qloggingcategory.h>
15#include <QtCore/qthread.h>
16
17QT_BEGIN_NAMESPACE
18
19using namespace Qt::StringLiterals;
20
21Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest")
22
23/*!
24
25 \class QRestAccessManager
26 \brief The QRestAccessManager is a convenience wrapper for
27 QNetworkAccessManager.
28 \since 6.7
29
30 \ingroup network
31 \inmodule QtNetwork
32 \reentrant
33
34 QRestAccessManager is a convenience wrapper on top of
35 QNetworkAccessManager. It amends datatypes and HTTP methods
36 that are useful for typical RESTful client applications.
37
38 The usual Qt networking features are accessible by configuring the
39 wrapped QNetworkAccessManager directly. QRestAccessManager does not
40 take ownership of the wrapped QNetworkAccessManager.
41
42 QRestAccessManager and related QRestReply classes can only be used in the
43 thread they live in. See \l {QObject#Thread Affinity}{QObject thread affinity}
44 for more information.
45
46 \section1 Issuing Network Requests and Handling Replies
47
48 Network requests are initiated with a function call corresponding to
49 the desired HTTP method, such as \c get() and \c post().
50
51 \section2 Using Signals and Slots
52
53 The function returns a QNetworkReply* object, whose signals can be used
54 to follow up on the completion of the request in a traditional
55 Qt-signals-and-slots way.
56
57 Here's an example of how you could send a GET request and handle the
58 response:
59
60 \snippet code/src_network_access_qrestaccessmanager.cpp 0
61
62 \section2 Using Callbacks and Context Objects
63
64 The functions also take a context object of QObject (subclass) type
65 and a callback function as parameters. The callback takes one QRestReply&
66 as a parameter. The callback can be any callable, including a
67 pointer-to-member-function.
68
69 These callbacks are invoked when the reply has finished processing
70 (also in the case the processing finished due to an error).
71
72 The context object can be \c nullptr, although, generally speaking,
73 this is discouraged. Using a valid context object ensures that if the
74 context object is destroyed during request processing, the callback will
75 not be called. Stray callbacks which access a destroyed context is a source
76 of application misbehavior.
77
78 Here's an example of how you could send a GET request and check the
79 response:
80
81 \snippet code/src_network_access_qrestaccessmanager.cpp 1
82
83 Many of the functions take in data for sending to a server. The data is
84 supplied as the second parameter after the request.
85
86 Here's an example of how you could send a POST request and check the
87 response:
88
89 \snippet code/src_network_access_qrestaccessmanager.cpp 2
90
91 The provided QRestReply& is valid only while the callback
92 executes. If you need it for longer, you can either move it
93 to another QRestReply, or construct a new one and initialize
94 it with the QNetworkReply (see QRestReply::networkReply()).
95
96 \section2 Supported data types
97
98 The following table summarizes the methods and the supported data types.
99 \c X means support.
100
101 \table
102 \header
103 \li Data type
104 \li \c get()
105 \li \c post()
106 \li \c put()
107 \li \c head()
108 \li \c patch()
109 \li \c deleteResource()
110 \li \c sendCustomRequest()
111 \row
112 \li No data
113 \li X
114 \li -
115 \li -
116 \li X
117 \li -
118 \li X
119 \li -
120 \row
121 \li QByteArray
122 \li X
123 \li X
124 \li X
125 \li -
126 \li X
127 \li -
128 \li X
129 \row
130 \li QJsonDocument *)
131 \li X
132 \li X
133 \li X
134 \li -
135 \li X
136 \li -
137 \li -
138 \row
139 \li QVariantMap **)
140 \li -
141 \li X
142 \li X
143 \li -
144 \li X
145 \li -
146 \li -
147 \row
148 \li QHttpMultiPart
149 \li -
150 \li X
151 \li X
152 \li -
153 \li -
154 \li -
155 \li X
156 \row
157 \li QIODevice
158 \li X
159 \li X
160 \li X
161 \li -
162 \li X
163 \li -
164 \li X
165 \endtable
166
167 *) QJsonDocument is sent in \l QJsonDocument::Compact format,
168 and the \c Content-Type header is set to \c {application/json} if the
169 \c Content-Type header was not set
170
171 **) QVariantMap is converted to and treated as a QJsonObject
172
173 \sa QRestReply, QNetworkRequestFactory, QNetworkAccessManager
174*/
175
176/*!
177 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::get(
178 const QNetworkRequest &request,
179 const ContextTypeForFunctor<Functor> *context,
180 Functor &&callback)
181
182 Issues an \c {HTTP GET} based on \a request.
183
184 The optional \a callback and \a context object can be provided for
185 handling the request completion as illustrated below:
186
187 \snippet code/src_network_access_qrestaccessmanager.cpp 3
188
189 Alternatively the signals of the returned QNetworkReply* object can be
190 used. For further information see
191 \l {Issuing Network Requests and Handling Replies}.
192
193 \sa QRestReply
194*/
195
196/*!
197 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::get(
198 const QNetworkRequest &request, const QByteArray &data,
199 const ContextTypeForFunctor<Functor> *context,
200 Functor &&callback)
201
202 Issues an \c {HTTP GET} based on \a request and provided \a data.
203
204 The optional \a callback and \a context object can be provided for
205 handling the request completion as illustrated below:
206
207 \snippet code/src_network_access_qrestaccessmanager.cpp 4
208
209 Alternatively the signals of the returned QNetworkReply* object can be
210 used. For further information see
211 \l {Issuing Network Requests and Handling Replies}.
212
213 \sa QRestReply
214*/
215
216/*!
217 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::get(
218 const QNetworkRequest &request, const QJsonDocument &data,
219 const ContextTypeForFunctor<Functor> *context,
220 Functor &&callback)
221
222 \overload
223*/
224
225/*!
226 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::get(
227 const QNetworkRequest &request, QIODevice *data,
228 const ContextTypeForFunctor<Functor> *context,
229 Functor &&callback)
230
231 \overload
232*/
233
234/*!
235 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::post(
236 const QNetworkRequest &request, const QJsonDocument &data,
237 const ContextTypeForFunctor<Functor> *context,
238 Functor &&callback)
239
240 Issues an \c {HTTP POST} based on \a request.
241
242 The optional \a callback and \a context object can be provided for
243 handling the request completion as illustrated below:
244
245 \snippet code/src_network_access_qrestaccessmanager.cpp 5
246
247 Alternatively, the signals of the returned QNetworkReply* object can be
248 used. For further information see
249 \l {Issuing Network Requests and Handling Replies}.
250
251 The \c post() method always requires \a data parameter. The following
252 data types are supported:
253 \list
254 \li QByteArray
255 \li QJsonDocument *)
256 \li QVariantMap **)
257 \li QHttpMultiPart*
258 \li QIODevice*
259 \endlist
260
261 *) Sent in \l QJsonDocument::Compact format, and the
262 \c Content-Type header is set to \c {application/json} if the
263 \c Content-Type header was not set
264 **) QVariantMap is converted to and treated as a QJsonObject
265
266 \sa QRestReply
267*/
268
269/*!
270
271 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::post(
272 const QNetworkRequest &request, const QVariantMap &data,
273 const ContextTypeForFunctor<Functor> *context,
274 Functor &&callback)
275
276 \overload
277*/
278
279/*!
280 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::post(
281 const QNetworkRequest &request, const QByteArray &data,
282 const ContextTypeForFunctor<Functor> *context,
283 Functor &&callback)
284
285 \overload
286*/
287
288/*!
289 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::post(
290 const QNetworkRequest &request, QHttpMultiPart *data,
291 const ContextTypeForFunctor<Functor> *context,
292 Functor &&callback)
293
294 \overload
295*/
296
297/*!
298 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::post(
299 const QNetworkRequest &request, QIODevice *data,
300 const ContextTypeForFunctor<Functor> *context,
301 Functor &&callback)
302
303 \overload
304*/
305
306/*!
307 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::put(
308 const QNetworkRequest &request, const QJsonDocument &data,
309 const ContextTypeForFunctor<Functor> *context,
310 Functor &&callback)
311
312 Issues an \c {HTTP PUT} based on \a request.
313
314 The optional \a callback and \a context object can be provided for
315 handling the request completion as illustrated below:
316
317 \snippet code/src_network_access_qrestaccessmanager.cpp 6
318
319 Alternatively the signals of the returned QNetworkReply* object can be
320 used. For further information see
321 \l {Issuing Network Requests and Handling Replies}.
322
323 The \c put() method always requires \a data parameter. The following
324 data types are supported:
325 \list
326 \li QByteArray
327 \li QJsonDocument *)
328 \li QVariantMap **)
329 \li QHttpMultiPart*
330 \li QIODevice*
331 \endlist
332
333 *) Sent in \l QJsonDocument::Compact format, and the
334 \c Content-Type header is set to \c {application/json} if the
335 \c Content-Type header was not set
336 **) QVariantMap is converted to and treated as a QJsonObject
337
338 \sa QRestReply
339*/
340
341/*!
342 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::put(
343 const QNetworkRequest &request, const QVariantMap &data,
344 const ContextTypeForFunctor<Functor> *context,
345 Functor &&callback)
346
347 \overload
348*/
349
350/*!
351 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::put(
352 const QNetworkRequest &request, const QByteArray &data,
353 const ContextTypeForFunctor<Functor> *context,
354 Functor &&callback)
355
356 \overload
357*/
358
359/*!
360 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::put(
361 const QNetworkRequest &request, QHttpMultiPart *data,
362 const ContextTypeForFunctor<Functor> *context,
363 Functor &&callback)
364
365 \overload
366*/
367
368/*!
369 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::put(
370 const QNetworkRequest &request, QIODevice *data,
371 const ContextTypeForFunctor<Functor> *context,
372 Functor &&callback)
373
374 \overload
375*/
376
377/*!
378 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::patch(
379 const QNetworkRequest &request, const QJsonDocument &data,
380 const ContextTypeForFunctor<Functor> *context,
381 Functor &&callback)
382
383 Issues an \c {HTTP PATCH} based on \a request.
384
385 The optional \a callback and \a context object can be provided for
386 handling the request completion as illustrated below:
387
388 \snippet code/src_network_access_qrestaccessmanager.cpp 10
389
390 Alternatively the signals of the returned QNetworkReply* object can be
391 used. For further information see
392 \l {Issuing Network Requests and Handling Replies}.
393
394 The \c patch() method always requires \a data parameter. The following
395 data types are supported:
396 \list
397 \li QByteArray
398 \li QJsonDocument *)
399 \li QVariantMap **)
400 \li QIODevice*
401 \endlist
402
403 *) Sent in \l QJsonDocument::Compact format, and the
404 \c Content-Type header is set to \c {application/json} if the
405 \c Content-Type header was not set
406 **) QVariantMap is converted to and treated as a QJsonObject
407
408 \sa QRestReply
409*/
410
411/*!
412 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::patch(
413 const QNetworkRequest &request, const QVariantMap &data,
414 const ContextTypeForFunctor<Functor> *context,
415 Functor &&callback)
416
417 \overload
418*/
419
420/*!
421 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::patch(
422 const QNetworkRequest &request, const QByteArray &data,
423 const ContextTypeForFunctor<Functor> *context,
424 Functor &&callback)
425
426 \overload
427*/
428
429/*!
430 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::patch(
431 const QNetworkRequest &request, QIODevice *data,
432 const ContextTypeForFunctor<Functor> *context,
433 Functor &&callback)
434
435 \overload
436*/
437
438/*!
439 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::head(
440 const QNetworkRequest &request,
441 const ContextTypeForFunctor<Functor> *context,
442 Functor &&callback)
443
444 Issues an \c {HTTP HEAD} based on \a request.
445
446 The optional \a callback and \a context object can be provided for
447 handling the request completion as illustrated below:
448
449 \snippet code/src_network_access_qrestaccessmanager.cpp 7
450
451 Alternatively the signals of the returned QNetworkReply* object can be
452 used. For further information see
453 \l {Issuing Network Requests and Handling Replies}.
454
455 \c head() request does not support providing data.
456
457 \sa QRestReply
458*/
459
460/*!
461 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::deleteResource(
462 const QNetworkRequest &request,
463 const ContextTypeForFunctor<Functor> *context,
464 Functor &&callback)
465
466 Issues an \c {HTTP DELETE} based on \a request.
467
468 The optional \a callback and \a context object can be provided for
469 handling the request completion as illustrated below:
470
471 \snippet code/src_network_access_qrestaccessmanager.cpp 8
472
473 Alternatively the signals of the returned QNetworkReply* object can be
474 used. For further information see
475 \l {Issuing Network Requests and Handling Replies}.
476
477 \c deleteResource() request does not support providing data.
478
479 \sa QRestReply
480*/
481
482/*!
483 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::sendCustomRequest(
484 const QNetworkRequest& request, const QByteArray &method, const QByteArray &data,
485 const ContextTypeForFunctor<Functor> *context,
486 Functor &&callback)
487
488 Issues \a request based HTTP request with custom \a method and the
489 provided \a data.
490
491 The optional \a callback and \a context object can be provided for
492 handling the request completion as illustrated below:
493
494 \snippet code/src_network_access_qrestaccessmanager.cpp 9
495
496 Alternatively the signals of the returned QNetworkReply* object can be
497 used. For further information see
498 \l {Issuing Network Requests and Handling Replies}.
499
500*/
501
502/*!
503 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::sendCustomRequest(
504 const QNetworkRequest& request, const QByteArray &method, QIODevice *data,
505 const ContextTypeForFunctor<Functor> *context,
506 Functor &&callback)
507
508 \overload
509*/
510
511/*!
512 \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::sendCustomRequest(
513 const QNetworkRequest& request, const QByteArray &method, QHttpMultiPart *data,
514 const ContextTypeForFunctor<Functor> *context,
515 Functor &&callback)
516
517 \overload
518*/
519
520/*!
521 Constructs a QRestAccessManager object and sets \a parent as the parent
522 object, and \a manager as the underlying QNetworkAccessManager which
523 is used for communication.
524
525 \sa networkAccessManager()
526*/
527
528QRestAccessManager::QRestAccessManager(QNetworkAccessManager *manager, QObject *parent)
529 : QObject(*new QRestAccessManagerPrivate, parent)
530{
531 Q_D(QRestAccessManager);
532 d->qnam = manager;
533 if (!d->qnam)
534 qCWarning(lcQrest, "QRestAccessManager: QNetworkAccesManager is nullptr");
535}
536
537/*!
538 Destroys the QRestAccessManager object.
539*/
540QRestAccessManager::~QRestAccessManager()
541 = default;
542
543/*!
544 Returns the underlying QNetworkAccessManager instance.
545
546 \sa QNetworkAccessManager
547*/
548QNetworkAccessManager *QRestAccessManager::networkAccessManager() const
549{
550 Q_D(const QRestAccessManager);
551 return d->qnam;
552}
553
554QRestAccessManagerPrivate::QRestAccessManagerPrivate()
555 = default;
556
557QRestAccessManagerPrivate::~QRestAccessManagerPrivate()
558{
559 if (!activeRequests.isEmpty()) {
560 qCWarning(lcQrest, "Access manager destroyed while %lld requests were still in progress",
561 qlonglong(activeRequests.size()));
562 }
563}
564
565QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
566 const QJsonDocument &data, const QObject *context,
567 QtPrivate::QSlotObjectBase *slot)
568{
569 Q_D(QRestAccessManager);
570 return d->executeRequest(requestOperation: [](auto qnam, auto req, auto data) { return qnam->post(req, data); },
571 jsonDoc: data, request, context, rawSlot: slot);
572}
573
574QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
575 const QVariantMap &data, const QObject *context,
576 QtPrivate::QSlotObjectBase *slot)
577{
578 return postWithDataImpl(request, data: QJsonDocument::fromVariant(variant: data), context, slot);
579}
580
581QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
582 const QByteArray &data, const QObject *context,
583 QtPrivate::QSlotObjectBase *slot)
584{
585 Q_D(QRestAccessManager);
586 return d->executeRequest(requestOperation: [&](auto qnam) { return qnam->post(request, data); }, context, rawSlot: slot);
587}
588
589QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
590 QHttpMultiPart *data, const QObject *context,
591 QtPrivate::QSlotObjectBase *slot)
592{
593 Q_D(QRestAccessManager);
594 return d->executeRequest(requestOperation: [&](auto qnam) { return qnam->post(request, data); }, context, rawSlot: slot);
595}
596
597QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
598 QIODevice *data, const QObject *context,
599 QtPrivate::QSlotObjectBase *slot)
600{
601 Q_D(QRestAccessManager);
602 return d->executeRequest(requestOperation: [&](auto qnam) { return qnam->post(request, data); }, context, rawSlot: slot);
603}
604
605QNetworkReply *QRestAccessManager::getNoDataImpl(const QNetworkRequest &request,
606 const QObject *context, QtPrivate::QSlotObjectBase *slot)
607{
608 Q_D(QRestAccessManager);
609 return d->executeRequest(requestOperation: [&](auto qnam) { return qnam->get(request); }, context, rawSlot: slot);
610}
611
612QNetworkReply *QRestAccessManager::getWithDataImpl(const QNetworkRequest &request,
613 const QByteArray &data, const QObject *context,
614 QtPrivate::QSlotObjectBase *slot)
615{
616 Q_D(QRestAccessManager);
617 return d->executeRequest(requestOperation: [&](auto qnam) { return qnam->get(request, data); }, context, rawSlot: slot);
618}
619
620QNetworkReply *QRestAccessManager::getWithDataImpl(const QNetworkRequest &request,
621 const QJsonDocument &data, const QObject *context,
622 QtPrivate::QSlotObjectBase *slot)
623{
624 Q_D(QRestAccessManager);
625 return d->executeRequest(requestOperation: [](auto qnam, auto req, auto data) { return qnam->get(req, data); },
626 jsonDoc: data, request, context, rawSlot: slot);
627}
628
629QNetworkReply *QRestAccessManager::getWithDataImpl(const QNetworkRequest &request,
630 QIODevice *data, const QObject *context,
631 QtPrivate::QSlotObjectBase *slot)
632{
633 Q_D(QRestAccessManager);
634 return d->executeRequest(requestOperation: [&](auto qnam) { return qnam->get(request, data); }, context, rawSlot: slot);
635}
636
637QNetworkReply *QRestAccessManager::deleteResourceNoDataImpl(const QNetworkRequest &request,
638 const QObject *context, QtPrivate::QSlotObjectBase *slot)
639{
640 Q_D(QRestAccessManager);
641 return d->executeRequest(requestOperation: [&](auto qnam) { return qnam->deleteResource(request); }, context, rawSlot: slot);
642}
643
644QNetworkReply *QRestAccessManager::headNoDataImpl(const QNetworkRequest &request,
645 const QObject *context, QtPrivate::QSlotObjectBase *slot)
646{
647 Q_D(QRestAccessManager);
648 return d->executeRequest(requestOperation: [&](auto qnam) { return qnam->head(request); }, context, rawSlot: slot);
649}
650
651QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
652 const QJsonDocument &data, const QObject *context,
653 QtPrivate::QSlotObjectBase *slot)
654{
655 Q_D(QRestAccessManager);
656 return d->executeRequest(requestOperation: [](auto qnam, auto req, auto data) { return qnam->put(req, data); },
657 jsonDoc: data, request, context, rawSlot: slot);
658}
659
660QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
661 const QVariantMap &data, const QObject *context,
662 QtPrivate::QSlotObjectBase *slot)
663{
664 return putWithDataImpl(request, data: QJsonDocument::fromVariant(variant: data), context, slot);
665}
666
667QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
668 const QByteArray &data, const QObject *context,
669 QtPrivate::QSlotObjectBase *slot)
670{
671 Q_D(QRestAccessManager);
672 return d->executeRequest(requestOperation: [&](auto qnam) { return qnam->put(request, data); }, context, rawSlot: slot);
673}
674
675QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
676 QHttpMultiPart *data, const QObject *context,
677 QtPrivate::QSlotObjectBase *slot)
678{
679 Q_D(QRestAccessManager);
680 return d->executeRequest(requestOperation: [&](auto qnam) { return qnam->put(request, data); }, context, rawSlot: slot);
681}
682
683QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request, QIODevice *data,
684 const QObject *context, QtPrivate::QSlotObjectBase *slot)
685{
686 Q_D(QRestAccessManager);
687 return d->executeRequest(requestOperation: [&](auto qnam) { return qnam->put(request, data); }, context, rawSlot: slot);
688}
689
690static const QByteArray& PATCH()
691{
692 static auto patch = "PATCH"_ba;
693 return patch;
694}
695
696QNetworkReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request,
697 const QJsonDocument &data, const QObject *context,
698 QtPrivate::QSlotObjectBase *slot)
699{
700 Q_D(QRestAccessManager);
701 return d->executeRequest(
702 requestOperation: [](auto qnam, auto req, auto data) { return qnam->sendCustomRequest(req, PATCH(), data); },
703 jsonDoc: data, request, context, rawSlot: slot);
704}
705
706QNetworkReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request,
707 const QVariantMap &data, const QObject *context,
708 QtPrivate::QSlotObjectBase *slot)
709{
710 return patchWithDataImpl(request, data: QJsonDocument::fromVariant(variant: data), context, slot);
711}
712
713QNetworkReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request,
714 const QByteArray &data, const QObject *context,
715 QtPrivate::QSlotObjectBase *slot)
716{
717 Q_D(QRestAccessManager);
718 return d->executeRequest(requestOperation: [&](auto qnam) { return qnam->sendCustomRequest(request, PATCH(), data); },
719 context, rawSlot: slot);
720}
721
722QNetworkReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request, QIODevice *data,
723 const QObject *context, QtPrivate::QSlotObjectBase *slot)
724{
725 Q_D(QRestAccessManager);
726 return d->executeRequest(requestOperation: [&](auto qnam) { return qnam->sendCustomRequest(request, PATCH(), data); },
727 context, rawSlot: slot);
728}
729
730QNetworkReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request,
731 const QByteArray& method, const QByteArray &data,
732 const QObject *context,
733 QtPrivate::QSlotObjectBase *slot)
734{
735 Q_D(QRestAccessManager);
736 return d->executeRequest(requestOperation: [&](auto qnam) { return qnam->sendCustomRequest(request, method, data); },
737 context, rawSlot: slot);
738}
739
740QNetworkReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request,
741 const QByteArray& method, QIODevice *data,
742 const QObject *context,
743 QtPrivate::QSlotObjectBase *slot)
744{
745 Q_D(QRestAccessManager);
746 return d->executeRequest(requestOperation: [&](auto qnam) { return qnam->sendCustomRequest(request, method, data); },
747 context, rawSlot: slot);
748}
749
750QNetworkReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request,
751 const QByteArray& method, QHttpMultiPart *data,
752 const QObject *context,
753 QtPrivate::QSlotObjectBase *slot)
754{
755 Q_D(QRestAccessManager);
756 return d->executeRequest(requestOperation: [&](auto qnam) { return qnam->sendCustomRequest(request, method, data); },
757 context, rawSlot: slot);
758}
759
760QNetworkReply *QRestAccessManagerPrivate::createActiveRequest(QNetworkReply *reply,
761 const QObject *contextObject,
762 QtPrivate::SlotObjUniquePtr slot)
763{
764 Q_Q(QRestAccessManager);
765 Q_ASSERT(reply);
766 QtPrivate::SlotObjSharedPtr slotPtr(std::move(slot)); // adopts
767 activeRequests.insert(key: reply, value: CallerInfo{.contextObject: contextObject, .slot: slotPtr});
768 // The signal connections below are made to 'q' to avoid stray signal
769 // handling upon its destruction while requests were still in progress
770
771 QObject::connect(sender: reply, signal: &QNetworkReply::finished, context: q, slot: [reply, this]() {
772 handleReplyFinished(reply);
773 });
774 // Safe guard in case reply is destroyed before it's finished
775 QObject::connect(sender: reply, signal: &QObject::destroyed, context: q, slot: [reply, this]() {
776 activeRequests.remove(key: reply);
777 });
778 // If context object is destroyed, clean up any possible replies it had associated with it
779 if (contextObject) {
780 QObject::connect(sender: contextObject, signal: &QObject::destroyed, context: q, slot: [reply, this]() {
781 activeRequests.remove(key: reply);
782 });
783 }
784 return reply;
785}
786
787void QRestAccessManagerPrivate::verifyThreadAffinity(const QObject *contextObject)
788{
789 Q_Q(QRestAccessManager);
790 if (QThread::currentThread() != q->thread()) {
791 qCWarning(lcQrest, "QRestAccessManager can only be called in the thread it belongs to");
792 Q_ASSERT(false);
793 }
794 if (contextObject && (contextObject->thread() != q->thread())) {
795 qCWarning(lcQrest, "QRestAccessManager: the context object must reside in the same thread");
796 Q_ASSERT(false);
797 }
798}
799
800QNetworkReply* QRestAccessManagerPrivate::warnNoAccessManager()
801{
802 qCWarning(lcQrest, "QRestAccessManager: QNetworkAccessManager not set");
803 return nullptr;
804}
805
806void QRestAccessManagerPrivate::handleReplyFinished(QNetworkReply *reply)
807{
808 auto request = activeRequests.find(key: reply);
809 if (request == activeRequests.end()) {
810 qCDebug(lcQrest, "QRestAccessManager: Unexpected reply received, ignoring");
811 return;
812 }
813
814 CallerInfo caller = request.value();
815 activeRequests.erase(it: request);
816
817 if (caller.slot) {
818 // Callback was provided
819 QRestReply restReply(reply);
820 void *argv[] = { nullptr, &restReply };
821 // If we have context object, use it
822 QObject *context = caller.contextObject
823 ? const_cast<QObject*>(caller.contextObject.get()) : nullptr;
824 caller.slot->call(r: context, a: argv);
825 }
826}
827
828QT_END_NAMESPACE
829
830#include "moc_qrestaccessmanager.cpp"
831

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtbase/src/network/access/qrestaccessmanager.cpp