From 2e72e428baca1ba7ede9847208ac3ed5fe94f98c Mon Sep 17 00:00:00 2001 From: Felix Kauselmann Date: Sat, 8 Oct 2022 13:38:52 +0200 Subject: [PATCH] Update QtWebApp to v1.8.6 --- CHANGELOG.md | 4 ++ .../httpserver/httpconnectionhandler.h | 5 +- .../httpserver/httpconnectionhandlerpool.cpp | 49 +++++++++++++- .../httpserver/httpconnectionhandlerpool.h | 67 ++++++++++++++----- .../QtWebApp/httpserver/httpglobal.cpp | 2 +- third_party/QtWebApp/httpserver/httpglobal.h | 4 ++ .../QtWebApp/httpserver/httplistener.h | 35 +++++++--- third_party/QtWebApp/httpserver/httprequest.h | 3 +- .../httpserver/staticfilecontroller.cpp | 3 +- .../QtWebApp/{LICENSE.txt => lgpl-3.0.txt} | 2 +- .../QtWebApp/{README.txt => readme.txt} | 4 +- .../{CHANGELOG.txt => releasenotes.txt} | 12 ++++ .../QtWebApp/templateengine/templateglobal.h | 4 ++ third_party/README.md | 2 +- 14 files changed, 157 insertions(+), 39 deletions(-) rename third_party/QtWebApp/{LICENSE.txt => lgpl-3.0.txt} (99%) rename third_party/QtWebApp/{README.txt => readme.txt} (71%) rename third_party/QtWebApp/{CHANGELOG.txt => releasenotes.txt} (97%) diff --git a/CHANGELOG.md b/CHANGELOG.md index b26d5d77..4265720e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Version counting is based on semantic versioning (Major.Feature.Patch) +## 9.9.3 [unreleased] + +### YACReaderLibrary +* Update QtWebApp webserver to v1.8.6 ## 9.9.2 ### General diff --git a/third_party/QtWebApp/httpserver/httpconnectionhandler.h b/third_party/QtWebApp/httpserver/httpconnectionhandler.h index fc03cc1d..ae0d92c1 100644 --- a/third_party/QtWebApp/httpserver/httpconnectionhandler.h +++ b/third_party/QtWebApp/httpserver/httpconnectionhandler.h @@ -44,7 +44,10 @@ namespace stefanfrings {

The readTimeout value defines the maximum time to wait for a complete HTTP request. - @see HttpRequest for description of config settings maxRequestSize and maxMultiPartSize. +

+ MaxRequestSize is the maximum size of a HTTP request. In case of + multipart/form-data requests (also known as file-upload), the maximum + size of the body must not exceed maxMultiPartSize. */ class DECLSPEC HttpConnectionHandler : public QObject { Q_OBJECT diff --git a/third_party/QtWebApp/httpserver/httpconnectionhandlerpool.cpp b/third_party/QtWebApp/httpserver/httpconnectionhandlerpool.cpp index 56a15ec9..5a03d0ce 100644 --- a/third_party/QtWebApp/httpserver/httpconnectionhandlerpool.cpp +++ b/third_party/QtWebApp/httpserver/httpconnectionhandlerpool.cpp @@ -92,6 +92,9 @@ 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 @@ -107,6 +110,7 @@ void HttpConnectionHandlerPool::loadSslConfig() { sslKeyFileName=QFileInfo(configFile.absolutePath(),sslKeyFileName).absoluteFilePath(); } + #ifdef Q_OS_WIN32 if (QDir::isRelativePath(sslCertFileName) && settings->format()!=QSettings::NativeFormat) #else @@ -138,10 +142,51 @@ void HttpConnectionHandlerPool::loadSslConfig() // Create the SSL configuration sslConfiguration=new QSslConfiguration(); + sslConfiguration->setProtocol(QSsl::AnyProtocol); sslConfiguration->setLocalCertificate(certificate); sslConfiguration->setPrivateKey(sslKey); - sslConfiguration->setPeerVerifyMode(QSslSocket::VerifyNone); - sslConfiguration->setProtocol(QSsl::AnyProtocol); + + // 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 diff --git a/third_party/QtWebApp/httpserver/httpconnectionhandlerpool.h b/third_party/QtWebApp/httpserver/httpconnectionhandlerpool.h index 3e556a56..7a358a70 100644 --- a/third_party/QtWebApp/httpserver/httpconnectionhandlerpool.h +++ b/third_party/QtWebApp/httpserver/httpconnectionhandlerpool.h @@ -16,33 +16,69 @@ namespace stefanfrings {

Example for the required configuration settings:

-  minThreads=4
-  maxThreads=100
-  cleanupInterval=60000
   readTimeout=60000
-  ;sslKeyFile=ssl/my.key
-  ;sslCertFile=ssl/my.cert
   maxRequestSize=16000
   maxMultiPartSize=1000000
+
+  minThreads=4
+  maxThreads=100
+  cleanupInterval=60000  
   
+

+ The readTimeout value defines the maximum time to wait for a complete HTTP request. +

+ MaxRequestSize is the maximum size of a HTTP request. In case of + multipart/form-data requests (also known as file-upload), the maximum + size of the body must not exceed maxMultiPartSize. +

After server start, the size of the thread pool is always 0. Threads are started on demand when requests come in. The cleanup timer reduces the number of idle threads slowly by closing one thread in each interval. But the configured minimum number of threads are kept running.

- For SSL support, you need an OpenSSL certificate file and a key file. - Both can be created with the command + Additional settings for SSL (HTTPS):

-      openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout my.key -out my.cert
+  sslKeyFile=ssl/server.key
+  sslCertFile=ssl/server.crt
+  ;caCertFile=ssl/ca.crt
+  verifyPeer=false
+  
+ For SSL support, you need at least a pair of OpenSSL x509 certificate and an RSA key, + both files in PEM format. To enable verification of the peer (the calling web browser), + you can either use the central certificate store of the operating system, or provide + a CA certificate file in PEM format. The certificates of the peers must have been + derived from the CA certificate. +

+ Example commands to create these files: +

+  # Generate CA key
+  openssl genrsa 2048 > ca.key
+
+  # Generate CA certificate
+  openssl req -new -x509 -nodes -days 365000 -key ca.key -out ca.crt
+
+  # Generate a server key and certificate request
+  openssl req -newkey rsa:2048 -nodes -days 365000 -keyout server.key -out server.req
+
+  # Generate a signed server certificate
+  openssl x509 -req -days 365000 -set_serial 01 -in server.req -out server.crt -CA ca.crt -CAkey ca.key
+
+  # Generate a client key and certificate request
+  openssl req -newkey rsa:2048 -nodes -days 365000 -keyout client.key -out client.req
+
+  # Generate a signed client certificate
+  openssl x509 -req -days 365000 -set_serial 01 -in client.req -out client.crt  -CA ca.crt -CAkey ca.key
+
+  # Combine client key and certificate into one PKCS12 file
+  openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12 -certfile ca.crt
+
+  # Remove temporary files
+  rm *.req
   

- Visit http://slproweb.com/products/Win32OpenSSL.html to download the Light version of OpenSSL for Windows. -

- Please note that a listener with SSL settings can only handle HTTPS protocol. To - support both HTTP and HTTPS simultaneously, you need to start two listeners on different ports - - one with SLL and one without SSL. - @see HttpConnectionHandler for description of the readTimeout - @see HttpRequest for description of config settings maxRequestSize and maxMultiPartSize + Please note that a listener with SSL can only handle HTTPS protocol. To support both + HTTP and HTTPS simultaneously, you need to start two listeners on different ports + one with SLL and one without SSL (usually on public ports 80 and 443, or locally on 8080 and 8443). */ class DECLSPEC HttpConnectionHandlerPool : public QObject { @@ -54,7 +90,6 @@ public: Constructor. @param settings Configuration settings for the HTTP server. Must not be 0. @param requestHandler The handler that will process each received HTTP request. - @warning The requestMapper gets deleted by the destructor of this pool */ HttpConnectionHandlerPool(const QSettings* settings, HttpRequestHandler *requestHandler); diff --git a/third_party/QtWebApp/httpserver/httpglobal.cpp b/third_party/QtWebApp/httpserver/httpglobal.cpp index a5b72a6a..2f06478b 100644 --- a/third_party/QtWebApp/httpserver/httpglobal.cpp +++ b/third_party/QtWebApp/httpserver/httpglobal.cpp @@ -2,6 +2,6 @@ const char* getQtWebAppLibVersion() { - return "1.8.3"; + return "1.8.6"; } diff --git a/third_party/QtWebApp/httpserver/httpglobal.h b/third_party/QtWebApp/httpserver/httpglobal.h index 4f499871..2735fe24 100644 --- a/third_party/QtWebApp/httpserver/httpglobal.h +++ b/third_party/QtWebApp/httpserver/httpglobal.h @@ -23,5 +23,9 @@ /** Get the library version number */ DECLSPEC const char* getQtWebAppLibVersion(); +#if __cplusplus < 201103L + #define nullptr 0 +#endif + #endif // HTTPGLOBAL_H diff --git a/third_party/QtWebApp/httpserver/httplistener.h b/third_party/QtWebApp/httpserver/httplistener.h index e5794f2f..9b11af39 100644 --- a/third_party/QtWebApp/httpserver/httplistener.h +++ b/third_party/QtWebApp/httpserver/httplistener.h @@ -24,21 +24,34 @@ namespace stefanfrings {

   ;host=192.168.0.100
   port=8080
+
+  readTimeout=60000
+  maxRequestSize=16000
+  maxMultiPartSize=1000000
+
   minThreads=1
   maxThreads=10
   cleanupInterval=1000
-  readTimeout=60000
-  ;sslKeyFile=ssl/my.key
-  ;sslCertFile=ssl/my.cert
-  maxRequestSize=16000
-  maxMultiPartSize=1000000
+
+  ;sslKeyFile=ssl/server.key
+  ;sslCertFile=ssl/server.crt
+  ;caCertFile=ssl/ca.crt
+  ;verifyPeer=false
   
- The optional host parameter binds the listener to one network interface. - The listener handles all network interfaces if no host is configured. - The port number specifies the incoming TCP port that this listener listens to. - @see HttpConnectionHandlerPool for description of config settings minThreads, maxThreads, cleanupInterval and ssl settings - @see HttpConnectionHandler for description of the readTimeout - @see HttpRequest for description of config settings maxRequestSize and maxMultiPartSize + The optional host parameter binds the listener to a specific network interface, + otherwise the server accepts connections from any network interface on the given port. +

+ The readTimeout value defines the maximum time to wait for a complete HTTP request. +

+ MaxRequestSize is the maximum size of a HTTP request. In case of + multipart/form-data requests (also known as file-upload), the maximum + size of the body must not exceed maxMultiPartSize. +

+ After server start, the size of the thread pool is always 0. Threads + are started on demand when requests come in. The cleanup timer reduces + the number of idle threads slowly by closing one thread in each interval. + But the configured minimum number of threads are kept running. + @see HttpConnectionHandlerPool for description of the optional ssl settings */ class DECLSPEC HttpListener : public QTcpServer { diff --git a/third_party/QtWebApp/httpserver/httprequest.h b/third_party/QtWebApp/httpserver/httprequest.h index 28e6ac30..f0da0848 100644 --- a/third_party/QtWebApp/httpserver/httprequest.h +++ b/third_party/QtWebApp/httpserver/httprequest.h @@ -23,7 +23,7 @@ namespace stefanfrings { from a TCP socket and provides getters for the individual parts of the request.

- The follwing config settings are required: + The following config settings are required:

   maxRequestSize=16000
   maxMultiPartSize=1000000
@@ -32,7 +32,6 @@ namespace stefanfrings {
   MaxRequestSize is the maximum size of a HTTP request. In case of
   multipart/form-data requests (also known as file-upload), the maximum
   size of the body must not exceed maxMultiPartSize.
-  The body is always a little larger than the file itself.
 */
 
 class DECLSPEC HttpRequest {
diff --git a/third_party/QtWebApp/httpserver/staticfilecontroller.cpp b/third_party/QtWebApp/httpserver/staticfilecontroller.cpp
index bafe4509..ac259252 100644
--- a/third_party/QtWebApp/httpserver/staticfilecontroller.cpp
+++ b/third_party/QtWebApp/httpserver/staticfilecontroller.cpp
@@ -53,7 +53,7 @@ void StaticFileController::service(HttpRequest &request, HttpResponse &response)
         qDebug("StaticFileController: Cache hit for %s",path.data());
         setContentType(filename,response);
         response.setHeader("Cache-Control","max-age="+QByteArray::number(maxAge/1000));
-        response.write(document);
+        response.write(document,true);
     }
     else
     {
@@ -80,6 +80,7 @@ void StaticFileController::service(HttpRequest &request, HttpResponse &response)
         {
             setContentType(path,response);
             response.setHeader("Cache-Control","max-age="+QByteArray::number(maxAge/1000));
+            response.setHeader("Content-Length",QByteArray::number(file.size()));
             if (file.size()<=maxCachedFileSize)
             {
                 // Return the file content and store it also in the cache
diff --git a/third_party/QtWebApp/LICENSE.txt b/third_party/QtWebApp/lgpl-3.0.txt
similarity index 99%
rename from third_party/QtWebApp/LICENSE.txt
rename to third_party/QtWebApp/lgpl-3.0.txt
index 65c5ca88..0a041280 100644
--- a/third_party/QtWebApp/LICENSE.txt
+++ b/third_party/QtWebApp/lgpl-3.0.txt
@@ -1,7 +1,7 @@
                    GNU LESSER GENERAL PUBLIC LICENSE
                        Version 3, 29 June 2007
 
- Copyright (C) 2007 Free Software Foundation, Inc. 
+ Copyright (C) 2007 Free Software Foundation, Inc. 
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
diff --git a/third_party/QtWebApp/README.txt b/third_party/QtWebApp/readme.txt
similarity index 71%
rename from third_party/QtWebApp/README.txt
rename to third_party/QtWebApp/readme.txt
index e9b2f575..3299c05f 100644
--- a/third_party/QtWebApp/README.txt
+++ b/third_party/QtWebApp/readme.txt
@@ -7,9 +7,7 @@ Project homepage:  http://stefanfrings.de/qtwebapp/index-en.html
 Tutorial:          http://stefanfrings.de/qtwebapp/tutorial/index.html
 API doc:           http://stefanfrings.de/qtwebapp/api/index.html
 
-In Qt 6.0 or newer, you must install the optional "core5compat" component.
-This package contains the QTextCodec class which is needed to decode template files.
-It supports a lot more encodings, for example ISO-8859-15 with the EUR symbol.
+In Qt 6.x you must install the "Qt5Compat" libraries.
 
 Demo1 shows how to use the library by including the source code into your
 project, the preferred method.
diff --git a/third_party/QtWebApp/CHANGELOG.txt b/third_party/QtWebApp/releasenotes.txt
similarity index 97%
rename from third_party/QtWebApp/CHANGELOG.txt
rename to third_party/QtWebApp/releasenotes.txt
index 19183495..8fc7cf93 100644
--- a/third_party/QtWebApp/CHANGELOG.txt
+++ b/third_party/QtWebApp/releasenotes.txt
@@ -1,6 +1,18 @@
 Dont forget to update the release number also in
 QtWebApp.pro and httpserver/httpglobal.cpp.
 
+1.8.6
+30.09.2022
+Fix compile error under Windows: sslCaCertFileName' was not declared
+
+1.8.5
+19.03.2022
+Add support for SSL peer verification and CA certificate.
+
+1.8.4
+29.10.2021
+Add Content-Length header to static file controller.
+
 1.8.3
 21.03.2021
 The minLevel for logging can now be configured as string:
diff --git a/third_party/QtWebApp/templateengine/templateglobal.h b/third_party/QtWebApp/templateengine/templateglobal.h
index eb1aa9d4..736b03d0 100644
--- a/third_party/QtWebApp/templateengine/templateglobal.h
+++ b/third_party/QtWebApp/templateengine/templateglobal.h
@@ -20,5 +20,9 @@
     #define DECLSPEC
 #endif
 
+#if __cplusplus < 201103L
+    #define nullptr 0
+#endif
+
 #endif // TEMPLATEGLOBAL_H
 
diff --git a/third_party/README.md b/third_party/README.md
index 5e956bd3..4818d0d8 100644
--- a/third_party/README.md
+++ b/third_party/README.md
@@ -6,4 +6,4 @@ needed to build YACReader.
 | Name      | Purpose  | Upstream | Version | License |
 |---------- |--------- |--------- |-------- |-------- |
 | QsLog     | Logging  | https://bitbucket.org/codeimproved/qslog | 2.1 46b643d5bcbc| 3-clause BSD|
-| QtWebApp  | Server   | http://stefanfrings.de/qtwebapp/ | 1.7.11 | LGPL3 |
+| QtWebApp  | Server   | http://stefanfrings.de/qtwebapp/ | 1.8.6 | LGPL3 |