diff --git a/BUILD b/BUILD
index f611c439ebc..1acba387931 100644
--- a/BUILD
+++ b/BUILD
@@ -1165,6 +1165,20 @@ grpc_cc_library(
],
)
+grpc_cc_library(
+ name = "grpc_http_util",
+ srcs = [
+ "src/core/ext/filters/http/client/util.cc",
+ ],
+ hdrs = [
+ "src/core/ext/filters/http/client/util.h",
+ ],
+ language = "c++",
+ deps = [
+ "grpc_base",
+ ],
+)
+
grpc_cc_library(
name = "grpc_http_filters",
srcs = [
@@ -1183,6 +1197,7 @@ grpc_cc_library(
language = "c++",
deps = [
"grpc_base",
+ "grpc_http_util",
"grpc_message_size_filter",
],
)
@@ -1462,6 +1477,7 @@ grpc_cc_library(
deps = [
"grpc_base",
"grpc_client_channel",
+ "grpc_http_util",
"grpc_resolver_xds_header",
"grpc_xds_api_header",
],
diff --git a/BUILD.gn b/BUILD.gn
index 50243a37885..48571619041 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -320,6 +320,8 @@ config("grpc_config") {
"src/core/ext/filters/deadline/deadline_filter.h",
"src/core/ext/filters/http/client/http_client_filter.cc",
"src/core/ext/filters/http/client/http_client_filter.h",
+ "src/core/ext/filters/http/client/util.cc",
+ "src/core/ext/filters/http/client/util.h",
"src/core/ext/filters/http/client_authority_filter.cc",
"src/core/ext/filters/http/client_authority_filter.h",
"src/core/ext/filters/http/http_filters_plugin.cc",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 61842a31b40..4604bfdb19f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1396,6 +1396,7 @@ add_library(grpc
src/core/ext/filters/client_idle/client_idle_filter.cc
src/core/ext/filters/deadline/deadline_filter.cc
src/core/ext/filters/http/client/http_client_filter.cc
+ src/core/ext/filters/http/client/util.cc
src/core/ext/filters/http/client_authority_filter.cc
src/core/ext/filters/http/http_filters_plugin.cc
src/core/ext/filters/http/message_compress/message_compress_filter.cc
@@ -2140,6 +2141,7 @@ add_library(grpc_unsecure
src/core/ext/filters/client_idle/client_idle_filter.cc
src/core/ext/filters/deadline/deadline_filter.cc
src/core/ext/filters/http/client/http_client_filter.cc
+ src/core/ext/filters/http/client/util.cc
src/core/ext/filters/http/client_authority_filter.cc
src/core/ext/filters/http/http_filters_plugin.cc
src/core/ext/filters/http/message_compress/message_compress_filter.cc
diff --git a/Makefile b/Makefile
index 8e3afd0bdf8..881c0d74997 100644
--- a/Makefile
+++ b/Makefile
@@ -3462,6 +3462,7 @@ LIBGRPC_SRC = \
src/core/ext/filters/client_idle/client_idle_filter.cc \
src/core/ext/filters/deadline/deadline_filter.cc \
src/core/ext/filters/http/client/http_client_filter.cc \
+ src/core/ext/filters/http/client/util.cc \
src/core/ext/filters/http/client_authority_filter.cc \
src/core/ext/filters/http/http_filters_plugin.cc \
src/core/ext/filters/http/message_compress/message_compress_filter.cc \
@@ -4175,6 +4176,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/filters/client_idle/client_idle_filter.cc \
src/core/ext/filters/deadline/deadline_filter.cc \
src/core/ext/filters/http/client/http_client_filter.cc \
+ src/core/ext/filters/http/client/util.cc \
src/core/ext/filters/http/client_authority_filter.cc \
src/core/ext/filters/http/http_filters_plugin.cc \
src/core/ext/filters/http/message_compress/message_compress_filter.cc \
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index 6af4abe17f3..3022305de8c 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -426,6 +426,7 @@ libs:
- src/core/ext/filters/client_channel/xds/xds_client_stats.h
- src/core/ext/filters/deadline/deadline_filter.h
- src/core/ext/filters/http/client/http_client_filter.h
+ - src/core/ext/filters/http/client/util.h
- src/core/ext/filters/http/client_authority_filter.h
- src/core/ext/filters/http/message_compress/message_compress_filter.h
- src/core/ext/filters/http/message_compress/message_decompress_filter.h
@@ -874,6 +875,7 @@ libs:
- src/core/ext/filters/client_idle/client_idle_filter.cc
- src/core/ext/filters/deadline/deadline_filter.cc
- src/core/ext/filters/http/client/http_client_filter.cc
+ - src/core/ext/filters/http/client/util.cc
- src/core/ext/filters/http/client_authority_filter.cc
- src/core/ext/filters/http/http_filters_plugin.cc
- src/core/ext/filters/http/message_compress/message_compress_filter.cc
@@ -1487,6 +1489,7 @@ libs:
- src/core/ext/filters/client_channel/xds/xds_client_stats.h
- src/core/ext/filters/deadline/deadline_filter.h
- src/core/ext/filters/http/client/http_client_filter.h
+ - src/core/ext/filters/http/client/util.h
- src/core/ext/filters/http/client_authority_filter.h
- src/core/ext/filters/http/message_compress/message_compress_filter.h
- src/core/ext/filters/http/message_compress/message_decompress_filter.h
@@ -1871,6 +1874,7 @@ libs:
- src/core/ext/filters/client_idle/client_idle_filter.cc
- src/core/ext/filters/deadline/deadline_filter.cc
- src/core/ext/filters/http/client/http_client_filter.cc
+ - src/core/ext/filters/http/client/util.cc
- src/core/ext/filters/http/client_authority_filter.cc
- src/core/ext/filters/http/http_filters_plugin.cc
- src/core/ext/filters/http/message_compress/message_compress_filter.cc
diff --git a/config.m4 b/config.m4
index 8fa0096a584..442df6ccbcb 100644
--- a/config.m4
+++ b/config.m4
@@ -106,6 +106,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/client_idle/client_idle_filter.cc \
src/core/ext/filters/deadline/deadline_filter.cc \
src/core/ext/filters/http/client/http_client_filter.cc \
+ src/core/ext/filters/http/client/util.cc \
src/core/ext/filters/http/client_authority_filter.cc \
src/core/ext/filters/http/http_filters_plugin.cc \
src/core/ext/filters/http/message_compress/message_compress_filter.cc \
diff --git a/config.w32 b/config.w32
index 05114b382f3..d8365fc9782 100644
--- a/config.w32
+++ b/config.w32
@@ -74,6 +74,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\client_idle\\client_idle_filter.cc " +
"src\\core\\ext\\filters\\deadline\\deadline_filter.cc " +
"src\\core\\ext\\filters\\http\\client\\http_client_filter.cc " +
+ "src\\core\\ext\\filters\\http\\client\\util.cc " +
"src\\core\\ext\\filters\\http\\client_authority_filter.cc " +
"src\\core\\ext\\filters\\http\\http_filters_plugin.cc " +
"src\\core\\ext\\filters\\http\\message_compress\\message_compress_filter.cc " +
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index 855a849d54f..8deac9095d8 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -271,6 +271,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/xds/xds_client_stats.h',
'src/core/ext/filters/deadline/deadline_filter.h',
'src/core/ext/filters/http/client/http_client_filter.h',
+ 'src/core/ext/filters/http/client/util.h',
'src/core/ext/filters/http/client_authority_filter.h',
'src/core/ext/filters/http/message_compress/message_compress_filter.h',
'src/core/ext/filters/http/message_compress/message_decompress_filter.h',
@@ -829,6 +830,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/xds/xds_client_stats.h',
'src/core/ext/filters/deadline/deadline_filter.h',
'src/core/ext/filters/http/client/http_client_filter.h',
+ 'src/core/ext/filters/http/client/util.h',
'src/core/ext/filters/http/client_authority_filter.h',
'src/core/ext/filters/http/message_compress/message_compress_filter.h',
'src/core/ext/filters/http/message_compress/message_decompress_filter.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index e1225d7ef58..65b7b14670c 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -304,6 +304,8 @@ Pod::Spec.new do |s|
'src/core/ext/filters/deadline/deadline_filter.h',
'src/core/ext/filters/http/client/http_client_filter.cc',
'src/core/ext/filters/http/client/http_client_filter.h',
+ 'src/core/ext/filters/http/client/util.cc',
+ 'src/core/ext/filters/http/client/util.h',
'src/core/ext/filters/http/client_authority_filter.cc',
'src/core/ext/filters/http/client_authority_filter.h',
'src/core/ext/filters/http/http_filters_plugin.cc',
@@ -1293,6 +1295,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/xds/xds_client_stats.h',
'src/core/ext/filters/deadline/deadline_filter.h',
'src/core/ext/filters/http/client/http_client_filter.h',
+ 'src/core/ext/filters/http/client/util.h',
'src/core/ext/filters/http/client_authority_filter.h',
'src/core/ext/filters/http/message_compress/message_compress_filter.h',
'src/core/ext/filters/http/message_compress/message_decompress_filter.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 61915d8be94..d543deaf6ca 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -226,6 +226,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/deadline/deadline_filter.h )
s.files += %w( src/core/ext/filters/http/client/http_client_filter.cc )
s.files += %w( src/core/ext/filters/http/client/http_client_filter.h )
+ s.files += %w( src/core/ext/filters/http/client/util.cc )
+ s.files += %w( src/core/ext/filters/http/client/util.h )
s.files += %w( src/core/ext/filters/http/client_authority_filter.cc )
s.files += %w( src/core/ext/filters/http/client_authority_filter.h )
s.files += %w( src/core/ext/filters/http/http_filters_plugin.cc )
diff --git a/grpc.gyp b/grpc.gyp
index cd20a0470f1..b533c33a2c3 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -503,6 +503,7 @@
'src/core/ext/filters/client_idle/client_idle_filter.cc',
'src/core/ext/filters/deadline/deadline_filter.cc',
'src/core/ext/filters/http/client/http_client_filter.cc',
+ 'src/core/ext/filters/http/client/util.cc',
'src/core/ext/filters/http/client_authority_filter.cc',
'src/core/ext/filters/http/http_filters_plugin.cc',
'src/core/ext/filters/http/message_compress/message_compress_filter.cc',
@@ -1078,6 +1079,7 @@
'src/core/ext/filters/client_idle/client_idle_filter.cc',
'src/core/ext/filters/deadline/deadline_filter.cc',
'src/core/ext/filters/http/client/http_client_filter.cc',
+ 'src/core/ext/filters/http/client/util.cc',
'src/core/ext/filters/http/client_authority_filter.cc',
'src/core/ext/filters/http/http_filters_plugin.cc',
'src/core/ext/filters/http/message_compress/message_compress_filter.cc',
diff --git a/package.xml b/package.xml
index 6b68301f6f5..f9a00ed29e3 100644
--- a/package.xml
+++ b/package.xml
@@ -206,6 +206,8 @@
+
+
diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_routing.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_routing.cc
index ebb870702f9..7e0d8d9a472 100644
--- a/src/core/ext/filters/client_channel/lb_policy/xds/xds_routing.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_routing.cc
@@ -35,6 +35,7 @@
#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
#include "src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h"
#include "src/core/ext/filters/client_channel/xds/xds_api.h"
+#include "src/core/ext/filters/http/client/util.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/orphanable.h"
@@ -117,14 +118,18 @@ class XdsRoutingLb : public LoadBalancingPolicy {
// Maintains an ordered xds route table as provided by RDS response.
using RouteTable = std::vector;
- explicit RoutePicker(RouteTable route_table,
- RefCountedPtr config)
- : route_table_(std::move(route_table)), config_(std::move(config)) {}
+ RoutePicker(RouteTable route_table, std::string user_agent,
+ RefCountedPtr config)
+ : route_table_(std::move(route_table)),
+ user_agent_(std::move(user_agent)),
+ config_(std::move(config)) {}
PickResult Pick(PickArgs args) override;
private:
RouteTable route_table_;
+ // Storing user_agent generated from args from http layer.
+ std::string user_agent_;
// Take a reference to config so that we can use
// XdsApi::RdsUpdate::RdsRoute::Matchers from it.
RefCountedPtr config_;
@@ -213,6 +218,9 @@ class XdsRoutingLb : public LoadBalancingPolicy {
// Children.
std::map> actions_;
+
+ // Storing user_agent generated from args from http layer.
+ std::string user_agent_;
};
//
@@ -254,8 +262,22 @@ bool PathMatch(
bool HeaderMatchHelper(
const XdsApi::RdsUpdate::RdsRoute::Matchers::HeaderMatcher& header_matcher,
- LoadBalancingPolicy::MetadataInterface* initial_metadata) {
- auto value = GetMetadataValue(header_matcher.name, initial_metadata);
+ LoadBalancingPolicy::MetadataInterface* initial_metadata,
+ const std::string& user_agent, absl::string_view deadline) {
+ absl::optional value;
+ if (header_matcher.name == "grpc-tags-bin" ||
+ header_matcher.name == "grpc-trace-bin" ||
+ header_matcher.name == "grpc-previous-rpc-attempts") {
+ value = absl::nullopt;
+ } else if (header_matcher.name == "content-type") {
+ value = "application/grpc";
+ } else if (header_matcher.name == "user-agent") {
+ value = user_agent;
+ } else if (header_matcher.name == "grpc-timeout") {
+ value = deadline;
+ } else {
+ value = GetMetadataValue(header_matcher.name, initial_metadata);
+ }
if (!value.has_value()) {
if (header_matcher.type == XdsApi::RdsUpdate::RdsRoute::Matchers::
HeaderMatcher::HeaderMatcherType::PRESENT) {
@@ -293,11 +315,13 @@ bool HeaderMatchHelper(
}
bool HeadersMatch(
- LoadBalancingPolicy::PickArgs args,
const std::vector&
- header_matchers) {
+ header_matchers,
+ LoadBalancingPolicy::MetadataInterface* initial_metadata,
+ const std::string& user_agent, absl::string_view deadline) {
for (const auto& header_matcher : header_matchers) {
- bool match = HeaderMatchHelper(header_matcher, args.initial_metadata);
+ bool match = HeaderMatchHelper(header_matcher, initial_metadata, user_agent,
+ deadline);
if (header_matcher.invert_match) match = !match;
if (!match) return false;
}
@@ -315,11 +339,16 @@ XdsRoutingLb::PickResult XdsRoutingLb::RoutePicker::Pick(PickArgs args) {
// Path matching.
if (!PathMatch(args.path, route.matchers->path_matcher)) continue;
// Header Matching.
- if (!HeadersMatch(args, route.matchers->header_matchers)) continue;
+ if (!HeadersMatch(route.matchers->header_matchers, args.initial_metadata,
+ user_agent_,
+ args.call_state->ExperimentalGetCallAttribute(
+ kCallAttributeDeadline)))
+ continue;
// Match fraction check
if (route.matchers->fraction_per_million.has_value() &&
- !UnderFraction(route.matchers->fraction_per_million.value()))
+ !UnderFraction(route.matchers->fraction_per_million.value())) {
continue;
+ }
// Found a match
return route.picker->Pick(args);
}
@@ -336,7 +365,9 @@ XdsRoutingLb::PickResult XdsRoutingLb::RoutePicker::Pick(PickArgs args) {
// XdsRoutingLb
//
-XdsRoutingLb::XdsRoutingLb(Args args) : LoadBalancingPolicy(std::move(args)) {}
+XdsRoutingLb::XdsRoutingLb(Args args)
+ : LoadBalancingPolicy(std::move(args)),
+ user_agent_(GenerateUserAgentFromArgs(args.args, "chttp2")) {}
XdsRoutingLb::~XdsRoutingLb() {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_routing_lb_trace)) {
@@ -461,7 +492,8 @@ void XdsRoutingLb::UpdateStateLocked() {
}
route_table.push_back(std::move(route));
}
- picker = absl::make_unique(std::move(route_table), config_);
+ picker = absl::make_unique(std::move(route_table),
+ user_agent_, config_);
break;
}
case GRPC_CHANNEL_CONNECTING:
diff --git a/src/core/ext/filters/http/client/http_client_filter.cc b/src/core/ext/filters/http/client/http_client_filter.cc
index f09c60ce8f6..44fefec3002 100644
--- a/src/core/ext/filters/http/client/http_client_filter.cc
+++ b/src/core/ext/filters/http/client/http_client_filter.cc
@@ -31,6 +31,7 @@
#include
#include "src/core/ext/filters/http/client/http_client_filter.h"
+#include "src/core/ext/filters/http/client/util.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/profiling/timers.h"
@@ -528,36 +529,8 @@ static size_t max_payload_size_from_args(const grpc_channel_args* args) {
static grpc_core::ManagedMemorySlice user_agent_from_args(
const grpc_channel_args* args, const char* transport_name) {
- std::vector user_agent_fields;
-
- for (size_t i = 0; args && i < args->num_args; i++) {
- if (0 == strcmp(args->args[i].key, GRPC_ARG_PRIMARY_USER_AGENT_STRING)) {
- if (args->args[i].type != GRPC_ARG_STRING) {
- gpr_log(GPR_ERROR, "Channel argument '%s' should be a string",
- GRPC_ARG_PRIMARY_USER_AGENT_STRING);
- } else {
- user_agent_fields.push_back(args->args[i].value.string);
- }
- }
- }
-
- user_agent_fields.push_back(
- absl::StrFormat("grpc-c/%s (%s; %s)", grpc_version_string(),
- GPR_PLATFORM_STRING, transport_name));
-
- for (size_t i = 0; args && i < args->num_args; i++) {
- if (0 == strcmp(args->args[i].key, GRPC_ARG_SECONDARY_USER_AGENT_STRING)) {
- if (args->args[i].type != GRPC_ARG_STRING) {
- gpr_log(GPR_ERROR, "Channel argument '%s' should be a string",
- GRPC_ARG_SECONDARY_USER_AGENT_STRING);
- } else {
- user_agent_fields.push_back(args->args[i].value.string);
- }
- }
- }
-
- std::string user_agent_string = absl::StrJoin(user_agent_fields, " ");
- return grpc_core::ManagedMemorySlice(user_agent_string.c_str());
+ return grpc_core::ManagedMemorySlice(
+ grpc_core::GenerateUserAgentFromArgs(args, transport_name).c_str());
}
/* Constructor for channel_data */
diff --git a/src/core/ext/filters/http/client/util.cc b/src/core/ext/filters/http/client/util.cc
new file mode 100644
index 00000000000..d79fb49e763
--- /dev/null
+++ b/src/core/ext/filters/http/client/util.cc
@@ -0,0 +1,53 @@
+//
+// Copyright 2015 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 "absl/strings/str_format.h"
+#include "absl/strings/str_join.h"
+
+#include "src/core/ext/filters/http/client/util.h"
+
+namespace grpc_core {
+std::string GenerateUserAgentFromArgs(const grpc_channel_args* args,
+ const char* transport_name) {
+ std::vector user_agent_fields;
+ for (size_t i = 0; args && i < args->num_args; i++) {
+ if (0 == strcmp(args->args[i].key, GRPC_ARG_PRIMARY_USER_AGENT_STRING)) {
+ if (args->args[i].type != GRPC_ARG_STRING) {
+ gpr_log(GPR_ERROR, "Channel argument '%s' should be a string",
+ GRPC_ARG_PRIMARY_USER_AGENT_STRING);
+ } else {
+ user_agent_fields.push_back(args->args[i].value.string);
+ }
+ }
+ }
+ user_agent_fields.push_back(
+ absl::StrFormat("grpc-c/%s (%s; %s)", grpc_version_string(),
+ GPR_PLATFORM_STRING, transport_name));
+ for (size_t i = 0; args && i < args->num_args; i++) {
+ if (0 == strcmp(args->args[i].key, GRPC_ARG_SECONDARY_USER_AGENT_STRING)) {
+ if (args->args[i].type != GRPC_ARG_STRING) {
+ gpr_log(GPR_ERROR, "Channel argument '%s' should be a string",
+ GRPC_ARG_SECONDARY_USER_AGENT_STRING);
+ } else {
+ user_agent_fields.push_back(args->args[i].value.string);
+ }
+ }
+ }
+ return absl::StrJoin(user_agent_fields, " ");
+}
+} // namespace grpc_core
diff --git a/src/core/ext/filters/http/client/util.h b/src/core/ext/filters/http/client/util.h
new file mode 100644
index 00000000000..725c3dba4b4
--- /dev/null
+++ b/src/core/ext/filters/http/client/util.h
@@ -0,0 +1,30 @@
+//
+// Copyright 2015 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.
+//
+
+#ifndef GRPC_CORE_EXT_FILTERS_HTTP_CLIENT_UTIL_H
+#define GRPC_CORE_EXT_FILTERS_HTTP_CLIENT_UTIL_H
+
+#include
+
+#include "absl/strings/str_join.h"
+
+#include "src/core/lib/channel/channel_stack.h"
+
+namespace grpc_core {
+std::string GenerateUserAgentFromArgs(const grpc_channel_args* args,
+ const char* transport_name);
+} // namespace grpc_core
+#endif /* GRPC_CORE_EXT_FILTERS_HTTP_CLIENT_UTIL_H */
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 6512c493673..3726c057eb9 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -83,6 +83,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/filters/client_idle/client_idle_filter.cc',
'src/core/ext/filters/deadline/deadline_filter.cc',
'src/core/ext/filters/http/client/http_client_filter.cc',
+ 'src/core/ext/filters/http/client/util.cc',
'src/core/ext/filters/http/client_authority_filter.cc',
'src/core/ext/filters/http/http_filters_plugin.cc',
'src/core/ext/filters/http/message_compress/message_compress_filter.cc',
diff --git a/test/cpp/end2end/xds_end2end_test.cc b/test/cpp/end2end/xds_end2end_test.cc
index 19561cec2e4..84a067e8983 100644
--- a/test/cpp/end2end/xds_end2end_test.cc
+++ b/test/cpp/end2end/xds_end2end_test.cc
@@ -3607,6 +3607,245 @@ TEST_P(LdsRdsTest, XdsRoutingHeadersMatching) {
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING");
}
+TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingSpecialHeaderContentType) {
+ gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true");
+ const char* kNewCluster1Name = "new_cluster_1";
+ const size_t kNumEchoRpcs = 100;
+ SetNextResolution({});
+ SetNextResolutionForLbChannelAllBalancers();
+ // Populate new EDS resources.
+ AdsServiceImpl::EdsResourceArgs args({
+ {"locality0", GetBackendPorts(0, 1)},
+ });
+ AdsServiceImpl::EdsResourceArgs args1({
+ {"locality0", GetBackendPorts(1, 2)},
+ });
+ balancers_[0]->ads_service()->SetEdsResource(
+ AdsServiceImpl::BuildEdsResource(args));
+ balancers_[0]->ads_service()->SetEdsResource(
+ AdsServiceImpl::BuildEdsResource(args1, kNewCluster1Name));
+ // Populate new CDS resources.
+ Cluster new_cluster1 = balancers_[0]->ads_service()->default_cluster();
+ new_cluster1.set_name(kNewCluster1Name);
+ balancers_[0]->ads_service()->SetCdsResource(new_cluster1);
+ // Populating Route Configurations for LDS.
+ RouteConfiguration route_config =
+ balancers_[0]->ads_service()->default_route_config();
+ auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
+ route1->mutable_match()->set_prefix("");
+ auto* header_matcher1 = route1->mutable_match()->add_headers();
+ header_matcher1->set_name("content-type");
+ header_matcher1->set_exact_match("notapplication/grpc");
+ route1->mutable_route()->set_cluster(kNewCluster1Name);
+ auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes();
+ default_route->mutable_match()->set_prefix("");
+ auto* header_matcher2 = default_route->mutable_match()->add_headers();
+ header_matcher2->set_name("content-type");
+ header_matcher2->set_exact_match("application/grpc");
+ default_route->mutable_route()->set_cluster(kDefaultResourceName);
+ SetRouteConfiguration(0, route_config);
+ // Make sure the backend is up.
+ WaitForAllBackends(0, 1);
+ // Send RPCs.
+ CheckRpcSendOk(kNumEchoRpcs);
+ EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
+ EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
+ const auto& response_state = RouteConfigurationResponseState(0);
+ EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::ACKED);
+ gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING");
+}
+
+TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingSpecialHeaderUserAgent) {
+ gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true");
+ const char* kNewCluster1Name = "new_cluster_1";
+ const size_t kNumEchoRpcs = 100;
+ SetNextResolution({});
+ SetNextResolutionForLbChannelAllBalancers();
+ // Populate new EDS resources.
+ AdsServiceImpl::EdsResourceArgs args({
+ {"locality0", GetBackendPorts(0, 1)},
+ });
+ AdsServiceImpl::EdsResourceArgs args1({
+ {"locality0", GetBackendPorts(1, 2)},
+ });
+ balancers_[0]->ads_service()->SetEdsResource(
+ AdsServiceImpl::BuildEdsResource(args));
+ balancers_[0]->ads_service()->SetEdsResource(
+ AdsServiceImpl::BuildEdsResource(args1, kNewCluster1Name));
+ // Populate new CDS resources.
+ Cluster new_cluster1 = balancers_[0]->ads_service()->default_cluster();
+ new_cluster1.set_name(kNewCluster1Name);
+ balancers_[0]->ads_service()->SetCdsResource(new_cluster1);
+ // Populating Route Configurations for LDS.
+ RouteConfiguration route_config =
+ balancers_[0]->ads_service()->default_route_config();
+ auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
+ route1->mutable_match()->set_prefix("");
+ auto* header_matcher1 = route1->mutable_match()->add_headers();
+ header_matcher1->set_name("user-agent");
+ header_matcher1->mutable_safe_regex_match()->set_regex(
+ "(does-not-match-grpc-c).*");
+ route1->mutable_route()->set_cluster(kNewCluster1Name);
+ auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes();
+ default_route->mutable_match()->set_prefix("");
+ auto* header_matcher2 = default_route->mutable_match()->add_headers();
+ header_matcher2->set_name("user-agent");
+ // user-agent string is a 2-part string like "grpc-c++/1.31.0-dev
+ // grpc-c/11.0.0".
+ header_matcher2->mutable_safe_regex_match()->set_regex(
+ "((grpc-c).*[0-9]+.[0-9]+.[0-9]+.*){2}");
+ default_route->mutable_route()->set_cluster(kDefaultResourceName);
+ SetRouteConfiguration(0, route_config);
+ // Make sure backend is up.
+ WaitForAllBackends(0, 1);
+ // Send RPCs.
+ CheckRpcSendOk(kNumEchoRpcs);
+ EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
+ EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
+ const auto& response_state = RouteConfigurationResponseState(0);
+ EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::ACKED);
+ gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING");
+}
+
+TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingSpecialHeaderGrpcTimeout) {
+ gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true");
+ const char* kNewCluster1Name = "new_cluster_1";
+ const size_t kNumEchoRpcs = 100;
+ SetNextResolution({});
+ SetNextResolutionForLbChannelAllBalancers();
+ // Populate new EDS resources.
+ AdsServiceImpl::EdsResourceArgs args({
+ {"locality0", GetBackendPorts(0, 1)},
+ });
+ AdsServiceImpl::EdsResourceArgs args1({
+ {"locality0", GetBackendPorts(1, 2)},
+ });
+ balancers_[0]->ads_service()->SetEdsResource(
+ AdsServiceImpl::BuildEdsResource(args));
+ balancers_[0]->ads_service()->SetEdsResource(
+ AdsServiceImpl::BuildEdsResource(args1, kNewCluster1Name));
+ // Populate new CDS resources.
+ Cluster new_cluster1 = balancers_[0]->ads_service()->default_cluster();
+ new_cluster1.set_name(kNewCluster1Name);
+ balancers_[0]->ads_service()->SetCdsResource(new_cluster1);
+ // Populating Route Configurations for LDS.
+ RouteConfiguration route_config =
+ balancers_[0]->ads_service()->default_route_config();
+ auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
+ route1->mutable_match()->set_prefix("");
+ auto* header_matcher1 = route1->mutable_match()->add_headers();
+ header_matcher1->set_name("grpc-timeout");
+ header_matcher1->mutable_safe_regex_match()->set_regex("[0-9]+(s|h)");
+ route1->mutable_route()->set_cluster(kNewCluster1Name);
+ auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes();
+ default_route->mutable_match()->set_prefix("");
+ auto* header_matcher2 = default_route->mutable_match()->add_headers();
+ header_matcher2->set_name("grpc-timeout");
+ header_matcher2->mutable_safe_regex_match()->set_regex("[0-9]+(m|S|M|H)");
+ default_route->mutable_route()->set_cluster(kDefaultResourceName);
+ SetRouteConfiguration(0, route_config);
+ // Make sure backend is up.
+ WaitForAllBackends(0, 1);
+ // Send RPCs.
+ CheckRpcSendOk(kNumEchoRpcs);
+ EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
+ EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
+ const auto& response_state = RouteConfigurationResponseState(0);
+ EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::ACKED);
+ gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING");
+}
+
+TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingSpecialCasesToIgnore) {
+ gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true");
+ const char* kNewCluster1Name = "new_cluster_1";
+ const char* kNewCluster2Name = "new_cluster_2";
+ const char* kNewCluster3Name = "new_cluster_3";
+ const size_t kNumEcho1Rpcs = 100;
+ const size_t kNumEchoRpcs = 5;
+ SetNextResolution({});
+ SetNextResolutionForLbChannelAllBalancers();
+ // Populate new EDS resources.
+ AdsServiceImpl::EdsResourceArgs args({
+ {"locality0", GetBackendPorts(0, 1)},
+ });
+ AdsServiceImpl::EdsResourceArgs args1({
+ {"locality0", GetBackendPorts(1, 2)},
+ });
+ AdsServiceImpl::EdsResourceArgs args2({
+ {"locality0", GetBackendPorts(2, 3)},
+ });
+ AdsServiceImpl::EdsResourceArgs args3({
+ {"locality0", GetBackendPorts(3, 4)},
+ });
+ balancers_[0]->ads_service()->SetEdsResource(
+ AdsServiceImpl::BuildEdsResource(args));
+ balancers_[0]->ads_service()->SetEdsResource(
+ AdsServiceImpl::BuildEdsResource(args1, kNewCluster1Name));
+ balancers_[0]->ads_service()->SetEdsResource(
+ AdsServiceImpl::BuildEdsResource(args2, kNewCluster2Name));
+ balancers_[0]->ads_service()->SetEdsResource(
+ AdsServiceImpl::BuildEdsResource(args3, kNewCluster3Name));
+ // Populate new CDS resources.
+ Cluster new_cluster1 = balancers_[0]->ads_service()->default_cluster();
+ new_cluster1.set_name(kNewCluster1Name);
+ balancers_[0]->ads_service()->SetCdsResource(new_cluster1);
+ Cluster new_cluster2 = balancers_[0]->ads_service()->default_cluster();
+ new_cluster2.set_name(kNewCluster2Name);
+ balancers_[0]->ads_service()->SetCdsResource(new_cluster2);
+ Cluster new_cluster3 = balancers_[0]->ads_service()->default_cluster();
+ new_cluster1.set_name(kNewCluster3Name);
+ balancers_[0]->ads_service()->SetCdsResource(new_cluster3);
+ // Populating Route Configurations for LDS.
+ RouteConfiguration route_config =
+ balancers_[0]->ads_service()->default_route_config();
+ auto* route1 = route_config.mutable_virtual_hosts(0)->mutable_routes(0);
+ route1->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
+ auto* header_matcher1 = route1->mutable_match()->add_headers();
+ header_matcher1->set_name("grpc-tags-bin");
+ header_matcher1->set_exact_match("grpc-tags-bin");
+ route1->mutable_route()->set_cluster(kNewCluster1Name);
+ auto route2 = route_config.mutable_virtual_hosts(0)->add_routes();
+ route2->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
+ auto* header_matcher2 = route2->mutable_match()->add_headers();
+ header_matcher2->set_name("grpc-trace-bin");
+ header_matcher2->set_exact_match("grpc-trace-bin");
+ route2->mutable_route()->set_cluster(kNewCluster2Name);
+ auto route3 = route_config.mutable_virtual_hosts(0)->add_routes();
+ route3->mutable_match()->set_prefix("/grpc.testing.EchoTest1Service/");
+ auto* header_matcher3 = route3->mutable_match()->add_headers();
+ header_matcher3->set_name("grpc-previous-rpc-attempts");
+ header_matcher3->set_exact_match("grpc-previous-rpc-attempts");
+ route3->mutable_route()->set_cluster(kNewCluster3Name);
+ auto* default_route = route_config.mutable_virtual_hosts(0)->add_routes();
+ default_route->mutable_match()->set_prefix("");
+ default_route->mutable_route()->set_cluster(kDefaultResourceName);
+ SetRouteConfiguration(0, route_config);
+ // Send headers which will mismatch each route
+ std::vector> metadata = {
+ {"grpc-tags-bin", "grpc-tags-bin"},
+ {"grpc-trace-bin", "grpc-trace-bin"},
+ {"grpc-previous-rpc-attempts", "grpc-previous-rpc-attempts"},
+ };
+ WaitForAllBackends(0, 1);
+ CheckRpcSendOk(kNumEchoRpcs, RpcOptions().set_metadata(metadata));
+ CheckRpcSendOk(kNumEcho1Rpcs, RpcOptions()
+ .set_rpc_service(SERVICE_ECHO1)
+ .set_rpc_method(METHOD_ECHO1)
+ .set_metadata(metadata));
+ // Verify that only the default backend got RPCs since all previous routes
+ // were mismatched.
+ for (size_t i = 1; i < 4; ++i) {
+ EXPECT_EQ(0, backends_[i]->backend_service()->request_count());
+ EXPECT_EQ(0, backends_[i]->backend_service1()->request_count());
+ EXPECT_EQ(0, backends_[i]->backend_service2()->request_count());
+ }
+ EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
+ EXPECT_EQ(kNumEcho1Rpcs, backends_[0]->backend_service1()->request_count());
+ EXPECT_EQ(0, backends_[0]->backend_service2()->request_count());
+ const auto& response_state = RouteConfigurationResponseState(0);
+ EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::ACKED);
+ gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_ROUTING");
+}
TEST_P(LdsRdsTest, XdsRoutingRuntimeFractionMatching) {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_ROUTING", "true");
const char* kNewCluster1Name = "new_cluster_1";
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 319a7b5f41b..590de9c19a4 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -1185,6 +1185,8 @@ src/core/ext/filters/deadline/deadline_filter.cc \
src/core/ext/filters/deadline/deadline_filter.h \
src/core/ext/filters/http/client/http_client_filter.cc \
src/core/ext/filters/http/client/http_client_filter.h \
+src/core/ext/filters/http/client/util.cc \
+src/core/ext/filters/http/client/util.h \
src/core/ext/filters/http/client_authority_filter.cc \
src/core/ext/filters/http/client_authority_filter.h \
src/core/ext/filters/http/http_filters_plugin.cc \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index b288eda20ce..aff7aeccf00 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -990,6 +990,8 @@ src/core/ext/filters/deadline/deadline_filter.cc \
src/core/ext/filters/deadline/deadline_filter.h \
src/core/ext/filters/http/client/http_client_filter.cc \
src/core/ext/filters/http/client/http_client_filter.h \
+src/core/ext/filters/http/client/util.cc \
+src/core/ext/filters/http/client/util.h \
src/core/ext/filters/http/client_authority_filter.cc \
src/core/ext/filters/http/client_authority_filter.h \
src/core/ext/filters/http/http_filters_plugin.cc \