diff --git a/BUILD b/BUILD
index 5e192dadfdc..a1858322fed 100644
--- a/BUILD
+++ b/BUILD
@@ -2009,6 +2009,7 @@ grpc_cc_library(
"src/core/lib/transport/status_conversion.cc",
"src/core/lib/transport/timeout_encoding.cc",
"src/core/lib/transport/transport.cc",
+ "src/core/lib/transport/metadata_batch.cc",
"src/core/lib/transport/transport_op_string.cc",
] +
# TODO(hork): delete the iomgr glue code when EventEngine is fully
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cc0602abfb0..1d41f09ad01 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2227,6 +2227,7 @@ add_library(grpc
src/core/lib/transport/byte_stream.cc
src/core/lib/transport/connectivity_state.cc
src/core/lib/transport/error_utils.cc
+ src/core/lib/transport/metadata_batch.cc
src/core/lib/transport/parsed_metadata.cc
src/core/lib/transport/pid_controller.cc
src/core/lib/transport/status_conversion.cc
@@ -2793,6 +2794,7 @@ add_library(grpc_unsecure
src/core/lib/transport/byte_stream.cc
src/core/lib/transport/connectivity_state.cc
src/core/lib/transport/error_utils.cc
+ src/core/lib/transport/metadata_batch.cc
src/core/lib/transport/parsed_metadata.cc
src/core/lib/transport/pid_controller.cc
src/core/lib/transport/status_conversion.cc
diff --git a/Makefile b/Makefile
index bfcbe5237d1..bd668f54a87 100644
--- a/Makefile
+++ b/Makefile
@@ -1646,6 +1646,7 @@ LIBGRPC_SRC = \
src/core/lib/transport/byte_stream.cc \
src/core/lib/transport/connectivity_state.cc \
src/core/lib/transport/error_utils.cc \
+ src/core/lib/transport/metadata_batch.cc \
src/core/lib/transport/parsed_metadata.cc \
src/core/lib/transport/pid_controller.cc \
src/core/lib/transport/status_conversion.cc \
@@ -2057,6 +2058,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/transport/byte_stream.cc \
src/core/lib/transport/connectivity_state.cc \
src/core/lib/transport/error_utils.cc \
+ src/core/lib/transport/metadata_batch.cc \
src/core/lib/transport/parsed_metadata.cc \
src/core/lib/transport/pid_controller.cc \
src/core/lib/transport/status_conversion.cc \
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index 21d629b296e..4a97b1e6a8f 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -1602,6 +1602,7 @@ libs:
- src/core/lib/transport/byte_stream.cc
- src/core/lib/transport/connectivity_state.cc
- src/core/lib/transport/error_utils.cc
+ - src/core/lib/transport/metadata_batch.cc
- src/core/lib/transport/parsed_metadata.cc
- src/core/lib/transport/pid_controller.cc
- src/core/lib/transport/status_conversion.cc
@@ -2396,6 +2397,7 @@ libs:
- src/core/lib/transport/byte_stream.cc
- src/core/lib/transport/connectivity_state.cc
- src/core/lib/transport/error_utils.cc
+ - src/core/lib/transport/metadata_batch.cc
- src/core/lib/transport/parsed_metadata.cc
- src/core/lib/transport/pid_controller.cc
- src/core/lib/transport/status_conversion.cc
diff --git a/config.m4 b/config.m4
index 0ee63d41214..96c25b1b105 100644
--- a/config.m4
+++ b/config.m4
@@ -712,6 +712,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/transport/byte_stream.cc \
src/core/lib/transport/connectivity_state.cc \
src/core/lib/transport/error_utils.cc \
+ src/core/lib/transport/metadata_batch.cc \
src/core/lib/transport/parsed_metadata.cc \
src/core/lib/transport/pid_controller.cc \
src/core/lib/transport/status_conversion.cc \
diff --git a/config.w32 b/config.w32
index 179591cc80e..75f77d0368a 100644
--- a/config.w32
+++ b/config.w32
@@ -678,6 +678,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\transport\\byte_stream.cc " +
"src\\core\\lib\\transport\\connectivity_state.cc " +
"src\\core\\lib\\transport\\error_utils.cc " +
+ "src\\core\\lib\\transport\\metadata_batch.cc " +
"src\\core\\lib\\transport\\parsed_metadata.cc " +
"src\\core\\lib\\transport\\pid_controller.cc " +
"src\\core\\lib\\transport\\status_conversion.cc " +
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 4aaa922ad4e..ce1e4d8b06d 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -1514,6 +1514,7 @@ Pod::Spec.new do |s|
'src/core/lib/transport/error_utils.cc',
'src/core/lib/transport/error_utils.h',
'src/core/lib/transport/http2_errors.h',
+ 'src/core/lib/transport/metadata_batch.cc',
'src/core/lib/transport/metadata_batch.h',
'src/core/lib/transport/parsed_metadata.cc',
'src/core/lib/transport/parsed_metadata.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 379a2d2dea6..99a3fcd8c77 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -1433,6 +1433,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/transport/error_utils.cc )
s.files += %w( src/core/lib/transport/error_utils.h )
s.files += %w( src/core/lib/transport/http2_errors.h )
+ s.files += %w( src/core/lib/transport/metadata_batch.cc )
s.files += %w( src/core/lib/transport/metadata_batch.h )
s.files += %w( src/core/lib/transport/parsed_metadata.cc )
s.files += %w( src/core/lib/transport/parsed_metadata.h )
diff --git a/grpc.gyp b/grpc.gyp
index 212b16be65c..fc3dbb6a7b7 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -999,6 +999,7 @@
'src/core/lib/transport/byte_stream.cc',
'src/core/lib/transport/connectivity_state.cc',
'src/core/lib/transport/error_utils.cc',
+ 'src/core/lib/transport/metadata_batch.cc',
'src/core/lib/transport/parsed_metadata.cc',
'src/core/lib/transport/pid_controller.cc',
'src/core/lib/transport/status_conversion.cc',
@@ -1417,6 +1418,7 @@
'src/core/lib/transport/byte_stream.cc',
'src/core/lib/transport/connectivity_state.cc',
'src/core/lib/transport/error_utils.cc',
+ 'src/core/lib/transport/metadata_batch.cc',
'src/core/lib/transport/parsed_metadata.cc',
'src/core/lib/transport/pid_controller.cc',
'src/core/lib/transport/status_conversion.cc',
diff --git a/package.xml b/package.xml
index fffbf08917d..3cca426b544 100644
--- a/package.xml
+++ b/package.xml
@@ -1413,6 +1413,7 @@
+
diff --git a/src/core/lib/security/authorization/grpc_server_authz_filter.cc b/src/core/lib/security/authorization/grpc_server_authz_filter.cc
index 44823c5f5eb..5397d093f97 100644
--- a/src/core/lib/security/authorization/grpc_server_authz_filter.cc
+++ b/src/core/lib/security/authorization/grpc_server_authz_filter.cc
@@ -16,6 +16,8 @@
#include "src/core/lib/security/authorization/grpc_server_authz_filter.h"
+#include "absl/strings/str_join.h"
+
#include "src/core/lib/channel/promise_based_filter.h"
#include "src/core/lib/security/authorization/evaluate_args.h"
#include "src/core/lib/transport/transport.h"
diff --git a/src/core/lib/transport/metadata_batch.cc b/src/core/lib/transport/metadata_batch.cc
new file mode 100644
index 00000000000..ccd2b5671b4
--- /dev/null
+++ b/src/core/lib/transport/metadata_batch.cc
@@ -0,0 +1,29 @@
+// Copyright 2021 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include
+
+#include "src/core/lib/transport/metadata_batch.h"
+
+#include "absl/strings/escaping.h"
+#include "absl/strings/str_join.h"
+
+namespace grpc_core {
+namespace metadata_detail {
+void DebugStringBuilder::Add(absl::string_view key, absl::string_view value) {
+ if (!out_.empty()) out_.append(", ");
+ absl::StrAppend(&out_, absl::CEscape(key), ": ", absl::CEscape(value));
+}
+} // namespace metadata_detail
+} // namespace grpc_core
diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h
index ccd34bc8909..8a184a9f04f 100644
--- a/src/core/lib/transport/metadata_batch.h
+++ b/src/core/lib/transport/metadata_batch.h
@@ -26,11 +26,6 @@
#include
#include
-#include "absl/strings/escaping.h"
-#include "absl/strings/match.h"
-#include "absl/strings/str_join.h"
-#include "absl/types/optional.h"
-
#include
#include
#include
@@ -553,6 +548,22 @@ struct GrpcStatusContext {
namespace metadata_detail {
+// Build a key/value formatted debug string.
+// Output looks like 'key1: value1, key2: value2'
+// The string is expected to be readable, but not necessarily parsable.
+class DebugStringBuilder {
+ public:
+ // Add one key/value pair to the output.
+ void Add(absl::string_view key, absl::string_view value);
+
+ // Finalize the output and return the string.
+ // Subsequent Add calls are UB.
+ std::string TakeOutput() { return std::move(out_); }
+
+ private:
+ std::string out_;
+};
+
// IsEncodable: Given a trait, determine if that trait is encodable, or is just
// a value attached to a MetadataMap.
// We use the presence of the key() static method to determine if a trait is
@@ -1135,12 +1146,11 @@ class MetadataMap {
}
std::string DebugString() const {
- std::string out;
- Log([&out](absl::string_view key, absl::string_view value) {
- if (!out.empty()) out.append(", ");
- absl::StrAppend(&out, absl::CEscape(key), ": ", absl::CEscape(value));
+ metadata_detail::DebugStringBuilder builder;
+ Log([&builder](absl::string_view key, absl::string_view value) {
+ builder.Add(key, value);
});
- return out;
+ return builder.TakeOutput();
}
// Get the pointer to the value of some known metadata.
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index d0b204ee377..3d5f8ca1c23 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -687,6 +687,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/transport/byte_stream.cc',
'src/core/lib/transport/connectivity_state.cc',
'src/core/lib/transport/error_utils.cc',
+ 'src/core/lib/transport/metadata_batch.cc',
'src/core/lib/transport/parsed_metadata.cc',
'src/core/lib/transport/pid_controller.cc',
'src/core/lib/transport/status_conversion.cc',
diff --git a/test/core/transport/binder/binder_transport_test.cc b/test/core/transport/binder/binder_transport_test.cc
index 1380afb8e5b..b61f55c9d7c 100644
--- a/test/core/transport/binder/binder_transport_test.cc
+++ b/test/core/transport/binder/binder_transport_test.cc
@@ -26,6 +26,7 @@
#include "absl/memory/memory.h"
#include "absl/strings/match.h"
+#include "absl/strings/str_join.h"
#include "absl/synchronization/notification.h"
#include
diff --git a/test/core/transport/metadata_map_test.cc b/test/core/transport/metadata_map_test.cc
index 6cc098ac119..6abba661e3c 100644
--- a/test/core/transport/metadata_map_test.cc
+++ b/test/core/transport/metadata_map_test.cc
@@ -125,6 +125,19 @@ TEST(MetadataMapTest, NonEncodableTrait) {
EXPECT_EQ(map.DebugString(), "GrpcStreamNetworkState: not sent on wire");
}
+TEST(DebugStringBuilderTest, AddOne) {
+ metadata_detail::DebugStringBuilder b;
+ b.Add("a", "b");
+ EXPECT_EQ(b.TakeOutput(), "a: b");
+}
+
+TEST(DebugStringBuilderTest, AddTwo) {
+ metadata_detail::DebugStringBuilder b;
+ b.Add("a", "b");
+ b.Add("c", "d");
+ EXPECT_EQ(b.TakeOutput(), "a: b, c: d");
+}
+
} // namespace testing
} // namespace grpc_core
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 3e94546deb7..172f4c5d656 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -2413,6 +2413,7 @@ src/core/lib/transport/connectivity_state.h \
src/core/lib/transport/error_utils.cc \
src/core/lib/transport/error_utils.h \
src/core/lib/transport/http2_errors.h \
+src/core/lib/transport/metadata_batch.cc \
src/core/lib/transport/metadata_batch.h \
src/core/lib/transport/parsed_metadata.cc \
src/core/lib/transport/parsed_metadata.h \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 2c20ed82703..e88580d864a 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -2210,6 +2210,7 @@ src/core/lib/transport/connectivity_state.h \
src/core/lib/transport/error_utils.cc \
src/core/lib/transport/error_utils.h \
src/core/lib/transport/http2_errors.h \
+src/core/lib/transport/metadata_batch.cc \
src/core/lib/transport/metadata_batch.h \
src/core/lib/transport/parsed_metadata.cc \
src/core/lib/transport/parsed_metadata.h \