Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package qt6-httpserver for openSUSE:Factory 
checked in at 2026-10-18 19:21:26
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/qt6-httpserver (Old)
 and      /work/SRC/openSUSE:Factory/.qt6-httpserver.new.3698736 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "qt6-httpserver"

Sun Oct 18 19:21:26 2026 rev:30 rq:1384393 version:6.12.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/qt6-httpserver/qt6-httpserver.changes    
2026-08-21 16:51:41.607497879 +0200
+++ 
/work/SRC/openSUSE:Factory/.qt6-httpserver.new.3698736/qt6-httpserver.changes   
    2026-10-18 19:21:27.852133524 +0200
@@ -1,0 +2,6 @@
+Wed Sep 30 16:09:58 UTC 2026 - Christophe Marin <[email protected]>
+
+- Update to 6.12.0
+  https://www.qt.io/blog/qt-6.12-released
+
+-------------------------------------------------------------------

Old:
----
  qthttpserver-everywhere-src-6.11.2.tar.xz

New:
----
  qthttpserver-everywhere-src-6.12.0.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ qt6-httpserver.spec ++++++
--- /var/tmp/diff_new_pack.Hvdn46/_old  2026-10-18 19:21:28.710169145 +0200
+++ /var/tmp/diff_new_pack.Hvdn46/_new  2026-10-18 19:21:28.711169187 +0200
@@ -16,8 +16,8 @@
 #
 
 
-%define real_version 6.11.2
-%define short_version 6.11
+%define real_version 6.12.0
+%define short_version 6.12
 %define tar_name qthttpserver-everywhere-src
 %define tar_suffix %{nil}
 #
@@ -27,7 +27,7 @@
 %endif
 #
 Name:           qt6-httpserver%{?pkg_suffix}
-Version:        6.11.2
+Version:        6.12.0
 Release:        0
 Summary:        Qt HTTP Server
 License:        GPL-3.0-only

++++++ qthttpserver-everywhere-src-6.11.2.tar.xz -> 
qthttpserver-everywhere-src-6.12.0.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qthttpserver-everywhere-src-6.11.2/.cmake.conf 
new/qthttpserver-everywhere-src-6.12.0/.cmake.conf
--- old/qthttpserver-everywhere-src-6.11.2/.cmake.conf  2026-08-12 
04:49:05.000000000 +0200
+++ new/qthttpserver-everywhere-src-6.12.0/.cmake.conf  2026-09-27 
12:11:39.000000000 +0200
@@ -1,9 +1,10 @@
-set(QT_REPO_MODULE_VERSION "6.11.2")
+set(QT_REPO_MODULE_VERSION "6.12.0")
 set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1")
 set(QT_EXTRA_INTERNAL_TARGET_DEFINES
     "QT_ENABLE_STRICT_MODE_UP_TO=QT_VERSION_CHECK(6,11,0)"
     # not yet in strict mode:
     "QT_LEAN_HEADERS=2"
+    "QT_NO_DISCONNECT_CONST_CONNECTION=1"
     "QT_NO_QPAIR=1"
     "QT_NO_SINGLE_ARGUMENT_QHASH_OVERLOAD=1"
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qthttpserver-everywhere-src-6.11.2/.tag 
new/qthttpserver-everywhere-src-6.12.0/.tag
--- old/qthttpserver-everywhere-src-6.11.2/.tag 2026-08-12 04:49:05.000000000 
+0200
+++ new/qthttpserver-everywhere-src-6.12.0/.tag 2026-09-27 12:11:39.000000000 
+0200
@@ -1 +1 @@
-86edbe897f1e7097cff1ae392e455f3055b84e68
+b9b95d5ef79f88948c6f5f6f91742cbeea8cea1e
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qthttpserver-everywhere-src-6.11.2/CONTRIBUTING.md 
new/qthttpserver-everywhere-src-6.12.0/CONTRIBUTING.md
--- old/qthttpserver-everywhere-src-6.11.2/CONTRIBUTING.md      1970-01-01 
01:00:00.000000000 +0100
+++ new/qthttpserver-everywhere-src-6.12.0/CONTRIBUTING.md      2026-09-27 
12:11:39.000000000 +0200
@@ -0,0 +1,11 @@
+## Qt contribution guidelines
+
+We welcome contributions to Qt!
+
+Note that we cannot accept pull requests on GitHub. All contributions
+to the Qt project are exclusively handled through the
+[Gerrit code review system](https://codereview.qt-project.org).
+
+See
+[contribute.qt-project.org](https://contribute.qt-project.org/) to learn
+more.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qthttpserver-everywhere-src-6.11.2/REUSE.toml 
new/qthttpserver-everywhere-src-6.12.0/REUSE.toml
--- old/qthttpserver-everywhere-src-6.11.2/REUSE.toml   2026-08-12 
04:49:05.000000000 +0200
+++ new/qthttpserver-everywhere-src-6.12.0/REUSE.toml   2026-09-27 
12:11:39.000000000 +0200
@@ -33,7 +33,8 @@
 SPDX-License-Identifier = "LicenseRef-Qt-Commercial OR BSD-3-Clause"
 
 [[annotations]]
-path = ["doc/images/**", "**/README*", "**.qdocconf"]
+path = ["doc/images/**", "**.qdocconf",
+        "**/README*", "CONTRIBUTING.md"]
 comment = "documentation"
 precedence = "closest"
 SPDX-FileCopyrightText = "Copyright (C) The Qt Company Ltd."
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qthttpserver-everywhere-src-6.11.2/dependencies.yaml 
new/qthttpserver-everywhere-src-6.12.0/dependencies.yaml
--- old/qthttpserver-everywhere-src-6.11.2/dependencies.yaml    2026-08-12 
04:49:05.000000000 +0200
+++ new/qthttpserver-everywhere-src-6.12.0/dependencies.yaml    2026-09-27 
12:11:39.000000000 +0200
@@ -1,7 +1,7 @@
 dependencies:
   ../qtbase:
-    ref: ef55f427f2c8b410d34f8a7681020a3000cf6866
+    ref: 025bdad181de241e81bf853c8a2d7bf3d19261a9
     required: true
   ../qtwebsockets:
-    ref: 3eab06de7076a83514e98c2403baa433d137b013
+    ref: 6aedb199b5d8ee4afa4cfc956ded22bc0a2632e9
     required: false
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qthttpserver-everywhere-src-6.11.2/doc/qthttpserver-security.qdoc 
new/qthttpserver-everywhere-src-6.12.0/doc/qthttpserver-security.qdoc
--- old/qthttpserver-everywhere-src-6.11.2/doc/qthttpserver-security.qdoc       
2026-08-12 04:49:05.000000000 +0200
+++ new/qthttpserver-everywhere-src-6.12.0/doc/qthttpserver-security.qdoc       
2026-09-27 12:11:39.000000000 +0200
@@ -27,7 +27,10 @@
     Ideally there should be no access to the internet at all. This is the
     safest setup, but you often need internet access. If Qt HTTP Server
     is bound to localhost or to a \l{QLocalServer}, it does not accept
-    connections from the internet.
+    connections from the internet. If multiple clients are connected to
+    127.0.0.1, the connections are added to connections per host,
+    and \l{QHttpServerConfiguration::}{setMaximumConnectionsPerHost()}
+    is affected. By default, no per-host connection limit is set.
 
     \section2 Binding to QSslServer on the internet
 
@@ -58,6 +61,19 @@
             \l{QHttpServerConfiguration::}{setRateLimitPerSecond()}.
             By default, there is no rate limit. When the limit is exceeded,
             the server responds with status code 429 (Too Many Requests).
+
+        \li Configure the maximum number of simultaneous connections
+            using \l{QHttpServerConfiguration::}{setMaximumConnections()}.
+            By default, there is no connection limit. When the limit is
+            exceeded, the server responds with status code 429 (Too Many
+            Requests), and the connection is closed.
+
+        \li Configure the maximum number of simultaneous
+            connections per client IP using
+            \l{QHttpServerConfiguration::}{setMaximumConnectionsPerHost()}.
+            By default, there is no limit. When the limit is exceeded,
+            the server responds with status code 429 (Too Many Requests), and
+            the connection is closed.
     \endlist
 
     \section2 Connection limits
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/qthttpserver-everywhere-src-6.11.2/licenseRule.json 
new/qthttpserver-everywhere-src-6.12.0/licenseRule.json
--- old/qthttpserver-everywhere-src-6.11.2/licenseRule.json     2026-08-12 
04:49:05.000000000 +0200
+++ new/qthttpserver-everywhere-src-6.12.0/licenseRule.json     2026-09-27 
12:11:39.000000000 +0200
@@ -58,7 +58,9 @@
     },
     {
         "comment": "Files with the following endings are Documentation 
licensed.",
-        "file_pattern_ending": [".qdoc", ".qdocinc" , ".qdocconf", "README", 
"qt_attribution.json"],
+        "file_pattern_ending": [".qdoc", ".qdocinc" , ".qdocconf",
+                                "README", "CONTRIBUTING.md",
+                                "qt_attribution.json"],
         "location":{
             "": {
                 "comment": "",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qthttpserver-everywhere-src-6.11.2/src/httpserver/qabstracthttpserver.cpp 
new/qthttpserver-everywhere-src-6.12.0/src/httpserver/qabstracthttpserver.cpp
--- 
old/qthttpserver-everywhere-src-6.11.2/src/httpserver/qabstracthttpserver.cpp   
    2026-08-12 04:49:05.000000000 +0200
+++ 
new/qthttpserver-everywhere-src-6.12.0/src/httpserver/qabstracthttpserver.cpp   
    2026-09-27 12:11:39.000000000 +0200
@@ -14,6 +14,10 @@
 #include <QtCore/qloggingcategory.h>
 #include <QtNetwork/qtcpserver.h>
 #include <QtNetwork/qtcpsocket.h>
+#if QT_CONFIG(ssl) && QT_CONFIG(http)
+#include <QtNetwork/private/qhttp2connection_p.h>
+#endif
+
 #if QT_CONFIG(localserver)
 #include <QtNetwork/qlocalserver.h>
 #include <QtNetwork/qlocalsocket.h>
@@ -31,7 +35,29 @@
 
 QT_BEGIN_NAMESPACE
 
-Q_STATIC_LOGGING_CATEGORY(lcHttpServer, "qt.httpserver")
+Q_STATIC_LOGGING_CATEGORY(lcHttpServer, "qt.httpserver", QtWarningMsg)
+
+bool LessHostAddress::operator()(const QHostAddress &lhs, const QHostAddress 
&rhs) const
+{
+    bool lhsIsIPv4 = false;
+    bool rhsIsIPv4 = false;
+    quint32 lhsIpAddressV4 = lhs.toIPv4Address(&lhsIsIPv4);
+    quint32 rhsIpAddressV4 = rhs.toIPv4Address(&rhsIsIPv4);
+    if (lhsIsIPv4 != rhsIsIPv4)
+        return lhsIsIPv4;
+    if (lhsIsIPv4)
+        return lhsIpAddressV4 < rhsIpAddressV4;
+
+    Q_IPV6ADDR lhsIpAddressV6 = lhs.toIPv6Address();
+    Q_IPV6ADDR rhsIpAddressV6 = rhs.toIPv6Address();
+    for (int i = 0; i < 16; ++i) {
+        if (lhsIpAddressV6[i] != rhsIpAddressV6[i])
+            return lhsIpAddressV6[i] < rhsIpAddressV6[i];
+    }
+
+    return false;
+}
+
 
 /*!
     \internal
@@ -84,9 +110,23 @@
 
 void QAbstractHttpServerPrivate::createHttp1Handler(QIODevice *socket)
 {
+    using namespace std::chrono_literals;
     Q_Q(QAbstractHttpServer);
 
+    if (hasTooManyConnections(socket)) {
+        if (auto tcpSocket = qobject_cast<QTcpSocket *>(socket)) {
+            QByteArray buffer;
+            buffer.append("HTTP/1.1 429 Too Many Requests");
+            buffer.append("\r\nConnection: close\r\n\r\n");
+            tcpSocket->write(buffer);
+            tcpSocket->flush();
+            QTimer::singleShot(1s, tcpSocket, &QObject::deleteLater);
+        }
+        return;
+    }
+
     auto handler = new QHttpServerHttp1ProtocolHandler(q, socket, 
&requestFilter, &configuration);
+    updateSocketCounter(socket);
     QObject::connect(&heartbeatTimer, &QTimer::timeout,
             handler, &QHttpServerHttp1ProtocolHandler::checkKeepAliveTimeout);
 }
@@ -94,14 +134,89 @@
 #if QT_CONFIG(ssl) && QT_CONFIG(http)
 void QAbstractHttpServerPrivate::createHttp2Handler(QIODevice *socket)
 {
+    using namespace std::chrono_literals;
     Q_Q(QAbstractHttpServer);
 
+    if (hasTooManyConnections(socket)) {
+        if (auto tcpSocket = qobject_cast<QTcpSocket *>(socket)) {
+            auto *connection = QHttp2Connection::createDirectServerConnection(
+                                    socket, q->http2Configuration());
+            connection->close(Http2::Http2Error::ENHANCE_YOUR_CALM);
+            QTimer::singleShot(1s, tcpSocket, &QObject::deleteLater);
+        }
+        return;
+    }
+
     auto handler = new QHttpServerHttp2ProtocolHandler(q, socket, 
&requestFilter);
+    updateSocketCounter(socket);
     QObject::connect(&heartbeatTimer, &QTimer::timeout,
             handler, &QHttpServerHttp2ProtocolHandler::checkKeepAliveTimeout);
 }
 #endif
 
+bool QAbstractHttpServerPrivate::hasTooManyConnections(QIODevice *socket)
+{
+    if (configuration.maximumConnections() != 0
+        && totalConnections >= configuration.maximumConnections())
+        return true;
+
+    if (configuration.maximumConnectionsPerHost() == 0)
+        return false;
+
+    if (auto tcpSocket = qobject_cast<QTcpSocket *>(socket)) {
+        auto foundNumberOfConnections = 
connectionsPerHost.find(tcpSocket->peerAddress());
+        if (foundNumberOfConnections != connectionsPerHost.end()) {
+            if (foundNumberOfConnections->second >= 
configuration.maximumConnectionsPerHost()) {
+                qCInfo(lcHttpServer) << "QAbstractHttpServer:"
+                                     << "closing socket: too many connections 
from"
+                                     << tcpSocket->peerAddress().toString();
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+void QAbstractHttpServerPrivate::updateSocketCounter(QIODevice *socket)
+{
+    // If there are no limits on connections per host or in total, there's no 
point in tracking
+    // the amount of connections, so we skip doing so.
+    if (configuration.maximumConnectionsPerHost() == 0 && 
configuration.maximumConnections() == 0)
+        return;
+
+    if (auto tcpSocket = qobject_cast<QTcpSocket *>(socket)) {
+        auto [it, _] = 
connectionsPerHost.try_emplace(tcpSocket->peerAddress(), 0);
+        ++(it->second);
+        ++totalConnections;
+        QObjectPrivate::connect(tcpSocket, &QAbstractSocket::disconnected, 
this,
+                                
&QAbstractHttpServerPrivate::socketDisconnected);
+    }
+}
+
+void QAbstractHttpServerPrivate::socketDisconnected()
+{
+
+    Q_Q(QAbstractHttpServer);
+    if (auto tcpSocket = qobject_cast<QTcpSocket *>(q->sender())) {
+        --totalConnections;
+        auto foundNumberOfConnections = 
connectionsPerHost.find(tcpSocket->peerAddress());
+        if (foundNumberOfConnections != connectionsPerHost.end()) {
+            if (foundNumberOfConnections->second == 1)
+                connectionsPerHost.erase(foundNumberOfConnections);
+            else
+                --(foundNumberOfConnections->second);
+        }
+    }
+}
+
+#if QT_CONFIG(ssl)
+void QAbstractHttpServerPrivate::handleStartedEncryptionHandshake(QSslSocket 
*socket)
+{
+    if (hasTooManyConnections(socket))
+        socket->close();
+}
+#endif
+
 void QAbstractHttpServerPrivate::restartHeartbeatTimer()
 {
     if (heartbeatTimer.isActive())
@@ -224,6 +339,13 @@
     QObjectPrivate::connect(server, &QTcpServer::pendingConnectionAvailable, d,
                             &QAbstractHttpServerPrivate::handleNewConnections,
                             Qt::UniqueConnection);
+#if QT_CONFIG(ssl)
+    if (auto *sslServer = qobject_cast<QSslServer *>(server)) {
+         
QObjectPrivate::connect(sslServer,&QSslServer::startedEncryptionHandshake, d,
+                                 
&QAbstractHttpServerPrivate::handleStartedEncryptionHandshake,
+                                 Qt::UniqueConnection);
+    }
+#endif
     return true;
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qthttpserver-everywhere-src-6.11.2/src/httpserver/qabstracthttpserver_p.h 
new/qthttpserver-everywhere-src-6.12.0/src/httpserver/qabstracthttpserver_p.h
--- 
old/qthttpserver-everywhere-src-6.11.2/src/httpserver/qabstracthttpserver_p.h   
    2026-08-12 04:49:05.000000000 +0200
+++ 
new/qthttpserver-everywhere-src-6.12.0/src/httpserver/qabstracthttpserver_p.h   
    2026-09-27 12:11:39.000000000 +0200
@@ -33,11 +33,17 @@
 
 #if QT_CONFIG(ssl)
 #include <QtNetwork/qhttp2configuration.h>
+#include <QtNetwork/qsslsocket.h>
 #endif
 
 QT_BEGIN_NAMESPACE
 
 class QHttpServerRequest;
+class LessHostAddress
+{
+public:
+    [[nodiscard]] bool operator()(const QHostAddress &lhs, const QHostAddress 
&rhs) const;
+};
 
 class QAbstractHttpServerPrivate: public QObjectPrivate
 {
@@ -65,7 +71,12 @@
     void createHttp2Handler(QIODevice *socket);
 #endif
     void restartHeartbeatTimer();
-
+    [[nodiscard]] bool hasTooManyConnections(QIODevice *socket);
+    void updateSocketCounter(QIODevice *socket);
+    void socketDisconnected();
+#if QT_CONFIG(ssl)
+    void handleStartedEncryptionHandshake(QSslSocket *socket);
+#endif
 #if defined(QT_WEBSOCKETS_LIB)
     mutable bool handlingWebSocketUpgrade = false;
     struct WebSocketUpgradeVerifier
@@ -81,6 +92,8 @@
     QHttpServerConfiguration configuration;
     QHttpServerRequestFilter requestFilter;
     QTimer heartbeatTimer;
+    std::map<QHostAddress, quint32, LessHostAddress> connectionsPerHost;
+    quint32 totalConnections = 0;
 };
 
 QT_END_NAMESPACE
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qthttpserver-everywhere-src-6.11.2/src/httpserver/qhttpserverconfiguration.cpp
 
new/qthttpserver-everywhere-src-6.12.0/src/httpserver/qhttpserverconfiguration.cpp
--- 
old/qthttpserver-everywhere-src-6.11.2/src/httpserver/qhttpserverconfiguration.cpp
  2026-08-12 04:49:05.000000000 +0200
+++ 
new/qthttpserver-everywhere-src-6.12.0/src/httpserver/qhttpserverconfiguration.cpp
  2026-09-27 12:11:39.000000000 +0200
@@ -18,6 +18,8 @@
     bool equals(const QHttpServerConfigurationPrivate &other) const noexcept
     {
         return rateLimit == other.rateLimit
+            && maxConnectionsPerHost == other.maxConnectionsPerHost
+            && maxConnections == other.maxConnections
             && keepAliveTimeout == other.keepAliveTimeout
             && whitelist == other.whitelist
             && blacklist == other.blacklist
@@ -29,6 +31,8 @@
     }
 
     quint32 rateLimit = 0;
+    quint32 maxConnectionsPerHost = 0;
+    quint32 maxConnections = 0;
     std::chrono::seconds keepAliveTimeout = std::chrono::seconds(15);
     QList<std::pair<QHostAddress, int>> whitelist;
     QList<std::pair<QHostAddress, int>> blacklist;
@@ -47,6 +51,8 @@
     Such a configuration has the following values:
      \list
          \li Rate limit is disabled.
+         \li Maximum connections is disabled.
+         \li Maximum connections per host is disabled.
          \li Keep-alive timeout is set to 15 seconds.
          \li Whitelist is empty.
          \li Blacklist is empty.
@@ -124,6 +130,86 @@
 }
 
 /*!
+    \since 6.12
+
+    Sets limit on \a maxPerHost simultaneous connections
+    per host that will be accepted by QHttpServer.
+    If the limit is exceeded, QHttpServer will respond with
+    QHttpServerResponder::StatusCode::TooManyRequests.
+
+    If \a maxPerHost is set to 0, the per-host
+    connection limit is disabled. This should be done when
+    running behind a reverse proxy, as all incoming
+    sockets will appear to originate from the reverse proxy.
+
+    When the per-host connection limit is reached, HTTP/1
+    connections are closed with a 429 (Too Many Requests) response.
+    For SSL connections the connection is closed when the limit is exceeded.
+
+    By default this is disabled.
+
+    \sa maximumConnectionsPerHost(), QHttpServerResponder::StatusCode
+*/
+void QHttpServerConfiguration::setMaximumConnectionsPerHost(quint32 maxPerHost)
+{
+    d.detach();
+    d->maxConnectionsPerHost = maxPerHost;
+}
+
+/*!
+    \since 6.12
+
+    Returns maximum number of simultaneous connections
+    per host that will be accepted by the server.
+    The host is identified by the IP address of the incoming TCP
+    connection.
+
+    Returns 0 if the per-host connection limit is disabled.
+
+    \sa setMaximumConnectionsPerHost()
+*/
+quint32 QHttpServerConfiguration::maximumConnectionsPerHost() const
+{
+    return d->maxConnectionsPerHost;
+}
+
+/*!
+    \since 6.12
+
+    Sets limit of \a maxConnections on the total simultaneous
+    connections that will be accepted by the server.
+    If the limit is reached, the server rejects new connections. For
+    HTTP/1 connections, QHttpServer responds with
+    QHttpServerResponder::StatusCode::TooManyRequests and closes the 
connection.
+
+    If \a maxConnections is set to 0, the total connection
+    limit is disabled.
+
+    By default this limit is disabled.
+
+    \sa maximumConnections(), QHttpServerResponder::StatusCode
+*/
+void QHttpServerConfiguration::setMaximumConnections(quint32 maxConnections)
+{
+    d.detach();
+    d->maxConnections = maxConnections;
+}
+
+/*!
+    \since 6.12
+
+    Returns the maximum number of simultaneous connections
+    accepted by the server in total.
+
+    Returns 0 if the total connection limit is disabled.
+
+    \sa setMaximumConnections()
+*/
+quint32 QHttpServerConfiguration::maximumConnections() const
+{
+    return d->maxConnections;
+}
+/*!
     \since 6.10
 
     Sets \a timeout as keep-alive timeout for QHttpServer.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qthttpserver-everywhere-src-6.11.2/src/httpserver/qhttpserverconfiguration.h
 
new/qthttpserver-everywhere-src-6.12.0/src/httpserver/qhttpserverconfiguration.h
--- 
old/qthttpserver-everywhere-src-6.11.2/src/httpserver/qhttpserverconfiguration.h
    2026-08-12 04:49:05.000000000 +0200
+++ 
new/qthttpserver-everywhere-src-6.12.0/src/httpserver/qhttpserverconfiguration.h
    2026-09-27 12:11:39.000000000 +0200
@@ -34,6 +34,12 @@
     Q_HTTPSERVER_EXPORT void setRateLimitPerSecond(quint32 maxRequests);
     Q_HTTPSERVER_EXPORT quint32 rateLimitPerSecond() const;
 
+    Q_HTTPSERVER_EXPORT void setMaximumConnectionsPerHost(quint32 maxPerHost);
+    Q_HTTPSERVER_EXPORT quint32 maximumConnectionsPerHost() const;
+
+    Q_HTTPSERVER_EXPORT void setMaximumConnections(quint32 maxConnections);
+    Q_HTTPSERVER_EXPORT quint32 maximumConnections() const;
+
     Q_HTTPSERVER_EXPORT void setKeepAliveTimeout(std::chrono::seconds timeout);
     Q_HTTPSERVER_EXPORT std::chrono::seconds keepAliveTimeout() const;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qthttpserver-everywhere-src-6.11.2/src/httpserver/qhttpserverstream_p.h 
new/qthttpserver-everywhere-src-6.12.0/src/httpserver/qhttpserverstream_p.h
--- old/qthttpserver-everywhere-src-6.11.2/src/httpserver/qhttpserverstream_p.h 
2026-08-12 04:49:05.000000000 +0200
+++ new/qthttpserver-everywhere-src-6.12.0/src/httpserver/qhttpserverstream_p.h 
2026-09-27 12:11:39.000000000 +0200
@@ -30,12 +30,14 @@
 
 class QTcpSocket;
 class QHttpServerResponderPrivate;
+class QAbstractHttpServerPrivate;
 
 class QHttpServerStream : public QObject
 {
     Q_OBJECT
 
     friend class QHttpServerResponderPrivate;
+    friend class QAbstractHttpServerPrivate;
 
 protected:
     QHttpServerStream(QIODevice *socket, QHttpServerRequestFilter *filter,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/qthttpserver-everywhere-src-6.11.2/tests/auto/qhttpserver/tst_qhttpserver.cpp
 
new/qthttpserver-everywhere-src-6.12.0/tests/auto/qhttpserver/tst_qhttpserver.cpp
--- 
old/qthttpserver-everywhere-src-6.11.2/tests/auto/qhttpserver/tst_qhttpserver.cpp
   2026-08-12 04:49:05.000000000 +0200
+++ 
new/qthttpserver-everywhere-src-6.12.0/tests/auto/qhttpserver/tst_qhttpserver.cpp
   2026-09-27 12:11:39.000000000 +0200
@@ -21,6 +21,7 @@
 #include <QtCore/qjsonobject.h>
 #include <QtCore/qjsonvalue.h>
 #include <QtCore/qjsonarray.h>
+#include <QtCore/qloggingcategory.h>
 #include <QtCore/qsemaphore.h>
 #include <QtCore/qset.h>
 #include <QtCore/qtimer.h>
@@ -44,7 +45,6 @@
 #endif
 
 #include <QtTest/private/qtesthelpers_p.h>
-
 #include <array>
 
 QT_BEGIN_NAMESPACE
@@ -255,6 +255,10 @@
     void concurrentRequestsToSequentialDevice();
     void timeoutConnection();
     void useCanceledResponders();
+    void maximumConnectionsPerHost_data();
+    void maximumConnectionsPerHost();
+    void maximumConnections_data();
+    void maximumConnections();
 
 #if QT_CONFIG(localserver)
     void localSocket();
@@ -267,7 +271,9 @@
     QHttpServer httpserver;
     QString clearUrlBase;
     QString sslUrlBase;
-    std::array<QNetworkAccessManager, 10> networkAccessManagers;
+    QString captureBase;
+    static constexpr qsizetype numberOfNetworkAccessManagers = 10;
+    std::array<QNetworkAccessManager, numberOfNetworkAccessManagers> 
networkAccessManagers;
     QNetworkAccessManager &networkAccessManager = networkAccessManagers[0];
     ReplyObject replyObject;
     std::vector<std::unique_ptr<QHttpServerResponder>> responders;
@@ -891,7 +897,8 @@
     if (useSsl && QTestPrivate::isSecureTransportBlockingTest())
         QSKIP("SslServer is blocking the test execution while trying to access 
the login keychain");
 #endif // QT_CONFIG(ssl)
-    networkAccessManager.clearConnectionCache();
+    for (auto &qnam : networkAccessManagers)
+        qnam.clearConnectionCache();
 }
 
 void tst_QHttpServer::routeGet_data()
@@ -1464,25 +1471,15 @@
     QString urlBase = useSsl ? sslUrlBase : clearUrlBase;
     QNetworkRequest request;
     request.setAttribute(QNetworkRequest::Http2AllowedAttribute, useHttp2);
-
-    httpserver.route("/capture-this/", this, [&urlBase] () {
-        return urlBase;
-    });
-
-    QString msg = urlBase + "/pod";
-    httpserver.route("/capture-non-pod-data/", this, [&msg] () {
-        return msg;
+    captureBase = urlBase;
+    httpserver.route("/capture-this/", this, [this] () {
+        return captureBase;
     });
 
     request.setUrl(QUrl(urlBase.arg("/capture-this/")));
     checkReply(networkAccessManager.get(request), urlBase);
     if (QTest::currentTestFailed())
         return;
-
-    request.setUrl(QUrl(urlBase.arg("/capture-non-pod-data/")));
-    checkReply(networkAccessManager.get(request), msg);
-    if (QTest::currentTestFailed())
-        return;
 }
 
 void tst_QHttpServer::afterRequest()
@@ -2341,6 +2338,144 @@
         responder->writeEndChunked("end");
 }
 
+void tst_QHttpServer::maximumConnectionsPerHost_data()
+{
+    QTest::addColumn<int>("limit");
+    QTest::addColumn<int>("expectedOkCount");
+
+    QTest::newRow("no-limit") << 0 << numberOfNetworkAccessManagers;
+    QTest::newRow("same-as-number-of-connections")
+                    << numberOfNetworkAccessManagers << 
numberOfNetworkAccessManagers;
+    QTest::newRow("total-limit-5") << 5 << 5;
+}
+
+void tst_QHttpServer::maximumConnectionsPerHost()
+{
+#if QT_CONFIG(concurrent)
+    QFETCH_GLOBAL(bool, useSsl);
+    QFETCH_GLOBAL(bool, useHttp2);
+
+    QFETCH(int, limit);
+    QFETCH(int, expectedOkCount);
+    const QString urlBase = useSsl ? sslUrlBase : clearUrlBase;
+
+    auto cleanup = qScopeGuard([this] {
+        QHttpServerConfiguration config;
+        httpserver.setConfiguration(config);
+        for (auto &qnam : networkAccessManagers)
+            qnam.clearConnectionCache();
+        QCoreApplication::processEvents();
+        QLoggingCategory::setFilterRules(QStringLiteral(""));
+    });
+
+    
QLoggingCategory::setFilterRules(QStringLiteral("qt.network.http2.warning=false"));
+    constexpr int waitInterval = 2000;
+    const QByteArray returnValue = QByteArray::number(waitInterval);
+    const QUrl requestUrl(urlBase.arg("/wait/") + returnValue);
+    constexpr qsizetype NumberOfConnections = numberOfNetworkAccessManagers;
+    std::array<std::unique_ptr<QNetworkReply>, NumberOfConnections> replies;
+    QThreadPool::globalInstance()->setMaxThreadCount(NumberOfConnections + 1);
+    QNetworkRequest req(requestUrl);
+    req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
+    req.setAttribute(QNetworkRequest::Http2AllowedAttribute, useHttp2);
+    QHttpServerConfiguration config;
+    config.setMaximumConnectionsPerHost(limit);
+    httpserver.setConfiguration(config);
+
+    for (qsizetype i = 0; i < NumberOfConnections; ++i)
+        replies[i].reset(networkAccessManagers[i].get(req));
+
+    int okCount = 0;
+    for (qsizetype i = 0; i < NumberOfConnections; ++i) {
+        QTRY_VERIFY(replies[i]->isFinished());
+        if (replies[i]->error() == QNetworkReply::NoError) {
+            ++okCount;
+        } else {
+            if (!useHttp2) {
+                bool isInt = false;
+                const int statusCode =
+                        
replies[i]->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(&isInt);
+                QVERIFY(isInt);
+                QCOMPARE(statusCode, 429);
+            }
+        }
+    }
+    QCOMPARE(okCount, expectedOkCount);
+#else
+    QSKIP("QtConcurrent is not available, skipping test");
+#endif // QT_CONFIG(concurrent)
+}
+
+void tst_QHttpServer::maximumConnections_data()
+{
+    QTest::addColumn<int>("limit");
+    QTest::addColumn<int>("expectedOkCount");
+
+    QTest::newRow("no-limit") << 0 << numberOfNetworkAccessManagers;
+    QTest::newRow("same-as-number-of-connections")
+                    << numberOfNetworkAccessManagers << 
numberOfNetworkAccessManagers;
+    QTest::newRow("total-limit-5") << 5 << 5;
+}
+
+void tst_QHttpServer::maximumConnections()
+{
+#if QT_CONFIG(concurrent)
+    QFETCH_GLOBAL(bool, useSsl);
+    QFETCH_GLOBAL(bool, useHttp2);
+
+    QFETCH(int, limit);
+    QFETCH(int, expectedOkCount);
+    const QString urlBase = useSsl ? sslUrlBase : clearUrlBase;
+
+    auto cleanup = qScopeGuard([this] {
+        QHttpServerConfiguration config;
+        httpserver.setConfiguration(config);
+        for (auto &qnam : networkAccessManagers)
+            qnam.clearConnectionCache();
+        QCoreApplication::processEvents();
+        QLoggingCategory::setFilterRules(QStringLiteral(""));
+    });
+
+    
QLoggingCategory::setFilterRules(QStringLiteral("qt.network.http2.warning=false"));
+    constexpr int waitInterval = 2000;
+    const QByteArray returnValue = QByteArray::number(waitInterval);
+    const QUrl requestUrl(urlBase.arg("/wait/") + returnValue);
+    constexpr qsizetype NumberOfConnections = numberOfNetworkAccessManagers;
+    std::array<std::unique_ptr<QNetworkReply>, NumberOfConnections> replies;
+    QThreadPool::globalInstance()->setMaxThreadCount(NumberOfConnections + 1);
+    QNetworkRequest req(requestUrl);
+    req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
+    req.setAttribute(QNetworkRequest::Http2AllowedAttribute, useHttp2);
+    QHttpServerConfiguration config;
+    config.setMaximumConnections(limit);
+    httpserver.setConfiguration(config);
+
+    for (qsizetype i = 0; i < NumberOfConnections; ++i)
+        replies[i].reset(networkAccessManagers[i].get(req));
+
+    int okCount = 0;
+    for (qsizetype i = 0; i < NumberOfConnections; ++i) {
+        QTRY_VERIFY(replies[i]->isFinished());
+        if (replies[i]->error() == QNetworkReply::NoError) {
+            ++okCount;
+            } else {
+                if (!useHttp2) {
+                    bool isInt = false;
+                    const int statusCode =
+                        
replies[i]->attribute(QNetworkRequest::HttpStatusCodeAttribute)
+                        .toInt(&isInt);
+                    QVERIFY(isInt);
+                    QCOMPARE(statusCode, 429);
+                }
+            }
+    }
+    QCOMPARE(okCount, expectedOkCount);
+#else
+    QSKIP("QtConcurrent is not available, skipping test");
+#endif // QT_CONFIG(concurrent)
+}
+
+
 QT_END_NAMESPACE
 
 Q_DECLARE_METATYPE(CustomArg);

Reply via email to