summaryrefslogtreecommitdiffstats
path: root/tests/auto/core/qwebengineglobalsettings/tst_qwebengineglobalsettings.cpp
blob: 0af85a7114e03ad30fb9a033e472f339f42546d7 (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
// 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 <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()
{
    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(QUrl("https://google.com/"));
    if (!loadSpy.wait(20000)) {
        QSKIP("Couldn't load page from network, skipping test.");
    }

    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"