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