1 /*
2  * Copyright 2021 The gRPC Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package io.grpc.xds;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static io.grpc.xds.XdsServerWrapper.ATTR_SERVER_ROUTING_CONFIG;
21 import static io.grpc.xds.internal.security.SecurityProtocolNegotiators.ATTR_SERVER_SSL_CONTEXT_PROVIDER_SUPPLIER;
22 import static org.junit.Assert.fail;
23 import static org.mockito.Mockito.mock;
24 import static org.mockito.Mockito.when;
25 
26 import com.google.common.collect.ImmutableList;
27 import com.google.common.collect.ImmutableMap;
28 import com.google.common.util.concurrent.SettableFuture;
29 import io.grpc.ServerInterceptor;
30 import io.grpc.internal.TestUtils.NoopChannelLogger;
31 import io.grpc.netty.GrpcHttp2ConnectionHandler;
32 import io.grpc.netty.InternalProtocolNegotiationEvent;
33 import io.grpc.netty.InternalProtocolNegotiator.ProtocolNegotiator;
34 import io.grpc.netty.ProtocolNegotiationEvent;
35 import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext;
36 import io.grpc.xds.EnvoyServerProtoData.FilterChain;
37 import io.grpc.xds.Filter.FilterConfig;
38 import io.grpc.xds.Filter.NamedFilterConfig;
39 import io.grpc.xds.FilterChainMatchingProtocolNegotiators.FilterChainMatchingHandler;
40 import io.grpc.xds.FilterChainMatchingProtocolNegotiators.FilterChainMatchingHandler.FilterChainSelector;
41 import io.grpc.xds.VirtualHost.Route;
42 import io.grpc.xds.XdsServerWrapper.ServerRoutingConfig;
43 import io.grpc.xds.internal.security.CommonTlsContextTestsUtil;
44 import io.grpc.xds.internal.security.SslContextProviderSupplier;
45 import io.netty.channel.ChannelHandler;
46 import io.netty.channel.ChannelHandlerContext;
47 import io.netty.channel.ChannelInboundHandlerAdapter;
48 import io.netty.channel.ChannelPipeline;
49 import io.netty.channel.ChannelPromise;
50 import io.netty.channel.embedded.EmbeddedChannel;
51 import io.netty.handler.codec.http2.DefaultHttp2Connection;
52 import io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder;
53 import io.netty.handler.codec.http2.DefaultHttp2ConnectionEncoder;
54 import io.netty.handler.codec.http2.DefaultHttp2FrameReader;
55 import io.netty.handler.codec.http2.DefaultHttp2FrameWriter;
56 import io.netty.handler.codec.http2.Http2ConnectionDecoder;
57 import io.netty.handler.codec.http2.Http2ConnectionEncoder;
58 import io.netty.handler.codec.http2.Http2Settings;
59 import java.net.InetSocketAddress;
60 import java.net.SocketAddress;
61 import java.net.UnknownHostException;
62 import java.util.ArrayList;
63 import java.util.Collections;
64 import java.util.HashMap;
65 import java.util.Map;
66 import java.util.concurrent.atomic.AtomicReference;
67 import org.junit.After;
68 import org.junit.Rule;
69 import org.junit.Test;
70 import org.junit.runner.RunWith;
71 import org.junit.runners.JUnit4;
72 import org.mockito.Mock;
73 import org.mockito.junit.MockitoJUnit;
74 import org.mockito.junit.MockitoRule;
75 
76 @RunWith(JUnit4.class)
77 public class FilterChainMatchingProtocolNegotiatorsTest {
78   @Rule
79   public final MockitoRule mocks = MockitoJUnit.rule();
80 
81   private final GrpcHttp2ConnectionHandler grpcHandler =
82           FakeGrpcHttp2ConnectionHandler.newHandler();
83   @Mock private TlsContextManager tlsContextManager;
84   private ProtocolNegotiationEvent event = InternalProtocolNegotiationEvent.getDefault();
85   private ChannelPipeline pipeline;
86   private EmbeddedChannel channel;
87   private ChannelHandlerContext channelHandlerCtx;
88   @Mock
89   private ProtocolNegotiator mockDelegate;
90   private FilterChainSelectorManager selectorManager = new FilterChainSelectorManager();
91   private static final EnvoyServerProtoData.FilterChainMatch DEFAULT_FILTER_CHAIN_MATCH =
92       EnvoyServerProtoData.FilterChainMatch.create(
93           0,
94           ImmutableList.of(),
95           ImmutableList.of(),
96           ImmutableList.of(),
97           EnvoyServerProtoData.ConnectionSourceType.ANY,
98           ImmutableList.of(),
99           ImmutableList.of(),
100           "");
101   private static final HttpConnectionManager HTTP_CONNECTION_MANAGER = createRds("routing-config");
102   private static final String LOCAL_IP = "10.1.2.3";  // dest
103   private static final String REMOTE_IP = "10.4.2.3"; // source
104   private static final int PORT = 7000;
105   private final AtomicReference<ServerRoutingConfig> noopConfig = new AtomicReference<>(
106       ServerRoutingConfig.create(ImmutableList.<VirtualHost>of(),
107           ImmutableMap.<Route, ServerInterceptor>of()));
108   final SettableFuture<SslContextProviderSupplier> sslSet = SettableFuture.create();
109   final SettableFuture<AtomicReference<ServerRoutingConfig>> routingSettable =
110       SettableFuture.create();
111 
112   @After
113   @SuppressWarnings("FutureReturnValueIgnored")
tearDown()114   public void tearDown() {
115     if (channel.isActive()) {
116       channel.close();
117       channel.runPendingTasks();
118     }
119     assertThat(selectorManager.getRegisterCount()).isEqualTo(0);
120   }
121 
122   @Test
nofilterChainMatch_defaultSslContext()123   public void nofilterChainMatch_defaultSslContext() throws Exception {
124     ChannelHandler next = captureAttrHandler(sslSet, routingSettable);
125     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
126 
127     SslContextProviderSupplier defaultSsl = new SslContextProviderSupplier(createTls(),
128             tlsContextManager);
129     selectorManager.updateSelector(new FilterChainSelector(
130             new HashMap<FilterChain, AtomicReference<ServerRoutingConfig>>(),
131         defaultSsl, noopConfig));
132     FilterChainMatchingHandler filterChainMatchingHandler =
133             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
134     setupChannel("172.168.1.1", "172.168.1.2", 80, filterChainMatchingHandler);
135     ChannelHandlerContext channelHandlerCtx = pipeline.context(filterChainMatchingHandler);
136     assertThat(channelHandlerCtx).isNotNull();
137 
138     pipeline.fireUserEventTriggered(event);
139     channelHandlerCtx = pipeline.context(filterChainMatchingHandler);
140     assertThat(channelHandlerCtx).isNull();
141 
142     channel.runPendingTasks();
143     assertThat(sslSet.isDone()).isTrue();
144     assertThat(sslSet.get()).isEqualTo(defaultSsl);
145     assertThat(routingSettable.get()).isEqualTo(noopConfig);
146     channelHandlerCtx = pipeline.context(next);
147     assertThat(channelHandlerCtx).isNotNull();
148   }
149 
150   @Test
noFilterChainMatch_noDefaultSslContext()151   public void noFilterChainMatch_noDefaultSslContext() {
152     selectorManager.updateSelector(new FilterChainSelector(
153             new HashMap<FilterChain, AtomicReference<ServerRoutingConfig>>(),
154         null, new AtomicReference<ServerRoutingConfig>()));
155     FilterChainMatchingHandler filterChainMatchingHandler =
156             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
157     setupChannel("172.168.1.1", "172.168.2.2", 90, filterChainMatchingHandler);
158     channelHandlerCtx = pipeline.context(filterChainMatchingHandler);
159     assertThat(channelHandlerCtx).isNotNull();
160 
161     assertThat(channel.closeFuture().isDone()).isFalse();
162     pipeline.fireUserEventTriggered(event);
163     channel.runPendingTasks();
164     assertThat(channel.closeFuture().isDone()).isTrue();
165   }
166 
167   @Test
filterSelectorChange_drainsConnection()168   public void filterSelectorChange_drainsConnection() {
169     ChannelHandler next = new ChannelInboundHandlerAdapter();
170     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
171     selectorManager.updateSelector(new FilterChainSelector(
172             new HashMap<FilterChain, AtomicReference<ServerRoutingConfig>>(), null, noopConfig));
173     FilterChainMatchingHandler filterChainMatchingHandler =
174             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
175     setupChannel("172.168.1.1", "172.168.2.2", 90, filterChainMatchingHandler);
176     channelHandlerCtx = pipeline.context(filterChainMatchingHandler);
177     assertThat(channelHandlerCtx).isNotNull();
178 
179     pipeline.fireUserEventTriggered(event);
180     channelHandlerCtx = pipeline.context(filterChainMatchingHandler);
181     assertThat(channelHandlerCtx).isNull();
182 
183     channel.runPendingTasks();
184     channelHandlerCtx = pipeline.context(next);
185     assertThat(channelHandlerCtx).isNotNull();
186     // Force return value to Object, to avoid confusing javac of the type passed to assertThat()
187     Object msg = channel.readOutbound();
188     assertThat(msg).isNull();
189 
190     selectorManager.updateSelector(new FilterChainSelector(
191             new HashMap<FilterChain, AtomicReference<ServerRoutingConfig>>(), null, noopConfig));
192     assertThat(channel.readOutbound().getClass().getName())
193         .isEqualTo("io.grpc.netty.GracefulServerCloseCommand");
194   }
195 
196   @Test
singleFilterChainWithoutAlpn()197   public void singleFilterChainWithoutAlpn() throws Exception {
198     EnvoyServerProtoData.FilterChainMatch filterChainMatch =
199         EnvoyServerProtoData.FilterChainMatch.create(
200             0,
201             ImmutableList.of(),
202             ImmutableList.of(),
203             ImmutableList.of(),
204             EnvoyServerProtoData.ConnectionSourceType.ANY,
205             ImmutableList.of(),
206             ImmutableList.of(),
207             "");
208     EnvoyServerProtoData.DownstreamTlsContext tlsContext =
209             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
210     EnvoyServerProtoData.FilterChain filterChain = EnvoyServerProtoData.FilterChain.create(
211             "filter-chain-foo", filterChainMatch, HTTP_CONNECTION_MANAGER, tlsContext,
212             tlsContextManager);
213 
214     selectorManager.updateSelector(new FilterChainSelector(ImmutableMap.of(filterChain, noopConfig),
215             null, new AtomicReference<ServerRoutingConfig>()));
216     FilterChainMatchingHandler filterChainMatchingHandler =
217             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
218     ChannelHandler next = captureAttrHandler(sslSet, routingSettable);
219     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
220     setupChannel(LOCAL_IP, REMOTE_IP, 15000, filterChainMatchingHandler);
221     pipeline.fireUserEventTriggered(event);
222     channel.runPendingTasks();
223     assertThat(sslSet.isDone()).isTrue();
224     assertThat(sslSet.get()).isEqualTo(filterChain.sslContextProviderSupplier());
225     assertThat(routingSettable.get()).isEqualTo(noopConfig);
226     assertThat(sslSet.get().getTlsContext()).isSameInstanceAs(tlsContext);
227   }
228 
229   @Test
singleFilterChainWithAlpn()230   public void singleFilterChainWithAlpn() throws Exception {
231     EnvoyServerProtoData.FilterChainMatch filterChainMatch =
232         EnvoyServerProtoData.FilterChainMatch.create(
233             0,
234             ImmutableList.of(),
235             ImmutableList.of("managed-mtls"),
236             ImmutableList.of(),
237             EnvoyServerProtoData.ConnectionSourceType.ANY,
238             ImmutableList.of(),
239             ImmutableList.of(),
240             "");
241     EnvoyServerProtoData.DownstreamTlsContext tlsContext =
242             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
243     EnvoyServerProtoData.FilterChain filterChain = EnvoyServerProtoData.FilterChain.create(
244             "filter-chain-foo", filterChainMatch, HTTP_CONNECTION_MANAGER, tlsContext,
245             tlsContextManager);
246     EnvoyServerProtoData.DownstreamTlsContext defaultTlsContext =
247             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
248     EnvoyServerProtoData.FilterChain defaultFilterChain = EnvoyServerProtoData.FilterChain.create(
249         "filter-chain-bar", DEFAULT_FILTER_CHAIN_MATCH, HTTP_CONNECTION_MANAGER, defaultTlsContext,
250         tlsContextManager);
251     selectorManager.updateSelector(new FilterChainSelector(
252             ImmutableMap.of(filterChain, randomConfig("no-match")),
253             defaultFilterChain.sslContextProviderSupplier(), noopConfig));
254     FilterChainMatchingHandler filterChainMatchingHandler =
255             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
256 
257     ChannelHandler next = captureAttrHandler(sslSet, routingSettable);
258     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
259     setupChannel(LOCAL_IP, REMOTE_IP, 15000, filterChainMatchingHandler);
260     pipeline.fireUserEventTriggered(event);
261     channel.runPendingTasks();
262     assertThat(sslSet.get()).isEqualTo(defaultFilterChain.sslContextProviderSupplier());
263     assertThat(routingSettable.get()).isEqualTo(noopConfig);
264     assertThat(sslSet.get().getTlsContext()).isSameInstanceAs(defaultTlsContext);
265   }
266 
267   @Test
destPortFails_returnDefaultFilterChain()268   public void destPortFails_returnDefaultFilterChain() throws Exception {
269     EnvoyServerProtoData.DownstreamTlsContext tlsContextWithDestPort =
270             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
271     EnvoyServerProtoData.FilterChainMatch filterChainMatchWithDestPort =
272         EnvoyServerProtoData.FilterChainMatch.create(
273             PORT,
274             ImmutableList.of(),
275             ImmutableList.of("managed-mtls"),
276             ImmutableList.of(),
277             EnvoyServerProtoData.ConnectionSourceType.ANY,
278             ImmutableList.of(),
279             ImmutableList.of(),
280             "");
281     EnvoyServerProtoData.FilterChain filterChainWithDestPort =
282             EnvoyServerProtoData.FilterChain.create(
283                     "filter-chain-foo", filterChainMatchWithDestPort, HTTP_CONNECTION_MANAGER,
284                     tlsContextWithDestPort, tlsContextManager);
285     EnvoyServerProtoData.DownstreamTlsContext tlsContextForDefaultFilterChain =
286             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
287     EnvoyServerProtoData.FilterChain defaultFilterChain =
288             EnvoyServerProtoData.FilterChain.create(
289                     "filter-chain-bar", DEFAULT_FILTER_CHAIN_MATCH, HTTP_CONNECTION_MANAGER,
290                     tlsContextForDefaultFilterChain, tlsContextManager);
291 
292     ServerRoutingConfig routingConfig = ServerRoutingConfig.create(
293                 ImmutableList.of(createVirtualHost("virtual")),
294         ImmutableMap.<Route, ServerInterceptor>of());
295     selectorManager.updateSelector(new FilterChainSelector(
296             ImmutableMap.of(filterChainWithDestPort,
297                 new AtomicReference<ServerRoutingConfig>(routingConfig)),
298             defaultFilterChain.sslContextProviderSupplier(), noopConfig));
299 
300     FilterChainMatchingHandler filterChainMatchingHandler =
301             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
302 
303     ChannelHandler next = captureAttrHandler(sslSet, routingSettable);
304     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
305     setupChannel(LOCAL_IP, REMOTE_IP, 15000, filterChainMatchingHandler);
306     pipeline.fireUserEventTriggered(event);
307     channel.runPendingTasks();
308     assertThat(sslSet.get()).isEqualTo(defaultFilterChain.sslContextProviderSupplier());
309     assertThat(routingSettable.get()).isEqualTo(noopConfig);
310     assertThat(sslSet.get().getTlsContext())
311             .isSameInstanceAs(tlsContextForDefaultFilterChain);
312   }
313 
314   @Test
destPrefixRangeMatch()315   public void destPrefixRangeMatch() throws Exception {
316     EnvoyServerProtoData.DownstreamTlsContext tlsContextMatch =
317             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
318     EnvoyServerProtoData.FilterChainMatch filterChainMatchWithMatch =
319         EnvoyServerProtoData.FilterChainMatch.create(
320             0,
321             ImmutableList.of(EnvoyServerProtoData.CidrRange.create("10.1.2.0", 24)),
322             ImmutableList.of(),
323             ImmutableList.of(),
324             EnvoyServerProtoData.ConnectionSourceType.ANY,
325             ImmutableList.of(),
326             ImmutableList.of(),
327             "");
328     EnvoyServerProtoData.FilterChain filterChainWithMatch = EnvoyServerProtoData.FilterChain.create(
329             "filter-chain-foo", filterChainMatchWithMatch, HTTP_CONNECTION_MANAGER,
330             tlsContextMatch, tlsContextManager);
331     EnvoyServerProtoData.DownstreamTlsContext tlsContextForDefaultFilterChain =
332             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
333     EnvoyServerProtoData.FilterChain defaultFilterChain = EnvoyServerProtoData.FilterChain.create(
334             "filter-chain-bar", DEFAULT_FILTER_CHAIN_MATCH, HTTP_CONNECTION_MANAGER,
335             tlsContextForDefaultFilterChain, tlsContextManager);
336 
337     selectorManager.updateSelector(new FilterChainSelector(
338             ImmutableMap.of(filterChainWithMatch, noopConfig),
339             defaultFilterChain.sslContextProviderSupplier(), randomConfig("no-match")));
340 
341     FilterChainMatchingHandler filterChainMatchingHandler =
342             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
343 
344     ChannelHandler next = captureAttrHandler(sslSet, routingSettable);
345     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
346     setupChannel(LOCAL_IP, REMOTE_IP, 15000, filterChainMatchingHandler);
347     pipeline.fireUserEventTriggered(event);
348     channel.runPendingTasks();
349     assertThat(sslSet.get()).isEqualTo(filterChainWithMatch.sslContextProviderSupplier());
350     assertThat(routingSettable.get()).isEqualTo(noopConfig);
351     assertThat(sslSet.get().getTlsContext()).isSameInstanceAs(tlsContextMatch);
352   }
353 
354   @Test
destPrefixRangeMismatch_returnDefaultFilterChain()355   public void destPrefixRangeMismatch_returnDefaultFilterChain()
356           throws Exception {
357     EnvoyServerProtoData.DownstreamTlsContext tlsContextMismatch =
358             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
359     // 10.2.2.0/24 doesn't match LOCAL_IP
360     EnvoyServerProtoData.FilterChainMatch filterChainMatchWithMismatch =
361         EnvoyServerProtoData.FilterChainMatch.create(
362             0,
363             ImmutableList.of(EnvoyServerProtoData.CidrRange.create("10.2.2.0", 24)),
364             ImmutableList.of(),
365             ImmutableList.of(),
366             EnvoyServerProtoData.ConnectionSourceType.ANY,
367             ImmutableList.of(),
368             ImmutableList.of(),
369             "");
370     EnvoyServerProtoData.FilterChain filterChainWithMismatch =
371             EnvoyServerProtoData.FilterChain.create(
372                     "filter-chain-foo", filterChainMatchWithMismatch, HTTP_CONNECTION_MANAGER,
373                     tlsContextMismatch, tlsContextManager);
374     EnvoyServerProtoData.DownstreamTlsContext tlsContextForDefaultFilterChain =
375             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
376     EnvoyServerProtoData.FilterChain defaultFilterChain = EnvoyServerProtoData.FilterChain.create(
377             "filter-chain-bar", DEFAULT_FILTER_CHAIN_MATCH, HTTP_CONNECTION_MANAGER,
378             tlsContextForDefaultFilterChain, tlsContextManager);
379     selectorManager.updateSelector(new FilterChainSelector(
380             ImmutableMap.of(filterChainWithMismatch, randomConfig("no-match")),
381             defaultFilterChain.sslContextProviderSupplier(), noopConfig));
382 
383     FilterChainMatchingHandler filterChainMatchingHandler =
384             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
385 
386     ChannelHandler next = captureAttrHandler(sslSet, routingSettable);
387     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
388     setupChannel(LOCAL_IP, REMOTE_IP, 15000, filterChainMatchingHandler);
389     pipeline.fireUserEventTriggered(event);
390     channel.runPendingTasks();
391     assertThat(sslSet.isDone()).isTrue();
392     assertThat(sslSet.get()).isEqualTo(defaultFilterChain.sslContextProviderSupplier());
393     assertThat(routingSettable.get()).isEqualTo(noopConfig);
394     assertThat(sslSet.get().getTlsContext()).isSameInstanceAs(tlsContextForDefaultFilterChain);
395   }
396 
397   @Test
dest0LengthPrefixRange()398   public void dest0LengthPrefixRange()
399           throws Exception {
400     EnvoyServerProtoData.DownstreamTlsContext tlsContext0Length =
401             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
402     // 10.2.2.0/24 doesn't match LOCAL_IP
403     EnvoyServerProtoData.FilterChainMatch filterChainMatch0Length =
404         EnvoyServerProtoData.FilterChainMatch.create(
405             0,
406             ImmutableList.of(EnvoyServerProtoData.CidrRange.create("10.2.2.0", 0)),
407             ImmutableList.of(),
408             ImmutableList.of(),
409             EnvoyServerProtoData.ConnectionSourceType.ANY,
410             ImmutableList.of(),
411             ImmutableList.of(),
412             "");
413     EnvoyServerProtoData.FilterChain filterChain0Length = EnvoyServerProtoData.FilterChain.create(
414             "filter-chain-foo", filterChainMatch0Length, HTTP_CONNECTION_MANAGER,
415             tlsContext0Length, tlsContextManager);
416     EnvoyServerProtoData.DownstreamTlsContext tlsContextForDefaultFilterChain =
417             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
418     EnvoyServerProtoData.FilterChain defaultFilterChain = EnvoyServerProtoData.FilterChain.create(
419             "filter-chain-bar", DEFAULT_FILTER_CHAIN_MATCH, HTTP_CONNECTION_MANAGER,
420             tlsContextForDefaultFilterChain, tlsContextManager);
421 
422     selectorManager.updateSelector(new FilterChainSelector(
423             ImmutableMap.of(filterChain0Length, noopConfig),
424             defaultFilterChain.sslContextProviderSupplier(),
425         new AtomicReference<ServerRoutingConfig>()));
426     FilterChainMatchingHandler filterChainMatchingHandler =
427             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
428 
429     ChannelHandler next = captureAttrHandler(sslSet, routingSettable);
430     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
431     setupChannel(LOCAL_IP, REMOTE_IP, 15000, filterChainMatchingHandler);
432     pipeline.fireUserEventTriggered(event);
433     channel.runPendingTasks();
434     assertThat(sslSet.get()).isEqualTo(filterChain0Length.sslContextProviderSupplier());
435     assertThat(routingSettable.get()).isEqualTo(noopConfig);
436     assertThat(sslSet.get().getTlsContext()).isSameInstanceAs(tlsContext0Length);
437   }
438 
439   @Test
destPrefixRange_moreSpecificWins()440   public void destPrefixRange_moreSpecificWins()
441           throws Exception {
442     EnvoyServerProtoData.DownstreamTlsContext tlsContextLessSpecific =
443             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
444     EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific =
445         EnvoyServerProtoData.FilterChainMatch.create(
446             0,
447             ImmutableList.of(EnvoyServerProtoData.CidrRange.create("10.1.2.0", 24)),
448             ImmutableList.of(),
449             ImmutableList.of(),
450             EnvoyServerProtoData.ConnectionSourceType.ANY,
451             ImmutableList.of(),
452             ImmutableList.of(),
453             "");
454     EnvoyServerProtoData.FilterChain filterChainLessSpecific =
455             EnvoyServerProtoData.FilterChain.create(
456                     "filter-chain-foo", filterChainMatchLessSpecific, HTTP_CONNECTION_MANAGER,
457                     tlsContextLessSpecific, tlsContextManager);
458 
459     EnvoyServerProtoData.DownstreamTlsContext tlsContextMoreSpecific =
460             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
461     EnvoyServerProtoData.FilterChainMatch filterChainMatchMoreSpecific =
462         EnvoyServerProtoData.FilterChainMatch.create(
463             0,
464             ImmutableList.of(EnvoyServerProtoData.CidrRange.create("10.1.2.2", 31)),
465             ImmutableList.of(),
466             ImmutableList.of(),
467             EnvoyServerProtoData.ConnectionSourceType.ANY,
468             ImmutableList.of(),
469             ImmutableList.of(),
470             "");
471     EnvoyServerProtoData.FilterChain filterChainMoreSpecific =
472             EnvoyServerProtoData.FilterChain.create(
473                     "filter-chain-bar", filterChainMatchMoreSpecific, HTTP_CONNECTION_MANAGER,
474                     tlsContextMoreSpecific,
475                     tlsContextManager);
476     EnvoyServerProtoData.FilterChain defaultFilterChain = EnvoyServerProtoData.FilterChain.create(
477             "filter-chain-baz", DEFAULT_FILTER_CHAIN_MATCH, HTTP_CONNECTION_MANAGER, null,
478         tlsContextManager);
479     selectorManager.updateSelector(new FilterChainSelector(
480             ImmutableMap.of(filterChainLessSpecific, randomConfig("no-match"),
481                     filterChainMoreSpecific, noopConfig),
482             defaultFilterChain.sslContextProviderSupplier(), randomConfig("default")));
483 
484     FilterChainMatchingHandler filterChainMatchingHandler =
485             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
486 
487     ChannelHandler next = captureAttrHandler(sslSet, routingSettable);
488     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
489     setupChannel(LOCAL_IP, REMOTE_IP, 15000, filterChainMatchingHandler);
490     pipeline.fireUserEventTriggered(event);
491     channel.runPendingTasks();
492     assertThat(sslSet.get()).isEqualTo(filterChainMoreSpecific.sslContextProviderSupplier());
493     assertThat(routingSettable.get()).isEqualTo(noopConfig);
494     assertThat(sslSet.get().getTlsContext()).isSameInstanceAs(tlsContextMoreSpecific);
495   }
496 
497   @Test
destPrefixRange_emptyListLessSpecific()498   public void destPrefixRange_emptyListLessSpecific()
499           throws Exception {
500     EnvoyServerProtoData.DownstreamTlsContext tlsContextLessSpecific =
501             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
502     EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific =
503         EnvoyServerProtoData.FilterChainMatch.create(
504             0,
505             ImmutableList.of(),
506             ImmutableList.of(),
507             ImmutableList.of(),
508             EnvoyServerProtoData.ConnectionSourceType.ANY,
509             ImmutableList.of(),
510             ImmutableList.of(),
511             "");
512     EnvoyServerProtoData.FilterChain filterChainLessSpecific =
513             EnvoyServerProtoData.FilterChain.create(
514                     "filter-chain-foo", filterChainMatchLessSpecific, HTTP_CONNECTION_MANAGER,
515                     tlsContextLessSpecific, tlsContextManager);
516 
517     EnvoyServerProtoData.DownstreamTlsContext tlsContextMoreSpecific =
518             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
519     EnvoyServerProtoData.FilterChainMatch filterChainMatchMoreSpecific =
520         EnvoyServerProtoData.FilterChainMatch.create(
521             0,
522             ImmutableList.of(EnvoyServerProtoData.CidrRange.create("8.0.0.0", 5)),
523             ImmutableList.of(),
524             ImmutableList.of(),
525             EnvoyServerProtoData.ConnectionSourceType.ANY,
526             ImmutableList.of(),
527             ImmutableList.of(),
528             "");
529     EnvoyServerProtoData.FilterChain filterChainMoreSpecific =
530             EnvoyServerProtoData.FilterChain.create(
531                     "filter-chain-bar", filterChainMatchMoreSpecific, HTTP_CONNECTION_MANAGER,
532                     tlsContextMoreSpecific,
533                     tlsContextManager);
534     EnvoyServerProtoData.FilterChain defaultFilterChain = EnvoyServerProtoData.FilterChain.create(
535         "filter-chain-baz", DEFAULT_FILTER_CHAIN_MATCH, HTTP_CONNECTION_MANAGER, null,
536         tlsContextManager);
537     selectorManager.updateSelector(new FilterChainSelector(
538             ImmutableMap.of(filterChainLessSpecific, randomConfig("no-match"),
539                     filterChainMoreSpecific, noopConfig),
540             defaultFilterChain.sslContextProviderSupplier(), randomConfig("default")));
541     FilterChainMatchingHandler filterChainMatchingHandler =
542             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
543 
544     ChannelHandler next = captureAttrHandler(sslSet, routingSettable);
545     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
546     setupChannel(LOCAL_IP, REMOTE_IP, 15000, filterChainMatchingHandler);
547     pipeline.fireUserEventTriggered(event);
548     channel.runPendingTasks();
549     assertThat(sslSet.get()).isEqualTo(filterChainMoreSpecific.sslContextProviderSupplier());
550     assertThat(routingSettable.get()).isEqualTo(noopConfig);
551     assertThat(sslSet.get().getTlsContext()).isSameInstanceAs(tlsContextMoreSpecific);
552   }
553 
554   @Test
destPrefixRangeIpv6_moreSpecificWins()555   public void destPrefixRangeIpv6_moreSpecificWins()
556           throws Exception {
557     EnvoyServerProtoData.DownstreamTlsContext tlsContextLessSpecific =
558             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
559     EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific =
560         EnvoyServerProtoData.FilterChainMatch.create(
561             0,
562             ImmutableList.of(EnvoyServerProtoData.CidrRange.create("FE80:0:0:0:0:0:0:0", 60)),
563             ImmutableList.of(),
564             ImmutableList.of(),
565             EnvoyServerProtoData.ConnectionSourceType.ANY,
566             ImmutableList.of(),
567             ImmutableList.of(),
568             "");
569     EnvoyServerProtoData.FilterChain filterChainLessSpecific =
570             EnvoyServerProtoData.FilterChain.create(
571                     "filter-chain-foo", filterChainMatchLessSpecific, HTTP_CONNECTION_MANAGER,
572                     tlsContextLessSpecific, tlsContextManager);
573 
574     EnvoyServerProtoData.DownstreamTlsContext tlsContextMoreSpecific =
575             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
576     EnvoyServerProtoData.FilterChainMatch filterChainMatchMoreSpecific =
577         EnvoyServerProtoData.FilterChainMatch.create(
578             0,
579             ImmutableList.of(
580                 EnvoyServerProtoData.CidrRange.create("FE80:0000:0000:0000:0202:0:0:0", 80)),
581             ImmutableList.of(),
582             ImmutableList.of(),
583             EnvoyServerProtoData.ConnectionSourceType.ANY,
584             ImmutableList.of(),
585             ImmutableList.of(),
586             "");
587     EnvoyServerProtoData.FilterChain filterChainMoreSpecific =
588             EnvoyServerProtoData.FilterChain.create(
589                     "filter-chain-bar", filterChainMatchMoreSpecific, HTTP_CONNECTION_MANAGER,
590                     tlsContextMoreSpecific, tlsContextManager);
591     EnvoyServerProtoData.FilterChain defaultFilterChain = EnvoyServerProtoData.FilterChain.create(
592         "filter-chain-baz", DEFAULT_FILTER_CHAIN_MATCH, HTTP_CONNECTION_MANAGER, null,
593         tlsContextManager);
594     selectorManager.updateSelector(new FilterChainSelector(
595             ImmutableMap.of(filterChainLessSpecific, randomConfig("no-match"),
596                     filterChainMoreSpecific, noopConfig),
597             defaultFilterChain.sslContextProviderSupplier(), randomConfig("default")));
598 
599     FilterChainMatchingHandler filterChainMatchingHandler =
600             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
601 
602     ChannelHandler next = captureAttrHandler(sslSet, routingSettable);
603     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
604 
605     setupChannel("FE80:0000:0000:0000:0202:B3FF:FE1E:8329", "2001:DB8::8:800:200C:417A",
606             15000, filterChainMatchingHandler);
607     pipeline.fireUserEventTriggered(event);
608     channel.runPendingTasks();
609     assertThat(sslSet.get()).isEqualTo(filterChainMoreSpecific.sslContextProviderSupplier());
610     assertThat(routingSettable.get()).isEqualTo(noopConfig);
611     assertThat(sslSet.get().getTlsContext()).isSameInstanceAs(tlsContextMoreSpecific);
612   }
613 
614   @Test
destPrefixRange_moreSpecificWith2Wins()615   public void destPrefixRange_moreSpecificWith2Wins()
616           throws Exception {
617     EnvoyServerProtoData.DownstreamTlsContext tlsContextMoreSpecificWith2 =
618             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
619     EnvoyServerProtoData.FilterChainMatch filterChainMatchMoreSpecificWith2 =
620         EnvoyServerProtoData.FilterChainMatch.create(
621             0,
622             ImmutableList.of(
623                 EnvoyServerProtoData.CidrRange.create("10.1.2.0", 24),
624                 EnvoyServerProtoData.CidrRange.create(LOCAL_IP, 32)),
625             ImmutableList.of(),
626             ImmutableList.of(),
627             EnvoyServerProtoData.ConnectionSourceType.ANY,
628             ImmutableList.of(),
629             ImmutableList.of(),
630             "");
631     EnvoyServerProtoData.FilterChain filterChainMoreSpecificWith2 =
632             EnvoyServerProtoData.FilterChain.create(
633                     "filter-chain-foo", filterChainMatchMoreSpecificWith2, HTTP_CONNECTION_MANAGER,
634                     tlsContextMoreSpecificWith2, tlsContextManager);
635 
636     EnvoyServerProtoData.DownstreamTlsContext tlsContextLessSpecific =
637             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
638     EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific =
639         EnvoyServerProtoData.FilterChainMatch.create(
640             0,
641             ImmutableList.of(EnvoyServerProtoData.CidrRange.create("10.1.2.2", 31)),
642             ImmutableList.of(),
643             ImmutableList.of(),
644             EnvoyServerProtoData.ConnectionSourceType.ANY,
645             ImmutableList.of(),
646             ImmutableList.of(),
647             "");
648     EnvoyServerProtoData.FilterChain filterChainLessSpecific =
649             EnvoyServerProtoData.FilterChain.create(
650                     "filter-chain-bar", filterChainMatchLessSpecific, HTTP_CONNECTION_MANAGER,
651                     tlsContextLessSpecific, tlsContextManager);
652     EnvoyServerProtoData.FilterChain defaultFilterChain = EnvoyServerProtoData.FilterChain.create(
653         "filter-chain-baz", DEFAULT_FILTER_CHAIN_MATCH, HTTP_CONNECTION_MANAGER, null,
654         tlsContextManager);
655 
656     selectorManager.updateSelector(new FilterChainSelector(
657             ImmutableMap.of(filterChainMoreSpecificWith2, noopConfig,
658                     filterChainLessSpecific, randomConfig("no-match")),
659             defaultFilterChain.sslContextProviderSupplier(), randomConfig("default")));
660     FilterChainMatchingHandler filterChainMatchingHandler =
661             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
662 
663     ChannelHandler next = captureAttrHandler(sslSet, routingSettable);
664     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
665     setupChannel(LOCAL_IP, REMOTE_IP, 15000, filterChainMatchingHandler);
666     pipeline.fireUserEventTriggered(event);
667     channel.runPendingTasks();
668     assertThat(sslSet.get()).isEqualTo(
669             filterChainMoreSpecificWith2.sslContextProviderSupplier());
670     assertThat(routingSettable.get()).isEqualTo(noopConfig);
671     assertThat(sslSet.get().getTlsContext()).isSameInstanceAs(tlsContextMoreSpecificWith2);
672   }
673 
674   @Test
sourceTypeMismatch_returnDefaultFilterChain()675   public void sourceTypeMismatch_returnDefaultFilterChain() throws Exception {
676     EnvoyServerProtoData.DownstreamTlsContext tlsContextMismatch =
677             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
678     EnvoyServerProtoData.FilterChainMatch filterChainMatchWithMismatch =
679         EnvoyServerProtoData.FilterChainMatch.create(
680             0,
681             ImmutableList.of(),
682             ImmutableList.of(),
683             ImmutableList.of(),
684             EnvoyServerProtoData.ConnectionSourceType.SAME_IP_OR_LOOPBACK,
685             ImmutableList.of(),
686             ImmutableList.of(),
687             "");
688     EnvoyServerProtoData.FilterChain filterChainWithMismatch =
689             EnvoyServerProtoData.FilterChain.create(
690                     "filter-chain-foo", filterChainMatchWithMismatch, HTTP_CONNECTION_MANAGER,
691                     tlsContextMismatch, tlsContextManager);
692     EnvoyServerProtoData.DownstreamTlsContext tlsContextForDefaultFilterChain =
693             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
694     EnvoyServerProtoData.FilterChain defaultFilterChain = EnvoyServerProtoData.FilterChain.create(
695         "filter-chain-bar", DEFAULT_FILTER_CHAIN_MATCH, HTTP_CONNECTION_MANAGER,
696         tlsContextForDefaultFilterChain, tlsContextManager);
697     selectorManager.updateSelector(new FilterChainSelector(
698             ImmutableMap.of(filterChainWithMismatch, randomConfig("no-match")),
699             defaultFilterChain.sslContextProviderSupplier(), noopConfig));
700     FilterChainMatchingHandler filterChainMatchingHandler =
701             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
702 
703 
704     ChannelHandler next = captureAttrHandler(sslSet, routingSettable);
705     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
706     setupChannel(LOCAL_IP, REMOTE_IP, 15000, filterChainMatchingHandler);
707     pipeline.fireUserEventTriggered(event);
708     channel.runPendingTasks();
709     assertThat(sslSet.get()).isEqualTo(defaultFilterChain.sslContextProviderSupplier());
710     assertThat(routingSettable.get()).isEqualTo(noopConfig);
711     assertThat(sslSet.get().getTlsContext()).isSameInstanceAs(tlsContextForDefaultFilterChain);
712   }
713 
714   @Test
sourceTypeLocal()715   public void sourceTypeLocal() throws Exception {
716     ChannelHandler next = captureAttrHandler(sslSet, routingSettable);
717     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
718     EnvoyServerProtoData.DownstreamTlsContext tlsContextMatch =
719             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
720     EnvoyServerProtoData.FilterChainMatch filterChainMatchWithMatch =
721         EnvoyServerProtoData.FilterChainMatch.create(
722             0,
723             ImmutableList.of(),
724             ImmutableList.of(),
725             ImmutableList.of(),
726             EnvoyServerProtoData.ConnectionSourceType.SAME_IP_OR_LOOPBACK,
727             ImmutableList.of(),
728             ImmutableList.of(),
729             "");
730     EnvoyServerProtoData.FilterChain filterChainWithMatch = EnvoyServerProtoData.FilterChain.create(
731             "filter-chain-foo", filterChainMatchWithMatch, HTTP_CONNECTION_MANAGER, tlsContextMatch,
732             tlsContextManager);
733     EnvoyServerProtoData.DownstreamTlsContext tlsContextForDefaultFilterChain =
734             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
735     EnvoyServerProtoData.FilterChain defaultFilterChain = EnvoyServerProtoData.FilterChain.create(
736         "filter-chain-bar", DEFAULT_FILTER_CHAIN_MATCH, HTTP_CONNECTION_MANAGER,
737         tlsContextForDefaultFilterChain, tlsContextManager);
738 
739     selectorManager.updateSelector(new FilterChainSelector(
740             ImmutableMap.of(filterChainWithMatch, noopConfig),
741             defaultFilterChain.sslContextProviderSupplier(), randomConfig("default")));
742     FilterChainMatchingHandler filterChainMatchingHandler =
743             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
744     setupChannel(LOCAL_IP, LOCAL_IP, 15000, filterChainMatchingHandler);
745     pipeline.fireUserEventTriggered(event);
746     channel.runPendingTasks();
747     assertThat(sslSet.get()).isEqualTo(filterChainWithMatch.sslContextProviderSupplier());
748     assertThat(routingSettable.get()).isEqualTo(noopConfig);
749     assertThat(sslSet.get().getTlsContext()).isSameInstanceAs(tlsContextMatch);
750   }
751 
752   @Test
sourcePrefixRange_moreSpecificWith2Wins()753   public void sourcePrefixRange_moreSpecificWith2Wins()
754           throws Exception {
755     ChannelHandler next = captureAttrHandler(sslSet, routingSettable);
756     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
757 
758     EnvoyServerProtoData.DownstreamTlsContext tlsContextMoreSpecificWith2 =
759             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
760     EnvoyServerProtoData.FilterChainMatch filterChainMatchMoreSpecificWith2 =
761         EnvoyServerProtoData.FilterChainMatch.create(
762             0,
763             ImmutableList.of(),
764             ImmutableList.of(),
765             ImmutableList.of(
766                 EnvoyServerProtoData.CidrRange.create("10.4.2.0", 24),
767                 EnvoyServerProtoData.CidrRange.create(REMOTE_IP, 32)),
768             EnvoyServerProtoData.ConnectionSourceType.ANY,
769             ImmutableList.of(),
770             ImmutableList.of(),
771             "");
772     EnvoyServerProtoData.FilterChain filterChainMoreSpecificWith2 =
773             EnvoyServerProtoData.FilterChain.create(
774                     "filter-chain-foo", filterChainMatchMoreSpecificWith2, HTTP_CONNECTION_MANAGER,
775                     tlsContextMoreSpecificWith2, tlsContextManager);
776 
777     EnvoyServerProtoData.DownstreamTlsContext tlsContextLessSpecific =
778             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
779     EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific =
780         EnvoyServerProtoData.FilterChainMatch.create(
781             0,
782             ImmutableList.of(),
783             ImmutableList.of(),
784             ImmutableList.of(EnvoyServerProtoData.CidrRange.create("10.4.2.2", 31)),
785             EnvoyServerProtoData.ConnectionSourceType.ANY,
786             ImmutableList.of(),
787             ImmutableList.of(),
788             "");
789     EnvoyServerProtoData.FilterChain filterChainLessSpecific =
790             EnvoyServerProtoData.FilterChain.create(
791                     "filter-chain-bar", filterChainMatchLessSpecific, HTTP_CONNECTION_MANAGER,
792                     tlsContextLessSpecific, tlsContextManager);
793     EnvoyServerProtoData.FilterChain defaultFilterChain = EnvoyServerProtoData.FilterChain.create(
794         "filter-chain-baz", DEFAULT_FILTER_CHAIN_MATCH, HTTP_CONNECTION_MANAGER, null,
795         tlsContextManager);
796 
797     selectorManager.updateSelector(new FilterChainSelector(
798             ImmutableMap.of(filterChainMoreSpecificWith2, noopConfig,
799                     filterChainLessSpecific, randomConfig("no-match")),
800             defaultFilterChain.sslContextProviderSupplier(), randomConfig("default")));
801 
802     FilterChainMatchingHandler filterChainMatchingHandler =
803             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
804     setupChannel(LOCAL_IP, REMOTE_IP, 15000, filterChainMatchingHandler);
805     pipeline.fireUserEventTriggered(event);
806     channel.runPendingTasks();
807     assertThat(sslSet.get()).isEqualTo(
808             filterChainMoreSpecificWith2.sslContextProviderSupplier());
809     assertThat(routingSettable.get()).isEqualTo(noopConfig);
810     assertThat(sslSet.get().getTlsContext()).isSameInstanceAs(tlsContextMoreSpecificWith2);
811   }
812 
813   @Test
sourcePrefixRange_2Matchers_expectException()814   public void sourcePrefixRange_2Matchers_expectException()
815           throws UnknownHostException {
816     ChannelHandler next = new ChannelInboundHandlerAdapter() {
817       @Override
818       public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
819         ProtocolNegotiationEvent e = (ProtocolNegotiationEvent)evt;
820         sslSet.set(InternalProtocolNegotiationEvent.getAttributes(e)
821                 .get(ATTR_SERVER_SSL_CONTEXT_PROVIDER_SUPPLIER));
822       }
823     };
824     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
825 
826     EnvoyServerProtoData.DownstreamTlsContext tlsContext1 =
827             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
828     EnvoyServerProtoData.FilterChainMatch filterChainMatch1 =
829         EnvoyServerProtoData.FilterChainMatch.create(
830             0,
831             ImmutableList.of(),
832             ImmutableList.of(),
833             ImmutableList.of(
834                 EnvoyServerProtoData.CidrRange.create("10.4.2.0", 24),
835                 EnvoyServerProtoData.CidrRange.create("192.168.10.2", 32)),
836             EnvoyServerProtoData.ConnectionSourceType.ANY,
837             ImmutableList.of(),
838             ImmutableList.of(),
839             "");
840     EnvoyServerProtoData.FilterChain filterChain1 = EnvoyServerProtoData.FilterChain.create(
841             "filter-chain-foo", filterChainMatch1, HTTP_CONNECTION_MANAGER, tlsContext1,
842             tlsContextManager);
843 
844     EnvoyServerProtoData.DownstreamTlsContext tlsContext2 =
845             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
846     EnvoyServerProtoData.FilterChainMatch filterChainMatch2 =
847         EnvoyServerProtoData.FilterChainMatch.create(
848             0,
849             ImmutableList.of(),
850             ImmutableList.of(),
851             ImmutableList.of(EnvoyServerProtoData.CidrRange.create("10.4.2.0", 24)),
852             EnvoyServerProtoData.ConnectionSourceType.ANY,
853             ImmutableList.of(),
854             ImmutableList.of(),
855             "");
856     EnvoyServerProtoData.FilterChain filterChain2 = EnvoyServerProtoData.FilterChain.create(
857             "filter-chain-bar", filterChainMatch2, HTTP_CONNECTION_MANAGER, tlsContext2,
858             tlsContextManager);
859     EnvoyServerProtoData.FilterChain defaultFilterChain = EnvoyServerProtoData.FilterChain.create(
860             "filter-chain-baz", DEFAULT_FILTER_CHAIN_MATCH, HTTP_CONNECTION_MANAGER, null, null);
861 
862     selectorManager.updateSelector(new FilterChainSelector(
863             ImmutableMap.of(filterChain1, noopConfig, filterChain2, noopConfig),
864             defaultFilterChain.sslContextProviderSupplier(), noopConfig));
865 
866     FilterChainMatchingHandler filterChainMatchingHandler =
867             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
868     setupChannel(LOCAL_IP, REMOTE_IP, 15000, filterChainMatchingHandler);
869     pipeline.fireUserEventTriggered(event);
870     channel.runPendingTasks();
871     try {
872       channel.checkException();
873       fail("expect exception!");
874     } catch (IllegalStateException ise) {
875       assertThat(ise).hasMessageThat().isEqualTo("Found more than one matching filter chains. This "
876           + "should not be possible as ClientXdsClient validated the chains for uniqueness.");
877       assertThat(sslSet.isDone()).isFalse();
878       channelHandlerCtx = pipeline.context(filterChainMatchingHandler);
879       assertThat(channelHandlerCtx).isNotNull();
880     }
881   }
882 
883   @Test
sourcePortMatch_exactMatchWinsOverEmptyList()884   public void sourcePortMatch_exactMatchWinsOverEmptyList() throws Exception {
885     EnvoyServerProtoData.DownstreamTlsContext tlsContextEmptySourcePorts =
886             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
887     EnvoyServerProtoData.FilterChainMatch filterChainMatchEmptySourcePorts =
888         EnvoyServerProtoData.FilterChainMatch.create(
889             0,
890             ImmutableList.of(),
891             ImmutableList.of(),
892             ImmutableList.of(
893                 EnvoyServerProtoData.CidrRange.create("10.4.2.0", 24),
894                 EnvoyServerProtoData.CidrRange.create("10.4.2.2", 31)),
895             EnvoyServerProtoData.ConnectionSourceType.ANY,
896             ImmutableList.of(),
897             ImmutableList.of(),
898             "");
899     EnvoyServerProtoData.FilterChain filterChainEmptySourcePorts =
900             EnvoyServerProtoData.FilterChain.create(
901                     "filter-chain-foo", filterChainMatchEmptySourcePorts, HTTP_CONNECTION_MANAGER,
902                     tlsContextEmptySourcePorts, tlsContextManager);
903 
904     EnvoyServerProtoData.DownstreamTlsContext tlsContextSourcePortMatch =
905             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
906     EnvoyServerProtoData.FilterChainMatch filterChainMatchSourcePortMatch =
907         EnvoyServerProtoData.FilterChainMatch.create(
908             0,
909             ImmutableList.of(),
910             ImmutableList.of(),
911             ImmutableList.of(EnvoyServerProtoData.CidrRange.create("10.4.2.2", 31)),
912             EnvoyServerProtoData.ConnectionSourceType.ANY,
913             ImmutableList.of(7000, 15000),
914             ImmutableList.of(),
915             "");
916     EnvoyServerProtoData.FilterChain filterChainSourcePortMatch =
917             EnvoyServerProtoData.FilterChain.create(
918                     "filter-chain-bar", filterChainMatchSourcePortMatch, HTTP_CONNECTION_MANAGER,
919                     tlsContextSourcePortMatch, tlsContextManager);
920     EnvoyServerProtoData.FilterChain defaultFilterChain = EnvoyServerProtoData.FilterChain.create(
921         "filter-chain-baz", DEFAULT_FILTER_CHAIN_MATCH, HTTP_CONNECTION_MANAGER, null,
922         tlsContextManager);
923 
924     selectorManager.updateSelector(new FilterChainSelector(
925             ImmutableMap.of(filterChainEmptySourcePorts, randomConfig("no-match"),
926                     filterChainSourcePortMatch, noopConfig),
927             defaultFilterChain.sslContextProviderSupplier(), randomConfig("default")));
928 
929     FilterChainMatchingHandler filterChainMatchingHandler =
930             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
931     ChannelHandler next = captureAttrHandler(sslSet, routingSettable);
932     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
933     setupChannel(LOCAL_IP, REMOTE_IP, 15000, filterChainMatchingHandler);
934     pipeline.fireUserEventTriggered(event);
935     channel.runPendingTasks();
936     assertThat(sslSet.get()).isEqualTo(filterChainSourcePortMatch.sslContextProviderSupplier());
937     assertThat(routingSettable.get()).isEqualTo(noopConfig);
938     assertThat(sslSet.get().getTlsContext()).isSameInstanceAs(tlsContextSourcePortMatch);
939   }
940 
941   /**
942    * Create 6 filterChains: - 1st filter chain has dest port & specific prefix range but is
943    * eliminated due to dest port - 5 advance to next step: 1 is eliminated due to being less
944    * specific than the remaining 4. - 4 advance to 3rd step: source type external eliminates one
945    * with local source_type. - 3 advance to 4th step: more specific 2 get picked based on
946    * source-prefix range. - 5th step: out of 2 one with matching source port gets picked
947    */
948   @Test
filterChain_5stepMatch()949   public void filterChain_5stepMatch() throws Exception {
950     EnvoyServerProtoData.DownstreamTlsContext tlsContext1 =
951             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
952     EnvoyServerProtoData.DownstreamTlsContext tlsContext2 =
953             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
954     EnvoyServerProtoData.DownstreamTlsContext tlsContext3 =
955             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT3", "VA3");
956     EnvoyServerProtoData.DownstreamTlsContext tlsContext4 =
957             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT4", "VA4");
958     EnvoyServerProtoData.DownstreamTlsContext tlsContext5 =
959             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT5", "VA5");
960     EnvoyServerProtoData.DownstreamTlsContext tlsContext6 =
961             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT6", "VA6");
962 
963     // has dest port and specific prefix ranges: gets eliminated in step 1
964     EnvoyServerProtoData.FilterChainMatch filterChainMatch1 =
965         EnvoyServerProtoData.FilterChainMatch.create(
966             PORT,
967             ImmutableList.of(),
968             ImmutableList.of(),
969             ImmutableList.of(EnvoyServerProtoData.CidrRange.create(REMOTE_IP, 32)),
970             EnvoyServerProtoData.ConnectionSourceType.ANY,
971             ImmutableList.of(),
972             ImmutableList.of(),
973             "");
974     EnvoyServerProtoData.FilterChain filterChain1 = EnvoyServerProtoData.FilterChain.create(
975             "filter-chain-1", filterChainMatch1, HTTP_CONNECTION_MANAGER, tlsContext1,
976             tlsContextManager);
977 
978     // next 5 use prefix range: 4 with prefixLen of 30 and last one with 29
979 
980     // has single prefix range: and less specific source prefix range: gets eliminated in step 4
981     EnvoyServerProtoData.FilterChainMatch filterChainMatch2 =
982         EnvoyServerProtoData.FilterChainMatch.create(
983             0,
984             ImmutableList.of(EnvoyServerProtoData.CidrRange.create("10.1.2.0", 30)),
985             ImmutableList.of(),
986             ImmutableList.of(EnvoyServerProtoData.CidrRange.create("10.4.0.0", 16)),
987             EnvoyServerProtoData.ConnectionSourceType.ANY,
988             ImmutableList.of(),
989             ImmutableList.of(),
990             "");
991     EnvoyServerProtoData.FilterChain filterChain2 = EnvoyServerProtoData.FilterChain.create(
992             "filter-chain-2", filterChainMatch2, HTTP_CONNECTION_MANAGER, tlsContext2,
993             tlsContextManager);
994 
995     // has prefix ranges with one not matching and source type local: gets eliminated in step 3
996     EnvoyServerProtoData.FilterChainMatch filterChainMatch3 =
997         EnvoyServerProtoData.FilterChainMatch.create(
998             0,
999             ImmutableList.of(
1000                 EnvoyServerProtoData.CidrRange.create("192.168.2.0", 24),
1001                 EnvoyServerProtoData.CidrRange.create("10.1.2.0", 30)),
1002             ImmutableList.of(),
1003             ImmutableList.of(),
1004             EnvoyServerProtoData.ConnectionSourceType.SAME_IP_OR_LOOPBACK,
1005             ImmutableList.of(),
1006             ImmutableList.of(),
1007             "");
1008     EnvoyServerProtoData.FilterChain filterChain3 = EnvoyServerProtoData.FilterChain.create(
1009             "filter-chain-3", filterChainMatch3, HTTP_CONNECTION_MANAGER, tlsContext3,
1010             tlsContextManager);
1011 
1012     // has prefix ranges with both matching and source type external but non matching source port:
1013     // gets eliminated in step 5
1014     EnvoyServerProtoData.FilterChainMatch filterChainMatch4 =
1015         EnvoyServerProtoData.FilterChainMatch.create(
1016             0,
1017             ImmutableList.of(
1018                 EnvoyServerProtoData.CidrRange.create("10.1.0.0", 16),
1019                 EnvoyServerProtoData.CidrRange.create("10.1.2.0", 30)),
1020             ImmutableList.of(),
1021             ImmutableList.of(EnvoyServerProtoData.CidrRange.create("10.4.2.0", 24)),
1022             EnvoyServerProtoData.ConnectionSourceType.EXTERNAL,
1023             ImmutableList.of(16000, 9000),
1024             ImmutableList.of(),
1025             "");
1026     EnvoyServerProtoData.FilterChain filterChain4 =
1027             EnvoyServerProtoData.FilterChain.create(
1028                     "filter-chain-4", filterChainMatch4, HTTP_CONNECTION_MANAGER, tlsContext4,
1029                     tlsContextManager);
1030 
1031     // has prefix ranges with both matching and source type external and matching source port: this
1032     // gets selected
1033     EnvoyServerProtoData.FilterChainMatch filterChainMatch5 =
1034         EnvoyServerProtoData.FilterChainMatch.create(
1035             0,
1036             ImmutableList.of(
1037                 EnvoyServerProtoData.CidrRange.create("10.1.0.0", 16),
1038                 EnvoyServerProtoData.CidrRange.create("10.1.2.0", 30)),
1039             ImmutableList.of(),
1040             ImmutableList.of(
1041                 EnvoyServerProtoData.CidrRange.create("10.4.2.0", 24),
1042                 EnvoyServerProtoData.CidrRange.create("192.168.2.0", 24)),
1043             EnvoyServerProtoData.ConnectionSourceType.ANY,
1044             ImmutableList.of(15000, 8000),
1045             ImmutableList.of(),
1046             "");
1047     EnvoyServerProtoData.FilterChain filterChain5 =
1048             EnvoyServerProtoData.FilterChain.create(
1049                     "filter-chain-5", filterChainMatch5, HTTP_CONNECTION_MANAGER, tlsContext5,
1050                     tlsContextManager);
1051 
1052     // has prefix range with prefixLen of 29: gets eliminated in step 2
1053     EnvoyServerProtoData.FilterChainMatch filterChainMatch6 =
1054         EnvoyServerProtoData.FilterChainMatch.create(
1055             0,
1056             ImmutableList.of(EnvoyServerProtoData.CidrRange.create("10.1.2.0", 29)),
1057             ImmutableList.of(),
1058             ImmutableList.of(),
1059             EnvoyServerProtoData.ConnectionSourceType.ANY,
1060             ImmutableList.of(),
1061             ImmutableList.of(),
1062             "");
1063     EnvoyServerProtoData.FilterChain filterChain6 =
1064             EnvoyServerProtoData.FilterChain.create(
1065                     "filter-chain-6", filterChainMatch6, HTTP_CONNECTION_MANAGER, tlsContext6,
1066                     tlsContextManager);
1067 
1068     EnvoyServerProtoData.FilterChain defaultFilterChain = EnvoyServerProtoData.FilterChain.create(
1069         "filter-chain-7", DEFAULT_FILTER_CHAIN_MATCH, HTTP_CONNECTION_MANAGER, null,
1070         tlsContextManager);
1071 
1072     Map<FilterChain, AtomicReference<ServerRoutingConfig>> map = new HashMap<>();
1073     map.put(filterChain1, randomConfig("1"));
1074     map.put(filterChain2, randomConfig("2"));
1075     map.put(filterChain3, randomConfig("3"));
1076     map.put(filterChain4, randomConfig("4"));
1077     map.put(filterChain5, noopConfig);
1078     map.put(filterChain6, randomConfig("6"));
1079     selectorManager.updateSelector(new FilterChainSelector(
1080             map, defaultFilterChain.sslContextProviderSupplier(), randomConfig("default")));
1081 
1082     FilterChainMatchingHandler filterChainMatchingHandler =
1083             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
1084 
1085     ChannelHandler next = captureAttrHandler(sslSet, routingSettable);
1086     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
1087     setupChannel(LOCAL_IP, REMOTE_IP, 15000, filterChainMatchingHandler);
1088     pipeline.fireUserEventTriggered(event);
1089     channel.runPendingTasks();
1090     assertThat(sslSet.get()).isEqualTo(filterChain5.sslContextProviderSupplier());
1091     assertThat(routingSettable.get()).isEqualTo(noopConfig);
1092     assertThat(sslSet.get().getTlsContext()).isSameInstanceAs(tlsContext5);
1093   }
1094 
1095   @Test
1096   @SuppressWarnings("deprecation")
filterChainMatch_unsupportedMatchers()1097   public void filterChainMatch_unsupportedMatchers() throws Exception {
1098     EnvoyServerProtoData.DownstreamTlsContext tlsContext1 =
1099             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "ROOTCA");
1100     EnvoyServerProtoData.DownstreamTlsContext tlsContext2 =
1101             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "ROOTCA");
1102     EnvoyServerProtoData.DownstreamTlsContext tlsContext3 =
1103             CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT3", "ROOTCA");
1104 
1105     EnvoyServerProtoData.FilterChainMatch filterChainMatch1 =
1106         EnvoyServerProtoData.FilterChainMatch.create(
1107             0 /* destinationPort */,
1108             ImmutableList.of(
1109                     EnvoyServerProtoData.CidrRange.create("10.1.0.0", 16)) /* prefixRange */,
1110             ImmutableList.of("managed-mtls", "h2") /* applicationProtocol */,
1111             ImmutableList.of() /* sourcePrefixRanges */,
1112             EnvoyServerProtoData.ConnectionSourceType.ANY /* sourceType */,
1113             ImmutableList.of() /* sourcePorts */,
1114             ImmutableList.of("server1", "server2") /* serverNames */,
1115             "tls" /* transportProtocol */);
1116 
1117     EnvoyServerProtoData.FilterChainMatch filterChainMatch2 =
1118         EnvoyServerProtoData.FilterChainMatch.create(
1119             0 /* destinationPort */,
1120             ImmutableList.of(
1121                     EnvoyServerProtoData.CidrRange.create("10.0.0.0", 8)) /* prefixRange */,
1122             ImmutableList.of() /* applicationProtocol */,
1123             ImmutableList.of() /* sourcePrefixRanges */,
1124             EnvoyServerProtoData.ConnectionSourceType.ANY /* sourceType */,
1125             ImmutableList.of() /* sourcePorts */,
1126             ImmutableList.of() /* serverNames */,
1127             "" /* transportProtocol */);
1128 
1129     EnvoyServerProtoData.FilterChainMatch defaultFilterChainMatch =
1130         EnvoyServerProtoData.FilterChainMatch.create(
1131             0 /* destinationPort */,
1132             ImmutableList.of() /* prefixRange */,
1133             ImmutableList.of() /* applicationProtocol */,
1134             ImmutableList.of() /* sourcePrefixRanges */,
1135             EnvoyServerProtoData.ConnectionSourceType.ANY /* sourceType */,
1136             ImmutableList.of() /* sourcePorts */,
1137             ImmutableList.of() /* serverNames */,
1138             "" /* transportProtocol */);
1139 
1140     EnvoyServerProtoData.FilterChain filterChain1 = EnvoyServerProtoData.FilterChain.create(
1141             "filter-chain-foo", filterChainMatch1, HTTP_CONNECTION_MANAGER, tlsContext1,
1142             mock(TlsContextManager.class));
1143     EnvoyServerProtoData.FilterChain filterChain2 = EnvoyServerProtoData.FilterChain.create(
1144             "filter-chain-bar", filterChainMatch2, HTTP_CONNECTION_MANAGER, tlsContext2,
1145             mock(TlsContextManager.class));
1146 
1147     EnvoyServerProtoData.FilterChain defaultFilterChain = EnvoyServerProtoData.FilterChain.create(
1148             "filter-chain-baz", defaultFilterChainMatch, HTTP_CONNECTION_MANAGER, tlsContext3,
1149             mock(TlsContextManager.class));
1150 
1151     selectorManager.updateSelector(new FilterChainSelector(
1152             ImmutableMap.of(filterChain1, randomConfig("1"), filterChain2, randomConfig("2")),
1153             defaultFilterChain.sslContextProviderSupplier(), noopConfig));
1154 
1155     FilterChainMatchingHandler filterChainMatchingHandler =
1156             new FilterChainMatchingHandler(grpcHandler, selectorManager, mockDelegate);
1157     ChannelHandler next = captureAttrHandler(sslSet, routingSettable);
1158     when(mockDelegate.newHandler(grpcHandler)).thenReturn(next);
1159     setupChannel(LOCAL_IP, REMOTE_IP, 15000, filterChainMatchingHandler);
1160     pipeline.fireUserEventTriggered(event);
1161     channel.runPendingTasks();
1162     assertThat(sslSet.get()).isEqualTo(defaultFilterChain.sslContextProviderSupplier());
1163     assertThat(routingSettable.get()).isEqualTo(noopConfig);
1164     assertThat(sslSet.get().getTlsContext().getCommonTlsContext()
1165             .getTlsCertificateCertificateProviderInstance()
1166             .getCertificateName()).isEqualTo("CERT3");
1167   }
1168 
createRds(String name)1169   private static HttpConnectionManager createRds(String name) {
1170     return HttpConnectionManager.forRdsName(0L, name,
1171             new ArrayList<NamedFilterConfig>());
1172   }
1173 
createVirtualHost(String name)1174   private static VirtualHost createVirtualHost(String name) {
1175     return VirtualHost.create(
1176             name, Collections.singletonList("auth"), new ArrayList<Route>(),
1177             ImmutableMap.<String, FilterConfig>of());
1178   }
1179 
randomConfig(String domain)1180   private static AtomicReference<ServerRoutingConfig> randomConfig(String domain) {
1181     return new AtomicReference<>(
1182         ServerRoutingConfig.create(ImmutableList.of(createVirtualHost(domain)),
1183         ImmutableMap.<Route, ServerInterceptor>of())
1184     );
1185   }
1186 
createTls()1187   private EnvoyServerProtoData.DownstreamTlsContext createTls() {
1188     return DownstreamTlsContext.fromEnvoyProtoDownstreamTlsContext(
1189             io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
1190                     .getDefaultInstance());
1191   }
1192 
setupChannel(final String localIp, final String remoteIp, final int remotePort, FilterChainMatchingHandler matchingHandler)1193   private void setupChannel(final String localIp, final String remoteIp, final int remotePort,
1194                             FilterChainMatchingHandler matchingHandler) {
1195     channel =
1196         new EmbeddedChannel() {
1197           @Override
1198           public SocketAddress localAddress() {
1199             return new InetSocketAddress(localIp, 80);
1200           }
1201 
1202           @Override
1203           public SocketAddress remoteAddress() {
1204             return new InetSocketAddress(remoteIp, remotePort);
1205           }
1206         };
1207     pipeline = channel.pipeline();
1208     pipeline.addLast(matchingHandler);
1209   }
1210 
captureAttrHandler( final SettableFuture<SslContextProviderSupplier> sslSet, final SettableFuture<AtomicReference<ServerRoutingConfig>> routingSettable)1211   private static ChannelHandler captureAttrHandler(
1212           final SettableFuture<SslContextProviderSupplier> sslSet,
1213           final SettableFuture<AtomicReference<ServerRoutingConfig>> routingSettable) {
1214     return new ChannelInboundHandlerAdapter() {
1215       @Override
1216       public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
1217         ProtocolNegotiationEvent e = (ProtocolNegotiationEvent)evt;
1218         sslSet.set(InternalProtocolNegotiationEvent.getAttributes(e)
1219                 .get(ATTR_SERVER_SSL_CONTEXT_PROVIDER_SUPPLIER));
1220         routingSettable.set(InternalProtocolNegotiationEvent.getAttributes(e)
1221                 .get(ATTR_SERVER_ROUTING_CONFIG));
1222       }
1223     };
1224   }
1225 
1226   private static final class FakeGrpcHttp2ConnectionHandler extends GrpcHttp2ConnectionHandler {
1227     FakeGrpcHttp2ConnectionHandler(
1228             ChannelPromise channelUnused,
1229             Http2ConnectionDecoder decoder,
1230             Http2ConnectionEncoder encoder,
1231             Http2Settings initialSettings) {
1232       super(channelUnused, decoder, encoder, initialSettings, new NoopChannelLogger());
1233     }
1234 
1235     static FakeGrpcHttp2ConnectionHandler newHandler() {
1236       DefaultHttp2Connection conn = new DefaultHttp2Connection(/*server=*/ false);
1237       DefaultHttp2ConnectionEncoder encoder =
1238               new DefaultHttp2ConnectionEncoder(conn, new DefaultHttp2FrameWriter());
1239       DefaultHttp2ConnectionDecoder decoder =
1240               new DefaultHttp2ConnectionDecoder(conn, encoder, new DefaultHttp2FrameReader());
1241       Http2Settings settings = new Http2Settings();
1242       return new FakeGrpcHttp2ConnectionHandler(
1243               /*channelUnused=*/ null, decoder, encoder, settings);
1244     }
1245 
1246     @Override
1247     public String getAuthority() {
1248       return "authority";
1249     }
1250   }
1251 }
1252