source: trunk/src/network/access/qnetworkaccessmanager.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 50.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtNetwork module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qnetworkaccessmanager.h"
43#include "qnetworkaccessmanager_p.h"
44#include "qnetworkrequest.h"
45#include "qnetworkreply.h"
46#include "qnetworkreply_p.h"
47#include "qnetworkcookie.h"
48#include "qabstractnetworkcache.h"
49
50#include "QtNetwork/qnetworksession.h"
51#include "QtNetwork/private/qsharednetworksession_p.h"
52
53#include "qnetworkaccesshttpbackend_p.h"
54#include "qnetworkaccessftpbackend_p.h"
55#include "qnetworkaccessfilebackend_p.h"
56#include "qnetworkaccessdatabackend_p.h"
57#include "qnetworkaccessdebugpipebackend_p.h"
58#include "qnetworkaccesscachebackend_p.h"
59#include "qfilenetworkreply_p.h"
60
61#include "QtCore/qbuffer.h"
62#include "QtCore/qurl.h"
63#include "QtCore/qvector.h"
64#include "QtNetwork/qauthenticator.h"
65#include "QtNetwork/qsslconfiguration.h"
66#include "QtNetwork/qnetworkconfigmanager.h"
67
68QT_BEGIN_NAMESPACE
69
70#ifndef QT_NO_HTTP
71Q_GLOBAL_STATIC(QNetworkAccessHttpBackendFactory, httpBackend)
72#endif // QT_NO_HTTP
73Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
74Q_GLOBAL_STATIC(QNetworkAccessDataBackendFactory, dataBackend)
75#ifndef QT_NO_FTP
76Q_GLOBAL_STATIC(QNetworkAccessFtpBackendFactory, ftpBackend)
77#endif // QT_NO_FTP
78
79#ifdef QT_BUILD_INTERNAL
80Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend)
81#endif
82
83static void ensureInitialized()
84{
85#ifndef QT_NO_HTTP
86 (void) httpBackend();
87#endif // QT_NO_HTTP
88 (void) dataBackend();
89#ifndef QT_NO_FTP
90 (void) ftpBackend();
91#endif
92
93#ifdef QT_BUILD_INTERNAL
94 (void) debugpipeBackend();
95#endif
96
97 // leave this one last since it will query the special QAbstractFileEngines
98 (void) fileBackend();
99}
100
101/*!
102 \class QNetworkAccessManager
103 \brief The QNetworkAccessManager class allows the application to
104 send network requests and receive replies
105 \since 4.4
106
107 \ingroup network
108 \inmodule QtNetwork
109 \reentrant
110
111 The Network Access API is constructed around one QNetworkAccessManager
112 object, which holds the common configuration and settings for the requests
113 it sends. It contains the proxy and cache configuration, as well as the
114 signals related to such issues, and reply signals that can be used to
115 monitor the progress of a network operation. One QNetworkAccessManager
116 should be enough for the whole Qt application.
117
118 Once a QNetworkAccessManager object has been created, the application can
119 use it to send requests over the network. A group of standard functions
120 are supplied that take a request and optional data, and each return a
121 QNetworkReply object. The returned object is used to obtain any data
122 returned in response to the corresponding request.
123
124 A simple download off the network could be accomplished with:
125 \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 0
126
127 QNetworkAccessManager has an asynchronous API.
128 When the \tt replyFinished slot above is called, the parameter it
129 takes is the QNetworkReply object containing the downloaded data
130 as well as meta-data (headers, etc.).
131
132 \note After the request has finished, it is the responsibility of the user
133 to delete the QNetworkReply object at an appropriate time. Do not directly
134 delete it inside the slot connected to finished(). You can use the
135 deleteLater() function.
136
137 \note QNetworkAccessManager queues the requests it receives. The number
138 of requests executed in parallel is dependent on the protocol.
139 Currently, for the HTTP protocol on desktop platforms, 6 requests are
140 executed in parallel for one host/port combination.
141
142 A more involved example, assuming the manager is already existent,
143 can be:
144 \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 1
145
146 \section1 Network and Roaming support
147
148 With the addition of the \l {Bearer Management} API to Qt 4.7
149 QNetworkAccessManager gained the ability to manage network connections.
150 QNetworkAccessManager can start the network interface if the device is
151 offline and terminates the interface if the current process is the last
152 one to use the uplink. Note that some platform utilize grace periods from
153 when the last application stops using a uplink until the system actually
154 terminates the connectivity link. Roaming is equally transparent. Any
155 queued/pending network requests are automatically transferred to new
156 access point.
157
158 Clients wanting to utilize this feature should not require any changes. In fact
159 it is likely that existing platform specific connection code can simply be
160 removed from the application.
161
162 \note The network and roaming support in QNetworkAccessManager is conditional
163 upon the platform supporting connection management. The
164 \l QNetworkConfigurationManager::NetworkSessionRequired can be used to
165 detect whether QNetworkAccessManager utilizes this feature. Currently only
166 Meego/Harmattan and Symbian platforms provide connection management support.
167
168 \note This feature cannot be used in combination with the Bearer Management
169 API as provided by QtMobility. Applications have to migrate to the Qt version
170 of Bearer Management.
171
172 \section1 Symbian Platform Security Requirements
173
174 On Symbian, processes which use this class must have the
175 \c NetworkServices platform security capability. If the client
176 process lacks this capability, operations will result in a panic.
177
178 Platform security capabilities are added via the
179 \l{qmake-variable-reference.html#target-capability}{TARGET.CAPABILITY}
180 qmake variable.
181
182 \sa QNetworkRequest, QNetworkReply, QNetworkProxy
183*/
184
185/*!
186 \enum QNetworkAccessManager::Operation
187
188 Indicates the operation this reply is processing.
189
190 \value HeadOperation retrieve headers operation (created
191 with head())
192
193 \value GetOperation retrieve headers and download contents
194 (created with get())
195
196 \value PutOperation upload contents operation (created
197 with put())
198
199 \value PostOperation send the contents of an HTML form for
200 processing via HTTP POST (created with post())
201
202 \value DeleteOperation delete contents operation (created with
203 deleteResource())
204
205 \value CustomOperation custom operation (created with
206 sendCustomRequest()) \since 4.7
207
208 \omitvalue UnknownOperation
209
210 \sa QNetworkReply::operation()
211*/
212
213/*!
214 \enum QNetworkAccessManager::NetworkAccessibility
215
216 Indicates whether the network is accessible via this network access manager.
217
218 \value UnknownAccessibility The network accessibility cannot be determined.
219 \value NotAccessible The network is not currently accessible, either because there
220 is currently no network coverage or network access has been
221 explicitly disabled by a call to setNetworkAccessible().
222 \value Accessible The network is accessible.
223
224 \sa networkAccessible
225*/
226
227/*!
228 \property QNetworkAccessManager::networkAccessible
229 \brief whether the network is currently accessible via this network access manager.
230
231 \since 4.7
232
233 If the network is \l {NotAccessible}{not accessible} the network access manager will not
234 process any new network requests, all such requests will fail with an error. Requests with
235 URLs with the file:// scheme will still be processed.
236
237 By default the value of this property reflects the physical state of the device. Applications
238 may override it to disable all network requests via this network access manager by calling
239
240 \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 4
241
242 Network requests can be reenabled again by calling
243
244 \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 5
245
246 \note Calling setNetworkAccessible() does not change the network state.
247*/
248
249/*!
250 \fn void QNetworkAccessManager::networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible)
251
252 This signal is emitted when the value of the \l networkAccessible property changes.
253 \a accessible is the new network accessibility.
254*/
255
256/*!
257 \fn void QNetworkAccessManager::networkSessionConnected()
258
259 \since 4.7
260
261 \internal
262
263 This signal is emitted when the status of the network session changes into a usable (Connected)
264 state. It is used to signal to QNetworkReplys to start or migrate their network operation once
265 the network session has been opened or finished roaming.
266*/
267
268/*!
269 \fn void QNetworkAccessManager::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)
270
271 This signal is emitted whenever a proxy requests authentication
272 and QNetworkAccessManager cannot find a valid, cached
273 credential. The slot connected to this signal should fill in the
274 credentials for the proxy \a proxy in the \a authenticator object.
275
276 QNetworkAccessManager will cache the credentials internally. The
277 next time the proxy requests authentication, QNetworkAccessManager
278 will automatically send the same credential without emitting the
279 proxyAuthenticationRequired signal again.
280
281 If the proxy rejects the credentials, QNetworkAccessManager will
282 emit the signal again.
283
284 \sa proxy(), setProxy(), authenticationRequired()
285*/
286
287/*!
288 \fn void QNetworkAccessManager::authenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator)
289
290 This signal is emitted whenever a final server requests
291 authentication before it delivers the requested contents. The slot
292 connected to this signal should fill the credentials for the
293 contents (which can be determined by inspecting the \a reply
294 object) in the \a authenticator object.
295
296 QNetworkAccessManager will cache the credentials internally and
297 will send the same values if the server requires authentication
298 again, without emitting the authenticationRequired() signal. If it
299 rejects the credentials, this signal will be emitted again.
300
301 \sa proxyAuthenticationRequired()
302*/
303
304/*!
305 \fn void QNetworkAccessManager::finished(QNetworkReply *reply)
306
307 This signal is emitted whenever a pending network reply is
308 finished. The \a reply parameter will contain a pointer to the
309 reply that has just finished. This signal is emitted in tandem
310 with the QNetworkReply::finished() signal.
311
312 See QNetworkReply::finished() for information on the status that
313 the object will be in.
314
315 \note Do not delete the \a reply object in the slot connected to this
316 signal. Use deleteLater().
317
318 \sa QNetworkReply::finished(), QNetworkReply::error()
319*/
320
321/*!
322 \fn void QNetworkAccessManager::sslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
323
324 This signal is emitted if the SSL/TLS session encountered errors
325 during the set up, including certificate verification errors. The
326 \a errors parameter contains the list of errors and \a reply is
327 the QNetworkReply that is encountering these errors.
328
329 To indicate that the errors are not fatal and that the connection
330 should proceed, the QNetworkReply::ignoreSslErrors() function should be called
331 from the slot connected to this signal. If it is not called, the
332 SSL session will be torn down before any data is exchanged
333 (including the URL).
334
335 This signal can be used to display an error message to the user
336 indicating that security may be compromised and display the
337 SSL settings (see sslConfiguration() to obtain it). If the user
338 decides to proceed after analyzing the remote certificate, the
339 slot should call ignoreSslErrors().
340
341 \sa QSslSocket::sslErrors(), QNetworkReply::sslErrors(),
342 QNetworkReply::sslConfiguration(), QNetworkReply::ignoreSslErrors()
343*/
344
345class QNetworkAuthenticationCredential
346{
347public:
348 QString domain;
349 QString user;
350 QString password;
351};
352Q_DECLARE_TYPEINFO(QNetworkAuthenticationCredential, Q_MOVABLE_TYPE);
353inline bool operator<(const QNetworkAuthenticationCredential &t1, const QString &t2)
354{ return t1.domain < t2; }
355
356class QNetworkAuthenticationCache: private QVector<QNetworkAuthenticationCredential>,
357 public QNetworkAccessCache::CacheableObject
358{
359public:
360 QNetworkAuthenticationCache()
361 {
362 setExpires(false);
363 setShareable(true);
364 reserve(1);
365 }
366
367 QNetworkAuthenticationCredential *findClosestMatch(const QString &domain)
368 {
369 iterator it = qLowerBound(begin(), end(), domain);
370 if (it == end() && !isEmpty())
371 --it;
372 if (it == end() || !domain.startsWith(it->domain))
373 return 0;
374 return &*it;
375 }
376
377 void insert(const QString &domain, const QString &user, const QString &password)
378 {
379 QNetworkAuthenticationCredential *closestMatch = findClosestMatch(domain);
380 if (closestMatch && closestMatch->domain == domain) {
381 // we're overriding the current credentials
382 closestMatch->user = user;
383 closestMatch->password = password;
384 } else {
385 QNetworkAuthenticationCredential newCredential;
386 newCredential.domain = domain;
387 newCredential.user = user;
388 newCredential.password = password;
389
390 if (closestMatch)
391 QVector<QNetworkAuthenticationCredential>::insert(++closestMatch, newCredential);
392 else
393 QVector<QNetworkAuthenticationCredential>::insert(end(), newCredential);
394 }
395 }
396
397 virtual void dispose() { delete this; }
398};
399
400#ifndef QT_NO_NETWORKPROXY
401static QByteArray proxyAuthenticationKey(const QNetworkProxy &proxy, const QString &realm)
402{
403 QUrl key;
404
405 switch (proxy.type()) {
406 case QNetworkProxy::Socks5Proxy:
407 key.setScheme(QLatin1String("proxy-socks5"));
408 break;
409
410 case QNetworkProxy::HttpProxy:
411 case QNetworkProxy::HttpCachingProxy:
412 key.setScheme(QLatin1String("proxy-http"));
413 break;
414
415 case QNetworkProxy::FtpCachingProxy:
416 key.setScheme(QLatin1String("proxy-ftp"));
417 break;
418
419 case QNetworkProxy::DefaultProxy:
420 case QNetworkProxy::NoProxy:
421 // shouldn't happen
422 return QByteArray();
423
424 // no default:
425 // let there be errors if a new proxy type is added in the future
426 }
427
428 if (key.scheme().isEmpty())
429 // proxy type not handled
430 return QByteArray();
431
432 key.setUserName(proxy.user());
433 key.setHost(proxy.hostName());
434 key.setPort(proxy.port());
435 key.setFragment(realm);
436 return "auth:" + key.toEncoded();
437}
438#endif
439
440static inline QByteArray authenticationKey(const QUrl &url, const QString &realm)
441{
442 QUrl copy = url;
443 copy.setFragment(realm);
444 return "auth:" + copy.toEncoded(QUrl::RemovePassword | QUrl::RemovePath | QUrl::RemoveQuery);
445}
446
447/*!
448 Constructs a QNetworkAccessManager object that is the center of
449 the Network Access API and sets \a parent as the parent object.
450*/
451QNetworkAccessManager::QNetworkAccessManager(QObject *parent)
452 : QObject(*new QNetworkAccessManagerPrivate, parent)
453{
454 ensureInitialized();
455}
456
457/*!
458 Destroys the QNetworkAccessManager object and frees up any
459 resources. Note that QNetworkReply objects that are returned from
460 this class have this object set as their parents, which means that
461 they will be deleted along with it if you don't call
462 QObject::setParent() on them.
463*/
464QNetworkAccessManager::~QNetworkAccessManager()
465{
466#ifndef QT_NO_NETWORKPROXY
467 delete d_func()->proxyFactory;
468#endif
469
470 // Delete the QNetworkReply children first.
471 // Else a QAbstractNetworkCache might get deleted in ~QObject
472 // before a QNetworkReply that accesses the QAbstractNetworkCache
473 // object in its destructor.
474 qDeleteAll(findChildren<QNetworkReply *>());
475 // The other children will be deleted in this ~QObject
476 // FIXME instead of this "hack" make the QNetworkReplyImpl
477 // properly watch the cache deletion, e.g. via a QWeakPointer.
478}
479
480#ifndef QT_NO_NETWORKPROXY
481/*!
482 Returns the QNetworkProxy that the requests sent using this
483 QNetworkAccessManager object will use. The default value for the
484 proxy is QNetworkProxy::DefaultProxy.
485
486 \sa setProxy(), setProxyFactory(), proxyAuthenticationRequired()
487*/
488QNetworkProxy QNetworkAccessManager::proxy() const
489{
490 return d_func()->proxy;
491}
492
493/*!
494 Sets the proxy to be used in future requests to be \a proxy. This
495 does not affect requests that have already been sent. The
496 proxyAuthenticationRequired() signal will be emitted if the proxy
497 requests authentication.
498
499 A proxy set with this function will be used for all requests
500 issued by QNetworkAccessManager. In some cases, it might be
501 necessary to select different proxies depending on the type of
502 request being sent or the destination host. If that's the case,
503 you should consider using setProxyFactory().
504
505 \sa proxy(), proxyAuthenticationRequired()
506*/
507void QNetworkAccessManager::setProxy(const QNetworkProxy &proxy)
508{
509 Q_D(QNetworkAccessManager);
510 delete d->proxyFactory;
511 d->proxy = proxy;
512 d->proxyFactory = 0;
513}
514
515/*!
516 \fn QNetworkProxyFactory *QNetworkAccessManager::proxyFactory() const
517 \since 4.5
518
519 Returns the proxy factory that this QNetworkAccessManager object
520 is using to determine the proxies to be used for requests.
521
522 Note that the pointer returned by this function is managed by
523 QNetworkAccessManager and could be deleted at any time.
524
525 \sa setProxyFactory(), proxy()
526*/
527QNetworkProxyFactory *QNetworkAccessManager::proxyFactory() const
528{
529 return d_func()->proxyFactory;
530}
531
532/*!
533 \since 4.5
534
535 Sets the proxy factory for this class to be \a factory. A proxy
536 factory is used to determine a more specific list of proxies to be
537 used for a given request, instead of trying to use the same proxy
538 value for all requests.
539
540 All queries sent by QNetworkAccessManager will have type
541 QNetworkProxyQuery::UrlRequest.
542
543 For example, a proxy factory could apply the following rules:
544 \list
545 \o if the target address is in the local network (for example,
546 if the hostname contains no dots or if it's an IP address in
547 the organization's range), return QNetworkProxy::NoProxy
548 \o if the request is FTP, return an FTP proxy
549 \o if the request is HTTP or HTTPS, then return an HTTP proxy
550 \o otherwise, return a SOCKSv5 proxy server
551 \endlist
552
553 The lifetime of the object \a factory will be managed by
554 QNetworkAccessManager. It will delete the object when necessary.
555
556 \note If a specific proxy is set with setProxy(), the factory will not
557 be used.
558
559 \sa proxyFactory(), setProxy(), QNetworkProxyQuery
560*/
561void QNetworkAccessManager::setProxyFactory(QNetworkProxyFactory *factory)
562{
563 Q_D(QNetworkAccessManager);
564 delete d->proxyFactory;
565 d->proxyFactory = factory;
566 d->proxy = QNetworkProxy();
567}
568#endif
569
570/*!
571 \since 4.5
572
573 Returns the cache that is used to store data obtained from the network.
574
575 \sa setCache()
576*/
577QAbstractNetworkCache *QNetworkAccessManager::cache() const
578{
579 Q_D(const QNetworkAccessManager);
580 return d->networkCache;
581}
582
583/*!
584 \since 4.5
585
586 Sets the manager's network cache to be the \a cache specified. The cache
587 is used for all requests dispatched by the manager.
588
589 Use this function to set the network cache object to a class that implements
590 additional features, like saving the cookies to permanent storage.
591
592 \note QNetworkAccessManager takes ownership of the \a cache object.
593
594 QNetworkAccessManager by default does not have a set cache.
595 Qt provides a simple disk cache, QNetworkDiskCache, which can be used.
596
597 \sa cache(), QNetworkRequest::CacheLoadControl
598*/
599void QNetworkAccessManager::setCache(QAbstractNetworkCache *cache)
600{
601 Q_D(QNetworkAccessManager);
602 if (d->networkCache != cache) {
603 delete d->networkCache;
604 d->networkCache = cache;
605 if (d->networkCache)
606 d->networkCache->setParent(this);
607 }
608}
609
610/*!
611 Returns the QNetworkCookieJar that is used to store cookies
612 obtained from the network as well as cookies that are about to be
613 sent.
614
615 \sa setCookieJar()
616*/
617QNetworkCookieJar *QNetworkAccessManager::cookieJar() const
618{
619 Q_D(const QNetworkAccessManager);
620 if (!d->cookieJar)
621 d->createCookieJar();
622 return d->cookieJar;
623}
624
625/*!
626 Sets the manager's cookie jar to be the \a cookieJar specified.
627 The cookie jar is used by all requests dispatched by the manager.
628
629 Use this function to set the cookie jar object to a class that
630 implements additional features, like saving the cookies to permanent
631 storage.
632
633 \note QNetworkAccessManager takes ownership of the \a cookieJar object.
634
635 If \a cookieJar is in the same thread as this QNetworkAccessManager,
636 it will set the parent of the \a cookieJar
637 so that the cookie jar is deleted when this
638 object is deleted as well. If you want to share cookie jars
639 between different QNetworkAccessManager objects, you may want to
640 set the cookie jar's parent to 0 after calling this function.
641
642 QNetworkAccessManager by default does not implement any cookie
643 policy of its own: it accepts all cookies sent by the server, as
644 long as they are well formed and meet the minimum security
645 requirements (cookie domain matches the request's and cookie path
646 matches the request's). In order to implement your own security
647 policy, override the QNetworkCookieJar::cookiesForUrl() and
648 QNetworkCookieJar::setCookiesFromUrl() virtual functions. Those
649 functions are called by QNetworkAccessManager when it detects a
650 new cookie.
651
652 \sa cookieJar(), QNetworkCookieJar::cookiesForUrl(), QNetworkCookieJar::setCookiesFromUrl()
653*/
654void QNetworkAccessManager::setCookieJar(QNetworkCookieJar *cookieJar)
655{
656 Q_D(QNetworkAccessManager);
657 d->cookieJarCreated = true;
658 if (d->cookieJar != cookieJar) {
659 if (d->cookieJar && d->cookieJar->parent() == this)
660 delete d->cookieJar;
661 d->cookieJar = cookieJar;
662 if (thread() == cookieJar->thread())
663 d->cookieJar->setParent(this);
664 }
665}
666
667/*!
668 Posts a request to obtain the network headers for \a request
669 and returns a new QNetworkReply object which will contain such headers.
670
671 The function is named after the HTTP request associated (HEAD).
672*/
673QNetworkReply *QNetworkAccessManager::head(const QNetworkRequest &request)
674{
675 return d_func()->postProcess(createRequest(QNetworkAccessManager::HeadOperation, request));
676}
677
678/*!
679 Posts a request to obtain the contents of the target \a request
680 and returns a new QNetworkReply object opened for reading which emits the
681 \l{QIODevice::readyRead()}{readyRead()} signal whenever new data
682 arrives.
683
684 The contents as well as associated headers will be downloaded.
685
686 \sa post(), put(), deleteResource(), sendCustomRequest()
687*/
688QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
689{
690 return d_func()->postProcess(createRequest(QNetworkAccessManager::GetOperation, request));
691}
692
693/*!
694 Sends an HTTP POST request to the destination specified by \a request
695 and returns a new QNetworkReply object opened for reading that will
696 contain the reply sent by the server. The contents of the \a data
697 device will be uploaded to the server.
698
699 \a data must be open for reading and must remain valid until the
700 finished() signal is emitted for this reply.
701
702 \note Sending a POST request on protocols other than HTTP and
703 HTTPS is undefined and will probably fail.
704
705 \sa get(), put(), deleteResource(), sendCustomRequest()
706*/
707QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QIODevice *data)
708{
709 return d_func()->postProcess(createRequest(QNetworkAccessManager::PostOperation, request, data));
710}
711
712/*!
713 \overload
714
715 Sends the contents of the \a data byte array to the destination
716 specified by \a request.
717*/
718QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, const QByteArray &data)
719{
720 QBuffer *buffer = new QBuffer;
721 buffer->setData(data);
722 buffer->open(QIODevice::ReadOnly);
723
724 QNetworkReply *reply = post(request, buffer);
725 buffer->setParent(reply);
726 return reply;
727}
728
729/*!
730 Uploads the contents of \a data to the destination \a request and
731 returnes a new QNetworkReply object that will be open for reply.
732
733 \a data must be opened for reading when this function is called
734 and must remain valid until the finished() signal is emitted for
735 this reply.
736
737 Whether anything will be available for reading from the returned
738 object is protocol dependent. For HTTP, the server may send a
739 small HTML page indicating the upload was successful (or not).
740 Other protocols will probably have content in their replies.
741
742 \note For HTTP, this request will send a PUT request, which most servers
743 do not allow. Form upload mechanisms, including that of uploading
744 files through HTML forms, use the POST mechanism.
745
746 \sa get(), post(), deleteResource(), sendCustomRequest()
747*/
748QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, QIODevice *data)
749{
750 return d_func()->postProcess(createRequest(QNetworkAccessManager::PutOperation, request, data));
751}
752
753/*!
754 \overload
755 Sends the contents of the \a data byte array to the destination
756 specified by \a request.
757*/
758QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, const QByteArray &data)
759{
760 QBuffer *buffer = new QBuffer;
761 buffer->setData(data);
762 buffer->open(QIODevice::ReadOnly);
763
764 QNetworkReply *reply = put(request, buffer);
765 buffer->setParent(reply);
766 return reply;
767}
768
769/*!
770 \since 4.6
771
772 Sends a request to delete the resource identified by the URL of \a request.
773
774 \note This feature is currently available for HTTP only, performing an
775 HTTP DELETE request.
776
777 \sa get(), post(), put(), sendCustomRequest()
778*/
779QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &request)
780{
781 return d_func()->postProcess(createRequest(QNetworkAccessManager::DeleteOperation, request));
782}
783
784#ifndef QT_NO_BEARERMANAGEMENT
785
786/*!
787 \since 4.7
788
789 Sets the network configuration that will be used when creating the
790 \l {QNetworkSession}{network session} to \a config.
791
792 The network configuration is used to create and open a network session before any request that
793 requires network access is process. If no network configuration is explicitly set via this
794 function the network configuration returned by
795 QNetworkConfigurationManager::defaultConfiguration() will be used.
796
797 To restore the default network configuration set the network configuration to the value
798 returned from QNetworkConfigurationManager::defaultConfiguration().
799
800 \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 2
801
802 If an invalid network configuration is set, a network session will not be created. In this
803 case network requests will be processed regardless, but may fail. For example:
804
805 \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 3
806
807 \sa configuration(), QNetworkSession
808*/
809void QNetworkAccessManager::setConfiguration(const QNetworkConfiguration &config)
810{
811 d_func()->createSession(config);
812}
813
814/*!
815 \since 4.7
816
817 Returns the network configuration that will be used to create the
818 \l {QNetworkSession}{network session} which will be used when processing network requests.
819
820 \sa setConfiguration(), activeConfiguration()
821*/
822QNetworkConfiguration QNetworkAccessManager::configuration() const
823{
824 Q_D(const QNetworkAccessManager);
825
826 if (d->networkSession)
827 return d->networkSession->configuration();
828 else
829 return QNetworkConfiguration();
830}
831
832/*!
833 \since 4.7
834
835 Returns the current active network configuration.
836
837 If the network configuration returned by configuration() is of type
838 QNetworkConfiguration::ServiceNetwork this function will return the current active child
839 network configuration of that configuration. Otherwise returns the same network configuration
840 as configuration().
841
842 Use this function to return the actual network configuration currently in use by the network
843 session.
844
845 \sa configuration()
846*/
847QNetworkConfiguration QNetworkAccessManager::activeConfiguration() const
848{
849 Q_D(const QNetworkAccessManager);
850
851 if (d->networkSession) {
852 QNetworkConfigurationManager manager;
853
854 return manager.configurationFromIdentifier(
855 d->networkSession->sessionProperty(QLatin1String("ActiveConfiguration")).toString());
856 } else {
857 return QNetworkConfiguration();
858 }
859}
860
861/*!
862 \since 4.7
863
864 Overrides the reported network accessibility. If \a accessible is NotAccessible the reported
865 network accessiblity will always be NotAccessible. Otherwise the reported network
866 accessibility will reflect the actual device state.
867*/
868void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkAccessibility accessible)
869{
870 Q_D(QNetworkAccessManager);
871
872 if (d->networkAccessible != accessible) {
873 NetworkAccessibility previous = networkAccessible();
874 d->networkAccessible = accessible;
875 NetworkAccessibility current = networkAccessible();
876 if (previous != current)
877 emit networkAccessibleChanged(current);
878 }
879}
880
881/*!
882 \since 4.7
883
884 Returns the current network accessibility.
885*/
886QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccessible() const
887{
888 Q_D(const QNetworkAccessManager);
889
890 if (d->networkSession) {
891 // d->online holds online/offline state of this network session.
892 if (d->online)
893 return d->networkAccessible;
894 else
895 return NotAccessible;
896 } else {
897 // Network accessibility is either disabled or unknown.
898 return (d->networkAccessible == NotAccessible) ? NotAccessible : UnknownAccessibility;
899 }
900}
901
902#endif // QT_NO_BEARERMANAGEMENT
903
904/*!
905 \since 4.7
906
907 Sends a custom request to the server identified by the URL of \a request.
908
909 It is the user's responsibility to send a \a verb to the server that is valid
910 according to the HTTP specification.
911
912 This method provides means to send verbs other than the common ones provided
913 via get() or post() etc., for instance sending an HTTP OPTIONS command.
914
915 If \a data is not empty, the contents of the \a data
916 device will be uploaded to the server; in that case, data must be open for
917 reading and must remain valid until the finished() signal is emitted for this reply.
918
919 \note This feature is currently available for HTTP only.
920
921 \sa get(), post(), put(), deleteResource()
922*/
923QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data)
924{
925 QNetworkRequest newRequest(request);
926 newRequest.setAttribute(QNetworkRequest::CustomVerbAttribute, verb);
927 return d_func()->postProcess(createRequest(QNetworkAccessManager::CustomOperation, newRequest, data));
928}
929
930/*!
931 Returns a new QNetworkReply object to handle the operation \a op
932 and request \a req. The device \a outgoingData is always 0 for Get and
933 Head requests, but is the value passed to post() and put() in
934 those operations (the QByteArray variants will pass a QBuffer
935 object).
936
937 The default implementation calls QNetworkCookieJar::cookiesForUrl()
938 on the cookie jar set with setCookieJar() to obtain the cookies to
939 be sent to the remote server.
940
941 The returned object must be in an open state.
942*/
943QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op,
944 const QNetworkRequest &req,
945 QIODevice *outgoingData)
946{
947 Q_D(QNetworkAccessManager);
948
949 // 4.7 only hotfix fast path for data:// URLs
950 // In 4.8 this is solved with QNetworkReplyDataImpl and will work there
951 // This hotfix is done for not needing a QNetworkSession for data://
952 if ((op == QNetworkAccessManager::GetOperation || op == QNetworkAccessManager::HeadOperation)
953 && (req.url().scheme() == QLatin1String("data"))) {
954 QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
955 QNetworkReplyImplPrivate *priv = reply->d_func();
956 priv->manager = this;
957 priv->backend = new QNetworkAccessDataBackend();
958 priv->backend->manager = this->d_func();
959 priv->backend->setParent(reply);
960 priv->backend->reply = priv;
961 priv->setup(op, req, outgoingData);
962 return reply;
963 }
964
965 // fast path for GET on file:// URLs
966 // Also if the scheme is empty we consider it a file.
967 // The QNetworkAccessFileBackend will right now only be used for PUT
968 if ((op == QNetworkAccessManager::GetOperation || op == QNetworkAccessManager::HeadOperation)
969 && (req.url().scheme() == QLatin1String("file")
970 || req.url().scheme() == QLatin1String("qrc")
971 || req.url().scheme().isEmpty())) {
972 return new QFileNetworkReply(this, req, op);
973 }
974
975 // A request with QNetworkRequest::AlwaysCache does not need any bearer management
976 QNetworkRequest::CacheLoadControl mode =
977 static_cast<QNetworkRequest::CacheLoadControl>(
978 req.attribute(QNetworkRequest::CacheLoadControlAttribute,
979 QNetworkRequest::PreferNetwork).toInt());
980 if (mode == QNetworkRequest::AlwaysCache
981 && (op == QNetworkAccessManager::GetOperation
982 || op == QNetworkAccessManager::HeadOperation)) {
983 // FIXME Implement a QNetworkReplyCacheImpl instead, see QTBUG-15106
984 QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
985 QNetworkReplyImplPrivate *priv = reply->d_func();
986 priv->manager = this;
987 priv->backend = new QNetworkAccessCacheBackend();
988 priv->backend->manager = this->d_func();
989 priv->backend->setParent(reply);
990 priv->backend->reply = priv;
991 priv->setup(op, req, outgoingData);
992 return reply;
993 }
994
995#ifndef QT_NO_BEARERMANAGEMENT
996 // Return a disabled network reply if network access is disabled.
997 // Except if the scheme is empty or file://.
998 if (!d->networkAccessible && !(req.url().scheme() == QLatin1String("file") ||
999 req.url().scheme().isEmpty())) {
1000 return new QDisabledNetworkReply(this, req, op);
1001 }
1002
1003 if (!d->networkSession && (d->initializeSession || !d->networkConfiguration.isEmpty())) {
1004 QNetworkConfigurationManager manager;
1005 if (!d->networkConfiguration.isEmpty()) {
1006 d->createSession(manager.configurationFromIdentifier(d->networkConfiguration));
1007 } else {
1008 if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired)
1009 d->createSession(manager.defaultConfiguration());
1010 else
1011 d->initializeSession = false;
1012 }
1013 }
1014
1015 if (d->networkSession)
1016 d->networkSession->setSessionProperty(QLatin1String("AutoCloseSessionTimeout"), -1);
1017#endif
1018
1019 QNetworkRequest request = req;
1020 if (!request.header(QNetworkRequest::ContentLengthHeader).isValid() &&
1021 outgoingData && !outgoingData->isSequential()) {
1022 // request has no Content-Length
1023 // but the data that is outgoing is random-access
1024 request.setHeader(QNetworkRequest::ContentLengthHeader, outgoingData->size());
1025 }
1026
1027 if (static_cast<QNetworkRequest::LoadControl>
1028 (request.attribute(QNetworkRequest::CookieLoadControlAttribute,
1029 QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Automatic) {
1030 if (d->cookieJar) {
1031 QList<QNetworkCookie> cookies = d->cookieJar->cookiesForUrl(request.url());
1032 if (!cookies.isEmpty())
1033 request.setHeader(QNetworkRequest::CookieHeader, qVariantFromValue(cookies));
1034 }
1035 }
1036
1037 // first step: create the reply
1038 QUrl url = request.url();
1039 QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
1040#ifndef QT_NO_BEARERMANAGEMENT
1041 if (req.url().scheme() != QLatin1String("file") && !req.url().scheme().isEmpty()) {
1042 connect(this, SIGNAL(networkSessionConnected()),
1043 reply, SLOT(_q_networkSessionConnected()));
1044 }
1045#endif
1046 QNetworkReplyImplPrivate *priv = reply->d_func();
1047 priv->manager = this;
1048
1049 // second step: fetch cached credentials
1050 // This is not done for the time being, we should use signal emissions to request
1051 // the credentials from cache.
1052
1053 // third step: find a backend
1054 priv->backend = d->findBackend(op, request);
1055
1056#ifndef QT_NO_NETWORKPROXY
1057 QList<QNetworkProxy> proxyList = d->queryProxy(QNetworkProxyQuery(request.url()));
1058 priv->proxyList = proxyList;
1059#endif
1060 if (priv->backend) {
1061 priv->backend->setParent(reply);
1062 priv->backend->reply = priv;
1063 }
1064
1065#ifndef QT_NO_OPENSSL
1066 reply->setSslConfiguration(request.sslConfiguration());
1067#endif
1068
1069 // fourth step: setup the reply
1070 priv->setup(op, request, outgoingData);
1071
1072 return reply;
1073}
1074
1075void QNetworkAccessManagerPrivate::_q_replyFinished()
1076{
1077 Q_Q(QNetworkAccessManager);
1078
1079 QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
1080 if (reply)
1081 emit q->finished(reply);
1082
1083#ifndef QT_NO_BEARERMANAGEMENT
1084 if (networkSession && q->findChildren<QNetworkReply *>().count() == 1)
1085 networkSession->setSessionProperty(QLatin1String("AutoCloseSessionTimeout"), 120000);
1086#endif
1087}
1088
1089void QNetworkAccessManagerPrivate::_q_replySslErrors(const QList<QSslError> &errors)
1090{
1091#ifndef QT_NO_OPENSSL
1092 Q_Q(QNetworkAccessManager);
1093 QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
1094 if (reply)
1095 emit q->sslErrors(reply, errors);
1096#else
1097 Q_UNUSED(errors);
1098#endif
1099}
1100
1101QNetworkReply *QNetworkAccessManagerPrivate::postProcess(QNetworkReply *reply)
1102{
1103 Q_Q(QNetworkAccessManager);
1104 QNetworkReplyPrivate::setManager(reply, q);
1105 q->connect(reply, SIGNAL(finished()), SLOT(_q_replyFinished()));
1106#ifndef QT_NO_OPENSSL
1107 /* In case we're compiled without SSL support, we don't have this signal and we need to
1108 * avoid getting a connection error. */
1109 q->connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SLOT(_q_replySslErrors(QList<QSslError>)));
1110#endif
1111
1112 return reply;
1113}
1114
1115void QNetworkAccessManagerPrivate::createCookieJar() const
1116{
1117 if (!cookieJarCreated) {
1118 // keep the ugly hack in here
1119 QNetworkAccessManagerPrivate *that = const_cast<QNetworkAccessManagerPrivate *>(this);
1120 that->cookieJar = new QNetworkCookieJar(that->q_func());
1121 that->cookieJarCreated = true;
1122 }
1123}
1124
1125void QNetworkAccessManagerPrivate::authenticationRequired(QNetworkAccessBackend *backend,
1126 QAuthenticator *authenticator)
1127{
1128 Q_Q(QNetworkAccessManager);
1129
1130 // FIXME: Add support for domains (i.e., the leading path)
1131 QUrl url = backend->reply->url;
1132
1133 // don't try the cache for the same URL twice in a row
1134 // being called twice for the same URL means the authentication failed
1135 // also called when last URL is empty, e.g. on first call
1136 if (backend->reply->urlForLastAuthentication.isEmpty()
1137 || url != backend->reply->urlForLastAuthentication) {
1138 QNetworkAuthenticationCredential *cred = fetchCachedCredentials(url, authenticator);
1139 if (cred) {
1140 authenticator->setUser(cred->user);
1141 authenticator->setPassword(cred->password);
1142 backend->reply->urlForLastAuthentication = url;
1143 return;
1144 }
1145 }
1146
1147 // if we emit a signal here in synchronous mode, the user might spin
1148 // an event loop, which might recurse and lead to problems
1149 if (backend->isSynchronous())
1150 return;
1151
1152 backend->reply->urlForLastAuthentication = url;
1153 emit q->authenticationRequired(backend->reply->q_func(), authenticator);
1154 cacheCredentials(url, authenticator);
1155}
1156
1157#ifndef QT_NO_NETWORKPROXY
1158void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(QNetworkAccessBackend *backend,
1159 const QNetworkProxy &proxy,
1160 QAuthenticator *authenticator)
1161{
1162 Q_Q(QNetworkAccessManager);
1163 // ### FIXME Tracking of successful authentications
1164 // This code is a bit broken right now for SOCKS authentication
1165 // first request: proxyAuthenticationRequired gets emitted, credentials gets saved
1166 // second request: (proxy != backend->reply->lastProxyAuthentication) does not evaluate to true,
1167 // proxyAuthenticationRequired gets emitted again
1168 // possible solution: some tracking inside the authenticator
1169 // or a new function proxyAuthenticationSucceeded(true|false)
1170 if (proxy != backend->reply->lastProxyAuthentication) {
1171 QNetworkAuthenticationCredential *cred = fetchCachedProxyCredentials(proxy);
1172 if (cred) {
1173 authenticator->setUser(cred->user);
1174 authenticator->setPassword(cred->password);
1175 return;
1176 }
1177 }
1178
1179 // if we emit a signal here in synchronous mode, the user might spin
1180 // an event loop, which might recurse and lead to problems
1181 if (backend->isSynchronous())
1182 return;
1183
1184 backend->reply->lastProxyAuthentication = proxy;
1185 emit q->proxyAuthenticationRequired(proxy, authenticator);
1186 cacheProxyCredentials(proxy, authenticator);
1187}
1188
1189void QNetworkAccessManagerPrivate::cacheProxyCredentials(const QNetworkProxy &p,
1190 const QAuthenticator *authenticator)
1191{
1192 Q_ASSERT(authenticator);
1193 Q_ASSERT(p.type() != QNetworkProxy::DefaultProxy);
1194 Q_ASSERT(p.type() != QNetworkProxy::NoProxy);
1195
1196 QString realm = authenticator->realm();
1197 QNetworkProxy proxy = p;
1198 proxy.setUser(authenticator->user());
1199 // Set two credentials: one with the username and one without
1200 do {
1201 // Set two credentials actually: one with and one without the realm
1202 do {
1203 QByteArray cacheKey = proxyAuthenticationKey(proxy, realm);
1204 if (cacheKey.isEmpty())
1205 return; // should not happen
1206
1207 QNetworkAuthenticationCache *auth = new QNetworkAuthenticationCache;
1208 auth->insert(QString(), authenticator->user(), authenticator->password());
1209 objectCache.addEntry(cacheKey, auth); // replace the existing one, if there's any
1210
1211 if (realm.isEmpty()) {
1212 break;
1213 } else {
1214 realm.clear();
1215 }
1216 } while (true);
1217
1218 if (proxy.user().isEmpty())
1219 break;
1220 else
1221 proxy.setUser(QString());
1222 } while (true);
1223}
1224
1225QNetworkAuthenticationCredential *
1226QNetworkAccessManagerPrivate::fetchCachedProxyCredentials(const QNetworkProxy &p,
1227 const QAuthenticator *authenticator)
1228{
1229 QNetworkProxy proxy = p;
1230 if (proxy.type() == QNetworkProxy::DefaultProxy) {
1231 proxy = QNetworkProxy::applicationProxy();
1232 }
1233 if (!proxy.password().isEmpty())
1234 return 0; // no need to set credentials if it already has them
1235
1236 QString realm;
1237 if (authenticator)
1238 realm = authenticator->realm();
1239
1240 QByteArray cacheKey = proxyAuthenticationKey(proxy, realm);
1241 if (cacheKey.isEmpty())
1242 return 0;
1243 if (!objectCache.hasEntry(cacheKey))
1244 return 0;
1245
1246 QNetworkAuthenticationCache *auth =
1247 static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey));
1248 QNetworkAuthenticationCredential *cred = auth->findClosestMatch(QString());
1249 objectCache.releaseEntry(cacheKey);
1250
1251 // proxy cache credentials always have exactly one item
1252 Q_ASSERT_X(cred, "QNetworkAccessManager",
1253 "Internal inconsistency: found a cache key for a proxy, but it's empty");
1254 return cred;
1255}
1256
1257QList<QNetworkProxy> QNetworkAccessManagerPrivate::queryProxy(const QNetworkProxyQuery &query)
1258{
1259 QList<QNetworkProxy> proxies;
1260 if (proxyFactory) {
1261 proxies = proxyFactory->queryProxy(query);
1262 if (proxies.isEmpty()) {
1263 qWarning("QNetworkAccessManager: factory %p has returned an empty result set",
1264 proxyFactory);
1265 proxies << QNetworkProxy::NoProxy;
1266 }
1267 } else if (proxy.type() == QNetworkProxy::DefaultProxy) {
1268 // no proxy set, query the application
1269 return QNetworkProxyFactory::proxyForQuery(query);
1270 } else {
1271 proxies << proxy;
1272 }
1273
1274 return proxies;
1275}
1276#endif
1277
1278void QNetworkAccessManagerPrivate::cacheCredentials(const QUrl &url,
1279 const QAuthenticator *authenticator)
1280{
1281 Q_ASSERT(authenticator);
1282 QString domain = QString::fromLatin1("/"); // FIXME: make QAuthenticator return the domain
1283 QString realm = authenticator->realm();
1284
1285 // Set two credentials actually: one with and one without the username in the URL
1286 QUrl copy = url;
1287 copy.setUserName(authenticator->user());
1288 do {
1289 QByteArray cacheKey = authenticationKey(copy, realm);
1290 if (objectCache.hasEntry(cacheKey)) {
1291 QNetworkAuthenticationCache *auth =
1292 static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey));
1293 auth->insert(domain, authenticator->user(), authenticator->password());
1294 objectCache.releaseEntry(cacheKey);
1295 } else {
1296 QNetworkAuthenticationCache *auth = new QNetworkAuthenticationCache;
1297 auth->insert(domain, authenticator->user(), authenticator->password());
1298 objectCache.addEntry(cacheKey, auth);
1299 }
1300
1301 if (copy.userName().isEmpty()) {
1302 break;
1303 } else {
1304 copy.setUserName(QString());
1305 }
1306 } while (true);
1307}
1308
1309/*!
1310 Fetch the credential data from the credential cache.
1311
1312 If auth is 0 (as it is when called from createRequest()), this will try to
1313 look up with an empty realm. That fails in most cases for HTTP (because the
1314 realm is seldom empty for HTTP challenges). In any case, QHttpNetworkConnection
1315 never sends the credentials on the first attempt: it needs to find out what
1316 authentication methods the server supports.
1317
1318 For FTP, realm is always empty.
1319*/
1320QNetworkAuthenticationCredential *
1321QNetworkAccessManagerPrivate::fetchCachedCredentials(const QUrl &url,
1322 const QAuthenticator *authentication)
1323{
1324 if (!url.password().isEmpty())
1325 return 0; // no need to set credentials if it already has them
1326
1327 QString realm;
1328 if (authentication)
1329 realm = authentication->realm();
1330
1331 QByteArray cacheKey = authenticationKey(url, realm);
1332 if (!objectCache.hasEntry(cacheKey))
1333 return 0;
1334
1335 QNetworkAuthenticationCache *auth =
1336 static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey));
1337 QNetworkAuthenticationCredential *cred = auth->findClosestMatch(url.path());
1338 objectCache.releaseEntry(cacheKey);
1339 return cred;
1340}
1341
1342void QNetworkAccessManagerPrivate::clearCache(QNetworkAccessManager *manager)
1343{
1344 manager->d_func()->objectCache.clear();
1345}
1346
1347QNetworkAccessManagerPrivate::~QNetworkAccessManagerPrivate()
1348{
1349}
1350
1351#ifndef QT_NO_BEARERMANAGEMENT
1352void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &config)
1353{
1354 Q_Q(QNetworkAccessManager);
1355
1356 initializeSession = false;
1357
1358 if (!config.isValid()) {
1359 networkSession.clear();
1360 online = false;
1361
1362 if (networkAccessible == QNetworkAccessManager::NotAccessible)
1363 emit q->networkAccessibleChanged(QNetworkAccessManager::NotAccessible);
1364 else
1365 emit q->networkAccessibleChanged(QNetworkAccessManager::UnknownAccessibility);
1366
1367 return;
1368 }
1369
1370 networkSession = QSharedNetworkSessionManager::getSession(config);
1371
1372 QObject::connect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected()), Qt::QueuedConnection);
1373 //QueuedConnection is used to avoid deleting the networkSession inside its closed signal
1374 QObject::connect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed()), Qt::QueuedConnection);
1375 QObject::connect(networkSession.data(), SIGNAL(stateChanged(QNetworkSession::State)),
1376 q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)), Qt::QueuedConnection);
1377
1378 _q_networkSessionStateChanged(networkSession->state());
1379}
1380
1381void QNetworkAccessManagerPrivate::_q_networkSessionClosed()
1382{
1383 if (networkSession) {
1384 networkConfiguration = networkSession->configuration().identifier();
1385
1386 networkSession.clear();
1387 }
1388}
1389
1390void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession::State state)
1391{
1392 Q_Q(QNetworkAccessManager);
1393
1394 if (state == QNetworkSession::Connected)
1395 emit q->networkSessionConnected();
1396 if (online) {
1397 if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) {
1398 online = false;
1399 emit q->networkAccessibleChanged(QNetworkAccessManager::NotAccessible);
1400 }
1401 } else {
1402 if (state == QNetworkSession::Connected || state == QNetworkSession::Roaming) {
1403 online = true;
1404 emit q->networkAccessibleChanged(networkAccessible);
1405 }
1406 }
1407}
1408#endif // QT_NO_BEARERMANAGEMENT
1409
1410QT_END_NAMESPACE
1411
1412#include "moc_qnetworkaccessmanager.cpp"
Note: See TracBrowser for help on using the repository browser.