summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp5
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp1
-rw-r--r--src/network/access/qhttpthreaddelegate.cpp5
-rw-r--r--tests/auto/qnetworkreply/tst_qnetworkreply.cpp89
4 files changed, 92 insertions, 8 deletions
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 4f2145e..0365703 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -387,6 +387,11 @@ bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket
// send any pending requests
copyCredentials(i, auth, isProxy);
}
+ } 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 reply->cacheCredentials(reply->request(), auth);
}
// - 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
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 9b2a6e8..15fda34 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -201,7 +201,6 @@ bool QHttpNetworkConnectionChannel::sendRequest()
|| (!url.password().isEmpty() && url.password() != auth.password())) {
auth.setUser(url.userName());
auth.setPassword(url.password());
- emit reply->cacheCredentials(request, &auth);
connection->d_func()->copyCredentials(connection->d_func()->indexOf(socket), &auth, false);
}
// clear the userinfo, since we use the same request for resending
diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp
index 092fa7d..68c2292 100644
--- a/src/network/access/qhttpthreaddelegate.cpp
+++ b/src/network/access/qhttpthreaddelegate.cpp
@@ -312,8 +312,6 @@ void QHttpThreadDelegate::startRequest()
// some signals are only interesting when normal asynchronous style is used
connect(httpReply,SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
connect(httpReply,SIGNAL(dataReadProgress(int, int)), this, SLOT(dataReadProgressSlot(int,int)));
- connect(httpReply, SIGNAL(cacheCredentials(QHttpNetworkRequest,QAuthenticator*)),
- this, SLOT(cacheCredentialsSlot(QHttpNetworkRequest,QAuthenticator*)));
#ifndef QT_NO_OPENSSL
connect(httpReply,SIGNAL(sslErrors(const QList<QSslError>)), this, SLOT(sslErrorsSlot(QList<QSslError>)));
#endif
@@ -325,6 +323,9 @@ void QHttpThreadDelegate::startRequest()
connect(httpReply, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
this, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
}
+
+ connect(httpReply, SIGNAL(cacheCredentials(QHttpNetworkRequest,QAuthenticator*)),
+ this, SLOT(cacheCredentialsSlot(QHttpNetworkRequest,QAuthenticator*)));
}
// This gets called from the user thread or by the synchronous HTTP timeout timer
diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
index 3d1e35e..9df820a 100644
--- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
+++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp
@@ -378,6 +378,7 @@ private Q_SLOTS:
void httpAbort();
void dontInsertPartialContentIntoTheCache();
+ void synchronousAuthenticationCache();
// NOTE: This test must be last!
void parentingRepliesToTheApp();
@@ -499,6 +500,14 @@ protected:
client->setParent(this);
++totalConnections;
}
+
+ virtual void reply() {
+ // we need to emulate the bytesWrittenSlot call if the data is empty.
+ if (dataToTransmit.size() == 0)
+ QMetaObject::invokeMethod(this, "bytesWrittenSlot", Qt::QueuedConnection);
+ else
+ client->write(dataToTransmit);
+ }
private:
void connectSocketSignals()
{
@@ -532,11 +541,7 @@ public slots:
if (multiple)
receivedData.remove(0, doubleEndlPos+4);
- // we need to emulate the bytesWrittenSlot call if the data is empty.
- if (dataToTransmit.size() == 0)
- QMetaObject::invokeMethod(this, "bytesWrittenSlot", Qt::QueuedConnection);
- else
- client->write(dataToTransmit);
+ reply();
}
}
@@ -6344,6 +6349,80 @@ void tst_QNetworkReply::dontInsertPartialContentIntoTheCache()
QCOMPARE(memoryCache->m_insertedUrls.count(), 0);
}
+void tst_QNetworkReply::synchronousAuthenticationCache()
+{
+ class MiniAuthServer : public MiniHttpServer {
+ public:
+ MiniAuthServer(QThread *thread) : MiniHttpServer(QByteArray(), false, thread) {};
+ virtual void reply() {
+
+ dataToTransmit =
+ "HTTP/1.0 401 Unauthorized\r\n"
+ "WWW-Authenticate: Basic realm=\"QNetworkAccessManager Test Realm\"\r\n"
+ "Content-Length: 4\r\n"
+ "Connection: close\r\n"
+ "Content-Type: text/plain\r\n"
+ "\r\n"
+ "auth";
+ QRegExp rx("Authorization: Basic ([^\r\n]*)\r\n");
+ if (rx.indexIn(receivedData) > 0) {
+ if (QByteArray::fromBase64(rx.cap(1).toLatin1()) == "login:password") {
+ dataToTransmit =
+ "HTTP/1.0 200 OK\r\n"
+ "Content-Type: text/plain\r\n"
+ "Content-Length: 2\r\n"
+ "\r\n"
+ "OK";
+ }
+ }
+ receivedData.clear();
+ MiniHttpServer::reply();
+ }
+ };
+
+ // when using synchronous commands, we need a different event loop for
+ // the server thread, because the client is never returning to the
+ // event loop
+ QScopedPointer<QThread, QThreadCleanup> serverThread(new QThread);
+ QScopedPointer<MiniHttpServer, QDeleteLaterCleanup> server(new MiniAuthServer(serverThread.data()));
+ server->doClose = true;
+
+ //1) URL without credentials, we are not authenticated
+ {
+ QUrl url = "http://localhost:" + QString::number(server->serverPort()) + "/path";
+ QNetworkRequest request(url);
+ request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
+
+ QNetworkReplyPtr reply = manager.get(request);
+ QVERIFY(reply->isFinished());
+ QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
+ }
+
+ //2) URL with credentials, we are authenticated
+ {
+ QUrl url = "http://login:password@localhost:" + QString::number(server->serverPort()) + "/path2";
+ QNetworkRequest request(url);
+ request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
+
+ QNetworkReplyPtr reply = manager.get(request);
+ QVERIFY(reply->isFinished());
+ QCOMPARE(reply->error(), QNetworkReply::NoError);
+ QCOMPARE(reply->readAll().constData(), "OK");
+ }
+
+ //3) URL without credentials, we are authenticated because they are cached
+ {
+ QUrl url = "http://localhost:" + QString::number(server->serverPort()) + "/path3";
+ QNetworkRequest request(url);
+ request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, true);
+
+ QNetworkReplyPtr reply = manager.get(request);
+ QVERIFY(reply->isFinished());
+ QCOMPARE(reply->error(), QNetworkReply::NoError);
+ QCOMPARE(reply->readAll().constData(), "OK");
+ }
+}
+
// NOTE: This test must be last testcase in tst_qnetworkreply!
void tst_QNetworkReply::parentingRepliesToTheApp()
{