diff options
author | Timur Pocheptsov <timur.pocheptsov@qt.io> | 2016-12-28 15:27:57 +0100 |
---|---|---|
committer | Timur Pocheptsov <timur.pocheptsov@qt.io> | 2017-01-17 18:51:32 +0000 |
commit | cebf1fea4a6802b8999469f647f52171e87d02b6 (patch) | |
tree | ca858bb7eb3b482d1e555c285b08c0e627497256 /tests/auto/network | |
parent | 27e27966bf01b4c42343100a49b1dd6b014025fe (diff) |
Add redirects policy to QNetworkAccessManager
This patch makes it possible to enable/disable redirects on QNAM
level (before it was per-request only). This policy would be applied
to all subsequent requests* created by QNAM.
The policies we support at the moment:
a. Manual - that's what we always had - it's up to a user to handle
redirects.
b. NoLessSafeRedirectsPolicy - we allow http->http, http->https and
https->https redirects, but no protocol 'downgrade' (no
https->http redirects).
c. SameOriginPolicy - we check that protocol/host/port are
the same.
Updated tst_qnetworkreply.
*We previously were enabling redirect for each request, by
setting FollowRedirectsAttribute on QNetworkRequest object.
For backward compatibility this attribute has a higher priority
(if set) than QNAM's policy (and it will work as NoLessSafeRedirectsPolicy).
[ChangeLog][QtNetwork] Added redirects policy to QNAM
Task-number: QTPM-239
Task-number: QTPM-237
Change-Id: I493d1728254b71b61b5504937e8e01dca5953527
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Diffstat (limited to 'tests/auto/network')
-rw-r--r-- | tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index 32446bcccd..7d07ae888c 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -476,6 +476,10 @@ private Q_SLOTS: void ioHttpChangeMaxRedirects(); void ioHttpRedirectErrors_data(); void ioHttpRedirectErrors(); + void ioHttpRedirectPolicy_data(); + void ioHttpRedirectPolicy(); + void ioHttpRedirectPolicyErrors_data(); + void ioHttpRedirectPolicyErrors(); #ifndef QT_NO_SSL void putWithServerClosingConnectionImmediately(); #endif @@ -8163,6 +8167,171 @@ void tst_QNetworkReply::ioHttpRedirectErrors() QCOMPARE(spy.count(), 1); QCOMPARE(reply->error(), error); } + +struct SameOriginRedirector : MiniHttpServer +{ + SameOriginRedirector(const QByteArray &data, bool ssl = false) + : MiniHttpServer(data, ssl) + { } + + std::vector<QByteArray> responses; + + void reply() override + { + if (responses.empty()) { + dataToTransmit.clear(); + } else { + dataToTransmit = responses.back(); + responses.pop_back(); + } + + MiniHttpServer::reply(); + } +}; + +void tst_QNetworkReply::ioHttpRedirectPolicy_data() +{ + QTest::addColumn<QNetworkRequest::RedirectsPolicy>("policy"); + QTest::addColumn<bool>("ssl"); + QTest::addColumn<int>("redirectCount"); + QTest::addColumn<int>("statusCode"); + + QTest::newRow("manual-nossl") << QNetworkRequest::ManualRedirectsPolicy << false << 0 << 307; + QTest::newRow("manual-ssl") << QNetworkRequest::ManualRedirectsPolicy << true << 0 << 307; + QTest::newRow("nolesssafe-nossl") << QNetworkRequest::NoLessSafeRedirectsPolicy << false << 1 << 200; + QTest::newRow("nolesssafe-ssl") << QNetworkRequest::NoLessSafeRedirectsPolicy << true << 1 << 200; + QTest::newRow("same-origin-nossl") << QNetworkRequest::SameOriginRedirectsPolicy << false << 1 << 200; + QTest::newRow("same-origin-ssl") << QNetworkRequest::SameOriginRedirectsPolicy << true << 1 << 200; +} + +void tst_QNetworkReply::ioHttpRedirectPolicy() +{ + QFETCH(const QNetworkRequest::RedirectsPolicy, policy); + + QFETCH(const bool, ssl); +#ifdef QT_NO_SSL + if (ssl) + QSKIP("SSL is not supported"); +#endif + + QFETCH(const int, redirectCount); + QFETCH(const int, statusCode); + + // Setup HTTP server. + SameOriginRedirector redirectServer("", ssl); + + QUrl url(QLatin1String( +#ifndef QT_NO_SSL + ssl ? "https://localhost" : +#endif + "http://localhost")); + + url.setPort(redirectServer.serverPort()); + redirectServer.responses.push_back("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + redirectServer.responses.push_back(tempRedirectReplyStr().arg(QString(url.toEncoded())).toLatin1()); + + // This is the default one we preserve between tests. + QCOMPARE(manager.redirectsPolicy(), QNetworkRequest::ManualRedirectsPolicy); + + manager.setRedirectsPolicy(policy); + QCOMPARE(manager.redirectsPolicy(), policy); + QNetworkReplyPtr reply(manager.get(QNetworkRequest(url))); + if (ssl) + reply->ignoreSslErrors(); + + // Restore default: + manager.setRedirectsPolicy(QNetworkRequest::ManualRedirectsPolicy); + QSignalSpy redirectSpy(reply.data(), SIGNAL(redirected(QUrl))); + QSignalSpy finishedSpy(reply.data(), SIGNAL(finished())); + QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); + QCOMPARE(finishedSpy.count(), 1); + QCOMPARE(redirectSpy.count(), redirectCount); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), statusCode); +} + +void tst_QNetworkReply::ioHttpRedirectPolicyErrors_data() +{ + QTest::addColumn<QNetworkRequest::RedirectsPolicy>("policy"); + QTest::addColumn<bool>("ssl"); + QTest::addColumn<QString>("location"); + QTest::addColumn<int>("maxRedirects"); + QTest::addColumn<QNetworkReply::NetworkError>("expectedError"); + + // 1. NoLessSafeRedirectsPolicy + QTest::newRow("nolesssafe-nossl-nossl-too-many") << QNetworkRequest::NoLessSafeRedirectsPolicy + << false << QString("http://localhost:%1") << 0 << QNetworkReply::TooManyRedirectsError; + QTest::newRow("nolesssafe-ssl-ssl-too-many") << QNetworkRequest::NoLessSafeRedirectsPolicy + << true << QString("https:/localhost:%1") << 0 << QNetworkReply::TooManyRedirectsError; + QTest::newRow("nolesssafe-ssl-nossl-insecure-redirect") << QNetworkRequest::NoLessSafeRedirectsPolicy + << true << QString("http://localhost:%1") << 50 << QNetworkReply::InsecureRedirectError; + // 2. SameOriginRedirectsPolicy + QTest::newRow("same-origin-nossl-nossl-too-many") << QNetworkRequest::SameOriginRedirectsPolicy + << false << QString("http://localhost:%1") << 0 << QNetworkReply::TooManyRedirectsError; + QTest::newRow("same-origin-ssl-ssl-too-many") << QNetworkRequest::SameOriginRedirectsPolicy + << true << QString("https://localhost:%1") << 0 << QNetworkReply::TooManyRedirectsError; + QTest::newRow("same-origin-https-http-wrong-protocol") << QNetworkRequest::SameOriginRedirectsPolicy + << true << QString("http://localhost:%1") << 50 << QNetworkReply::InsecureRedirectError; + QTest::newRow("same-origin-http-https-wrong-protocol") << QNetworkRequest::SameOriginRedirectsPolicy + << false << QString("https://localhost:%1") << 50 << QNetworkReply::InsecureRedirectError; + QTest::newRow("same-origin-http-http-wrong-host") << QNetworkRequest::SameOriginRedirectsPolicy + << false << QString("http://not-so-localhost:%1") << 50 << QNetworkReply::InsecureRedirectError; + QTest::newRow("same-origin-https-https-wrong-host") << QNetworkRequest::SameOriginRedirectsPolicy + << true << QString("https://not-so-localhost:%1") << 50 << QNetworkReply::InsecureRedirectError; + QTest::newRow("same-origin-http-http-wrong-port") << QNetworkRequest::SameOriginRedirectsPolicy + << false << QString("http://localhost/%1") << 50 << QNetworkReply::InsecureRedirectError; + QTest::newRow("same-origin-https-https-wrong-port") << QNetworkRequest::SameOriginRedirectsPolicy + << true << QString("https://localhost/%1") << 50 << QNetworkReply::InsecureRedirectError; +} + +void tst_QNetworkReply::ioHttpRedirectPolicyErrors() +{ + QFETCH(const QNetworkRequest::RedirectsPolicy, policy); + // This should never happen: + QVERIFY(policy != QNetworkRequest::ManualRedirectsPolicy); + + QFETCH(const bool, ssl); + QFETCH(const QString, location); + QFETCH(const int, maxRedirects); + QFETCH(const QNetworkReply::NetworkError, expectedError); + +#ifdef QT_NO_SSL + if (ssl || location.contains("https")) + QSKIP("SSL required to run this test"); +#endif + + // Setup the server. + MiniHttpServer server("", ssl); + server.setDataToTransmit(tempRedirectReplyStr().arg(location.arg(server.serverPort())).toLatin1()); + + QUrl url(QLatin1String( +#ifndef QT_NO_SSL + ssl ? "https://localhost" : +#endif + "http://localhost")); + url.setPort(server.serverPort()); + + QNetworkRequest request(url); + request.setMaximumRedirectsAllowed(maxRedirects); + // We always reset the policy to the default one ('Manual') after any related + // test is finished: + QCOMPARE(manager.redirectsPolicy(), QNetworkRequest::ManualRedirectsPolicy); + manager.setRedirectsPolicy(policy); + QCOMPARE(manager.redirectsPolicy(), policy); + + QNetworkReplyPtr reply(manager.get(request)); + // Set it back to default: + manager.setRedirectsPolicy(QNetworkRequest::ManualRedirectsPolicy); + + if (ssl) + reply->ignoreSslErrors(); + + QSignalSpy spy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError))); + + QCOMPARE(waitForFinish(reply), int(Failure)); + QCOMPARE(spy.count(), 1); + QCOMPARE(reply->error(), expectedError); +} + #ifndef QT_NO_SSL class PutWithServerClosingConnectionImmediatelyHandler: public QObject |