Revision control
Copy as Markdown
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtGrpc/private/qgrpccommonoptions_p.h>
QT_BEGIN_NAMESPACE
#if QT_DEPRECATED_SINCE(6, 13)
QHash<QByteArray, QByteArray>
QtGrpcPrivate::toHash(const QMultiHash<QByteArray, QByteArray> &multiHash)
{
// Transform a QMultiHash into a QHash by keeping only the first value for each key.
// The first value will be the newest one when iterating the multi-hash.
QHash<QByteArray, QByteArray> out;
out.reserve(multiHash.size());
for (const auto &[k, v] : multiHash.asKeyValueRange())
out.try_emplace(k, v);
return out;
}
/*!
//! [metadata]
Returns the metadata. If this field is unset, returns empty
metadata.
\include qtgrpc-shared.qdocinc metadata-note
//! [metadata]
*/
const QHash<QByteArray, QByteArray> &QGrpcCommonOptions::metadata() const & noexcept
{
return m_deprecatedMetadata;
}
QHash<QByteArray, QByteArray> QGrpcCommonOptions::metadata() &&
{
return std::move(m_deprecatedMetadata);
}
/*!
\internal
\class QGrpcCommonOptions
\inmodule QtGrpc
\brief Shared implementation of QGrpcCallOptions and QGrpcChannelOptions
functionality.
*/
/*!
//! [set-metadata]
Sets the \a metadata and returns a reference to the updated object.
\include qtgrpc-shared.qdocinc metadata-note
//! [set-metadata]
*/
void QGrpcCommonOptions::setMetadata(const QHash<QByteArray, QByteArray> &md)
{
m_deprecatedMetadata = md;
m_metadata = QMultiHash<QByteArray, QByteArray>(md);
}
void QGrpcCommonOptions::setMetadata(QHash<QByteArray, QByteArray> &&md)
{
m_deprecatedMetadata = std::move(md);
m_metadata = QMultiHash<QByteArray, QByteArray>(m_deprecatedMetadata);
}
#endif // QT_DEPRECATED_SINCE(6, 13)
/*!
//! [deadline-timeout]
Returns the timeout duration that is used to calculate the deadline for RPCs.
If this field is unset, returns an empty \c {std::optional}.
//! [deadline-timeout]
*/
std::optional<std::chrono::milliseconds> QGrpcCommonOptions::deadlineTimeout() const noexcept
{
return m_timeout;
}
/*!
//! [set-deadline-timeout]
Sets the \a timeout and returns a reference to the updated object.
A deadline sets the limit for how long a client is willing to wait for a
response from a server. The actual deadline is computed by adding the \a
timeout to the start time of the RPC.
The deadline applies to the entire lifetime of an RPC, which includes
receiving the final QGrpcStatus for a previously started call and can thus
be unwanted for (long-lived) streams.
//! [set-deadline-timeout]
*/
void QGrpcCommonOptions::setDeadlineTimeout(std::chrono::milliseconds t)
{
m_timeout = t;
}
/*!
//! [metadata-multi]
\include qgrpccommonoptions.cpp metadata
Multiple values per key are supported.
\code
const auto &md = opts.metadata(QtGrpc::MultiValue);
\endcode
//! [metadata-multi]
*/
const QMultiHash<QByteArray, QByteArray> &
QGrpcCommonOptions::metadata(QtGrpc::MultiValue_t /*tag*/) const & noexcept
{
return m_metadata;
}
QMultiHash<QByteArray, QByteArray> QGrpcCommonOptions::metadata(QtGrpc::MultiValue_t /*tag*/) &&
{
return std::move(m_metadata);
}
/*!
//! [set-metadata-multi]
\include qgrpccommonoptions.cpp set-metadata
Multiple values per key are supported.
//! [set-metadata-multi]
*/
void QGrpcCommonOptions::setMetadata(const QMultiHash<QByteArray, QByteArray> &md)
{
m_metadata = md;
#if QT_DEPRECATED_SINCE(6, 13)
m_deprecatedMetadata = QtGrpcPrivate::toHash(m_metadata);
#endif
}
void QGrpcCommonOptions::setMetadata(QMultiHash<QByteArray, QByteArray> &&md)
{
m_metadata = std::move(md);
#if QT_DEPRECATED_SINCE(6, 13)
m_deprecatedMetadata = QtGrpcPrivate::toHash(m_metadata);
#endif
}
/*!
//! [add-metadata]
\since 6.10
Adds \a key and \a value to the \l metadata if the exact pair is not already contained.
The same key may appear multiple times with different values.
\include qtgrpc-shared.qdocinc metadata-note
\sa {metadata(QtGrpc::MultiValue_t)}{metadata()} {setMetadata(const
QMultiHash<QByteArray, QByteArray>&)}{setMetadata()}
//! [add-metadata]
*/
void QGrpcCommonOptions::addMetadata(QByteArray &&key, QByteArray &&value)
{
#if QT_DEPRECATED_SINCE(6, 13)
m_deprecatedMetadata.insertOrAssign(key, value);
#endif
m_metadata.emplace(std::move(key), std::move(value));
}
bool QGrpcCommonOptions::containsMetadata(QByteArrayView key, QByteArrayView value) const
{
const auto &md = metadata(QtGrpc::MultiValue);
auto [f, l] = md.equal_range(key);
return std::find(f, l, value) != l;
}
/*!
//! [filterServerMetadata]
\since 6.11
Returns \c true if protocol-related server metadata is excluded from the
result. Returns \c false to include all metadata received from the server.
If this field is unset, returns an empty \c {std::optional}.
\sa setFilterServerMetadata()
//! [filterServerMetadata]
*/
std::optional<bool> QGrpcCommonOptions::filterServerMetadata() const noexcept
{
return m_filterServerMetadata;
}
/*!
//! [setFilterServerMetadata]
\since 6.11
If \a value is \c true, protocol-related metadata defined by the gRPC
transport (such as reserved \c{grpc-} keys) will be excluded. If \a value
is \c false, all metadata received from the server will be included.
\sa filterServerMetadata()
//! [setFilterServerMetadata]
*/
void QGrpcCommonOptions::setFilterServerMetadata(bool value)
{
m_filterServerMetadata = value;
}
/*!
//! [maximumReceiveMessageSize]
\since 6.12
Returns the maximum allowed size in bytes of an incoming gRPC message. The
limit applies to the decoded gRPC frame payload, after transport-level
decryption and any per-message decompression.
If the value is not specified, returns an empty \c {std::optional}.
By default, the value is not specified.
\h2EnvFallback {QT_GRPC_MAXIMUM_RECEIVE_MESSAGE_SIZE} {4 MiB}
\sa setMaximumReceiveMessageSize()
//! [maximumReceiveMessageSize]
*/
std::optional<quint64> QGrpcCommonOptions::maximumReceiveMessageSize() const noexcept
{
return m_maximumReceiveMessageSize;
}
/*!
//! [setMaximumReceiveMessageSize]
\since 6.12
Sets the maximum incoming message \a size in bytes and returns a reference
to the updated object.
Messages exceeding this limit are rejected with
\l{QtGrpc::}{StatusCode::ResourceExhausted} before their payload is
buffered. The value is used verbatim, so a \a size of \c 0 accepts only
empty messages.
\note Concrete channel implementations may impose a hard upper bound on the
effective limit. The \l QGrpcHttp2Channel transport caps the value at the
maximum gRPC-over-HTTP/2 frame payload (\c{2^32 - 1}) bytes, or \c
qsizetype's maximum minus the 5-byte gRPC frame header on 32-bit platforms.
A larger configured value is clamped to that cap.
\sa maximumReceiveMessageSize()
//! [setMaximumReceiveMessageSize]
*/
void QGrpcCommonOptions::setMaximumReceiveMessageSize(quint64 size)
{
m_maximumReceiveMessageSize = size;
}
/*!
//! [requestCompression]
\since 6.12
Returns the compression algorithm used to compress outbound messages on
this channel or call.
If this field is unset, returns an empty \c {std::optional}.
\sa setRequestCompression()
//! [requestCompression]
*/
std::optional<QtGrpc::CompressionAlgorithm> QGrpcCommonOptions::requestCompression() const noexcept
{
return m_requestCompression;
}
/*!
//! [setRequestCompression]
\since 6.12
Sets the compression \a algorithm used to compress messages sent by the
client and returns a reference to the updated object.
When set, the algorithm is announced in the \c{grpc-encoding} request
header. Each message is compressed independently; if compression does not
reduce the payload size, the message is sent uncompressed with the
\c{Compressed-Flag} set to \c 0 regardless.
\note Compressing messages that contain both sensitive data and data that
could potentially be influenced by an attacker may expose the connection to
compression side-channel attacks such as CRIME or BREACH. If possible,
avoid compressing such messages, or separate sensitive and untrusted data
into different requests.
\sa requestCompression()
//! [setRequestCompression]
*/
void QGrpcCommonOptions::setRequestCompression(QtGrpc::CompressionAlgorithm algorithm)
{
m_requestCompression = algorithm;
}
QT_END_NAMESPACE