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