summaryrefslogtreecommitdiffstats
path: root/src/network/access
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/access')
-rw-r--r--src/network/access/qbytedatabuffer_p.h2
-rw-r--r--src/network/access/qformdatabuilder.cpp1
-rw-r--r--src/network/access/qformdatabuilder.h1
-rw-r--r--src/network/access/qhttp2connection.cpp77
-rw-r--r--src/network/access/qhttp2connection_p.h24
-rw-r--r--src/network/access/qhttp2protocolhandler_p.h1
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp12
-rw-r--r--src/network/access/qhttpnetworkconnection_p.h6
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp16
-rw-r--r--src/network/access/qhttpthreaddelegate.cpp2
-rw-r--r--src/network/access/qhttpthreaddelegate_p.h2
-rw-r--r--src/network/access/qnetworkaccesscache.cpp5
-rw-r--r--src/network/access/qnetworkcookie.cpp1
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp3
-rw-r--r--src/network/access/qnetworkrequest.cpp99
-rw-r--r--src/network/access/qnetworkrequest.h21
-rw-r--r--src/network/access/qtcpkeepaliveconfiguration_p.h50
17 files changed, 297 insertions, 26 deletions
diff --git a/src/network/access/qbytedatabuffer_p.h b/src/network/access/qbytedatabuffer_p.h
index a119093cf7e..036b562d06a 100644
--- a/src/network/access/qbytedatabuffer_p.h
+++ b/src/network/access/qbytedatabuffer_p.h
@@ -280,6 +280,8 @@ public:
}
return false;
}
+
+ const QByteArray &last() const { return buffers.last(); }
};
QT_END_NAMESPACE
diff --git a/src/network/access/qformdatabuilder.cpp b/src/network/access/qformdatabuilder.cpp
index 470e285c6ad..debefd24634 100644
--- a/src/network/access/qformdatabuilder.cpp
+++ b/src/network/access/qformdatabuilder.cpp
@@ -9,6 +9,7 @@
#include "QtCore/qmimedatabase.h"
#endif
+#include <variant>
#include <vector>
QT_BEGIN_NAMESPACE
diff --git a/src/network/access/qformdatabuilder.h b/src/network/access/qformdatabuilder.h
index 7d667aea21c..3992776161d 100644
--- a/src/network/access/qformdatabuilder.h
+++ b/src/network/access/qformdatabuilder.h
@@ -15,7 +15,6 @@
#include <QtCore/qstring.h>
#include <memory>
-#include <variant>
#ifndef Q_OS_WASM
QT_REQUIRE_CONFIG(http);
diff --git a/src/network/access/qhttp2connection.cpp b/src/network/access/qhttp2connection.cpp
index 2895e8335d2..c0b07ddd652 100644
--- a/src/network/access/qhttp2connection.cpp
+++ b/src/network/access/qhttp2connection.cpp
@@ -34,8 +34,38 @@ using namespace Http2;
\sa QHttp2Connection
*/
-QHttp2Stream::QHttp2Stream(QHttp2Connection *connection, quint32 streamID) noexcept
- : QObject(connection), m_streamID(streamID)
+/*!
+ \struct QHttp2Stream::Configuration
+ \inmodule QtNetwork
+ \internal
+
+ \brief Configuration options for a QHttp2Stream.
+
+ The Configuration struct holds options that control stream behavior.
+
+ \sa QHttp2Connection::createStream()
+*/
+
+/*!
+ \variable QHttp2Stream::Configuration::useDownloadBuffer
+
+ Controls whether incoming DATA frames, from QHttp2Stream::dataReceived(),
+ are buffered. The default is \c true.
+
+ You may disable buffering for client-initiated streams when the
+ application processes DATA immediately.
+
+ Buffering must remain enabled for pushed streams. A pushed stream can
+ receive DATA before the application becomes aware of them and the buffered
+ DATA is required to deliver the pushed response.
+
+ \sa QHttp2Stream::downloadBuffer(), QHttp2Stream::takeDownloadBuffer(),
+ QHttp2Configuration::serverPushEnabled(), QHttp2Stream::dataReceived()
+*/
+
+QHttp2Stream::QHttp2Stream(QHttp2Connection *connection, quint32 streamID,
+ Configuration configuration) noexcept
+ : QObject(connection), m_streamID(streamID), m_configuration(configuration)
{
Q_ASSERT(connection);
Q_ASSERT(streamID); // stream id 0 is reserved for connection control messages
@@ -213,6 +243,12 @@ QHttp2Stream::~QHttp2Stream() noexcept {
Returns the buffer containing the data received from the remote peer.
*/
+/*!
+ \fn QHttp2Stream::Configuration QHttp2Stream::configuration() const
+
+ Returns the configuration of this stream.
+*/
+
void QHttp2Stream::finishWithError(Http2::Http2Error errorCode, const QString &message)
{
qCDebug(qHttp2ConnectionLog, "[%p] stream %u finished with error: %ls (error code: %u)",
@@ -697,8 +733,14 @@ void QHttp2Stream::handleDATA(const Frame &inboundFrame)
inboundFrame.dataSize());
if (endStream)
transitionState(StateTransition::CloseRemote);
- emit dataReceived(fragment, endStream);
- m_downloadBuffer.append(std::move(fragment));
+ const auto shouldBuffer = m_configuration.useDownloadBuffer && !fragment.isEmpty();
+ if (shouldBuffer) {
+ // Only non-empty fragments get appended!
+ m_downloadBuffer.append(std::move(fragment));
+ emit dataReceived(m_downloadBuffer.last(), endStream);
+ } else {
+ emit dataReceived(fragment, endStream);
+ }
}
if (!endStream && m_recvWindow < connection->streamInitialReceiveWindowSize / 2) {
@@ -885,23 +927,35 @@ QHttp2Connection *QHttp2Connection::createDirectServerConnection(QIODevice *sock
}
/*!
- Creates a stream on this connection.
+ \fn QH2Expected<QHttp2Stream *, QHttp2Connection::CreateStreamError> QHttp2Connection::createStream()
+ Creates a stream on this connection, using the default QHttp2Stream::Configuration.
+
+//! [createStream]
Automatically picks the next available stream ID and returns a pointer to
the new stream, if possible. Otherwise returns an error.
\sa QHttp2Connection::CreateStreamError, QHttp2Stream
+//! [createStream]
+ \sa createStream(QHttp2Stream::Configuration)
+*/
+
+/*!
+ Creates a stream with \a configuration on this connection.
+
+ \include qhttp2connection.cpp createStream
*/
-QH2Expected<QHttp2Stream *, QHttp2Connection::CreateStreamError> QHttp2Connection::createStream()
+QH2Expected<QHttp2Stream *, QHttp2Connection::CreateStreamError>
+QHttp2Connection::createStream(QHttp2Stream::Configuration configuration)
{
Q_ASSERT(m_connectionType == Type::Client); // This overload is just for clients
if (m_nextStreamID > lastValidStreamID)
return { QHttp2Connection::CreateStreamError::StreamIdsExhausted };
- return createLocalStreamInternal();
+ return createLocalStreamInternal(configuration);
}
QH2Expected<QHttp2Stream *, QHttp2Connection::CreateStreamError>
-QHttp2Connection::createLocalStreamInternal()
+QHttp2Connection::createLocalStreamInternal(QHttp2Stream::Configuration conf)
{
if (m_goingAway)
return { QHttp2Connection::CreateStreamError::ReceivedGOAWAY };
@@ -909,7 +963,7 @@ QHttp2Connection::createLocalStreamInternal()
if (size_t(m_peerMaxConcurrentStreams) <= size_t(numActiveLocalStreams()))
return { QHttp2Connection::CreateStreamError::MaxConcurrentStreamsReached };
- if (QHttp2Stream *ptr = createStreamInternal_impl(streamID)) {
+ if (QHttp2Stream *ptr = createStreamInternal_impl(streamID, conf)) {
m_nextStreamID += 2;
return {ptr};
}
@@ -917,7 +971,8 @@ QHttp2Connection::createLocalStreamInternal()
return { QHttp2Connection::CreateStreamError::UnknownError };
}
-QHttp2Stream *QHttp2Connection::createStreamInternal_impl(quint32 streamID)
+QHttp2Stream *QHttp2Connection::createStreamInternal_impl(quint32 streamID,
+ QHttp2Stream::Configuration conf)
{
Q_ASSERT(streamID > m_lastIncomingStreamID || streamID >= m_nextStreamID);
@@ -930,7 +985,7 @@ QHttp2Stream *QHttp2Connection::createStreamInternal_impl(quint32 streamID)
if (!result.inserted)
return nullptr;
QPointer<QHttp2Stream> &stream = result.iterator.value();
- stream = new QHttp2Stream(this, streamID);
+ stream = new QHttp2Stream(this, streamID, conf);
stream->m_recvWindow = streamInitialReceiveWindowSize;
stream->m_sendWindow = streamInitialSendWindowSize;
diff --git a/src/network/access/qhttp2connection_p.h b/src/network/access/qhttp2connection_p.h
index f3f14145278..e2af7d7ab33 100644
--- a/src/network/access/qhttp2connection_p.h
+++ b/src/network/access/qhttp2connection_p.h
@@ -101,6 +101,11 @@ public:
Q_ENUM(State)
constexpr static quint8 DefaultPriority = 127;
+ struct Configuration
+ {
+ bool useDownloadBuffer = true;
+ };
+
~QHttp2Stream() noexcept;
// HTTP2 things
@@ -124,6 +129,8 @@ public:
QByteDataBuffer takeDownloadBuffer() noexcept { return std::exchange(m_downloadBuffer, {}); }
void clearDownloadBuffer() { m_downloadBuffer.clear(); }
+ Configuration configuration() const { return m_configuration; }
+
Q_SIGNALS:
void headersReceived(const HPack::HttpHeader &headers, bool endStream);
void headersUpdated();
@@ -154,7 +161,8 @@ private Q_SLOTS:
private:
friend class QHttp2Connection;
- QHttp2Stream(QHttp2Connection *connection, quint32 streamID) noexcept;
+ QHttp2Stream(QHttp2Connection *connection, quint32 streamID,
+ Configuration configuration) noexcept;
[[nodiscard]] QHttp2Connection *getConnection() const
{
@@ -201,6 +209,8 @@ private:
bool m_isReserved = false;
bool m_owningByteDevice = false;
+ const Configuration m_configuration;
+
friend tst_QHttp2Connection;
};
@@ -235,7 +245,12 @@ public:
createDirectServerConnection(QIODevice *socket, const QHttp2Configuration &config);
~QHttp2Connection();
- [[nodiscard]] QH2Expected<QHttp2Stream *, CreateStreamError> createStream();
+ [[nodiscard]] QH2Expected<QHttp2Stream *, CreateStreamError> createStream()
+ {
+ return createStream(QHttp2Stream::Configuration{});
+ }
+ [[nodiscard]] QH2Expected<QHttp2Stream *, CreateStreamError>
+ createStream(QHttp2Stream::Configuration config);
QHttp2Stream *getStream(quint32 streamId) const;
QHttp2Stream *promisedStream(const QUrl &streamKey) const
@@ -278,8 +293,9 @@ private:
friend class QHttp2Stream;
[[nodiscard]] QIODevice *getSocket() const { return qobject_cast<QIODevice *>(parent()); }
- QH2Expected<QHttp2Stream *, QHttp2Connection::CreateStreamError> createLocalStreamInternal();
- QHttp2Stream *createStreamInternal_impl(quint32 streamID);
+ QH2Expected<QHttp2Stream *, QHttp2Connection::CreateStreamError>
+ createLocalStreamInternal(QHttp2Stream::Configuration = {});
+ QHttp2Stream *createStreamInternal_impl(quint32 streamID, QHttp2Stream::Configuration = {});
bool isInvalidStream(quint32 streamID) noexcept;
bool streamWasResetLocally(quint32 streamID) noexcept;
diff --git a/src/network/access/qhttp2protocolhandler_p.h b/src/network/access/qhttp2protocolhandler_p.h
index 2fde9e4c9d5..37e960b19dc 100644
--- a/src/network/access/qhttp2protocolhandler_p.h
+++ b/src/network/access/qhttp2protocolhandler_p.h
@@ -93,7 +93,6 @@ private:
// Stream's lifecycle management:
QHttp2Stream *createNewStream(const HttpMessagePair &message, bool uploadDone = false);
void connectStream(const HttpMessagePair &message, QHttp2Stream *stream);
- quint32 popStreamToResume();
QHttp2Connection *h2Connection;
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index e0f5bfc2d64..1b8bfd5d72b 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -1485,6 +1485,18 @@ void QHttpNetworkConnection::setHttp2Parameters(const QHttp2Configuration &param
d->http2Parameters = params;
}
+QTcpKeepAliveConfiguration QHttpNetworkConnection::tcpKeepAliveParameters() const
+{
+ Q_D(const QHttpNetworkConnection);
+ return d->tcpKeepAliveConfiguration;
+}
+
+void QHttpNetworkConnection::setTcpKeepAliveParameters(QTcpKeepAliveConfiguration config)
+{
+ Q_D(QHttpNetworkConnection);
+ d->tcpKeepAliveConfiguration = config;
+}
+
// SSL support below
#ifndef QT_NO_SSL
void QHttpNetworkConnection::setSslConfiguration(const QSslConfiguration &config)
diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h
index 67b568caea8..3f60c5b3925 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -36,6 +36,7 @@
#include <private/http2protocol_p.h>
#include <private/qhttpnetworkconnectionchannel_p.h>
+#include <private/qtcpkeepaliveconfiguration_p.h>
#include <utility>
@@ -98,6 +99,9 @@ public:
QHttp2Configuration http2Parameters() const;
void setHttp2Parameters(const QHttp2Configuration &params);
+ QTcpKeepAliveConfiguration tcpKeepAliveParameters() const;
+ void setTcpKeepAliveParameters(QTcpKeepAliveConfiguration config);
+
#ifndef QT_NO_SSL
void setSslConfiguration(const QSslConfiguration &config);
void ignoreSslErrors(int channel = -1);
@@ -255,6 +259,8 @@ public:
QString peerVerifyName;
+ QTcpKeepAliveConfiguration tcpKeepAliveConfiguration = {};
+
friend class QHttpNetworkConnectionChannel;
};
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index ffd5d8ff333..e427175ce61 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -923,9 +923,19 @@ void QHttpNetworkConnectionChannel::_q_connected_abstract_socket(QAbstractSocket
// not sure yet if it helps, but it makes sense
absSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
- int kaIdleOption = qEnvironmentVariableIntegerValue(keepAliveIdleOption).value_or(TCP_KEEPIDLE_DEF);
- int kaIntervalOption = qEnvironmentVariableIntegerValue(keepAliveIntervalOption).value_or(TCP_KEEPINTVL_DEF);
- int kaCountOption = qEnvironmentVariableIntegerValue(keepAliveCountOption).value_or(TCP_KEEPCNT_DEF);
+ QTcpKeepAliveConfiguration keepAliveConfig = connection->tcpKeepAliveParameters();
+
+ auto getKeepAliveValue = [](int configValue,
+ const char* envName,
+ int defaultValue) {
+ if (configValue > 0)
+ return configValue;
+ return static_cast<int>(qEnvironmentVariableIntegerValue(envName).value_or(defaultValue));
+ };
+
+ int kaIdleOption = getKeepAliveValue(keepAliveConfig.idleTimeBeforeProbes.count(), keepAliveIdleOption, TCP_KEEPIDLE_DEF);
+ int kaIntervalOption = getKeepAliveValue(keepAliveConfig.intervalBetweenProbes.count(), keepAliveIntervalOption, TCP_KEEPINTVL_DEF);
+ int kaCountOption = getKeepAliveValue(keepAliveConfig.probeCount, keepAliveCountOption, TCP_KEEPCNT_DEF);
absSocket->setSocketOption(QAbstractSocket::KeepAliveIdleOption, kaIdleOption);
absSocket->setSocketOption(QAbstractSocket::KeepAliveIntervalOption, kaIntervalOption);
absSocket->setSocketOption(QAbstractSocket::KeepAliveCountOption, kaCountOption);
diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp
index fbbc55dc4a4..82455e96a81 100644
--- a/src/network/access/qhttpthreaddelegate.cpp
+++ b/src/network/access/qhttpthreaddelegate.cpp
@@ -327,6 +327,8 @@ void QHttpThreadDelegate::startRequest()
|| connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
httpConnection->setHttp2Parameters(http2Parameters);
}
+
+ httpConnection->setTcpKeepAliveParameters(tcpKeepAliveParameters);
#ifndef QT_NO_SSL
// Set the QSslConfiguration from this QNetworkRequest.
if (ssl)
diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h
index 2ce64dc9a17..5005f8c01c2 100644
--- a/src/network/access/qhttpthreaddelegate_p.h
+++ b/src/network/access/qhttpthreaddelegate_p.h
@@ -34,6 +34,7 @@
#include "qnetworkaccessauthenticationmanager_p.h"
#include <QtNetwork/private/http2protocol_p.h>
#include <QtNetwork/qhttpheaders.h>
+#include "qtcpkeepaliveconfiguration_p.h"
#ifndef QT_NO_SSL
#include <memory>
@@ -91,6 +92,7 @@ public:
QString incomingErrorDetail;
QHttp1Configuration http1Parameters;
QHttp2Configuration http2Parameters;
+ QTcpKeepAliveConfiguration tcpKeepAliveParameters = {};
protected:
// The zerocopy download buffer, if used:
diff --git a/src/network/access/qnetworkaccesscache.cpp b/src/network/access/qnetworkaccesscache.cpp
index bb1bdd87a8a..6ff70cd546d 100644
--- a/src/network/access/qnetworkaccesscache.cpp
+++ b/src/network/access/qnetworkaccesscache.cpp
@@ -5,11 +5,6 @@
#include "qnetworkaccesscache_p.h"
#include "QtCore/qpointer.h"
#include "QtCore/qdeadlinetimer.h"
-#include "qnetworkaccessmanager_p.h"
-#include "qnetworkreply_p.h"
-#include "qnetworkrequest.h"
-
-#include <vector>
//#define DEBUG_ACCESSCACHE
diff --git a/src/network/access/qnetworkcookie.cpp b/src/network/access/qnetworkcookie.cpp
index c20cd43a2fd..6c44e42dbba 100644
--- a/src/network/access/qnetworkcookie.cpp
+++ b/src/network/access/qnetworkcookie.cpp
@@ -5,7 +5,6 @@
#include "qnetworkcookie.h"
#include "qnetworkcookie_p.h"
-#include "qnetworkrequest.h"
#include "qnetworkreply.h"
#include "QtCore/qbytearray.h"
#include "QtCore/qdatetime.h"
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index f76d79571c3..9a27da00960 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -896,6 +896,9 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
// Propagate Http/2 settings:
delegate->http2Parameters = request.http2Configuration();
delegate->http1Parameters = request.http1Configuration();
+ delegate->tcpKeepAliveParameters.idleTimeBeforeProbes = request.tcpKeepAliveIdleTimeBeforeProbes();
+ delegate->tcpKeepAliveParameters.intervalBetweenProbes = request.tcpKeepAliveIntervalBetweenProbes();
+ delegate->tcpKeepAliveParameters.probeCount = request.tcpKeepAliveProbeCount();
if (request.attribute(QNetworkRequest::ConnectionCacheExpiryTimeoutSecondsAttribute).isValid())
delegate->connectionCacheExpiryTimeoutSeconds = request.attribute(QNetworkRequest::ConnectionCacheExpiryTimeoutSecondsAttribute).toInt();
diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp
index 5047fc77bd5..d41124f7b14 100644
--- a/src/network/access/qnetworkrequest.cpp
+++ b/src/network/access/qnetworkrequest.cpp
@@ -475,6 +475,9 @@ public:
decompressedSafetyCheckThreshold = other.decompressedSafetyCheckThreshold;
#endif
transferTimeout = other.transferTimeout;
+ idleTimeBeforeProbes = other.idleTimeBeforeProbes;
+ intervalBetweenProbes = other.intervalBetweenProbes;
+ probeCount = other.probeCount;
}
inline bool operator==(const QNetworkRequestPrivate &other) const
@@ -491,6 +494,9 @@ public:
#endif
&& transferTimeout == other.transferTimeout
&& QHttpHeadersHelper::compareStrict(httpHeaders, other.httpHeaders)
+ && idleTimeBeforeProbes == other.idleTimeBeforeProbes
+ && intervalBetweenProbes == other.intervalBetweenProbes
+ && probeCount == other.probeCount;
;
// don't compare cookedHeaders
}
@@ -508,6 +514,9 @@ public:
qint64 decompressedSafetyCheckThreshold = 10ll * 1024ll * 1024ll;
#endif
std::chrono::milliseconds transferTimeout = 0ms;
+ std::chrono::duration<int> idleTimeBeforeProbes{0};
+ std::chrono::duration<int> intervalBetweenProbes{0};
+ int probeCount = 0;
};
/*!
@@ -1035,6 +1044,96 @@ void QNetworkRequest::setDecompressedSafetyCheckThreshold(qint64 threshold)
}
#endif // QT_CONFIG(http)
+/*!
+ \since 6.11
+
+ Returns the time the connection needs to remain idle before TCP
+ starts sending keepalive probes, if the TCP Keepalive functionality has
+ been turned on.
+
+ \sa setIdleTimeBeforeProbes
+*/
+
+std::chrono::seconds QNetworkRequest::tcpKeepAliveIdleTimeBeforeProbes() const
+{
+ return d->idleTimeBeforeProbes;
+}
+
+/*!
+ \fn void QNetworkRequest::setTcpKeepAliveIdleTimeBeforeProbes(std::chrono::seconds idle)
+ \since 6.11
+
+ Sets the time the connection needs to remain idle before TCP starts
+ sending keepalive probes to be \a idle, if the TCP Keepalive
+ functionality has been turned on.
+
+ \sa idleTimeBeforeProbes
+*/
+
+void QNetworkRequest::doSetIdleTimeBeforeProbes(std::chrono::duration<int> seconds) noexcept
+{
+ d->idleTimeBeforeProbes = seconds;
+}
+
+/*!
+ \since 6.11
+
+ Returns the time between individual keepalive probes, if the TCP
+ Keepalive functionality has been turned on.
+
+ \sa setIntervalBetweenProbes
+*/
+
+std::chrono::seconds QNetworkRequest::tcpKeepAliveIntervalBetweenProbes() const
+{
+ return d->intervalBetweenProbes;
+}
+
+/*!
+ \fn void QNetworkRequest::setTcpKeepAliveIntervalBetweenProbes(std::chrono::seconds interval)
+ \since 6.11
+
+ Sets the time between individual keepalive probes to be \a interval,
+ if the TCP Keepalive functionality has been turned on.
+
+ \sa intervalBetweenProbes
+*/
+
+void QNetworkRequest::doSetIntervalBetweenProbes(std::chrono::duration<int> seconds) noexcept
+{
+ d->intervalBetweenProbes = seconds;
+}
+
+/*!
+ \since 6.11
+
+ Returns the maximum number of keepalive probes TCP should send before
+ dropping the connection, if the TCP Keepalive functionality has been
+ turned on.
+
+ \sa setIntervalBetweenProbes
+*/
+
+int QNetworkRequest::tcpKeepAliveProbeCount() const
+{
+ return d->probeCount;
+}
+
+/*!
+ \since 6.11
+
+ Sets the maximum number of keepalive \a probes TCP should send
+ before dropping the connection, if the TCP Keepalive functionality has
+ been turned on.
+
+ \sa probeCount
+*/
+
+void QNetworkRequest::setTcpKeepAliveProbeCount(int probes) noexcept
+{
+ d->probeCount = probes;
+}
+
#if QT_CONFIG(http) || defined (Q_OS_WASM)
/*!
\fn int QNetworkRequest::transferTimeout() const
diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h
index ea70255a718..49aa45233af 100644
--- a/src/network/access/qnetworkrequest.h
+++ b/src/network/access/qnetworkrequest.h
@@ -7,12 +7,15 @@
#include <QtNetwork/qtnetworkglobal.h>
#include <QtNetwork/qhttpheaders.h>
+
+#include <QtCore/qassert.h>
#include <QtCore/QSharedDataPointer>
#include <QtCore/QString>
#include <QtCore/QUrl>
#include <QtCore/QVariant>
#include <QtCore/q26numeric.h>
+#include <QtCore/q20utility.h>
#include <chrono>
@@ -178,6 +181,22 @@ public:
qint64 decompressedSafetyCheckThreshold() const;
void setDecompressedSafetyCheckThreshold(qint64 threshold);
#endif // QT_CONFIG(http)
+ std::chrono::seconds tcpKeepAliveIdleTimeBeforeProbes() const;
+ void setTcpKeepAliveIdleTimeBeforeProbes(std::chrono::seconds idle)
+ {
+ const auto r = q26::saturate_cast<int>(idle.count());
+ Q_PRE(q20::cmp_equal(r, idle.count()));
+ doSetIdleTimeBeforeProbes(std::chrono::duration<int>(r));
+ }
+ std::chrono::seconds tcpKeepAliveIntervalBetweenProbes() const;
+ void setTcpKeepAliveIntervalBetweenProbes(std::chrono::seconds interval)
+ {
+ const auto r = q26::saturate_cast<int>(interval.count());
+ Q_PRE(q20::cmp_equal(r, interval.count()));
+ doSetIntervalBetweenProbes(std::chrono::duration<int>(r));
+ }
+ int tcpKeepAliveProbeCount() const;
+ void setTcpKeepAliveProbeCount(int probes) noexcept;
#if QT_CONFIG(http) || defined (Q_OS_WASM)
QT_NETWORK_INLINE_SINCE(6, 8)
@@ -189,6 +208,8 @@ public:
void setTransferTimeout(std::chrono::milliseconds duration = DefaultTransferTimeout);
#endif // QT_CONFIG(http) || defined (Q_OS_WASM)
private:
+ void doSetIdleTimeBeforeProbes(std::chrono::duration<int> idle) noexcept;
+ void doSetIntervalBetweenProbes(std::chrono::duration<int> interval) noexcept;
QSharedDataPointer<QNetworkRequestPrivate> d;
friend class QNetworkRequestPrivate;
};
diff --git a/src/network/access/qtcpkeepaliveconfiguration_p.h b/src/network/access/qtcpkeepaliveconfiguration_p.h
new file mode 100644
index 00000000000..b8bd96666ef
--- /dev/null
+++ b/src/network/access/qtcpkeepaliveconfiguration_p.h
@@ -0,0 +1,50 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
+
+#ifndef QTCPKEEPALIVECONFIGURATION_P_H
+#define QTCPKEEPALIVECONFIGURATION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/private/qglobal_p.h>
+#include <QtNetwork/qtnetworkglobal.h>
+
+#include <chrono>
+
+QT_BEGIN_NAMESPACE
+
+struct QTcpKeepAliveConfiguration
+{
+ std::chrono::duration<int> idleTimeBeforeProbes;
+ std::chrono::duration<int> intervalBetweenProbes;
+ int probeCount;
+
+ bool isEqual(const QTcpKeepAliveConfiguration &other) const noexcept
+ {
+ return idleTimeBeforeProbes == other.idleTimeBeforeProbes
+ && intervalBetweenProbes == other.intervalBetweenProbes
+ && probeCount == other.probeCount;
+ }
+
+ friend bool operator==(const QTcpKeepAliveConfiguration &lhs, const QTcpKeepAliveConfiguration &rhs) noexcept
+ { return lhs.isEqual(rhs); }
+ friend bool operator!=(const QTcpKeepAliveConfiguration &lhs, const QTcpKeepAliveConfiguration &rhs) noexcept
+ { return !lhs.isEqual(rhs); }
+
+};
+
+Q_DECLARE_TYPEINFO(QTcpKeepAliveConfiguration, Q_PRIMITIVE_TYPE);
+
+QT_END_NAMESPACE
+
+#endif // QTCPKEEPALIVECONFIGURATION_P_H