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