diff --git a/examples/grpc/chat/client/simplechatengine.cpp b/examples/grpc/chat/client/simplechatengine.cpp index 0e602cbf..abc20d84 100644 --- a/examples/grpc/chat/client/simplechatengine.cpp +++ b/examples/grpc/chat/client/simplechatengine.cpp @@ -5,7 +5,6 @@ #include "simplechatengine.h" #include -#include #include #include diff --git a/src/grpc/CMakeLists.txt b/src/grpc/CMakeLists.txt index 0b7fd3e1..99481513 100644 --- a/src/grpc/CMakeLists.txt +++ b/src/grpc/CMakeLists.txt @@ -14,6 +14,7 @@ qt_internal_add_module(Grpc qgrpcuserpasswordcredentials.h qgrpcuserpasswordcredentials.cpp qgrpccalloptions.h qgrpccalloptions.cpp qgrpcchanneloptions.h qgrpcchanneloptions.cpp + qgrpcmetadata.h qtgrpcglobal.h qtgrpcglobal_p.h qtgrpcglobal.cpp GENERATE_CPP_EXPORTS LIBRARIES diff --git a/src/grpc/qgrpccalloptions.cpp b/src/grpc/qgrpccalloptions.cpp index d55f3e2d..5eae93fc 100644 --- a/src/grpc/qgrpccalloptions.cpp +++ b/src/grpc/qgrpccalloptions.cpp @@ -27,6 +27,7 @@ public: std::optional deadline; std::shared_ptr credentials; std::optional maxRetryAttempts; + QGrpcMetadata metadata; }; /*! @@ -87,6 +88,15 @@ QGrpcCallOptions &QGrpcCallOptions::withMaxRetryAttempts(qint64 maxRetryAttempts return *this; } +/*! + Sets \a metadata for a call and returns updated QGrpcCallOptions object. +*/ +QGrpcCallOptions &QGrpcCallOptions::withMetadata(const QGrpcMetadata &metadata) +{ + dPtr->metadata = metadata; + return *this; +} + /*! Returns deadline value for a call. @@ -117,4 +127,14 @@ std::optional QGrpcCallOptions::maxRetryAttempts() const return dPtr->maxRetryAttempts; } +/*! + Returns metadata used for a call. + + If value was not set returns empty QGrpcMetadata. +*/ +QGrpcMetadata QGrpcCallOptions::metadata() const +{ + return dPtr->metadata; +} + QT_END_NAMESPACE diff --git a/src/grpc/qgrpccalloptions.h b/src/grpc/qgrpccalloptions.h index a6488526..21552303 100644 --- a/src/grpc/qgrpccalloptions.h +++ b/src/grpc/qgrpccalloptions.h @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -28,10 +29,12 @@ public: QGrpcCallOptions &withDeadline(std::chrono::milliseconds deadline); QGrpcCallOptions &withCredentials(std::shared_ptr credentials); QGrpcCallOptions &withMaxRetryAttempts(qint64 maxRetryAttempts); + QGrpcCallOptions &withMetadata(const QGrpcMetadata &metadata); std::optional deadline() const; std::optional credentials() const; std::optional maxRetryAttempts() const; + QGrpcMetadata metadata() const; private: std::unique_ptr dPtr; diff --git a/src/grpc/qgrpcchanneloptions.cpp b/src/grpc/qgrpcchanneloptions.cpp index 55bf35c2..abcf7bdd 100644 --- a/src/grpc/qgrpcchanneloptions.cpp +++ b/src/grpc/qgrpcchanneloptions.cpp @@ -27,6 +27,7 @@ public: std::optional deadline; std::shared_ptr credentials; std::optional credentialList; + QGrpcMetadata metadata; #if QT_CONFIG(ssl) std::optional sslConfiguration; #endif @@ -100,6 +101,15 @@ QGrpcChannelOptions &QGrpcChannelOptions::withCredentialList(const QStringList & return *this; } +/*! + Sets \a metadata for a call and returns updated QGrpcCallOptions object. +*/ +QGrpcChannelOptions &QGrpcChannelOptions::withMetadata(const QGrpcMetadata &metadata) +{ + dPtr->metadata = metadata; + return *this; +} + /*! Returns deadline value for every call on the channel. @@ -140,6 +150,16 @@ std::optional QGrpcChannelOptions::credentialList() const } #if QT_CONFIG(ssl) +/*! + Returns metadata used for a call. + + If value was not set returns empty QGrpcMetadata. +*/ +QGrpcMetadata QGrpcChannelOptions::metadata() const +{ + return dPtr->metadata; +} + /*! Sets SSL configuration with \a sslConfiguration and returns updated QGrpcChannelOptions object. */ diff --git a/src/grpc/qgrpcchanneloptions.h b/src/grpc/qgrpcchanneloptions.h index 472eefde..341357c5 100644 --- a/src/grpc/qgrpcchanneloptions.h +++ b/src/grpc/qgrpcchanneloptions.h @@ -6,6 +6,7 @@ #include #include +#include #include #if QT_CONFIG(ssl) @@ -34,11 +35,13 @@ public: QGrpcChannelOptions &withDeadline(std::chrono::milliseconds deadline); QGrpcChannelOptions &withCredentials(std::shared_ptr credentials); QGrpcChannelOptions &withCredentialList(const QStringList &credentialList); + QGrpcChannelOptions &withMetadata(const QGrpcMetadata &metadata); QUrl host() const; std::optional deadline() const; std::optional credentials() const; std::optional credentialList() const; + QGrpcMetadata metadata() const; #if QT_CONFIG(ssl) QGrpcChannelOptions &withSslConfiguration(const QSslConfiguration &sslConfiguration); diff --git a/src/grpc/qgrpchttp2channel.cpp b/src/grpc/qgrpchttp2channel.cpp index 83f4b9f8..6b5b771d 100644 --- a/src/grpc/qgrpchttp2channel.cpp +++ b/src/grpc/qgrpchttp2channel.cpp @@ -86,6 +86,19 @@ constexpr char GrpcStatusHeader[] = "grpc-status"; constexpr char GrpcStatusMessageHeader[] = "grpc-message"; constexpr qsizetype GrpcMessageSizeHeaderSize = 5; +static void addMetadataToRequest(QNetworkRequest *request, const QGrpcMetadata &channelMetadata, + const QGrpcMetadata &callMetadata) +{ + auto iterateMetadata = [&request](const auto &metadata) { + for (const auto &[key, value] : std::as_const(metadata)) { + request->setRawHeader(key, value); + } + }; + + iterateMetadata(channelMetadata); + iterateMetadata(callMetadata); +} + struct QGrpcHttp2ChannelPrivate { struct ExpectedData @@ -121,6 +134,8 @@ struct QGrpcHttp2ChannelPrivate for (const auto &[key, value] : credentials->toStdMap()) request.setRawHeader(key, value.toString().toUtf8()); } + addMetadataToRequest(&request, channelOptions.metadata(), callOptions.metadata()); + request.setAttribute(QNetworkRequest::Http2DirectAttribute, true); QByteArray msg(GrpcMessageSizeHeaderSize, '\0'); diff --git a/src/grpc/qgrpcmetadata.h b/src/grpc/qgrpcmetadata.h new file mode 100644 index 00000000..b1a99efe --- /dev/null +++ b/src/grpc/qgrpcmetadata.h @@ -0,0 +1,17 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef QGRPCMETADATA_H +#define QGRPCMETADATA_H + +#include + +#include + +QT_BEGIN_NAMESPACE + +using QGrpcMetadata = std::unordered_multimap; + +QT_END_NAMESPACE + +#endif // QGRPCMETADATA_H