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