diff options
author | Qt Continuous Integration System <qt-info@nokia.com> | 2012-01-05 09:04:56 (GMT) |
---|---|---|
committer | Qt Continuous Integration System <qt-info@nokia.com> | 2012-01-05 09:04:56 (GMT) |
commit | 218ef02b6e3995f9dd01aafb6a41fe90e68b32e2 (patch) | |
tree | 3593584557ff594372dde11f92fd545a4b1e909b /src/network | |
parent | e87db399c27bfd325fb502b7b30db1dce9b87fa5 (diff) | |
parent | 450478d8281f54003c546b0e67bb61948c46207d (diff) | |
download | Qt-218ef02b6e3995f9dd01aafb6a41fe90e68b32e2.zip Qt-218ef02b6e3995f9dd01aafb6a41fe90e68b32e2.tar.gz Qt-218ef02b6e3995f9dd01aafb6a41fe90e68b32e2.tar.bz2 |
Merge branch 'master' of scm.dev.nokia.troll.no:qt/qt-symbian-staging into master-integration
* 'master' of scm.dev.nokia.troll.no:qt/qt-symbian-staging:
Fix http authentication to a different realm on the same server
Fix race in http connection channel
Don't fetch credentials from cache following a failed proxy authentication
Handle plain socket write errors in SSL
Fix for assertion failure
Fix faulty logic in http connection pipelining
Test case for QTBUG-22875
QThreads on Symbian are named to allow them to be opened externally
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/access/qhttpnetworkconnection.cpp | 25 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkconnectionchannel.cpp | 15 | ||||
-rw-r--r-- | src/network/access/qhttpnetworkconnectionchannel_p.h | 2 | ||||
-rw-r--r-- | src/network/access/qnetworkaccessauthenticationmanager.cpp | 5 | ||||
-rw-r--r-- | src/network/access/qnetworkaccessauthenticationmanager_p.h | 2 | ||||
-rw-r--r-- | src/network/access/qnetworkaccessmanager.cpp | 12 | ||||
-rw-r--r-- | src/network/kernel/qauthenticator.cpp | 7 | ||||
-rw-r--r-- | src/network/kernel/qauthenticator_p.h | 1 | ||||
-rw-r--r-- | src/network/socket/qhttpsocketengine.cpp | 20 | ||||
-rw-r--r-- | src/network/socket/qhttpsocketengine_p.h | 1 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_openssl.cpp | 11 |
11 files changed, 78 insertions, 23 deletions
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 0365703..33e3be9 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -375,9 +375,23 @@ bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket if (priv->phase == QAuthenticatorPrivate::Done) { pauseConnection(); if (!isProxy) { + if (channels[i].authenticationCredentialsSent) { + auth->detach(); + priv = QAuthenticatorPrivate::getPrivate(*auth); + priv->hasFailed = true; + priv->phase = QAuthenticatorPrivate::Done; + channels[i].authenticationCredentialsSent = false; + } emit reply->authenticationRequired(reply->request(), auth); #ifndef QT_NO_NETWORKPROXY } else { + if (channels[i].proxyCredentialsSent) { + auth->detach(); + priv = QAuthenticatorPrivate::getPrivate(*auth); + priv->hasFailed = true; + priv->phase = QAuthenticatorPrivate::Done; + channels[i].proxyCredentialsSent = false; + } emit reply->proxyAuthenticationRequired(networkProxy, auth); #endif } @@ -415,7 +429,6 @@ bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket reply->d_func()->errorString = errorDetail(errorCode, socket); emit reply->finishedWithError(errorCode, reply->d_func()->errorString); // ### at this point the reply could be deleted - socket->close(); return true; } //resend the request @@ -438,6 +451,7 @@ void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket, if (priv && priv->method != QAuthenticatorPrivate::None) { QByteArray response = priv->calculateResponse(request.d->methodName(), request.d->uri(false)); request.setHeaderField("Authorization", response); + channels[i].authenticationCredentialsSent = true; } } } @@ -449,6 +463,7 @@ void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket, if (priv && priv->method != QAuthenticatorPrivate::None) { QByteArray response = priv->calculateResponse(request.d->methodName(), request.d->uri(false)); request.setHeaderField("Proxy-Authorization", response); + channels[i].proxyCredentialsSent = true; } } } @@ -582,9 +597,13 @@ void QHttpNetworkConnectionPrivate::fillPipeline(QAbstractSocket *socket) // we do not like authentication stuff // ### make sure to be OK with this in later releases - if (!channels[i].authenticator.isNull() || !channels[i].authenticator.user().isEmpty()) + if (!channels[i].authenticator.isNull() + && (!channels[i].authenticator.user().isEmpty() + || !channels[i].authenticator.password().isEmpty())) return; - if (!channels[i].proxyAuthenticator.isNull() || !channels[i].proxyAuthenticator.user().isEmpty()) + if (!channels[i].proxyAuthenticator.isNull() + && (!channels[i].proxyAuthenticator.user().isEmpty() + || !channels[i].proxyAuthenticator.password().isEmpty())) return; // must be in ReadingState or WaitingState diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index b9db7fe..628114a 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -73,6 +73,8 @@ QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel() , lastStatus(0) , pendingEncrypt(false) , reconnectAttempts(2) + , authenticationCredentialsSent(false) + , proxyCredentialsSent(false) , authMethod(QAuthenticatorPrivate::None) , proxyAuthMethod(QAuthenticatorPrivate::None) #ifndef QT_NO_OPENSSL @@ -555,6 +557,14 @@ bool QHttpNetworkConnectionChannel::ensureConnection() // reset state pipeliningSupported = PipeliningSupportUnknown; + authenticationCredentialsSent = false; + proxyCredentialsSent = false; + authenticator.detach(); + QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(authenticator); + priv->hasFailed = false; + proxyAuthenticator.detach(); + priv = QAuthenticatorPrivate::getPrivate(proxyAuthenticator); + priv->hasFailed = false; // This workaround is needed since we use QAuthenticator for NTLM authentication. The "phase == Done" // is the usual criteria for emitting authentication signals. The "phase" is set to "Done" when the @@ -562,7 +572,7 @@ bool QHttpNetworkConnectionChannel::ensureConnection() // check the "phase" for generating the Authorization header. NTLM authentication is a two stage // process & needs the "phase". To make sure the QAuthenticator uses the current username/password // the phase is reset to Start. - QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(authenticator); + priv = QAuthenticatorPrivate::getPrivate(authenticator); if (priv && priv->phase == QAuthenticatorPrivate::Done) priv->phase = QAuthenticatorPrivate::Start; priv = QAuthenticatorPrivate::getPrivate(proxyAuthenticator); @@ -837,6 +847,9 @@ void QHttpNetworkConnectionChannel::handleStatus() closeAndResendCurrentRequest(); QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); } + } else { + //authentication cancelled, close the channel. + close(); } } else { emit reply->headerChanged(); diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h index f635cc9..31a286b 100644 --- a/src/network/access/qhttpnetworkconnectionchannel_p.h +++ b/src/network/access/qhttpnetworkconnectionchannel_p.h @@ -113,6 +113,8 @@ public: QAuthenticatorPrivate::Method proxyAuthMethod; QAuthenticator authenticator; QAuthenticator proxyAuthenticator; + bool authenticationCredentialsSent; + bool proxyCredentialsSent; #ifndef QT_NO_OPENSSL bool ignoreAllSslErrors; QList<QSslError> ignoreSslErrorsList; diff --git a/src/network/access/qnetworkaccessauthenticationmanager.cpp b/src/network/access/qnetworkaccessauthenticationmanager.cpp index b618ccc..9551b76 100644 --- a/src/network/access/qnetworkaccessauthenticationmanager.cpp +++ b/src/network/access/qnetworkaccessauthenticationmanager.cpp @@ -159,6 +159,11 @@ void QNetworkAccessAuthenticationManager::cacheProxyCredentials(const QNetworkPr QString realm = authenticator->realm(); QNetworkProxy proxy = p; proxy.setUser(authenticator->user()); + + // don't cache null passwords, empty password may be valid though + if (authenticator->password().isNull()) + return; + // Set two credentials: one with the username and one without do { // Set two credentials actually: one with and one without the realm diff --git a/src/network/access/qnetworkaccessauthenticationmanager_p.h b/src/network/access/qnetworkaccessauthenticationmanager_p.h index ddfc116..718c58f 100644 --- a/src/network/access/qnetworkaccessauthenticationmanager_p.h +++ b/src/network/access/qnetworkaccessauthenticationmanager_p.h @@ -73,7 +73,7 @@ public: QString user; QString password; bool isNull() { - return domain.isNull(); + return domain.isNull() && user.isNull() && password.isNull(); } }; Q_DECLARE_TYPEINFO(QNetworkAuthenticationCredential, Q_MOVABLE_TYPE); diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 8fc8eb7..689441e 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -61,7 +61,7 @@ #include "QtCore/qbuffer.h" #include "QtCore/qurl.h" #include "QtCore/qvector.h" -#include "QtNetwork/qauthenticator.h" +#include "QtNetwork/private/qauthenticator_p.h" #include "QtNetwork/qsslconfiguration.h" #include "QtNetwork/qnetworkconfigmanager.h" #include "QtNetwork/qhttpmultipart.h" @@ -1093,14 +1093,8 @@ void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(QNetworkAccessBac QAuthenticator *authenticator) { Q_Q(QNetworkAccessManager); - // ### FIXME Tracking of successful authentications - // This code is a bit broken right now for SOCKS authentication - // first request: proxyAuthenticationRequired gets emitted, credentials gets saved - // second request: (proxy != backend->reply->lastProxyAuthentication) does not evaluate to true, - // proxyAuthenticationRequired gets emitted again - // possible solution: some tracking inside the authenticator - // or a new function proxyAuthenticationSucceeded(true|false) - if (proxy != backend->reply->lastProxyAuthentication) { + QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(*authenticator); + if (proxy != backend->reply->lastProxyAuthentication && (!priv || !priv->hasFailed)) { QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedProxyCredentials(proxy); if (!cred.isNull()) { authenticator->setUser(cred.user); diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp index 7b63567..d0524ee 100644 --- a/src/network/kernel/qauthenticator.cpp +++ b/src/network/kernel/qauthenticator.cpp @@ -326,6 +326,7 @@ bool QAuthenticator::isNull() const QAuthenticatorPrivate::QAuthenticatorPrivate() : ref(0) , method(None) + , hasFailed(false) , phase(Start) , nonceCount(0) { @@ -387,8 +388,7 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByt switch(method) { case Basic: - if(realm.isEmpty()) - this->options[QLatin1String("realm")] = realm = QString::fromLatin1(options.value("realm")); + this->options[QLatin1String("realm")] = realm = QString::fromLatin1(options.value("realm")); if (user.isEmpty() && password.isEmpty()) phase = Done; break; @@ -396,8 +396,7 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByt // #### extract from header break; case DigestMd5: { - if(realm.isEmpty()) - this->options[QLatin1String("realm")] = realm = QString::fromLatin1(options.value("realm")); + this->options[QLatin1String("realm")] = realm = QString::fromLatin1(options.value("realm")); if (options.value("stale").toLower() == "true") phase = Start; if (user.isEmpty() && password.isEmpty()) diff --git a/src/network/kernel/qauthenticator_p.h b/src/network/kernel/qauthenticator_p.h index 88a3051..937f4e0 100644 --- a/src/network/kernel/qauthenticator_p.h +++ b/src/network/kernel/qauthenticator_p.h @@ -77,6 +77,7 @@ public: Method method; QString realm; QByteArray challenge; + bool hasFailed; //credentials have been tried but rejected by server. enum Phase { Start, diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp index b62bc05..c582c57 100644 --- a/src/network/socket/qhttpsocketengine.cpp +++ b/src/network/socket/qhttpsocketengine.cpp @@ -136,6 +136,8 @@ bool QHttpSocketEngine::connectInternal() { Q_D(QHttpSocketEngine); + d->credentialsSent = false; + // If the handshake is done, enter ConnectedState state and return true. if (d->state == Connected) { qWarning("QHttpSocketEngine::connectToHost: called when already connected"); @@ -514,6 +516,7 @@ void QHttpSocketEngine::slotSocketConnected() QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(d->authenticator); //qDebug() << "slotSocketConnected: priv=" << priv << (priv ? (int)priv->method : -1); if (priv && priv->method != QAuthenticatorPrivate::None) { + d->credentialsSent = true; data += "Proxy-Authorization: " + priv->calculateResponse(method, path); data += "\r\n"; } @@ -591,15 +594,26 @@ void QHttpSocketEngine::slotSocketReadNotification() d->readBuffer.clear(); // we parsed the proxy protocol response. from now on direct socket reading will be done int statusCode = responseHeader.statusCode(); + QAuthenticatorPrivate *priv = 0; if (statusCode == 200) { d->state = Connected; setLocalAddress(d->socket->localAddress()); setLocalPort(d->socket->localPort()); setState(QAbstractSocket::ConnectedState); + d->authenticator.detach(); + priv = QAuthenticatorPrivate::getPrivate(d->authenticator); + priv->hasFailed = false; } else if (statusCode == 407) { - if (d->authenticator.isNull()) + if (d->credentialsSent) { + //407 response again means the provided username/password were invalid. + d->authenticator = QAuthenticator(); //this is needed otherwise parseHttpResponse won't set the state, and then signal isn't emitted. + d->authenticator.detach(); + priv = QAuthenticatorPrivate::getPrivate(d->authenticator); + priv->hasFailed = true; + } + else if (d->authenticator.isNull()) d->authenticator.detach(); - QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(d->authenticator); + priv = QAuthenticatorPrivate::getPrivate(d->authenticator); priv->parseHttpResponse(responseHeader, true); @@ -639,7 +653,6 @@ void QHttpSocketEngine::slotSocketReadNotification() if (priv->phase == QAuthenticatorPrivate::Done) emit proxyAuthenticationRequired(d->proxy, &d->authenticator); - // priv->phase will get reset to QAuthenticatorPrivate::Start if the authenticator got modified in the signal above. if (priv->phase == QAuthenticatorPrivate::Done) { setError(QAbstractSocket::ProxyAuthenticationRequiredError, tr("Authentication required")); @@ -796,6 +809,7 @@ QHttpSocketEnginePrivate::QHttpSocketEnginePrivate() , readNotificationPending(false) , writeNotificationPending(false) , connectionNotificationPending(false) + , credentialsSent(false) , pendingResponseData(0) { socket = 0; diff --git a/src/network/socket/qhttpsocketengine_p.h b/src/network/socket/qhttpsocketengine_p.h index d7cc7c1..476d689 100644 --- a/src/network/socket/qhttpsocketengine_p.h +++ b/src/network/socket/qhttpsocketengine_p.h @@ -182,6 +182,7 @@ public: bool readNotificationPending; bool writeNotificationPending; bool connectionNotificationPending; + bool credentialsSent; uint pendingResponseData; }; diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 652bcbd..e432865 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -1040,10 +1040,17 @@ void QSslSocketBackendPrivate::transmit() int encryptedBytesRead = q_BIO_read(writeBio, data.data(), pendingBytes); // Write encrypted data from the buffer to the socket. - plainSocket->write(data.constData(), encryptedBytesRead); + qint64 actualWritten = plainSocket->write(data.constData(), encryptedBytesRead); #ifdef QSSLSOCKET_DEBUG - qDebug() << "QSslSocketBackendPrivate::transmit: wrote" << encryptedBytesRead << "encrypted bytes to the socket"; + qDebug() << "QSslSocketBackendPrivate::transmit: wrote" << encryptedBytesRead << "encrypted bytes to the socket" << actualWritten << "actual."; #endif + if (actualWritten < 0) { + //plain socket write fails if it was in the pending close state. + q->setErrorString(plainSocket->errorString()); + q->setSocketError(plainSocket->error()); + emit q->error(plainSocket->error()); + return; + } transmitting = true; } |