| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  | #ifndef QT_NO_OPENSSL
 | 
					
						
							|  |  |  |     #include <QSslSocket>
 | 
					
						
							|  |  |  |     #include <QSslKey>
 | 
					
						
							|  |  |  |     #include <QSslCertificate>
 | 
					
						
							|  |  |  |     #include <QSslConfiguration>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #include <QDir>
 | 
					
						
							|  |  |  | #include "httpconnectionhandlerpool.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-11 09:32:15 +01:00
										 |  |  | using namespace qtwebapp; | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | HttpConnectionHandlerPool::HttpConnectionHandlerPool(QSettings* settings, HttpRequestHandler* requestHandler) | 
					
						
							| 
									
										
										
										
											2017-11-13 01:36:00 +01:00
										 |  |  |     : QObject(), useQtSettings(true) | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-11-18 10:15:29 +01:00
										 |  |  |     Q_ASSERT(settings != 0); | 
					
						
							|  |  |  |     this->settings = settings; | 
					
						
							|  |  |  |     this->listenerSettings = 0; | 
					
						
							|  |  |  |     this->requestHandler = requestHandler; | 
					
						
							|  |  |  |     this->sslConfiguration = 0; | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |     loadSslConfig(); | 
					
						
							|  |  |  |     cleanupTimer.start(settings->value("cleanupInterval",1000).toInt()); | 
					
						
							|  |  |  |     connect(&cleanupTimer, SIGNAL(timeout()), SLOT(cleanup())); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-18 10:15:29 +01:00
										 |  |  | HttpConnectionHandlerPool::HttpConnectionHandlerPool(const HttpListenerSettings* settings, HttpRequestHandler* requestHandler) | 
					
						
							| 
									
										
										
										
											2017-11-13 13:46:02 +01:00
										 |  |  |     : QObject(), useQtSettings(false) | 
					
						
							| 
									
										
										
										
											2017-11-13 01:36:00 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-12-24 20:27:20 +01:00
										 |  |  |     Q_ASSERT(settings != 0); | 
					
						
							| 
									
										
										
										
											2017-11-18 10:15:29 +01:00
										 |  |  |     this->settings = 0; | 
					
						
							|  |  |  |     this->listenerSettings = settings; | 
					
						
							|  |  |  |     this->requestHandler = requestHandler; | 
					
						
							|  |  |  |     this->sslConfiguration = 0; | 
					
						
							| 
									
										
										
										
											2017-11-13 01:36:00 +01:00
										 |  |  |     loadSslConfig(); | 
					
						
							| 
									
										
										
										
											2017-11-18 10:15:29 +01:00
										 |  |  |     cleanupTimer.start(settings->cleanupInterval); | 
					
						
							| 
									
										
										
										
											2017-11-13 01:36:00 +01:00
										 |  |  |     connect(&cleanupTimer, SIGNAL(timeout()), SLOT(cleanup())); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  | 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) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-11-18 10:15:29 +01:00
										 |  |  |         int maxConnectionHandlers = useQtSettings ? settings->value("maxThreads",100).toInt() : listenerSettings->maxThreads; | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |         if (pool.count()<maxConnectionHandlers) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2017-11-17 08:52:15 +01:00
										 |  |  |             if (useQtSettings) { | 
					
						
							|  |  |  |                 freeHandler = new HttpConnectionHandler(settings, requestHandler, sslConfiguration); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 freeHandler = new HttpConnectionHandler(listenerSettings, requestHandler, sslConfiguration); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |             freeHandler->setBusy(); | 
					
						
							|  |  |  |             pool.append(freeHandler); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     mutex.unlock(); | 
					
						
							|  |  |  |     return freeHandler; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void HttpConnectionHandlerPool::cleanup() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-11-18 10:15:29 +01:00
										 |  |  |     int maxIdleHandlers = useQtSettings ? settings->value("minThreads",1).toInt() : listenerSettings->minThreads; | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |     int idleCounter=0; | 
					
						
							|  |  |  |     mutex.lock(); | 
					
						
							|  |  |  |     foreach(HttpConnectionHandler* handler, pool) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!handler->isBusy()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (++idleCounter > maxIdleHandlers) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 pool.removeOne(handler); | 
					
						
							| 
									
										
										
										
											2024-09-03 18:38:32 +03:00
										 |  |  |                 qDebug("HttpConnectionHandlerPool: Removed connection handler (%p), pool size is now %i",handler,(int)pool.size()); | 
					
						
							| 
									
										
										
										
											2018-02-21 18:54:59 +01:00
										 |  |  |                 delete handler; | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |                 break; // remove only one handler in each interval
 | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     mutex.unlock(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void HttpConnectionHandlerPool::loadSslConfig() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // If certificate and key files are configured, then load them
 | 
					
						
							| 
									
										
										
										
											2017-11-18 10:15:29 +01:00
										 |  |  |     QString sslKeyFileName = useQtSettings ? settings->value("sslKeyFile","").toString() : listenerSettings->sslKeyFile; | 
					
						
							|  |  |  |     QString sslCertFileName = useQtSettings ? settings->value("sslCertFile","").toString() : listenerSettings->sslCertFile; | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |     if (!sslKeyFileName.isEmpty() && !sslCertFileName.isEmpty()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         #ifdef QT_NO_OPENSSL
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |             qWarning("HttpConnectionHandlerPool::loadSslConfig: SSL is not supported"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |         #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->setLocalCertificate(certificate); | 
					
						
							|  |  |  |             sslConfiguration->setPrivateKey(sslKey); | 
					
						
							|  |  |  |             sslConfiguration->setPeerVerifyMode(QSslSocket::VerifyNone); | 
					
						
							| 
									
										
										
										
											2022-09-23 00:27:29 +02:00
										 |  |  |             sslConfiguration->setProtocol(QSsl::TlsV1_0); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             qDebug("HttpConnectionHandlerPool: SSL settings loaded"); | 
					
						
							|  |  |  |          #endif
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |