1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtNetwork module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <QtNetwork/private/qtnetworkglobal_p.h>
41
42#include "qnetworkaccessmanager.h"
43#include "qnetworkaccessmanager_p.h"
44#include "qnetworkrequest.h"
45#include "qnetworkreply.h"
46#include "qnetworkreply_p.h"
47#include "qnetworkcookie.h"
48#include "qnetworkcookiejar.h"
49#include "qabstractnetworkcache.h"
50#include "qhstspolicy.h"
51#include "qhsts_p.h"
52
53#if QT_CONFIG(settings)
54#include "qhstsstore_p.h"
55#endif // QT_CONFIG(settings)
56
57#include "QtNetwork/qnetworksession.h"
58#include "QtNetwork/private/qsharednetworksession_p.h"
59
60#if QT_CONFIG(ftp)
61#include "qnetworkaccessftpbackend_p.h"
62#endif
63#include "qnetworkaccessfilebackend_p.h"
64#include "qnetworkaccessdebugpipebackend_p.h"
65#include "qnetworkaccesscachebackend_p.h"
66#include "qnetworkreplydataimpl_p.h"
67#include "qnetworkreplyfileimpl_p.h"
68
69#include "QtCore/qbuffer.h"
70#include "QtCore/qurl.h"
71#include "QtCore/qvector.h"
72#include "QtNetwork/private/qauthenticator_p.h"
73#include "QtNetwork/qsslconfiguration.h"
74#include "QtNetwork/qnetworkconfigmanager.h"
75#include "QtNetwork/private/http2protocol_p.h"
76
77#if QT_CONFIG(http)
78#include "qhttpmultipart.h"
79#include "qhttpmultipart_p.h"
80#include "qnetworkreplyhttpimpl_p.h"
81#endif
82
83#include "qthread.h"
84
85#include <QHostInfo>
86
87#if defined(Q_OS_MACOS)
88#include <CoreServices/CoreServices.h>
89#include <SystemConfiguration/SystemConfiguration.h>
90#include <Security/SecKeychain.h>
91#endif
92#ifdef Q_OS_WASM
93#include "qnetworkreplywasmimpl_p.h"
94#endif
95
96#include "qnetconmonitor_p.h"
97
98QT_BEGIN_NAMESPACE
99
100Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
101#if QT_CONFIG(ftp)
102Q_GLOBAL_STATIC(QNetworkAccessFtpBackendFactory, ftpBackend)
103#endif // QT_CONFIG(ftp)
104
105#ifdef QT_BUILD_INTERNAL
106Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend)
107#endif
108
109#if defined(Q_OS_MACX)
110bool getProxyAuth(const QString& proxyHostname, const QString &scheme, QString& username, QString& password)
111{
112 OSStatus err;
113 SecKeychainItemRef itemRef;
114 bool retValue = false;
115 SecProtocolType protocolType = kSecProtocolTypeAny;
116 if (scheme.compare(QLatin1String("ftp"),Qt::CaseInsensitive)==0) {
117 protocolType = kSecProtocolTypeFTPProxy;
118 } else if (scheme.compare(QLatin1String("http"),Qt::CaseInsensitive)==0
119 || scheme.compare(QLatin1String("preconnect-http"),Qt::CaseInsensitive)==0) {
120 protocolType = kSecProtocolTypeHTTPProxy;
121 } else if (scheme.compare(QLatin1String("https"),Qt::CaseInsensitive)==0
122 || scheme.compare(QLatin1String("preconnect-https"),Qt::CaseInsensitive)==0) {
123 protocolType = kSecProtocolTypeHTTPSProxy;
124 }
125 QByteArray proxyHostnameUtf8(proxyHostname.toUtf8());
126 err = SecKeychainFindInternetPassword(NULL,
127 proxyHostnameUtf8.length(), proxyHostnameUtf8.constData(),
128 0,NULL,
129 0, NULL,
130 0, NULL,
131 0,
132 protocolType,
133 kSecAuthenticationTypeAny,
134 0, NULL,
135 &itemRef);
136 if (err == noErr) {
137
138 SecKeychainAttribute attr;
139 SecKeychainAttributeList attrList;
140 UInt32 length;
141 void *outData;
142
143 attr.tag = kSecAccountItemAttr;
144 attr.length = 0;
145 attr.data = NULL;
146
147 attrList.count = 1;
148 attrList.attr = &attr;
149
150 if (SecKeychainItemCopyContent(itemRef, NULL, &attrList, &length, &outData) == noErr) {
151 username = QString::fromUtf8((const char*)attr.data, attr.length);
152 password = QString::fromUtf8((const char*)outData, length);
153 SecKeychainItemFreeContent(&attrList,outData);
154 retValue = true;
155 }
156 CFRelease(itemRef);
157 }
158 return retValue;
159}
160#endif
161
162
163
164static void ensureInitialized()
165{
166#if QT_CONFIG(ftp)
167 (void) ftpBackend();
168#endif
169
170#ifdef QT_BUILD_INTERNAL
171 (void) debugpipeBackend();
172#endif
173
174 // leave this one last since it will query the special QAbstractFileEngines
175 (void) fileBackend();
176}
177
178/*!
179 \class QNetworkAccessManager
180 \brief The QNetworkAccessManager class allows the application to
181 send network requests and receive replies.
182 \since 4.4
183
184 \ingroup network
185 \inmodule QtNetwork
186 \reentrant
187
188 The Network Access API is constructed around one QNetworkAccessManager
189 object, which holds the common configuration and settings for the requests
190 it sends. It contains the proxy and cache configuration, as well as the
191 signals related to such issues, and reply signals that can be used to
192 monitor the progress of a network operation. One QNetworkAccessManager
193 instance should be enough for the whole Qt application. Since
194 QNetworkAccessManager is based on QObject, it can only be used from the
195 thread it belongs to.
196
197 Once a QNetworkAccessManager object has been created, the application can
198 use it to send requests over the network. A group of standard functions
199 are supplied that take a request and optional data, and each return a
200 QNetworkReply object. The returned object is used to obtain any data
201 returned in response to the corresponding request.
202
203 A simple download off the network could be accomplished with:
204 \snippet code/src_network_access_qnetworkaccessmanager.cpp 0
205
206 QNetworkAccessManager has an asynchronous API.
207 When the \tt replyFinished slot above is called, the parameter it
208 takes is the QNetworkReply object containing the downloaded data
209 as well as meta-data (headers, etc.).
210
211 \note After the request has finished, it is the responsibility of the user
212 to delete the QNetworkReply object at an appropriate time. Do not directly
213 delete it inside the slot connected to finished(). You can use the
214 deleteLater() function.
215
216 \note QNetworkAccessManager queues the requests it receives. The number
217 of requests executed in parallel is dependent on the protocol.
218 Currently, for the HTTP protocol on desktop platforms, 6 requests are
219 executed in parallel for one host/port combination.
220
221 A more involved example, assuming the manager is already existent,
222 can be:
223 \snippet code/src_network_access_qnetworkaccessmanager.cpp 1
224
225 \sa QNetworkRequest, QNetworkReply, QNetworkProxy
226*/
227
228/*!
229 \enum QNetworkAccessManager::Operation
230
231 Indicates the operation this reply is processing.
232
233 \value HeadOperation retrieve headers operation (created
234 with head())
235
236 \value GetOperation retrieve headers and download contents
237 (created with get())
238
239 \value PutOperation upload contents operation (created
240 with put())
241
242 \value PostOperation send the contents of an HTML form for
243 processing via HTTP POST (created with post())
244
245 \value DeleteOperation delete contents operation (created with
246 deleteResource())
247
248 \value CustomOperation custom operation (created with
249 sendCustomRequest()) \since 4.7
250
251 \omitvalue UnknownOperation
252
253 \sa QNetworkReply::operation()
254*/
255
256/*!
257 \enum QNetworkAccessManager::NetworkAccessibility
258 \obsolete
259
260 Indicates whether the network is accessible via this network access manager.
261
262 \value UnknownAccessibility The network accessibility cannot be determined.
263 \value NotAccessible The network is not currently accessible, either because there
264 is currently no network coverage or network access has been
265 explicitly disabled by a call to setNetworkAccessible().
266 \value Accessible The network is accessible.
267
268 \sa networkAccessible
269*/
270
271/*!
272 \property QNetworkAccessManager::networkAccessible
273 \brief whether the network is currently accessible via this network access manager.
274 \obsolete
275
276 \since 4.7
277
278 If the network is \l {NotAccessible}{not accessible} the network access manager will not
279 process any new network requests, all such requests will fail with an error. Requests with
280 URLs with the file:// scheme will still be processed.
281
282 By default the value of this property reflects the physical state of the device. Applications
283 may override it to disable all network requests via this network access manager by calling
284
285 \snippet code/src_network_access_qnetworkaccessmanager.cpp 4
286
287 Network requests can be re-enabled again, and this property will resume to
288 reflect the actual device state by calling
289
290 \snippet code/src_network_access_qnetworkaccessmanager.cpp 5
291
292 \note Calling setNetworkAccessible() does not change the network state.
293*/
294
295/*!
296 \fn void QNetworkAccessManager::networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible)
297 \obsolete
298
299 This signal is emitted when the value of the \l networkAccessible property changes.
300 \a accessible is the new network accessibility.
301*/
302
303/*!
304 \fn void QNetworkAccessManager::networkSessionConnected()
305
306 \since 4.7
307 \obsolete
308
309 \internal
310
311 This signal is emitted when the status of the network session changes into a usable (Connected)
312 state. It is used to signal to QNetworkReplys to start or migrate their network operation once
313 the network session has been opened or finished roaming.
314*/
315
316/*!
317 \fn void QNetworkAccessManager::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)
318
319 This signal is emitted whenever a proxy requests authentication
320 and QNetworkAccessManager cannot find a valid, cached
321 credential. The slot connected to this signal should fill in the
322 credentials for the proxy \a proxy in the \a authenticator object.
323
324 QNetworkAccessManager will cache the credentials internally. The
325 next time the proxy requests authentication, QNetworkAccessManager
326 will automatically send the same credential without emitting the
327 proxyAuthenticationRequired signal again.
328
329 If the proxy rejects the credentials, QNetworkAccessManager will
330 emit the signal again.
331
332 \sa proxy(), setProxy(), authenticationRequired()
333*/
334
335/*!
336 \fn void QNetworkAccessManager::authenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator)
337
338 This signal is emitted whenever a final server requests
339 authentication before it delivers the requested contents. The slot
340 connected to this signal should fill the credentials for the
341 contents (which can be determined by inspecting the \a reply
342 object) in the \a authenticator object.
343
344 QNetworkAccessManager will cache the credentials internally and
345 will send the same values if the server requires authentication
346 again, without emitting the authenticationRequired() signal. If it
347 rejects the credentials, this signal will be emitted again.
348
349 \note To have the request not send credentials you must not call
350 setUser() or setPassword() on the \a authenticator object. This
351 will result in the \l finished() signal being emitted with a
352 \l QNetworkReply with error \l {QNetworkReply::} {AuthenticationRequiredError}.
353
354 \note It is not possible to use a QueuedConnection to connect to
355 this signal, as the connection will fail if the authenticator has
356 not been filled in with new information when the signal returns.
357
358 \sa proxyAuthenticationRequired(), QAuthenticator::setUser(), QAuthenticator::setPassword()
359*/
360
361/*!
362 \fn void QNetworkAccessManager::finished(QNetworkReply *reply)
363
364 This signal is emitted whenever a pending network reply is
365 finished. The \a reply parameter will contain a pointer to the
366 reply that has just finished. This signal is emitted in tandem
367 with the QNetworkReply::finished() signal.
368
369 See QNetworkReply::finished() for information on the status that
370 the object will be in.
371
372 \note Do not delete the \a reply object in the slot connected to this
373 signal. Use deleteLater().
374
375 \sa QNetworkReply::finished(), QNetworkReply::error()
376*/
377
378/*!
379 \fn void QNetworkAccessManager::encrypted(QNetworkReply *reply)
380 \since 5.1
381
382 This signal is emitted when an SSL/TLS session has successfully
383 completed the initial handshake. At this point, no user data
384 has been transmitted. The signal can be used to perform
385 additional checks on the certificate chain, for example to
386 notify users when the certificate for a website has changed. The
387 \a reply parameter specifies which network reply is responsible.
388 If the reply does not match the expected criteria then it should
389 be aborted by calling QNetworkReply::abort() by a slot connected
390 to this signal. The SSL configuration in use can be inspected
391 using the QNetworkReply::sslConfiguration() method.
392
393 Internally, QNetworkAccessManager may open multiple connections
394 to a server, in order to allow it process requests in parallel.
395 These connections may be reused, which means that the encrypted()
396 signal would not be emitted. This means that you are only
397 guaranteed to receive this signal for the first connection to a
398 site in the lifespan of the QNetworkAccessManager.
399
400 \sa QSslSocket::encrypted()
401 \sa QNetworkReply::encrypted()
402*/
403
404/*!
405 \fn void QNetworkAccessManager::sslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
406
407 This signal is emitted if the SSL/TLS session encountered errors
408 during the set up, including certificate verification errors. The
409 \a errors parameter contains the list of errors and \a reply is
410 the QNetworkReply that is encountering these errors.
411
412 To indicate that the errors are not fatal and that the connection
413 should proceed, the QNetworkReply::ignoreSslErrors() function should be called
414 from the slot connected to this signal. If it is not called, the
415 SSL session will be torn down before any data is exchanged
416 (including the URL).
417
418 This signal can be used to display an error message to the user
419 indicating that security may be compromised and display the
420 SSL settings (see sslConfiguration() to obtain it). If the user
421 decides to proceed after analyzing the remote certificate, the
422 slot should call ignoreSslErrors().
423
424 \sa QSslSocket::sslErrors(), QNetworkReply::sslErrors(),
425 QNetworkReply::sslConfiguration(), QNetworkReply::ignoreSslErrors()
426*/
427
428/*!
429 \fn void QNetworkAccessManager::preSharedKeyAuthenticationRequired(QNetworkReply *reply, QSslPreSharedKeyAuthenticator *authenticator)
430 \since 5.5
431
432 This signal is emitted if the SSL/TLS handshake negotiates a PSK
433 ciphersuite, and therefore a PSK authentication is then required.
434 The \a reply object is the QNetworkReply that is negotiating
435 such ciphersuites.
436
437 When using PSK, the client must send to the server a valid identity and a
438 valid pre shared key, in order for the SSL handshake to continue.
439 Applications can provide this information in a slot connected to this
440 signal, by filling in the passed \a authenticator object according to their
441 needs.
442
443 \note Ignoring this signal, or failing to provide the required credentials,
444 will cause the handshake to fail, and therefore the connection to be aborted.
445
446 \note The \a authenticator object is owned by the reply and must not be
447 deleted by the application.
448
449 \sa QSslPreSharedKeyAuthenticator
450*/
451
452/*!
453 Constructs a QNetworkAccessManager object that is the center of
454 the Network Access API and sets \a parent as the parent object.
455*/
456QNetworkAccessManager::QNetworkAccessManager(QObject *parent)
457 : QObject(*new QNetworkAccessManagerPrivate, parent)
458{
459 ensureInitialized();
460
461 qRegisterMetaType<QNetworkReply::NetworkError>();
462#ifndef QT_NO_NETWORKPROXY
463 qRegisterMetaType<QNetworkProxy>();
464#endif
465#ifndef QT_NO_SSL
466 qRegisterMetaType<QList<QSslError> >();
467 qRegisterMetaType<QSslConfiguration>();
468 qRegisterMetaType<QSslPreSharedKeyAuthenticator *>();
469#endif
470 qRegisterMetaType<QList<QPair<QByteArray,QByteArray> > >();
471#if QT_CONFIG(http)
472 qRegisterMetaType<QHttpNetworkRequest>();
473#endif
474 qRegisterMetaType<QNetworkReply::NetworkError>();
475 qRegisterMetaType<QSharedPointer<char> >();
476
477 Q_D(QNetworkAccessManager);
478
479 if (QNetworkStatusMonitor::isEnabled()) {
480 d->statusMonitor = new QNetworkStatusMonitor(this);
481 connect(asender: d->statusMonitor, SIGNAL(onlineStateChanged(bool)),
482 SLOT(_q_onlineStateChanged(bool)));
483#ifdef QT_NO_BEARERMANAGEMENT
484 d->networkAccessible = d->statusMonitor->isNetworkAccessible();
485#else
486 d->networkAccessible = d->statusMonitor->isNetworkAccessible() ? Accessible : NotAccessible;
487 } else {
488 // if a session is required, we track online state through
489 // the QNetworkSession's signals if a request is already made.
490 // we need to track current accessibility state by default
491 //
492 connect(asender: &d->networkConfigurationManager, SIGNAL(onlineStateChanged(bool)),
493 SLOT(_q_onlineStateChanged(bool)));
494 connect(asender: &d->networkConfigurationManager, SIGNAL(configurationChanged(QNetworkConfiguration)),
495 SLOT(_q_configurationChanged(QNetworkConfiguration)));
496#endif // QT_NO_BEARERMANAGEMENT
497 }
498}
499
500/*!
501 Destroys the QNetworkAccessManager object and frees up any
502 resources. Note that QNetworkReply objects that are returned from
503 this class have this object set as their parents, which means that
504 they will be deleted along with it if you don't call
505 QObject::setParent() on them.
506*/
507QNetworkAccessManager::~QNetworkAccessManager()
508{
509#ifndef QT_NO_NETWORKPROXY
510 delete d_func()->proxyFactory;
511#endif
512
513 // Delete the QNetworkReply children first.
514 // Else a QAbstractNetworkCache might get deleted in ~QObject
515 // before a QNetworkReply that accesses the QAbstractNetworkCache
516 // object in its destructor.
517 qDeleteAll(c: findChildren<QNetworkReply *>());
518 // The other children will be deleted in this ~QObject
519 // FIXME instead of this "hack" make the QNetworkReplyImpl
520 // properly watch the cache deletion, e.g. via a QWeakPointer.
521}
522
523#ifndef QT_NO_NETWORKPROXY
524/*!
525 Returns the QNetworkProxy that the requests sent using this
526 QNetworkAccessManager object will use. The default value for the
527 proxy is QNetworkProxy::DefaultProxy.
528
529 \sa setProxy(), setProxyFactory(), proxyAuthenticationRequired()
530*/
531QNetworkProxy QNetworkAccessManager::proxy() const
532{
533 return d_func()->proxy;
534}
535
536/*!
537 Sets the proxy to be used in future requests to be \a proxy. This
538 does not affect requests that have already been sent. The
539 proxyAuthenticationRequired() signal will be emitted if the proxy
540 requests authentication.
541
542 A proxy set with this function will be used for all requests
543 issued by QNetworkAccessManager. In some cases, it might be
544 necessary to select different proxies depending on the type of
545 request being sent or the destination host. If that's the case,
546 you should consider using setProxyFactory().
547
548 \sa proxy(), proxyAuthenticationRequired()
549*/
550void QNetworkAccessManager::setProxy(const QNetworkProxy &proxy)
551{
552 Q_D(QNetworkAccessManager);
553 delete d->proxyFactory;
554 d->proxy = proxy;
555 d->proxyFactory = nullptr;
556}
557
558/*!
559 \fn QNetworkProxyFactory *QNetworkAccessManager::proxyFactory() const
560 \since 4.5
561
562 Returns the proxy factory that this QNetworkAccessManager object
563 is using to determine the proxies to be used for requests.
564
565 Note that the pointer returned by this function is managed by
566 QNetworkAccessManager and could be deleted at any time.
567
568 \sa setProxyFactory(), proxy()
569*/
570QNetworkProxyFactory *QNetworkAccessManager::proxyFactory() const
571{
572 return d_func()->proxyFactory;
573}
574
575/*!
576 \since 4.5
577
578 Sets the proxy factory for this class to be \a factory. A proxy
579 factory is used to determine a more specific list of proxies to be
580 used for a given request, instead of trying to use the same proxy
581 value for all requests.
582
583 All queries sent by QNetworkAccessManager will have type
584 QNetworkProxyQuery::UrlRequest.
585
586 For example, a proxy factory could apply the following rules:
587 \list
588 \li if the target address is in the local network (for example,
589 if the hostname contains no dots or if it's an IP address in
590 the organization's range), return QNetworkProxy::NoProxy
591 \li if the request is FTP, return an FTP proxy
592 \li if the request is HTTP or HTTPS, then return an HTTP proxy
593 \li otherwise, return a SOCKSv5 proxy server
594 \endlist
595
596 The lifetime of the object \a factory will be managed by
597 QNetworkAccessManager. It will delete the object when necessary.
598
599 \note If a specific proxy is set with setProxy(), the factory will not
600 be used.
601
602 \sa proxyFactory(), setProxy(), QNetworkProxyQuery
603*/
604void QNetworkAccessManager::setProxyFactory(QNetworkProxyFactory *factory)
605{
606 Q_D(QNetworkAccessManager);
607 delete d->proxyFactory;
608 d->proxyFactory = factory;
609 d->proxy = QNetworkProxy();
610}
611#endif
612
613/*!
614 \since 4.5
615
616 Returns the cache that is used to store data obtained from the network.
617
618 \sa setCache()
619*/
620QAbstractNetworkCache *QNetworkAccessManager::cache() const
621{
622 Q_D(const QNetworkAccessManager);
623 return d->networkCache;
624}
625
626/*!
627 \since 4.5
628
629 Sets the manager's network cache to be the \a cache specified. The cache
630 is used for all requests dispatched by the manager.
631
632 Use this function to set the network cache object to a class that implements
633 additional features, like saving the cookies to permanent storage.
634
635 \note QNetworkAccessManager takes ownership of the \a cache object.
636
637 QNetworkAccessManager by default does not have a set cache.
638 Qt provides a simple disk cache, QNetworkDiskCache, which can be used.
639
640 \sa cache(), QNetworkRequest::CacheLoadControl
641*/
642void QNetworkAccessManager::setCache(QAbstractNetworkCache *cache)
643{
644 Q_D(QNetworkAccessManager);
645 if (d->networkCache != cache) {
646 delete d->networkCache;
647 d->networkCache = cache;
648 if (d->networkCache)
649 d->networkCache->setParent(this);
650 }
651}
652
653/*!
654 Returns the QNetworkCookieJar that is used to store cookies
655 obtained from the network as well as cookies that are about to be
656 sent.
657
658 \sa setCookieJar()
659*/
660QNetworkCookieJar *QNetworkAccessManager::cookieJar() const
661{
662 Q_D(const QNetworkAccessManager);
663 if (!d->cookieJar)
664 d->createCookieJar();
665 return d->cookieJar;
666}
667
668/*!
669 Sets the manager's cookie jar to be the \a cookieJar specified.
670 The cookie jar is used by all requests dispatched by the manager.
671
672 Use this function to set the cookie jar object to a class that
673 implements additional features, like saving the cookies to permanent
674 storage.
675
676 \note QNetworkAccessManager takes ownership of the \a cookieJar object.
677
678 If \a cookieJar is in the same thread as this QNetworkAccessManager,
679 it will set the parent of the \a cookieJar
680 so that the cookie jar is deleted when this
681 object is deleted as well. If you want to share cookie jars
682 between different QNetworkAccessManager objects, you may want to
683 set the cookie jar's parent to 0 after calling this function.
684
685 QNetworkAccessManager by default does not implement any cookie
686 policy of its own: it accepts all cookies sent by the server, as
687 long as they are well formed and meet the minimum security
688 requirements (cookie domain matches the request's and cookie path
689 matches the request's). In order to implement your own security
690 policy, override the QNetworkCookieJar::cookiesForUrl() and
691 QNetworkCookieJar::setCookiesFromUrl() virtual functions. Those
692 functions are called by QNetworkAccessManager when it detects a
693 new cookie.
694
695 \sa cookieJar(), QNetworkCookieJar::cookiesForUrl(), QNetworkCookieJar::setCookiesFromUrl()
696*/
697void QNetworkAccessManager::setCookieJar(QNetworkCookieJar *cookieJar)
698{
699 Q_D(QNetworkAccessManager);
700 d->cookieJarCreated = true;
701 if (d->cookieJar != cookieJar) {
702 if (d->cookieJar && d->cookieJar->parent() == this)
703 delete d->cookieJar;
704 d->cookieJar = cookieJar;
705 if (cookieJar && thread() == cookieJar->thread())
706 d->cookieJar->setParent(this);
707 }
708}
709
710/*!
711 \since 5.9
712
713 If \a enabled is \c true, QNetworkAccessManager follows the HTTP Strict Transport
714 Security policy (HSTS, RFC6797). When processing a request, QNetworkAccessManager
715 automatically replaces the "http" scheme with "https" and uses a secure transport
716 for HSTS hosts. If it's set explicitly, port 80 is replaced by port 443.
717
718 When HSTS is enabled, for each HTTP response containing HSTS header and
719 received over a secure transport, QNetworkAccessManager will update its HSTS
720 cache, either remembering a host with a valid policy or removing a host with
721 an expired or disabled HSTS policy.
722
723 \sa isStrictTransportSecurityEnabled()
724*/
725void QNetworkAccessManager::setStrictTransportSecurityEnabled(bool enabled)
726{
727 Q_D(QNetworkAccessManager);
728 d->stsEnabled = enabled;
729}
730
731/*!
732 \since 5.9
733
734 Returns true if HTTP Strict Transport Security (HSTS) was enabled. By default
735 HSTS is disabled.
736
737 \sa setStrictTransportSecurityEnabled()
738*/
739bool QNetworkAccessManager::isStrictTransportSecurityEnabled() const
740{
741 Q_D(const QNetworkAccessManager);
742 return d->stsEnabled;
743}
744
745/*!
746 \since 5.10
747
748 If \a enabled is \c true, the internal HSTS cache will use a persistent store
749 to read and write HSTS policies. \a storeDir defines where this store will be
750 located. The default location is defined by QStandardPaths::CacheLocation.
751 If there is no writable QStandartPaths::CacheLocation and \a storeDir is an
752 empty string, the store will be located in the program's working directory.
753
754 \note If HSTS cache already contains HSTS policies by the time persistent
755 store is enabled, these policies will be preserved in the store. In case both
756 cache and store contain the same known hosts, policies from cache are considered
757 to be more up-to-date (and thus will overwrite the previous values in the store).
758 If this behavior is undesired, enable HSTS store before enabling Strict Transport
759 Security. By default, the persistent store of HSTS policies is disabled.
760
761 \sa isStrictTransportSecurityStoreEnabled(), setStrictTransportSecurityEnabled(),
762 QStandardPaths::standardLocations()
763*/
764
765void QNetworkAccessManager::enableStrictTransportSecurityStore(bool enabled, const QString &storeDir)
766{
767#if QT_CONFIG(settings)
768 Q_D(QNetworkAccessManager);
769 d->stsStore.reset(other: enabled ? new QHstsStore(storeDir) : nullptr);
770 d->stsCache.setStore(d->stsStore.data());
771#else
772 Q_UNUSED(enabled) Q_UNUSED(storeDir)
773 qWarning("HSTS permanent store requires the feature 'settings' enabled");
774#endif // QT_CONFIG(settings)
775}
776
777/*!
778 \since 5.10
779
780 Returns true if HSTS cache uses a permanent store to load and store HSTS
781 policies.
782
783 \sa enableStrictTransportSecurityStore()
784*/
785
786bool QNetworkAccessManager::isStrictTransportSecurityStoreEnabled() const
787{
788#if QT_CONFIG(settings)
789 Q_D(const QNetworkAccessManager);
790 return bool(d->stsStore.data());
791#else
792 return false;
793#endif // QT_CONFIG(settings)
794}
795
796/*!
797 \since 5.9
798
799 Adds HTTP Strict Transport Security policies into HSTS cache.
800 \a knownHosts contains the known hosts that have QHstsPolicy
801 information.
802
803 \note An expired policy will remove a known host from the cache, if previously
804 present.
805
806 \note While processing HTTP responses, QNetworkAccessManager can also update
807 the HSTS cache, removing or updating exitsting policies or introducing new
808 \a knownHosts. The current implementation thus is server-driven, client code
809 can provide QNetworkAccessManager with previously known or discovered
810 policies, but this information can be overridden by "Strict-Transport-Security"
811 response headers.
812
813 \sa addStrictTransportSecurityHosts(), enableStrictTransportSecurityStore(), QHstsPolicy
814*/
815
816void QNetworkAccessManager::addStrictTransportSecurityHosts(const QVector<QHstsPolicy> &knownHosts)
817{
818 Q_D(QNetworkAccessManager);
819 d->stsCache.updateFromPolicies(hosts: knownHosts);
820}
821
822/*!
823 \since 5.9
824
825 Returns the list of HTTP Strict Transport Security policies. This list can
826 differ from what was initially set via addStrictTransportSecurityHosts() if
827 HSTS cache was updated from a "Strict-Transport-Security" response header.
828
829 \sa addStrictTransportSecurityHosts(), QHstsPolicy
830*/
831QVector<QHstsPolicy> QNetworkAccessManager::strictTransportSecurityHosts() const
832{
833 Q_D(const QNetworkAccessManager);
834 return d->stsCache.policies();
835}
836
837/*!
838 Posts a request to obtain the network headers for \a request
839 and returns a new QNetworkReply object which will contain such headers.
840
841 The function is named after the HTTP request associated (HEAD).
842*/
843QNetworkReply *QNetworkAccessManager::head(const QNetworkRequest &request)
844{
845 return d_func()->postProcess(reply: createRequest(op: QNetworkAccessManager::HeadOperation, request));
846}
847
848/*!
849 Posts a request to obtain the contents of the target \a request
850 and returns a new QNetworkReply object opened for reading which emits the
851 \l{QIODevice::readyRead()}{readyRead()} signal whenever new data
852 arrives.
853
854 The contents as well as associated headers will be downloaded.
855
856 \sa post(), put(), deleteResource(), sendCustomRequest()
857*/
858QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
859{
860 return d_func()->postProcess(reply: createRequest(op: QNetworkAccessManager::GetOperation, request));
861}
862
863/*!
864 Sends an HTTP POST request to the destination specified by \a request
865 and returns a new QNetworkReply object opened for reading that will
866 contain the reply sent by the server. The contents of the \a data
867 device will be uploaded to the server.
868
869 \a data must be open for reading and must remain valid until the
870 finished() signal is emitted for this reply.
871
872 \note Sending a POST request on protocols other than HTTP and
873 HTTPS is undefined and will probably fail.
874
875 \sa get(), put(), deleteResource(), sendCustomRequest()
876*/
877QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QIODevice *data)
878{
879 return d_func()->postProcess(reply: createRequest(op: QNetworkAccessManager::PostOperation, request, outgoingData: data));
880}
881
882/*!
883 \overload
884
885 Sends the contents of the \a data byte array to the destination
886 specified by \a request.
887*/
888QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, const QByteArray &data)
889{
890 QBuffer *buffer = new QBuffer;
891 buffer->setData(data);
892 buffer->open(openMode: QIODevice::ReadOnly);
893
894 QNetworkReply *reply = post(request, data: buffer);
895 buffer->setParent(reply);
896 return reply;
897}
898
899#if QT_CONFIG(http)
900/*!
901 \since 4.8
902
903 \overload
904
905 Sends the contents of the \a multiPart message to the destination
906 specified by \a request.
907
908 This can be used for sending MIME multipart messages over HTTP.
909
910 \sa QHttpMultiPart, QHttpPart, put()
911*/
912QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QHttpMultiPart *multiPart)
913{
914 QNetworkRequest newRequest = d_func()->prepareMultipart(request, multiPart);
915 QIODevice *device = multiPart->d_func()->device;
916 QNetworkReply *reply = post(request: newRequest, data: device);
917 return reply;
918}
919
920/*!
921 \since 4.8
922
923 \overload
924
925 Sends the contents of the \a multiPart message to the destination
926 specified by \a request.
927
928 This can be used for sending MIME multipart messages over HTTP.
929
930 \sa QHttpMultiPart, QHttpPart, post()
931*/
932QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, QHttpMultiPart *multiPart)
933{
934 QNetworkRequest newRequest = d_func()->prepareMultipart(request, multiPart);
935 QIODevice *device = multiPart->d_func()->device;
936 QNetworkReply *reply = put(request: newRequest, data: device);
937 return reply;
938}
939#endif // QT_CONFIG(http)
940
941/*!
942 Uploads the contents of \a data to the destination \a request and
943 returns a new QNetworkReply object that will be open for reply.
944
945 \a data must be opened for reading when this function is called
946 and must remain valid until the finished() signal is emitted for
947 this reply.
948
949 Whether anything will be available for reading from the returned
950 object is protocol dependent. For HTTP, the server may send a
951 small HTML page indicating the upload was successful (or not).
952 Other protocols will probably have content in their replies.
953
954 \note For HTTP, this request will send a PUT request, which most servers
955 do not allow. Form upload mechanisms, including that of uploading
956 files through HTML forms, use the POST mechanism.
957
958 \sa get(), post(), deleteResource(), sendCustomRequest()
959*/
960QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, QIODevice *data)
961{
962 return d_func()->postProcess(reply: createRequest(op: QNetworkAccessManager::PutOperation, request, outgoingData: data));
963}
964
965/*!
966 \overload
967
968 Sends the contents of the \a data byte array to the destination
969 specified by \a request.
970*/
971QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, const QByteArray &data)
972{
973 QBuffer *buffer = new QBuffer;
974 buffer->setData(data);
975 buffer->open(openMode: QIODevice::ReadOnly);
976
977 QNetworkReply *reply = put(request, data: buffer);
978 buffer->setParent(reply);
979 return reply;
980}
981
982/*!
983 \since 4.6
984
985 Sends a request to delete the resource identified by the URL of \a request.
986
987 \note This feature is currently available for HTTP only, performing an
988 HTTP DELETE request.
989
990 \sa get(), post(), put(), sendCustomRequest()
991*/
992QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &request)
993{
994 return d_func()->postProcess(reply: createRequest(op: QNetworkAccessManager::DeleteOperation, request));
995}
996
997#ifndef QT_NO_BEARERMANAGEMENT // ### Qt6: Remove section
998
999/*!
1000 \since 4.7
1001 \obsolete
1002
1003 Sets the network configuration that will be used when creating the
1004 \l {QNetworkSession}{network session} to \a config.
1005
1006 The network configuration is used to create and open a network session before any request that
1007 requires network access is process. If no network configuration is explicitly set via this
1008 function the network configuration returned by
1009 QNetworkConfigurationManager::defaultConfiguration() will be used.
1010
1011 To restore the default network configuration set the network configuration to the value
1012 returned from QNetworkConfigurationManager::defaultConfiguration().
1013
1014 Setting a network configuration means that the QNetworkAccessManager instance will only
1015 be using the specified one. In particular, if the default network configuration changes
1016 (upon e.g. Wifi being available), this new configuration needs to be enabled
1017 manually if desired.
1018
1019 \snippet code/src_network_access_qnetworkaccessmanager.cpp 2
1020
1021 If an invalid network configuration is set, a network session will not be created. In this
1022 case network requests will be processed regardless, but may fail. For example:
1023
1024 \snippet code/src_network_access_qnetworkaccessmanager.cpp 3
1025
1026 \sa configuration(), QNetworkSession
1027*/
1028void QNetworkAccessManager::setConfiguration(const QNetworkConfiguration &config)
1029{
1030 Q_D(QNetworkAccessManager);
1031
1032 d->networkConfiguration = config;
1033 d->customNetworkConfiguration = true;
1034 d->createSession(config);
1035}
1036
1037/*!
1038 \since 4.7
1039 \obsolete
1040
1041 Returns the network configuration that will be used to create the
1042 \l {QNetworkSession}{network session} which will be used when processing network requests.
1043
1044 \sa setConfiguration(), activeConfiguration()
1045*/
1046QNetworkConfiguration QNetworkAccessManager::configuration() const
1047{
1048 Q_D(const QNetworkAccessManager);
1049
1050 QSharedPointer<QNetworkSession> session(d->getNetworkSession());
1051 if (session && !d->statusMonitor->isEnabled()) {
1052 return session->configuration();
1053 } else {
1054 return d->networkConfigurationManager.defaultConfiguration();
1055 }
1056}
1057
1058/*!
1059 \since 4.7
1060 \obsolete
1061
1062 Returns the current active network configuration.
1063
1064 If the network configuration returned by configuration() is of type
1065 QNetworkConfiguration::ServiceNetwork this function will return the current active child
1066 network configuration of that configuration. Otherwise returns the same network configuration
1067 as configuration().
1068
1069 Use this function to return the actual network configuration currently in use by the network
1070 session.
1071
1072 \sa configuration()
1073*/
1074QNetworkConfiguration QNetworkAccessManager::activeConfiguration() const
1075{
1076 Q_D(const QNetworkAccessManager);
1077
1078 QSharedPointer<QNetworkSession> networkSession(d->getNetworkSession());
1079 if (networkSession && !d->statusMonitor->isEnabled()) {
1080 return d->networkConfigurationManager.configurationFromIdentifier(
1081 identifier: networkSession->sessionProperty(key: QLatin1String("ActiveConfiguration")).toString());
1082 } else {
1083 return d->networkConfigurationManager.defaultConfiguration();
1084 }
1085}
1086
1087/*!
1088 \since 4.7
1089 \obsolete
1090
1091 Overrides the reported network accessibility. If \a accessible is NotAccessible the reported
1092 network accessiblity will always be NotAccessible. Otherwise the reported network
1093 accessibility will reflect the actual device state.
1094*/
1095void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkAccessibility accessible)
1096{
1097 Q_D(QNetworkAccessManager);
1098
1099 d->defaultAccessControl = accessible == NotAccessible ? false : true;
1100
1101 if (d->networkAccessible != accessible) {
1102QT_WARNING_PUSH
1103QT_WARNING_DISABLE_DEPRECATED
1104 NetworkAccessibility previous = networkAccessible();
1105 d->networkAccessible = accessible;
1106 NetworkAccessibility current = networkAccessible();
1107 if (previous != current)
1108 emit networkAccessibleChanged(accessible: current);
1109QT_WARNING_POP
1110 }
1111}
1112
1113/*!
1114 \since 4.7
1115 \obsolete
1116
1117 Returns the current network accessibility.
1118*/
1119QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccessible() const
1120{
1121 Q_D(const QNetworkAccessManager);
1122
1123 if (d->statusMonitor->isEnabled()) {
1124 if (!d->statusMonitor->isMonitoring())
1125 d->statusMonitor->start();
1126 return d->networkAccessible;
1127 }
1128
1129 if (d->customNetworkConfiguration && d->networkConfiguration.state().testFlag(flag: QNetworkConfiguration::Undefined))
1130 return UnknownAccessibility;
1131
1132 if (d->networkSessionRequired) {
1133 QSharedPointer<QNetworkSession> networkSession(d->getNetworkSession());
1134 if (networkSession) {
1135 // d->online holds online/offline state of this network session.
1136 if (d->online)
1137 return d->networkAccessible;
1138 else
1139 return NotAccessible;
1140 } else {
1141 if (d->defaultAccessControl) {
1142 if (d->online)
1143 return d->networkAccessible;
1144 else
1145 return NotAccessible;
1146 }
1147 return (d->networkAccessible);
1148 }
1149 } else {
1150 if (d->online)
1151 return d->networkAccessible;
1152 else
1153 return NotAccessible;
1154 }
1155}
1156
1157/*!
1158 \internal
1159
1160 Returns the network session currently in use.
1161 This can be changed at any time, ownership remains with the QNetworkAccessManager
1162*/
1163const QWeakPointer<const QNetworkSession> QNetworkAccessManagerPrivate::getNetworkSession(const QNetworkAccessManager *q)
1164{
1165 return q->d_func()->networkSessionWeakRef;
1166}
1167
1168QSharedPointer<QNetworkSession> QNetworkAccessManagerPrivate::getNetworkSession() const
1169{
1170 if (networkSessionStrongRef)
1171 return networkSessionStrongRef;
1172 return networkSessionWeakRef.toStrongRef();
1173}
1174
1175#endif // QT_NO_BEARERMANAGEMENT
1176
1177#ifndef QT_NO_SSL
1178/*!
1179 \since 5.2
1180
1181 Initiates a connection to the host given by \a hostName at port \a port, using
1182 \a sslConfiguration. This function is useful to complete the TCP and SSL handshake
1183 to a host before the HTTPS request is made, resulting in a lower network latency.
1184
1185 \note Preconnecting a SPDY connection can be done by calling setAllowedNextProtocols()
1186 on \a sslConfiguration with QSslConfiguration::NextProtocolSpdy3_0 contained in
1187 the list of allowed protocols. When using SPDY, one single connection per host is
1188 enough, i.e. calling this method multiple times per host will not result in faster
1189 network transactions.
1190
1191 \note This function has no possibility to report errors.
1192
1193 \sa connectToHost(), get(), post(), put(), deleteResource()
1194*/
1195
1196void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quint16 port,
1197 const QSslConfiguration &sslConfiguration)
1198{
1199 connectToHostEncrypted(hostName, port, sslConfiguration, peerName: QString());
1200}
1201
1202/*!
1203 \since 5.13
1204 \overload
1205
1206 Initiates a connection to the host given by \a hostName at port \a port, using
1207 \a sslConfiguration with \a peerName set to be the hostName used for certificate
1208 validation. This function is useful to complete the TCP and SSL handshake
1209 to a host before the HTTPS request is made, resulting in a lower network latency.
1210
1211 \note Preconnecting a SPDY connection can be done by calling setAllowedNextProtocols()
1212 on \a sslConfiguration with QSslConfiguration::NextProtocolSpdy3_0 contained in
1213 the list of allowed protocols. When using SPDY, one single connection per host is
1214 enough, i.e. calling this method multiple times per host will not result in faster
1215 network transactions.
1216
1217 \note This function has no possibility to report errors.
1218
1219 \sa connectToHost(), get(), post(), put(), deleteResource()
1220*/
1221
1222void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quint16 port,
1223 const QSslConfiguration &sslConfiguration,
1224 const QString &peerName)
1225{
1226 QUrl url;
1227 url.setHost(host: hostName);
1228 url.setPort(port);
1229 url.setScheme(QLatin1String("preconnect-https"));
1230 QNetworkRequest request(url);
1231 if (sslConfiguration != QSslConfiguration::defaultConfiguration())
1232 request.setSslConfiguration(sslConfiguration);
1233
1234 // There is no way to enable SPDY/HTTP2 via a request, so we need to check
1235 // the ssl configuration whether SPDY/HTTP2 is allowed here.
1236 if (sslConfiguration.allowedNextProtocols().contains(t: QSslConfiguration::ALPNProtocolHTTP2))
1237 request.setAttribute(code: QNetworkRequest::Http2AllowedAttribute, value: true);
1238 else if (sslConfiguration.allowedNextProtocols().contains(t: QSslConfiguration::NextProtocolSpdy3_0))
1239 request.setAttribute(code: QNetworkRequest::SpdyAllowedAttribute, value: true);
1240
1241 request.setPeerVerifyName(peerName);
1242 get(request);
1243}
1244#endif
1245
1246/*!
1247 \since 5.2
1248
1249 Initiates a connection to the host given by \a hostName at port \a port.
1250 This function is useful to complete the TCP handshake
1251 to a host before the HTTP request is made, resulting in a lower network latency.
1252
1253 \note This function has no possibility to report errors.
1254
1255 \sa connectToHostEncrypted(), get(), post(), put(), deleteResource()
1256*/
1257void QNetworkAccessManager::connectToHost(const QString &hostName, quint16 port)
1258{
1259 QUrl url;
1260 url.setHost(host: hostName);
1261 url.setPort(port);
1262 url.setScheme(QLatin1String("preconnect-http"));
1263 QNetworkRequest request(url);
1264 get(request);
1265}
1266
1267/*!
1268 \since 5.9
1269
1270 Sets the manager's redirect policy to be the \a policy specified. This policy
1271 will affect all subsequent requests created by the manager.
1272
1273 Use this function to enable or disable HTTP redirects on the manager's level.
1274
1275 \note When creating a request QNetworkRequest::RedirectAttributePolicy has
1276 the highest priority, next by priority is QNetworkRequest::FollowRedirectsAttribute.
1277 Finally, the manager's policy has the lowest priority.
1278
1279 For backwards compatibility the default value is QNetworkRequest::ManualRedirectPolicy.
1280 This may change in the future and some type of auto-redirect policy will become
1281 the default; clients relying on manual redirect handling are encouraged to set
1282 this policy explicitly in their code.
1283
1284 \sa redirectPolicy(), QNetworkRequest::RedirectPolicy,
1285 QNetworkRequest::FollowRedirectsAttribute
1286*/
1287void QNetworkAccessManager::setRedirectPolicy(QNetworkRequest::RedirectPolicy policy)
1288{
1289 Q_D(QNetworkAccessManager);
1290 d->redirectPolicy = policy;
1291}
1292
1293/*!
1294 \since 5.9
1295
1296 Returns the redirect policy that is used when creating new requests.
1297
1298 \sa setRedirectPolicy(), QNetworkRequest::RedirectPolicy
1299*/
1300QNetworkRequest::RedirectPolicy QNetworkAccessManager::redirectPolicy() const
1301{
1302 Q_D(const QNetworkAccessManager);
1303 return d->redirectPolicy;
1304}
1305
1306/*!
1307 \since 4.7
1308
1309 Sends a custom request to the server identified by the URL of \a request.
1310
1311 It is the user's responsibility to send a \a verb to the server that is valid
1312 according to the HTTP specification.
1313
1314 This method provides means to send verbs other than the common ones provided
1315 via get() or post() etc., for instance sending an HTTP OPTIONS command.
1316
1317 If \a data is not empty, the contents of the \a data
1318 device will be uploaded to the server; in that case, data must be open for
1319 reading and must remain valid until the finished() signal is emitted for this reply.
1320
1321 \note This feature is currently available for HTTP(S) only.
1322
1323 \sa get(), post(), put(), deleteResource()
1324*/
1325QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data)
1326{
1327 QNetworkRequest newRequest(request);
1328 newRequest.setAttribute(code: QNetworkRequest::CustomVerbAttribute, value: verb);
1329 return d_func()->postProcess(reply: createRequest(op: QNetworkAccessManager::CustomOperation, request: newRequest, outgoingData: data));
1330}
1331
1332/*!
1333 \since 5.8
1334
1335 \overload
1336
1337 Sends the contents of the \a data byte array to the destination
1338 specified by \a request.
1339*/
1340QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, const QByteArray &data)
1341{
1342 QBuffer *buffer = new QBuffer;
1343 buffer->setData(data);
1344 buffer->open(openMode: QIODevice::ReadOnly);
1345
1346 QNetworkReply *reply = sendCustomRequest(request, verb, data: buffer);
1347 buffer->setParent(reply);
1348 return reply;
1349}
1350
1351#if QT_CONFIG(http)
1352/*!
1353 \since 5.8
1354
1355 \overload
1356
1357 Sends a custom request to the server identified by the URL of \a request.
1358
1359 Sends the contents of the \a multiPart message to the destination
1360 specified by \a request.
1361
1362 This can be used for sending MIME multipart messages for custom verbs.
1363
1364 \sa QHttpMultiPart, QHttpPart, put()
1365*/
1366QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QHttpMultiPart *multiPart)
1367{
1368 QNetworkRequest newRequest = d_func()->prepareMultipart(request, multiPart);
1369 QIODevice *device = multiPart->d_func()->device;
1370 QNetworkReply *reply = sendCustomRequest(request: newRequest, verb, data: device);
1371 return reply;
1372}
1373#endif // QT_CONFIG(http)
1374
1375/*!
1376 Returns a new QNetworkReply object to handle the operation \a op
1377 and request \a originalReq. The device \a outgoingData is always 0
1378 for Get and Head requests, but is the value passed to post() and
1379 put() in those operations (the QByteArray variants will pass a QBuffer
1380 object).
1381
1382 The default implementation calls QNetworkCookieJar::cookiesForUrl()
1383 on the cookie jar set with setCookieJar() to obtain the cookies to
1384 be sent to the remote server.
1385
1386 The returned object must be in an open state.
1387*/
1388QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op,
1389 const QNetworkRequest &originalReq,
1390 QIODevice *outgoingData)
1391{
1392 Q_D(QNetworkAccessManager);
1393
1394 QNetworkRequest req(originalReq);
1395 if (redirectPolicy() != QNetworkRequest::ManualRedirectPolicy
1396 && req.attribute(code: QNetworkRequest::RedirectPolicyAttribute).isNull()
1397 && req.attribute(code: QNetworkRequest::FollowRedirectsAttribute).isNull()) {
1398 req.setAttribute(code: QNetworkRequest::RedirectPolicyAttribute, value: redirectPolicy());
1399 }
1400
1401#if QT_CONFIG(http) || defined (Q_OS_WASM)
1402 if (!req.transferTimeout())
1403 req.setTransferTimeout(transferTimeout());
1404#endif
1405
1406 if (autoDeleteReplies()
1407 && req.attribute(code: QNetworkRequest::AutoDeleteReplyOnFinishAttribute).isNull()) {
1408 req.setAttribute(code: QNetworkRequest::AutoDeleteReplyOnFinishAttribute, value: true);
1409 }
1410
1411 bool isLocalFile = req.url().isLocalFile();
1412 QString scheme = req.url().scheme();
1413
1414
1415 // fast path for GET on file:// URLs
1416 // The QNetworkAccessFileBackend will right now only be used for PUT
1417 if (op == QNetworkAccessManager::GetOperation
1418 || op == QNetworkAccessManager::HeadOperation) {
1419 if (isLocalFile
1420#ifdef Q_OS_ANDROID
1421 || scheme == QLatin1String("assets")
1422#endif
1423 || scheme == QLatin1String("qrc")) {
1424 return new QNetworkReplyFileImpl(this, req, op);
1425 }
1426
1427 if (scheme == QLatin1String("data"))
1428 return new QNetworkReplyDataImpl(this, req, op);
1429
1430 // A request with QNetworkRequest::AlwaysCache does not need any bearer management
1431 QNetworkRequest::CacheLoadControl mode =
1432 static_cast<QNetworkRequest::CacheLoadControl>(
1433 req.attribute(code: QNetworkRequest::CacheLoadControlAttribute,
1434 defaultValue: QNetworkRequest::PreferNetwork).toInt());
1435 if (mode == QNetworkRequest::AlwaysCache) {
1436 // FIXME Implement a QNetworkReplyCacheImpl instead, see QTBUG-15106
1437 QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
1438 QNetworkReplyImplPrivate *priv = reply->d_func();
1439 priv->manager = this;
1440 priv->backend = new QNetworkAccessCacheBackend();
1441 priv->backend->manager = this->d_func();
1442 priv->backend->setParent(reply);
1443 priv->backend->reply = priv;
1444 priv->setup(op, request: req, outgoingData);
1445 return reply;
1446 }
1447 }
1448 QNetworkRequest request = req;
1449 if (!request.header(header: QNetworkRequest::ContentLengthHeader).isValid() &&
1450 outgoingData && !outgoingData->isSequential()) {
1451 // request has no Content-Length
1452 // but the data that is outgoing is random-access
1453 request.setHeader(header: QNetworkRequest::ContentLengthHeader, value: outgoingData->size());
1454 }
1455
1456 if (static_cast<QNetworkRequest::LoadControl>
1457 (request.attribute(code: QNetworkRequest::CookieLoadControlAttribute,
1458 defaultValue: QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Automatic) {
1459 if (d->cookieJar) {
1460 QList<QNetworkCookie> cookies = d->cookieJar->cookiesForUrl(url: request.url());
1461 if (!cookies.isEmpty())
1462 request.setHeader(header: QNetworkRequest::CookieHeader, value: QVariant::fromValue(value: cookies));
1463 }
1464 }
1465#ifdef Q_OS_WASM
1466 // Support http, https, and relative urls
1467 if (scheme == QLatin1String("http") || scheme == QLatin1String("https") || scheme.isEmpty()) {
1468 QNetworkReplyWasmImpl *reply = new QNetworkReplyWasmImpl(this);
1469 QNetworkReplyWasmImplPrivate *priv = reply->d_func();
1470 priv->manager = this;
1471 priv->setup(op, request, outgoingData);
1472 return reply;
1473 }
1474#endif
1475
1476#if QT_CONFIG(http)
1477 // Since Qt 5 we use the new QNetworkReplyHttpImpl
1478 if (scheme == QLatin1String("http") || scheme == QLatin1String("preconnect-http")
1479#ifndef QT_NO_SSL
1480 || scheme == QLatin1String("https") || scheme == QLatin1String("preconnect-https")
1481#endif
1482 ) {
1483#ifndef QT_NO_SSL
1484 if (isStrictTransportSecurityEnabled() && d->stsCache.isKnownHost(url: request.url())) {
1485 QUrl stsUrl(request.url());
1486 // RFC6797, 8.3:
1487 // The UA MUST replace the URI scheme with "https" [RFC2818],
1488 // and if the URI contains an explicit port component of "80",
1489 // then the UA MUST convert the port component to be "443", or
1490 // if the URI contains an explicit port component that is not
1491 // equal to "80", the port component value MUST be preserved;
1492 // otherwise,
1493 // if the URI does not contain an explicit port component, the UA
1494 // MUST NOT add one.
1495 if (stsUrl.port() == 80)
1496 stsUrl.setPort(443);
1497 stsUrl.setScheme(QLatin1String("https"));
1498 request.setUrl(stsUrl);
1499 }
1500#endif
1501 QNetworkReplyHttpImpl *reply = new QNetworkReplyHttpImpl(this, request, op, outgoingData);
1502#ifndef QT_NO_BEARERMANAGEMENT // ### Qt6: Remove section
1503 if (!d->statusMonitor->isEnabled()) {
1504 connect(sender: this, SIGNAL(networkSessionConnected()),
1505 receiver: reply, SLOT(_q_networkSessionConnected()));
1506 }
1507#endif
1508 return reply;
1509 }
1510#endif // QT_CONFIG(http)
1511
1512 // first step: create the reply
1513 QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
1514#ifndef QT_NO_BEARERMANAGEMENT // ### Qt6: Remove section
1515 // NETMONTODO: network reply impl must be augmented to use the same monitoring
1516 // capabilities as http network reply impl does. Once it does: uncomment the condition below
1517 if (!isLocalFile /*&& !d->statusMonitor.isEnabled()*/) {
1518 connect(sender: this, SIGNAL(networkSessionConnected()),
1519 receiver: reply, SLOT(_q_networkSessionConnected()));
1520 }
1521#endif
1522 QNetworkReplyImplPrivate *priv = reply->d_func();
1523 priv->manager = this;
1524
1525 // second step: fetch cached credentials
1526 // This is not done for the time being, we should use signal emissions to request
1527 // the credentials from cache.
1528
1529 // third step: find a backend
1530 priv->backend = d->findBackend(op, request);
1531
1532 if (priv->backend) {
1533 priv->backend->setParent(reply);
1534 priv->backend->reply = priv;
1535 }
1536
1537#ifndef QT_NO_SSL
1538 reply->setSslConfiguration(request.sslConfiguration());
1539#endif
1540
1541 // fourth step: setup the reply
1542 priv->setup(op, request, outgoingData);
1543
1544 return reply;
1545}
1546
1547/*!
1548 \since 5.2
1549
1550 Lists all the URL schemes supported by the access manager.
1551
1552 \sa supportedSchemesImplementation()
1553*/
1554QStringList QNetworkAccessManager::supportedSchemes() const
1555{
1556 QStringList schemes;
1557 QNetworkAccessManager *self = const_cast<QNetworkAccessManager *>(this); // We know we call a const slot
1558 QMetaObject::invokeMethod(obj: self, member: "supportedSchemesImplementation", Qt::DirectConnection,
1559 Q_RETURN_ARG(QStringList, schemes));
1560 schemes.removeDuplicates();
1561 return schemes;
1562}
1563
1564/*!
1565 \since 5.2
1566
1567 Lists all the URL schemes supported by the access manager.
1568
1569 You should not call this function directly; use
1570 QNetworkAccessManager::supportedSchemes() instead.
1571
1572 Reimplement this slot to provide your own supported schemes
1573 in a QNetworkAccessManager subclass. It is for instance necessary
1574 when your subclass provides support for new protocols.
1575
1576 Because of binary compatibility constraints, the supportedSchemes()
1577 method (introduced in Qt 5.2) is not virtual. Instead, supportedSchemes()
1578 will dynamically detect and call this slot.
1579
1580 \sa supportedSchemes()
1581*/
1582QStringList QNetworkAccessManager::supportedSchemesImplementation() const
1583{
1584 Q_D(const QNetworkAccessManager);
1585
1586 QStringList schemes = d->backendSupportedSchemes();
1587 // Those ones don't exist in backends
1588#if QT_CONFIG(http)
1589 schemes << QStringLiteral("http");
1590#ifndef QT_NO_SSL
1591 if (QSslSocket::supportsSsl())
1592 schemes << QStringLiteral("https");
1593#endif
1594#endif
1595 schemes << QStringLiteral("data");
1596 return schemes;
1597}
1598
1599/*!
1600 \since 5.0
1601
1602 Flushes the internal cache of authentication data and network connections.
1603
1604 This function is useful for doing auto tests.
1605
1606 \sa clearConnectionCache()
1607*/
1608void QNetworkAccessManager::clearAccessCache()
1609{
1610 QNetworkAccessManagerPrivate::clearAuthenticationCache(manager: this);
1611 QNetworkAccessManagerPrivate::clearConnectionCache(manager: this);
1612}
1613
1614/*!
1615 \since 5.9
1616
1617 Flushes the internal cache of network connections.
1618 In contrast to clearAccessCache() the authentication data
1619 is preserved.
1620
1621 \sa clearAccessCache()
1622*/
1623void QNetworkAccessManager::clearConnectionCache()
1624{
1625 QNetworkAccessManagerPrivate::clearConnectionCache(manager: this);
1626}
1627
1628
1629/*!
1630 \since 5.14
1631
1632 Returns the true if QNetworkAccessManager is currently configured
1633 to automatically delete QNetworkReplies, false otherwise.
1634
1635 \sa setAutoDeleteReplies,
1636 QNetworkRequest::AutoDeleteReplyOnFinishAttribute
1637*/
1638bool QNetworkAccessManager::autoDeleteReplies() const
1639{
1640 return d_func()->autoDeleteReplies;
1641}
1642
1643/*!
1644 \since 5.14
1645
1646 Enables or disables automatic deletion of \l {QNetworkReply} {QNetworkReplies}.
1647
1648 Setting \a shouldAutoDelete to true is the same as setting the
1649 QNetworkRequest::AutoDeleteReplyOnFinishAttribute attribute to
1650 true on all \e{future} \l {QNetworkRequest} {QNetworkRequests}
1651 passed to this instance of QNetworkAccessManager unless the
1652 attribute was already explicitly set on the QNetworkRequest.
1653
1654 \sa autoDeleteReplies,
1655 QNetworkRequest::AutoDeleteReplyOnFinishAttribute
1656*/
1657void QNetworkAccessManager::setAutoDeleteReplies(bool shouldAutoDelete)
1658{
1659 d_func()->autoDeleteReplies = shouldAutoDelete;
1660}
1661
1662/*!
1663 \since 5.15
1664
1665 Returns the timeout used for transfers, in milliseconds.
1666
1667 This timeout is zero if setTransferTimeout() hasn't been
1668 called, which means that the timeout is not used.
1669*/
1670int QNetworkAccessManager::transferTimeout() const
1671{
1672 return d_func()->transferTimeout;
1673}
1674
1675/*!
1676 \since 5.15
1677
1678 Sets \a timeout as the transfer timeout in milliseconds.
1679
1680 Transfers are aborted if no bytes are transferred before
1681 the timeout expires. Zero means no timer is set. If no
1682 argument is provided, the timeout is
1683 QNetworkRequest::DefaultTransferTimeoutConstant. If this function
1684 is not called, the timeout is disabled and has the
1685 value zero. The request-specific non-zero timeouts set for
1686 the requests that are executed override this value. This means
1687 that if QNetworkAccessManager has an enabled timeout, it needs
1688 to be disabled to execute a request without a timeout.
1689
1690 \sa transferTimeout()
1691*/
1692void QNetworkAccessManager::setTransferTimeout(int timeout)
1693{
1694 d_func()->transferTimeout = timeout;
1695}
1696
1697void QNetworkAccessManagerPrivate::_q_replyFinished(QNetworkReply *reply)
1698{
1699 Q_Q(QNetworkAccessManager);
1700
1701 emit q->finished(reply);
1702 if (reply->request().attribute(code: QNetworkRequest::AutoDeleteReplyOnFinishAttribute, defaultValue: false).toBool())
1703 QMetaObject::invokeMethod(context: reply, function: [reply] { reply->deleteLater(); }, type: Qt::QueuedConnection);
1704
1705#ifndef QT_NO_BEARERMANAGEMENT // ### Qt6: Remove section
1706 // If there are no active requests, release our reference to the network session.
1707 // It will not be destroyed immediately, but rather when the connection cache is flushed
1708 // after 2 minutes.
1709 activeReplyCount--;
1710 if (networkSessionStrongRef && activeReplyCount == 0)
1711 networkSessionStrongRef.clear();
1712#endif
1713}
1714
1715void QNetworkAccessManagerPrivate::_q_replyEncrypted(QNetworkReply *reply)
1716{
1717#ifndef QT_NO_SSL
1718 Q_Q(QNetworkAccessManager);
1719 emit q->encrypted(reply);
1720#else
1721 Q_UNUSED(reply);
1722#endif
1723}
1724
1725void QNetworkAccessManagerPrivate::_q_replySslErrors(const QList<QSslError> &errors)
1726{
1727#ifndef QT_NO_SSL
1728 Q_Q(QNetworkAccessManager);
1729 QNetworkReply *reply = qobject_cast<QNetworkReply *>(object: q->sender());
1730 if (reply)
1731 emit q->sslErrors(reply, errors);
1732#else
1733 Q_UNUSED(errors);
1734#endif
1735}
1736
1737void QNetworkAccessManagerPrivate::_q_replyPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator)
1738{
1739#ifndef QT_NO_SSL
1740 Q_Q(QNetworkAccessManager);
1741 QNetworkReply *reply = qobject_cast<QNetworkReply *>(object: q->sender());
1742 if (reply)
1743 emit q->preSharedKeyAuthenticationRequired(reply, authenticator);
1744#else
1745 Q_UNUSED(authenticator);
1746#endif
1747}
1748
1749QNetworkReply *QNetworkAccessManagerPrivate::postProcess(QNetworkReply *reply)
1750{
1751 Q_Q(QNetworkAccessManager);
1752 QNetworkReplyPrivate::setManager(reply, manager: q);
1753 q->connect(sender: reply, signal: &QNetworkReply::finished, context: reply,
1754 slot: [this, reply]() { _q_replyFinished(reply); });
1755#ifndef QT_NO_SSL
1756 /* In case we're compiled without SSL support, we don't have this signal and we need to
1757 * avoid getting a connection error. */
1758 q->connect(sender: reply, signal: &QNetworkReply::encrypted, context: reply,
1759 slot: [this, reply]() { _q_replyEncrypted(reply); });
1760 q->connect(asender: reply, SIGNAL(sslErrors(QList<QSslError>)), SLOT(_q_replySslErrors(QList<QSslError>)));
1761 q->connect(asender: reply, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), SLOT(_q_replyPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)));
1762#endif
1763#ifndef QT_NO_BEARERMANAGEMENT // ### Qt6: Remove section
1764 activeReplyCount++;
1765#endif
1766
1767 return reply;
1768}
1769
1770void QNetworkAccessManagerPrivate::createCookieJar() const
1771{
1772 if (!cookieJarCreated) {
1773 // keep the ugly hack in here
1774 QNetworkAccessManagerPrivate *that = const_cast<QNetworkAccessManagerPrivate *>(this);
1775 that->cookieJar = new QNetworkCookieJar(that->q_func());
1776 that->cookieJarCreated = true;
1777 }
1778}
1779
1780void QNetworkAccessManagerPrivate::authenticationRequired(QAuthenticator *authenticator,
1781 QNetworkReply *reply,
1782 bool synchronous,
1783 QUrl &url,
1784 QUrl *urlForLastAuthentication,
1785 bool allowAuthenticationReuse)
1786{
1787 Q_Q(QNetworkAccessManager);
1788
1789 // don't try the cache for the same URL twice in a row
1790 // being called twice for the same URL means the authentication failed
1791 // also called when last URL is empty, e.g. on first call
1792 if (allowAuthenticationReuse && (urlForLastAuthentication->isEmpty()
1793 || url != *urlForLastAuthentication)) {
1794 // if credentials are included in the url, then use them, unless they were already used
1795 if (!url.userName().isEmpty() && !url.password().isEmpty()
1796 && (url.userName() != authenticator->user()
1797 || url.password() != authenticator->password())) {
1798 authenticator->setUser(url.userName(options: QUrl::FullyDecoded));
1799 authenticator->setPassword(url.password(QUrl::FullyDecoded));
1800 *urlForLastAuthentication = url;
1801 authenticationManager->cacheCredentials(url, auth: authenticator);
1802 return;
1803 }
1804
1805 QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedCredentials(url, auth: authenticator);
1806 if (!cred.isNull()
1807 && (cred.user != authenticator->user() || cred.password != authenticator->password())) {
1808 authenticator->setUser(cred.user);
1809 authenticator->setPassword(cred.password);
1810 *urlForLastAuthentication = url;
1811 return;
1812 }
1813 }
1814
1815 // if we emit a signal here in synchronous mode, the user might spin
1816 // an event loop, which might recurse and lead to problems
1817 if (synchronous)
1818 return;
1819
1820 *urlForLastAuthentication = url;
1821 emit q->authenticationRequired(reply, authenticator);
1822 if (allowAuthenticationReuse)
1823 authenticationManager->cacheCredentials(url, auth: authenticator);
1824}
1825
1826#ifndef QT_NO_NETWORKPROXY
1827void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(const QUrl &url,
1828 const QNetworkProxy &proxy,
1829 bool synchronous,
1830 QAuthenticator *authenticator,
1831 QNetworkProxy *lastProxyAuthentication)
1832{
1833 Q_Q(QNetworkAccessManager);
1834 QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(auth&: *authenticator);
1835 if (proxy != *lastProxyAuthentication && (!priv || !priv->hasFailed)) {
1836 QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedProxyCredentials(proxy);
1837 if (!cred.isNull()) {
1838 authenticator->setUser(cred.user);
1839 authenticator->setPassword(cred.password);
1840 return;
1841 }
1842 }
1843
1844#if defined(Q_OS_MACOS)
1845 //now we try to get the username and password from keychain
1846 //if not successful signal will be emitted
1847 QString username;
1848 QString password;
1849 if (getProxyAuth(proxy.hostName(), url.scheme(), username, password)) {
1850 // only cache the system credentials if they are correct (or if they have changed)
1851 // to not run into an endless loop in case they are wrong
1852 QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedProxyCredentials(proxy);
1853 if (!priv->hasFailed || cred.user != username || cred.password != password) {
1854 authenticator->setUser(username);
1855 authenticator->setPassword(password);
1856 authenticationManager->cacheProxyCredentials(proxy, authenticator);
1857 return;
1858 }
1859 }
1860#else
1861 Q_UNUSED(url);
1862#endif
1863
1864 // if we emit a signal here in synchronous mode, the user might spin
1865 // an event loop, which might recurse and lead to problems
1866 if (synchronous)
1867 return;
1868
1869 *lastProxyAuthentication = proxy;
1870 emit q->proxyAuthenticationRequired(proxy, authenticator);
1871 authenticationManager->cacheProxyCredentials(proxy, auth: authenticator);
1872}
1873
1874QList<QNetworkProxy> QNetworkAccessManagerPrivate::queryProxy(const QNetworkProxyQuery &query)
1875{
1876 QList<QNetworkProxy> proxies;
1877 if (proxyFactory) {
1878 proxies = proxyFactory->queryProxy(query);
1879 if (proxies.isEmpty()) {
1880 qWarning(msg: "QNetworkAccessManager: factory %p has returned an empty result set",
1881 proxyFactory);
1882 proxies << QNetworkProxy::NoProxy;
1883 }
1884 } else if (proxy.type() == QNetworkProxy::DefaultProxy) {
1885 // no proxy set, query the application
1886 return QNetworkProxyFactory::proxyForQuery(query);
1887 } else {
1888 proxies << proxy;
1889 }
1890
1891 return proxies;
1892}
1893#endif
1894
1895void QNetworkAccessManagerPrivate::clearAuthenticationCache(QNetworkAccessManager *manager)
1896{
1897 manager->d_func()->authenticationManager->clearCache();
1898}
1899
1900void QNetworkAccessManagerPrivate::clearConnectionCache(QNetworkAccessManager *manager)
1901{
1902 manager->d_func()->objectCache.clear();
1903 manager->d_func()->destroyThread();
1904}
1905
1906QNetworkAccessManagerPrivate::~QNetworkAccessManagerPrivate()
1907{
1908 destroyThread();
1909}
1910
1911QThread * QNetworkAccessManagerPrivate::createThread()
1912{
1913 if (!thread) {
1914 thread = new QThread;
1915 thread->setObjectName(QStringLiteral("QNetworkAccessManager thread"));
1916 thread->start();
1917 }
1918 Q_ASSERT(thread);
1919 return thread;
1920}
1921
1922void QNetworkAccessManagerPrivate::destroyThread()
1923{
1924 if (thread) {
1925 thread->quit();
1926 thread->wait(deadline: QDeadlineTimer(5000));
1927 if (thread->isFinished())
1928 delete thread;
1929 else
1930 QObject::connect(sender: thread, SIGNAL(finished()), receiver: thread, SLOT(deleteLater()));
1931 thread = nullptr;
1932 }
1933}
1934
1935#ifndef QT_NO_BEARERMANAGEMENT // ### Qt6: Remove section
1936void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &config)
1937{
1938 Q_Q(QNetworkAccessManager);
1939
1940 initializeSession = false;
1941
1942 //resurrect weak ref if possible
1943 networkSessionStrongRef = networkSessionWeakRef.toStrongRef();
1944
1945 QSharedPointer<QNetworkSession> newSession;
1946 if (config.isValid())
1947 newSession = QSharedNetworkSessionManager::getSession(config);
1948
1949 QNetworkSession::State oldState = QNetworkSession::Invalid;
1950 if (networkSessionStrongRef) {
1951 //do nothing if new and old session are the same
1952 if (networkSessionStrongRef == newSession)
1953 return;
1954 //disconnect from old session
1955 QObject::disconnect(sender: networkSessionStrongRef.data(), SIGNAL(opened()), receiver: q, SIGNAL(networkSessionConnected()));
1956 QObject::disconnect(sender: networkSessionStrongRef.data(), SIGNAL(closed()), receiver: q, SLOT(_q_networkSessionClosed()));
1957 QObject::disconnect(sender: networkSessionStrongRef.data(), SIGNAL(stateChanged(QNetworkSession::State)),
1958 receiver: q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)));
1959 QObject::disconnect(sender: networkSessionStrongRef.data(), SIGNAL(error(QNetworkSession::SessionError)),
1960 receiver: q, SLOT(_q_networkSessionFailed(QNetworkSession::SessionError)));
1961 oldState = networkSessionStrongRef->state();
1962 }
1963
1964 //switch to new session (null if config was invalid)
1965 networkSessionStrongRef = newSession;
1966 networkSessionWeakRef = networkSessionStrongRef.toWeakRef();
1967
1968 if (!networkSessionStrongRef) {
1969
1970QT_WARNING_PUSH
1971QT_WARNING_DISABLE_DEPRECATED
1972 if (networkAccessible == QNetworkAccessManager::NotAccessible || !online)
1973 emit q->networkAccessibleChanged(accessible: QNetworkAccessManager::NotAccessible);
1974 else
1975 emit q->networkAccessibleChanged(accessible: QNetworkAccessManager::UnknownAccessibility);
1976QT_WARNING_POP
1977
1978 return;
1979 }
1980
1981 //connect to new session
1982 QObject::connect(sender: networkSessionStrongRef.data(), SIGNAL(opened()), receiver: q, SIGNAL(networkSessionConnected()), Qt::QueuedConnection);
1983 //QueuedConnection is used to avoid deleting the networkSession inside its closed signal
1984 QObject::connect(sender: networkSessionStrongRef.data(), SIGNAL(closed()), receiver: q, SLOT(_q_networkSessionClosed()), Qt::QueuedConnection);
1985 QObject::connect(sender: networkSessionStrongRef.data(), SIGNAL(stateChanged(QNetworkSession::State)),
1986 receiver: q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)), Qt::QueuedConnection);
1987 QObject::connect(sender: networkSessionStrongRef.data(), SIGNAL(error(QNetworkSession::SessionError)),
1988 receiver: q, SLOT(_q_networkSessionFailed(QNetworkSession::SessionError)));
1989
1990 const QNetworkSession::State newState = networkSessionStrongRef->state();
1991 if (newState != oldState) {
1992 QMetaObject::invokeMethod(obj: q, member: "_q_networkSessionStateChanged", type: Qt::QueuedConnection,
1993 Q_ARG(QNetworkSession::State, newState));
1994 }
1995}
1996
1997void QNetworkAccessManagerPrivate::_q_networkSessionClosed()
1998{
1999 Q_Q(QNetworkAccessManager);
2000 QSharedPointer<QNetworkSession> networkSession(getNetworkSession());
2001 if (networkSession) {
2002 networkConfiguration = networkSession->configuration();
2003
2004 //disconnect from old session
2005 QObject::disconnect(sender: networkSession.data(), SIGNAL(opened()), receiver: q, SIGNAL(networkSessionConnected()));
2006 QObject::disconnect(sender: networkSession.data(), SIGNAL(closed()), receiver: q, SLOT(_q_networkSessionClosed()));
2007 QObject::disconnect(sender: networkSession.data(), SIGNAL(stateChanged(QNetworkSession::State)),
2008 receiver: q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)));
2009 QObject::disconnect(sender: networkSession.data(), SIGNAL(error(QNetworkSession::SessionError)),
2010 receiver: q, SLOT(_q_networkSessionFailed(QNetworkSession::SessionError)));
2011
2012 networkSessionStrongRef.clear();
2013 networkSessionWeakRef.clear();
2014 }
2015}
2016
2017void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession::State state)
2018{
2019 Q_Q(QNetworkAccessManager);
2020 bool reallyOnline = false;
2021 //Do not emit the networkSessionConnected signal here, except for roaming -> connected
2022 //transition, otherwise it is emitted twice in a row when opening a connection.
2023QT_WARNING_PUSH
2024QT_WARNING_DISABLE_DEPRECATED
2025 if (state == QNetworkSession::Connected && lastSessionState != QNetworkSession::Roaming)
2026 emit q->networkSessionConnected();
2027 lastSessionState = state;
2028
2029 if (online && (state == QNetworkSession::Disconnected
2030 || state == QNetworkSession::NotAvailable)) {
2031 const auto cfgs = networkConfigurationManager.allConfigurations();
2032 for (const QNetworkConfiguration &cfg : cfgs) {
2033 if (cfg.state().testFlag(flag: QNetworkConfiguration::Active)) {
2034 reallyOnline = true;
2035 }
2036 }
2037 } else if (state == QNetworkSession::Connected || state == QNetworkSession::Roaming) {
2038 reallyOnline = true;
2039 }
2040 online = reallyOnline;
2041
2042 if (!reallyOnline) {
2043 if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) {
2044 if (networkAccessible != QNetworkAccessManager::NotAccessible) {
2045 networkAccessible = QNetworkAccessManager::NotAccessible;
2046 emit q->networkAccessibleChanged(accessible: networkAccessible);
2047 }
2048 }
2049 } else {
2050 if (defaultAccessControl)
2051 if (networkAccessible != QNetworkAccessManager::Accessible) {
2052 networkAccessible = QNetworkAccessManager::Accessible;
2053 emit q->networkAccessibleChanged(accessible: networkAccessible);
2054 }
2055 }
2056 if (online && (state != QNetworkSession::Connected && state != QNetworkSession::Roaming)) {
2057 _q_networkSessionClosed();
2058 createSession(config: q->configuration());
2059 }
2060QT_WARNING_POP
2061}
2062
2063void QNetworkAccessManagerPrivate::_q_onlineStateChanged(bool isOnline)
2064{
2065 Q_Q(QNetworkAccessManager);
2066
2067QT_WARNING_PUSH
2068QT_WARNING_DISABLE_DEPRECATED
2069
2070 if (statusMonitor->isEnabled()) {
2071 auto previous = networkAccessible;
2072 networkAccessible = isOnline ? QNetworkAccessManager::Accessible : QNetworkAccessManager::NotAccessible;
2073QT_WARNING_PUSH
2074QT_WARNING_DISABLE_DEPRECATED
2075 if (previous != networkAccessible)
2076 emit q->networkAccessibleChanged(accessible: networkAccessible);
2077QT_WARNING_POP
2078 return;
2079 }
2080
2081 // if the user set a config, we only care whether this one is active.
2082 // Otherwise, this QNAM is online if there is an online config.
2083 if (customNetworkConfiguration) {
2084 online = (networkConfiguration.state() & QNetworkConfiguration::Active);
2085 } else {
2086 if (online != isOnline) {
2087 online = isOnline;
2088 _q_networkSessionClosed();
2089 createSession(config: q->configuration());
2090 }
2091 }
2092 if (online) {
2093 if (defaultAccessControl) {
2094 if (networkAccessible != QNetworkAccessManager::Accessible) {
2095 networkAccessible = QNetworkAccessManager::Accessible;
2096 emit q->networkAccessibleChanged(accessible: networkAccessible);
2097 }
2098 }
2099 } else {
2100 if (networkAccessible != QNetworkAccessManager::NotAccessible) {
2101 networkAccessible = QNetworkAccessManager::NotAccessible;
2102 emit q->networkAccessibleChanged(accessible: networkAccessible);
2103 }
2104 }
2105QT_WARNING_POP
2106}
2107
2108void QNetworkAccessManagerPrivate::_q_configurationChanged(const QNetworkConfiguration &configuration)
2109{
2110 if (statusMonitor->isEnabled())
2111 return;
2112
2113 const QString id = configuration.identifier();
2114 if (configuration.state().testFlag(flag: QNetworkConfiguration::Active)) {
2115 if (!onlineConfigurations.contains(value: id)) {
2116 QSharedPointer<QNetworkSession> session(getNetworkSession());
2117 if (session) {
2118 if (online && session->configuration().identifier()
2119 != networkConfigurationManager.defaultConfiguration().identifier()) {
2120
2121 onlineConfigurations.insert(value: id);
2122 // CHECK: If it's having Active flag - why would it be disconnected ???
2123 //this one disconnected but another one is online,
2124 // close and create new session
2125 _q_networkSessionClosed();
2126 createSession(config: networkConfigurationManager.defaultConfiguration());
2127 }
2128 }
2129 }
2130
2131 } else if (onlineConfigurations.contains(value: id)) {
2132 //this one is disconnecting
2133 // CHECK: If it disconnected while we create a session over a down configuration ???
2134 onlineConfigurations.remove(value: id);
2135 if (!onlineConfigurations.isEmpty()) {
2136 _q_networkSessionClosed();
2137 createSession(config: configuration);
2138 }
2139 }
2140}
2141
2142
2143void QNetworkAccessManagerPrivate::_q_networkSessionFailed(QNetworkSession::SessionError)
2144{
2145 if (statusMonitor->isEnabled())
2146 return;
2147
2148 const auto cfgs = networkConfigurationManager.allConfigurations();
2149 for (const QNetworkConfiguration &cfg : cfgs) {
2150 if (cfg.state().testFlag(flag: QNetworkConfiguration::Active)) {
2151 online = true;
2152 _q_networkSessionClosed();
2153 createSession(config: networkConfigurationManager.defaultConfiguration());
2154 return;
2155 }
2156 }
2157}
2158
2159#else
2160
2161void QNetworkAccessManagerPrivate::_q_onlineStateChanged(bool isOnline)
2162{
2163 networkAccessible = isOnline;
2164}
2165
2166#endif // QT_NO_BEARERMANAGEMENT
2167
2168#if QT_CONFIG(http)
2169QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart)
2170{
2171 // copy the request, we probably need to add some headers
2172 QNetworkRequest newRequest(request);
2173
2174 // add Content-Type header if not there already
2175 if (!request.header(header: QNetworkRequest::ContentTypeHeader).isValid()) {
2176 QByteArray contentType;
2177 contentType.reserve(asize: 34 + multiPart->d_func()->boundary.count());
2178 contentType += "multipart/";
2179 switch (multiPart->d_func()->contentType) {
2180 case QHttpMultiPart::RelatedType:
2181 contentType += "related";
2182 break;
2183 case QHttpMultiPart::FormDataType:
2184 contentType += "form-data";
2185 break;
2186 case QHttpMultiPart::AlternativeType:
2187 contentType += "alternative";
2188 break;
2189 default:
2190 contentType += "mixed";
2191 break;
2192 }
2193 // putting the boundary into quotes, recommended in RFC 2046 section 5.1.1
2194 contentType += "; boundary=\"" + multiPart->d_func()->boundary + '"';
2195 newRequest.setHeader(header: QNetworkRequest::ContentTypeHeader, value: QVariant(contentType));
2196 }
2197
2198 // add MIME-Version header if not there already (we must include the header
2199 // if the message conforms to RFC 2045, see section 4 of that RFC)
2200 QByteArray mimeHeader("MIME-Version");
2201 if (!request.hasRawHeader(headerName: mimeHeader))
2202 newRequest.setRawHeader(headerName: mimeHeader, value: QByteArray("1.0"));
2203
2204 QIODevice *device = multiPart->d_func()->device;
2205 if (!device->isReadable()) {
2206 if (!device->isOpen()) {
2207 if (!device->open(mode: QIODevice::ReadOnly))
2208 qWarning(msg: "could not open device for reading");
2209 } else {
2210 qWarning(msg: "device is not readable");
2211 }
2212 }
2213
2214 return newRequest;
2215}
2216#endif // QT_CONFIG(http)
2217
2218QT_END_NAMESPACE
2219
2220#include "moc_qnetworkaccessmanager.cpp"
2221

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