xds: Required Router Filter for both Client and Server side (#4676)

* Added isTerminal() to FilterAPI and required router filter on Client and Server side
This commit is contained in:
Zach Reyes 2021-08-30 16:49:46 -04:00 committed by GitHub
parent 85b9a1a0fa
commit ef66d13abb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 404 additions and 63 deletions

View File

@ -101,6 +101,10 @@ func (builder) ParseFilterConfigOverride(override proto.Message) (httpfilter.Fil
return parseConfig(override)
}
func (builder) IsTerminal() bool {
return false
}
var _ httpfilter.ClientInterceptorBuilder = builder{}
func (builder) BuildClientInterceptor(cfg, override httpfilter.FilterConfig) (iresolver.ClientInterceptor, error) {

View File

@ -50,6 +50,9 @@ type Filter interface {
// not accept a custom type. The resulting FilterConfig will later be
// passed to Build.
ParseFilterConfigOverride(proto.Message) (FilterConfig, error)
// IsTerminal returns whether this Filter is terminal or not (i.e. it must
// be last filter in the filter chain).
IsTerminal() bool
}
// ClientInterceptorBuilder constructs a Client Interceptor. If this type is

View File

@ -73,6 +73,10 @@ func (builder) ParseFilterConfigOverride(override proto.Message) (httpfilter.Fil
return config{}, nil
}
func (builder) IsTerminal() bool {
return true
}
var (
_ httpfilter.ClientInterceptorBuilder = builder{}
_ httpfilter.ServerInterceptorBuilder = builder{}

View File

@ -34,6 +34,8 @@ import (
wrapperspb "github.com/golang/protobuf/ptypes/wrappers"
"google.golang.org/grpc/internal/grpctest"
"google.golang.org/grpc/internal/testutils"
_ "google.golang.org/grpc/xds/internal/httpfilter/router"
"google.golang.org/grpc/xds/internal/testutils/e2e"
"google.golang.org/grpc/xds/internal/testutils/fakeclient"
"google.golang.org/grpc/xds/internal/xdsclient"
)
@ -82,6 +84,7 @@ var listenerWithRouteConfiguration = &v3listenerpb.Listener{
RouteConfigName: "route-1",
},
},
HttpFilters: []*v3httppb.HttpFilter{e2e.RouterHTTPFilter},
}),
},
},
@ -143,6 +146,7 @@ var listenerWithFilterChains = &v3listenerpb.Listener{
Action: &v3routepb.Route_NonForwardingAction{},
}}}}},
},
HttpFilters: []*v3httppb.HttpFilter{e2e.RouterHTTPFilter},
}),
},
},

View File

@ -97,6 +97,9 @@ func DefaultClientResources(params ResourceParams) UpdateOptions {
}
}
// RouterHTTPFilter is the HTTP Filter configuration for the Router filter.
var RouterHTTPFilter = HTTPFilter("router", &v3routerpb.Router{})
// DefaultClientListener returns a basic xds Listener resource to be used on
// the client side.
func DefaultClientListener(target, routeName string) *v3listenerpb.Listener {
@ -212,6 +215,7 @@ func DefaultServerListener(host string, port uint32, secLevel SecurityLevel) *v3
Action: &v3routepb.Route_NonForwardingAction{},
}}}}},
},
HttpFilters: []*v3httppb.HttpFilter{RouterHTTPFilter},
}),
},
},
@ -256,6 +260,7 @@ func DefaultServerListener(host string, port uint32, secLevel SecurityLevel) *v3
Action: &v3routepb.Route_NonForwardingAction{},
}}}}},
},
HttpFilters: []*v3httppb.HttpFilter{RouterHTTPFilter},
}),
},
},

View File

@ -505,7 +505,7 @@ func processNetworkFilters(filters []*v3listenerpb.Filter) (*FilterChain, error)
// HTTPConnectionManager must have valid http_filters." - A36
filters, err := processHTTPFilters(hcm.GetHttpFilters(), true)
if err != nil {
return nil, fmt.Errorf("network filters {%+v} had invalid server side HTTP Filters {%+v}", filters, hcm.GetHttpFilters())
return nil, fmt.Errorf("network filters {%+v} had invalid server side HTTP Filters {%+v}: %v", filters, hcm.GetHttpFilters(), err)
}
if !seenHCM {
// TODO: Implement terminal filter logic, as per A36.

View File

@ -27,6 +27,7 @@ import (
v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
v3routerpb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/router/v3"
v3httppb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
v3tlspb "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"
"github.com/google/go-cmp/cmp"
@ -36,6 +37,9 @@ import (
"google.golang.org/protobuf/types/known/wrapperspb"
"google.golang.org/grpc/internal/testutils"
"google.golang.org/grpc/xds/internal/httpfilter"
"google.golang.org/grpc/xds/internal/httpfilter/router"
"google.golang.org/grpc/xds/internal/testutils/e2e"
"google.golang.org/grpc/xds/internal/version"
)
@ -63,6 +67,7 @@ var (
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
RouteConfig: routeConfig,
},
HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter},
}),
},
},
@ -75,6 +80,11 @@ var (
Name: "serverOnlyCustomFilter2",
ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: serverOnlyCustomFilterConfig},
}
emptyRouterFilter = e2e.RouterHTTPFilter
routerBuilder = httpfilter.Get(router.TypeURL)
routerConfig, _ = routerBuilder.ParseFilterConfig(testutils.MarshalAny(&v3routerpb.Router{}))
routerFilter = HTTPFilter{Name: "router", Filter: routerBuilder, Config: routerConfig}
routerFilterList = []HTTPFilter{routerFilter}
)
// TestNewFilterChainImpl_Failure_BadMatchFields verifies cases where we have a
@ -461,6 +471,7 @@ func TestNewFilterChainImpl_Success_RouteUpdate(t *testing.T) {
RouteConfigName: "route-1",
},
},
HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter},
}),
},
},
@ -481,6 +492,7 @@ func TestNewFilterChainImpl_Success_RouteUpdate(t *testing.T) {
RouteConfigName: "route-1",
},
},
HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter},
}),
},
},
@ -497,6 +509,7 @@ func TestNewFilterChainImpl_Success_RouteUpdate(t *testing.T) {
srcPortMap: map[int]*FilterChain{
0: {
RouteConfigName: "route-1",
HTTPFilters: routerFilterList,
},
},
},
@ -507,6 +520,7 @@ func TestNewFilterChainImpl_Success_RouteUpdate(t *testing.T) {
},
def: &FilterChain{
RouteConfigName: "route-1",
HTTPFilters: routerFilterList,
},
RouteConfigNames: map[string]bool{"route-1": true},
},
@ -525,6 +539,7 @@ func TestNewFilterChainImpl_Success_RouteUpdate(t *testing.T) {
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
RouteConfig: routeConfig,
},
HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter},
}),
},
},
@ -540,6 +555,7 @@ func TestNewFilterChainImpl_Success_RouteUpdate(t *testing.T) {
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
RouteConfig: routeConfig,
},
HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter},
}),
},
},
@ -556,6 +572,7 @@ func TestNewFilterChainImpl_Success_RouteUpdate(t *testing.T) {
srcPortMap: map[int]*FilterChain{
0: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
@ -566,6 +583,7 @@ func TestNewFilterChainImpl_Success_RouteUpdate(t *testing.T) {
},
def: &FilterChain{
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
@ -590,6 +608,7 @@ func TestNewFilterChainImpl_Success_RouteUpdate(t *testing.T) {
RouteConfigName: "route-1",
},
},
HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter},
}),
},
},
@ -610,6 +629,7 @@ func TestNewFilterChainImpl_Success_RouteUpdate(t *testing.T) {
RouteConfigName: "route-2",
},
},
HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter},
}),
},
},
@ -626,6 +646,7 @@ func TestNewFilterChainImpl_Success_RouteUpdate(t *testing.T) {
srcPortMap: map[int]*FilterChain{
0: {
RouteConfigName: "route-1",
HTTPFilters: routerFilterList,
},
},
},
@ -636,6 +657,7 @@ func TestNewFilterChainImpl_Success_RouteUpdate(t *testing.T) {
},
def: &FilterChain{
RouteConfigName: "route-2",
HTTPFilters: routerFilterList,
},
RouteConfigNames: map[string]bool{
"route-1": true,
@ -675,12 +697,14 @@ func TestNewFilterChainImpl_Failure_BadRouteUpdate(t *testing.T) {
{
Name: "hcm",
ConfigType: &v3listenerpb.Filter_TypedConfig{
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{
Rds: &v3httppb.Rds{
RouteConfigName: "route-1",
},
},
HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter},
}),
},
},
@ -698,6 +722,7 @@ func TestNewFilterChainImpl_Failure_BadRouteUpdate(t *testing.T) {
RouteConfigName: "route-1",
},
},
HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter},
}),
},
},
@ -718,6 +743,7 @@ func TestNewFilterChainImpl_Failure_BadRouteUpdate(t *testing.T) {
ConfigType: &v3listenerpb.Filter_TypedConfig{
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
RouteSpecifier: &v3httppb.HttpConnectionManager_ScopedRoutes{},
HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter},
}),
},
},
@ -731,6 +757,7 @@ func TestNewFilterChainImpl_Failure_BadRouteUpdate(t *testing.T) {
ConfigType: &v3listenerpb.Filter_TypedConfig{
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
RouteSpecifier: &v3httppb.HttpConnectionManager_ScopedRoutes{},
HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter},
}),
},
},
@ -846,6 +873,7 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
HttpFilters: []*v3httppb.HttpFilter{
validServerSideHTTPFilter1,
emptyRouterFilter,
},
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
RouteConfig: routeConfig,
@ -864,6 +892,7 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
HttpFilters: []*v3httppb.HttpFilter{
validServerSideHTTPFilter1,
emptyRouterFilter,
},
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
RouteConfig: routeConfig,
@ -888,6 +917,7 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
Filter: serverOnlyHTTPFilter{},
Config: filterConfig{Cfg: serverOnlyCustomFilterConfig},
},
routerFilter,
},
InlineRouteConfig: inlineRouteConfig,
},
@ -899,11 +929,14 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
},
},
def: &FilterChain{
HTTPFilters: []HTTPFilter{{
Name: "serverOnlyCustomFilter",
Filter: serverOnlyHTTPFilter{},
Config: filterConfig{Cfg: serverOnlyCustomFilterConfig},
}},
HTTPFilters: []HTTPFilter{
{
Name: "serverOnlyCustomFilter",
Filter: serverOnlyHTTPFilter{},
Config: filterConfig{Cfg: serverOnlyCustomFilterConfig},
},
routerFilter,
},
InlineRouteConfig: inlineRouteConfig,
},
},
@ -922,6 +955,7 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
HttpFilters: []*v3httppb.HttpFilter{
validServerSideHTTPFilter1,
validServerSideHTTPFilter2,
emptyRouterFilter,
},
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
RouteConfig: routeConfig,
@ -941,6 +975,7 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
HttpFilters: []*v3httppb.HttpFilter{
validServerSideHTTPFilter1,
validServerSideHTTPFilter2,
emptyRouterFilter,
},
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
RouteConfig: routeConfig,
@ -970,6 +1005,7 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
Filter: serverOnlyHTTPFilter{},
Config: filterConfig{Cfg: serverOnlyCustomFilterConfig},
},
routerFilter,
},
InlineRouteConfig: inlineRouteConfig,
},
@ -991,6 +1027,7 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
Filter: serverOnlyHTTPFilter{},
Config: filterConfig{Cfg: serverOnlyCustomFilterConfig},
},
routerFilter,
},
InlineRouteConfig: inlineRouteConfig,
},
@ -1012,6 +1049,7 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
HttpFilters: []*v3httppb.HttpFilter{
validServerSideHTTPFilter1,
validServerSideHTTPFilter2,
emptyRouterFilter,
},
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
RouteConfig: routeConfig,
@ -1025,6 +1063,7 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
HttpFilters: []*v3httppb.HttpFilter{
validServerSideHTTPFilter1,
emptyRouterFilter,
},
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
RouteConfig: routeConfig,
@ -1044,6 +1083,7 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
HttpFilters: []*v3httppb.HttpFilter{
validServerSideHTTPFilter1,
validServerSideHTTPFilter2,
emptyRouterFilter,
},
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
RouteConfig: routeConfig,
@ -1057,6 +1097,7 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
HttpFilters: []*v3httppb.HttpFilter{
validServerSideHTTPFilter1,
emptyRouterFilter,
},
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
RouteConfig: routeConfig,
@ -1086,6 +1127,7 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
Filter: serverOnlyHTTPFilter{},
Config: filterConfig{Cfg: serverOnlyCustomFilterConfig},
},
routerFilter,
},
InlineRouteConfig: inlineRouteConfig,
},
@ -1107,6 +1149,7 @@ func TestNewFilterChainImpl_Success_HTTPFilters(t *testing.T) {
Filter: serverOnlyHTTPFilter{},
Config: filterConfig{Cfg: serverOnlyCustomFilterConfig},
},
routerFilter,
},
InlineRouteConfig: inlineRouteConfig,
},
@ -1156,7 +1199,10 @@ func TestNewFilterChainImpl_Success_SecurityConfig(t *testing.T) {
srcPrefixMap: map[string]*sourcePrefixEntry{
unspecifiedPrefixMapKey: {
srcPortMap: map[int]*FilterChain{
0: {InlineRouteConfig: inlineRouteConfig},
0: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
},
@ -1164,7 +1210,10 @@ func TestNewFilterChainImpl_Success_SecurityConfig(t *testing.T) {
},
},
},
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
def: &FilterChain{
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
{
@ -1219,6 +1268,7 @@ func TestNewFilterChainImpl_Success_SecurityConfig(t *testing.T) {
IdentityCertName: "identityCertName",
},
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
@ -1233,6 +1283,7 @@ func TestNewFilterChainImpl_Success_SecurityConfig(t *testing.T) {
IdentityCertName: "defaultIdentityCertName",
},
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
@ -1306,6 +1357,7 @@ func TestNewFilterChainImpl_Success_SecurityConfig(t *testing.T) {
RequireClientCert: true,
},
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
@ -1323,6 +1375,7 @@ func TestNewFilterChainImpl_Success_SecurityConfig(t *testing.T) {
RequireClientCert: true,
},
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
@ -1353,7 +1406,10 @@ func TestNewFilterChainImpl_Success_UnsupportedMatchFields(t *testing.T) {
srcPrefixMap: map[string]*sourcePrefixEntry{
unspecifiedPrefixMapKey: {
srcPortMap: map[int]*FilterChain{
0: {InlineRouteConfig: inlineRouteConfig},
0: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
},
@ -1389,7 +1445,10 @@ func TestNewFilterChainImpl_Success_UnsupportedMatchFields(t *testing.T) {
dstPrefixMap: map[string]*destPrefixEntry{
unspecifiedPrefixMapKey: unspecifiedEntry,
},
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
def: &FilterChain{
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
{
@ -1418,7 +1477,10 @@ func TestNewFilterChainImpl_Success_UnsupportedMatchFields(t *testing.T) {
net: ipNetFromCIDR("192.168.2.2/16"),
},
},
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
def: &FilterChain{
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
{
@ -1447,7 +1509,10 @@ func TestNewFilterChainImpl_Success_UnsupportedMatchFields(t *testing.T) {
net: ipNetFromCIDR("192.168.2.2/16"),
},
},
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
def: &FilterChain{
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
{
@ -1476,7 +1541,10 @@ func TestNewFilterChainImpl_Success_UnsupportedMatchFields(t *testing.T) {
net: ipNetFromCIDR("192.168.2.2/16"),
},
},
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
def: &FilterChain{
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
}
@ -1546,7 +1614,10 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
srcPrefixMap: map[string]*sourcePrefixEntry{
unspecifiedPrefixMapKey: {
srcPortMap: map[int]*FilterChain{
0: {InlineRouteConfig: inlineRouteConfig},
0: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
},
@ -1562,7 +1633,10 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
srcPrefixMap: map[string]*sourcePrefixEntry{
unspecifiedPrefixMapKey: {
srcPortMap: map[int]*FilterChain{
0: {InlineRouteConfig: inlineRouteConfig},
0: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
},
@ -1578,7 +1652,10 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
srcPrefixMap: map[string]*sourcePrefixEntry{
unspecifiedPrefixMapKey: {
srcPortMap: map[int]*FilterChain{
0: {InlineRouteConfig: inlineRouteConfig},
0: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
},
@ -1592,7 +1669,10 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
srcPrefixMap: map[string]*sourcePrefixEntry{
unspecifiedPrefixMapKey: {
srcPortMap: map[int]*FilterChain{
0: {InlineRouteConfig: inlineRouteConfig},
0: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
},
@ -1606,7 +1686,10 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
srcPrefixMap: map[string]*sourcePrefixEntry{
unspecifiedPrefixMapKey: {
srcPortMap: map[int]*FilterChain{
0: {InlineRouteConfig: inlineRouteConfig},
0: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
},
@ -1614,7 +1697,10 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
},
},
},
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
def: &FilterChain{
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
{
@ -1644,7 +1730,10 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
srcPrefixMap: map[string]*sourcePrefixEntry{
unspecifiedPrefixMapKey: {
srcPortMap: map[int]*FilterChain{
0: {InlineRouteConfig: inlineRouteConfig},
0: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
},
@ -1660,7 +1749,10 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
srcPrefixMap: map[string]*sourcePrefixEntry{
unspecifiedPrefixMapKey: {
srcPortMap: map[int]*FilterChain{
0: {InlineRouteConfig: inlineRouteConfig},
0: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
},
@ -1668,7 +1760,10 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
},
},
},
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
def: &FilterChain{
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
{
@ -1698,7 +1793,10 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
"10.0.0.0/8": {
net: ipNetFromCIDR("10.0.0.0/8"),
srcPortMap: map[int]*FilterChain{
0: {InlineRouteConfig: inlineRouteConfig},
0: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
},
@ -1713,7 +1811,10 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
"192.168.0.0/16": {
net: ipNetFromCIDR("192.168.0.0/16"),
srcPortMap: map[int]*FilterChain{
0: {InlineRouteConfig: inlineRouteConfig},
0: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
},
@ -1721,7 +1822,10 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
},
},
},
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
def: &FilterChain{
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
{
@ -1752,9 +1856,18 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
srcPrefixMap: map[string]*sourcePrefixEntry{
unspecifiedPrefixMapKey: {
srcPortMap: map[int]*FilterChain{
1: {InlineRouteConfig: inlineRouteConfig},
2: {InlineRouteConfig: inlineRouteConfig},
3: {InlineRouteConfig: inlineRouteConfig},
1: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
2: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
3: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
},
@ -1771,9 +1884,18 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
"192.168.0.0/16": {
net: ipNetFromCIDR("192.168.0.0/16"),
srcPortMap: map[int]*FilterChain{
1: {InlineRouteConfig: inlineRouteConfig},
2: {InlineRouteConfig: inlineRouteConfig},
3: {InlineRouteConfig: inlineRouteConfig},
1: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
2: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
3: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
},
@ -1781,7 +1903,10 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
},
},
},
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
def: &FilterChain{
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
{
@ -1855,7 +1980,10 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
srcPrefixMap: map[string]*sourcePrefixEntry{
unspecifiedPrefixMapKey: {
srcPortMap: map[int]*FilterChain{
0: {InlineRouteConfig: inlineRouteConfig},
0: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
},
@ -1869,7 +1997,10 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
srcPrefixMap: map[string]*sourcePrefixEntry{
unspecifiedPrefixMapKey: {
srcPortMap: map[int]*FilterChain{
0: {InlineRouteConfig: inlineRouteConfig},
0: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
},
@ -1883,7 +2014,10 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
srcPrefixMap: map[string]*sourcePrefixEntry{
unspecifiedPrefixMapKey: {
srcPortMap: map[int]*FilterChain{
0: {InlineRouteConfig: inlineRouteConfig},
0: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
},
@ -1903,7 +2037,10 @@ func TestNewFilterChainImpl_Success_AllCombinations(t *testing.T) {
srcTypeArr: [3]*sourcePrefixes{},
},
},
def: &FilterChain{InlineRouteConfig: inlineRouteConfig},
def: &FilterChain{
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
}
@ -2178,6 +2315,7 @@ func TestLookup_Successes(t *testing.T) {
wantFC: &FilterChain{
SecurityCfg: &SecurityConfig{IdentityInstanceName: "default"},
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
{
@ -2192,6 +2330,7 @@ func TestLookup_Successes(t *testing.T) {
wantFC: &FilterChain{
SecurityCfg: &SecurityConfig{IdentityInstanceName: "unspecified-dest-and-source-prefix"},
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
{
@ -2206,6 +2345,7 @@ func TestLookup_Successes(t *testing.T) {
wantFC: &FilterChain{
SecurityCfg: &SecurityConfig{IdentityInstanceName: "wildcard-prefixes-v4"},
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
{
@ -2220,6 +2360,7 @@ func TestLookup_Successes(t *testing.T) {
wantFC: &FilterChain{
SecurityCfg: &SecurityConfig{IdentityInstanceName: "wildcard-source-prefix-v6"},
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
{
@ -2234,6 +2375,7 @@ func TestLookup_Successes(t *testing.T) {
wantFC: &FilterChain{
SecurityCfg: &SecurityConfig{IdentityInstanceName: "specific-destination-prefix-unspecified-source-type"},
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
{
@ -2248,6 +2390,7 @@ func TestLookup_Successes(t *testing.T) {
wantFC: &FilterChain{
SecurityCfg: &SecurityConfig{IdentityInstanceName: "specific-destination-prefix-specific-source-type"},
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
{
@ -2262,6 +2405,7 @@ func TestLookup_Successes(t *testing.T) {
wantFC: &FilterChain{
SecurityCfg: &SecurityConfig{IdentityInstanceName: "specific-destination-prefix-specific-source-type-specific-source-prefix"},
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
{
@ -2276,6 +2420,7 @@ func TestLookup_Successes(t *testing.T) {
wantFC: &FilterChain{
SecurityCfg: &SecurityConfig{IdentityInstanceName: "specific-destination-prefix-specific-source-type-specific-source-prefix-specific-source-port"},
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
}

View File

@ -33,6 +33,8 @@ import (
"google.golang.org/grpc/internal/testutils"
"google.golang.org/grpc/xds/internal/httpfilter"
_ "google.golang.org/grpc/xds/internal/httpfilter/router"
"google.golang.org/grpc/xds/internal/testutils/e2e"
"google.golang.org/grpc/xds/internal/version"
v2xdspb "github.com/envoyproxy/go-control-plane/envoy/api/v2"
@ -139,6 +141,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) {
ClusterSpecifier: &v3routepb.RouteAction_Cluster{Cluster: clusterName},
}}}}}}},
},
HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter},
CommonHttpProtocolOptions: &v3corepb.HttpProtocolOptions{
MaxStreamDuration: durationpb.New(time.Second),
},
@ -146,6 +149,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) {
},
})
v3LisWithFilters = func(fs ...*v3httppb.HttpFilter) *anypb.Any {
fs = append(fs, emptyRouterFilter)
return testutils.MarshalAny(&v3listenerpb.Listener{
Name: v3LDSTarget,
ApiListener: &v3listenerpb.ApiListener{
@ -290,24 +294,52 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) {
name: "v3 with no filters",
resources: []*anypb.Any{v3LisWithFilters()},
wantUpdate: map[string]ListenerUpdate{
v3LDSTarget: {RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, Raw: v3LisWithFilters()},
v3LDSTarget: {RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, HTTPFilters: routerFilterList, Raw: v3LisWithFilters()},
},
wantMD: UpdateMetadata{
Status: ServiceStatusACKed,
Version: testVersion,
},
},
{
name: "v3 no terminal filter",
resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{
Name: v3LDSTarget,
ApiListener: &v3listenerpb.ApiListener{
ApiListener: testutils.MarshalAny(
&v3httppb.HttpConnectionManager{
RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{
Rds: &v3httppb.Rds{
ConfigSource: &v3corepb.ConfigSource{
ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{Ads: &v3corepb.AggregatedConfigSource{}},
},
RouteConfigName: v3RouteConfigName,
},
},
CommonHttpProtocolOptions: &v3corepb.HttpProtocolOptions{
MaxStreamDuration: durationpb.New(time.Second),
},
}),
},
})},
wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}},
wantMD: errMD,
wantErr: true,
},
{
name: "v3 with custom filter",
resources: []*anypb.Any{v3LisWithFilters(customFilter)},
wantUpdate: map[string]ListenerUpdate{
v3LDSTarget: {
RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second,
HTTPFilters: []HTTPFilter{{
Name: "customFilter",
Filter: httpFilter{},
Config: filterConfig{Cfg: customFilterConfig},
}},
HTTPFilters: []HTTPFilter{
{
Name: "customFilter",
Filter: httpFilter{},
Config: filterConfig{Cfg: customFilterConfig},
},
routerFilter,
},
Raw: v3LisWithFilters(customFilter),
},
},
@ -322,11 +354,14 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) {
wantUpdate: map[string]ListenerUpdate{
v3LDSTarget: {
RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second,
HTTPFilters: []HTTPFilter{{
Name: "customFilter",
Filter: httpFilter{},
Config: filterConfig{Cfg: customFilterTypedStructConfig},
}},
HTTPFilters: []HTTPFilter{
{
Name: "customFilter",
Filter: httpFilter{},
Config: filterConfig{Cfg: customFilterTypedStructConfig},
},
routerFilter,
},
Raw: v3LisWithFilters(typedStructFilter),
},
},
@ -341,11 +376,14 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) {
wantUpdate: map[string]ListenerUpdate{
v3LDSTarget: {
RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second,
HTTPFilters: []HTTPFilter{{
Name: "customFilter",
Filter: httpFilter{},
Config: filterConfig{Cfg: customFilterConfig},
}},
HTTPFilters: []HTTPFilter{
{
Name: "customFilter",
Filter: httpFilter{},
Config: filterConfig{Cfg: customFilterConfig},
},
routerFilter,
},
Raw: v3LisWithFilters(customOptionalFilter),
},
},
@ -375,7 +413,9 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) {
Name: "customFilter2",
Filter: httpFilter{},
Config: filterConfig{Cfg: customFilterConfig},
}},
},
routerFilter,
},
Raw: v3LisWithFilters(customFilter, customFilter2),
},
},
@ -399,6 +439,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) {
RouteConfigName: v3RouteConfigName,
MaxStreamDuration: time.Second,
Raw: v3LisWithFilters(serverOnlyOptionalCustomFilter),
HTTPFilters: routerFilterList,
},
},
wantMD: UpdateMetadata{
@ -412,11 +453,13 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) {
wantUpdate: map[string]ListenerUpdate{
v3LDSTarget: {
RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second,
HTTPFilters: []HTTPFilter{{
Name: "clientOnlyCustomFilter",
Filter: clientOnlyHTTPFilter{},
Config: filterConfig{Cfg: clientOnlyCustomFilterConfig},
}},
HTTPFilters: []HTTPFilter{
{
Name: "clientOnlyCustomFilter",
Filter: clientOnlyHTTPFilter{},
Config: filterConfig{Cfg: clientOnlyCustomFilterConfig},
},
routerFilter},
Raw: v3LisWithFilters(clientOnlyCustomFilter),
},
},
@ -453,6 +496,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) {
v3LDSTarget: {
RouteConfigName: v3RouteConfigName,
MaxStreamDuration: time.Second,
HTTPFilters: routerFilterList,
Raw: v3LisWithFilters(unknownOptionalFilter),
},
},
@ -476,7 +520,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) {
name: "v3 listener resource",
resources: []*anypb.Any{v3LisWithFilters()},
wantUpdate: map[string]ListenerUpdate{
v3LDSTarget: {RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, Raw: v3LisWithFilters()},
v3LDSTarget: {RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, HTTPFilters: routerFilterList, Raw: v3LisWithFilters()},
},
wantMD: UpdateMetadata{
Status: ServiceStatusACKed,
@ -495,6 +539,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) {
}}},
MaxStreamDuration: time.Second,
Raw: v3LisWithInlineRoute,
HTTPFilters: routerFilterList,
},
},
wantMD: UpdateMetadata{
@ -507,7 +552,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) {
resources: []*anypb.Any{v2Lis, v3LisWithFilters()},
wantUpdate: map[string]ListenerUpdate{
v2LDSTarget: {RouteConfigName: v2RouteConfigName, Raw: v2Lis},
v3LDSTarget: {RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, Raw: v3LisWithFilters()},
v3LDSTarget: {RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, Raw: v3LisWithFilters(), HTTPFilters: routerFilterList},
},
wantMD: UpdateMetadata{
Status: ServiceStatusACKed,
@ -530,7 +575,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) {
},
wantUpdate: map[string]ListenerUpdate{
v2LDSTarget: {RouteConfigName: v2RouteConfigName, Raw: v2Lis},
v3LDSTarget: {RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, Raw: v3LisWithFilters()},
v3LDSTarget: {RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, Raw: v3LisWithFilters(), HTTPFilters: routerFilterList},
"bad": {},
},
wantMD: errMD,
@ -561,6 +606,10 @@ func (s) TestUnmarshalListener_ServerSide(t *testing.T) {
)
var (
serverOnlyCustomFilter = &v3httppb.HttpFilter{
Name: "serverOnlyCustomFilter",
ConfigType: &v3httppb.HttpFilter_TypedConfig{TypedConfig: serverOnlyCustomFilterConfig},
}
routeConfig = &v3routepb.RouteConfiguration{
Name: "routeName",
VirtualHosts: []*v3routepb.VirtualHost{{
@ -584,6 +633,7 @@ func (s) TestUnmarshalListener_ServerSide(t *testing.T) {
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
RouteConfig: routeConfig,
},
HttpFilters: []*v3httppb.HttpFilter{e2e.RouterHTTPFilter},
}),
},
},
@ -827,9 +877,38 @@ func (s) TestUnmarshalListener_ServerSide(t *testing.T) {
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
RouteConfig: routeConfig,
},
HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter},
}),
},
},
{
Name: "name",
ConfigType: &v3listenerpb.Filter_TypedConfig{
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
RouteConfig: routeConfig,
},
HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter},
}),
},
},
},
},
},
})},
wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}},
wantMD: errMD,
wantErr: "duplicate filter name",
},
{
name: "no terminal filter",
resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{
Name: v3LDSTarget,
Address: localSocketAddress,
FilterChains: []*v3listenerpb.FilterChain{
{
Name: "filter-chain-1",
Filters: []*v3listenerpb.Filter{
{
Name: "name",
ConfigType: &v3listenerpb.Filter_TypedConfig{
@ -846,7 +925,63 @@ func (s) TestUnmarshalListener_ServerSide(t *testing.T) {
})},
wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}},
wantMD: errMD,
wantErr: "duplicate filter name",
wantErr: "http filters list is empty",
},
{
name: "terminal filter not last",
resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{
Name: v3LDSTarget,
Address: localSocketAddress,
FilterChains: []*v3listenerpb.FilterChain{
{
Name: "filter-chain-1",
Filters: []*v3listenerpb.Filter{
{
Name: "name",
ConfigType: &v3listenerpb.Filter_TypedConfig{
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
RouteConfig: routeConfig,
},
HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter, serverOnlyCustomFilter},
}),
},
},
},
},
},
})},
wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}},
wantMD: errMD,
wantErr: "is a terminal filter but it is not last in the filter chain",
},
{
name: "last not terminal filter",
resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{
Name: v3LDSTarget,
Address: localSocketAddress,
FilterChains: []*v3listenerpb.FilterChain{
{
Name: "filter-chain-1",
Filters: []*v3listenerpb.Filter{
{
Name: "name",
ConfigType: &v3listenerpb.Filter_TypedConfig{
TypedConfig: testutils.MarshalAny(&v3httppb.HttpConnectionManager{
RouteSpecifier: &v3httppb.HttpConnectionManager_RouteConfig{
RouteConfig: routeConfig,
},
HttpFilters: []*v3httppb.HttpFilter{serverOnlyCustomFilter},
}),
},
},
},
},
},
})},
wantUpdate: map[string]ListenerUpdate{v3LDSTarget: {}},
wantMD: errMD,
wantErr: "is not a terminal filter",
},
{
name: "unsupported oneof in typed config of http filter",
@ -1076,7 +1211,10 @@ func (s) TestUnmarshalListener_ServerSide(t *testing.T) {
srcPrefixMap: map[string]*sourcePrefixEntry{
unspecifiedPrefixMapKey: {
srcPortMap: map[int]*FilterChain{
0: {InlineRouteConfig: inlineRouteConfig},
0: {
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
},
@ -1170,6 +1308,7 @@ func (s) TestUnmarshalListener_ServerSide(t *testing.T) {
IdentityCertName: "identityCertName",
},
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
@ -1184,6 +1323,7 @@ func (s) TestUnmarshalListener_ServerSide(t *testing.T) {
IdentityCertName: "defaultIdentityCertName",
},
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
@ -1220,6 +1360,7 @@ func (s) TestUnmarshalListener_ServerSide(t *testing.T) {
RequireClientCert: true,
},
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
@ -1237,6 +1378,7 @@ func (s) TestUnmarshalListener_ServerSide(t *testing.T) {
RequireClientCert: true,
},
InlineRouteConfig: inlineRouteConfig,
HTTPFilters: routerFilterList,
},
},
},
@ -1291,6 +1433,10 @@ func (httpFilter) ParseFilterConfigOverride(override proto.Message) (httpfilter.
return filterConfig{Override: override}, nil
}
func (httpFilter) IsTerminal() bool {
return false
}
// errHTTPFilter returns errors no matter what is passed to ParseFilterConfig.
type errHTTPFilter struct {
httpfilter.ClientInterceptorBuilder
@ -1306,6 +1452,10 @@ func (errHTTPFilter) ParseFilterConfigOverride(override proto.Message) (httpfilt
return nil, fmt.Errorf("error from ParseFilterConfigOverride")
}
func (errHTTPFilter) IsTerminal() bool {
return false
}
func init() {
httpfilter.Register(httpFilter{})
httpfilter.Register(errHTTPFilter{})
@ -1328,6 +1478,10 @@ func (serverOnlyHTTPFilter) ParseFilterConfigOverride(override proto.Message) (h
return filterConfig{Override: override}, nil
}
func (serverOnlyHTTPFilter) IsTerminal() bool {
return false
}
// clientOnlyHTTPFilter does not implement ServerInterceptorBuilder
type clientOnlyHTTPFilter struct {
httpfilter.ClientInterceptorBuilder
@ -1343,6 +1497,10 @@ func (clientOnlyHTTPFilter) ParseFilterConfigOverride(override proto.Message) (h
return filterConfig{Override: override}, nil
}
func (clientOnlyHTTPFilter) IsTerminal() bool {
return false
}
var customFilterConfig = &anypb.Any{
TypeUrl: "custom.filter",
Value: []byte{1, 2, 3},

View File

@ -244,6 +244,20 @@ func processHTTPFilters(filters []*v3httppb.HttpFilter, server bool) ([]HTTPFilt
// Save name/config
ret = append(ret, HTTPFilter{Name: name, Filter: httpFilter, Config: config})
}
// "Validation will fail if a terminal filter is not the last filter in the
// chain or if a non-terminal filter is the last filter in the chain." - A39
if len(ret) == 0 {
return nil, fmt.Errorf("http filters list is empty")
}
var i int
for ; i < len(ret)-1; i++ {
if ret[i].Filter.IsTerminal() {
return nil, fmt.Errorf("http filter %q is a terminal filter but it is not last in the filter chain", ret[i].Name)
}
}
if !ret[i].Filter.IsTerminal() {
return nil, fmt.Errorf("http filter %q is not a terminal filter", ret[len(ret)-1].Name)
}
return ret, nil
}

View File

@ -40,7 +40,9 @@ import (
"google.golang.org/grpc/credentials/xds"
"google.golang.org/grpc/internal/grpctest"
"google.golang.org/grpc/internal/testutils"
_ "google.golang.org/grpc/xds/internal/httpfilter/router"
xdstestutils "google.golang.org/grpc/xds/internal/testutils"
"google.golang.org/grpc/xds/internal/testutils/e2e"
"google.golang.org/grpc/xds/internal/testutils/fakeclient"
"google.golang.org/grpc/xds/internal/xdsclient"
"google.golang.org/grpc/xds/internal/xdsclient/bootstrap"
@ -105,6 +107,7 @@ var listenerWithFilterChains = &v3listenerpb.Listener{
Action: &v3routepb.Route_NonForwardingAction{},
}}}}},
},
HttpFilters: []*v3httppb.HttpFilter{e2e.RouterHTTPFilter},
}),
},
},
@ -769,6 +772,7 @@ func (s) TestHandleListenerUpdate_NoXDSCreds(t *testing.T) {
Action: &v3routepb.Route_NonForwardingAction{},
}}}}},
},
HttpFilters: []*v3httppb.HttpFilter{e2e.RouterHTTPFilter},
}),
},
},