|  | @@ -3477,6 +3477,116 @@ TEST_P(LdsRdsTest, XdsRoutingHeadersMatching) {
 | 
	
		
			
				|  |  |    EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::ACKED);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingSpecialHeaderContentType) {
 | 
	
		
			
				|  |  | +  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);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +TEST_P(LdsRdsTest, XdsRoutingHeadersMatchingSpecialCasesToIgnore) {
 | 
	
		
			
				|  |  | +  const char* kNewCluster1Name = "new_cluster_1";
 | 
	
		
			
				|  |  | +  const char* kNewCluster2Name = "new_cluster_2";
 | 
	
		
			
				|  |  | +  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)},
 | 
	
		
			
				|  |  | +  });
 | 
	
		
			
				|  |  | +  AdsServiceImpl::EdsResourceArgs args2({
 | 
	
		
			
				|  |  | +      {"locality0", GetBackendPorts(2, 3)},
 | 
	
		
			
				|  |  | +  });
 | 
	
		
			
				|  |  | +  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));
 | 
	
		
			
				|  |  | +  // 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);
 | 
	
		
			
				|  |  | +  // 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-foo-bin");
 | 
	
		
			
				|  |  | +  header_matcher1->set_present_match(true);
 | 
	
		
			
				|  |  | +  route1->mutable_route()->set_cluster(kNewCluster1Name);
 | 
	
		
			
				|  |  | +  auto route2 = route_config.mutable_virtual_hosts(0)->add_routes();
 | 
	
		
			
				|  |  | +  route2->mutable_match()->set_prefix("");
 | 
	
		
			
				|  |  | +  auto* header_matcher2 = route2->mutable_match()->add_headers();
 | 
	
		
			
				|  |  | +  header_matcher2->set_name("grpc-previous-rpc-attempts");
 | 
	
		
			
				|  |  | +  header_matcher2->set_present_match(true);
 | 
	
		
			
				|  |  | +  route2->mutable_route()->set_cluster(kNewCluster2Name);
 | 
	
		
			
				|  |  | +  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<std::pair<std::string, std::string>> metadata = {
 | 
	
		
			
				|  |  | +      {"grpc-foo-bin", "grpc-foo-bin"},
 | 
	
		
			
				|  |  | +      {"grpc-previous-rpc-attempts", "grpc-previous-rpc-attempts"},
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +  WaitForAllBackends(0, 1);
 | 
	
		
			
				|  |  | +  CheckRpcSendOk(kNumEchoRpcs, RpcOptions().set_metadata(metadata));
 | 
	
		
			
				|  |  | +  // Verify that only the default backend got RPCs since all previous routes
 | 
	
		
			
				|  |  | +  // were mismatched.
 | 
	
		
			
				|  |  | +  EXPECT_EQ(kNumEchoRpcs, backends_[0]->backend_service()->request_count());
 | 
	
		
			
				|  |  | +  EXPECT_EQ(0, backends_[1]->backend_service()->request_count());
 | 
	
		
			
				|  |  | +  EXPECT_EQ(0, backends_[2]->backend_service()->request_count());
 | 
	
		
			
				|  |  | +  const auto& response_state = RouteConfigurationResponseState(0);
 | 
	
		
			
				|  |  | +  EXPECT_EQ(response_state.state, AdsServiceImpl::ResponseState::ACKED);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  TEST_P(LdsRdsTest, XdsRoutingRuntimeFractionMatching) {
 | 
	
		
			
				|  |  |    const char* kNewCluster1Name = "new_cluster_1";
 | 
	
		
			
				|  |  |    const size_t kNumRpcs = 1000;
 |