summaryrefslogtreecommitdiffstats
path: root/src/network/access/qhttpnetworkconnection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/access/qhttpnetworkconnection.cpp')
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp157
1 files changed, 77 insertions, 80 deletions
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 2ab28c7..1ef58d8 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -39,6 +39,7 @@
**
****************************************************************************/
+#include <private/qabstractsocket_p.h>
#include "qhttpnetworkconnection_p.h"
#include "qhttpnetworkconnectionchannel_p.h"
#include "private/qnoncontiguousbytedevice_p.h"
@@ -56,6 +57,7 @@
#ifndef QT_NO_HTTP
#ifndef QT_NO_OPENSSL
+# include <private/qsslsocket_p.h>
# include <QtNetwork/qsslkey.h>
# include <QtNetwork/qsslcipher.h>
# include <QtNetwork/qsslconfiguration.h>
@@ -79,9 +81,9 @@ const int QHttpNetworkConnectionPrivate::defaultRePipelineLength = 2;
QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &hostName, quint16 port, bool encrypt)
-: hostName(hostName), port(port), encrypt(encrypt),
- channelCount(defaultChannelCount),
- pendingAuthSignal(false), pendingProxyAuthSignal(false)
+: state(RunningState),
+ hostName(hostName), port(port), encrypt(encrypt),
+ channelCount(defaultChannelCount)
#ifndef QT_NO_NETWORKPROXY
, networkProxy(QNetworkProxy::NoProxy)
#endif
@@ -90,9 +92,9 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &host
}
QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(quint16 channelCount, const QString &hostName, quint16 port, bool encrypt)
-: hostName(hostName), port(port), encrypt(encrypt),
- channelCount(channelCount),
- pendingAuthSignal(false), pendingProxyAuthSignal(false)
+: state(RunningState),
+ hostName(hostName), port(port), encrypt(encrypt),
+ channelCount(channelCount)
#ifndef QT_NO_NETWORKPROXY
, networkProxy(QNetworkProxy::NoProxy)
#endif
@@ -122,6 +124,42 @@ void QHttpNetworkConnectionPrivate::init()
}
}
+void QHttpNetworkConnectionPrivate::pauseConnection()
+{
+ state = PausedState;
+
+ // Disable all socket notifiers
+ for (int i = 0; i < channelCount; i++) {
+#ifndef QT_NO_OPENSSL
+ if (encrypt)
+ QSslSocketPrivate::pauseSocketNotifiers(static_cast<QSslSocket*>(channels[i].socket));
+ else
+#endif
+ QAbstractSocketPrivate::pauseSocketNotifiers(channels[i].socket);
+ }
+}
+
+void QHttpNetworkConnectionPrivate::resumeConnection()
+{
+ state = RunningState;
+ // Enable all socket notifiers
+ for (int i = 0; i < channelCount; i++) {
+#ifndef QT_NO_OPENSSL
+ if (encrypt)
+ QSslSocketPrivate::resumeSocketNotifiers(static_cast<QSslSocket*>(channels[i].socket));
+ else
+#endif
+ QAbstractSocketPrivate::resumeSocketNotifiers(channels[i].socket);
+
+ // Resume pending upload if needed
+ if (channels[i].state == QHttpNetworkConnectionChannel::WritingState)
+ QMetaObject::invokeMethod(&channels[i], "_q_uploadDataReadyRead", Qt::QueuedConnection);
+ }
+
+ // queue _q_startNextRequest
+ QMetaObject::invokeMethod(this->q_func(), "_q_startNextRequest", Qt::QueuedConnection);
+}
+
int QHttpNetworkConnectionPrivate::indexOf(QAbstractSocket *socket) const
{
for (int i = 0; i < channelCount; ++i)
@@ -258,6 +296,13 @@ void QHttpNetworkConnectionPrivate::copyCredentials(int fromChannel, QAuthentica
{
Q_ASSERT(auth);
+ // NTLM is a multi phase authentication. Copying credentials between authenticators would mess things up.
+ if (!isProxy && channels[fromChannel].authMethod == QAuthenticatorPrivate::Ntlm)
+ return;
+ if (isProxy && channels[fromChannel].proxyAuthMethod == QAuthenticatorPrivate::Ntlm)
+ return;
+
+
// select another channel
QAuthenticator* otherAuth = 0;
for (int i = 0; i < channelCount; ++i) {
@@ -297,10 +342,10 @@ bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket
QAuthenticator* auth = 0;
if (isProxy) {
auth = &channels[i].proxyAuthenticator;
- channels[i].proxyAuthMehtod = authMethod;
+ channels[i].proxyAuthMethod = authMethod;
} else {
auth = &channels[i].authenticator;
- channels[i].authMehtod = authMethod;
+ channels[i].authMethod = authMethod;
}
//proceed with the authentication.
if (auth->isNull())
@@ -309,43 +354,23 @@ bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket
priv->parseHttpResponse(fields, isProxy);
if (priv->phase == QAuthenticatorPrivate::Done) {
- if ((isProxy && pendingProxyAuthSignal) ||(!isProxy && pendingAuthSignal)) {
- // drop the request
- reply->d_func()->eraseData();
- channels[i].close();
- channels[i].lastStatus = 0;
- channels[i].state = QHttpNetworkConnectionChannel::Wait4AuthState;
- return false;
- }
- // cannot use this socket until the slot returns
- channels[i].state = QHttpNetworkConnectionChannel::WaitingState;
- socket->blockSignals(true);
+ pauseConnection();
if (!isProxy) {
- pendingAuthSignal = true;
- emit q->authenticationRequired(reply->request(), auth, q);
- pendingAuthSignal = false;
+ emit reply->authenticationRequired(reply->request(), auth);
#ifndef QT_NO_NETWORKPROXY
} else {
- pendingProxyAuthSignal = true;
- emit q->proxyAuthenticationRequired(networkProxy, auth, q);
- pendingProxyAuthSignal = false;
+ emit reply->proxyAuthenticationRequired(networkProxy, auth);
#endif
}
- socket->blockSignals(false);
- // socket free to use
- channels[i].state = QHttpNetworkConnectionChannel::IdleState;
+ resumeConnection();
+
if (priv->phase != QAuthenticatorPrivate::Done) {
// send any pending requests
copyCredentials(i, auth, isProxy);
- QMetaObject::invokeMethod(q, "_q_restartAuthPendingRequests", Qt::QueuedConnection);
}
- } else if (priv->phase == QAuthenticatorPrivate::Start) {
- // If the url's authenticator has a 'user' set we will end up here (phase is only set to 'Done' by
- // parseHttpResponse above if 'user' is empty). So if credentials were supplied with the request,
- // such as in the case of an XMLHttpRequest, this is our only opportunity to cache them.
- emit q->cacheCredentials(reply->request(), auth, q);
}
- // - Changing values in QAuthenticator will reset the 'phase'.
+ // - Changing values in QAuthenticator will reset the 'phase'. Therefore if it is still "Done"
+ // then nothing was filled in by the user or the cache
// - If withCredentials has been set to false (e.g. by QtWebKit for a cross-origin XMLHttpRequest) then
// we need to bail out if authentication is required.
if (priv->phase == QAuthenticatorPrivate::Done || !reply->request().withCredentials()) {
@@ -357,15 +382,9 @@ bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket
? QNetworkReply::ProxyAuthenticationRequiredError
: QNetworkReply::AuthenticationRequiredError;
reply->d_func()->errorString = errorDetail(errorCode, socket);
- emit q->error(errorCode, reply->d_func()->errorString);
- emit channels[i].reply->finished();
+ emit reply->finishedWithError(errorCode, reply->d_func()->errorString);
// ### at this point the reply could be deleted
socket->close();
- // remove pending request on the other channels
- for (int j = 0; j < channelCount; ++j) {
- if (j != i && channels[j].state == QHttpNetworkConnectionChannel::Wait4AuthState)
- channels[j].state = QHttpNetworkConnectionChannel::IdleState;
- }
return true;
}
//resend the request
@@ -381,8 +400,9 @@ void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket,
int i = indexOf(socket);
- if (channels[i].authMehtod != QAuthenticatorPrivate::None) {
- if (!(channels[i].authMehtod == QAuthenticatorPrivate::Ntlm && channels[i].lastStatus != 401)) {
+ // Send "Authorization" header, but not if it's NTLM and the socket is already authenticated.
+ if (channels[i].authMethod != QAuthenticatorPrivate::None) {
+ if (!(channels[i].authMethod == QAuthenticatorPrivate::Ntlm && channels[i].lastStatus != 401)) {
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(channels[i].authenticator);
if (priv && priv->method != QAuthenticatorPrivate::None) {
QByteArray response = priv->calculateResponse(request.d->methodName(), request.d->uri(false));
@@ -390,8 +410,10 @@ void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket,
}
}
}
- if (channels[i].proxyAuthMehtod != QAuthenticatorPrivate::None) {
- if (!(channels[i].proxyAuthMehtod == QAuthenticatorPrivate::Ntlm && channels[i].lastStatus != 407)) {
+
+ // Send "Proxy-Authorization" header, but not if it's NTLM and the socket is already authenticated.
+ if (channels[i].proxyAuthMethod != QAuthenticatorPrivate::None) {
+ if (!(channels[i].proxyAuthMethod == QAuthenticatorPrivate::Ntlm && channels[i].lastStatus != 407)) {
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(channels[i].proxyAuthenticator);
if (priv && priv->method != QAuthenticatorPrivate::None) {
QByteArray response = priv->calculateResponse(request.d->methodName(), request.d->uri(false));
@@ -726,6 +748,10 @@ void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply)
// although it is called _q_startNextRequest, it will actually start multiple requests when possible
void QHttpNetworkConnectionPrivate::_q_startNextRequest()
{
+ // If the QHttpNetworkConnection is currently paused then bail out immediately
+ if (state == PausedState)
+ return;
+
//resend the necessary ones.
for (int i = 0; i < channelCount; ++i) {
if (channels[i].resendCurrent) {
@@ -776,17 +802,6 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
fillPipeline(channels[i].socket);
}
-void QHttpNetworkConnectionPrivate::_q_restartAuthPendingRequests()
-{
- // send the request using the idle socket
- for (int i = 0 ; i < channelCount; ++i) {
- if (channels[i].state == QHttpNetworkConnectionChannel::Wait4AuthState) {
- channels[i].state = QHttpNetworkConnectionChannel::IdleState;
- if (channels[i].reply)
- channels[i].sendRequest();
- }
- }
-}
void QHttpNetworkConnectionPrivate::readMoreLater(QHttpNetworkReply *reply)
{
@@ -835,33 +850,12 @@ QHttpNetworkReply* QHttpNetworkConnection::sendRequest(const QHttpNetworkRequest
return d->queueRequest(request);
}
-void QHttpNetworkConnection::enableEncryption()
-{
- Q_D(QHttpNetworkConnection);
- d->encrypt = true;
-}
-
bool QHttpNetworkConnection::isEncrypted() const
{
Q_D(const QHttpNetworkConnection);
return d->encrypt;
}
-void QHttpNetworkConnection::setProxyAuthentication(QAuthenticator *authenticator)
-{
- Q_D(QHttpNetworkConnection);
- for (int i = 0; i < d->channelCount; ++i)
- d->channels[i].proxyAuthenticator = *authenticator;
-}
-
-void QHttpNetworkConnection::setAuthentication(const QString &domain, QAuthenticator *authenticator)
-{
- Q_UNUSED(domain); // ### domain ?
- Q_D(QHttpNetworkConnection);
- for (int i = 0; i < d->channelCount; ++i)
- d->channels[i].authenticator = *authenticator;
-}
-
#ifndef QT_NO_NETWORKPROXY
void QHttpNetworkConnection::setCacheProxy(const QNetworkProxy &networkProxy)
{
@@ -954,8 +948,11 @@ void QHttpNetworkConnection::ignoreSslErrors(const QList<QSslError> &errors, int
// e.g. it is for SOCKS proxies which require authentication.
void QHttpNetworkConnectionPrivate::emitProxyAuthenticationRequired(const QHttpNetworkConnectionChannel *chan, const QNetworkProxy &proxy, QAuthenticator* auth)
{
- Q_Q(QHttpNetworkConnection);
- emit q->proxyAuthenticationRequired(proxy, auth, q);
+ // Also pause the connection because socket notifiers may fire while an user
+ // dialog is displaying
+ pauseConnection();
+ emit chan->reply->proxyAuthenticationRequired(proxy, auth);
+ resumeConnection();
int i = indexOf(chan->socket);
copyCredentials(i, auth, true);
}