Files
YACReader
YACReaderLibrary
YACReaderLibraryServer
ci
common
compressed_archive
custom_widgets
dependencies
files
images
release
shortcuts_management
tests
third_party
KDToolBox
QrCode
QsLog
QtWebApp
httpserver
httpconnectionhandler.cpp
httpconnectionhandler.h
httpconnectionhandlerpool.cpp
httpconnectionhandlerpool.h
httpcookie.cpp
httpcookie.h
httpglobal.cpp
httpglobal.h
httplistener.cpp
httplistener.h
httprequest.cpp
httprequest.h
httprequesthandler.cpp
httprequesthandler.h
httpresponse.cpp
httpresponse.h
httpserver.pri
httpsession.cpp
httpsession.h
httpsessionstore.cpp
httpsessionstore.h
staticfilecontroller.cpp
staticfilecontroller.h
templateengine
.clang-format
lgpl-3.0.txt
readme.txt
releasenotes.txt
README.md
.clang-format
.editorconfig
.gitattributes
.gitignore
CHANGELOG.md
COPYING.txt
INSTALL.md
README.md
YACReader.1
YACReader.desktop
YACReader.pro
YACReader.svg
YACReaderLibrary.1
YACReaderLibrary.desktop
YACReaderLibrary.svg
azure-pipelines-build-number.yml
azure-pipelines-windows-template-qt6.yml
azure-pipelines-windows-template.yml
azure-pipelines.yml
background.png
background@2x.png
cleanOSX.sh
compileOSX.sh
config.pri
dmg.json
icon.icns
mktarball.sh
signapps.sh
yacreader/third_party/QtWebApp/httpserver/httpconnectionhandlerpool.cpp
2022-10-08 13:38:52 +02:00

195 lines
6.7 KiB
C++

#ifndef QT_NO_SSL
#include <QSslSocket>
#include <QSslKey>
#include <QSslCertificate>
#include <QSslConfiguration>
#endif
#include <QDir>
#include "httpconnectionhandlerpool.h"
using namespace stefanfrings;
HttpConnectionHandlerPool::HttpConnectionHandlerPool(const QSettings *settings, HttpRequestHandler *requestHandler)
: QObject()
{
Q_ASSERT(settings!=0);
this->settings=settings;
this->requestHandler=requestHandler;
this->sslConfiguration=NULL;
loadSslConfig();
cleanupTimer.start(settings->value("cleanupInterval",1000).toInt());
connect(&cleanupTimer, SIGNAL(timeout()), SLOT(cleanup()));
}
HttpConnectionHandlerPool::~HttpConnectionHandlerPool()
{
// delete all connection handlers and wait until their threads are closed
foreach(HttpConnectionHandler* handler, pool)
{
delete handler;
}
delete sslConfiguration;
qDebug("HttpConnectionHandlerPool (%p): destroyed", this);
}
HttpConnectionHandler* HttpConnectionHandlerPool::getConnectionHandler()
{
HttpConnectionHandler* freeHandler=0;
mutex.lock();
// find a free handler in pool
foreach(HttpConnectionHandler* handler, pool)
{
if (!handler->isBusy())
{
freeHandler=handler;
freeHandler->setBusy();
break;
}
}
// create a new handler, if necessary
if (!freeHandler)
{
int maxConnectionHandlers=settings->value("maxThreads",100).toInt();
if (pool.count()<maxConnectionHandlers)
{
freeHandler=new HttpConnectionHandler(settings,requestHandler,sslConfiguration);
freeHandler->setBusy();
pool.append(freeHandler);
}
}
mutex.unlock();
return freeHandler;
}
void HttpConnectionHandlerPool::cleanup()
{
int maxIdleHandlers=settings->value("minThreads",1).toInt();
int idleCounter=0;
mutex.lock();
foreach(HttpConnectionHandler* handler, pool)
{
if (!handler->isBusy())
{
if (++idleCounter > maxIdleHandlers)
{
delete handler;
pool.removeOne(handler);
long int poolSize=(long int)pool.size();
qDebug("HttpConnectionHandlerPool: Removed connection handler (%p), pool size is now %li",handler,poolSize);
break; // remove only one handler in each interval
}
}
}
mutex.unlock();
}
void HttpConnectionHandlerPool::loadSslConfig()
{
// If certificate and key files are configured, then load them
QString sslKeyFileName=settings->value("sslKeyFile","").toString();
QString sslCertFileName=settings->value("sslCertFile","").toString();
QString caCertFileName=settings->value("caCertFile","").toString();
bool verifyPeer=settings->value("verifyPeer","false").toBool();
if (!sslKeyFileName.isEmpty() && !sslCertFileName.isEmpty())
{
#ifdef QT_NO_SSL
qWarning("HttpConnectionHandlerPool: SSL is not supported");
#else
// Convert relative fileNames to absolute, based on the directory of the config file.
QFileInfo configFile(settings->fileName());
#ifdef Q_OS_WIN32
if (QDir::isRelativePath(sslKeyFileName) && settings->format()!=QSettings::NativeFormat)
#else
if (QDir::isRelativePath(sslKeyFileName))
#endif
{
sslKeyFileName=QFileInfo(configFile.absolutePath(),sslKeyFileName).absoluteFilePath();
}
#ifdef Q_OS_WIN32
if (QDir::isRelativePath(sslCertFileName) && settings->format()!=QSettings::NativeFormat)
#else
if (QDir::isRelativePath(sslCertFileName))
#endif
{
sslCertFileName=QFileInfo(configFile.absolutePath(),sslCertFileName).absoluteFilePath();
}
// Load the SSL certificate
QFile certFile(sslCertFileName);
if (!certFile.open(QIODevice::ReadOnly))
{
qCritical("HttpConnectionHandlerPool: cannot open sslCertFile %s", qPrintable(sslCertFileName));
return;
}
QSslCertificate certificate(&certFile, QSsl::Pem);
certFile.close();
// Load the key file
QFile keyFile(sslKeyFileName);
if (!keyFile.open(QIODevice::ReadOnly))
{
qCritical("HttpConnectionHandlerPool: cannot open sslKeyFile %s", qPrintable(sslKeyFileName));
return;
}
QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem);
keyFile.close();
// Create the SSL configuration
sslConfiguration=new QSslConfiguration();
sslConfiguration->setProtocol(QSsl::AnyProtocol);
sslConfiguration->setLocalCertificate(certificate);
sslConfiguration->setPrivateKey(sslKey);
// We can optionally use a CA certificate to validate the HTTP clients
if (!caCertFileName.isEmpty())
{
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
qCritical("HttpConnectionHandlerPool: Using a caCertFile requires Qt 5.15 or newer");
#else
// Convert relative fileName to absolute, based on the directory of the config file.
#ifdef Q_OS_WIN32
if (QDir::isRelativePath(caCertFileName) && settings->format()!=QSettings::NativeFormat)
#else
if (QDir::isRelativePath(caCertFileName))
#endif
{
caCertFileName=QFileInfo(configFile.absolutePath(),caCertFileName).absoluteFilePath();
}
// Load the CA cert file
QFile caCertFile(caCertFileName);
if (!caCertFile.open(QIODevice::ReadOnly))
{
qCritical("HttpConnectionHandlerPool: cannot open caCertFile %s", qPrintable(caCertFileName));
return;
}
QSslCertificate caCertificate(&caCertFile, QSsl::Pem);
caCertFile.close();
// Configure SSL
sslConfiguration->addCaCertificate(caCertificate);
#endif
}
// Enable or disable verification of the HTTP client
if (verifyPeer)
{
sslConfiguration->setPeerVerifyMode(QSslSocket::VerifyPeer);
}
else
{
sslConfiguration->setPeerVerifyMode(QSslSocket::VerifyNone);
}
qDebug("HttpConnectionHandlerPool: SSL settings loaded");
#endif
}
}