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
|