Skip to content

Commit cd6c611

Browse files
committed
add support for keep_matching
1 parent 603d4fe commit cd6c611

9 files changed

Lines changed: 195 additions & 205 deletions

File tree

xds/src/main/java/io/grpc/xds/CompositeFilter.java

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -310,17 +310,22 @@ public <ReqT, RespT> io.grpc.ServerCall.Listener<ReqT> interceptCall(
310310
UnifiedMatcher.MatchingData data = new MatchingDataImpl(headers, null,
311311
call.getAttributes());
312312

313-
FilterDelegate delegate = matcher.match(data);
314-
if (delegate != null && delegate.shouldExecute()) {
313+
List<FilterDelegate> delegates = matcher.match(data);
314+
if (delegates != null && !delegates.isEmpty()) {
315315
List<ServerInterceptor> interceptors = new ArrayList<>();
316316
final List<Filter> filters = new ArrayList<>();
317317
try {
318-
for (DelegateEntry entry : delegate.delegates) {
319-
Filter filter = entry.provider.newInstance("composite_child");
320-
filters.add(filter);
321-
ServerInterceptor interceptor = filter.buildServerInterceptor(entry.config, null);
322-
if (interceptor != null) {
323-
interceptors.add(interceptor);
318+
for (FilterDelegate delegate : delegates) {
319+
if (!delegate.shouldExecute()) {
320+
continue;
321+
}
322+
for (DelegateEntry entry : delegate.delegates) {
323+
Filter filter = entry.provider.newInstance("composite_child");
324+
filters.add(filter);
325+
ServerInterceptor interceptor = filter.buildServerInterceptor(entry.config, null);
326+
if (interceptor != null) {
327+
interceptors.add(interceptor);
328+
}
324329
}
325330
}
326331
} catch (Throwable t) {
@@ -496,19 +501,24 @@ public void start(Listener<RespT> responseListener, Metadata headers) {
496501
started = true;
497502

498503
UnifiedMatcher.MatchingData data = new MatchingDataImpl(headers, callOptions);
499-
FilterDelegate filterDelegate = matcher.match(data);
504+
List<FilterDelegate> filterDelegates = matcher.match(data);
500505

501-
if (filterDelegate != null && filterDelegate.shouldExecute()) {
506+
if (filterDelegates != null && !filterDelegates.isEmpty()) {
502507
List<ClientInterceptor> interceptors = new ArrayList<>();
503508
List<Filter> filters = new ArrayList<>();
504509
try {
505-
for (DelegateEntry entry : filterDelegate.delegates) {
506-
Filter filter = entry.provider.newInstance("composite_child");
507-
filters.add(filter);
508-
ClientInterceptor interceptor = filter.buildClientInterceptor(entry.config, null,
509-
scheduler);
510-
if (interceptor != null) {
511-
interceptors.add(interceptor);
510+
for (FilterDelegate filterDelegate : filterDelegates) {
511+
if (!filterDelegate.shouldExecute()) {
512+
continue;
513+
}
514+
for (DelegateEntry entry : filterDelegate.delegates) {
515+
Filter filter = entry.provider.newInstance("composite_child");
516+
filters.add(filter);
517+
ClientInterceptor interceptor = filter.buildClientInterceptor(entry.config, null,
518+
scheduler);
519+
if (interceptor != null) {
520+
interceptors.add(interceptor);
521+
}
512522
}
513523
}
514524
} catch (Throwable t) {

xds/src/main/java/io/grpc/xds/FaultFilter.java

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -106,24 +106,15 @@ public FaultFilter newInstance(String name) {
106106
@Override
107107
public ConfigOrError<FaultConfig> parseFilterConfig(Message rawProtoMessage) {
108108
HTTPFault httpFaultProto;
109-
if (rawProtoMessage instanceof Any) {
110-
try {
111-
httpFaultProto = ((Any) rawProtoMessage).unpack(HTTPFault.class);
112-
} catch (InvalidProtocolBufferException e) {
113-
return ConfigOrError.fromError("Invalid proto: " + e);
114-
}
115-
} else if (rawProtoMessage instanceof com.google.protobuf.Struct) {
116-
try {
117-
HTTPFault.Builder builder = HTTPFault.newBuilder();
118-
com.google.protobuf.util.JsonFormat.parser().merge(
119-
com.google.protobuf.util.JsonFormat.printer().print(rawProtoMessage), builder);
120-
httpFaultProto = builder.build();
121-
} catch (InvalidProtocolBufferException e) {
122-
return ConfigOrError.fromError("Failed to parse Struct to HTTPFault: " + e);
123-
}
124-
} else {
109+
if (!(rawProtoMessage instanceof Any)) {
125110
return ConfigOrError.fromError("Invalid config type: " + rawProtoMessage.getClass());
126111
}
112+
Any anyMessage = (Any) rawProtoMessage;
113+
try {
114+
httpFaultProto = anyMessage.unpack(HTTPFault.class);
115+
} catch (InvalidProtocolBufferException e) {
116+
return ConfigOrError.fromError("Invalid proto: " + e);
117+
}
127118
return parseHttpFault(httpFaultProto);
128119
}
129120

xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -88,24 +88,16 @@ public GcpAuthenticationFilter newInstance(String name) {
8888
@Override
8989
public ConfigOrError<GcpAuthenticationConfig> parseFilterConfig(Message rawProtoMessage) {
9090
GcpAuthnFilterConfig gcpAuthnProto;
91-
if (rawProtoMessage instanceof Any) {
92-
try {
93-
gcpAuthnProto = ((Any) rawProtoMessage).unpack(GcpAuthnFilterConfig.class);
94-
} catch (InvalidProtocolBufferException e) {
95-
return ConfigOrError.fromError("Invalid proto: " + e);
96-
}
97-
} else if (rawProtoMessage instanceof com.google.protobuf.Struct) {
98-
try {
99-
GcpAuthnFilterConfig.Builder builder = GcpAuthnFilterConfig.newBuilder();
100-
com.google.protobuf.util.JsonFormat.parser().merge(
101-
com.google.protobuf.util.JsonFormat.printer().print(rawProtoMessage), builder);
102-
gcpAuthnProto = builder.build();
103-
} catch (InvalidProtocolBufferException e) {
104-
return ConfigOrError.fromError("Failed to parse Struct to GcpAuthnFilterConfig: " + e);
105-
}
106-
} else {
91+
if (!(rawProtoMessage instanceof Any)) {
10792
return ConfigOrError.fromError("Invalid config type: " + rawProtoMessage.getClass());
10893
}
94+
Any anyMessage = (Any) rawProtoMessage;
95+
96+
try {
97+
gcpAuthnProto = anyMessage.unpack(GcpAuthnFilterConfig.class);
98+
} catch (InvalidProtocolBufferException e) {
99+
return ConfigOrError.fromError("Invalid proto: " + e);
100+
}
109101

110102
long cacheSize = 10;
111103
// Validate cache_config

xds/src/main/java/io/grpc/xds/RbacFilter.java

Lines changed: 14 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -96,48 +96,30 @@ public RbacFilter newInstance(String name) {
9696
@Override
9797
public ConfigOrError<RbacConfig> parseFilterConfig(Message rawProtoMessage) {
9898
RBAC rbacProto;
99-
if (rawProtoMessage instanceof Any) {
100-
try {
101-
rbacProto = ((Any) rawProtoMessage).unpack(RBAC.class);
102-
} catch (InvalidProtocolBufferException e) {
103-
return ConfigOrError.fromError("Invalid proto: " + e);
104-
}
105-
} else if (rawProtoMessage instanceof com.google.protobuf.Struct) {
106-
try {
107-
RBAC.Builder builder = RBAC.newBuilder();
108-
com.google.protobuf.util.JsonFormat.parser().merge(
109-
com.google.protobuf.util.JsonFormat.printer().print(rawProtoMessage), builder);
110-
rbacProto = builder.build();
111-
} catch (InvalidProtocolBufferException e) {
112-
return ConfigOrError.fromError("Failed to parse Struct to RBAC: " + e);
113-
}
114-
} else {
99+
if (!(rawProtoMessage instanceof Any)) {
115100
return ConfigOrError.fromError("Invalid config type: " + rawProtoMessage.getClass());
116101
}
102+
Any anyMessage = (Any) rawProtoMessage;
103+
try {
104+
rbacProto = anyMessage.unpack(RBAC.class);
105+
} catch (InvalidProtocolBufferException e) {
106+
return ConfigOrError.fromError("Invalid proto: " + e);
107+
}
117108
return parseRbacConfig(rbacProto);
118109
}
119110

120111
@Override
121112
public ConfigOrError<RbacConfig> parseFilterConfigOverride(Message rawProtoMessage) {
122113
RBACPerRoute rbacPerRoute;
123-
if (rawProtoMessage instanceof Any) {
124-
try {
125-
rbacPerRoute = ((Any) rawProtoMessage).unpack(RBACPerRoute.class);
126-
} catch (InvalidProtocolBufferException e) {
127-
return ConfigOrError.fromError("Invalid proto: " + e);
128-
}
129-
} else if (rawProtoMessage instanceof com.google.protobuf.Struct) {
130-
try {
131-
RBACPerRoute.Builder builder = RBACPerRoute.newBuilder();
132-
com.google.protobuf.util.JsonFormat.parser().merge(
133-
com.google.protobuf.util.JsonFormat.printer().print(rawProtoMessage), builder);
134-
rbacPerRoute = builder.build();
135-
} catch (InvalidProtocolBufferException e) {
136-
return ConfigOrError.fromError("Failed to parse Struct to RBACPerRoute: " + e);
137-
}
138-
} else {
114+
if (!(rawProtoMessage instanceof Any)) {
139115
return ConfigOrError.fromError("Invalid config type: " + rawProtoMessage.getClass());
140116
}
117+
Any anyMessage = (Any) rawProtoMessage;
118+
try {
119+
rbacPerRoute = anyMessage.unpack(RBACPerRoute.class);
120+
} catch (InvalidProtocolBufferException e) {
121+
return ConfigOrError.fromError("Invalid proto: " + e);
122+
}
141123
if (rbacPerRoute.hasRbac()) {
142124
return parseRbacConfig(rbacPerRoute.getRbac());
143125
} else {

xds/src/main/java/io/grpc/xds/XdsListenerResource.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,6 @@ static io.grpc.xds.HttpConnectionManager parseHttpConnectionManager(
513513
}
514514

515515
// Parse http filters.
516-
// todo: AgraVator are we changing the assumption here ??
517516
if (proto.getHttpFiltersList().isEmpty()) {
518517
throw new ResourceInvalidException("Missing HttpFilter in HttpConnectionManager.");
519518
}
@@ -583,7 +582,6 @@ private static boolean isTerminalFilter(Filter.FilterConfig filterConfig) {
583582
static StructOrError<Filter.FilterConfig> parseHttpFilter(
584583
io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpFilter
585584
httpFilter, FilterRegistry filterRegistry, boolean isForClient) {
586-
// todo: AgraVator do we need to change anything here for composite filter ??
587585
String filterName = httpFilter.getName();
588586
boolean isOptional = httpFilter.getIsOptional();
589587
if (!httpFilter.hasTypedConfig()) {

xds/src/main/java/io/grpc/xds/internal/MatcherParser.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ public static Matchers.StringMatcher parseStringMatcher(
9191
Pattern.compile(proto.getSafeRegex().getRegex()));
9292
case CONTAINS:
9393
return Matchers.StringMatcher.forContains(proto.getContains());
94+
case CUSTOM:
95+
throw new IllegalArgumentException("custom string matcher is not supported");
9496
case MATCHPATTERN_NOT_SET:
9597
default:
9698
throw new IllegalArgumentException(
@@ -113,6 +115,8 @@ public static Matchers.StringMatcher parseStringMatcher(
113115
Pattern.compile(proto.getSafeRegex().getRegex()));
114116
case CONTAINS:
115117
return Matchers.StringMatcher.forContains(proto.getContains());
118+
case CUSTOM:
119+
throw new IllegalArgumentException("custom string matcher is not supported");
116120
case MATCHPATTERN_NOT_SET:
117121
default:
118122
throw new IllegalArgumentException(

xds/src/main/java/io/grpc/xds/internal/UnifiedMatcher.java

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,19 @@ public interface ActionParser<T> {
5454

5555
/**
5656
* Evaluates the matcher against the provided data.
57-
* Returns the action config if matched, null otherwise.
57+
* Returns the action configs if matched, null otherwise.
5858
*/
5959
@Nullable
60-
public abstract T match(MatchingData data);
60+
public abstract List<T> match(MatchingData data);
6161

6262
public static <T> UnifiedMatcher<T> create(Matcher proto, ActionParser<T> parser) {
6363
return createRecursive(proto, parser, 0);
6464
}
6565

6666
private static <T> UnifiedMatcher<T> createRecursive(Matcher proto, ActionParser<T> parser,
6767
int depth) {
68-
if (depth > 8) {
69-
throw new IllegalArgumentException("Maximum recursion depth of 8 exceeded");
68+
if (depth > 16) {
69+
throw new IllegalArgumentException("Maximum recursion depth of 16 exceeded");
7070
}
7171
if (proto.hasMatcherList()) {
7272
return new MatcherList<>(proto.getMatcherList(), parser, depth);
@@ -91,7 +91,7 @@ private static class OnNoMatch<T> extends UnifiedMatcher<T> {
9191
}
9292

9393
@Override
94-
public T match(MatchingData data) {
94+
public List<T> match(MatchingData data) {
9595
return delegate != null ? delegate.match(data) : null;
9696
}
9797
}
@@ -104,8 +104,8 @@ private static class ActionMatcher<T> extends UnifiedMatcher<T> {
104104
}
105105

106106
@Override
107-
public T match(MatchingData data) {
108-
return action;
107+
public List<T> match(MatchingData data) {
108+
return ImmutableList.of(action);
109109
}
110110
}
111111

@@ -121,24 +121,30 @@ private static class MatcherList<T> extends UnifiedMatcher<T> {
121121
}
122122

123123
@Override
124-
public T match(MatchingData data) {
124+
public List<T> match(MatchingData data) {
125+
List<T> results = new ArrayList<>();
125126
for (FieldMatcher<T> matcher : fieldMatchers) {
126-
T result = matcher.match(data);
127-
if (result != null) {
128-
return result;
127+
List<T> result = matcher.match(data);
128+
if (result != null && !result.isEmpty()) {
129+
results.addAll(result);
130+
if (!matcher.keepMatching) {
131+
break;
132+
}
129133
}
130134
}
131-
return null;
135+
return results.isEmpty() ? null : ImmutableList.copyOf(results);
132136
}
133137
}
134138

135139
private static class FieldMatcher<T> {
136140
private final UnifiedPredicate predicate;
137141
private final UnifiedMatcher<T> onMatch;
142+
private final boolean keepMatching;
138143

139144
FieldMatcher(Matcher.MatcherList.FieldMatcher proto, ActionParser<T> parser, int depth) {
140145
this.predicate = UnifiedPredicate.create(proto.getPredicate());
141146
Matcher.OnMatch onMatchProto = proto.getOnMatch();
147+
this.keepMatching = onMatchProto.getKeepMatching();
142148
if (onMatchProto.hasAction()) {
143149
this.onMatch = new ActionMatcher<>(onMatchProto.getAction(), parser);
144150
} else if (onMatchProto.hasMatcher()) {
@@ -149,7 +155,7 @@ private static class FieldMatcher<T> {
149155
}
150156

151157
@Nullable
152-
T match(MatchingData data) {
158+
List<T> match(MatchingData data) {
153159
if (predicate.matches(data)) {
154160
return onMatch.match(data);
155161
}
@@ -164,6 +170,9 @@ private static class MatcherTree<T> extends UnifiedMatcher<T> {
164170

165171
MatcherTree(Matcher.MatcherTree proto, ActionParser<T> parser, int depth) {
166172
this.input = new MatcherInput(proto.getInput());
173+
if (proto.hasCustomMatch()) {
174+
throw new IllegalArgumentException("custom_match is not supported in MatcherTree");
175+
}
167176
this.exactMap = parseMap(proto.getExactMatchMap().getMapMap(), parser, depth);
168177
this.prefixMap = parseMap(proto.getPrefixMatchMap().getMapMap(), parser, depth);
169178
}
@@ -183,7 +192,7 @@ private Map<String, UnifiedMatcher<T>> parseMap(
183192
}
184193

185194
@Override
186-
public T match(MatchingData data) {
195+
public List<T> match(MatchingData data) {
187196
String value = input.get(data);
188197
if (value == null) {
189198
return null;
@@ -225,7 +234,7 @@ String get(MatchingData data) {
225234

226235
private static class AlwaysFalseMatcher<T> extends UnifiedMatcher<T> {
227236
@Override
228-
public T match(MatchingData data) {
237+
public List<T> match(MatchingData data) {
229238
return null;
230239
}
231240
}
@@ -260,6 +269,9 @@ private static class SinglePredicate extends UnifiedPredicate {
260269

261270
SinglePredicate(Predicate.SinglePredicate proto) {
262271
this.input = new MatcherInput(proto.getInput());
272+
if (proto.hasCustomMatch()) {
273+
throw new IllegalArgumentException("custom_match is not supported in SinglePredicate");
274+
}
263275
if (proto.hasValueMatch()) {
264276
this.stringMatcher = MatcherParser.parseStringMatcher(proto.getValueMatch());
265277
} else {

0 commit comments

Comments
 (0)