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 \sa isStrictTransportSecurityStoreEnabled(), setStrictTransportSecurityEnabled(),
701 QStandardPaths::standardLocations()
702*/
703
704void QNetworkAccessManager::enableStrictTransportSecurityStore(bool enabled, const QString &storeDir)
705{
706#if QT_CONFIG(settings)
707 Q_D(QNetworkAccessManager);
708 d->stsStore.reset(enabled ? new QHstsStore(storeDir) : nullptr);
709 d->stsCache.setStore(d->stsStore.get());
710#else
711 Q_UNUSED(enabled);
712 Q_UNUSED(storeDir);
713 qWarning("HSTS permanent store requires the feature 'settings' enabled");
714#endif // QT_CONFIG(settings)
715}
716
717/*!
718 \since 5.10
719
720 Returns true if HSTS cache uses a permanent store to load and store HSTS
721 policies.
722
723 \sa enableStrictTransportSecurityStore()
724*/
725
726bool QNetworkAccessManager::isStrictTransportSecurityStoreEnabled() const
727{
728#if QT_CONFIG(settings)
729 Q_D(const QNetworkAccessManager);
730 return bool(d->stsStore);
731#else
732 return false;
733#endif // QT_CONFIG(settings)
734}
735
736/*!
737 \since 5.9
738
739 Adds HTTP Strict Transport Security policies into HSTS cache.
740 \a knownHosts contains the known hosts that have QHstsPolicy
741 information.
742
743 \note An expired policy will remove a known host from the cache, if previously
744 present.
745
746 \note While processing HTTP responses, QNetworkAccessManager can also update
747 the HSTS cache, removing or updating exitsting policies or introducing new
748 \a knownHosts. The current implementation thus is server-driven, client code
749 can provide QNetworkAccessManager with previously known or discovered
750 policies, but this information can be overridden by "Strict-Transport-Security"
751 response headers.
752
753 \sa strictTransportSecurityHosts(), enableStrictTransportSecurityStore(), QHstsPolicy
754*/
755
756void QNetworkAccessManager::addStrictTransportSecurityHosts(const QList<QHstsPolicy> &knownHosts)
757{
758 Q_D(QNetworkAccessManager);
759 d->stsCache.updateFromPolicies(knownHosts);
760}
761
762/*!
763 \since 5.9
764
765 Returns the list of HTTP Strict Transport Security policies. This list can
766 differ from what was initially set via addStrictTransportSecurityHosts() if
767 HSTS cache was updated from a "Strict-Transport-Security" response header.
768
769 \sa addStrictTransportSecurityHosts(), QHstsPolicy
770*/
771QList<QHstsPolicy> QNetworkAccessManager::strictTransportSecurityHosts() const
772{
773 Q_D(const QNetworkAccessManager);
774 return d->stsCache.policies();
775}
776
777/*!
778 Posts a request to obtain the network headers for \a request
779 and returns a new QNetworkReply object which will contain such headers.
780
781 The function is named after the HTTP request associated (HEAD).
782*/
783QNetworkReply *QNetworkAccessManager::head(const QNetworkRequest &request)
784{
785 return d_func()->postProcess(createRequest(QNetworkAccessManager::HeadOperation, request));
786}
787
788/*!
789 Posts a request to obtain the contents of the target \a request
790 and returns a new QNetworkReply object opened for reading which emits the
791 \l{QIODevice::readyRead()}{readyRead()} signal whenever new data
792 arrives.
793
794 The contents as well as associated headers will be downloaded.
795
796 \sa post(), put(), deleteResource(), sendCustomRequest()
797*/
798QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
799{
800 return d_func()->postProcess(createRequest(QNetworkAccessManager::GetOperation, request));
801}
802
803/*!
804 \since 6.7
805
806 \overload
807
808 \note A GET request with a message body is not cached.
809
810 \note If the request is redirected, the message body will be kept only if the status code is
811 308.
812*/
813
814QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request, QIODevice *data)
815{
816 QNetworkRequest newRequest(request);
817 return d_func()->postProcess(
818 createRequest(QNetworkAccessManager::GetOperation, newRequest, data));
819}
820
821/*!
822 \since 6.7
823
824 \overload
825
826 \note A GET request with a message body is not cached.
827
828 \note If the request is redirected, the message body will be kept only if the status code is
829 308.
830*/
831
832QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request, const QByteArray &data)
833{
834 QBuffer *buffer = new QBuffer;
835 buffer->setData(data);
836 buffer->open(QIODevice::ReadOnly);
837
838 QNetworkReply *reply = get(request, buffer);
839 buffer->setParent(reply);
840 return reply;
841}
842
843/*!
844 Sends an HTTP POST request to the destination specified by \a request
845 and returns a new QNetworkReply object opened for reading that will
846 contain the reply sent by the server. The contents of the \a data
847 device will be uploaded to the server.
848
849 \a data must be open for reading and must remain valid until the
850 finished() signal is emitted for this reply.
851
852 \note Sending a POST request on protocols other than HTTP and
853 HTTPS is undefined and will probably fail.
854
855 \sa get(), put(), deleteResource(), sendCustomRequest()
856*/
857QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QIODevice *data)
858{
859 return d_func()->postProcess(createRequest(QNetworkAccessManager::PostOperation, request, data));
860}
861
862/*!
863 \overload
864
865 Sends the contents of the \a data byte array to the destination
866 specified by \a request.
867*/
868QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, const QByteArray &data)
869{
870 QBuffer *buffer = new QBuffer;
871 buffer->setData(data);
872 buffer->open(QIODevice::ReadOnly);
873
874 QNetworkReply *reply = post(request, buffer);
875 buffer->setParent(reply);
876 return reply;
877}
878
879/*!
880 \fn QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, std::nullptr_t nptr)
881
882 \since 6.8
883
884 \overload
885
886 Sends the POST request specified by \a request without a body and returns
887 a new QNetworkReply object.
888*/
889
890#if QT_CONFIG(http) || defined(Q_OS_WASM)
891/*!
892 \since 4.8
893
894 \overload
895
896 Sends the contents of the \a multiPart message to the destination
897 specified by \a request.
898
899 This can be used for sending MIME multipart messages over HTTP.
900
901 \sa QHttpMultiPart, QHttpPart, put()
902*/
903QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QHttpMultiPart *multiPart)
904{
905 QNetworkRequest newRequest = d_func()->prepareMultipart(request, multiPart);
906 QIODevice *device = multiPart->d_func()->device;
907 QNetworkReply *reply = post(newRequest, device);
908 return reply;
909}
910
911/*!
912 \since 4.8
913
914 \overload
915
916 Sends the contents of the \a multiPart message to the destination
917 specified by \a request.
918
919 This can be used for sending MIME multipart messages over HTTP.
920
921 \sa QHttpMultiPart, QHttpPart, post()
922*/
923QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, QHttpMultiPart *multiPart)
924{
925 QNetworkRequest newRequest = d_func()->prepareMultipart(request, multiPart);
926 QIODevice *device = multiPart->d_func()->device;
927 QNetworkReply *reply = put(newRequest, device);
928 return reply;
929}
930#endif // QT_CONFIG(http)
931
932/*!
933 Uploads the contents of \a data to the destination \a request and
934 returns a new QNetworkReply object that will be open for reply.
935
936 \a data must be opened for reading when this function is called
937 and must remain valid until the finished() signal is emitted for
938 this reply.
939
940 Whether anything will be available for reading from the returned
941 object is protocol dependent. For HTTP, the server may send a
942 small HTML page indicating the upload was successful (or not).
943 Other protocols will probably have content in their replies.
944
945 \note For HTTP, this request will send a PUT request, which most servers
946 do not allow. Form upload mechanisms, including that of uploading
947 files through HTML forms, use the POST mechanism.
948
949 \sa get(), post(), deleteResource(), sendCustomRequest()
950*/
951QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, QIODevice *data)
952{
953 return d_func()->postProcess(createRequest(QNetworkAccessManager::PutOperation, request, data));
954}
955
956/*!
957 \overload
958
959 Sends the contents of the \a data byte array to the destination
960 specified by \a request.
961*/
962QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, const QByteArray &data)
963{
964 QBuffer *buffer = new QBuffer;
965 buffer->setData(data);
966 buffer->open(QIODevice::ReadOnly);
967
968 QNetworkReply *reply = put(request, buffer);
969 buffer->setParent(reply);
970 return reply;
971}
972
973/*!
974 \since 6.8
975
976 \overload
977
978 \fn QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, std::nullptr_t nptr)
979
980 Sends the PUT request specified by \a request without a body and returns
981 a new QNetworkReply object.
982*/
983
984/*!
985 \since 4.6
986
987 Sends a request to delete the resource identified by the URL of \a request.
988
989 \note This feature is currently available for HTTP only, performing an
990 HTTP DELETE request.
991
992 \sa get(), post(), put(), sendCustomRequest()
993*/
994QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &request)
995{
996 return d_func()->postProcess(createRequest(QNetworkAccessManager::DeleteOperation, request));
997}
998
999#ifndef QT_NO_SSL
1000/*!
1001 \since 5.2
1002
1003 Initiates a connection to the host given by \a hostName at port \a port, using
1004 \a sslConfiguration. This function is useful to complete the TCP and SSL handshake
1005 to a host before the HTTPS request is made, resulting in a lower network latency.
1006
1007 \note Preconnecting a HTTP/2 connection can be done by calling setAllowedNextProtocols()
1008 on \a sslConfiguration with QSslConfiguration::ALPNProtocolHTTP2 contained in
1009 the list of allowed protocols. When using HTTP/2, one single connection per host is
1010 enough, i.e. calling this method multiple times per host will not result in faster
1011 network transactions.
1012
1013 \note This function has no possibility to report errors.
1014
1015 \sa connectToHost(), get(), post(), put(), deleteResource()
1016*/
1017
1018void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quint16 port,
1019 const QSslConfiguration &sslConfiguration)
1020{
1021 connectToHostEncrypted(hostName, port, sslConfiguration, QString());
1022}
1023
1024/*!
1025 \since 5.13
1026 \overload
1027
1028 Initiates a connection to the host given by \a hostName at port \a port, using
1029 \a sslConfiguration with \a peerName set to be the hostName used for certificate
1030 validation. This function is useful to complete the TCP and SSL handshake
1031 to a host before the HTTPS request is made, resulting in a lower network latency.
1032
1033 \note Preconnecting a HTTP/2 connection can be done by calling setAllowedNextProtocols()
1034 on \a sslConfiguration with QSslConfiguration::ALPNProtocolHTTP2 contained in
1035 the list of allowed protocols. When using HTTP/2, one single connection per host is
1036 enough, i.e. calling this method multiple times per host will not result in faster
1037 network transactions.
1038
1039 \note This function has no possibility to report errors.
1040
1041 \sa connectToHost(), get(), post(), put(), deleteResource()
1042*/
1043
1044void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quint16 port,
1045 const QSslConfiguration &sslConfiguration,
1046 const QString &peerName)
1047{
1048 QUrl url;
1049 url.setHost(hostName);
1050 url.setPort(port);
1051 url.setScheme("preconnect-https"_L1);
1052 QNetworkRequest request(url);
1053 if (sslConfiguration != QSslConfiguration::defaultConfiguration())
1054 request.setSslConfiguration(sslConfiguration);
1055
1056 // There is no way to enable HTTP2 via a request after having established the connection,
1057 // so we need to check the ssl configuration whether HTTP2 is allowed here.
1058 if (!sslConfiguration.allowedNextProtocols().contains(QSslConfiguration::ALPNProtocolHTTP2))
1059 request.setAttribute(QNetworkRequest::Http2AllowedAttribute, false);
1060
1061 request.setPeerVerifyName(peerName);
1062 get(request);
1063}
1064#endif
1065
1066/*!
1067 \since 5.2
1068
1069 Initiates a connection to the host given by \a hostName at port \a port.
1070 This function is useful to complete the TCP handshake
1071 to a host before the HTTP request is made, resulting in a lower network latency.
1072
1073 \note This function has no possibility to report errors.
1074
1075 \sa connectToHostEncrypted(), get(), post(), put(), deleteResource()
1076*/
1077void QNetworkAccessManager::connectToHost(const QString &hostName, quint16 port)
1078{
1079 QUrl url;
1080 url.setHost(hostName);
1081 url.setPort(port);
1082 url.setScheme("preconnect-http"_L1);
1083 QNetworkRequest request(url);
1084 get(request);
1085}
1086
1087/*!
1088 \since 5.9
1089
1090 Sets the manager's redirect policy to be the \a policy specified. This policy
1091 will affect all subsequent requests created by the manager.
1092
1093 Use this function to enable or disable HTTP redirects on the manager's level.
1094
1095 \note When creating a request QNetworkRequest::RedirectAttributePolicy has
1096 the highest priority, next by priority the manager's policy.
1097
1098 The default value is QNetworkRequest::NoLessSafeRedirectPolicy.
1099 Clients relying on manual redirect handling are encouraged to set
1100 this policy explicitly in their code.
1101
1102 \sa redirectPolicy(), QNetworkRequest::RedirectPolicy
1103*/
1104void QNetworkAccessManager::setRedirectPolicy(QNetworkRequest::RedirectPolicy policy)
1105{
1106 Q_D(QNetworkAccessManager);
1107 d->redirectPolicy = policy;
1108}
1109
1110/*!
1111 \since 5.9
1112
1113 Returns the redirect policy that is used when creating new requests.
1114
1115 \sa setRedirectPolicy(), QNetworkRequest::RedirectPolicy
1116*/
1117QNetworkRequest::RedirectPolicy QNetworkAccessManager::redirectPolicy() const
1118{
1119 Q_D(const QNetworkAccessManager);
1120 return d->redirectPolicy;
1121}
1122
1123/*!
1124 \since 4.7
1125
1126 Sends a custom request to the server identified by the URL of \a request.
1127
1128 It is the user's responsibility to send a \a verb to the server that is valid
1129 according to the HTTP specification.
1130
1131 This method provides means to send verbs other than the common ones provided
1132 via get() or post() etc., for instance sending an HTTP OPTIONS command.
1133
1134 If \a data is not empty, the contents of the \a data
1135 device will be uploaded to the server; in that case, data must be open for
1136 reading and must remain valid until the finished() signal is emitted for this reply.
1137
1138 \note This feature is currently available for HTTP(S) only.
1139
1140 \sa get(), post(), put(), deleteResource()
1141*/
1142QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data)
1143{
1144 QNetworkRequest newRequest(request);
1145 newRequest.setAttribute(QNetworkRequest::CustomVerbAttribute, verb);
1146 return d_func()->postProcess(createRequest(QNetworkAccessManager::CustomOperation, newRequest, data));
1147}
1148
1149/*!
1150 \since 5.8
1151
1152 \overload
1153
1154 Sends the contents of the \a data byte array to the destination
1155 specified by \a request.
1156*/
1157QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, const QByteArray &data)
1158{
1159 QBuffer *buffer = new QBuffer;
1160 buffer->setData(data);
1161 buffer->open(QIODevice::ReadOnly);
1162
1163 QNetworkReply *reply = sendCustomRequest(request, verb, buffer);
1164 buffer->setParent(reply);
1165 return reply;
1166}
1167
1168#if QT_CONFIG(http) || defined(Q_OS_WASM)
1169/*!
1170 \since 5.8
1171
1172 \overload
1173
1174 Sends a custom request to the server identified by the URL of \a request.
1175
1176 Sends the contents of the \a multiPart message to the destination
1177 specified by \a request.
1178
1179 This can be used for sending MIME multipart messages for custom verbs.
1180
1181 \sa QHttpMultiPart, QHttpPart, put()
1182*/
1183QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QHttpMultiPart *multiPart)
1184{
1185 QNetworkRequest newRequest = d_func()->prepareMultipart(request, multiPart);
1186 QIODevice *device = multiPart->d_func()->device;
1187 QNetworkReply *reply = sendCustomRequest(newRequest, verb, device);
1188 return reply;
1189}
1190#endif // QT_CONFIG(http)
1191
1192/*!
1193 Returns a new QNetworkReply object to handle the operation \a op
1194 and request \a originalReq. The device \a outgoingData is always 0
1195 for Get and Head requests, but is the value passed to post() and
1196 put() in those operations (the QByteArray variants will pass a QBuffer
1197 object).
1198
1199 The default implementation calls QNetworkCookieJar::cookiesForUrl()
1200 on the cookie jar set with setCookieJar() to obtain the cookies to
1201 be sent to the remote server.
1202
1203 The returned object must be in an open state.
1204*/
1205QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op,
1206 const QNetworkRequest &originalReq,
1207 QIODevice *outgoingData)
1208{
1209 Q_D(QNetworkAccessManager);
1210
1211 QNetworkRequest req(originalReq);
1212 if (redirectPolicy() != QNetworkRequest::NoLessSafeRedirectPolicy
1213 && req.attribute(QNetworkRequest::RedirectPolicyAttribute).isNull()) {
1214 req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, redirectPolicy());
1215 }
1216
1217#if QT_CONFIG(http) || defined (Q_OS_WASM)
1218 if (req.transferTimeoutAsDuration() == 0ms)
1219 req.setTransferTimeout(transferTimeoutAsDuration());
1220#endif
1221
1222 if (autoDeleteReplies()
1223 && req.attribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute).isNull()) {
1224 req.setAttribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute, true);
1225 }
1226
1227 bool isLocalFile = req.url().isLocalFile();
1228 QString scheme = req.url().scheme();
1229
1230 // Remap local+http to unix+http to make further processing easier
1231 if (scheme == "local+http"_L1) {
1232 scheme = u"unix+http"_s;
1233 QUrl url = req.url();
1234 url.setScheme(scheme);
1235 req.setUrl(url);
1236 }
1237
1238 // fast path for GET on file:// URLs
1239 // The QNetworkAccessFileBackend will right now only be used for PUT
1240 if (op == QNetworkAccessManager::GetOperation
1241 || op == QNetworkAccessManager::HeadOperation) {
1242 if (isLocalFile
1243#ifdef Q_OS_ANDROID
1244 || scheme == "assets"_L1
1245#endif
1246 || scheme == "qrc"_L1) {
1247 return new QNetworkReplyFileImpl(this, req, op);
1248 }
1249
1250 if (scheme == "data"_L1)
1251 return new QNetworkReplyDataImpl(this, req, op);
1252
1253 // A request with QNetworkRequest::AlwaysCache does not need any bearer management
1254 QNetworkRequest::CacheLoadControl mode =
1255 static_cast<QNetworkRequest::CacheLoadControl>(
1256 req.attribute(QNetworkRequest::CacheLoadControlAttribute,
1257 QNetworkRequest::PreferNetwork).toInt());
1258 if (mode == QNetworkRequest::AlwaysCache) {
1259 // FIXME Implement a QNetworkReplyCacheImpl instead, see QTBUG-15106
1260 QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
1261 QNetworkReplyImplPrivate *priv = reply->d_func();
1262 priv->manager = this;
1263 priv->backend = new QNetworkAccessCacheBackend();
1264 priv->backend->setManagerPrivate(this->d_func());
1265 priv->backend->setParent(reply);
1266 priv->backend->setReplyPrivate(priv);
1267 priv->setup(op, req, outgoingData);
1268 return reply;
1269 }
1270 }
1271 QNetworkRequest request = req;
1272 auto h = request.headers();
1273#ifndef Q_OS_WASM // Content-length header is not allowed to be set by user in wasm
1274 if (!h.contains(QHttpHeaders::WellKnownHeader::ContentLength) &&
1275 outgoingData && !outgoingData->isSequential() && outgoingData->size()) {
1276 // request has no Content-Length
1277 // but the data that is outgoing is random-access
1278 h.append(QHttpHeaders::WellKnownHeader::ContentLength,
1279 QByteArray::number(outgoingData->size()));
1280 }
1281#endif
1282 if (static_cast<QNetworkRequest::LoadControl>
1283 (request.attribute(QNetworkRequest::CookieLoadControlAttribute,
1284 QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Automatic) {
1285 if (d->cookieJar) {
1286 QList<QNetworkCookie> cookies = d->cookieJar->cookiesForUrl(request.url());
1287 if (!cookies.isEmpty())
1288 h.replaceOrAppend(QHttpHeaders::WellKnownHeader::Cookie,
1289 QNetworkHeadersPrivate::fromCookieList(cookies));
1290 }
1291 }
1292 request.setHeaders(std::move(h));
1293#ifdef Q_OS_WASM
1294 Q_UNUSED(isLocalFile);
1295 // Support http, https, and relative urls
1296 if (scheme == "http"_L1 || scheme == "https"_L1 || scheme.isEmpty()) {
1297 QNetworkReplyWasmImpl *reply = new QNetworkReplyWasmImpl(this);
1298 QNetworkReplyWasmImplPrivate *priv = reply->d_func();
1299 priv->manager = this;
1300 priv->setup(op, request, outgoingData);
1301 return reply;
1302 }
1303#endif
1304
1305#if QT_CONFIG(http)
1306 constexpr char16_t httpSchemes[][17] = {
1307 u"http",
1308 u"preconnect-http",
1309#ifndef QT_NO_SSL
1310 u"https",
1311 u"preconnect-https",
1312#endif
1313 u"unix+http",
1314 };
1315 // Since Qt 5 we use the new QNetworkReplyHttpImpl
1316 if (std::find(std::begin(httpSchemes), std::end(httpSchemes), scheme) != std::end(httpSchemes)) {
1317
1318#ifndef QT_NO_SSL
1319 const bool isLocalSocket = scheme.startsWith("unix"_L1);
1320 if (!isLocalSocket && isStrictTransportSecurityEnabled()
1321 && d->stsCache.isKnownHost(request.url())) {
1322 QUrl stsUrl(request.url());
1323 // RFC6797, 8.3:
1324 // The UA MUST replace the URI scheme with "https" [RFC2818],
1325 // and if the URI contains an explicit port component of "80",
1326 // then the UA MUST convert the port component to be "443", or
1327 // if the URI contains an explicit port component that is not
1328 // equal to "80", the port component value MUST be preserved;
1329 // otherwise,
1330 // if the URI does not contain an explicit port component, the UA
1331 // MUST NOT add one.
1332 if (stsUrl.port() == 80)
1333 stsUrl.setPort(443);
1334 stsUrl.setScheme("https"_L1);
1335 request.setUrl(stsUrl);
1336 }
1337#endif
1338 QNetworkReplyHttpImpl *reply = new QNetworkReplyHttpImpl(this, request, op, outgoingData);
1339 return reply;
1340 }
1341#endif // QT_CONFIG(http)
1342
1343 // first step: create the reply
1344 QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
1345 QNetworkReplyImplPrivate *priv = reply->d_func();
1346 priv->manager = this;
1347
1348 // second step: fetch cached credentials
1349 // This is not done for the time being, we should use signal emissions to request
1350 // the credentials from cache.
1351
1352 // third step: find a backend
1353 priv->backend = d->findBackend(op, request);
1354
1355 if (priv->backend) {
1356 priv->backend->setParent(reply);
1357 priv->backend->setReplyPrivate(priv);
1358 }
1359
1360#ifndef QT_NO_SSL
1361 reply->setSslConfiguration(request.sslConfiguration());
1362#endif
1363
1364 // fourth step: setup the reply
1365 priv->setup(op, request, outgoingData);
1366
1367 return reply;
1368}
1369
1370/*!
1371 \since 5.2
1372
1373 Lists all the URL schemes supported by the access manager.
1374
1375 Reimplement this method to provide your own supported schemes
1376 in a QNetworkAccessManager subclass. It is for instance necessary
1377 when your subclass provides support for new protocols.
1378*/
1379QStringList QNetworkAccessManager::supportedSchemes() const
1380{
1381 QStringList schemes;
1382 QNetworkAccessManager *self = const_cast<QNetworkAccessManager *>(this); // We know we call a const slot
1383 QMetaObject::invokeMethod(self, "supportedSchemesImplementation", Qt::DirectConnection,
1384 Q_RETURN_ARG(QStringList, schemes));
1385 schemes.removeDuplicates();
1386 return schemes;
1387}
1388
1389/*!
1390 \since 5.2
1391 \deprecated
1392
1393 Lists all the URL schemes supported by the access manager.
1394
1395 You should not call this function directly; use
1396 QNetworkAccessManager::supportedSchemes() instead.
1397
1398 Because of binary compatibility constraints, the supportedSchemes()
1399 method (introduced in Qt 5.2) was not virtual in Qt 5, but now it
1400 is. Override the supportedSchemes method rather than this one.
1401
1402 \sa supportedSchemes()
1403*/
1404QStringList QNetworkAccessManager::supportedSchemesImplementation() const
1405{
1406 Q_D(const QNetworkAccessManager);
1407
1408 QStringList schemes = d->backendSupportedSchemes();
1409 // Those ones don't exist in backends
1410#if QT_CONFIG(http)
1411 schemes << QStringLiteral("http");
1412 schemes << QStringLiteral("unix+http");
1413 schemes << QStringLiteral("local+http");
1414#ifndef QT_NO_SSL
1415 if (QSslSocket::supportsSsl())
1416 schemes << QStringLiteral("https");
1417#endif
1418#endif
1419 schemes << QStringLiteral("data");
1420 return schemes;
1421}
1422
1423/*!
1424 \since 5.0
1425
1426 Flushes the internal cache of authentication data and network connections.
1427
1428 This function is useful for doing auto tests.
1429
1430 \sa clearConnectionCache()
1431*/
1432void QNetworkAccessManager::clearAccessCache()
1433{
1434 QNetworkAccessManagerPrivate::clearAuthenticationCache(this);
1435 QNetworkAccessManagerPrivate::clearConnectionCache(this);
1436}
1437
1438/*!
1439 \since 5.9
1440
1441 Flushes the internal cache of network connections.
1442 In contrast to clearAccessCache() the authentication data
1443 is preserved.
1444
1445 \sa clearAccessCache()
1446*/
1447void QNetworkAccessManager::clearConnectionCache()
1448{
1449 QNetworkAccessManagerPrivate::clearConnectionCache(this);
1450}
1451
1452
1453/*!
1454 \since 5.14
1455
1456 Returns the true if QNetworkAccessManager is currently configured
1457 to automatically delete QNetworkReplies, false otherwise.
1458
1459 \sa setAutoDeleteReplies,
1460 QNetworkRequest::AutoDeleteReplyOnFinishAttribute
1461*/
1462bool QNetworkAccessManager::autoDeleteReplies() const
1463{
1464 return d_func()->autoDeleteReplies;
1465}
1466
1467/*!
1468 \since 5.14
1469
1470 Enables or disables automatic deletion of \l {QNetworkReply} {QNetworkReplies}.
1471
1472 Setting \a shouldAutoDelete to true is the same as setting the
1473 QNetworkRequest::AutoDeleteReplyOnFinishAttribute attribute to
1474 true on all \e{future} \l {QNetworkRequest} {QNetworkRequests}
1475 passed to this instance of QNetworkAccessManager unless the
1476 attribute was already explicitly set on the QNetworkRequest.
1477
1478 \sa autoDeleteReplies,
1479 QNetworkRequest::AutoDeleteReplyOnFinishAttribute
1480*/
1481void QNetworkAccessManager::setAutoDeleteReplies(bool shouldAutoDelete)
1482{
1483 d_func()->autoDeleteReplies = shouldAutoDelete;
1484}
1485
1486/*!
1487 \fn int QNetworkAccessManager::transferTimeout() const
1488 \since 5.15
1489
1490 Returns the timeout used for transfers, in milliseconds.
1491
1492 \sa setTransferTimeout()
1493*/
1494
1495/*!
1496 \fn void QNetworkAccessManager::setTransferTimeout(int timeout)
1497 \since 5.15
1498
1499 Sets \a timeout as the transfer timeout in milliseconds.
1500
1501 \sa setTransferTimeout(std::chrono::milliseconds),
1502 transferTimeout(), transferTimeoutAsDuration()
1503*/
1504
1505/*!
1506 \since 6.7
1507
1508 Returns the timeout duration after which the transfer is aborted if no
1509 data is exchanged.
1510
1511 The default duration is zero, which means that the timeout is not used.
1512
1513 \sa setTransferTimeout(std::chrono::milliseconds)
1514 */
1515std::chrono::milliseconds QNetworkAccessManager::transferTimeoutAsDuration() const
1516{
1517 return d_func()->transferTimeout;
1518}
1519
1520/*!
1521 \since 6.7
1522
1523 Sets the timeout \a duration to abort the transfer if no data is exchanged.
1524
1525 Transfers are aborted if no bytes are transferred before
1526 the timeout expires. Zero means no timer is set. If no
1527 argument is provided, the timeout is
1528 QNetworkRequest::DefaultTransferTimeout. If this function
1529 is not called, the timeout is disabled and has the
1530 value zero. The request-specific non-zero timeouts set for
1531 the requests that are executed override this value. This means
1532 that if QNetworkAccessManager has an enabled timeout, it needs
1533 to be disabled to execute a request without a timeout.
1534
1535 \sa transferTimeoutAsDuration()
1536 */
1537void QNetworkAccessManager::setTransferTimeout(std::chrono::milliseconds duration)
1538{
1539 d_func()->transferTimeout = duration;
1540}
1541
1542void QNetworkAccessManagerPrivate::_q_replyFinished(QNetworkReply *reply)
1543{
1544 Q_Q(QNetworkAccessManager);
1545
1546 emit q->finished(reply);
1547 if (reply->request().attribute(QNetworkRequest::AutoDeleteReplyOnFinishAttribute, false).toBool())
1548 QMetaObject::invokeMethod(reply, [reply] { reply->deleteLater(); }, Qt::QueuedConnection);
1549}
1550
1551void QNetworkAccessManagerPrivate::_q_replyEncrypted(QNetworkReply *reply)
1552{
1553#ifndef QT_NO_SSL
1554 Q_Q(QNetworkAccessManager);
1555 emit q->encrypted(reply);
1556#else
1557 Q_UNUSED(reply);
1558#endif
1559}
1560
1561void QNetworkAccessManagerPrivate::_q_replySslErrors(const QList<QSslError> &errors)
1562{
1563#ifndef QT_NO_SSL
1564 Q_Q(QNetworkAccessManager);
1565 QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
1566 if (reply)
1567 emit q->sslErrors(reply, errors);
1568#else
1569 Q_UNUSED(errors);
1570#endif
1571}
1572
1573#ifndef QT_NO_SSL
1574void QNetworkAccessManagerPrivate::_q_replyPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator)
1575{
1576 Q_Q(QNetworkAccessManager);
1577 QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
1578 if (reply)
1579 emit q->preSharedKeyAuthenticationRequired(reply, authenticator);
1580}
1581#endif
1582
1583QNetworkReply *QNetworkAccessManagerPrivate::postProcess(QNetworkReply *reply)
1584{
1585 Q_Q(QNetworkAccessManager);
1586 QNetworkReplyPrivate::setManager(reply, q);
1587 q->connect(reply, &QNetworkReply::finished, reply,
1588 [this, reply]() { _q_replyFinished(reply); });
1589#ifndef QT_NO_SSL
1590 /* In case we're compiled without SSL support, we don't have this signal and we need to
1591 * avoid getting a connection error. */
1592 q->connect(reply, &QNetworkReply::encrypted, reply,
1593 [this, reply]() { _q_replyEncrypted(reply); });
1594 q->connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SLOT(_q_replySslErrors(QList<QSslError>)));
1595 q->connect(reply, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), SLOT(_q_replyPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)));
1596#endif
1597
1598 return reply;
1599}
1600
1601void QNetworkAccessManagerPrivate::createCookieJar() const
1602{
1603 if (!cookieJarCreated) {
1604 // keep the ugly hack in here
1605 QNetworkAccessManagerPrivate *that = const_cast<QNetworkAccessManagerPrivate *>(this);
1606 that->cookieJar = new QNetworkCookieJar(that->q_func());
1607 that->cookieJarCreated = true;
1608 }
1609}
1610
1611void QNetworkAccessManagerPrivate::authenticationRequired(QAuthenticator *authenticator,
1612 QNetworkReply *reply,
1613 bool synchronous,
1614 QUrl &url,
1615 QUrl *urlForLastAuthentication,
1616 bool allowAuthenticationReuse)
1617{
1618 Q_Q(QNetworkAccessManager);
1619
1620 // don't try the cache for the same URL twice in a row
1621 // being called twice for the same URL means the authentication failed
1622 // also called when last URL is empty, e.g. on first call
1623 if (allowAuthenticationReuse && (urlForLastAuthentication->isEmpty()
1624 || url != *urlForLastAuthentication)) {
1625 // if credentials are included in the url, then use them, unless they were already used
1626 if (!url.userName().isEmpty() && !url.password().isEmpty()
1627 && (url.userName() != authenticator->user()
1628 || url.password() != authenticator->password())) {
1629 authenticator->setUser(url.userName(QUrl::FullyDecoded));
1630 authenticator->setPassword(url.password(QUrl::FullyDecoded));
1631 *urlForLastAuthentication = url;
1632 authenticationManager->cacheCredentials(url, authenticator);
1633 return;
1634 }
1635
1636 QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedCredentials(url, authenticator);
1637 if (!cred.isNull()
1638 && (cred.user != authenticator->user() || cred.password != authenticator->password())) {
1639 authenticator->setUser(cred.user);
1640 authenticator->setPassword(cred.password);
1641 *urlForLastAuthentication = url;
1642 return;
1643 }
1644 }
1645
1646 // if we emit a signal here in synchronous mode, the user might spin
1647 // an event loop, which might recurse and lead to problems
1648 if (synchronous)
1649 return;
1650
1651 *urlForLastAuthentication = url;
1652 emit q->authenticationRequired(reply, authenticator);
1653 if (allowAuthenticationReuse)
1654 authenticationManager->cacheCredentials(url, authenticator);
1655}
1656
1657#ifndef QT_NO_NETWORKPROXY
1658void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(const QUrl &url,
1659 const QNetworkProxy &proxy,
1660 bool synchronous,
1661 QAuthenticator *authenticator,
1662 QNetworkProxy *lastProxyAuthentication)
1663{
1664 Q_Q(QNetworkAccessManager);
1665 QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(*authenticator);
1666 if (proxy != *lastProxyAuthentication && (!priv || !priv->hasFailed)) {
1667 QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedProxyCredentials(proxy);
1668 if (!cred.isNull()) {
1669 authenticator->setUser(cred.user);
1670 authenticator->setPassword(cred.password);
1671 return;
1672 }
1673 }
1674
1675#if defined(Q_OS_MACOS)
1676 //now we try to get the username and password from keychain
1677 //if not successful signal will be emitted
1678 QString username;
1679 QString password;
1680 if (getProxyAuth(proxy.hostName(), url.scheme(), username, password)) {
1681 // only cache the system credentials if they are correct (or if they have changed)
1682 // to not run into an endless loop in case they are wrong
1683 QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedProxyCredentials(proxy);
1684 if (!priv->hasFailed || cred.user != username || cred.password != password) {
1685 authenticator->setUser(username);
1686 authenticator->setPassword(password);
1687 authenticationManager->cacheProxyCredentials(proxy, authenticator);
1688 return;
1689 }
1690 }
1691#else
1692 Q_UNUSED(url);
1693#endif
1694
1695 // if we emit a signal here in synchronous mode, the user might spin
1696 // an event loop, which might recurse and lead to problems
1697 if (synchronous)
1698 return;
1699
1700 *lastProxyAuthentication = proxy;
1701 emit q->proxyAuthenticationRequired(proxy, authenticator);
1702 authenticationManager->cacheProxyCredentials(proxy, authenticator);
1703}
1704
1705QList<QNetworkProxy> QNetworkAccessManagerPrivate::queryProxy(const QNetworkProxyQuery &query)
1706{
1707 QList<QNetworkProxy> proxies;
1708 if (proxyFactory) {
1709 proxies = proxyFactory->queryProxy(query);
1710 if (proxies.isEmpty()) {
1711 qWarning("QNetworkAccessManager: factory %p has returned an empty result set",
1712 proxyFactory);
1713 proxies << QNetworkProxy::NoProxy;
1714 }
1715 } else if (proxy.type() == QNetworkProxy::DefaultProxy) {
1716 // no proxy set, query the application
1717 return QNetworkProxyFactory::proxyForQuery(query);
1718 } else {
1719 proxies << proxy;
1720 }
1721
1722 return proxies;
1723}
1724#endif
1725
1726void QNetworkAccessManagerPrivate::clearAuthenticationCache(QNetworkAccessManager *manager)
1727{
1728 manager->d_func()->authenticationManager->clearCache();
1729}
1730
1731void QNetworkAccessManagerPrivate::clearConnectionCache(QNetworkAccessManager *manager)
1732{
1733 manager->d_func()->destroyThread();
1734}
1735
1736QNetworkAccessManagerPrivate::~QNetworkAccessManagerPrivate()
1737{
1738 destroyThread();
1739}
1740
1741QThread * QNetworkAccessManagerPrivate::createThread()
1742{
1743 if (!thread) {
1744 thread = new QThread;
1745 thread->setObjectName(QStringLiteral("QNetworkAccessManager thread"));
1746 thread->start();
1747 }
1748 Q_ASSERT(thread);
1749 return thread;
1750}
1751
1752void QNetworkAccessManagerPrivate::destroyThread()
1753{
1754 if (thread) {
1755 thread->quit();
1756 thread->wait(QDeadlineTimer(5000));
1757 if (thread->isFinished())
1758 delete thread;
1759 else
1760 QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
1761 thread = nullptr;
1762 }
1763}
1764
1765
1766#if QT_CONFIG(http) || defined(Q_OS_WASM)
1767
1768QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart)
1769{
1770 // copy the request, we probably need to add some headers
1771 QNetworkRequest newRequest(request);
1772 auto h = newRequest.headers();
1773
1774 // add Content-Type header if not there already
1775 if (!h.contains(QHttpHeaders::WellKnownHeader::ContentType)) {
1776 QByteArray contentType;
1777 contentType.reserve(34 + multiPart->d_func()->boundary.size());
1778 contentType += "multipart/";
1779 switch (multiPart->d_func()->contentType) {
1780 case QHttpMultiPart::RelatedType:
1781 contentType += "related";
1782 break;
1783 case QHttpMultiPart::FormDataType:
1784 contentType += "form-data";
1785 break;
1786 case QHttpMultiPart::AlternativeType:
1787 contentType += "alternative";
1788 break;
1789 default:
1790 contentType += "mixed";
1791 break;
1792 }
1793 // putting the boundary into quotes, recommended in RFC 2046 section 5.1.1
1794 contentType += "; boundary=\"" + multiPart->d_func()->boundary + '"';
1795 h.append(QHttpHeaders::WellKnownHeader::ContentType, contentType);
1796 }
1797
1798 // add MIME-Version header if not there already (we must include the header
1799 // if the message conforms to RFC 2045, see section 4 of that RFC)
1800 if (!h.contains(QHttpHeaders::WellKnownHeader::MIMEVersion))
1801 h.append(QHttpHeaders::WellKnownHeader::MIMEVersion, "1.0"_ba);
1802
1803 newRequest.setHeaders(std::move(h));
1804
1805 QIODevice *device = multiPart->d_func()->device;
1806 if (!device->isReadable()) {
1807 if (!device->isOpen()) {
1808 if (!device->open(QIODevice::ReadOnly))
1809 qWarning("could not open device for reading");
1810 } else {
1811 qWarning("device is not readable");
1812 }
1813 }
1814
1815 return newRequest;
1816}
1817#endif // QT_CONFIG(http)
1818
1819/*!
1820 \internal
1821 Go through the instances so the factories will be created and
1822 register themselves to QNetworkAccessBackendFactoryData
1823*/
1824void QNetworkAccessManagerPrivate::ensureBackendPluginsLoaded()
1825{
1826 Q_CONSTINIT static QBasicMutex mutex;
1827 std::unique_lock locker(mutex);
1828 if (!qnabfLoader())
1829 return;
1830#if QT_CONFIG(library)
1831 qnabfLoader->update();
1832#endif
1833 int index = 0;
1834 while (qnabfLoader->instance(index))
1835 ++index;
1836}
1837
1838QT_END_NAMESPACE
1839
1840#include "moc_qnetworkaccessmanager.cpp"
Combined button and popup list for selecting options.
#define QNetworkAccessBackendFactory_iid