httpconnectionhandlerpool.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. #ifndef QT_NO_SSL
  2. #include <QSslSocket>
  3. #include <QSslKey>
  4. #include <QSslCertificate>
  5. #include <QSslConfiguration>
  6. #endif
  7. #include <QDir>
  8. #include "httpconnectionhandlerpool.h"
  9. using namespace stefanfrings;
  10. HttpConnectionHandlerPool::HttpConnectionHandlerPool(const QSettings *settings, HttpRequestHandler *requestHandler)
  11. : QObject()
  12. {
  13. Q_ASSERT(settings!=0);
  14. this->settings=settings;
  15. this->requestHandler=requestHandler;
  16. this->sslConfiguration=NULL;
  17. loadSslConfig();
  18. cleanupTimer.start(settings->value("cleanupInterval",1000).toInt());
  19. connect(&cleanupTimer, SIGNAL(timeout()), SLOT(cleanup()));
  20. }
  21. HttpConnectionHandlerPool::~HttpConnectionHandlerPool()
  22. {
  23. // delete all connection handlers and wait until their threads are closed
  24. for (int i=0; i<pool.size(); i++)
  25. {
  26. HttpConnectionHandler* handler=pool.at(i);
  27. delete handler;
  28. }
  29. delete sslConfiguration;
  30. qDebug("HttpConnectionHandlerPool (%p): destroyed", this);
  31. }
  32. HttpConnectionHandler* HttpConnectionHandlerPool::getConnectionHandler()
  33. {
  34. HttpConnectionHandler* freeHandler=0;
  35. mutex.lock();
  36. // find a free handler in pool
  37. for (int i=0; i<pool.size(); i++)
  38. {
  39. HttpConnectionHandler* handler=pool.at(i);
  40. if (!handler->isBusy())
  41. {
  42. freeHandler=handler;
  43. freeHandler->setBusy();
  44. break;
  45. }
  46. }
  47. // create a new handler, if necessary
  48. if (!freeHandler)
  49. {
  50. int maxConnectionHandlers=settings->value("maxThreads",100).toInt();
  51. if (pool.count()<maxConnectionHandlers)
  52. {
  53. freeHandler=new HttpConnectionHandler(settings,requestHandler,sslConfiguration);
  54. freeHandler->setBusy();
  55. pool.append(freeHandler);
  56. }
  57. }
  58. mutex.unlock();
  59. return freeHandler;
  60. }
  61. void HttpConnectionHandlerPool::cleanup()
  62. {
  63. int maxIdleHandlers=settings->value("minThreads",1).toInt();
  64. int idleCounter=0;
  65. mutex.lock();
  66. for (int i=0; i<pool.size(); i++)
  67. {
  68. HttpConnectionHandler* handler=pool.at(i);
  69. if (!handler->isBusy())
  70. {
  71. if (++idleCounter > maxIdleHandlers)
  72. {
  73. pool.removeAt(i);
  74. delete handler;
  75. long int poolSize=(long int)pool.size();
  76. qDebug("HttpConnectionHandlerPool: Removed connection handler (%p), pool size is now %li",handler,poolSize);
  77. break; // remove only one handler in each interval
  78. }
  79. }
  80. }
  81. mutex.unlock();
  82. }
  83. void HttpConnectionHandlerPool::loadSslConfig()
  84. {
  85. // If certificate and key files are configured, then load them
  86. QString sslKeyFileName=settings->value("sslKeyFile","").toString();
  87. QString sslCertFileName=settings->value("sslCertFile","").toString();
  88. QString caCertFileName=settings->value("caCertFile","").toString();
  89. bool verifyPeer=settings->value("verifyPeer","false").toBool();
  90. if (!sslKeyFileName.isEmpty() && !sslCertFileName.isEmpty())
  91. {
  92. #ifdef QT_NO_SSL
  93. qWarning("HttpConnectionHandlerPool: SSL is not supported");
  94. #else
  95. // Convert relative fileNames to absolute, based on the directory of the config file.
  96. QFileInfo configFile(settings->fileName());
  97. #ifdef Q_OS_WIN32
  98. if (QDir::isRelativePath(sslKeyFileName) && settings->format()!=QSettings::NativeFormat)
  99. #else
  100. if (QDir::isRelativePath(sslKeyFileName))
  101. #endif
  102. {
  103. sslKeyFileName=QFileInfo(configFile.absolutePath(),sslKeyFileName).absoluteFilePath();
  104. }
  105. #ifdef Q_OS_WIN32
  106. if (QDir::isRelativePath(sslCertFileName) && settings->format()!=QSettings::NativeFormat)
  107. #else
  108. if (QDir::isRelativePath(sslCertFileName))
  109. #endif
  110. {
  111. sslCertFileName=QFileInfo(configFile.absolutePath(),sslCertFileName).absoluteFilePath();
  112. }
  113. // Load the SSL certificate
  114. QFile certFile(sslCertFileName);
  115. if (!certFile.open(QIODevice::ReadOnly))
  116. {
  117. qCritical("HttpConnectionHandlerPool: cannot open sslCertFile %s", qPrintable(sslCertFileName));
  118. return;
  119. }
  120. QSslCertificate certificate(&certFile, QSsl::Pem);
  121. certFile.close();
  122. // Load the key file
  123. QFile keyFile(sslKeyFileName);
  124. if (!keyFile.open(QIODevice::ReadOnly))
  125. {
  126. qCritical("HttpConnectionHandlerPool: cannot open sslKeyFile %s", qPrintable(sslKeyFileName));
  127. return;
  128. }
  129. QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem);
  130. keyFile.close();
  131. // Create the SSL configuration
  132. sslConfiguration=new QSslConfiguration();
  133. sslConfiguration->setProtocol(QSsl::AnyProtocol);
  134. sslConfiguration->setLocalCertificate(certificate);
  135. sslConfiguration->setPrivateKey(sslKey);
  136. // We can optionally use a CA certificate to validate the HTTP clients
  137. if (!caCertFileName.isEmpty())
  138. {
  139. #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
  140. qCritical("HttpConnectionHandlerPool: Using a caCertFile requires Qt 5.15 or newer");
  141. #else
  142. // Convert relative fileName to absolute, based on the directory of the config file.
  143. #ifdef Q_OS_WIN32
  144. if (QDir::isRelativePath(caCertFileName) && settings->format()!=QSettings::NativeFormat)
  145. #else
  146. if (QDir::isRelativePath(caCertFileName))
  147. #endif
  148. {
  149. caCertFileName=QFileInfo(configFile.absolutePath(),caCertFileName).absoluteFilePath();
  150. }
  151. // Load the CA cert file
  152. QFile caCertFile(caCertFileName);
  153. if (!caCertFile.open(QIODevice::ReadOnly))
  154. {
  155. qCritical("HttpConnectionHandlerPool: cannot open caCertFile %s", qPrintable(caCertFileName));
  156. return;
  157. }
  158. QSslCertificate caCertificate(&caCertFile, QSsl::Pem);
  159. caCertFile.close();
  160. // Configure SSL
  161. sslConfiguration->addCaCertificate(caCertificate);
  162. #endif
  163. }
  164. // Enable or disable verification of the HTTP client
  165. if (verifyPeer)
  166. {
  167. sslConfiguration->setPeerVerifyMode(QSslSocket::VerifyPeer);
  168. }
  169. else
  170. {
  171. sslConfiguration->setPeerVerifyMode(QSslSocket::VerifyNone);
  172. }
  173. qDebug("HttpConnectionHandlerPool: SSL settings loaded");
  174. #endif
  175. }
  176. }