1 /* 2 * Copyright 2014 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.testing.integration; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertNotNull; 21 import static org.junit.Assert.assertTrue; 22 23 import com.google.common.base.Throwables; 24 import com.squareup.okhttp.ConnectionSpec; 25 import io.grpc.ChannelCredentials; 26 import io.grpc.ManagedChannel; 27 import io.grpc.ServerBuilder; 28 import io.grpc.ServerCredentials; 29 import io.grpc.TlsChannelCredentials; 30 import io.grpc.TlsServerCredentials; 31 import io.grpc.internal.GrpcUtil; 32 import io.grpc.internal.testing.StreamRecorder; 33 import io.grpc.internal.testing.TestUtils; 34 import io.grpc.netty.InternalNettyServerBuilder; 35 import io.grpc.netty.NettyServerBuilder; 36 import io.grpc.okhttp.InternalOkHttpChannelBuilder; 37 import io.grpc.okhttp.OkHttpChannelBuilder; 38 import io.grpc.okhttp.internal.Platform; 39 import io.grpc.stub.StreamObserver; 40 import io.grpc.testing.TlsTesting; 41 import io.grpc.testing.integration.EmptyProtos.Empty; 42 import java.io.IOException; 43 import java.net.InetSocketAddress; 44 import javax.net.ssl.HostnameVerifier; 45 import javax.net.ssl.SSLPeerUnverifiedException; 46 import javax.net.ssl.SSLSession; 47 import org.junit.Test; 48 import org.junit.runner.RunWith; 49 import org.junit.runners.JUnit4; 50 51 /** 52 * Integration tests for GRPC over Http2 using the OkHttp framework. 53 */ 54 @RunWith(JUnit4.class) 55 public class Http2OkHttpTest extends AbstractInteropTest { 56 57 private static final String BAD_HOSTNAME = "I.am.a.bad.hostname"; 58 59 @Override getServerBuilder()60 protected ServerBuilder<?> getServerBuilder() { 61 // Starts the server with HTTPS. 62 try { 63 ServerCredentials serverCreds = TlsServerCredentials.create( 64 TlsTesting.loadCert("server1.pem"), TlsTesting.loadCert("server1.key")); 65 NettyServerBuilder builder = NettyServerBuilder.forPort(0, serverCreds) 66 .flowControlWindow(AbstractInteropTest.TEST_FLOW_CONTROL_WINDOW) 67 .maxInboundMessageSize(AbstractInteropTest.MAX_MESSAGE_SIZE); 68 // Disable the default census stats tracer, use testing tracer instead. 69 InternalNettyServerBuilder.setStatsEnabled(builder, false); 70 return builder.addStreamTracerFactory(createCustomCensusTracerFactory()); 71 } catch (IOException ex) { 72 throw new RuntimeException(ex); 73 } 74 } 75 76 @Override createChannelBuilder()77 protected OkHttpChannelBuilder createChannelBuilder() { 78 int port = ((InetSocketAddress) getListenAddress()).getPort(); 79 ChannelCredentials channelCreds; 80 try { 81 channelCreds = TlsChannelCredentials.newBuilder() 82 .trustManager(TlsTesting.loadCert("ca.pem")) 83 .build(); 84 } catch (IOException ex) { 85 throw new RuntimeException(ex); 86 } 87 OkHttpChannelBuilder builder = OkHttpChannelBuilder.forAddress("localhost", port, channelCreds) 88 .maxInboundMessageSize(AbstractInteropTest.MAX_MESSAGE_SIZE) 89 .overrideAuthority(GrpcUtil.authorityFromHostAndPort( 90 TestUtils.TEST_SERVER_HOST, port)); 91 // Disable the default census stats interceptor, use testing interceptor instead. 92 InternalOkHttpChannelBuilder.setStatsEnabled(builder, false); 93 return builder.intercept(createCensusStatsClientInterceptor()); 94 } 95 createChannelBuilderPreCredentialsApi()96 private OkHttpChannelBuilder createChannelBuilderPreCredentialsApi() { 97 int port = ((InetSocketAddress) getListenAddress()).getPort(); 98 OkHttpChannelBuilder builder = OkHttpChannelBuilder.forAddress("localhost", port) 99 .maxInboundMessageSize(AbstractInteropTest.MAX_MESSAGE_SIZE) 100 .connectionSpec(new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) 101 .build()) 102 .overrideAuthority(GrpcUtil.authorityFromHostAndPort( 103 TestUtils.TEST_SERVER_HOST, port)); 104 try { 105 builder.sslSocketFactory(TestUtils.newSslSocketFactoryForCa(Platform.get().getProvider(), 106 TestUtils.loadCert("ca.pem"))); 107 } catch (Exception e) { 108 throw new RuntimeException(e); 109 } 110 // Disable the default census stats interceptor, use testing interceptor instead. 111 InternalOkHttpChannelBuilder.setStatsEnabled(builder, false); 112 return builder.intercept(createCensusStatsClientInterceptor()); 113 } 114 115 @Test receivedDataForFinishedStream()116 public void receivedDataForFinishedStream() throws Exception { 117 Messages.ResponseParameters.Builder responseParameters = 118 Messages.ResponseParameters.newBuilder() 119 .setSize(1); 120 Messages.StreamingOutputCallRequest.Builder requestBuilder = 121 Messages.StreamingOutputCallRequest.newBuilder(); 122 for (int i = 0; i < 1000; i++) { 123 requestBuilder.addResponseParameters(responseParameters); 124 } 125 126 StreamRecorder<Messages.StreamingOutputCallResponse> recorder = StreamRecorder.create(); 127 StreamObserver<Messages.StreamingOutputCallRequest> requestStream = 128 asyncStub.fullDuplexCall(recorder); 129 Messages.StreamingOutputCallRequest request = requestBuilder.build(); 130 requestStream.onNext(request); 131 recorder.firstValue().get(); 132 requestStream.onError(new Exception("failed")); 133 134 recorder.awaitCompletion(); 135 136 assertEquals(EMPTY, blockingStub.emptyCall(EMPTY)); 137 } 138 139 @Test wrongHostNameFailHostnameVerification()140 public void wrongHostNameFailHostnameVerification() throws Exception { 141 int port = ((InetSocketAddress) getListenAddress()).getPort(); 142 ManagedChannel channel = createChannelBuilderPreCredentialsApi() 143 .overrideAuthority(GrpcUtil.authorityFromHostAndPort( 144 BAD_HOSTNAME, port)) 145 .build(); 146 TestServiceGrpc.TestServiceBlockingStub blockingStub = 147 TestServiceGrpc.newBlockingStub(channel); 148 149 Throwable actualThrown = null; 150 try { 151 blockingStub.emptyCall(Empty.getDefaultInstance()); 152 } catch (Throwable t) { 153 actualThrown = t; 154 } 155 assertNotNull("The rpc should have been failed due to hostname verification", actualThrown); 156 Throwable cause = Throwables.getRootCause(actualThrown); 157 assertTrue( 158 "Failed by unexpected exception: " + cause, cause instanceof SSLPeerUnverifiedException); 159 channel.shutdown(); 160 } 161 162 @Test hostnameVerifierWithBadHostname()163 public void hostnameVerifierWithBadHostname() throws Exception { 164 int port = ((InetSocketAddress) getListenAddress()).getPort(); 165 ManagedChannel channel = createChannelBuilderPreCredentialsApi() 166 .overrideAuthority(GrpcUtil.authorityFromHostAndPort( 167 BAD_HOSTNAME, port)) 168 .hostnameVerifier(new HostnameVerifier() { 169 @Override 170 public boolean verify(String hostname, SSLSession session) { 171 return true; 172 } 173 }) 174 .build(); 175 TestServiceGrpc.TestServiceBlockingStub blockingStub = 176 TestServiceGrpc.newBlockingStub(channel); 177 178 blockingStub.emptyCall(Empty.getDefaultInstance()); 179 180 channel.shutdown(); 181 } 182 183 @Test hostnameVerifierWithCorrectHostname()184 public void hostnameVerifierWithCorrectHostname() throws Exception { 185 int port = ((InetSocketAddress) getListenAddress()).getPort(); 186 ManagedChannel channel = createChannelBuilderPreCredentialsApi() 187 .overrideAuthority(GrpcUtil.authorityFromHostAndPort( 188 TestUtils.TEST_SERVER_HOST, port)) 189 .hostnameVerifier(new HostnameVerifier() { 190 @Override 191 public boolean verify(String hostname, SSLSession session) { 192 return false; 193 } 194 }) 195 .build(); 196 TestServiceGrpc.TestServiceBlockingStub blockingStub = 197 TestServiceGrpc.newBlockingStub(channel); 198 199 Throwable actualThrown = null; 200 try { 201 blockingStub.emptyCall(Empty.getDefaultInstance()); 202 } catch (Throwable t) { 203 actualThrown = t; 204 } 205 assertNotNull("The rpc should have been failed due to hostname verification", actualThrown); 206 Throwable cause = Throwables.getRootCause(actualThrown); 207 assertTrue( 208 "Failed by unexpected exception: " + cause, cause instanceof SSLPeerUnverifiedException); 209 channel.shutdown(); 210 } 211 } 212