1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** All rights reserved.
|
---|
5 | ** Contact: Nokia Corporation ([email protected])
|
---|
6 | **
|
---|
7 | ** This file is part of the QtNetwork module of the Qt Toolkit.
|
---|
8 | **
|
---|
9 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
10 | ** Commercial Usage
|
---|
11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
13 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
14 | ** a written agreement between you and Nokia.
|
---|
15 | **
|
---|
16 | ** GNU Lesser General Public License Usage
|
---|
17 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
18 | ** General Public License version 2.1 as published by the Free Software
|
---|
19 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
20 | ** packaging of this file. Please review the following information to
|
---|
21 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
23 | **
|
---|
24 | ** In addition, as a special exception, Nokia gives you certain additional
|
---|
25 | ** rights. These rights are described in the Nokia Qt LGPL Exception
|
---|
26 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you have questions regarding the use of this file, please contact
|
---|
37 | ** Nokia at [email protected].
|
---|
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 "qnetworkaccesshttpbackend_p.h"
|
---|
51 | #include "qnetworkaccessftpbackend_p.h"
|
---|
52 | #include "qnetworkaccessfilebackend_p.h"
|
---|
53 | #include "qnetworkaccessdatabackend_p.h"
|
---|
54 | #include "qnetworkaccessdebugpipebackend_p.h"
|
---|
55 | #include "qfilenetworkreply_p.h"
|
---|
56 |
|
---|
57 | #include "QtCore/qbuffer.h"
|
---|
58 | #include "QtCore/qurl.h"
|
---|
59 | #include "QtCore/qvector.h"
|
---|
60 | #include "QtNetwork/qauthenticator.h"
|
---|
61 | #include "QtNetwork/qsslconfiguration.h"
|
---|
62 |
|
---|
63 | QT_BEGIN_NAMESPACE
|
---|
64 |
|
---|
65 | #ifndef QT_NO_HTTP
|
---|
66 | Q_GLOBAL_STATIC(QNetworkAccessHttpBackendFactory, httpBackend)
|
---|
67 | #endif // QT_NO_HTTP
|
---|
68 | Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
|
---|
69 | Q_GLOBAL_STATIC(QNetworkAccessDataBackendFactory, dataBackend)
|
---|
70 | #ifndef QT_NO_FTP
|
---|
71 | Q_GLOBAL_STATIC(QNetworkAccessFtpBackendFactory, ftpBackend)
|
---|
72 | #endif // QT_NO_FTP
|
---|
73 |
|
---|
74 | #ifdef QT_BUILD_INTERNAL
|
---|
75 | Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend)
|
---|
76 | #endif
|
---|
77 |
|
---|
78 | static void ensureInitialized()
|
---|
79 | {
|
---|
80 | #ifndef QT_NO_HTTP
|
---|
81 | (void) httpBackend();
|
---|
82 | #endif // QT_NO_HTTP
|
---|
83 | (void) dataBackend();
|
---|
84 | #ifndef QT_NO_FTP
|
---|
85 | (void) ftpBackend();
|
---|
86 | #endif
|
---|
87 |
|
---|
88 | #ifdef QT_BUILD_INTERNAL
|
---|
89 | (void) debugpipeBackend();
|
---|
90 | #endif
|
---|
91 |
|
---|
92 | // leave this one last since it will query the special QAbstractFileEngines
|
---|
93 | (void) fileBackend();
|
---|
94 | }
|
---|
95 |
|
---|
96 | /*!
|
---|
97 | \class QNetworkAccessManager
|
---|
98 | \brief The QNetworkAccessManager class allows the application to
|
---|
99 | send network requests and receive replies
|
---|
100 | \since 4.4
|
---|
101 |
|
---|
102 | \ingroup network
|
---|
103 | \inmodule QtNetwork
|
---|
104 | \reentrant
|
---|
105 |
|
---|
106 | The Network Access API is constructed around one QNetworkAccessManager
|
---|
107 | object, which holds the common configuration and settings for the requests
|
---|
108 | it sends. It contains the proxy and cache configuration, as well as the
|
---|
109 | signals related to such issues, and reply signals that can be used to
|
---|
110 | monitor the progress of a network operation. One QNetworkAccessManager
|
---|
111 | should be enough for the whole Qt application.
|
---|
112 |
|
---|
113 | Once a QNetworkAccessManager object has been created, the application can
|
---|
114 | use it to send requests over the network. A group of standard functions
|
---|
115 | are supplied that take a request and optional data, and each return a
|
---|
116 | QNetworkReply object. The returned object is used to obtain any data
|
---|
117 | returned in response to the corresponding request.
|
---|
118 |
|
---|
119 | A simple download off the network could be accomplished with:
|
---|
120 | \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 0
|
---|
121 |
|
---|
122 | QNetworkAccessManager has an asynchronous API.
|
---|
123 | When the \tt replyFinished slot above is called, the parameter it
|
---|
124 | takes is the QNetworkReply object containing the downloaded data
|
---|
125 | as well as meta-data (headers, etc.).
|
---|
126 |
|
---|
127 | \note After the request has finished, it is the responsibility of the user
|
---|
128 | to delete the QNetworkReply object at an appropriate time. Do not directly
|
---|
129 | delete it inside the slot connected to finished(). You can use the
|
---|
130 | deleteLater() function.
|
---|
131 |
|
---|
132 | \note QNetworkAccessManager queues the requests it receives. The number
|
---|
133 | of requests executed in parallel is dependent on the protocol.
|
---|
134 | Currently, for the HTTP protocol on desktop platforms, 6 requests are
|
---|
135 | executed in parallel for one host/port combination.
|
---|
136 |
|
---|
137 | A more involved example, assuming the manager is already existent,
|
---|
138 | can be:
|
---|
139 | \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 1
|
---|
140 |
|
---|
141 | \section1 Symbian Platform Security Requirements
|
---|
142 |
|
---|
143 | On Symbian, processes which use this class must have the
|
---|
144 | \c NetworkServices platform security capability. If the client
|
---|
145 | process lacks this capability, operations will result in a panic.
|
---|
146 |
|
---|
147 | Platform security capabilities are added via the
|
---|
148 | \l{qmake-variable-reference.html#target-capability}{TARGET.CAPABILITY}
|
---|
149 | qmake variable.
|
---|
150 |
|
---|
151 | \sa QNetworkRequest, QNetworkReply, QNetworkProxy
|
---|
152 | */
|
---|
153 |
|
---|
154 | /*!
|
---|
155 | \enum QNetworkAccessManager::Operation
|
---|
156 |
|
---|
157 | Indicates the operation this reply is processing.
|
---|
158 |
|
---|
159 | \value HeadOperation retrieve headers operation (created
|
---|
160 | with head())
|
---|
161 |
|
---|
162 | \value GetOperation retrieve headers and download contents
|
---|
163 | (created with get())
|
---|
164 |
|
---|
165 | \value PutOperation upload contents operation (created
|
---|
166 | with put())
|
---|
167 |
|
---|
168 | \value PostOperation send the contents of an HTML form for
|
---|
169 | processing via HTTP POST (created with post())
|
---|
170 |
|
---|
171 | \value DeleteOperation delete contents operation (created with
|
---|
172 | deleteResource())
|
---|
173 |
|
---|
174 | \omitvalue UnknownOperation
|
---|
175 |
|
---|
176 | \sa QNetworkReply::operation()
|
---|
177 | */
|
---|
178 |
|
---|
179 | /*!
|
---|
180 | \fn void QNetworkAccessManager::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)
|
---|
181 |
|
---|
182 | This signal is emitted whenever a proxy requests authentication
|
---|
183 | and QNetworkAccessManager cannot find a valid, cached
|
---|
184 | credential. The slot connected to this signal should fill in the
|
---|
185 | credentials for the proxy \a proxy in the \a authenticator object.
|
---|
186 |
|
---|
187 | QNetworkAccessManager will cache the credentials internally. The
|
---|
188 | next time the proxy requests authentication, QNetworkAccessManager
|
---|
189 | will automatically send the same credential without emitting the
|
---|
190 | proxyAuthenticationRequired signal again.
|
---|
191 |
|
---|
192 | If the proxy rejects the credentials, QNetworkAccessManager will
|
---|
193 | emit the signal again.
|
---|
194 |
|
---|
195 | \sa proxy(), setProxy(), authenticationRequired()
|
---|
196 | */
|
---|
197 |
|
---|
198 | /*!
|
---|
199 | \fn void QNetworkAccessManager::authenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator)
|
---|
200 |
|
---|
201 | This signal is emitted whenever a final server requests
|
---|
202 | authentication before it delivers the requested contents. The slot
|
---|
203 | connected to this signal should fill the credentials for the
|
---|
204 | contents (which can be determined by inspecting the \a reply
|
---|
205 | object) in the \a authenticator object.
|
---|
206 |
|
---|
207 | QNetworkAccessManager will cache the credentials internally and
|
---|
208 | will send the same values if the server requires authentication
|
---|
209 | again, without emitting the authenticationRequired() signal. If it
|
---|
210 | rejects the credentials, this signal will be emitted again.
|
---|
211 |
|
---|
212 | \sa proxyAuthenticationRequired()
|
---|
213 | */
|
---|
214 |
|
---|
215 | /*!
|
---|
216 | \fn void QNetworkAccessManager::finished(QNetworkReply *reply)
|
---|
217 |
|
---|
218 | This signal is emitted whenever a pending network reply is
|
---|
219 | finished. The \a reply parameter will contain a pointer to the
|
---|
220 | reply that has just finished. This signal is emitted in tandem
|
---|
221 | with the QNetworkReply::finished() signal.
|
---|
222 |
|
---|
223 | See QNetworkReply::finished() for information on the status that
|
---|
224 | the object will be in.
|
---|
225 |
|
---|
226 | \note Do not delete the \a reply object in the slot connected to this
|
---|
227 | signal. Use deleteLater().
|
---|
228 |
|
---|
229 | \sa QNetworkReply::finished(), QNetworkReply::error()
|
---|
230 | */
|
---|
231 |
|
---|
232 | /*!
|
---|
233 | \fn void QNetworkAccessManager::sslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
|
---|
234 |
|
---|
235 | This signal is emitted if the SSL/TLS session encountered errors
|
---|
236 | during the set up, including certificate verification errors. The
|
---|
237 | \a errors parameter contains the list of errors and \a reply is
|
---|
238 | the QNetworkReply that is encountering these errors.
|
---|
239 |
|
---|
240 | To indicate that the errors are not fatal and that the connection
|
---|
241 | should proceed, the QNetworkReply::ignoreSslErrors() function should be called
|
---|
242 | from the slot connected to this signal. If it is not called, the
|
---|
243 | SSL session will be torn down before any data is exchanged
|
---|
244 | (including the URL).
|
---|
245 |
|
---|
246 | This signal can be used to display an error message to the user
|
---|
247 | indicating that security may be compromised and display the
|
---|
248 | SSL settings (see sslConfiguration() to obtain it). If the user
|
---|
249 | decides to proceed after analyzing the remote certificate, the
|
---|
250 | slot should call ignoreSslErrors().
|
---|
251 |
|
---|
252 | \sa QSslSocket::sslErrors(), QNetworkReply::sslErrors(),
|
---|
253 | QNetworkReply::sslConfiguration(), QNetworkReply::ignoreSslErrors()
|
---|
254 | */
|
---|
255 |
|
---|
256 | class QNetworkAuthenticationCredential
|
---|
257 | {
|
---|
258 | public:
|
---|
259 | QString domain;
|
---|
260 | QString user;
|
---|
261 | QString password;
|
---|
262 | };
|
---|
263 | Q_DECLARE_TYPEINFO(QNetworkAuthenticationCredential, Q_MOVABLE_TYPE);
|
---|
264 | inline bool operator<(const QNetworkAuthenticationCredential &t1, const QString &t2)
|
---|
265 | { return t1.domain < t2; }
|
---|
266 |
|
---|
267 | class QNetworkAuthenticationCache: private QVector<QNetworkAuthenticationCredential>,
|
---|
268 | public QNetworkAccessCache::CacheableObject
|
---|
269 | {
|
---|
270 | public:
|
---|
271 | QNetworkAuthenticationCache()
|
---|
272 | {
|
---|
273 | setExpires(false);
|
---|
274 | setShareable(true);
|
---|
275 | reserve(1);
|
---|
276 | }
|
---|
277 |
|
---|
278 | QNetworkAuthenticationCredential *findClosestMatch(const QString &domain)
|
---|
279 | {
|
---|
280 | iterator it = qLowerBound(begin(), end(), domain);
|
---|
281 | if (it == end() && !isEmpty())
|
---|
282 | --it;
|
---|
283 | if (it == end() || !domain.startsWith(it->domain))
|
---|
284 | return 0;
|
---|
285 | return &*it;
|
---|
286 | }
|
---|
287 |
|
---|
288 | void insert(const QString &domain, const QString &user, const QString &password)
|
---|
289 | {
|
---|
290 | QNetworkAuthenticationCredential *closestMatch = findClosestMatch(domain);
|
---|
291 | if (closestMatch && closestMatch->domain == domain) {
|
---|
292 | // we're overriding the current credentials
|
---|
293 | closestMatch->user = user;
|
---|
294 | closestMatch->password = password;
|
---|
295 | } else {
|
---|
296 | QNetworkAuthenticationCredential newCredential;
|
---|
297 | newCredential.domain = domain;
|
---|
298 | newCredential.user = user;
|
---|
299 | newCredential.password = password;
|
---|
300 |
|
---|
301 | if (closestMatch)
|
---|
302 | QVector<QNetworkAuthenticationCredential>::insert(++closestMatch, newCredential);
|
---|
303 | else
|
---|
304 | QVector<QNetworkAuthenticationCredential>::insert(end(), newCredential);
|
---|
305 | }
|
---|
306 | }
|
---|
307 |
|
---|
308 | virtual void dispose() { delete this; }
|
---|
309 | };
|
---|
310 |
|
---|
311 | #ifndef QT_NO_NETWORKPROXY
|
---|
312 | static QByteArray proxyAuthenticationKey(const QNetworkProxy &proxy, const QString &realm)
|
---|
313 | {
|
---|
314 | QUrl key;
|
---|
315 |
|
---|
316 | switch (proxy.type()) {
|
---|
317 | case QNetworkProxy::Socks5Proxy:
|
---|
318 | key.setScheme(QLatin1String("proxy-socks5"));
|
---|
319 | break;
|
---|
320 |
|
---|
321 | case QNetworkProxy::HttpProxy:
|
---|
322 | case QNetworkProxy::HttpCachingProxy:
|
---|
323 | key.setScheme(QLatin1String("proxy-http"));
|
---|
324 | break;
|
---|
325 |
|
---|
326 | case QNetworkProxy::FtpCachingProxy:
|
---|
327 | key.setScheme(QLatin1String("proxy-ftp"));
|
---|
328 | break;
|
---|
329 |
|
---|
330 | case QNetworkProxy::DefaultProxy:
|
---|
331 | case QNetworkProxy::NoProxy:
|
---|
332 | // shouldn't happen
|
---|
333 | return QByteArray();
|
---|
334 |
|
---|
335 | // no default:
|
---|
336 | // let there be errors if a new proxy type is added in the future
|
---|
337 | }
|
---|
338 |
|
---|
339 | if (key.scheme().isEmpty())
|
---|
340 | // proxy type not handled
|
---|
341 | return QByteArray();
|
---|
342 |
|
---|
343 | key.setUserName(proxy.user());
|
---|
344 | key.setHost(proxy.hostName());
|
---|
345 | key.setPort(proxy.port());
|
---|
346 | key.setFragment(realm);
|
---|
347 | return "auth:" + key.toEncoded();
|
---|
348 | }
|
---|
349 | #endif
|
---|
350 |
|
---|
351 | static inline QByteArray authenticationKey(const QUrl &url, const QString &realm)
|
---|
352 | {
|
---|
353 | QUrl copy = url;
|
---|
354 | copy.setFragment(realm);
|
---|
355 | return "auth:" + copy.toEncoded(QUrl::RemovePassword | QUrl::RemovePath | QUrl::RemoveQuery);
|
---|
356 | }
|
---|
357 |
|
---|
358 | /*!
|
---|
359 | Constructs a QNetworkAccessManager object that is the center of
|
---|
360 | the Network Access API and sets \a parent as the parent object.
|
---|
361 | */
|
---|
362 | QNetworkAccessManager::QNetworkAccessManager(QObject *parent)
|
---|
363 | : QObject(*new QNetworkAccessManagerPrivate, parent)
|
---|
364 | {
|
---|
365 | ensureInitialized();
|
---|
366 | }
|
---|
367 |
|
---|
368 | /*!
|
---|
369 | Destroys the QNetworkAccessManager object and frees up any
|
---|
370 | resources. Note that QNetworkReply objects that are returned from
|
---|
371 | this class have this object set as their parents, which means that
|
---|
372 | they will be deleted along with it if you don't call
|
---|
373 | QObject::setParent() on them.
|
---|
374 | */
|
---|
375 | QNetworkAccessManager::~QNetworkAccessManager()
|
---|
376 | {
|
---|
377 | #ifndef QT_NO_NETWORKPROXY
|
---|
378 | delete d_func()->proxyFactory;
|
---|
379 | #endif
|
---|
380 | }
|
---|
381 |
|
---|
382 | #ifndef QT_NO_NETWORKPROXY
|
---|
383 | /*!
|
---|
384 | Returns the QNetworkProxy that the requests sent using this
|
---|
385 | QNetworkAccessManager object will use. The default value for the
|
---|
386 | proxy is QNetworkProxy::DefaultProxy.
|
---|
387 |
|
---|
388 | \sa setProxy(), setProxyFactory(), proxyAuthenticationRequired()
|
---|
389 | */
|
---|
390 | QNetworkProxy QNetworkAccessManager::proxy() const
|
---|
391 | {
|
---|
392 | return d_func()->proxy;
|
---|
393 | }
|
---|
394 |
|
---|
395 | /*!
|
---|
396 | Sets the proxy to be used in future requests to be \a proxy. This
|
---|
397 | does not affect requests that have already been sent. The
|
---|
398 | proxyAuthenticationRequired() signal will be emitted if the proxy
|
---|
399 | requests authentication.
|
---|
400 |
|
---|
401 | A proxy set with this function will be used for all requests
|
---|
402 | issued by QNetworkAccessManager. In some cases, it might be
|
---|
403 | necessary to select different proxies depending on the type of
|
---|
404 | request being sent or the destination host. If that's the case,
|
---|
405 | you should consider using setProxyFactory().
|
---|
406 |
|
---|
407 | \sa proxy(), proxyAuthenticationRequired()
|
---|
408 | */
|
---|
409 | void QNetworkAccessManager::setProxy(const QNetworkProxy &proxy)
|
---|
410 | {
|
---|
411 | Q_D(QNetworkAccessManager);
|
---|
412 | delete d->proxyFactory;
|
---|
413 | d->proxy = proxy;
|
---|
414 | d->proxyFactory = 0;
|
---|
415 | }
|
---|
416 |
|
---|
417 | /*!
|
---|
418 | \fn QNetworkProxyFactory *QNetworkAccessManager::proxyFactory() const
|
---|
419 | \since 4.5
|
---|
420 |
|
---|
421 | Returns the proxy factory that this QNetworkAccessManager object
|
---|
422 | is using to determine the proxies to be used for requests.
|
---|
423 |
|
---|
424 | Note that the pointer returned by this function is managed by
|
---|
425 | QNetworkAccessManager and could be deleted at any time.
|
---|
426 |
|
---|
427 | \sa setProxyFactory(), proxy()
|
---|
428 | */
|
---|
429 | QNetworkProxyFactory *QNetworkAccessManager::proxyFactory() const
|
---|
430 | {
|
---|
431 | return d_func()->proxyFactory;
|
---|
432 | }
|
---|
433 |
|
---|
434 | /*!
|
---|
435 | \since 4.5
|
---|
436 |
|
---|
437 | Sets the proxy factory for this class to be \a factory. A proxy
|
---|
438 | factory is used to determine a more specific list of proxies to be
|
---|
439 | used for a given request, instead of trying to use the same proxy
|
---|
440 | value for all requests.
|
---|
441 |
|
---|
442 | All queries sent by QNetworkAccessManager will have type
|
---|
443 | QNetworkProxyQuery::UrlRequest.
|
---|
444 |
|
---|
445 | For example, a proxy factory could apply the following rules:
|
---|
446 | \list
|
---|
447 | \o if the target address is in the local network (for example,
|
---|
448 | if the hostname contains no dots or if it's an IP address in
|
---|
449 | the organization's range), return QNetworkProxy::NoProxy
|
---|
450 | \o if the request is FTP, return an FTP proxy
|
---|
451 | \o if the request is HTTP or HTTPS, then return an HTTP proxy
|
---|
452 | \o otherwise, return a SOCKSv5 proxy server
|
---|
453 | \endlist
|
---|
454 |
|
---|
455 | The lifetime of the object \a factory will be managed by
|
---|
456 | QNetworkAccessManager. It will delete the object when necessary.
|
---|
457 |
|
---|
458 | \note If a specific proxy is set with setProxy(), the factory will not
|
---|
459 | be used.
|
---|
460 |
|
---|
461 | \sa proxyFactory(), setProxy(), QNetworkProxyQuery
|
---|
462 | */
|
---|
463 | void QNetworkAccessManager::setProxyFactory(QNetworkProxyFactory *factory)
|
---|
464 | {
|
---|
465 | Q_D(QNetworkAccessManager);
|
---|
466 | delete d->proxyFactory;
|
---|
467 | d->proxyFactory = factory;
|
---|
468 | d->proxy = QNetworkProxy();
|
---|
469 | }
|
---|
470 | #endif
|
---|
471 |
|
---|
472 | /*!
|
---|
473 | \since 4.5
|
---|
474 |
|
---|
475 | Returns the cache that is used to store data obtained from the network.
|
---|
476 |
|
---|
477 | \sa setCache()
|
---|
478 | */
|
---|
479 | QAbstractNetworkCache *QNetworkAccessManager::cache() const
|
---|
480 | {
|
---|
481 | Q_D(const QNetworkAccessManager);
|
---|
482 | return d->networkCache;
|
---|
483 | }
|
---|
484 |
|
---|
485 | /*!
|
---|
486 | \since 4.5
|
---|
487 |
|
---|
488 | Sets the manager's network cache to be the \a cache specified. The cache
|
---|
489 | is used for all requests dispatched by the manager.
|
---|
490 |
|
---|
491 | Use this function to set the network cache object to a class that implements
|
---|
492 | additional features, like saving the cookies to permanent storage.
|
---|
493 |
|
---|
494 | \note QNetworkAccessManager takes ownership of the \a cache object.
|
---|
495 |
|
---|
496 | QNetworkAccessManager by default does not have a set cache.
|
---|
497 | Qt provides a simple disk cache, QNetworkDiskCache, which can be used.
|
---|
498 |
|
---|
499 | \sa cache(), QNetworkRequest::CacheLoadControl
|
---|
500 | */
|
---|
501 | void QNetworkAccessManager::setCache(QAbstractNetworkCache *cache)
|
---|
502 | {
|
---|
503 | Q_D(QNetworkAccessManager);
|
---|
504 | if (d->networkCache != cache) {
|
---|
505 | delete d->networkCache;
|
---|
506 | d->networkCache = cache;
|
---|
507 | if (d->networkCache)
|
---|
508 | d->networkCache->setParent(this);
|
---|
509 | }
|
---|
510 | }
|
---|
511 |
|
---|
512 | /*!
|
---|
513 | Returns the QNetworkCookieJar that is used to store cookies
|
---|
514 | obtained from the network as well as cookies that are about to be
|
---|
515 | sent.
|
---|
516 |
|
---|
517 | \sa setCookieJar()
|
---|
518 | */
|
---|
519 | QNetworkCookieJar *QNetworkAccessManager::cookieJar() const
|
---|
520 | {
|
---|
521 | Q_D(const QNetworkAccessManager);
|
---|
522 | if (!d->cookieJar)
|
---|
523 | d->createCookieJar();
|
---|
524 | return d->cookieJar;
|
---|
525 | }
|
---|
526 |
|
---|
527 | /*!
|
---|
528 | Sets the manager's cookie jar to be the \a cookieJar specified.
|
---|
529 | The cookie jar is used by all requests dispatched by the manager.
|
---|
530 |
|
---|
531 | Use this function to set the cookie jar object to a class that
|
---|
532 | implements additional features, like saving the cookies to permanent
|
---|
533 | storage.
|
---|
534 |
|
---|
535 | \note QNetworkAccessManager takes ownership of the \a cookieJar object.
|
---|
536 |
|
---|
537 | QNetworkAccessManager will set the parent of the \a cookieJar
|
---|
538 | passed to itself, so that the cookie jar is deleted when this
|
---|
539 | object is deleted as well. If you want to share cookie jars
|
---|
540 | between different QNetworkAccessManager objects, you may want to
|
---|
541 | set the cookie jar's parent to 0 after calling this function.
|
---|
542 |
|
---|
543 | QNetworkAccessManager by default does not implement any cookie
|
---|
544 | policy of its own: it accepts all cookies sent by the server, as
|
---|
545 | long as they are well formed and meet the minimum security
|
---|
546 | requirements (cookie domain matches the request's and cookie path
|
---|
547 | matches the request's). In order to implement your own security
|
---|
548 | policy, override the QNetworkCookieJar::cookiesForUrl() and
|
---|
549 | QNetworkCookieJar::setCookiesFromUrl() virtual functions. Those
|
---|
550 | functions are called by QNetworkAccessManager when it detects a
|
---|
551 | new cookie.
|
---|
552 |
|
---|
553 | \sa cookieJar(), QNetworkCookieJar::cookiesForUrl(), QNetworkCookieJar::setCookiesFromUrl()
|
---|
554 | */
|
---|
555 | void QNetworkAccessManager::setCookieJar(QNetworkCookieJar *cookieJar)
|
---|
556 | {
|
---|
557 | Q_D(QNetworkAccessManager);
|
---|
558 | d->cookieJarCreated = true;
|
---|
559 | if (d->cookieJar != cookieJar) {
|
---|
560 | if (d->cookieJar && d->cookieJar->parent() == this)
|
---|
561 | delete d->cookieJar;
|
---|
562 | d->cookieJar = cookieJar;
|
---|
563 | d->cookieJar->setParent(this);
|
---|
564 | }
|
---|
565 | }
|
---|
566 |
|
---|
567 | /*!
|
---|
568 | Posts a request to obtain the network headers for \a request
|
---|
569 | and returns a new QNetworkReply object which will contain such headers.
|
---|
570 |
|
---|
571 | The function is named after the HTTP request associated (HEAD).
|
---|
572 | */
|
---|
573 | QNetworkReply *QNetworkAccessManager::head(const QNetworkRequest &request)
|
---|
574 | {
|
---|
575 | return d_func()->postProcess(createRequest(QNetworkAccessManager::HeadOperation, request));
|
---|
576 | }
|
---|
577 |
|
---|
578 | /*!
|
---|
579 | Posts a request to obtain the contents of the target \a request
|
---|
580 | and returns a new QNetworkReply object opened for reading which emits the
|
---|
581 | \l{QIODevice::readyRead()}{readyRead()} signal whenever new data
|
---|
582 | arrives.
|
---|
583 |
|
---|
584 | The contents as well as associated headers will be downloaded.
|
---|
585 |
|
---|
586 | \sa post(), put(), deleteResource()
|
---|
587 | */
|
---|
588 | QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
|
---|
589 | {
|
---|
590 | return d_func()->postProcess(createRequest(QNetworkAccessManager::GetOperation, request));
|
---|
591 | }
|
---|
592 |
|
---|
593 | /*!
|
---|
594 | Sends an HTTP POST request to the destination specified by \a request
|
---|
595 | and returns a new QNetworkReply object opened for reading that will
|
---|
596 | contain the reply sent by the server. The contents of the \a data
|
---|
597 | device will be uploaded to the server.
|
---|
598 |
|
---|
599 | \a data must be open for reading and must remain valid until the
|
---|
600 | finished() signal is emitted for this reply.
|
---|
601 |
|
---|
602 | \note Sending a POST request on protocols other than HTTP and
|
---|
603 | HTTPS is undefined and will probably fail.
|
---|
604 |
|
---|
605 | \sa get(), put(), deleteResource()
|
---|
606 | */
|
---|
607 | QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QIODevice *data)
|
---|
608 | {
|
---|
609 | return d_func()->postProcess(createRequest(QNetworkAccessManager::PostOperation, request, data));
|
---|
610 | }
|
---|
611 |
|
---|
612 | /*!
|
---|
613 | \overload
|
---|
614 |
|
---|
615 | Sends the contents of the \a data byte array to the destination
|
---|
616 | specified by \a request.
|
---|
617 | */
|
---|
618 | QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, const QByteArray &data)
|
---|
619 | {
|
---|
620 | QBuffer *buffer = new QBuffer;
|
---|
621 | buffer->setData(data);
|
---|
622 | buffer->open(QIODevice::ReadOnly);
|
---|
623 |
|
---|
624 | QNetworkReply *reply = post(request, buffer);
|
---|
625 | buffer->setParent(reply);
|
---|
626 | return reply;
|
---|
627 | }
|
---|
628 |
|
---|
629 | /*!
|
---|
630 | Uploads the contents of \a data to the destination \a request and
|
---|
631 | returnes a new QNetworkReply object that will be open for reply.
|
---|
632 |
|
---|
633 | \a data must be opened for reading when this function is called
|
---|
634 | and must remain valid until the finished() signal is emitted for
|
---|
635 | this reply.
|
---|
636 |
|
---|
637 | Whether anything will be available for reading from the returned
|
---|
638 | object is protocol dependent. For HTTP, the server may send a
|
---|
639 | small HTML page indicating the upload was successful (or not).
|
---|
640 | Other protocols will probably have content in their replies.
|
---|
641 |
|
---|
642 | \note For HTTP, this request will send a PUT request, which most servers
|
---|
643 | do not allow. Form upload mechanisms, including that of uploading
|
---|
644 | files through HTML forms, use the POST mechanism.
|
---|
645 |
|
---|
646 | \sa get(), post()
|
---|
647 | */
|
---|
648 | QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, QIODevice *data)
|
---|
649 | {
|
---|
650 | return d_func()->postProcess(createRequest(QNetworkAccessManager::PutOperation, request, data));
|
---|
651 | }
|
---|
652 |
|
---|
653 | /*!
|
---|
654 | \overload
|
---|
655 | Sends the contents of the \a data byte array to the destination
|
---|
656 | specified by \a request.
|
---|
657 | */
|
---|
658 | QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, const QByteArray &data)
|
---|
659 | {
|
---|
660 | QBuffer *buffer = new QBuffer;
|
---|
661 | buffer->setData(data);
|
---|
662 | buffer->open(QIODevice::ReadOnly);
|
---|
663 |
|
---|
664 | QNetworkReply *reply = put(request, buffer);
|
---|
665 | buffer->setParent(reply);
|
---|
666 | return reply;
|
---|
667 | }
|
---|
668 |
|
---|
669 | /*!
|
---|
670 | \since 4.6
|
---|
671 |
|
---|
672 | Sends a request to delete the resource identified by the URL of \a request.
|
---|
673 |
|
---|
674 | \note This feature is currently available for HTTP only, performing an
|
---|
675 | HTTP DELETE request.
|
---|
676 |
|
---|
677 | \sa get(), post(), put()
|
---|
678 | */
|
---|
679 | QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &request)
|
---|
680 | {
|
---|
681 | return d_func()->postProcess(createRequest(QNetworkAccessManager::DeleteOperation, request));
|
---|
682 | }
|
---|
683 |
|
---|
684 | /*!
|
---|
685 | Returns a new QNetworkReply object to handle the operation \a op
|
---|
686 | and request \a req. The device \a outgoingData is always 0 for Get and
|
---|
687 | Head requests, but is the value passed to post() and put() in
|
---|
688 | those operations (the QByteArray variants will pass a QBuffer
|
---|
689 | object).
|
---|
690 |
|
---|
691 | The default implementation calls QNetworkCookieJar::cookiesForUrl()
|
---|
692 | on the cookie jar set with setCookieJar() to obtain the cookies to
|
---|
693 | be sent to the remote server.
|
---|
694 |
|
---|
695 | The returned object must be in an open state.
|
---|
696 | */
|
---|
697 | QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op,
|
---|
698 | const QNetworkRequest &req,
|
---|
699 | QIODevice *outgoingData)
|
---|
700 | {
|
---|
701 | Q_D(QNetworkAccessManager);
|
---|
702 |
|
---|
703 | // fast path for GET on file:// URLs
|
---|
704 | // Also if the scheme is empty we consider it a file.
|
---|
705 | // The QNetworkAccessFileBackend will right now only be used
|
---|
706 | // for PUT or qrc://
|
---|
707 | if ((op == QNetworkAccessManager::GetOperation || op == QNetworkAccessManager::HeadOperation)
|
---|
708 | && (req.url().scheme() == QLatin1String("file")
|
---|
709 | || req.url().scheme().isEmpty())) {
|
---|
710 | return new QFileNetworkReply(this, req, op);
|
---|
711 | }
|
---|
712 |
|
---|
713 | QNetworkRequest request = req;
|
---|
714 | if (!request.header(QNetworkRequest::ContentLengthHeader).isValid() &&
|
---|
715 | outgoingData && !outgoingData->isSequential()) {
|
---|
716 | // request has no Content-Length
|
---|
717 | // but the data that is outgoing is random-access
|
---|
718 | request.setHeader(QNetworkRequest::ContentLengthHeader, outgoingData->size());
|
---|
719 | }
|
---|
720 | if (d->cookieJar) {
|
---|
721 | QList<QNetworkCookie> cookies = d->cookieJar->cookiesForUrl(request.url());
|
---|
722 | if (!cookies.isEmpty())
|
---|
723 | request.setHeader(QNetworkRequest::CookieHeader, qVariantFromValue(cookies));
|
---|
724 | }
|
---|
725 |
|
---|
726 | // first step: create the reply
|
---|
727 | QUrl url = request.url();
|
---|
728 | QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
|
---|
729 | QNetworkReplyImplPrivate *priv = reply->d_func();
|
---|
730 | priv->manager = this;
|
---|
731 |
|
---|
732 | // second step: fetch cached credentials
|
---|
733 | QNetworkAuthenticationCredential *cred = d->fetchCachedCredentials(url);
|
---|
734 | if (cred) {
|
---|
735 | url.setUserName(cred->user);
|
---|
736 | url.setPassword(cred->password);
|
---|
737 | priv->urlForLastAuthentication = url;
|
---|
738 | }
|
---|
739 |
|
---|
740 | // third step: find a backend
|
---|
741 | priv->backend = d->findBackend(op, request);
|
---|
742 |
|
---|
743 | #ifndef QT_NO_NETWORKPROXY
|
---|
744 | QList<QNetworkProxy> proxyList = d->queryProxy(QNetworkProxyQuery(request.url()));
|
---|
745 | priv->proxyList = proxyList;
|
---|
746 | #endif
|
---|
747 | if (priv->backend) {
|
---|
748 | priv->backend->setParent(reply);
|
---|
749 | priv->backend->reply = priv;
|
---|
750 | }
|
---|
751 | // fourth step: setup the reply
|
---|
752 | priv->setup(op, request, outgoingData);
|
---|
753 |
|
---|
754 | #ifndef QT_NO_OPENSSL
|
---|
755 | reply->setSslConfiguration(request.sslConfiguration());
|
---|
756 | #endif
|
---|
757 | return reply;
|
---|
758 | }
|
---|
759 |
|
---|
760 | void QNetworkAccessManagerPrivate::_q_replyFinished()
|
---|
761 | {
|
---|
762 | Q_Q(QNetworkAccessManager);
|
---|
763 | QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
|
---|
764 | if (reply)
|
---|
765 | emit q->finished(reply);
|
---|
766 | }
|
---|
767 |
|
---|
768 | void QNetworkAccessManagerPrivate::_q_replySslErrors(const QList<QSslError> &errors)
|
---|
769 | {
|
---|
770 | #ifndef QT_NO_OPENSSL
|
---|
771 | Q_Q(QNetworkAccessManager);
|
---|
772 | QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
|
---|
773 | if (reply)
|
---|
774 | emit q->sslErrors(reply, errors);
|
---|
775 | #else
|
---|
776 | Q_UNUSED(errors);
|
---|
777 | #endif
|
---|
778 | }
|
---|
779 |
|
---|
780 | QNetworkReply *QNetworkAccessManagerPrivate::postProcess(QNetworkReply *reply)
|
---|
781 | {
|
---|
782 | Q_Q(QNetworkAccessManager);
|
---|
783 | QNetworkReplyPrivate::setManager(reply, q);
|
---|
784 | q->connect(reply, SIGNAL(finished()), SLOT(_q_replyFinished()));
|
---|
785 | #ifndef QT_NO_OPENSSL
|
---|
786 | /* In case we're compiled without SSL support, we don't have this signal and we need to
|
---|
787 | * avoid getting a connection error. */
|
---|
788 | q->connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SLOT(_q_replySslErrors(QList<QSslError>)));
|
---|
789 | #endif
|
---|
790 |
|
---|
791 | return reply;
|
---|
792 | }
|
---|
793 |
|
---|
794 | void QNetworkAccessManagerPrivate::createCookieJar() const
|
---|
795 | {
|
---|
796 | if (!cookieJarCreated) {
|
---|
797 | // keep the ugly hack in here
|
---|
798 | QNetworkAccessManagerPrivate *that = const_cast<QNetworkAccessManagerPrivate *>(this);
|
---|
799 | that->cookieJar = new QNetworkCookieJar(that->q_func());
|
---|
800 | that->cookieJarCreated = true;
|
---|
801 | }
|
---|
802 | }
|
---|
803 |
|
---|
804 | void QNetworkAccessManagerPrivate::authenticationRequired(QNetworkAccessBackend *backend,
|
---|
805 | QAuthenticator *authenticator)
|
---|
806 | {
|
---|
807 | Q_Q(QNetworkAccessManager);
|
---|
808 |
|
---|
809 | // FIXME: Add support for domains (i.e., the leading path)
|
---|
810 | QUrl url = backend->reply->url;
|
---|
811 |
|
---|
812 | // don't try the cache for the same URL twice in a row
|
---|
813 | // being called twice for the same URL means the authentication failed
|
---|
814 | if (url != backend->reply->urlForLastAuthentication) {
|
---|
815 | QNetworkAuthenticationCredential *cred = fetchCachedCredentials(url, authenticator);
|
---|
816 | if (cred) {
|
---|
817 | authenticator->setUser(cred->user);
|
---|
818 | authenticator->setPassword(cred->password);
|
---|
819 | backend->reply->urlForLastAuthentication = url;
|
---|
820 | return;
|
---|
821 | }
|
---|
822 | }
|
---|
823 |
|
---|
824 | backend->reply->urlForLastAuthentication = url;
|
---|
825 | emit q->authenticationRequired(backend->reply->q_func(), authenticator);
|
---|
826 | addCredentials(url, authenticator);
|
---|
827 | }
|
---|
828 |
|
---|
829 | #ifndef QT_NO_NETWORKPROXY
|
---|
830 | void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(QNetworkAccessBackend *backend,
|
---|
831 | const QNetworkProxy &proxy,
|
---|
832 | QAuthenticator *authenticator)
|
---|
833 | {
|
---|
834 | Q_Q(QNetworkAccessManager);
|
---|
835 | // ### FIXME Tracking of successful authentications
|
---|
836 | // This code is a bit broken right now for SOCKS authentication
|
---|
837 | // first request: proxyAuthenticationRequired gets emitted, credentials gets saved
|
---|
838 | // second request: (proxy != backend->reply->lastProxyAuthentication) does not evaluate to true,
|
---|
839 | // proxyAuthenticationRequired gets emitted again
|
---|
840 | // possible solution: some tracking inside the authenticator
|
---|
841 | // or a new function proxyAuthenticationSucceeded(true|false)
|
---|
842 | if (proxy != backend->reply->lastProxyAuthentication) {
|
---|
843 | QNetworkAuthenticationCredential *cred = fetchCachedCredentials(proxy);
|
---|
844 | if (cred) {
|
---|
845 | authenticator->setUser(cred->user);
|
---|
846 | authenticator->setPassword(cred->password);
|
---|
847 | return;
|
---|
848 | }
|
---|
849 | }
|
---|
850 |
|
---|
851 | backend->reply->lastProxyAuthentication = proxy;
|
---|
852 | emit q->proxyAuthenticationRequired(proxy, authenticator);
|
---|
853 | addCredentials(proxy, authenticator);
|
---|
854 | }
|
---|
855 |
|
---|
856 | void QNetworkAccessManagerPrivate::addCredentials(const QNetworkProxy &p,
|
---|
857 | const QAuthenticator *authenticator)
|
---|
858 | {
|
---|
859 | Q_ASSERT(authenticator);
|
---|
860 | Q_ASSERT(p.type() != QNetworkProxy::DefaultProxy);
|
---|
861 | Q_ASSERT(p.type() != QNetworkProxy::NoProxy);
|
---|
862 |
|
---|
863 | QString realm = authenticator->realm();
|
---|
864 | QNetworkProxy proxy = p;
|
---|
865 | proxy.setUser(authenticator->user());
|
---|
866 | // Set two credentials: one with the username and one without
|
---|
867 | do {
|
---|
868 | // Set two credentials actually: one with and one without the realm
|
---|
869 | do {
|
---|
870 | QByteArray cacheKey = proxyAuthenticationKey(proxy, realm);
|
---|
871 | if (cacheKey.isEmpty())
|
---|
872 | return; // should not happen
|
---|
873 |
|
---|
874 | QNetworkAuthenticationCache *auth = new QNetworkAuthenticationCache;
|
---|
875 | auth->insert(QString(), authenticator->user(), authenticator->password());
|
---|
876 | objectCache.addEntry(cacheKey, auth); // replace the existing one, if there's any
|
---|
877 |
|
---|
878 | if (realm.isEmpty()) {
|
---|
879 | break;
|
---|
880 | } else {
|
---|
881 | realm.clear();
|
---|
882 | }
|
---|
883 | } while (true);
|
---|
884 |
|
---|
885 | if (proxy.user().isEmpty())
|
---|
886 | break;
|
---|
887 | else
|
---|
888 | proxy.setUser(QString());
|
---|
889 | } while (true);
|
---|
890 | }
|
---|
891 |
|
---|
892 | QNetworkAuthenticationCredential *
|
---|
893 | QNetworkAccessManagerPrivate::fetchCachedCredentials(const QNetworkProxy &p,
|
---|
894 | const QAuthenticator *authenticator)
|
---|
895 | {
|
---|
896 | QNetworkProxy proxy = p;
|
---|
897 | if (proxy.type() == QNetworkProxy::DefaultProxy) {
|
---|
898 | proxy = QNetworkProxy::applicationProxy();
|
---|
899 | }
|
---|
900 | if (!proxy.password().isEmpty())
|
---|
901 | return 0; // no need to set credentials if it already has them
|
---|
902 |
|
---|
903 | QString realm;
|
---|
904 | if (authenticator)
|
---|
905 | realm = authenticator->realm();
|
---|
906 |
|
---|
907 | QByteArray cacheKey = proxyAuthenticationKey(proxy, realm);
|
---|
908 | if (cacheKey.isEmpty())
|
---|
909 | return 0;
|
---|
910 | if (!objectCache.hasEntry(cacheKey))
|
---|
911 | return 0;
|
---|
912 |
|
---|
913 | QNetworkAuthenticationCache *auth =
|
---|
914 | static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey));
|
---|
915 | QNetworkAuthenticationCredential *cred = auth->findClosestMatch(QString());
|
---|
916 | objectCache.releaseEntry(cacheKey);
|
---|
917 |
|
---|
918 | // proxy cache credentials always have exactly one item
|
---|
919 | Q_ASSERT_X(cred, "QNetworkAccessManager",
|
---|
920 | "Internal inconsistency: found a cache key for a proxy, but it's empty");
|
---|
921 | return cred;
|
---|
922 | }
|
---|
923 |
|
---|
924 | QList<QNetworkProxy> QNetworkAccessManagerPrivate::queryProxy(const QNetworkProxyQuery &query)
|
---|
925 | {
|
---|
926 | QList<QNetworkProxy> proxies;
|
---|
927 | if (proxyFactory) {
|
---|
928 | proxies = proxyFactory->queryProxy(query);
|
---|
929 | if (proxies.isEmpty()) {
|
---|
930 | qWarning("QNetworkAccessManager: factory %p has returned an empty result set",
|
---|
931 | proxyFactory);
|
---|
932 | proxies << QNetworkProxy::NoProxy;
|
---|
933 | }
|
---|
934 | } else if (proxy.type() == QNetworkProxy::DefaultProxy) {
|
---|
935 | // no proxy set, query the application
|
---|
936 | return QNetworkProxyFactory::proxyForQuery(query);
|
---|
937 | } else {
|
---|
938 | proxies << proxy;
|
---|
939 | }
|
---|
940 |
|
---|
941 | return proxies;
|
---|
942 | }
|
---|
943 | #endif
|
---|
944 |
|
---|
945 | void QNetworkAccessManagerPrivate::addCredentials(const QUrl &url,
|
---|
946 | const QAuthenticator *authenticator)
|
---|
947 | {
|
---|
948 | Q_ASSERT(authenticator);
|
---|
949 | QString domain = QString::fromLatin1("/"); // FIXME: make QAuthenticator return the domain
|
---|
950 | QString realm = authenticator->realm();
|
---|
951 |
|
---|
952 | // Set two credentials actually: one with and one without the username in the URL
|
---|
953 | QUrl copy = url;
|
---|
954 | copy.setUserName(authenticator->user());
|
---|
955 | do {
|
---|
956 | QByteArray cacheKey = authenticationKey(copy, realm);
|
---|
957 | if (objectCache.hasEntry(cacheKey)) {
|
---|
958 | QNetworkAuthenticationCache *auth =
|
---|
959 | static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey));
|
---|
960 | auth->insert(domain, authenticator->user(), authenticator->password());
|
---|
961 | objectCache.releaseEntry(cacheKey);
|
---|
962 | } else {
|
---|
963 | QNetworkAuthenticationCache *auth = new QNetworkAuthenticationCache;
|
---|
964 | auth->insert(domain, authenticator->user(), authenticator->password());
|
---|
965 | objectCache.addEntry(cacheKey, auth);
|
---|
966 | }
|
---|
967 |
|
---|
968 | if (copy.userName().isEmpty()) {
|
---|
969 | break;
|
---|
970 | } else {
|
---|
971 | copy.setUserName(QString());
|
---|
972 | }
|
---|
973 | } while (true);
|
---|
974 | }
|
---|
975 |
|
---|
976 | /*!
|
---|
977 | Fetch the credential data from the credential cache.
|
---|
978 |
|
---|
979 | If auth is 0 (as it is when called from createRequest()), this will try to
|
---|
980 | look up with an empty realm. That fails in most cases for HTTP (because the
|
---|
981 | realm is seldom empty for HTTP challenges). In any case, QHttpNetworkConnection
|
---|
982 | never sends the credentials on the first attempt: it needs to find out what
|
---|
983 | authentication methods the server supports.
|
---|
984 |
|
---|
985 | For FTP, realm is always empty.
|
---|
986 | */
|
---|
987 | QNetworkAuthenticationCredential *
|
---|
988 | QNetworkAccessManagerPrivate::fetchCachedCredentials(const QUrl &url,
|
---|
989 | const QAuthenticator *authentication)
|
---|
990 | {
|
---|
991 | if (!url.password().isEmpty())
|
---|
992 | return 0; // no need to set credentials if it already has them
|
---|
993 |
|
---|
994 | QString realm;
|
---|
995 | if (authentication)
|
---|
996 | realm = authentication->realm();
|
---|
997 |
|
---|
998 | QByteArray cacheKey = authenticationKey(url, realm);
|
---|
999 | if (!objectCache.hasEntry(cacheKey))
|
---|
1000 | return 0;
|
---|
1001 |
|
---|
1002 | QNetworkAuthenticationCache *auth =
|
---|
1003 | static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey));
|
---|
1004 | QNetworkAuthenticationCredential *cred = auth->findClosestMatch(url.path());
|
---|
1005 | objectCache.releaseEntry(cacheKey);
|
---|
1006 | return cred;
|
---|
1007 | }
|
---|
1008 |
|
---|
1009 | void QNetworkAccessManagerPrivate::clearCache(QNetworkAccessManager *manager)
|
---|
1010 | {
|
---|
1011 | manager->d_func()->objectCache.clear();
|
---|
1012 | }
|
---|
1013 |
|
---|
1014 | QNetworkAccessManagerPrivate::~QNetworkAccessManagerPrivate()
|
---|
1015 | {
|
---|
1016 | }
|
---|
1017 |
|
---|
1018 | QT_END_NAMESPACE
|
---|
1019 |
|
---|
1020 | #include "moc_qnetworkaccessmanager.cpp"
|
---|