diff options
Diffstat (limited to 'src/network/access/qnetworkaccessmanager.cpp')
-rw-r--r-- | src/network/access/qnetworkaccessmanager.cpp | 267 |
1 files changed, 24 insertions, 243 deletions
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index f1c444790b..7e75045da6 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -65,6 +65,8 @@ #include "QtNetwork/qsslconfiguration.h" #include "QtNetwork/qnetworkconfigmanager.h" +#include "qthread.h" + QT_BEGIN_NAMESPACE #ifndef QT_NO_HTTP @@ -341,107 +343,6 @@ static void ensureInitialized() QNetworkReply::sslConfiguration(), QNetworkReply::ignoreSslErrors() */ -class QNetworkAuthenticationCredential -{ -public: - QString domain; - QString user; - QString password; -}; -Q_DECLARE_TYPEINFO(QNetworkAuthenticationCredential, Q_MOVABLE_TYPE); -inline bool operator<(const QNetworkAuthenticationCredential &t1, const QString &t2) -{ return t1.domain < t2; } - -class QNetworkAuthenticationCache: private QVector<QNetworkAuthenticationCredential>, - public QNetworkAccessCache::CacheableObject -{ -public: - QNetworkAuthenticationCache() - { - setExpires(false); - setShareable(true); - reserve(1); - } - - QNetworkAuthenticationCredential *findClosestMatch(const QString &domain) - { - iterator it = qLowerBound(begin(), end(), domain); - if (it == end() && !isEmpty()) - --it; - if (it == end() || !domain.startsWith(it->domain)) - return 0; - return &*it; - } - - void insert(const QString &domain, const QString &user, const QString &password) - { - QNetworkAuthenticationCredential *closestMatch = findClosestMatch(domain); - if (closestMatch && closestMatch->domain == domain) { - // we're overriding the current credentials - closestMatch->user = user; - closestMatch->password = password; - } else { - QNetworkAuthenticationCredential newCredential; - newCredential.domain = domain; - newCredential.user = user; - newCredential.password = password; - - if (closestMatch) - QVector<QNetworkAuthenticationCredential>::insert(++closestMatch, newCredential); - else - QVector<QNetworkAuthenticationCredential>::insert(end(), newCredential); - } - } - - virtual void dispose() { delete this; } -}; - -#ifndef QT_NO_NETWORKPROXY -static QByteArray proxyAuthenticationKey(const QNetworkProxy &proxy, const QString &realm) -{ - QUrl key; - - switch (proxy.type()) { - case QNetworkProxy::Socks5Proxy: - key.setScheme(QLatin1String("proxy-socks5")); - break; - - case QNetworkProxy::HttpProxy: - case QNetworkProxy::HttpCachingProxy: - key.setScheme(QLatin1String("proxy-http")); - break; - - case QNetworkProxy::FtpCachingProxy: - key.setScheme(QLatin1String("proxy-ftp")); - break; - - case QNetworkProxy::DefaultProxy: - case QNetworkProxy::NoProxy: - // shouldn't happen - return QByteArray(); - - // no default: - // let there be errors if a new proxy type is added in the future - } - - if (key.scheme().isEmpty()) - // proxy type not handled - return QByteArray(); - - key.setUserName(proxy.user()); - key.setHost(proxy.hostName()); - key.setPort(proxy.port()); - key.setFragment(realm); - return "auth:" + key.toEncoded(); -} -#endif - -static inline QByteArray authenticationKey(const QUrl &url, const QString &realm) -{ - QUrl copy = url; - copy.setFragment(realm); - return "auth:" + copy.toEncoded(QUrl::RemovePassword | QUrl::RemovePath | QUrl::RemoveQuery); -} /*! Constructs a QNetworkAccessManager object that is the center of @@ -1124,10 +1025,10 @@ void QNetworkAccessManagerPrivate::authenticationRequired(QNetworkAccessBackend // also called when last URL is empty, e.g. on first call if (backend->reply->urlForLastAuthentication.isEmpty() || url != backend->reply->urlForLastAuthentication) { - QNetworkAuthenticationCredential *cred = fetchCachedCredentials(url, authenticator); - if (cred) { - authenticator->setUser(cred->user); - authenticator->setPassword(cred->password); + QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedCredentials(url, authenticator); + if (!cred.isNull()) { + authenticator->setUser(cred.user); + authenticator->setPassword(cred.password); backend->reply->urlForLastAuthentication = url; return; } @@ -1140,7 +1041,7 @@ void QNetworkAccessManagerPrivate::authenticationRequired(QNetworkAccessBackend backend->reply->urlForLastAuthentication = url; emit q->authenticationRequired(backend->reply->q_func(), authenticator); - cacheCredentials(url, authenticator); + authenticationManager->cacheCredentials(url, authenticator); } #ifndef QT_NO_NETWORKPROXY @@ -1157,10 +1058,10 @@ void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(QNetworkAccessBac // possible solution: some tracking inside the authenticator // or a new function proxyAuthenticationSucceeded(true|false) if (proxy != backend->reply->lastProxyAuthentication) { - QNetworkAuthenticationCredential *cred = fetchCachedProxyCredentials(proxy); - if (cred) { - authenticator->setUser(cred->user); - authenticator->setPassword(cred->password); + QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedProxyCredentials(proxy); + if (!cred.isNull()) { + authenticator->setUser(cred.user); + authenticator->setPassword(cred.password); return; } } @@ -1172,75 +1073,7 @@ void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(QNetworkAccessBac backend->reply->lastProxyAuthentication = proxy; emit q->proxyAuthenticationRequired(proxy, authenticator); - cacheProxyCredentials(proxy, authenticator); -} - -void QNetworkAccessManagerPrivate::cacheProxyCredentials(const QNetworkProxy &p, - const QAuthenticator *authenticator) -{ - Q_ASSERT(authenticator); - Q_ASSERT(p.type() != QNetworkProxy::DefaultProxy); - Q_ASSERT(p.type() != QNetworkProxy::NoProxy); - - QString realm = authenticator->realm(); - QNetworkProxy proxy = p; - proxy.setUser(authenticator->user()); - // Set two credentials: one with the username and one without - do { - // Set two credentials actually: one with and one without the realm - do { - QByteArray cacheKey = proxyAuthenticationKey(proxy, realm); - if (cacheKey.isEmpty()) - return; // should not happen - - QNetworkAuthenticationCache *auth = new QNetworkAuthenticationCache; - auth->insert(QString(), authenticator->user(), authenticator->password()); - objectCache.addEntry(cacheKey, auth); // replace the existing one, if there's any - - if (realm.isEmpty()) { - break; - } else { - realm.clear(); - } - } while (true); - - if (proxy.user().isEmpty()) - break; - else - proxy.setUser(QString()); - } while (true); -} - -QNetworkAuthenticationCredential * -QNetworkAccessManagerPrivate::fetchCachedProxyCredentials(const QNetworkProxy &p, - const QAuthenticator *authenticator) -{ - QNetworkProxy proxy = p; - if (proxy.type() == QNetworkProxy::DefaultProxy) { - proxy = QNetworkProxy::applicationProxy(); - } - if (!proxy.password().isEmpty()) - return 0; // no need to set credentials if it already has them - - QString realm; - if (authenticator) - realm = authenticator->realm(); - - QByteArray cacheKey = proxyAuthenticationKey(proxy, realm); - if (cacheKey.isEmpty()) - return 0; - if (!objectCache.hasEntry(cacheKey)) - return 0; - - QNetworkAuthenticationCache *auth = - static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey)); - QNetworkAuthenticationCredential *cred = auth->findClosestMatch(QString()); - objectCache.releaseEntry(cacheKey); - - // proxy cache credentials always have exactly one item - Q_ASSERT_X(cred, "QNetworkAccessManager", - "Internal inconsistency: found a cache key for a proxy, but it's empty"); - return cred; + authenticationManager->cacheProxyCredentials(proxy, authenticator); } QList<QNetworkProxy> QNetworkAccessManagerPrivate::queryProxy(const QNetworkProxyQuery &query) @@ -1264,77 +1097,25 @@ QList<QNetworkProxy> QNetworkAccessManagerPrivate::queryProxy(const QNetworkProx } #endif -void QNetworkAccessManagerPrivate::cacheCredentials(const QUrl &url, - const QAuthenticator *authenticator) -{ - Q_ASSERT(authenticator); - QString domain = QString::fromLatin1("/"); // FIXME: make QAuthenticator return the domain - QString realm = authenticator->realm(); - - // Set two credentials actually: one with and one without the username in the URL - QUrl copy = url; - copy.setUserName(authenticator->user()); - do { - QByteArray cacheKey = authenticationKey(copy, realm); - if (objectCache.hasEntry(cacheKey)) { - QNetworkAuthenticationCache *auth = - static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey)); - auth->insert(domain, authenticator->user(), authenticator->password()); - objectCache.releaseEntry(cacheKey); - } else { - QNetworkAuthenticationCache *auth = new QNetworkAuthenticationCache; - auth->insert(domain, authenticator->user(), authenticator->password()); - objectCache.addEntry(cacheKey, auth); - } - - if (copy.userName().isEmpty()) { - break; - } else { - copy.setUserName(QString()); - } - } while (true); -} - -/*! - Fetch the credential data from the credential cache. - - If auth is 0 (as it is when called from createRequest()), this will try to - look up with an empty realm. That fails in most cases for HTTP (because the - realm is seldom empty for HTTP challenges). In any case, QHttpNetworkConnection - never sends the credentials on the first attempt: it needs to find out what - authentication methods the server supports. - - For FTP, realm is always empty. -*/ -QNetworkAuthenticationCredential * -QNetworkAccessManagerPrivate::fetchCachedCredentials(const QUrl &url, - const QAuthenticator *authentication) -{ - if (!url.password().isEmpty()) - return 0; // no need to set credentials if it already has them - - QString realm; - if (authentication) - realm = authentication->realm(); - - QByteArray cacheKey = authenticationKey(url, realm); - if (!objectCache.hasEntry(cacheKey)) - return 0; - - QNetworkAuthenticationCache *auth = - static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey)); - QNetworkAuthenticationCredential *cred = auth->findClosestMatch(url.path()); - objectCache.releaseEntry(cacheKey); - return cred; -} - void QNetworkAccessManagerPrivate::clearCache(QNetworkAccessManager *manager) { manager->d_func()->objectCache.clear(); + manager->d_func()->authenticationManager->clearCache(); + + if (manager->d_func()->httpThread) { + // The thread will deleteLater() itself from its finished() signal + manager->d_func()->httpThread->quit(); + manager->d_func()->httpThread = 0; + } } QNetworkAccessManagerPrivate::~QNetworkAccessManagerPrivate() { + if (httpThread) { + // The thread will deleteLater() itself from its finished() signal + httpThread->quit(); + httpThread = 0; + } } #ifndef QT_NO_BEARERMANAGEMENT |