1/****************************************************************************
2**
3** Copyright (C) 2020 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 "qnetworkaccessfilebackend_p.h"
58#include "qnetworkaccessdebugpipebackend_p.h"
59#include "qnetworkaccesscachebackend_p.h"
60#include "qnetworkreplydataimpl_p.h"
61#include "qnetworkreplyfileimpl_p.h"
62
63#include "qnetworkaccessbackend_p.h"
64#include "qnetworkreplyimpl_p.h"
65
66#include "QtCore/qbuffer.h"
67#include "QtCore/qlist.h"
68#include "QtCore/qurl.h"
69#include "QtNetwork/private/qauthenticator_p.h"
70#include "QtNetwork/qsslconfiguration.h"
71#include "QtNetwork/private/http2protocol_p.h"
72
73#if QT_CONFIG(http)
74#include "qhttpmultipart.h"
75#include "qhttpmultipart_p.h"
76#include "qnetworkreplyhttpimpl_p.h"
77#endif
78
79#include "qthread.h"
80
81#include <QHostInfo>
82
83#include <QtCore/private/qfactoryloader_p.h>
84
85#if defined(Q_OS_MACOS)
86#include <CoreServices/CoreServices.h>
87#include <SystemConfiguration/SystemConfiguration.h>
88#include <Security/SecKeychain.h>
89#endif
90#ifdef Q_OS_WASM
91#include "qnetworkreplywasmimpl_p.h"
92#include "qhttpmultipart.h"
93#include "qhttpmultipart_p.h"
94#endif
95
96#include "qnetconmonitor_p.h"
97
98QT_BEGIN_NAMESPACE
99
100Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
101
102#ifdef QT_BUILD_INTERNAL
103Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend)
104#endif
105
106Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
107 (QNetworkAccessBackendFactory_iid,
108 QLatin1String("/networkaccessbackends")))
109#if defined(Q_OS_MACOS)
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#ifdef QT_BUILD_INTERNAL
167 (void) debugpipeBackend();
168#endif
169
170 // leave this one last since it will query the special QAbstractFileEngines
171 (void) fileBackend();
172}
173
174/*!
175 \class QNetworkAccessManager
176 \brief The QNetworkAccessManager class allows the application to
177 send network requests and receive replies.
178 \since 4.4
179
180 \ingroup network
181 \inmodule QtNetwork
182 \reentrant
183
184 The Network Access API is constructed around one QNetworkAccessManager
185 object, which holds the common configuration and settings for the requests
186 it sends. It contains the proxy and cache configuration, as well as the
187 signals related to such issues, and reply signals that can be used to
188 monitor the progress of a network operation. One QNetworkAccessManager
189 instance should be enough for the whole Qt application. Since
190 QNetworkAccessManager is based on QObject, it can only be used from the
191 thread it belongs to.
192
193 Once a QNetworkAccessManager object has been created, the application can
194 use it to send requests over the network. A group of standard functions
195 are supplied that take a request and optional data, and each return a
196 QNetworkReply object. The returned object is used to obtain any data
197 returned in response to the corresponding request.
198
199 A simple download off the network could be accomplished with:
200 \snippet code/src_network_access_qnetworkaccessmanager.cpp 0
201
202 QNetworkAccessManager has an asynchronous API.
203 When the \tt replyFinished slot above is called, the parameter it
204 takes is the QNetworkReply object containing the downloaded data
205 as well as meta-data (headers, etc.).
206
207 \note After the request has finished, it is the responsibility of the user
208 to delete the QNetworkReply object at an appropriate time. Do not directly
209 delete it inside the slot connected to finished(). You can use the
210 deleteLater() function.
211
212 \note QNetworkAccessManager queues the requests it receives. The number
213 of requests executed in parallel is dependent on the protocol.
214 Currently, for the HTTP protocol on desktop platforms, 6 requests are
215 executed in parallel for one host/port combination.
216
217 A more involved example, assuming the manager is already existent,
218 can be:
219 \snippet code/src_network_access_qnetworkaccessmanager.cpp 1
220
221 \sa QNetworkRequest, QNetworkReply, QNetworkProxy
222*/
223
224/*!
225 \enum QNetworkAccessManager::Operation
226
227 Indicates the operation this reply is processing.
228
229 \value HeadOperation retrieve headers operation (created
230 with head())
231
232 \value GetOperation retrieve headers and download contents
233 (created with get())
234
235 \value PutOperation upload contents operation (created
236 with put())
237
238 \value PostOperation send the contents of an HTML form for
239 processing via HTTP POST (created with post())
240
241 \value DeleteOperation delete contents operation (created with
242 deleteResource())
243
244 \value CustomOperation custom operation (created with
245 sendCustomRequest()) \since 4.7
246
247 \omitvalue UnknownOperation
248
249 \sa QNetworkReply::operation()
250*/
251
252/*!
253 \fn void QNetworkAccessManager::networkSessionConnected()
254
255 \since 4.7
256 \obsolete
257
258 \internal
259
260 This signal is emitted when the status of the network session changes into a usable (Connected)
261 state. It is used to signal to QNetworkReplys to start or migrate their network operation once
262 the network session has been opened or finished roaming.
263*/
264
265/*!
266 \fn void QNetworkAccessManager::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)
267
268 This signal is emitted whenever a proxy requests authentication
269 and QNetworkAccessManager cannot find a valid, cached
270 credential. The slot connected to this signal should fill in the
271 credentials for the proxy \a proxy in the \a authenticator object.
272
273 QNetworkAccessManager will cache the credentials internally. The
274 next time the proxy requests authentication, QNetworkAccessManager
275 will automatically send the same credential without emitting the
276 proxyAuthenticationRequired signal again.
277
278 If the proxy rejects the credentials, QNetworkAccessManager will
279 emit the signal again.
280
281 \sa proxy(), setProxy(), authenticationRequired()
282*/
283
284/*!
285 \fn void QNetworkAccessManager::authenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator)
286
287 This signal is emitted whenever a final server requests
288 authentication before it delivers the requested contents. The slot
289 connected to this signal should fill the credentials for the
290 contents (which can be determined by inspecting the \a reply
291 object) in the \a authenticator object.
292
293 QNetworkAccessManager will cache the credentials internally and
294 will send the same values if the server requires authentication
295 again, without emitting the authenticationRequired() signal. If it
296 rejects the credentials, this signal will be emitted again.
297
298 \note To have the request not send credentials you must not call
299 setUser() or setPassword() on the \a authenticator object. This
300 will result in the \l finished() signal being emitted with a
301 \l QNetworkReply with error \l {QNetworkReply::} {AuthenticationRequiredError}.
302
303 \note It is not possible to use a QueuedConnection to connect to
304 this signal, as the connection will fail if the authenticator has
305 not been filled in with new information when the signal returns.
306
307 \sa proxyAuthenticationRequired(), QAuthenticator::setUser(), QAuthenticator::setPassword()
308*/
309
310/*!
311 \fn void QNetworkAccessManager::finished(QNetworkReply *reply)
312
313 This signal is emitted whenever a pending network reply is
314 finished. The \a reply parameter will contain a pointer to the
315 reply that has just finished. This signal is emitted in tandem
316 with the QNetworkReply::finished() signal.
317
318 See QNetworkReply::finished() for information on the status that
319 the object will be in.
320
321 \note Do not delete the \a reply object in the slot connected to this
322 signal. Use deleteLater().
323
324 \sa QNetworkReply::finished(), QNetworkReply::error()
325*/
326
327/*!
328 \fn void QNetworkAccessManager::encrypted(QNetworkReply *reply)
329 \since 5.1
330
331 This signal is emitted when an SSL/TLS session has successfully
332 completed the initial handshake. At this point, no user data
333 has been transmitted. The signal can be used to perform
334 additional checks on the certificate chain, for example to
335 notify users when the certificate for a website has changed. The
336 \a reply parameter specifies which network reply is responsible.
337 If the reply does not match the expected criteria then it should
338 be aborted by calling QNetworkReply::abort() by a slot connected
339 to this signal. The SSL configuration in use can be inspected
340 using the QNetworkReply::sslConfiguration() method.
341
342 Internally, QNetworkAccessManager may open multiple connections
343 to a server, in order to allow it process requests in parallel.
344 These connections may be reused, which means that the encrypted()
345 signal would not be emitted. This means that you are only
346 guaranteed to receive this signal for the first connection to a
347 site in the lifespan of the QNetworkAccessManager.
348
349 \sa QSslSocket::encrypted()
350 \sa QNetworkReply::encrypted()
351*/
352
353/*!
354 \fn void QNetworkAccessManager::sslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
355
356 This signal is emitted if the SSL/TLS session encountered errors
357 during the set up, including certificate verification errors. The
358 \a errors parameter contains the list of errors and \a reply is
359 the QNetworkReply that is encountering these errors.
360
361 To indicate that the errors are not fatal and that the connection
362 should proceed, the QNetworkReply::ignoreSslErrors() function should be called
363 from the slot connected to this signal. If it is not called, the
364 SSL session will be torn down before any data is exchanged
365 (including the URL).
366
367 This signal can be used to display an error message to the user
368 indicating that security may be compromised and display the
369 SSL settings (see sslConfiguration() to obtain it). If the user
370 decides to proceed after analyzing the remote certificate, the
371 slot should call ignoreSslErrors().
372
373 \sa QSslSocket::sslErrors(), QNetworkReply::sslErrors(),
374 QNetworkReply::sslConfiguration(), QNetworkReply::ignoreSslErrors()
375*/
376
377/*!
378 \fn void QNetworkAccessManager::preSharedKeyAuthenticationRequired(QNetworkReply *reply, QSslPreSharedKeyAuthenticator *authenticator)
379 \since 5.5
380
381 This signal is emitted if the SSL/TLS handshake negotiates a PSK
382 ciphersuite, and therefore a PSK authentication is then required.
383 The \a reply object is the QNetworkReply that is negotiating
384 such ciphersuites.
385
386 When using PSK, the client must send to the server a valid identity and a
387 valid pre shared key, in order for the SSL handshake to continue.
388 Applications can provide this information in a slot connected to this
389 signal, by filling in the passed \a authenticator object according to their
390 needs.
391
392 \note Ignoring this signal, or failing to provide the required credentials,
393 will cause the handshake to fail, and therefore the connection to be aborted.
394
395 \note The \a authenticator object is owned by the reply and must not be
396 deleted by the application.
397
398 \sa QSslPreSharedKeyAuthenticator
399*/
400
401/*!
402 Constructs a QNetworkAccessManager object that is the center of
403 the Network Access API and sets \a parent as the parent object.
404*/
405QNetworkAccessManager::QNetworkAccessManager(QObject *parent)
406 : QObject(*new QNetworkAccessManagerPrivate, parent)
407{
408 ensureInitialized();
409 d_func()->ensureBackendPluginsLoaded();
410
411 qRegisterMetaType<QNetworkReply::NetworkError>();
412#ifndef QT_NO_NETWORKPROXY
413 qRegisterMetaType<QNetworkProxy>();
414#endif
415#ifndef QT_NO_SSL
416 qRegisterMetaType<QList<QSslError> >();
417 qRegisterMetaType<QSslConfiguration>();
418 qRegisterMetaType<QSslPreSharedKeyAuthenticator *>();
419#endif
420 qRegisterMetaType<QList<QPair<QByteArray,QByteArray> > >();
421#if QT_CONFIG(http)
422 qRegisterMetaType<QHttpNetworkRequest>();
423#endif
424 qRegisterMetaType<QNetworkReply::NetworkError>();
425 qRegisterMetaType<QSharedPointer<char> >();
426}
427
428/*!
429 Destroys the QNetworkAccessManager object and frees up any
430 resources. Note that QNetworkReply objects that are returned from
431 this class have this object set as their parents, which means that
432 they will be deleted along with it if you don't call
433 QObject::setParent() on them.
434*/
435QNetworkAccessManager::~QNetworkAccessManager()
436{
437#ifndef QT_NO_NETWORKPROXY
438 delete d_func()->proxyFactory;
439#endif
440
441 // Delete the QNetworkReply children first.
442 // Else a QAbstractNetworkCache might get deleted in ~QObject
443 // before a QNetworkReply that accesses the QAbstractNetworkCache
444 // object in its destructor.
445 qDeleteAll(findChildren<QNetworkReply *>());
446 // The other children will be deleted in this ~QObject
447 // FIXME instead of this "hack" make the QNetworkReplyImpl
448 // properly watch the cache deletion, e.g. via a QWeakPointer.
449}
450
451#ifndef QT_NO_NETWORKPROXY
452/*!
453 Returns the QNetworkProxy that the requests sent using this
454 QNetworkAccessManager object will use. The default value for the
455 proxy is QNetworkProxy::DefaultProxy.
456
457 \sa setProxy(), setProxyFactory(), proxyAuthenticationRequired()
458*/
459QNetworkProxy QNetworkAccessManager::proxy() const
460{
461 return d_func()->proxy;
462}
463
464/*!
465 Sets the proxy to be used in future requests to be \a proxy. This
466 does not affect requests that have already been sent. The
467 proxyAuthenticationRequired() signal will be emitted if the proxy
468 requests authentication.
469
470 A proxy set with this function will be used for all requests
471 issued by QNetworkAccessManager. In some cases, it might be
472 necessary to select different proxies depending on the type of
473 request being sent or the destination host. If that's the case,
474 you should consider using setProxyFactory().
475
476 \sa proxy(), proxyAuthenticationRequired()
477*/
478void QNetworkAccessManager::setProxy(const QNetworkProxy &proxy)
479{
480 Q_D(QNetworkAccessManager);
481 delete d->proxyFactory;
482 d->proxy = proxy;
483 d->proxyFactory = nullptr;
484}
485
486/*!
487 \fn QNetworkProxyFactory *QNetworkAccessManager::proxyFactory() const
488 \since 4.5
489
490 Returns the proxy factory that this QNetworkAccessManager object
491 is using to determine the proxies to be used for requests.
492
493 Note that the pointer returned by this function is managed by
494 QNetworkAccessManager and could be deleted at any time.
495
496 \sa setProxyFactory(), proxy()
497*/
498QNetworkProxyFactory *QNetworkAccessManager::proxyFactory() const
499{
500 return d_func()->proxyFactory;
501}
502
503/*!
504 \since 4.5
505
506 Sets the proxy factory for this class to be \a factory. A proxy
507 factory is used to determine a more specific list of proxies to be
508 used for a given request, instead of trying to use the same proxy
509 value for all requests.
510
511 All queries sent by QNetworkAccessManager will have type
512 QNetworkProxyQuery::UrlRequest.
513
514 For example, a proxy factory could apply the following rules:
515 \list
516 \li if the target address is in the local network (for example,
517 if the hostname contains no dots or if it's an IP address in
518 the organization's range), return QNetworkProxy::NoProxy
519 \li if the request is FTP, return an FTP proxy
520 \li if the request is HTTP or HTTPS, then return an HTTP proxy
521 \li otherwise, return a SOCKSv5 proxy server
522 \endlist
523
524 The lifetime of the object \a factory will be managed by
525 QNetworkAccessManager. It will delete the object when necessary.
526
527 \note If a specific proxy is set with setProxy(), the factory will not
528 be used.
529
530 \sa proxyFactory(), setProxy(), QNetworkProxyQuery
531*/
532void QNetworkAccessManager::setProxyFactory(QNetworkProxyFactory *factory)
533{
534 Q_D(QNetworkAccessManager);
535 delete d->proxyFactory;
536 d->proxyFactory = factory;
537 d->proxy = QNetworkProxy();
538}
539#endif
540
541/*!
542 \since 4.5
543
544 Returns the cache that is used to store data obtained from the network.
545
546 \sa setCache()
547*/
548QAbstractNetworkCache *QNetworkAccessManager::cache() const
549{
550 Q_D(const QNetworkAccessManager);
551 return d->networkCache;
552}
553
554/*!
555 \since 4.5
556
557 Sets the manager's network cache to be the \a cache specified. The cache
558 is used for all requests dispatched by the manager.
559
560 Use this function to set the network cache object to a class that implements
561 additional features, like saving the cookies to permanent storage.
562
563 \note QNetworkAccessManager takes ownership of the \a cache object.
564
565 QNetworkAccessManager by default does not have a set cache.
566 Qt provides a simple disk cache, QNetworkDiskCache, which can be used.
567
568 \sa cache(), QNetworkRequest::CacheLoadControl
569*/
570void QNetworkAccessManager::setCache(QAbstractNetworkCache *cache)
571{
572 Q_D(QNetworkAccessManager);
573 if (d->networkCache != cache) {
574 delete d->networkCache;
575 d->networkCache = cache;
576 if (d->networkCache)
577 d->networkCache->setParent(this);
578 }
579}
580
581/*!
582 Returns the QNetworkCookieJar that is used to store cookies
583 obtained from the network as well as cookies that are about to be
584 sent.
585
586 \sa setCookieJar()
587*/
588QNetworkCookieJar *QNetworkAccessManager::cookieJar() const
589{
590 Q_D(const QNetworkAccessManager);
591 if (!d->cookieJar)
592 d->createCookieJar();
593 return d->cookieJar;
594}
595
596/*!
597 Sets the manager's cookie jar to be the \a cookieJar specified.
598 The cookie jar is used by all requests dispatched by the manager.
599
600 Use this function to set the cookie jar object to a class that
601 implements additional features, like saving the cookies to permanent
602 storage.
603
604 \note QNetworkAccessManager takes ownership of the \a cookieJar object.
605
606 If \a cookieJar is in the same thread as this QNetworkAccessManager,
607 it will set the parent of the \a cookieJar
608 so that the cookie jar is deleted when this
609 object is deleted as well. If you want to share cookie jars
610 between different QNetworkAccessManager objects, you may want to
611 set the cookie jar's parent to 0 after calling this function.
612
613 QNetworkAccessManager by default does not implement any cookie
614 policy of its own: it accepts all cookies sent by the server, as
615 long as they are well formed and meet the minimum security
616 requirements (cookie domain matches the request's and cookie path
617 matches the request's). In order to implement your own security
618 policy, override the QNetworkCookieJar::cookiesForUrl() and
619 QNetworkCookieJar::setCookiesFromUrl() virtual functions. Those
620 functions are called by QNetworkAccessManager when it detects a
621 new cookie.
622
623 \sa cookieJar(), QNetworkCookieJar::cookiesForUrl(), QNetworkCookieJar::setCookiesFromUrl()
624*/
625void QNetworkAccessManager::setCookieJar(QNetworkCookieJar *cookieJar)
626{
627 Q_D(QNetworkAccessManager);
628 d->cookieJarCreated = true;
629 if (d->cookieJar != cookieJar) {
630 if (d->cookieJar && d->cookieJar->parent() == this)
631 delete d->cookieJar;
632 d->cookieJar = cookieJar;
633 if (cookieJar && thread() == cookieJar->thread())
634 d->cookieJar->setParent(this);
635 }
636}
637
638/*!
639 \since 5.9
640
641 If \a enabled is \c true, QNetworkAccessManager follows the HTTP Strict Transport
642 Security policy (HSTS, RFC6797). When processing a request, QNetworkAccessManager
643 automatically replaces the "http" scheme with "https" and uses a secure transport
644 for HSTS hosts. If it's set explicitly, port 80 is replaced by port 443.
645
646 When HSTS is enabled, for each HTTP response containing HSTS header and
647 received over a secure transport, QNetworkAccessManager will update its HSTS
648 cache, either remembering a host with a valid policy or removing a host with
649 an expired or disabled HSTS policy.
650
651 \sa isStrictTransportSecurityEnabled()
652*/
653void QNetworkAccessManager::setStrictTransportSecurityEnabled(bool enabled)
654{
655 Q_D(QNetworkAccessManager);
656 d->stsEnabled = enabled;
657}
658
659/*!
660 \since 5.9
661
662 Returns true if HTTP Strict Transport Security (HSTS) was enabled. By default
663 HSTS is disabled.
664
665 \sa setStrictTransportSecurityEnabled()
666*/
667bool QNetworkAccessManager::isStrictTransportSecurityEnabled() const
668{
669 Q_D(const QNetworkAccessManager);
670 return d->stsEnabled;
671}
672
673/*!
674 \since 5.10
675
676 If \a enabled is \c true, the internal HSTS cache will use a persistent store
677 to read and write HSTS policies. \a storeDir defines where this store will be
678 located. The default location is defined by QStandardPaths::CacheLocation.
679 If there is no writable QStandartPaths::CacheLocation and \a storeDir is an
680 empty string, the store will be located in the program's working directory.
681
682 \note If HSTS cache already contains HSTS policies by the time persistent
683 store is enabled, these policies will be preserved in the store. In case both
684 cache and store contain the same known hosts, policies from cache are considered
685 to be more up-to-date (and thus will overwrite the previous values in the store).
686 If this behavior is undesired, enable HSTS store before enabling Strict Tranport
687 Security. By default, the persistent store of HSTS policies is disabled.
688
689 \sa isStrictTransportSecurityStoreEnabled(), setStrictTransportSecurityEnabled(),
690 QStandardPaths::standardLocations()
691*/
692
693void QNetworkAccessManager::enableStrictTransportSecurityStore(bool enabled, const QString &storeDir)
694{
695#if QT_CONFIG(settings)
696 Q_D(QNetworkAccessManager);
697 d->stsStore.reset(enabled ? new QHstsStore(storeDir) : nullptr);
698 d->stsCache.setStore(d->stsStore.data());
699#else
700 Q_UNUSED(enabled);
701 Q_UNUSED(storeDir);
702 qWarning("HSTS permanent store requires the feature 'settings' enabled");
703#endif // QT_CONFIG(settings)
704}
705
706/*!
707 \since 5.10
708
709 Returns true if HSTS cache uses a permanent store to load and store HSTS
710 policies.
711
712 \sa enableStrictTransportSecurityStore()
713*/
714
715bool QNetworkAccessManager::isStrictTransportSecurityStoreEnabled() const
716{
717#if QT_CONFIG(settings)
718 Q_D(const QNetworkAccessManager);
719 return bool(d->stsStore.data());
720#else
721 return false;
722#endif // QT_CONFIG(settings)
723}
724
725/*!
726 \since 5.9
727
728 Adds HTTP Strict Transport Security policies into HSTS cache.
729 \a knownHosts contains the known hosts that have QHstsPolicy
730 information.
731
732 \note An expired policy will remove a known host from the cache, if previously
733 present.
734
735 \note While processing HTTP responses, QNetworkAccessManager can also update
736 the HSTS cache, removing or updating exitsting policies or introducing new
737 \a knownHosts. The current implementation thus is server-driven, client code
738 can provide QNetworkAccessManager with previously known or discovered
739 policies, but this information can be overridden by "Strict-Transport-Security"
740 response headers.
741
742 \sa addStrictTransportSecurityHosts(), enableStrictTransportSecurityStore(), QHstsPolicy
743*/
744
745void QNetworkAccessManager::addStrictTransportSecurityHosts(const QList<QHstsPolicy> &knownHosts)
746{
747 Q_D(QNetworkAccessManager);
748 d->stsCache.updateFromPolicies(knownHosts);
749}
750
751/*!
752 \since 5.9
753
754 Returns the list of HTTP Strict Transport Security policies. This list can
755 differ from what was initially set via addStrictTransportSecurityHosts() if
756 HSTS cache was updated from a "Strict-Transport-Security" response header.
757
758 \sa addStrictTransportSecurityHosts(), QHstsPolicy
759*/
760QList<QHstsPolicy> QNetworkAccessManager::strictTransportSecurityHosts() const
761{
762 Q_D(const QNetworkAccessManager);
763 return d->stsCache.policies();
764}
765
766/*!
767 Posts a request to obtain the network headers for \a request
768 and returns a new QNetworkReply object which will contain such headers.
769
770 The function is named after the HTTP request associated (HEAD).
771*/
772QNetworkReply *QNetworkAccessManager::head(const QNetworkRequest &request)
773{
774 return d_func()->postProcess(createRequest(QNetworkAccessManager::HeadOperation, request));
775}
776
777/*!
778 Posts a request to obtain the contents of the target \a request
779 and returns a new QNetworkReply object opened for reading which emits the
780 \l{QIODevice::readyRead()}{readyRead()} signal whenever new data
781 arrives.
782
783 The contents as well as associated headers will be downloaded.
784
785 \sa post(), put(), deleteResource(), sendCustomRequest()
786*/
787QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
788{
789 return d_func()->postProcess(createRequest(QNetworkAccessManager::GetOperation, request));
790}
791
792/*!
793 Sends an HTTP POST request to the destination specified by \a request
794 and returns a new QNetworkReply object opened for reading that will
795 contain the reply sent by the server. The contents of the \a data
796 device will be uploaded to the server.
797
798 \a data must be open for reading and must remain valid until the
799 finished() signal is emitted for this reply.
800
801 \note Sending a POST request on protocols other than HTTP and
802 HTTPS is undefined and will probably fail.
803
804 \sa get(), put(), deleteResource(), sendCustomRequest()
805*/
806QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QIODevice *data)
807{
808 return d_func()->postProcess(createRequest(QNetworkAccessManager::PostOperation, request, data));
809}
810
811/*!
812 \overload
813
814 Sends the contents of the \a data byte array to the destination
815 specified by \a request.
816*/
817QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, const QByteArray &data)
818{
819 QBuffer *buffer = new QBuffer;
820 buffer->setData(data);
821 buffer->open(QIODevice::ReadOnly);
822
823 QNetworkReply *reply = post(request, buffer);
824 buffer->setParent(reply);
825 return reply;
826}
827
828#if QT_CONFIG(http) || defined(Q_OS_WASM)
829/*!
830 \since 4.8
831
832 \overload
833
834 Sends the contents of the \a multiPart message to the destination
835 specified by \a request.
836
837 This can be used for sending MIME multipart messages over HTTP.
838
839 \sa QHttpMultiPart, QHttpPart, put()
840*/
841QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QHttpMultiPart *multiPart)
842{
843 QNetworkRequest newRequest = d_func()->prepareMultipart(request, multiPart);
844 QIODevice *device = multiPart->d_func()->device;
845 QNetworkReply *reply = post(newRequest, device);
846 return reply;
847}
848
849/*!
850 \since 4.8
851
852 \overload
853
854 Sends the contents of the \a multiPart message to the destination
855 specified by \a request.
856
857 This can be used for sending MIME multipart messages over HTTP.
858
859 \sa QHttpMultiPart, QHttpPart, post()
860*/
861QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, QHttpMultiPart *multiPart)
862{
863 QNetworkRequest newRequest = d_func()->prepareMultipart(request, multiPart);
864 QIODevice *device = multiPart->d_func()->device;
865 QNetworkReply *reply = put(newRequest, device);
866 return reply;
867}
868#endif // QT_CONFIG(http)
869
870/*!
871 Uploads the contents of \a data to the destination \a request and
872 returns a new QNetworkReply object that will be open for reply.
873
874 \a data must be opened for reading when this function is called
875 and must remain valid until the finished() signal is emitted for
876 this reply.
877
878 Whether anything will be available for reading from the returned
879 object is protocol dependent. For HTTP, the server may send a
880 small HTML page indicating the upload was successful (or not).
881 Other protocols will probably have content in their replies.
882
883 \note For HTTP, this request will send a PUT request, which most servers
884 do not allow. Form upload mechanisms, including that of uploading
885 files through HTML forms, use the POST mechanism.
886
887 \sa get(), post(), deleteResource(), sendCustomRequest()
888*/
889QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, QIODevice *data)
890{
891 return d_func()->postProcess(createRequest(QNetworkAccessManager::PutOperation, request, data));
892}
893
894/*!
895 \overload
896
897 Sends the contents of the \a data byte array to the destination
898 specified by \a request.
899*/
900QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, const QByteArray &data)
901{
902 QBuffer *buffer = new QBuffer;
903 buffer->setData(data);
904 buffer->open(QIODevice::ReadOnly);
905
906 QNetworkReply *reply = put(request, buffer);
907 buffer->setParent(reply);
908 return reply;
909}
910
911/*!
912 \since 4.6
913
914 Sends a request to delete the resource identified by the URL of \a request.
915
916 \note This feature is currently available for HTTP only, performing an
917 HTTP DELETE request.
918
919 \sa get(), post(), put(), sendCustomRequest()
920*/
921QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &request)
922{
923 return d_func()->postProcess(createRequest(QNetworkAccessManager::DeleteOperation, request));
924}
925
926#ifndef QT_NO_SSL
927/*!
928 \since 5.2
929
930 Initiates a connection to the host given by \a hostName at port \a port, using
931 \a sslConfiguration. This function is useful to complete the TCP and SSL handshake
932 to a host before the HTTPS request is made, resulting in a lower network latency.
933
934 \note Preconnecting a HTTP/2 connection can be done by calling setAllowedNextProtocols()
935 on \a sslConfiguration with QSslConfiguration::ALPNProtocolHTTP2 contained in
936 the list of allowed protocols. When using HTTP/2, one single connection per host is
937 enough, i.e. calling this method multiple times per host will not result in faster
938 network transactions.
939
940 \note This function has no possibility to report errors.
941
942 \sa connectToHost(), get(), post(), put(), deleteResource()
943*/
944
945void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quint16 port,
946 const QSslConfiguration &sslConfiguration)
947{
948 connectToHostEncrypted(hostName, port, sslConfiguration, QString());
949}
950
951/*!
952 \since 5.13
953 \overload
954
955 Initiates a connection to the host given by \a hostName at port \a port, using
956 \a sslConfiguration with \a peerName set to be the hostName used for certificate
957 validation. This function is useful to complete the TCP and SSL handshake
958 to a host before the HTTPS request is made, resulting in a lower network latency.
959
960 \note Preconnecting a HTTP/2 connection can be done by calling setAllowedNextProtocols()
961 on \a sslConfiguration with QSslConfiguration::ALPNProtocolHTTP2 contained in
962 the list of allowed protocols. When using HTTP/2, one single connection per host is
963 enough, i.e. calling this method multiple times per host will not result in faster
964 network transactions.
965
966 \note This function has no possibility to report errors.
967
968 \sa connectToHost(), get(), post(), put(), deleteResource()
969*/
970
971void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quint16 port,
972 const QSslConfiguration &sslConfiguration,
973 const QString &peerName)
974{
975 QUrl url;
976 url.setHost(hostName);
977 url.setPort(port);
978 url.setScheme(QLatin1String("preconnect-https"));
979 QNetworkRequest request(url);
980 if (sslConfiguration != QSslConfiguration::defaultConfiguration())
981 request.setSslConfiguration(sslConfiguration);
982
983 // There is no way to enable HTTP2 via a request after having established the connection,
984 // so we need to check the ssl configuration whether HTTP2 is allowed here.
985 if (!sslConfiguration.allowedNextProtocols().contains(QSslConfiguration::ALPNProtocolHTTP2))
986 request.setAttribute(QNetworkRequest::Http2AllowedAttribute, false);
987
988 request.setPeerVerifyName(peerName);
989 get(request);
990}
991#endif
992
993/*!
994 \since 5.2
995
996 Initiates a connection to the host given by \a hostName at port \a port.
997 This function is useful to complete the TCP handshake
998 to a host before the HTTP request is made, resulting in a lower network latency.
999
1000 \note This function has no possibility to report errors.
1001
1002 \sa connectToHostEncrypted(), get(), post(), put(), deleteResource()
1003*/
1004void QNetworkAccessManager::connectToHost(const QString &hostName, quint16 port)
1005{
1006 QUrl url;
1007 url.setHost(hostName);
1008 url.setPort(port);
1009 url.setScheme(QLatin1String("preconnect-http"));
1010 QNetworkRequest request(url);
1011 get(request);
1012}
1013
1014/*!
1015 \since 5.9
1016
1017 Sets the manager's redirect policy to be the \a policy specified. This policy
1018 will affect all subsequent requests created by the manager.
1019
1020 Use this function to enable or disable HTTP redirects on the manager's level.
1021
1022 \note When creating a request QNetworkRequest::RedirectAttributePolicy has
1023 the highest priority, next by priority the manager's policy.
1024
1025 The default value is QNetworkRequest::NoLessSafeRedirectPolicy.
1026 Clients relying on manual redirect handling are encouraged to set
1027 this policy explicitly in their code.
1028
1029 \sa redirectPolicy(), QNetworkRequest::RedirectPolicy
1030*/
1031void QNetworkAccessManager::setRedirectPolicy(QNetworkRequest::RedirectPolicy policy)
1032{
1033 Q_D(QNetworkAccessManager);
1034 d->redirectPolicy = policy;
1035}
1036
1037/*!
1038 \since 5.9
1039
1040 Returns the redirect policy that is used when creating new requests.
1041
1042 \sa setRedirectPolicy(), QNetworkRequest::RedirectPolicy
1043*/
1044QNetworkRequest::RedirectPolicy QNetworkAccessManager::redirectPolicy() const
1045{
1046 Q_D(const QNetworkAccessManager);
1047 return d->redirectPolicy;
1048}
1049
1050/*!
1051 \since 4.7
1052
1053 Sends a custom request to the server identified by the URL of \a request.
1054
1055 It is the user's responsibility to send a \a verb to the server that is valid
1056 according to the HTTP specification.
1057
1058 This method provides means to send verbs other than the common ones provided
1059 via get() or post() etc., for instance sending an HTTP OPTIONS command.
1060
1061 If \a data is not empty, the contents of the \a data
1062 device will be uploaded to the server; in that case, data must be open for
1063 reading and must remain valid until the finished() signal is emitted for this reply.
1064
1065 \note This feature is currently available for HTTP(S) only.
1066
1067 \sa get(), post(), put(), deleteResource()
1068*/
1069QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data)
1070{
1071 QNetworkRequest newRequest(request);
1072 newRequest.setAttribute(QNetworkRequest::CustomVerbAttribute, verb);
1073 return d_func()->postProcess(createRequest(QNetworkAccessManager::CustomOperation, newRequest, data));
1074}
1075
1076/*!
1077 \since 5.8
1078
1079 \overload
1080
1081 Sends the contents of the \a data byte array to the destination
1082 specified by \a request.
1083*/
1084QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, const QByteArray &data)
1085{
1086 QBuffer *buffer = new QBuffer;
1087 buffer->setData(data);
1088 buffer->open(QIODevice::ReadOnly);
1089
1090 QNetworkReply *reply = sendCustomRequest(request, verb, buffer);
1091 buffer->setParent(reply);
1092 return reply;
1093}
1094
1095#if QT_CONFIG(http) || defined(Q_OS_WASM)
1096/*!
1097 \since 5.8
1098
1099 \overload
1100
1101 Sends a custom request to the server identified by the URL of \a request.
1102
1103 Sends the contents of the \a multiPart message to the destination
1104 specified by \a request.
1105
1106 This can be used for sending MIME multipart messages for custom verbs.
1107
1108 \sa QHttpMultiPart, QHttpPart, put()
1109*/
1110QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QHttpMultiPart *multiPart)
1111{
1112 QNetworkRequest newRequest = d_func()->prepareMultipart(request, multiPart);
1113 QIODevice *device = multiPart->d_func()->device;
1114 QNetworkReply *reply = sendCustomRequest(newRequest, verb, device);
1115 return reply;
1116}
1117#endif // QT_CONFIG(http)
1118
1119/*!
1120 Returns a new QNetworkReply object to handle the operation \a op
1121 and request \a originalReq. The device \a outgoingData is always 0
1122 for Get and Head requests, but is the value passed to post() and
1123 put() in those operations (the QByteArray variants will pass a QBuffer
1124 object).
1125
1126 The default implementation calls QNetworkCookieJar::cookiesForUrl()
1127 on the cookie jar set with setCookieJar() to obtain the cookies to
1128 be sent to the remote server.
1129
1130 The returned object must be in an open state.
1131*/
1132QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op,
1133 const QNetworkRequest &originalReq,
1134 QIODevice *outgoingData)
1135{
1136 Q_D(QNetworkAccessManager);
1137
1138 QNetworkRequest req(originalReq);
1139 if (redirectPolicy() != QNetworkRequest::NoLessSafeRedirectPolicy
1140 && req.attribute(QNetworkRequest::RedirectPolicyAttribute).isNull()) {
1141 req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, redirectPolicy());
1142 }
1143
1144#if QT_CONFIG(http) || defined (Q_OS_WASM)
1145 if (!req.transferTimeout())
1146 req.setTransferTimeout(transferTimeout());
1147#endif
1148
1149 if (autoDeleteReplies()
1150 && req.attribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute).isNull()) {
1151 req.setAttribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute, true);
1152 }
1153
1154 bool isLocalFile = req.url().isLocalFile();
1155 QString scheme = req.url().scheme();
1156
1157#ifndef Q_OS_WASM
1158
1159 // fast path for GET on file:// URLs
1160 // The QNetworkAccessFileBackend will right now only be used for PUT
1161 if (op == QNetworkAccessManager::GetOperation
1162 || op == QNetworkAccessManager::HeadOperation) {
1163 if (isLocalFile
1164#ifdef Q_OS_ANDROID
1165 || scheme == QLatin1String("assets")
1166#endif
1167 || scheme == QLatin1String("qrc")) {
1168 return new QNetworkReplyFileImpl(this, req, op);
1169 }
1170
1171 if (scheme == QLatin1String("data"))
1172 return new QNetworkReplyDataImpl(this, req, op);
1173
1174 // A request with QNetworkRequest::AlwaysCache does not need any bearer management
1175 QNetworkRequest::CacheLoadControl mode =
1176 static_cast<QNetworkRequest::CacheLoadControl>(
1177 req.attribute(QNetworkRequest::CacheLoadControlAttribute,
1178 QNetworkRequest::PreferNetwork).toInt());
1179 if (mode == QNetworkRequest::AlwaysCache) {
1180 // FIXME Implement a QNetworkReplyCacheImpl instead, see QTBUG-15106
1181 QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
1182 QNetworkReplyImplPrivate *priv = reply->d_func();
1183 priv->manager = this;
1184 priv->backend = new QNetworkAccessCacheBackend();
1185 priv->backend->setManagerPrivate(this->d_func());
1186 priv->backend->setParent(reply);
1187 priv->backend->setReplyPrivate(priv);
1188 priv->setup(op, req, outgoingData);
1189 return reply;
1190 }
1191 }
1192#endif
1193 QNetworkRequest request = req;
1194#ifndef Q_OS_WASM // Content-length header is not allowed to be set by user in wasm
1195 if (!request.header(QNetworkRequest::ContentLengthHeader).isValid() &&
1196 outgoingData && !outgoingData->isSequential()) {
1197 // request has no Content-Length
1198 // but the data that is outgoing is random-access
1199 request.setHeader(QNetworkRequest::ContentLengthHeader, outgoingData->size());
1200 }
1201#endif
1202 if (static_cast<QNetworkRequest::LoadControl>
1203 (request.attribute(QNetworkRequest::CookieLoadControlAttribute,
1204 QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Automatic) {
1205 if (d->cookieJar) {
1206 QList<QNetworkCookie> cookies = d->cookieJar->cookiesForUrl(request.url());
1207 if (!cookies.isEmpty())
1208 request.setHeader(QNetworkRequest::CookieHeader, QVariant::fromValue(cookies));
1209 }
1210 }
1211#ifdef Q_OS_WASM
1212 // Support http, https, and relative urls
1213 if (scheme == QLatin1String("http") || scheme == QLatin1String("https") || scheme.isEmpty()) {
1214 QNetworkReplyWasmImpl *reply = new QNetworkReplyWasmImpl(this);
1215 QNetworkReplyWasmImplPrivate *priv = reply->d_func();
1216 priv->manager = this;
1217 priv->setup(op, request, outgoingData);
1218 return reply;
1219 }
1220#endif
1221
1222#if QT_CONFIG(http)
1223 // Since Qt 5 we use the new QNetworkReplyHttpImpl
1224 if (scheme == QLatin1String("http") || scheme == QLatin1String("preconnect-http")
1225#ifndef QT_NO_SSL
1226 || scheme == QLatin1String("https") || scheme == QLatin1String("preconnect-https")
1227#endif
1228 ) {
1229#ifndef QT_NO_SSL
1230 if (isStrictTransportSecurityEnabled() && d->stsCache.isKnownHost(request.url())) {
1231 QUrl stsUrl(request.url());
1232 // RFC6797, 8.3:
1233 // The UA MUST replace the URI scheme with "https" [RFC2818],
1234 // and if the URI contains an explicit port component of "80",
1235 // then the UA MUST convert the port component to be "443", or
1236 // if the URI contains an explicit port component that is not
1237 // equal to "80", the port component value MUST be preserved;
1238 // otherwise,
1239 // if the URI does not contain an explicit port component, the UA
1240 // MUST NOT add one.
1241 if (stsUrl.port() == 80)
1242 stsUrl.setPort(443);
1243 stsUrl.setScheme(QLatin1String("https"));
1244 request.setUrl(stsUrl);
1245 }
1246#endif
1247 QNetworkReplyHttpImpl *reply = new QNetworkReplyHttpImpl(this, request, op, outgoingData);
1248 return reply;
1249 }
1250#endif // QT_CONFIG(http)
1251
1252 // first step: create the reply
1253 QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
1254 QNetworkReplyImplPrivate *priv = reply->d_func();
1255 priv->manager = this;
1256
1257 // second step: fetch cached credentials
1258 // This is not done for the time being, we should use signal emissions to request
1259 // the credentials from cache.
1260
1261 // third step: find a backend
1262 priv->backend = d->findBackend(op, request);
1263
1264 if (priv->backend) {
1265 priv->backend->setParent(reply);
1266 priv->backend->setReplyPrivate(priv);
1267 }
1268
1269#ifndef QT_NO_SSL
1270 reply->setSslConfiguration(request.sslConfiguration());
1271#endif
1272
1273 // fourth step: setup the reply
1274 priv->setup(op, request, outgoingData);
1275
1276 return reply;
1277}
1278
1279/*!
1280 \since 5.2
1281
1282 Lists all the URL schemes supported by the access manager.
1283
1284 Reimplement this method to provide your own supported schemes
1285 in a QNetworkAccessManager subclass. It is for instance necessary
1286 when your subclass provides support for new protocols.
1287*/
1288QStringList QNetworkAccessManager::supportedSchemes() const
1289{
1290 QStringList schemes;
1291 QNetworkAccessManager *self = const_cast<QNetworkAccessManager *>(this); // We know we call a const slot
1292 QMetaObject::invokeMethod(self, "supportedSchemesImplementation", Qt::DirectConnection,
1293 Q_RETURN_ARG(QStringList, schemes));
1294 schemes.removeDuplicates();
1295 return schemes;
1296}
1297
1298/*!
1299 \since 5.2
1300 \obsolete
1301
1302 Lists all the URL schemes supported by the access manager.
1303
1304 You should not call this function directly; use
1305 QNetworkAccessManager::supportedSchemes() instead.
1306
1307 Because of binary compatibility constraints, the supportedSchemes()
1308 method (introduced in Qt 5.2) was not virtual in Qt 5, but now it
1309 is. Override the supportedSchemes method rather than this one.
1310
1311 \sa supportedSchemes()
1312*/
1313QStringList QNetworkAccessManager::supportedSchemesImplementation() const
1314{
1315 Q_D(const QNetworkAccessManager);
1316
1317 QStringList schemes = d->backendSupportedSchemes();
1318 // Those ones don't exist in backends
1319#if QT_CONFIG(http)
1320 schemes << QStringLiteral("http");
1321#ifndef QT_NO_SSL
1322 if (QSslSocket::supportsSsl())
1323 schemes << QStringLiteral("https");
1324#endif
1325#endif
1326 schemes << QStringLiteral("data");
1327 return schemes;
1328}
1329
1330/*!
1331 \since 5.0
1332
1333 Flushes the internal cache of authentication data and network connections.
1334
1335 This function is useful for doing auto tests.
1336
1337 \sa clearConnectionCache()
1338*/
1339void QNetworkAccessManager::clearAccessCache()
1340{
1341 QNetworkAccessManagerPrivate::clearAuthenticationCache(this);
1342 QNetworkAccessManagerPrivate::clearConnectionCache(this);
1343}
1344
1345/*!
1346 \since 5.9
1347
1348 Flushes the internal cache of network connections.
1349 In contrast to clearAccessCache() the authentication data
1350 is preserved.
1351
1352 \sa clearAccessCache()
1353*/
1354void QNetworkAccessManager::clearConnectionCache()
1355{
1356 QNetworkAccessManagerPrivate::clearConnectionCache(this);
1357}
1358
1359
1360/*!
1361 \since 5.14
1362
1363 Returns the true if QNetworkAccessManager is currently configured
1364 to automatically delete QNetworkReplies, false otherwise.
1365
1366 \sa setAutoDeleteReplies,
1367 QNetworkRequest::AutoDeleteReplyOnFinishAttribute
1368*/
1369bool QNetworkAccessManager::autoDeleteReplies() const
1370{
1371 return d_func()->autoDeleteReplies;
1372}
1373
1374/*!
1375 \since 5.14
1376
1377 Enables or disables automatic deletion of \l {QNetworkReply} {QNetworkReplies}.
1378
1379 Setting \a shouldAutoDelete to true is the same as setting the
1380 QNetworkRequest::AutoDeleteReplyOnFinishAttribute attribute to
1381 true on all \e{future} \l {QNetworkRequest} {QNetworkRequests}
1382 passed to this instance of QNetworkAccessManager unless the
1383 attribute was already explicitly set on the QNetworkRequest.
1384
1385 \sa autoDeleteReplies,
1386 QNetworkRequest::AutoDeleteReplyOnFinishAttribute
1387*/
1388void QNetworkAccessManager::setAutoDeleteReplies(bool shouldAutoDelete)
1389{
1390 d_func()->autoDeleteReplies = shouldAutoDelete;
1391}
1392
1393/*!
1394 \since 5.15
1395
1396 Returns the timeout used for transfers, in milliseconds.
1397
1398 This timeout is zero if setTransferTimeout() hasn't been
1399 called, which means that the timeout is not used.
1400*/
1401int QNetworkAccessManager::transferTimeout() const
1402{
1403 return d_func()->transferTimeout;
1404}
1405
1406/*!
1407 \since 5.15
1408
1409 Sets \a timeout as the transfer timeout in milliseconds.
1410
1411 Transfers are aborted if no bytes are transferred before
1412 the timeout expires. Zero means no timer is set. If no
1413 argument is provided, the timeout is
1414 QNetworkRequest::DefaultTransferTimeoutConstant. If this function
1415 is not called, the timeout is disabled and has the
1416 value zero. The request-specific non-zero timeouts set for
1417 the requests that are executed override this value. This means
1418 that if QNetworkAccessManager has an enabled timeout, it needs
1419 to be disabled to execute a request without a timeout.
1420
1421 \sa transferTimeout()
1422*/
1423void QNetworkAccessManager::setTransferTimeout(int timeout)
1424{
1425 d_func()->transferTimeout = timeout;
1426}
1427
1428void QNetworkAccessManagerPrivate::_q_replyFinished(QNetworkReply *reply)
1429{
1430 Q_Q(QNetworkAccessManager);
1431
1432 emit q->finished(reply);
1433 if (reply->request().attribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute, false).toBool())
1434 QMetaObject::invokeMethod(reply, [reply] { reply->deleteLater(); }, Qt::QueuedConnection);
1435}
1436
1437void QNetworkAccessManagerPrivate::_q_replyEncrypted(QNetworkReply *reply)
1438{
1439#ifndef QT_NO_SSL
1440 Q_Q(QNetworkAccessManager);
1441 emit q->encrypted(reply);
1442#else
1443 Q_UNUSED(reply);
1444#endif
1445}
1446
1447void QNetworkAccessManagerPrivate::_q_replySslErrors(const QList<QSslError> &errors)
1448{
1449#ifndef QT_NO_SSL
1450 Q_Q(QNetworkAccessManager);
1451 QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
1452 if (reply)
1453 emit q->sslErrors(reply, errors);
1454#else
1455 Q_UNUSED(errors);
1456#endif
1457}
1458
1459#ifndef QT_NO_SSL
1460void QNetworkAccessManagerPrivate::_q_replyPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator)
1461{
1462 Q_Q(QNetworkAccessManager);
1463 QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
1464 if (reply)
1465 emit q->preSharedKeyAuthenticationRequired(reply, authenticator);
1466}
1467#endif
1468
1469QNetworkReply *QNetworkAccessManagerPrivate::postProcess(QNetworkReply *reply)
1470{
1471 Q_Q(QNetworkAccessManager);
1472 QNetworkReplyPrivate::setManager(reply, q);
1473 q->connect(reply, &QNetworkReply::finished, reply,
1474 [this, reply]() { _q_replyFinished(reply); });
1475#ifndef QT_NO_SSL
1476 /* In case we're compiled without SSL support, we don't have this signal and we need to
1477 * avoid getting a connection error. */
1478 q->connect(reply, &QNetworkReply::encrypted, reply,
1479 [this, reply]() { _q_replyEncrypted(reply); });
1480 q->connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SLOT(_q_replySslErrors(QList<QSslError>)));
1481 q->connect(reply, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), SLOT(_q_replyPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)));
1482#endif
1483
1484 return reply;
1485}
1486
1487void QNetworkAccessManagerPrivate::createCookieJar() const
1488{
1489 if (!cookieJarCreated) {
1490 // keep the ugly hack in here
1491 QNetworkAccessManagerPrivate *that = const_cast<QNetworkAccessManagerPrivate *>(this);
1492 that->cookieJar = new QNetworkCookieJar(that->q_func());
1493 that->cookieJarCreated = true;
1494 }
1495}
1496
1497void QNetworkAccessManagerPrivate::authenticationRequired(QAuthenticator *authenticator,
1498 QNetworkReply *reply,
1499 bool synchronous,
1500 QUrl &url,
1501 QUrl *urlForLastAuthentication,
1502 bool allowAuthenticationReuse)
1503{
1504 Q_Q(QNetworkAccessManager);
1505
1506 // don't try the cache for the same URL twice in a row
1507 // being called twice for the same URL means the authentication failed
1508 // also called when last URL is empty, e.g. on first call
1509 if (allowAuthenticationReuse && (urlForLastAuthentication->isEmpty()
1510 || url != *urlForLastAuthentication)) {
1511 // if credentials are included in the url, then use them, unless they were already used
1512 if (!url.userName().isEmpty() && !url.password().isEmpty()
1513 && (url.userName() != authenticator->user()
1514 || url.password() != authenticator->password())) {
1515 authenticator->setUser(url.userName(QUrl::FullyDecoded));
1516 authenticator->setPassword(url.password(QUrl::FullyDecoded));
1517 *urlForLastAuthentication = url;
1518 authenticationManager->cacheCredentials(url, authenticator);
1519 return;
1520 }
1521
1522 QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedCredentials(url, authenticator);
1523 if (!cred.isNull()
1524 && (cred.user != authenticator->user() || cred.password != authenticator->password())) {
1525 authenticator->setUser(cred.user);
1526 authenticator->setPassword(cred.password);
1527 *urlForLastAuthentication = url;
1528 return;
1529 }
1530 }
1531
1532 // if we emit a signal here in synchronous mode, the user might spin
1533 // an event loop, which might recurse and lead to problems
1534 if (synchronous)
1535 return;
1536
1537 *urlForLastAuthentication = url;
1538 emit q->authenticationRequired(reply, authenticator);
1539 if (allowAuthenticationReuse)
1540 authenticationManager->cacheCredentials(url, authenticator);
1541}
1542
1543#ifndef QT_NO_NETWORKPROXY
1544void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(const QUrl &url,
1545 const QNetworkProxy &proxy,
1546 bool synchronous,
1547 QAuthenticator *authenticator,
1548 QNetworkProxy *lastProxyAuthentication)
1549{
1550 Q_Q(QNetworkAccessManager);
1551 QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(*authenticator);
1552 if (proxy != *lastProxyAuthentication && (!priv || !priv->hasFailed)) {
1553 QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedProxyCredentials(proxy);
1554 if (!cred.isNull()) {
1555 authenticator->setUser(cred.user);
1556 authenticator->setPassword(cred.password);
1557 return;
1558 }
1559 }
1560
1561#if defined(Q_OS_MACOS)
1562 //now we try to get the username and password from keychain
1563 //if not successful signal will be emitted
1564 QString username;
1565 QString password;
1566 if (getProxyAuth(proxy.hostName(), url.scheme(), username, password)) {
1567 // only cache the system credentials if they are correct (or if they have changed)
1568 // to not run into an endless loop in case they are wrong
1569 QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedProxyCredentials(proxy);
1570 if (!priv->hasFailed || cred.user != username || cred.password != password) {
1571 authenticator->setUser(username);
1572 authenticator->setPassword(password);
1573 authenticationManager->cacheProxyCredentials(proxy, authenticator);
1574 return;
1575 }
1576 }
1577#else
1578 Q_UNUSED(url);
1579#endif
1580
1581 // if we emit a signal here in synchronous mode, the user might spin
1582 // an event loop, which might recurse and lead to problems
1583 if (synchronous)
1584 return;
1585
1586 *lastProxyAuthentication = proxy;
1587 emit q->proxyAuthenticationRequired(proxy, authenticator);
1588 authenticationManager->cacheProxyCredentials(proxy, authenticator);
1589}
1590
1591QList<QNetworkProxy> QNetworkAccessManagerPrivate::queryProxy(const QNetworkProxyQuery &query)
1592{
1593 QList<QNetworkProxy> proxies;
1594 if (proxyFactory) {
1595 proxies = proxyFactory->queryProxy(query);
1596 if (proxies.isEmpty()) {
1597 qWarning("QNetworkAccessManager: factory %p has returned an empty result set",
1598 proxyFactory);
1599 proxies << QNetworkProxy::NoProxy;
1600 }
1601 } else if (proxy.type() == QNetworkProxy::DefaultProxy) {
1602 // no proxy set, query the application
1603 return QNetworkProxyFactory::proxyForQuery(query);
1604 } else {
1605 proxies << proxy;
1606 }
1607
1608 return proxies;
1609}
1610#endif
1611
1612void QNetworkAccessManagerPrivate::clearAuthenticationCache(QNetworkAccessManager *manager)
1613{
1614 manager->d_func()->authenticationManager->clearCache();
1615}
1616
1617void QNetworkAccessManagerPrivate::clearConnectionCache(QNetworkAccessManager *manager)
1618{
1619 manager->d_func()->objectCache.clear();
1620 manager->d_func()->destroyThread();
1621}
1622
1623QNetworkAccessManagerPrivate::~QNetworkAccessManagerPrivate()
1624{
1625 destroyThread();
1626}
1627
1628QThread * QNetworkAccessManagerPrivate::createThread()
1629{
1630 if (!thread) {
1631 thread = new QThread;
1632 thread->setObjectName(QStringLiteral("QNetworkAccessManager thread"));
1633 thread->start();
1634 }
1635 Q_ASSERT(thread);
1636 return thread;
1637}
1638
1639void QNetworkAccessManagerPrivate::destroyThread()
1640{
1641 if (thread) {
1642 thread->quit();
1643 thread->wait(QDeadlineTimer(5000));
1644 if (thread->isFinished())
1645 delete thread;
1646 else
1647 QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
1648 thread = nullptr;
1649 }
1650}
1651
1652
1653#if QT_CONFIG(http) || defined(Q_OS_WASM)
1654
1655QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart)
1656{
1657 // copy the request, we probably need to add some headers
1658 QNetworkRequest newRequest(request);
1659
1660 // add Content-Type header if not there already
1661 if (!request.header(QNetworkRequest::ContentTypeHeader).isValid()) {
1662 QByteArray contentType;
1663 contentType.reserve(34 + multiPart->d_func()->boundary.count());
1664 contentType += "multipart/";
1665 switch (multiPart->d_func()->contentType) {
1666 case QHttpMultiPart::RelatedType:
1667 contentType += "related";
1668 break;
1669 case QHttpMultiPart::FormDataType:
1670 contentType += "form-data";
1671 break;
1672 case QHttpMultiPart::AlternativeType:
1673 contentType += "alternative";
1674 break;
1675 default:
1676 contentType += "mixed";
1677 break;
1678 }
1679 // putting the boundary into quotes, recommended in RFC 2046 section 5.1.1
1680 contentType += "; boundary=\"" + multiPart->d_func()->boundary + '"';
1681 newRequest.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(contentType));
1682 }
1683
1684 // add MIME-Version header if not there already (we must include the header
1685 // if the message conforms to RFC 2045, see section 4 of that RFC)
1686 QByteArray mimeHeader("MIME-Version");
1687 if (!request.hasRawHeader(mimeHeader))
1688 newRequest.setRawHeader(mimeHeader, QByteArray("1.0"));
1689
1690 QIODevice *device = multiPart->d_func()->device;
1691 if (!device->isReadable()) {
1692 if (!device->isOpen()) {
1693 if (!device->open(QIODevice::ReadOnly))
1694 qWarning("could not open device for reading");
1695 } else {
1696 qWarning("device is not readable");
1697 }
1698 }
1699
1700 return newRequest;
1701}
1702#endif // QT_CONFIG(http)
1703
1704/*!
1705 \internal
1706 Go through the instances so the factories will be created and
1707 register themselves to QNetworkAccessBackendFactoryData
1708*/
1709void QNetworkAccessManagerPrivate::ensureBackendPluginsLoaded()
1710{
1711 static QBasicMutex mutex;
1712 std::unique_lock locker(mutex);
1713 if (!loader())
1714 return;
1715#if QT_CONFIG(library)
1716 loader->update();
1717#endif
1718 int index = 0;
1719 while (loader->instance(index))
1720 ++index;
1721}
1722
1723QT_END_NAMESPACE
1724
1725#include "moc_qnetworkaccessmanager.cpp"
1726