summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmake/QtInternalTargets.cmake5
-rw-r--r--coin/instructions/coin_module_axivion_template_v2.yaml7
-rw-r--r--src/corelib/animation/qabstractanimation.cpp1
-rw-r--r--src/corelib/io/qfsfileengine.cpp6
-rw-r--r--src/corelib/io/qwindowspipereader.cpp5
-rw-r--r--src/corelib/kernel/qeventdispatcher_cf.mm1
-rw-r--r--src/corelib/kernel/qproperty.cpp20
-rw-r--r--src/corelib/serialization/qcborvalue.cpp1
-rw-r--r--src/corelib/text/qlocale.cpp1
-rw-r--r--src/corelib/time/qdatetimeparser.cpp1
-rw-r--r--src/network/access/qbytedatabuffer_p.h2
-rw-r--r--src/network/access/qhttp2connection.cpp77
-rw-r--r--src/network/access/qhttp2connection_p.h24
-rw-r--r--tests/auto/network/access/qhttp2connection/tst_qhttp2connection.cpp55
14 files changed, 184 insertions, 22 deletions
diff --git a/cmake/QtInternalTargets.cmake b/cmake/QtInternalTargets.cmake
index 45e75d4836f..f0d7d06fb84 100644
--- a/cmake/QtInternalTargets.cmake
+++ b/cmake/QtInternalTargets.cmake
@@ -385,7 +385,10 @@ if(QT_FEATURE_stdlib_libcpp)
target_compile_definitions(PlatformCommonInternal INTERFACE _LIBCPP_REMOVE_TRANSITIVE_INCLUDES)
endif()
-if(QT_USE_CCACHE AND CLANG AND BUILD_WITH_PCH)
+if((QT_USE_CCACHE
+ OR (CMAKE_CXX_COMPILER_LAUNCHER MATCHES "^(.*[/\\])?sccache$"))
+ AND CLANG
+ AND BUILD_WITH_PCH)
# The ccache man page says we must compile with -fno-pch-timestamp when using clang and pch.
foreach(language IN ITEMS C CXX OBJC OBJCXX)
target_compile_options(PlatformCommonInternal INTERFACE
diff --git a/coin/instructions/coin_module_axivion_template_v2.yaml b/coin/instructions/coin_module_axivion_template_v2.yaml
index 90d57de281c..9840d1138b6 100644
--- a/coin/instructions/coin_module_axivion_template_v2.yaml
+++ b/coin/instructions/coin_module_axivion_template_v2.yaml
@@ -16,6 +16,13 @@ analysis_instructions_axivion: &analysis_instructions_axivion
condition: runtime
env_var: TESTED_MODULE_COIN
not_equals_value: "qtbase"
+ - type: EnvironmentVariable
+ variableName: TESTED_MODULE_BRANCH_COIN
+ variableValue: "unknown"
+ enable_if:
+ condition: runtime
+ env_var: TESTED_MODULE_BRANCH_COIN
+ equals_value: null
- type: Group
instructions:
- type: Rename
diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp
index c3e1ba4010f..8a343b15eeb 100644
--- a/src/corelib/animation/qabstractanimation.cpp
+++ b/src/corelib/animation/qabstractanimation.cpp
@@ -858,6 +858,7 @@ qint64 QAnimationDriver::elapsed() const
*/
/*!
+ \internal
The default animation driver just spins the timer...
*/
QDefaultAnimationDriver::QDefaultAnimationDriver(QUnifiedTimer *timer)
diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp
index 0771c15584b..d3c398f0860 100644
--- a/src/corelib/io/qfsfileengine.cpp
+++ b/src/corelib/io/qfsfileengine.cpp
@@ -249,6 +249,12 @@ bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh, QFile::FileHand
}
/*!
+ \class QFSFileEnginePrivate
+ \inmodule QtCore
+ \internal
+*/
+
+/*!
Opens the file handle \a fh using the open mode \a flags.
*/
bool QFSFileEnginePrivate::openFh(QIODevice::OpenMode openMode, FILE *fh)
diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp
index 456a209af37..6edf4395887 100644
--- a/src/corelib/io/qwindowspipereader.cpp
+++ b/src/corelib/io/qwindowspipereader.cpp
@@ -14,6 +14,11 @@ using namespace Qt::StringLiterals;
static const DWORD minReadBufferSize = 4096;
+/*!
+ \class QWindowsPipeReader
+ \inmodule QtCore
+ \internal
+*/
QWindowsPipeReader::QWindowsPipeReader(QObject *parent)
: QObject(parent),
handle(INVALID_HANDLE_VALUE),
diff --git a/src/corelib/kernel/qeventdispatcher_cf.mm b/src/corelib/kernel/qeventdispatcher_cf.mm
index 2dddf147f85..d57c057a21a 100644
--- a/src/corelib/kernel/qeventdispatcher_cf.mm
+++ b/src/corelib/kernel/qeventdispatcher_cf.mm
@@ -207,6 +207,7 @@ QEventLoop *QEventDispatcherCoreFoundation::currentEventLoop() const
}
/*!
+ \internal
Processes all pending events that match \a flags until there are no
more events to process. Returns \c true if pending events were handled;
otherwise returns \c false.
diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp
index d538ed7b4e9..9141a8f8bad 100644
--- a/src/corelib/kernel/qproperty.cpp
+++ b/src/corelib/kernel/qproperty.cpp
@@ -402,6 +402,16 @@ QPropertyBindingPrivate::NotificationState QPropertyBindingPrivate::notifyNonRec
}
/*!
+ \class QUntypedPropertyBinding
+ \inmodule QtCore
+ \since 6.0
+ \ingroup tools
+ \brief Represents a type-erased property binding.
+
+ \sa QUntypedBindable
+*/
+
+/*!
Constructs a null QUntypedPropertyBinding.
\sa isNull()
@@ -409,8 +419,8 @@ QPropertyBindingPrivate::NotificationState QPropertyBindingPrivate::notifyNonRec
QUntypedPropertyBinding::QUntypedPropertyBinding() = default;
/*!
- \fn template<typename Functor>
- QUntypedPropertyBinding(QMetaType metaType, Functor &&f, const QPropertyBindingSourceLocation &location)
+ \fn template<typename Functor> QUntypedPropertyBinding(
+ QMetaType metaType, Functor &&f, const QPropertyBindingSourceLocation &location)
\internal
*/
@@ -448,7 +458,6 @@ QUntypedPropertyBinding::QUntypedPropertyBinding(const QUntypedPropertyBinding &
: d(other.d)
{
}
-
/*!
Copy-assigns \a other to this QUntypedPropertyBinding.
*/
@@ -1183,7 +1192,7 @@ QString QPropertyBindingError::description() const
\return \c true when the binding was successfully set.
- //! \sa QUntypedPropertyBinding::valueMetaType()
+ \sa QUntypedPropertyBinding::valueMetaType()
*/
/*!
@@ -1199,8 +1208,7 @@ QString QPropertyBindingError::description() const
Returns the metatype of the property from which the QUntypedBindable was created.
If the bindable is invalid, an invalid metatype will be returned.
- \sa isValid()
- //! \sa QUntypedPropertyBinding::valueMetaType()
+ \sa isValid(), QUntypedPropertyBinding::valueMetaType()
*/
/*!
diff --git a/src/corelib/serialization/qcborvalue.cpp b/src/corelib/serialization/qcborvalue.cpp
index 13d74e591d5..0aeb2b07f47 100644
--- a/src/corelib/serialization/qcborvalue.cpp
+++ b/src/corelib/serialization/qcborvalue.cpp
@@ -975,6 +975,7 @@ QCborContainerPrivate *QCborContainerPrivate::detach(QCborContainerPrivate *d, q
}
/*!
+ \internal
Prepare for an insertion at position \a index
Detaches and ensures there are at least index entries in the array, padding
diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp
index fed09aee45e..18007cacae6 100644
--- a/src/corelib/text/qlocale.cpp
+++ b/src/corelib/text/qlocale.cpp
@@ -301,6 +301,7 @@ bool operator<(LikelyPair lhs, LikelyPair rhs)
} // anonymous namespace
/*!
+ \internal
Fill in blank fields of a locale ID.
An ID in which some fields are zero stands for any locale that agrees with
diff --git a/src/corelib/time/qdatetimeparser.cpp b/src/corelib/time/qdatetimeparser.cpp
index 10882738a39..05ba3d2beae 100644
--- a/src/corelib/time/qdatetimeparser.cpp
+++ b/src/corelib/time/qdatetimeparser.cpp
@@ -2389,6 +2389,7 @@ bool operator==(QDateTimeParser::SectionNode s1, QDateTimeParser::SectionNode s2
}
/*!
+ \internal
Sets \a cal as the calendar to use. The default is Gregorian.
*/
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/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/tests/auto/network/access/qhttp2connection/tst_qhttp2connection.cpp b/tests/auto/network/access/qhttp2connection/tst_qhttp2connection.cpp
index 417655c31d9..22aa9d44262 100644
--- a/tests/auto/network/access/qhttp2connection/tst_qhttp2connection.cpp
+++ b/tests/auto/network/access/qhttp2connection/tst_qhttp2connection.cpp
@@ -21,6 +21,8 @@ class tst_QHttp2Connection : public QObject
private slots:
void construct();
void constructStream();
+ void streamConfiguration_data();
+ void streamConfiguration();
void testSETTINGSFrame();
void maxHeaderTableSize();
void testPING();
@@ -204,6 +206,59 @@ void tst_QHttp2Connection::constructStream()
QCOMPARE(stream->isUploadingDATA(), false);
}
+void tst_QHttp2Connection::streamConfiguration_data()
+{
+ QTest::addColumn<bool>("useDownloadBuffer");
+
+ QTest::addRow("useDownloadBuffer=true") << true;
+ QTest::addRow("useDownloadBuffer=false") << false;
+}
+
+void tst_QHttp2Connection::streamConfiguration()
+{
+ QFETCH(const bool, useDownloadBuffer);
+
+ auto [client, server] = makeFakeConnectedSockets();
+ auto *clientConnection = makeHttp2Connection(client.get(), {}, Client);
+ auto *serverConnection = makeHttp2Connection(server.get(), {}, Server);
+
+ QHttp2Stream::Configuration config;
+ config.useDownloadBuffer = useDownloadBuffer;
+
+ QHttp2Stream *clientStream = clientConnection->createStream(config).unwrap();
+ QVERIFY(clientStream);
+ QCOMPARE(clientStream->configuration().useDownloadBuffer, useDownloadBuffer);
+ QVERIFY(waitForSettingsExchange(clientConnection, serverConnection));
+
+ QSignalSpy newIncomingStreamSpy{ serverConnection, &QHttp2Connection::newIncomingStream };
+ QSignalSpy clientDataReceivedSpy{ clientStream, &QHttp2Stream::dataReceived };
+
+ HPack::HttpHeader headers = getRequiredHeaders();
+ clientStream->sendHEADERS(headers, false);
+
+ QVERIFY(newIncomingStreamSpy.wait());
+ auto *serverStream = newIncomingStreamSpy.front().front().value<QHttp2Stream *>();
+ QVERIFY(serverStream);
+
+ const HPack::HttpHeader responseHeaders{ { ":status", "200" } };
+ serverStream->sendHEADERS(responseHeaders, false);
+
+ const QByteArray testData = "Hello World"_ba.repeated(100);
+ serverStream->sendDATA(testData, true);
+
+ QVERIFY(clientDataReceivedSpy.wait());
+ QCOMPARE(clientDataReceivedSpy.count(), 1);
+
+ const QByteArray receivedData = clientDataReceivedSpy.front().front().value<QByteArray>();
+ QCOMPARE(receivedData, testData);
+
+ if (useDownloadBuffer) {
+ QCOMPARE(clientStream->downloadBuffer().byteAmount(), testData.size());
+ } else {
+ QVERIFY(clientStream->downloadBuffer().isEmpty());
+ }
+}
+
void tst_QHttp2Connection::testSETTINGSFrame()
{
constexpr qint32 PrefaceLength = 24;