Doc: Modularize QtNetwork documentation.
[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     qRegisterMetaType<QHttpNetworkRequest>("QHttpNetworkRequest");
420     qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
421     qRegisterMetaType<QSharedPointer<char> >("QSharedPointer<char>");
422 }
423
424 /*!
425     Destroys the QNetworkAccessManager object and frees up any
426     resources. Note that QNetworkReply objects that are returned from
427     this class have this object set as their parents, which means that
428     they will be deleted along with it if you don't call
429     QObject::setParent() on them.
430 */
431 QNetworkAccessManager::~QNetworkAccessManager()
432 {
433 #ifndef QT_NO_NETWORKPROXY
434     delete d_func()->proxyFactory;
435 #endif
436
437     // Delete the QNetworkReply children first.
438     // Else a QAbstractNetworkCache might get deleted in ~QObject
439     // before a QNetworkReply that accesses the QAbstractNetworkCache
440     // object in its destructor.
441     qDeleteAll(findChildren<QNetworkReply *>());
442     // The other children will be deleted in this ~QObject
443     // FIXME instead of this "hack" make the QNetworkReplyImpl
444     // properly watch the cache deletion, e.g. via a QWeakPointer.
445 }
446
447 #ifndef QT_NO_NETWORKPROXY
448 /*!
449     Returns the QNetworkProxy that the requests sent using this
450     QNetworkAccessManager object will use. The default value for the
451     proxy is QNetworkProxy::DefaultProxy.
452
453     \sa setProxy(), setProxyFactory(), proxyAuthenticationRequired()
454 */
455 QNetworkProxy QNetworkAccessManager::proxy() const
456 {
457     return d_func()->proxy;
458 }
459
460 /*!
461     Sets the proxy to be used in future requests to be \a proxy. This
462     does not affect requests that have already been sent. The
463     proxyAuthenticationRequired() signal will be emitted if the proxy
464     requests authentication.
465
466     A proxy set with this function will be used for all requests
467     issued by QNetworkAccessManager. In some cases, it might be
468     necessary to select different proxies depending on the type of
469     request being sent or the destination host. If that's the case,
470     you should consider using setProxyFactory().
471
472     \sa proxy(), proxyAuthenticationRequired()
473 */
474 void QNetworkAccessManager::setProxy(const QNetworkProxy &proxy)
475 {
476     Q_D(QNetworkAccessManager);
477     delete d->proxyFactory;
478     d->proxy = proxy;
479     d->proxyFactory = 0;
480 }
481
482 /*!
483     \fn QNetworkProxyFactory *QNetworkAccessManager::proxyFactory() const
484     \since 4.5
485
486     Returns the proxy factory that this QNetworkAccessManager object
487     is using to determine the proxies to be used for requests.
488
489     Note that the pointer returned by this function is managed by
490     QNetworkAccessManager and could be deleted at any time.
491
492     \sa setProxyFactory(), proxy()
493 */
494 QNetworkProxyFactory *QNetworkAccessManager::proxyFactory() const
495 {
496     return d_func()->proxyFactory;
497 }
498
499 /*!
500     \since 4.5
501
502     Sets the proxy factory for this class to be \a factory. A proxy
503     factory is used to determine a more specific list of proxies to be
504     used for a given request, instead of trying to use the same proxy
505     value for all requests.
506
507     All queries sent by QNetworkAccessManager will have type
508     QNetworkProxyQuery::UrlRequest.
509
510     For example, a proxy factory could apply the following rules:
511     \list
512       \li if the target address is in the local network (for example,
513          if the hostname contains no dots or if it's an IP address in
514          the organization's range), return QNetworkProxy::NoProxy
515       \li if the request is FTP, return an FTP proxy
516       \li if the request is HTTP or HTTPS, then return an HTTP proxy
517       \li otherwise, return a SOCKSv5 proxy server
518     \endlist
519
520     The lifetime of the object \a factory will be managed by
521     QNetworkAccessManager. It will delete the object when necessary.
522
523     \note If a specific proxy is set with setProxy(), the factory will not
524     be used.
525
526     \sa proxyFactory(), setProxy(), QNetworkProxyQuery
527 */
528 void QNetworkAccessManager::setProxyFactory(QNetworkProxyFactory *factory)
529 {
530     Q_D(QNetworkAccessManager);
531     delete d->proxyFactory;
532     d->proxyFactory = factory;
533     d->proxy = QNetworkProxy();
534 }
535 #endif
536
537 /*!
538     \since 4.5
539
540     Returns the cache that is used to store data obtained from the network.
541
542     \sa setCache()
543 */
544 QAbstractNetworkCache *QNetworkAccessManager::cache() const
545 {
546     Q_D(const QNetworkAccessManager);
547     return d->networkCache;
548 }
549
550 /*!
551     \since 4.5
552
553     Sets the manager's network cache to be the \a cache specified. The cache
554     is used for all requests dispatched by the manager.
555
556     Use this function to set the network cache object to a class that implements
557     additional features, like saving the cookies to permanent storage.
558
559     \note QNetworkAccessManager takes ownership of the \a cache object.
560
561     QNetworkAccessManager by default does not have a set cache.
562     Qt provides a simple disk cache, QNetworkDiskCache, which can be used.
563
564     \sa cache(), QNetworkRequest::CacheLoadControl
565 */
566 void QNetworkAccessManager::setCache(QAbstractNetworkCache *cache)
567 {
568     Q_D(QNetworkAccessManager);
569     if (d->networkCache != cache) {
570         delete d->networkCache;
571         d->networkCache = cache;
572         if (d->networkCache)
573             d->networkCache->setParent(this);
574     }
575 }
576
577 /*!
578     Returns the QNetworkCookieJar that is used to store cookies
579     obtained from the network as well as cookies that are about to be
580     sent.
581
582     \sa setCookieJar()
583 */
584 QNetworkCookieJar *QNetworkAccessManager::cookieJar() const
585 {
586     Q_D(const QNetworkAccessManager);
587     if (!d->cookieJar)
588         d->createCookieJar();
589     return d->cookieJar;
590 }
591
592 /*!
593     Sets the manager's cookie jar to be the \a cookieJar specified.
594     The cookie jar is used by all requests dispatched by the manager.
595
596     Use this function to set the cookie jar object to a class that
597     implements additional features, like saving the cookies to permanent
598     storage.
599
600     \note QNetworkAccessManager takes ownership of the \a cookieJar object.
601
602     If \a cookieJar is in the same thread as this QNetworkAccessManager,
603     it will set the parent of the \a cookieJar
604     so that the cookie jar is deleted when this
605     object is deleted as well. If you want to share cookie jars
606     between different QNetworkAccessManager objects, you may want to
607     set the cookie jar's parent to 0 after calling this function.
608
609     QNetworkAccessManager by default does not implement any cookie
610     policy of its own: it accepts all cookies sent by the server, as
611     long as they are well formed and meet the minimum security
612     requirements (cookie domain matches the request's and cookie path
613     matches the request's). In order to implement your own security
614     policy, override the QNetworkCookieJar::cookiesForUrl() and
615     QNetworkCookieJar::setCookiesFromUrl() virtual functions. Those
616     functions are called by QNetworkAccessManager when it detects a
617     new cookie.
618
619     \sa cookieJar(), QNetworkCookieJar::cookiesForUrl(), QNetworkCookieJar::setCookiesFromUrl()
620 */
621 void QNetworkAccessManager::setCookieJar(QNetworkCookieJar *cookieJar)
622 {
623     Q_D(QNetworkAccessManager);
624     d->cookieJarCreated = true;
625     if (d->cookieJar != cookieJar) {
626         if (d->cookieJar && d->cookieJar->parent() == this)
627             delete d->cookieJar;
628         d->cookieJar = cookieJar;
629         if (thread() == cookieJar->thread())
630             d->cookieJar->setParent(this);
631     }
632 }
633
634 /*!
635     Posts a request to obtain the network headers for \a request
636     and returns a new QNetworkReply object which will contain such headers.
637
638     The function is named after the HTTP request associated (HEAD).
639 */
640 QNetworkReply *QNetworkAccessManager::head(const QNetworkRequest &request)
641 {
642     return d_func()->postProcess(createRequest(QNetworkAccessManager::HeadOperation, request));
643 }
644
645 /*!
646     Posts a request to obtain the contents of the target \a request
647     and returns a new QNetworkReply object opened for reading which emits the 
648     \l{QIODevice::readyRead()}{readyRead()} signal whenever new data 
649     arrives.
650
651     The contents as well as associated headers will be downloaded.
652
653     \sa post(), put(), deleteResource(), sendCustomRequest()
654 */
655 QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
656 {
657     return d_func()->postProcess(createRequest(QNetworkAccessManager::GetOperation, request));
658 }
659
660 /*!
661     Sends an HTTP POST request to the destination specified by \a request
662     and returns a new QNetworkReply object opened for reading that will 
663     contain the reply sent by the server. The contents of  the \a data 
664     device will be uploaded to the server.
665
666     \a data must be open for reading and must remain valid until the 
667     finished() signal is emitted for this reply.
668
669     \note Sending a POST request on protocols other than HTTP and
670     HTTPS is undefined and will probably fail.
671
672     \sa get(), put(), deleteResource(), sendCustomRequest()
673 */
674 QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QIODevice *data)
675 {
676     return d_func()->postProcess(createRequest(QNetworkAccessManager::PostOperation, request, data));
677 }
678
679 /*!
680     \overload
681
682     Sends the contents of the \a data byte array to the destination 
683     specified by \a request.
684 */
685 QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, const QByteArray &data)
686 {
687     QBuffer *buffer = new QBuffer;
688     buffer->setData(data);
689     buffer->open(QIODevice::ReadOnly);
690
691     QNetworkReply *reply = post(request, buffer);
692     buffer->setParent(reply);
693     return reply;
694 }
695
696 /*!
697     \since 4.8
698
699     \overload
700
701     Sends the contents of the \a multiPart message to the destination
702     specified by \a request.
703
704     This can be used for sending MIME multipart messages over HTTP.
705
706     \sa QHttpMultiPart, QHttpPart, put()
707 */
708 QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QHttpMultiPart *multiPart)
709 {
710     QNetworkRequest newRequest = d_func()->prepareMultipart(request, multiPart);
711     QIODevice *device = multiPart->d_func()->device;
712     QNetworkReply *reply = post(newRequest, device);
713     return reply;
714 }
715
716 /*!
717     \since 4.8
718
719     \overload
720
721     Sends the contents of the \a multiPart message to the destination
722     specified by \a request.
723
724     This can be used for sending MIME multipart messages over HTTP.
725
726     \sa QHttpMultiPart, QHttpPart, post()
727 */
728 QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, QHttpMultiPart *multiPart)
729 {
730     QNetworkRequest newRequest = d_func()->prepareMultipart(request, multiPart);
731     QIODevice *device = multiPart->d_func()->device;
732     QNetworkReply *reply = put(newRequest, device);
733     return reply;
734 }
735
736 /*!
737     Uploads the contents of \a data to the destination \a request and
738     returnes a new QNetworkReply object that will be open for reply.
739
740     \a data must be opened for reading when this function is called
741     and must remain valid until the finished() signal is emitted for
742     this reply.
743
744     Whether anything will be available for reading from the returned
745     object is protocol dependent. For HTTP, the server may send a 
746     small HTML page indicating the upload was successful (or not). 
747     Other protocols will probably have content in their replies.
748
749     \note For HTTP, this request will send a PUT request, which most servers
750     do not allow. Form upload mechanisms, including that of uploading
751     files through HTML forms, use the POST mechanism.
752
753     \sa get(), post(), deleteResource(), sendCustomRequest()
754 */
755 QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, QIODevice *data)
756 {
757     return d_func()->postProcess(createRequest(QNetworkAccessManager::PutOperation, request, data));
758 }
759
760 /*!
761     \overload
762
763     Sends the contents of the \a data byte array to the destination
764     specified by \a request.
765 */
766 QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, const QByteArray &data)
767 {
768     QBuffer *buffer = new QBuffer;
769     buffer->setData(data);
770     buffer->open(QIODevice::ReadOnly);
771
772     QNetworkReply *reply = put(request, buffer);
773     buffer->setParent(reply);
774     return reply;
775 }
776
777 /*!
778     \since 4.6
779
780     Sends a request to delete the resource identified by the URL of \a request.
781
782     \note This feature is currently available for HTTP only, performing an 
783     HTTP DELETE request.
784
785     \sa get(), post(), put(), sendCustomRequest()
786 */
787 QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &request)
788 {
789     return d_func()->postProcess(createRequest(QNetworkAccessManager::DeleteOperation, request));
790 }
791
792 #ifndef QT_NO_BEARERMANAGEMENT
793
794 /*!
795     \since 4.7
796
797     Sets the network configuration that will be used when creating the
798     \l {QNetworkSession}{network session} to \a config.
799
800     The network configuration is used to create and open a network session before any request that
801     requires network access is process.  If no network configuration is explicitly set via this
802     function the network configuration returned by
803     QNetworkConfigurationManager::defaultConfiguration() will be used.
804
805     To restore the default network configuration set the network configuration to the value
806     returned from QNetworkConfigurationManager::defaultConfiguration().
807
808     \snippet code/src_network_access_qnetworkaccessmanager.cpp 2
809
810     If an invalid network configuration is set, a network session will not be created.  In this
811     case network requests will be processed regardless, but may fail.  For example:
812
813     \snippet code/src_network_access_qnetworkaccessmanager.cpp 3
814
815     \sa configuration(), QNetworkSession
816 */
817 void QNetworkAccessManager::setConfiguration(const QNetworkConfiguration &config)
818 {
819     d_func()->createSession(config);
820 }
821
822 /*!
823     \since 4.7
824
825     Returns the network configuration that will be used to create the
826     \l {QNetworkSession}{network session} which will be used when processing network requests.
827
828     \sa setConfiguration(), activeConfiguration()
829 */
830 QNetworkConfiguration QNetworkAccessManager::configuration() const
831 {
832     Q_D(const QNetworkAccessManager);
833
834     if (d->networkSession)
835         return d->networkSession->configuration();
836     else
837         return QNetworkConfiguration();
838 }
839
840 /*!
841     \since 4.7
842
843     Returns the current active network configuration.
844
845     If the network configuration returned by configuration() is of type
846     QNetworkConfiguration::ServiceNetwork this function will return the current active child
847     network configuration of that configuration.  Otherwise returns the same network configuration
848     as configuration().
849
850     Use this function to return the actual network configuration currently in use by the network
851     session.
852
853     \sa configuration()
854 */
855 QNetworkConfiguration QNetworkAccessManager::activeConfiguration() const
856 {
857     Q_D(const QNetworkAccessManager);
858
859     if (d->networkSession) {
860         QNetworkConfigurationManager manager;
861
862         return manager.configurationFromIdentifier(
863             d->networkSession->sessionProperty(QLatin1String("ActiveConfiguration")).toString());
864     } else {
865         return QNetworkConfiguration();
866     }
867 }
868
869 /*!
870     \since 4.7
871
872     Overrides the reported network accessibility.  If \a accessible is NotAccessible the reported
873     network accessiblity will always be NotAccessible.  Otherwise the reported network
874     accessibility will reflect the actual device state.
875 */
876 void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkAccessibility accessible)
877 {
878     Q_D(QNetworkAccessManager);
879
880     if (d->networkAccessible != accessible) {
881         NetworkAccessibility previous = networkAccessible();
882         d->networkAccessible = accessible;
883         NetworkAccessibility current = networkAccessible();
884         if (previous != current)
885             emit networkAccessibleChanged(current);
886     }
887 }
888
889 /*!
890     \since 4.7
891
892     Returns the current network accessibility.
893 */
894 QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccessible() const
895 {
896     Q_D(const QNetworkAccessManager);
897
898     if (d->networkSession) {
899         // d->online holds online/offline state of this network session.
900         if (d->online)
901             return d->networkAccessible;
902         else
903             return NotAccessible;
904     } else {
905         // Network accessibility is either disabled or unknown.
906         return (d->networkAccessible == NotAccessible) ? NotAccessible : UnknownAccessibility;
907     }
908 }
909
910 /*!
911     \internal
912
913     Returns the network session currently in use.
914     This can be changed at any time, ownership remains with the QNetworkAccessManager
915 */
916 const QWeakPointer<const QNetworkSession> QNetworkAccessManagerPrivate::getNetworkSession(const QNetworkAccessManager *q)
917 {
918     return q->d_func()->networkSession.toWeakRef();
919 }
920
921 #endif // QT_NO_BEARERMANAGEMENT
922
923 /*!
924     \since 4.7
925
926     Sends a custom request to the server identified by the URL of \a request.
927
928     It is the user's responsibility to send a \a verb to the server that is valid
929     according to the HTTP specification.
930
931     This method provides means to send verbs other than the common ones provided
932     via get() or post() etc., for instance sending an HTTP OPTIONS command.
933
934     If \a data is not empty, the contents of the \a data
935     device will be uploaded to the server; in that case, data must be open for
936     reading and must remain valid until the finished() signal is emitted for this reply.
937
938     \note This feature is currently available for HTTP(S) only.
939
940     \sa get(), post(), put(), deleteResource()
941 */
942 QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data)
943 {
944     QNetworkRequest newRequest(request);
945     newRequest.setAttribute(QNetworkRequest::CustomVerbAttribute, verb);
946     return d_func()->postProcess(createRequest(QNetworkAccessManager::CustomOperation, newRequest, data));
947 }
948
949 /*!
950     Returns a new QNetworkReply object to handle the operation \a op
951     and request \a req. The device \a outgoingData is always 0 for Get and
952     Head requests, but is the value passed to post() and put() in
953     those operations (the QByteArray variants will pass a QBuffer
954     object).
955
956     The default implementation calls QNetworkCookieJar::cookiesForUrl()
957     on the cookie jar set with setCookieJar() to obtain the cookies to
958     be sent to the remote server.
959
960     The returned object must be in an open state.
961 */
962 QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op,
963                                                     const QNetworkRequest &req,
964                                                     QIODevice *outgoingData)
965 {
966     Q_D(QNetworkAccessManager);
967
968     bool isLocalFile = req.url().isLocalFile();
969     QString scheme = req.url().scheme().toLower();
970
971     // fast path for GET on file:// URLs
972     // The QNetworkAccessFileBackend will right now only be used for PUT
973     if ((op == QNetworkAccessManager::GetOperation || op == QNetworkAccessManager::HeadOperation)
974         && (isLocalFile || scheme == QLatin1String("qrc"))) {
975         return new QNetworkReplyFileImpl(this, req, op);
976     }
977
978     if ((op == QNetworkAccessManager::GetOperation || op == QNetworkAccessManager::HeadOperation)
979             && scheme == QLatin1String("data")) {
980         return new QNetworkReplyDataImpl(this, req, op);
981     }
982
983     // A request with QNetworkRequest::AlwaysCache does not need any bearer management
984     QNetworkRequest::CacheLoadControl mode =
985         static_cast<QNetworkRequest::CacheLoadControl>(
986             req.attribute(QNetworkRequest::CacheLoadControlAttribute,
987                               QNetworkRequest::PreferNetwork).toInt());
988     if (mode == QNetworkRequest::AlwaysCache
989         && (op == QNetworkAccessManager::GetOperation
990         || op == QNetworkAccessManager::HeadOperation)) {
991         // FIXME Implement a QNetworkReplyCacheImpl instead, see QTBUG-15106
992         QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
993         QNetworkReplyImplPrivate *priv = reply->d_func();
994         priv->manager = this;
995         priv->backend = new QNetworkAccessCacheBackend();
996         priv->backend->manager = this->d_func();
997         priv->backend->setParent(reply);
998         priv->backend->reply = priv;
999         priv->setup(op, req, outgoingData);
1000         return reply;
1001     }
1002
1003 #ifndef QT_NO_BEARERMANAGEMENT
1004     // Return a disabled network reply if network access is disabled.
1005     // Except if the scheme is empty or file://.
1006     if (!d->networkAccessible && !isLocalFile) {
1007         return new QDisabledNetworkReply(this, req, op);
1008     }
1009
1010     if (!d->networkSession && (d->initializeSession || !d->networkConfiguration.isEmpty())) {
1011         QNetworkConfigurationManager manager;
1012         if (!d->networkConfiguration.isEmpty()) {
1013             d->createSession(manager.configurationFromIdentifier(d->networkConfiguration));
1014         } else {
1015             if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired)
1016                 d->createSession(manager.defaultConfiguration());
1017             else
1018                 d->initializeSession = false;
1019         }
1020     }
1021 #endif
1022
1023     QNetworkRequest request = req;
1024     if (!request.header(QNetworkRequest::ContentLengthHeader).isValid() &&
1025         outgoingData && !outgoingData->isSequential()) {
1026         // request has no Content-Length
1027         // but the data that is outgoing is random-access
1028         request.setHeader(QNetworkRequest::ContentLengthHeader, outgoingData->size());
1029     }
1030
1031     if (static_cast<QNetworkRequest::LoadControl>
1032         (request.attribute(QNetworkRequest::CookieLoadControlAttribute,
1033                            QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Automatic) {
1034         if (d->cookieJar) {
1035             QList<QNetworkCookie> cookies = d->cookieJar->cookiesForUrl(request.url());
1036             if (!cookies.isEmpty())
1037                 request.setHeader(QNetworkRequest::CookieHeader, QVariant::fromValue(cookies));
1038         }
1039     }
1040
1041 #ifndef QT_NO_HTTP
1042     // Since Qt 5 we use the new QNetworkReplyHttpImpl
1043     if (scheme == QLatin1String("http")
1044 #ifndef QT_NO_SSL
1045         || scheme == QLatin1String("https")
1046 #endif
1047         ) {
1048         QNetworkReplyHttpImpl *reply = new QNetworkReplyHttpImpl(this, request, op, outgoingData);
1049 #ifndef QT_NO_BEARERMANAGEMENT
1050         connect(this, SIGNAL(networkSessionConnected()),
1051                 reply, SLOT(_q_networkSessionConnected()));
1052 #endif
1053         return reply;
1054     }
1055 #endif // QT_NO_HTTP
1056
1057     // first step: create the reply
1058     QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
1059 #ifndef QT_NO_BEARERMANAGEMENT
1060     if (!isLocalFile) {
1061         connect(this, SIGNAL(networkSessionConnected()),
1062                 reply, SLOT(_q_networkSessionConnected()));
1063     }
1064 #endif
1065     QNetworkReplyImplPrivate *priv = reply->d_func();
1066     priv->manager = this;
1067
1068     // second step: fetch cached credentials
1069     // This is not done for the time being, we should use signal emissions to request
1070     // the credentials from cache.
1071
1072     // third step: find a backend
1073     priv->backend = d->findBackend(op, request);
1074
1075     if (priv->backend) {
1076         priv->backend->setParent(reply);
1077         priv->backend->reply = priv;
1078     }
1079
1080 #ifndef QT_NO_SSL
1081     reply->setSslConfiguration(request.sslConfiguration());
1082 #endif
1083
1084     // fourth step: setup the reply
1085     priv->setup(op, request, outgoingData);
1086
1087     return reply;
1088 }
1089
1090
1091 /*!
1092     \since 5.0
1093
1094     Flushes the internal cache of authentication data and network connections.
1095
1096     This function is useful for doing auto tests.
1097
1098 */
1099 void QNetworkAccessManager::clearAccessCache()
1100 {
1101     QNetworkAccessManagerPrivate::clearCache(this);
1102 }
1103
1104 void QNetworkAccessManagerPrivate::_q_replyFinished()
1105 {
1106     Q_Q(QNetworkAccessManager);
1107
1108     QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
1109     if (reply)
1110         emit q->finished(reply);
1111
1112 #ifndef QT_NO_BEARERMANAGEMENT
1113     // If there are no active requests, release our reference to the network session.
1114     // It will not be destroyed immediately, but rather when the connection cache is flushed
1115     // after 2 minutes.
1116     if (networkSession && q->findChildren<QNetworkReply *>().count() == 1)
1117         networkSession.clear();
1118 #endif
1119 }
1120
1121 void QNetworkAccessManagerPrivate::_q_replySslErrors(const QList<QSslError> &errors)
1122 {
1123 #ifndef QT_NO_SSL
1124     Q_Q(QNetworkAccessManager);
1125     QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
1126     if (reply)
1127         emit q->sslErrors(reply, errors);
1128 #else
1129     Q_UNUSED(errors);
1130 #endif
1131 }
1132
1133 QNetworkReply *QNetworkAccessManagerPrivate::postProcess(QNetworkReply *reply)
1134 {
1135     Q_Q(QNetworkAccessManager);
1136     QNetworkReplyPrivate::setManager(reply, q);
1137     q->connect(reply, SIGNAL(finished()), SLOT(_q_replyFinished()));
1138 #ifndef QT_NO_SSL
1139     /* In case we're compiled without SSL support, we don't have this signal and we need to
1140      * avoid getting a connection error. */
1141     q->connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SLOT(_q_replySslErrors(QList<QSslError>)));
1142 #endif
1143
1144     return reply;
1145 }
1146
1147 void QNetworkAccessManagerPrivate::createCookieJar() const
1148 {
1149     if (!cookieJarCreated) {
1150         // keep the ugly hack in here
1151         QNetworkAccessManagerPrivate *that = const_cast<QNetworkAccessManagerPrivate *>(this);
1152         that->cookieJar = new QNetworkCookieJar(that->q_func());
1153         that->cookieJarCreated = true;
1154     }
1155 }
1156
1157 void QNetworkAccessManagerPrivate::authenticationRequired(QAuthenticator *authenticator,
1158                                                           QNetworkReply *reply,
1159                                                           bool synchronous,
1160                                                           QUrl &url,
1161                                                           QUrl *urlForLastAuthentication,
1162                                                           bool allowAuthenticationReuse)
1163 {
1164     Q_Q(QNetworkAccessManager);
1165
1166     // don't try the cache for the same URL twice in a row
1167     // being called twice for the same URL means the authentication failed
1168     // also called when last URL is empty, e.g. on first call
1169     if (allowAuthenticationReuse && (urlForLastAuthentication->isEmpty()
1170             || url != *urlForLastAuthentication)) {
1171         // if credentials are included in the url, then use them
1172         if (!url.userName().isEmpty()
1173             && !url.password().isEmpty()) {
1174             authenticator->setUser(url.userName());
1175             authenticator->setPassword(url.password());
1176             *urlForLastAuthentication = url;
1177             authenticationManager->cacheCredentials(url, authenticator);
1178             return;
1179         }
1180
1181         QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedCredentials(url, authenticator);
1182         if (!cred.isNull()) {
1183             authenticator->setUser(cred.user);
1184             authenticator->setPassword(cred.password);
1185             *urlForLastAuthentication = url;
1186             return;
1187         }
1188     }
1189 #if defined(Q_OS_MAC) && !defined(Q_OS_IOS)
1190     //now we try to get the username and password from keychain
1191     //if not successful signal will be emitted
1192     QString username;
1193     QString password;
1194     if (getProxyAuth(proxy.hostName(),reply->request().url().scheme(),username,password)) {
1195         authenticator->setUser(username);
1196         authenticator->setPassword(password);
1197         authenticationManager->cacheProxyCredentials(proxy, authenticator);
1198         return;
1199     }
1200 #endif
1201
1202     // if we emit a signal here in synchronous mode, the user might spin
1203     // an event loop, which might recurse and lead to problems
1204     if (synchronous)
1205         return;
1206
1207     *urlForLastAuthentication = url;
1208     emit q->authenticationRequired(reply, authenticator);
1209     if (allowAuthenticationReuse)
1210         authenticationManager->cacheCredentials(url, authenticator);
1211 }
1212
1213 #ifndef QT_NO_NETWORKPROXY
1214 void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(const QNetworkProxy &proxy,
1215                                                                bool synchronous,
1216                                                                QAuthenticator *authenticator,
1217                                                                QNetworkProxy *lastProxyAuthentication)
1218 {
1219     Q_Q(QNetworkAccessManager);
1220     QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(*authenticator);
1221     if (proxy != *lastProxyAuthentication && (!priv || !priv->hasFailed)) {
1222         QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedProxyCredentials(proxy);
1223         if (!cred.isNull()) {
1224             authenticator->setUser(cred.user);
1225             authenticator->setPassword(cred.password);
1226             return;
1227         }
1228     }
1229
1230     // if we emit a signal here in synchronous mode, the user might spin
1231     // an event loop, which might recurse and lead to problems
1232     if (synchronous)
1233         return;
1234
1235     *lastProxyAuthentication = proxy;
1236     emit q->proxyAuthenticationRequired(proxy, authenticator);
1237     authenticationManager->cacheProxyCredentials(proxy, authenticator);
1238 }
1239
1240 QList<QNetworkProxy> QNetworkAccessManagerPrivate::queryProxy(const QNetworkProxyQuery &query)
1241 {
1242     QList<QNetworkProxy> proxies;
1243     if (proxyFactory) {
1244         proxies = proxyFactory->queryProxy(query);
1245         if (proxies.isEmpty()) {
1246             qWarning("QNetworkAccessManager: factory %p has returned an empty result set",
1247                      proxyFactory);
1248             proxies << QNetworkProxy::NoProxy;
1249         }
1250     } else if (proxy.type() == QNetworkProxy::DefaultProxy) {
1251         // no proxy set, query the application
1252         return QNetworkProxyFactory::proxyForQuery(query);
1253     } else {
1254         proxies << proxy;
1255     }
1256
1257     return proxies;
1258 }
1259 #endif
1260
1261 void QNetworkAccessManagerPrivate::clearCache(QNetworkAccessManager *manager)
1262 {
1263     manager->d_func()->objectCache.clear();
1264     manager->d_func()->authenticationManager->clearCache();
1265
1266     if (manager->d_func()->httpThread) {
1267         // The thread will deleteLater() itself from its finished() signal
1268         manager->d_func()->httpThread->quit();
1269         manager->d_func()->httpThread->wait(5000);
1270         manager->d_func()->httpThread = 0;
1271     }
1272 }
1273
1274 QNetworkAccessManagerPrivate::~QNetworkAccessManagerPrivate()
1275 {
1276     if (httpThread) {
1277         // The thread will deleteLater() itself from its finished() signal
1278         httpThread->quit();
1279         httpThread->wait(5000);
1280         httpThread = 0;
1281     }
1282 }
1283
1284 #ifndef QT_NO_BEARERMANAGEMENT
1285 void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &config)
1286 {
1287     Q_Q(QNetworkAccessManager);
1288
1289     initializeSession = false;
1290
1291     QSharedPointer<QNetworkSession> newSession;
1292     if (config.isValid())
1293         newSession = QSharedNetworkSessionManager::getSession(config);
1294
1295     if (networkSession) {
1296         //do nothing if new and old session are the same
1297         if (networkSession == newSession)
1298             return;
1299         //disconnect from old session
1300         QObject::disconnect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected()));
1301         QObject::disconnect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed()));
1302         QObject::disconnect(networkSession.data(), SIGNAL(stateChanged(QNetworkSession::State)),
1303             q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)));
1304     }
1305
1306     //switch to new session (null if config was invalid)
1307     networkSession = newSession;
1308
1309     if (!networkSession) {
1310         online = false;
1311
1312         if (networkAccessible == QNetworkAccessManager::NotAccessible)
1313             emit q->networkAccessibleChanged(QNetworkAccessManager::NotAccessible);
1314         else
1315             emit q->networkAccessibleChanged(QNetworkAccessManager::UnknownAccessibility);
1316
1317         return;
1318     }
1319
1320     //connect to new session
1321     QObject::connect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected()), Qt::QueuedConnection);
1322     //QueuedConnection is used to avoid deleting the networkSession inside its closed signal
1323     QObject::connect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed()), Qt::QueuedConnection);
1324     QObject::connect(networkSession.data(), SIGNAL(stateChanged(QNetworkSession::State)),
1325                      q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)), Qt::QueuedConnection);
1326
1327     _q_networkSessionStateChanged(networkSession->state());
1328 }
1329
1330 void QNetworkAccessManagerPrivate::_q_networkSessionClosed()
1331 {
1332     Q_Q(QNetworkAccessManager);
1333     if (networkSession) {
1334         networkConfiguration = networkSession->configuration().identifier();
1335
1336         //disconnect from old session
1337         QObject::disconnect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected()));
1338         QObject::disconnect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed()));
1339         QObject::disconnect(networkSession.data(), SIGNAL(stateChanged(QNetworkSession::State)),
1340             q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)));
1341         networkSession.clear();
1342     }
1343 }
1344
1345 void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession::State state)
1346 {
1347     Q_Q(QNetworkAccessManager);
1348
1349     //Do not emit the networkSessionConnected signal here, except for roaming -> connected
1350     //transition, otherwise it is emitted twice in a row when opening a connection.
1351     if (state == QNetworkSession::Connected && lastSessionState == QNetworkSession::Roaming)
1352         emit q->networkSessionConnected();
1353     lastSessionState = state;
1354
1355     if (online) {
1356         if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) {
1357             online = false;
1358             emit q->networkAccessibleChanged(QNetworkAccessManager::NotAccessible);
1359         }
1360     } else {
1361         if (state == QNetworkSession::Connected || state == QNetworkSession::Roaming) {
1362             online = true;
1363             emit q->networkAccessibleChanged(networkAccessible);
1364         }
1365     }
1366 }
1367 #endif // QT_NO_BEARERMANAGEMENT
1368
1369 QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart)
1370 {
1371     // copy the request, we probably need to add some headers
1372     QNetworkRequest newRequest(request);
1373
1374     // add Content-Type header if not there already
1375     if (!request.header(QNetworkRequest::ContentTypeHeader).isValid()) {
1376         QByteArray contentType;
1377         contentType.reserve(34 + multiPart->d_func()->boundary.count());
1378         contentType += "multipart/";
1379         switch (multiPart->d_func()->contentType) {
1380         case QHttpMultiPart::RelatedType:
1381             contentType += "related";
1382             break;
1383         case QHttpMultiPart::FormDataType:
1384             contentType += "form-data";
1385             break;
1386         case QHttpMultiPart::AlternativeType:
1387             contentType += "alternative";
1388             break;
1389         default:
1390             contentType += "mixed";
1391             break;
1392         }
1393         // putting the boundary into quotes, recommended in RFC 2046 section 5.1.1
1394         contentType += "; boundary=\"" + multiPart->d_func()->boundary + "\"";
1395         newRequest.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(contentType));
1396     }
1397
1398     // add MIME-Version header if not there already (we must include the header
1399     // if the message conforms to RFC 2045, see section 4 of that RFC)
1400     QByteArray mimeHeader("MIME-Version");
1401     if (!request.hasRawHeader(mimeHeader))
1402         newRequest.setRawHeader(mimeHeader, QByteArray("1.0"));
1403
1404     QIODevice *device = multiPart->d_func()->device;
1405     if (!device->isReadable()) {
1406         if (!device->isOpen()) {
1407             if (!device->open(QIODevice::ReadOnly))
1408                 qWarning("could not open device for reading");
1409         } else {
1410             qWarning("device is not readable");
1411         }
1412     }
1413
1414     return newRequest;
1415 }
1416
1417 QT_END_NAMESPACE
1418
1419 #include "moc_qnetworkaccessmanager.cpp"