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
|
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "tlswebserver.h"
#ifndef QT_NO_SSL
#include <QtNetwork/qsslconfiguration.h>
#include <QtNetwork/qsslsocket.h>
#include <QtNetwork/qtcpserver.h>
#include <QtCore/qurl.h>
TlsWebServer::TlsWebServer(Handler h, const QSslConfiguration &config, QObject *parent) :
QSslServer(parent),
handler(h)
{
connect(this, &QSslServer::pendingConnectionAvailable, this, [this]() {
auto socket = nextPendingConnection();
Q_ASSERT(socket);
auto sslSocket = qobject_cast<QSslSocket *>(socket);
Q_ASSERT(sslSocket);
connect(socket, &QTcpSocket::disconnected, socket, &QTcpSocket::deleteLater);
connect(sslSocket, &QSslSocket::sslErrors, this, [sslSocket](const QList<QSslError> &errors) {
qDebug() << errors;
sslSocket->ignoreSslErrors();
});
connect(socket, &QTcpSocket::readyRead, this, [this, socket]() {
if (!clients.contains(socket))
clients[socket].port = serverPort();
auto *request = &clients[socket];
auto ok = true;
while (socket->bytesAvailable()) {
if (Q_LIKELY(request->state == HttpRequest::State::ReadingMethod))
if (Q_UNLIKELY(!(ok = request->readMethod(socket))))
qWarning("Invalid Method");
if (Q_LIKELY(ok && request->state == HttpRequest::State::ReadingUrl))
if (Q_UNLIKELY(!(ok = request->readUrl(socket))))
qWarning("Invalid URL");
if (Q_LIKELY(ok && request->state == HttpRequest::State::ReadingStatus))
if (Q_UNLIKELY(!(ok = request->readStatus(socket))))
qWarning("Invalid Status");
if (Q_LIKELY(ok && request->state == HttpRequest::State::ReadingHeader))
if (Q_UNLIKELY(!(ok = request->readHeaders(socket))))
qWarning("Invalid Header");
if (Q_LIKELY(ok && request->state == HttpRequest::State::ReadingBody))
if (Q_UNLIKELY(!(ok = request->readBody(socket))))
qWarning("Invalid Body");
}
if (Q_UNLIKELY(!ok)) {
socket->disconnectFromHost();
clients.remove(socket);
} else if (Q_LIKELY(request->state == HttpRequest::State::AllDone)) {
Q_ASSERT(handler);
if (request->headers.contains("Host")) {
const auto parts = request->headers["Host"].split(':');
request->url.setHost(parts.at(0));
if (parts.size() == 2)
request->url.setPort(parts.at(1).toUInt());
}
handler(*request, socket);
socket->disconnectFromHost();
clients.remove(socket);
}
});
});
connect(this, &QSslServer::sslErrors, this, [this](QSslSocket *s, const QList<QSslError> &errors) {
bool hasOnlyExpectedErrors = true;
for (const auto &err : errors)
hasOnlyExpectedErrors &= expectedSslErrors.contains(err.error());
if (hasOnlyExpectedErrors)
s->ignoreSslErrors();
else
qWarning() << "Got unexpected SSL errors" << errors;
});
setSslConfiguration(config);
const bool ok = listen(QHostAddress::LocalHost);
Q_ASSERT(ok);
}
QUrl TlsWebServer::url(const QString &path)
{
using namespace Qt::StringLiterals;
return QUrl(u"https://127.0.0.1:%1%2"_s.arg(serverPort()).arg(path.startsWith('/')
? path : "/" + path));
}
void TlsWebServer::setExpectedSslErrors(const QSet<QSslError::SslError> &errors)
{
expectedSslErrors = errors;
}
#endif // !QT_NO_SSL
|