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