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 \fn QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, std::nullptr_t)
1163 \since 6.13
1164 \overload
1165
1166 Sends the custom request without body to the server specified by the URL of
1167 \a request and returns a new QNetworkReply object.
1168*/
1169
1170/*!
1171 \since 5.8
1172
1173 \overload
1174
1175 Sends the contents of the \a data byte array to the destination
1176 specified by \a request.
1177*/
1178QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, const QByteArray &data)
1179{
1180 QBuffer *buffer = new QBuffer;
1181 buffer->setData(data);
1182 buffer->open(QIODevice::ReadOnly);
1183
1184 QNetworkReply *reply = sendCustomRequest(request, verb, buffer);
1185 buffer->setParent(reply);
1186 return reply;
1187}
1188
1189#if QT_CONFIG(http) || defined(Q_OS_WASM)
1190/*!
1191 \since 5.8
1192
1193 \overload
1194
1195 Sends a custom request to the server identified by the URL of \a request.
1196
1197 Sends the contents of the \a multiPart message to the destination
1198 specified by \a request.
1199
1200 This can be used for sending MIME multipart messages for custom verbs.
1201
1202 \sa QHttpMultiPart, QHttpPart, put()
1203*/
1204QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QHttpMultiPart *multiPart)
1205{
1206 QNetworkRequest newRequest = d_func()->prepareMultipart(request, multiPart);
1207 QIODevice *device = multiPart->d_func()->device;
1208 QNetworkReply *reply = sendCustomRequest(newRequest, verb, device);
1209 return reply;
1210}
1211#endif // QT_CONFIG(http)
1212
1213/*!
1214 Returns a new QNetworkReply object to handle the operation \a op
1215 and request \a originalReq. The device \a outgoingData is always 0
1216 for Get and Head requests, but is the value passed to post() and
1217 put() in those operations (the QByteArray variants will pass a QBuffer
1218 object).
1219
1220 The default implementation calls QNetworkCookieJar::cookiesForUrl()
1221 on the cookie jar set with setCookieJar() to obtain the cookies to
1222 be sent to the remote server.
1223
1224 The returned object must be in an open state.
1225*/
1226QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op,
1227 const QNetworkRequest &originalReq,
1228 QIODevice *outgoingData)
1229{
1230 Q_D(QNetworkAccessManager);
1231
1232 QNetworkRequest req(originalReq);
1233 if (redirectPolicy() != QNetworkRequest::NoLessSafeRedirectPolicy
1234 && req.attribute(QNetworkRequest::RedirectPolicyAttribute).isNull()) {
1235 req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, redirectPolicy());
1236 }
1237
1238#if QT_CONFIG(http) || defined (Q_OS_WASM)
1239 if (req.transferTimeoutAsDuration() == 0ms)
1240 req.setTransferTimeout(transferTimeoutAsDuration());
1241#endif
1242
1243 if (autoDeleteReplies()
1244 && req.attribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute).isNull()) {
1245 req.setAttribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute, true);
1246 }
1247
1248 bool isLocalFile = req.url().isLocalFile();
1249 QString scheme = req.url().scheme();
1250
1251 // Remap local+http to unix+http to make further processing easier
1252 if (scheme == "local+http"_L1) {
1253 scheme = u"unix+http"_s;
1254 QUrl url = req.url();
1255 url.setScheme(scheme);
1256 req.setUrl(url);
1257 }
1258
1259 // fast path for GET on file:// URLs
1260 // The QNetworkAccessFileBackend will right now only be used for PUT
1261 if (op == QNetworkAccessManager::GetOperation
1262 || op == QNetworkAccessManager::HeadOperation) {
1263 if (isLocalFile
1264#ifdef Q_OS_ANDROID
1265 || scheme == "assets"_L1
1266#endif
1267 || scheme == "qrc"_L1) {
1268 return new QNetworkReplyFileImpl(this, req, op);
1269 }
1270
1271 if (scheme == "data"_L1)
1272 return new QNetworkReplyDataImpl(this, req, op);
1273
1274 // A request with QNetworkRequest::AlwaysCache does not need any bearer management
1275 QNetworkRequest::CacheLoadControl mode =
1276 static_cast<QNetworkRequest::CacheLoadControl>(
1277 req.attribute(QNetworkRequest::CacheLoadControlAttribute,
1278 QNetworkRequest::PreferNetwork).toInt());
1279 if (mode == QNetworkRequest::AlwaysCache) {
1280 // FIXME Implement a QNetworkReplyCacheImpl instead, see QTBUG-15106
1281 QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
1282 QNetworkReplyImplPrivate *priv = reply->d_func();
1283 priv->manager = this;
1284 priv->backend = new QNetworkAccessCacheBackend();
1285 priv->backend->setManagerPrivate(this->d_func());
1286 priv->backend->setParent(reply);
1287 priv->backend->setReplyPrivate(priv);
1288 priv->setup(op, req, outgoingData);
1289 return reply;
1290 }
1291 }
1292 QNetworkRequest request = req;
1293 auto h = request.headers();
1294#ifndef Q_OS_WASM // Content-length header is not allowed to be set by user in wasm
1295 if (!h.contains(QHttpHeaders::WellKnownHeader::ContentLength) &&
1296 outgoingData && !outgoingData->isSequential() && outgoingData->size()) {
1297 // request has no Content-Length
1298 // but the data that is outgoing is random-access
1299 h.append(QHttpHeaders::WellKnownHeader::ContentLength,
1300 QByteArray::number(outgoingData->size()));
1301 }
1302#endif
1303 if (static_cast<QNetworkRequest::LoadControl>
1304 (request.attribute(QNetworkRequest::CookieLoadControlAttribute,
1305 QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Automatic) {
1306 if (d->cookieJar) {
1307 QList<QNetworkCookie> cookies = d->cookieJar->cookiesForUrl(request.url());
1308 if (!cookies.isEmpty())
1309 h.replaceOrAppend(QHttpHeaders::WellKnownHeader::Cookie,
1310 QNetworkHeadersPrivate::fromCookieList(cookies));
1311 }
1312 }
1313 request.setHeaders(std::move(h));
1314#ifdef Q_OS_WASM
1315 Q_UNUSED(isLocalFile);
1316 // Support http, https, and relative urls
1317 if (scheme == "http"_L1 || scheme == "https"_L1 || scheme.isEmpty()) {
1318 QNetworkReplyWasmImpl *reply = new QNetworkReplyWasmImpl(this);
1319 QNetworkReplyWasmImplPrivate *priv = reply->d_func();
1320 priv->manager = this;
1321 priv->setup(op, request, outgoingData);
1322 return reply;
1323 }
1324#endif
1325
1326#if QT_CONFIG(http)
1327 constexpr char16_t httpSchemes[][17] = {
1328 u"http",
1329 u"preconnect-http",
1330#ifndef QT_NO_SSL
1331 u"https",
1332 u"preconnect-https",
1333#endif
1334 u"unix+http",
1335 };
1336 // Since Qt 5 we use the new QNetworkReplyHttpImpl
1337 if (std::find(std::begin(httpSchemes), std::end(httpSchemes), scheme) != std::end(httpSchemes)) {
1338
1339#ifndef QT_NO_SSL
1340 const bool isLocalSocket = scheme.startsWith("unix"_L1);
1341 if (!isLocalSocket && isStrictTransportSecurityEnabled()
1342 && d->stsCache.isKnownHost(request.url())) {
1343 QUrl stsUrl(request.url());
1344 // RFC6797, 8.3:
1345 // The UA MUST replace the URI scheme with "https" [RFC2818],
1346 // and if the URI contains an explicit port component of "80",
1347 // then the UA MUST convert the port component to be "443", or
1348 // if the URI contains an explicit port component that is not
1349 // equal to "80", the port component value MUST be preserved;
1350 // otherwise,
1351 // if the URI does not contain an explicit port component, the UA
1352 // MUST NOT add one.
1353 if (stsUrl.port() == 80)
1354 stsUrl.setPort(443);
1355 stsUrl.setScheme("https"_L1);
1356 request.setUrl(stsUrl);
1357 }
1358#endif
1359 QNetworkReplyHttpImpl *reply = new QNetworkReplyHttpImpl(this, request, op, outgoingData);
1360 return reply;
1361 }
1362#endif // QT_CONFIG(http)
1363
1364 // first step: create the reply
1365 QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
1366 QNetworkReplyImplPrivate *priv = reply->d_func();
1367 priv->manager = this;
1368
1369 // second step: fetch cached credentials
1370 // This is not done for the time being, we should use signal emissions to request
1371 // the credentials from cache.
1372
1373 // third step: find a backend
1374 priv->backend = d->findBackend(op, request);
1375
1376 if (priv->backend) {
1377 priv->backend->setParent(reply);
1378 priv->backend->setReplyPrivate(priv);
1379 }
1380
1381#ifndef QT_NO_SSL
1382 reply->setSslConfiguration(request.sslConfiguration());
1383#endif
1384
1385 // fourth step: setup the reply
1386 priv->setup(op, request, outgoingData);
1387
1388 return reply;
1389}
1390
1391/*!
1392 \since 5.2
1393
1394 Lists all the URL schemes supported by the access manager.
1395
1396 Reimplement this method to provide your own supported schemes
1397 in a QNetworkAccessManager subclass. It is for instance necessary
1398 when your subclass provides support for new protocols.
1399*/
1400QStringList QNetworkAccessManager::supportedSchemes() const
1401{
1402 QStringList schemes;
1403 QNetworkAccessManager *self = const_cast<QNetworkAccessManager *>(this); // We know we call a const slot
1404 QMetaObject::invokeMethod(self, "supportedSchemesImplementation", Qt::DirectConnection,
1405 Q_RETURN_ARG(QStringList, schemes));
1406 schemes.removeDuplicates();
1407 return schemes;
1408}
1409
1410/*!
1411 \since 5.2
1412 \deprecated
1413
1414 Lists all the URL schemes supported by the access manager.
1415
1416 You should not call this function directly; use
1417 QNetworkAccessManager::supportedSchemes() instead.
1418
1419 Because of binary compatibility constraints, the supportedSchemes()
1420 method (introduced in Qt 5.2) was not virtual in Qt 5, but now it
1421 is. Override the supportedSchemes method rather than this one.
1422
1423 \sa supportedSchemes()
1424*/
1425QStringList QNetworkAccessManager::supportedSchemesImplementation() const
1426{
1427 Q_D(const QNetworkAccessManager);
1428
1429 QStringList schemes = d->backendSupportedSchemes();
1430 // Those ones don't exist in backends
1431#if QT_CONFIG(http)
1432 schemes << QStringLiteral("http");
1433 schemes << QStringLiteral("unix+http");
1434 schemes << QStringLiteral("local+http");
1435#ifndef QT_NO_SSL
1436 if (QSslSocket::supportsSsl())
1437 schemes << QStringLiteral("https");
1438#endif
1439#endif
1440 schemes << QStringLiteral("data");
1441 return schemes;
1442}
1443
1444/*!
1445 \since 5.0
1446
1447 Flushes the internal cache of authentication data and network connections.
1448
1449 This function is useful for doing auto tests.
1450
1451 \sa clearConnectionCache()
1452*/
1453void QNetworkAccessManager::clearAccessCache()
1454{
1455 QNetworkAccessManagerPrivate::clearAuthenticationCache(this);
1456 QNetworkAccessManagerPrivate::clearConnectionCache(this);
1457}
1458
1459/*!
1460 \since 5.9
1461
1462 Flushes the internal cache of network connections.
1463 In contrast to clearAccessCache() the authentication data
1464 is preserved.
1465
1466 \sa clearAccessCache()
1467*/
1468void QNetworkAccessManager::clearConnectionCache()
1469{
1470 QNetworkAccessManagerPrivate::clearConnectionCache(this);
1471}
1472
1473
1474/*!
1475 \since 5.14
1476
1477 Returns the true if QNetworkAccessManager is currently configured
1478 to automatically delete QNetworkReplies, false otherwise.
1479
1480 \sa setAutoDeleteReplies,
1481 QNetworkRequest::AutoDeleteReplyOnFinishAttribute
1482*/
1483bool QNetworkAccessManager::autoDeleteReplies() const
1484{
1485 return d_func()->autoDeleteReplies;
1486}
1487
1488/*!
1489 \since 5.14
1490
1491 Enables or disables automatic deletion of \l {QNetworkReply} {QNetworkReplies}.
1492
1493 Setting \a shouldAutoDelete to true is the same as setting the
1494 QNetworkRequest::AutoDeleteReplyOnFinishAttribute attribute to
1495 true on all \e{future} \l {QNetworkRequest} {QNetworkRequests}
1496 passed to this instance of QNetworkAccessManager unless the
1497 attribute was already explicitly set on the QNetworkRequest.
1498
1499 \sa autoDeleteReplies,
1500 QNetworkRequest::AutoDeleteReplyOnFinishAttribute
1501*/
1502void QNetworkAccessManager::setAutoDeleteReplies(bool shouldAutoDelete)
1503{
1504 d_func()->autoDeleteReplies = shouldAutoDelete;
1505}
1506
1507/*!
1508 \fn int QNetworkAccessManager::transferTimeout() const
1509 \since 5.15
1510
1511 Returns the timeout used for transfers, in milliseconds.
1512
1513 \sa setTransferTimeout()
1514*/
1515
1516/*!
1517 \fn void QNetworkAccessManager::setTransferTimeout(int timeout)
1518 \since 5.15
1519
1520 Sets \a timeout as the transfer timeout in milliseconds.
1521
1522 \sa setTransferTimeout(std::chrono::milliseconds),
1523 transferTimeout(), transferTimeoutAsDuration()
1524*/
1525
1526/*!
1527 \since 6.7
1528
1529 Returns the timeout duration after which the transfer is aborted if no
1530 data is exchanged.
1531
1532 The default duration is zero, which means that the timeout is not used.
1533
1534 \sa setTransferTimeout(std::chrono::milliseconds)
1535 */
1536std::chrono::milliseconds QNetworkAccessManager::transferTimeoutAsDuration() const
1537{
1538 return d_func()->transferTimeout;
1539}
1540
1541/*!
1542 \since 6.7
1543
1544 Sets the timeout \a duration to abort the transfer if no data is exchanged.
1545
1546 Transfers are aborted if no bytes are transferred before
1547 the timeout expires. Zero means no timer is set. If no
1548 argument is provided, the timeout is
1549 QNetworkRequest::DefaultTransferTimeout. If this function
1550 is not called, the timeout is disabled and has the
1551 value zero. The request-specific non-zero timeouts set for
1552 the requests that are executed override this value. This means
1553 that if QNetworkAccessManager has an enabled timeout, it needs
1554 to be disabled to execute a request without a timeout.
1555
1556 \sa transferTimeoutAsDuration()
1557 */
1558void QNetworkAccessManager::setTransferTimeout(std::chrono::milliseconds duration)
1559{
1560 d_func()->transferTimeout = duration;
1561}
1562
1563void QNetworkAccessManagerPrivate::_q_replyFinished(QNetworkReply *reply)
1564{
1565 Q_Q(QNetworkAccessManager);
1566
1567 emit q->finished(reply);
1568 if (reply->request().attribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute, false).toBool())
1569 QMetaObject::invokeMethod(reply, [reply] { reply->deleteLater(); }, Qt::QueuedConnection);
1570}
1571
1572void QNetworkAccessManagerPrivate::_q_replyEncrypted(QNetworkReply *reply)
1573{
1574#ifndef QT_NO_SSL
1575 Q_Q(QNetworkAccessManager);
1576 emit q->encrypted(reply);
1577#else
1578 Q_UNUSED(reply);
1579#endif
1580}
1581
1582void QNetworkAccessManagerPrivate::_q_replySslErrors(const QList<QSslError> &errors)
1583{
1584#ifndef QT_NO_SSL
1585 Q_Q(QNetworkAccessManager);
1586 QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
1587 if (reply)
1588 emit q->sslErrors(reply, errors);
1589#else
1590 Q_UNUSED(errors);
1591#endif
1592}
1593
1594#ifndef QT_NO_SSL
1595void QNetworkAccessManagerPrivate::_q_replyPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator)
1596{
1597 Q_Q(QNetworkAccessManager);
1598 QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
1599 if (reply)
1600 emit q->preSharedKeyAuthenticationRequired(reply, authenticator);
1601}
1602#endif
1603
1604QNetworkReply *QNetworkAccessManagerPrivate::postProcess(QNetworkReply *reply)
1605{
1606 Q_Q(QNetworkAccessManager);
1607 QNetworkReplyPrivate::setManager(reply, q);
1608 q->connect(reply, &QNetworkReply::finished, reply,
1609 [this, reply]() { _q_replyFinished(reply); });
1610#ifndef QT_NO_SSL
1611 /* In case we're compiled without SSL support, we don't have this signal and we need to
1612 * avoid getting a connection error. */
1613 q->connect(reply, &QNetworkReply::encrypted, reply,
1614 [this, reply]() { _q_replyEncrypted(reply); });
1615 q->connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SLOT(_q_replySslErrors(QList<QSslError>)));
1616 q->connect(reply, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), SLOT(_q_replyPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)));
1617#endif
1618
1619 return reply;
1620}
1621
1622void QNetworkAccessManagerPrivate::createCookieJar() const
1623{
1624 if (!cookieJarCreated) {
1625 // keep the ugly hack in here
1626 QNetworkAccessManagerPrivate *that = const_cast<QNetworkAccessManagerPrivate *>(this);
1627 that->cookieJar = new QNetworkCookieJar(that->q_func());
1628 that->cookieJarCreated = true;
1629 }
1630}
1631
1632void QNetworkAccessManagerPrivate::authenticationRequired(QAuthenticator *authenticator,
1633 QNetworkReply *reply,
1634 bool synchronous,
1635 QUrl &url,
1636 QUrl *urlForLastAuthentication,
1637 bool allowAuthenticationReuse)
1638{
1639 Q_Q(QNetworkAccessManager);
1640
1641 // don't try the cache for the same URL twice in a row
1642 // being called twice for the same URL means the authentication failed
1643 // also called when last URL is empty, e.g. on first call
1644 if (allowAuthenticationReuse && (urlForLastAuthentication->isEmpty()
1645 || url != *urlForLastAuthentication)) {
1646 // if credentials are included in the url, then use them, unless they were already used
1647 if (!url.userName().isEmpty() && !url.password().isEmpty()
1648 && (url.userName() != authenticator->user()
1649 || url.password() != authenticator->password())) {
1650 authenticator->setUser(url.userName(QUrl::FullyDecoded));
1651 authenticator->setPassword(url.password(QUrl::FullyDecoded));
1652 *urlForLastAuthentication = url;
1653 authenticationManager->cacheCredentials(url, authenticator);
1654 return;
1655 }
1656
1657 QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedCredentials(url, authenticator);
1658 if (!cred.isNull()
1659 && (cred.user != authenticator->user() || cred.password != authenticator->password())) {
1660 authenticator->setUser(cred.user);
1661 authenticator->setPassword(cred.password);
1662 *urlForLastAuthentication = url;
1663 return;
1664 }
1665 }
1666
1667 // if we emit a signal here in synchronous mode, the user might spin
1668 // an event loop, which might recurse and lead to problems
1669 if (synchronous)
1670 return;
1671
1672 *urlForLastAuthentication = url;
1673 emit q->authenticationRequired(reply, authenticator);
1674 if (allowAuthenticationReuse)
1675 authenticationManager->cacheCredentials(url, authenticator);
1676}
1677
1678#ifndef QT_NO_NETWORKPROXY
1679void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(const QUrl &url,
1680 const QNetworkProxy &proxy,
1681 bool synchronous,
1682 QAuthenticator *authenticator,
1683 QNetworkProxy *lastProxyAuthentication)
1684{
1685 Q_Q(QNetworkAccessManager);
1686 QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(*authenticator);
1687 if (proxy != *lastProxyAuthentication && (!priv || !priv->hasFailed)) {
1688 QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedProxyCredentials(proxy);
1689 if (!cred.isNull()) {
1690 authenticator->setUser(cred.user);
1691 authenticator->setPassword(cred.password);
1692 return;
1693 }
1694 }
1695
1696#if defined(Q_OS_MACOS)
1697 //now we try to get the username and password from keychain
1698 //if not successful signal will be emitted
1699 QString username;
1700 QString password;
1701 if (getProxyAuth(proxy.hostName(), url.scheme(), username, password)) {
1702 // only cache the system credentials if they are correct (or if they have changed)
1703 // to not run into an endless loop in case they are wrong
1704 QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedProxyCredentials(proxy);
1705 if (!priv->hasFailed || cred.user != username || cred.password != password) {
1706 authenticator->setUser(username);
1707 authenticator->setPassword(password);
1708 authenticationManager->cacheProxyCredentials(proxy, authenticator);
1709 return;
1710 }
1711 }
1712#else
1713 Q_UNUSED(url);
1714#endif
1715
1716 // if we emit a signal here in synchronous mode, the user might spin
1717 // an event loop, which might recurse and lead to problems
1718 if (synchronous)
1719 return;
1720
1721 *lastProxyAuthentication = proxy;
1722 emit q->proxyAuthenticationRequired(proxy, authenticator);
1723 authenticationManager->cacheProxyCredentials(proxy, authenticator);
1724}
1725
1726QList<QNetworkProxy> QNetworkAccessManagerPrivate::queryProxy(const QNetworkProxyQuery &query)
1727{
1728 QList<QNetworkProxy> proxies;
1729 if (proxyFactory) {
1730 proxies = proxyFactory->queryProxy(query);
1731 if (proxies.isEmpty()) {
1732 qWarning("QNetworkAccessManager: factory %p has returned an empty result set",
1733 proxyFactory);
1734 proxies << QNetworkProxy::NoProxy;
1735 }
1736 } else if (proxy.type() == QNetworkProxy::DefaultProxy) {
1737 // no proxy set, query the application
1738 return QNetworkProxyFactory::proxyForQuery(query);
1739 } else {
1740 proxies << proxy;
1741 }
1742
1743 return proxies;
1744}
1745#endif
1746
1747void QNetworkAccessManagerPrivate::clearAuthenticationCache(QNetworkAccessManager *manager)
1748{
1749 manager->d_func()->authenticationManager->clearCache();
1750}
1751
1752void QNetworkAccessManagerPrivate::clearConnectionCache(QNetworkAccessManager *manager)
1753{
1754 manager->d_func()->destroyThread();
1755}
1756
1757QNetworkAccessManagerPrivate::~QNetworkAccessManagerPrivate()
1758{
1759 destroyThread();
1760}
1761
1762QThread * QNetworkAccessManagerPrivate::createThread()
1763{
1764 if (!thread) {
1765 thread = new QThread;
1766 thread->setObjectName(QStringLiteral("QNetworkAccessManager thread"));
1767 thread->start();
1768 }
1769 Q_ASSERT(thread);
1770 return thread;
1771}
1772
1773void QNetworkAccessManagerPrivate::destroyThread()
1774{
1775 if (thread) {
1776 thread->quit();
1777 thread->wait(QDeadlineTimer(5000));
1778 if (thread->isFinished())
1779 delete thread;
1780 else
1781 QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
1782 thread = nullptr;
1783 }
1784}
1785
1786
1787#if QT_CONFIG(http) || defined(Q_OS_WASM)
1788
1789QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart)
1790{
1791 // copy the request, we probably need to add some headers
1792 QNetworkRequest newRequest(request);
1793 auto h = newRequest.headers();
1794
1795 // add Content-Type header if not there already
1796 if (!h.contains(QHttpHeaders::WellKnownHeader::ContentType)) {
1797 QByteArray contentType;
1798 contentType.reserve(34 + multiPart->d_func()->boundary.size());
1799 contentType += "multipart/";
1800 switch (multiPart->d_func()->contentType) {
1801 case QHttpMultiPart::RelatedType:
1802 contentType += "related";
1803 break;
1804 case QHttpMultiPart::FormDataType:
1805 contentType += "form-data";
1806 break;
1807 case QHttpMultiPart::AlternativeType:
1808 contentType += "alternative";
1809 break;
1810 default:
1811 contentType += "mixed";
1812 break;
1813 }
1814 // putting the boundary into quotes, recommended in RFC 2046 section 5.1.1
1815 contentType += "; boundary=\"" + multiPart->d_func()->boundary + '"';
1816 h.append(QHttpHeaders::WellKnownHeader::ContentType, contentType);
1817 }
1818
1819 // add MIME-Version header if not there already (we must include the header
1820 // if the message conforms to RFC 2045, see section 4 of that RFC)
1821 if (!h.contains(QHttpHeaders::WellKnownHeader::MIMEVersion))
1822 h.append(QHttpHeaders::WellKnownHeader::MIMEVersion, "1.0"_ba);
1823
1824 newRequest.setHeaders(std::move(h));
1825
1826 QIODevice *device = multiPart->d_func()->device;
1827 if (!device->isReadable()) {
1828 if (!device->isOpen()) {
1829 if (!device->open(QIODevice::ReadOnly))
1830 qWarning("could not open device for reading");
1831 } else {
1832 qWarning("device is not readable");
1833 }
1834 }
1835
1836 return newRequest;
1837}
1838#endif // QT_CONFIG(http)
1839
1840/*!
1841 \internal
1842 Go through the instances so the factories will be created and
1843 register themselves to QNetworkAccessBackendFactoryData
1844*/
1845void QNetworkAccessManagerPrivate::ensureBackendPluginsLoaded()
1846{
1847 Q_CONSTINIT static QBasicMutex mutex;
1848 std::unique_lock locker(mutex);
1849 if (!qnabfLoader())
1850 return;
1851#if QT_CONFIG(library)
1852 qnabfLoader->update();
1853#endif
1854 const int pluginCount = qnabfLoader->metaData().size();
1855 for (int i = 0; i < pluginCount; ++i)
1856 qnabfLoader->instance(i);
1857}
1858
1859QT_END_NAMESPACE
1860
1861#include "moc_qnetworkaccessmanager.cpp"
Combined button and popup list for selecting options.
#define QNetworkAccessBackendFactory_iid