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

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