Workaround crash when multiple QNetworkAccessManager instances are used
[qt:qt.git] / src / network / access / qnetworkaccessmanager.cpp
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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
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 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
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 "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
68 QT_BEGIN_NAMESPACE
69
70 #ifndef QT_NO_HTTP
71 Q_GLOBAL_STATIC(QNetworkAccessHttpBackendFactory, httpBackend)
72 #endif // QT_NO_HTTP
73 Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
74 Q_GLOBAL_STATIC(QNetworkAccessDataBackendFactory, dataBackend)
75 #ifndef QT_NO_FTP
76 Q_GLOBAL_STATIC(QNetworkAccessFtpBackendFactory, ftpBackend)
77 #endif // QT_NO_FTP
78
79 #ifdef QT_BUILD_INTERNAL
80 Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend)
81 #endif
82
83 static 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
345 class QNetworkAuthenticationCredential
346 {
347 public:
348     QString domain;
349     QString user;
350     QString password;
351 };
352 Q_DECLARE_TYPEINFO(QNetworkAuthenticationCredential, Q_MOVABLE_TYPE);
353 inline bool operator<(const QNetworkAuthenticationCredential &t1, const QString &t2)
354 { return t1.domain < t2; }
355
356 class QNetworkAuthenticationCache: private QVector<QNetworkAuthenticationCredential>,
357                                    public QNetworkAccessCache::CacheableObject
358 {
359 public:
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
401 static 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
440 static 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 */
451 QNetworkAccessManager::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 */
464 QNetworkAccessManager::~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 */
488 QNetworkProxy 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 */
507 void 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 */
527 QNetworkProxyFactory *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 */
561 void 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 */
577 QAbstractNetworkCache *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 */
599 void 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 */
617 QNetworkCookieJar *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 */
654 void 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 */
673 QNetworkReply *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 */
688 QNetworkReply *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 */
707 QNetworkReply *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 */
718 QNetworkReply *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 */
748 QNetworkReply *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 */
758 QNetworkReply *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 */
779 QNetworkReply *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 */
809 void 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 */
822 QNetworkConfiguration 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 */
847 QNetworkConfiguration 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 */
868 void 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 */
886 QNetworkAccessManager::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 */
923 QNetworkReply *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 */
943 QNetworkReply *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
1075 void 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
1089 void 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
1101 QNetworkReply *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
1115 void 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
1125 void 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
1158 void 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
1189 void 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
1225 QNetworkAuthenticationCredential *
1226 QNetworkAccessManagerPrivate::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
1257 QList<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
1278 void 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 */
1320 QNetworkAuthenticationCredential *
1321 QNetworkAccessManagerPrivate::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
1342 void QNetworkAccessManagerPrivate::clearCache(QNetworkAccessManager *manager)
1343 {
1344     manager->d_func()->objectCache.clear();
1345 }
1346
1347 QNetworkAccessManagerPrivate::~QNetworkAccessManagerPrivate()
1348 {
1349 }
1350
1351 #ifndef QT_NO_BEARERMANAGEMENT
1352 void 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()));
1373     QObject::connect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed()));
1374     QObject::connect(networkSession.data(), SIGNAL(stateChanged(QNetworkSession::State)),
1375                      q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)));
1376
1377     _q_networkSessionStateChanged(networkSession->state());
1378 }
1379
1380 void QNetworkAccessManagerPrivate::_q_networkSessionClosed()
1381 {
1382     if (networkSession) {
1383         networkConfiguration = networkSession->configuration().identifier();
1384
1385         networkSession.clear();
1386     }
1387 }
1388
1389 void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession::State state)
1390 {
1391     Q_Q(QNetworkAccessManager);
1392
1393     if (state == QNetworkSession::Connected)
1394         emit q->networkSessionConnected();
1395     if (online) {
1396         if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) {
1397             online = false;
1398             emit q->networkAccessibleChanged(QNetworkAccessManager::NotAccessible);
1399         }
1400     } else {
1401         if (state == QNetworkSession::Connected || state == QNetworkSession::Roaming) {
1402             online = true;
1403             emit q->networkAccessibleChanged(networkAccessible);
1404         }
1405     }
1406 }
1407 #endif // QT_NO_BEARERMANAGEMENT
1408
1409 QT_END_NAMESPACE
1410
1411 #include "moc_qnetworkaccessmanager.cpp"