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