Skip to content

Commit d54148a

Browse files
committed
SI-4041 Add SSL support for netty server, deprecate HttpNettyServerFactory(use HttpNettyServerBuilder)
RB=1188873 BUG=SI-4041 G=si-core-reviewers R=ssheng A=ssheng
1 parent 78ae922 commit d54148a

File tree

17 files changed

+808
-332
lines changed

17 files changed

+808
-332
lines changed

r2-int-test/src/test/java/test/r2/integ/AbstractEchoServiceTest.java

+47-34
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,10 @@ public abstract class AbstractEchoServiceTest
5454
private final String _toClientKey = "to-client";
5555
private final String _toClientValue = "this value goes to the client";
5656

57-
protected Client _client;
57+
protected final static String ECHO_MSG = "This is a simple echo message";
5858

59-
private Server _server;
59+
protected Client _client;
60+
protected Server _server;
6061

6162
private CaptureWireAttributesFilter _serverCaptureFilter;
6263
private CaptureWireAttributesFilter _clientCaptureFilter;
@@ -66,55 +67,35 @@ public abstract class AbstractEchoServiceTest
6667
@BeforeClass
6768
protected void setUp() throws Exception
6869
{
69-
_serverCaptureFilter = new CaptureWireAttributesFilter();
70-
_clientCaptureFilter = new CaptureWireAttributesFilter();
71-
72-
_serverLengthFilter = new LogEntityLengthFilter();
73-
_clientLengthFilter = new LogEntityLengthFilter();
74-
75-
SendWireAttributeFilter serverWireFilter = new SendWireAttributeFilter(_toClientKey, _toClientValue, false);
76-
SendWireAttributeFilter clientWireFilter = new SendWireAttributeFilter(_toServerKey, _toServerValue, true);
77-
78-
final FilterChain serverFilters = FilterChains.empty()
79-
.addFirstRest(_serverCaptureFilter)
80-
.addLastRest(_serverLengthFilter)
81-
.addLastRest(serverWireFilter)
82-
.addFirst(_serverCaptureFilter)
83-
// test adapted rest filter works fine in rest over stream setting
84-
.addLast(StreamFilterAdapters.adaptRestFilter(_serverLengthFilter))
85-
.addLast(serverWireFilter);
86-
87-
final FilterChain clientFilters = FilterChains.empty()
88-
.addFirstRest(_clientCaptureFilter)
89-
.addLastRest(_clientLengthFilter)
90-
.addLastRest(clientWireFilter)
91-
.addFirst(_clientCaptureFilter)
92-
// test adapted rest filter works fine in rest over stream setting
93-
.addLast(StreamFilterAdapters.adaptRestFilter(_clientLengthFilter))
94-
.addLast(clientWireFilter);
70+
final FilterChain clientFilters = getClientFilters();
71+
final FilterChain serverFilters = getServerFilters();
9572

9673
_client = createClient(clientFilters);
97-
9874
_server = createServer(serverFilters);
9975
_server.start();
10076
}
10177

10278
@AfterClass
10379
protected void tearDown() throws Exception
80+
{
81+
tearDown(_client, _server);
82+
}
83+
84+
protected void tearDown(Client client, Server server) throws Exception
10485
{
10586
final FutureCallback<None> callback = new FutureCallback<None>();
106-
_client.shutdown(callback);
87+
client.shutdown(callback);
10788

10889
try
10990
{
11091
callback.get();
11192
}
11293
finally
11394
{
114-
if (_server != null)
95+
if (server != null)
11596
{
116-
_server.stop();
117-
_server.waitForStop();
97+
server.stop();
98+
server.waitForStop();
11899
}
119100
}
120101
}
@@ -272,10 +253,42 @@ public void testFilterChainOnException() throws Exception
272253
Assert.assertNull(_clientCaptureFilter.getResponse().get(_toServerKey));
273254
}
274255

256+
protected FilterChain getClientFilters()
257+
{
258+
_clientCaptureFilter = new CaptureWireAttributesFilter();
259+
_clientLengthFilter = new LogEntityLengthFilter();
260+
final SendWireAttributeFilter clientWireFilter = new SendWireAttributeFilter(_toServerKey, _toServerValue, true);
261+
262+
return FilterChains.empty()
263+
.addFirstRest(_clientCaptureFilter)
264+
.addLastRest(_clientLengthFilter)
265+
.addLastRest(clientWireFilter)
266+
.addFirst(_clientCaptureFilter)
267+
// test adapted rest filter works fine in rest over stream setting
268+
.addLast(StreamFilterAdapters.adaptRestFilter(_clientLengthFilter))
269+
.addLast(clientWireFilter);
270+
}
271+
272+
protected FilterChain getServerFilters()
273+
{
274+
_serverCaptureFilter = new CaptureWireAttributesFilter();
275+
_serverLengthFilter = new LogEntityLengthFilter();
276+
final SendWireAttributeFilter serverWireFilter = new SendWireAttributeFilter(_toClientKey, _toClientValue, false);
277+
278+
return FilterChains.empty()
279+
.addFirstRest(_serverCaptureFilter)
280+
.addLastRest(_serverLengthFilter)
281+
.addLastRest(serverWireFilter)
282+
.addFirst(_serverCaptureFilter)
283+
// test adapted rest filter works fine in rest over stream setting
284+
.addLast(StreamFilterAdapters.adaptRestFilter(_serverLengthFilter))
285+
.addLast(serverWireFilter);
286+
}
287+
275288
protected abstract EchoService getEchoClient(Client client, URI uri);
276289

277290
protected abstract Client createClient(FilterChain filters) throws Exception;
278291

279-
protected abstract Server createServer(FilterChain filters);
292+
protected abstract Server createServer(FilterChain filters) throws Exception;
280293

281294
}

r2-int-test/src/test/java/test/r2/integ/AbstractTestHttps.java

+2-17
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,9 @@
2121
import com.linkedin.r2.sample.echo.rest.RestEchoClient;
2222
import com.linkedin.r2.transport.common.Client;
2323
import com.linkedin.r2.transport.common.Server;
24-
import com.linkedin.r2.transport.common.bridge.client.TransportClient;
25-
import com.linkedin.r2.transport.common.bridge.client.TransportClientAdapter;
26-
import com.linkedin.r2.transport.http.client.HttpClientFactory;
2724
import java.io.FileInputStream;
2825
import java.net.URI;
2926
import java.security.KeyStore;
30-
import java.util.HashMap;
31-
import java.util.Map;
3227
import javax.net.ssl.KeyManagerFactory;
3328
import javax.net.ssl.SSLContext;
3429
import javax.net.ssl.TrustManagerFactory;
@@ -98,21 +93,11 @@ protected SSLContext getContext() throws Exception
9893
@Override
9994
protected Client createClient(FilterChain filters) throws Exception
10095
{
101-
final Map<String, Object> properties = new HashMap<>();
102-
103-
SSLContext context = getContext();
104-
properties.put(HttpClientFactory.HTTP_SSL_CONTEXT, context);
105-
properties.put(HttpClientFactory.HTTP_SSL_PARAMS, context.getDefaultSSLParameters());
106-
107-
final TransportClient client = new HttpClientFactory.Builder()
108-
.setFilterChain(filters)
109-
.build()
110-
.getClient(properties);
111-
return new TransportClientAdapter(client, _clientROS);
96+
return Bootstrap.createHttpsClient(filters, _clientROS, getContext(), null);
11297
}
11398

11499
@Override
115-
protected Server createServer(FilterChain filters)
100+
protected Server createServer(FilterChain filters) throws Exception
116101
{
117102
return Bootstrap.createHttpsServer(_port, keyStore, keyStorePassword, filters, _serverROS);
118103
}

r2-int-test/src/test/java/test/r2/integ/TestHttpsEarlyHandshake.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import com.linkedin.r2.transport.http.client.common.ChannelPoolManagerFactoryImpl;
2323
import com.linkedin.r2.transport.http.client.common.ChannelPoolManagerKey;
2424
import com.linkedin.r2.transport.http.client.common.ChannelPoolManagerKeyBuilder;
25-
import com.linkedin.r2.transport.http.client.common.SslHandlerUtil;
25+
import com.linkedin.r2.transport.http.util.SslHandlerUtil;
2626
import io.netty.channel.Channel;
2727
import io.netty.channel.nio.NioEventLoopGroup;
2828
import io.netty.handler.ssl.SslHandler;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/*
2+
Copyright (c) 2018 LinkedIn Corp.
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 test.r2.integ;
18+
19+
import com.linkedin.common.callback.FutureCallback;
20+
import com.linkedin.r2.RemoteInvocationException;
21+
import com.linkedin.r2.filter.FilterChain;
22+
import com.linkedin.r2.sample.Bootstrap;
23+
import com.linkedin.r2.sample.echo.EchoService;
24+
import com.linkedin.r2.sample.echo.EchoServiceImpl;
25+
import com.linkedin.r2.sample.echo.rest.RestEchoClient;
26+
import com.linkedin.r2.sample.echo.rest.RestEchoServer;
27+
import com.linkedin.r2.transport.common.Client;
28+
import com.linkedin.r2.transport.common.Server;
29+
import com.linkedin.r2.transport.common.bridge.server.TransportDispatcher;
30+
import com.linkedin.r2.transport.common.bridge.server.TransportDispatcherBuilder;
31+
import com.linkedin.r2.transport.http.server.HttpNettyServerBuilder;
32+
import java.util.concurrent.TimeUnit;
33+
import org.testng.Assert;
34+
import org.testng.annotations.Factory;
35+
import org.testng.annotations.Test;
36+
import java.net.URI;
37+
38+
39+
/**
40+
* @author Dengpan Yin
41+
*/
42+
public class TestNettyHttpsEcho extends AbstractTestHttps
43+
{
44+
private static final int TEST_CASE_TIME_OUT = 10000;
45+
private static final int CALL_BACK_TIME_OUT = 1000;
46+
47+
@Factory(dataProvider = "configs")
48+
public TestNettyHttpsEcho(boolean clientROS, boolean serverROS, int port)
49+
{
50+
super(clientROS, serverROS, port);
51+
}
52+
53+
@Override
54+
protected Server createServer(FilterChain filters) throws Exception
55+
{
56+
return createHttpsServer(filters, _port);
57+
}
58+
59+
protected TransportDispatcher getTransportDispatcher()
60+
{
61+
return new TransportDispatcherBuilder()
62+
.addRestHandler(Bootstrap.getEchoURI(), new RestEchoServer(new EchoServiceImpl()))
63+
.build();
64+
}
65+
66+
protected Server createHttpServer(FilterChain filters, int port) throws Exception
67+
{
68+
final TransportDispatcher dispatcher = getTransportDispatcher();
69+
70+
return new HttpNettyServerBuilder().filters(filters).port(port).transportDispatcher(dispatcher).build();
71+
}
72+
73+
protected Server createHttpsServer(FilterChain filters, int port) throws Exception
74+
{
75+
final TransportDispatcher dispatcher = getTransportDispatcher();
76+
77+
return new HttpNettyServerBuilder()
78+
.port(port)
79+
.filters(filters)
80+
.transportDispatcher(dispatcher)
81+
.sslContext(getContext()).build();
82+
}
83+
84+
/**
85+
* SSL disabled Netty server is able to process http request from SSL enabled netty client.
86+
*/
87+
@Test(timeOut = TEST_CASE_TIME_OUT)
88+
public void testInsecureServerProcessHttpRequestFromSecureClient() throws Exception
89+
{
90+
testInsecureServerProcessRequestFromSecureClient(true);
91+
}
92+
93+
/**
94+
* SSL disabled Netty server is unable to process https request from SSL enabled netty client
95+
*/
96+
@Test(timeOut = TEST_CASE_TIME_OUT)
97+
public void testInsecureServerProcessHttpsRequestFromSecureClient() throws Exception
98+
{
99+
testInsecureServerProcessRequestFromSecureClient(false);
100+
}
101+
102+
/**
103+
* SSL enabled Netty server is unable to process http request from SSL disabled netty client.
104+
*/
105+
@Test(timeOut = TEST_CASE_TIME_OUT)
106+
public void testSecureServerProcessHttpRequestFromInsecureClient() throws Exception
107+
{
108+
testSecureServerProcessRequestFromInsecureClient(true);
109+
}
110+
111+
/**
112+
* SSL enabled Netty server is unable to process https request from SSL disabled netty client.
113+
*/
114+
@Test(timeOut = TEST_CASE_TIME_OUT)
115+
public void testSecureServerProcessHttpsRequestFromInsecureClient() throws Exception
116+
{
117+
testSecureServerProcessRequestFromInsecureClient(false);
118+
}
119+
120+
private void testInsecureServerProcessRequestFromSecureClient(boolean httpUri) throws Exception
121+
{
122+
final FilterChain filters = getServerFilters();
123+
final Client client = createClient(filters);
124+
final int port = _port + 1;
125+
final URI uri = httpUri ? Bootstrap.createHttpURI(port, Bootstrap.getEchoURI()) : Bootstrap.createHttpsURI(port, Bootstrap.getEchoURI());
126+
final EchoService echoClient = new RestEchoClient(uri, client);
127+
final Server server = createHttpServer(filters, port);
128+
129+
try
130+
{
131+
server.start();
132+
final FutureCallback<String> callback = new FutureCallback<String>();
133+
echoClient.echo(ECHO_MSG, callback);
134+
135+
final String actual = callback.get(CALL_BACK_TIME_OUT, TimeUnit.MILLISECONDS);
136+
if (httpUri)
137+
{
138+
Assert.assertEquals(actual, ECHO_MSG);
139+
}
140+
else
141+
{
142+
Assert.fail("Should have thrown an exception.");
143+
}
144+
}
145+
catch (Exception e)
146+
{
147+
if (!httpUri)
148+
{
149+
Assert.assertTrue(e.getCause() instanceof RemoteInvocationException);
150+
}
151+
else
152+
{
153+
Assert.fail("Unexpected Exception:", e);
154+
}
155+
}
156+
finally
157+
{
158+
tearDown(client, server);
159+
}
160+
}
161+
162+
private void testSecureServerProcessRequestFromInsecureClient(boolean httpUri) throws Exception
163+
{
164+
final FilterChain filters = getServerFilters();
165+
final Client client = Bootstrap.createHttpClient(filters, _clientROS);
166+
final int port = _port + 1;
167+
final URI uri = httpUri ? Bootstrap.createHttpURI(port, Bootstrap.getEchoURI()) : Bootstrap.createHttpsURI(port, Bootstrap.getEchoURI());
168+
final EchoService echoClient = new RestEchoClient(uri, client);
169+
final Server server = createHttpsServer(filters, port);
170+
171+
try
172+
{
173+
server.start();
174+
final FutureCallback<String> callback = new FutureCallback<String>();
175+
echoClient.echo(ECHO_MSG, callback);
176+
177+
callback.get(CALL_BACK_TIME_OUT, TimeUnit.MILLISECONDS);
178+
Assert.fail("Should have thrown an exception.");
179+
}
180+
catch (Exception e)
181+
{
182+
Assert.assertTrue(e.getCause() instanceof RemoteInvocationException);
183+
}
184+
finally
185+
{
186+
tearDown(client, server);
187+
}
188+
}
189+
}

0 commit comments

Comments
 (0)