summaryrefslogtreecommitdiffstats
path: root/tests/auto/core/qwebengineglobalsettings/tst_qwebengineglobalsettings.cpp
blob: 5b6b64778d2f645c786903cd296e899c0c9d9987 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0

#include <QtTest>
#include <widgetutil.h>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QWebEngineProfile>
#include <QWebEnginePage>
#include <QWebEngineGlobalSettings>
#include <QWebEngineLoadingInfo>

#include "httpsserver.h"
#include "httpreqrep.h"

class tst_QWebEngineGlobalSettings : public QObject
{
    Q_OBJECT

public:
    tst_QWebEngineGlobalSettings() { }
    ~tst_QWebEngineGlobalSettings() { }

public Q_SLOTS:
    void init() { }
    void cleanup() { }

private Q_SLOTS:
    void initTestCase() { }
    void cleanupTestCase() { }
    void dnsOverHttps_data();
    void dnsOverHttps();
};

Q_LOGGING_CATEGORY(lc, "qt.webengine.tests")

void tst_QWebEngineGlobalSettings::dnsOverHttps_data()
{
    QTest::addColumn<QWebEngineGlobalSettings::SecureDnsMode>("dnsMode");
    QTest::addColumn<QString>("uriTemplate");
    QTest::addColumn<bool>("isMockDnsServerCalledExpected");
    QTest::addColumn<bool>("isDnsResolutionSuccessExpected");
    QTest::addColumn<bool>("isConfigurationSuccessExpected");
    QTest::newRow("DnsMode::SystemOnly (no DoH server)")
            << QWebEngineGlobalSettings::SecureDnsMode::SystemOnly << QStringLiteral("") << false
            << true << true;
    QTest::newRow("DnsMode::SecureOnly (mock DoH server)")
            << QWebEngineGlobalSettings::SecureDnsMode::SecureOnly
            << QStringLiteral("https://127.0.0.1:3000/dns-query{?dns}") << true << false << true;
    QTest::newRow("DnsMode::SecureOnly (real DoH server)")
            << QWebEngineGlobalSettings::SecureDnsMode::SecureOnly
            << QStringLiteral("https://dns.google/dns-query{?dns}") << false << true << true;
    QTest::newRow("DnsMode::SecureOnly (Empty URI Templates)")
            << QWebEngineGlobalSettings::SecureDnsMode::SecureOnly << QStringLiteral("") << false
            << false << false;
    // Note: In the following test, we can't verify that the DoH server is called first and
    // afterwards insecure DNS is tried, because for the DoH server to ever be used when the DNS
    // mode is set to DnsMode::WithFallback, Chromium starts an asynchronous DoH server DnsProbe and
    // requires that the connection is successful. That is, we'd have to implement a correct
    // DNS response, which in turn requires that certificate errors aren't ignored and
    // non-self-signed certificates are used for correct encryption. Instead of implementing
    // all of that, this test verifies that Chromium tries probing the configured DoH server only.
    QTest::newRow("DnsMode::SecureWithFallback (mock DoH server)")
            << QWebEngineGlobalSettings::SecureDnsMode::SecureWithFallback
            << QStringLiteral("https://127.0.0.1:3000/dns-query{?dns}") << true << true << true;
    QTest::newRow("DnsMode::SecureWithFallback (Empty URI Templates)")
            << QWebEngineGlobalSettings::SecureDnsMode::SecureWithFallback << QStringLiteral("")
            << false << false << false;
}

void tst_QWebEngineGlobalSettings::dnsOverHttps()
{
    const QUrl url = QStringLiteral("https://google.com/");
    // Verify network access with NAM because the result of loadFinished signal
    // is used to verify that the DNS resolution was successful.
    QNetworkAccessManager nam;
    QSignalSpy namSpy(&nam, &QNetworkAccessManager::finished);
    QScopedPointer<QNetworkReply> reply(nam.get(QNetworkRequest(url)));
    if (!namSpy.wait(20000) || reply->error() != QNetworkReply::NoError)
        QSKIP("Couldn't load page from network, skipping test.");

    QFETCH(QWebEngineGlobalSettings::SecureDnsMode, dnsMode);
    QFETCH(QString, uriTemplate);
    QFETCH(bool, isMockDnsServerCalledExpected);
    QFETCH(bool, isDnsResolutionSuccessExpected);
    QFETCH(bool, isConfigurationSuccessExpected);
    bool isMockDnsServerCalled = false;
    bool isLoadSuccessful = false;

    bool configurationSuccess =
            QWebEngineGlobalSettings::setDnsMode({ dnsMode, QStringList{ uriTemplate } });
    QCOMPARE(configurationSuccess, isConfigurationSuccessExpected);

    if (!configurationSuccess) {
        // In this case, DNS has invalid configuration, so the DNS change transaction is not
        // triggered and the result of the DNS resolution depends on the current DNS mode, which is
        // set by the previous run of this function.
        return;
    }
    HttpsServer httpsServer(":/cert/localhost.crt", ":/cert/localhost.key", ":/cert/RootCA.pem",
                            3000, this);
    QObject::connect(&httpsServer, &HttpsServer::newRequest, this,
                     [&isMockDnsServerCalled](HttpReqRep *rr) {
                         QVERIFY(rr->requestPath().contains(QByteArrayLiteral("/dns-query?dns=")));
                         isMockDnsServerCalled = true;
                         rr->close();
                     });
    QVERIFY(httpsServer.start());
    httpsServer.setExpectError(isMockDnsServerCalledExpected);
    httpsServer.setVerifyMode(QSslSocket::PeerVerifyMode::VerifyNone);

    QWebEngineProfile profile;
    QWebEnginePage page(&profile);
    QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool)));

    connect(&page, &QWebEnginePage::loadFinished, this,
            [&isLoadSuccessful](bool ok) { isLoadSuccessful = ok; });

    page.load(url);
    QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 1, 20000);

    QTRY_COMPARE(isMockDnsServerCalled, isMockDnsServerCalledExpected);
    QCOMPARE(isLoadSuccessful, isDnsResolutionSuccessExpected);
    QVERIFY(httpsServer.stop());
}

static QByteArrayList params = QByteArrayList() << "--ignore-certificate-errors";

W_QTEST_MAIN(tst_QWebEngineGlobalSettings, params)
#include "tst_qwebengineglobalsettings.moc"