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.ManagedChannel; 26 import io.grpc.internal.AbstractServerImplBuilder; 27 import io.grpc.internal.GrpcUtil; 28 import io.grpc.internal.testing.StreamRecorder; 29 import io.grpc.internal.testing.TestUtils; 30 import io.grpc.netty.GrpcSslContexts; 31 import io.grpc.netty.NettyServerBuilder; 32 import io.grpc.okhttp.OkHttpChannelBuilder; 33 import io.grpc.okhttp.internal.Platform; 34 import io.grpc.stub.StreamObserver; 35 import io.grpc.testing.integration.EmptyProtos.Empty; 36 import io.netty.handler.ssl.OpenSsl; 37 import io.netty.handler.ssl.SslContext; 38 import io.netty.handler.ssl.SslContextBuilder; 39 import io.netty.handler.ssl.SslProvider; 40 import io.netty.handler.ssl.SupportedCipherSuiteFilter; 41 import java.io.IOException; 42 import javax.net.ssl.HostnameVerifier; 43 import javax.net.ssl.SSLPeerUnverifiedException; 44 import javax.net.ssl.SSLSession; 45 import org.junit.BeforeClass; 46 import org.junit.Test; 47 import org.junit.runner.RunWith; 48 import org.junit.runners.JUnit4; 49 50 /** 51 * Integration tests for GRPC over Http2 using the OkHttp framework. 52 */ 53 @RunWith(JUnit4.class) 54 public class Http2OkHttpTest extends AbstractInteropTest { 55 56 private static final String BAD_HOSTNAME = "I.am.a.bad.hostname"; 57 58 @BeforeClass loadConscrypt()59 public static void loadConscrypt() throws Exception { 60 // Load conscrypt if it is available. Either Conscrypt or Jetty ALPN needs to be available for 61 // OkHttp to negotiate. 62 TestUtils.installConscryptIfAvailable(); 63 } 64 65 @Override getServerBuilder()66 protected AbstractServerImplBuilder<?> getServerBuilder() { 67 // Starts the server with HTTPS. 68 try { 69 SslProvider sslProvider = SslContext.defaultServerProvider(); 70 if (sslProvider == SslProvider.OPENSSL && !OpenSsl.isAlpnSupported()) { 71 // OkHttp only supports Jetty ALPN on OpenJDK. So if OpenSSL doesn't support ALPN, then we 72 // are forced to use Jetty ALPN for Netty instead of OpenSSL. 73 sslProvider = SslProvider.JDK; 74 } 75 SslContextBuilder contextBuilder = SslContextBuilder 76 .forServer(TestUtils.loadCert("server1.pem"), TestUtils.loadCert("server1.key")); 77 GrpcSslContexts.configure(contextBuilder, sslProvider); 78 contextBuilder.ciphers(TestUtils.preferredTestCiphers(), SupportedCipherSuiteFilter.INSTANCE); 79 return NettyServerBuilder.forPort(0) 80 .flowControlWindow(65 * 1024) 81 .maxInboundMessageSize(AbstractInteropTest.MAX_MESSAGE_SIZE) 82 .sslContext(contextBuilder.build()); 83 } catch (IOException ex) { 84 throw new RuntimeException(ex); 85 } 86 } 87 88 @Override createChannel()89 protected ManagedChannel createChannel() { 90 return createChannelBuilder().build(); 91 } 92 createChannelBuilder()93 private OkHttpChannelBuilder createChannelBuilder() { 94 OkHttpChannelBuilder builder = OkHttpChannelBuilder.forAddress("localhost", getPort()) 95 .maxInboundMessageSize(AbstractInteropTest.MAX_MESSAGE_SIZE) 96 .connectionSpec(new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) 97 .cipherSuites(TestUtils.preferredTestCiphers().toArray(new String[0])) 98 .build()) 99 .overrideAuthority(GrpcUtil.authorityFromHostAndPort( 100 TestUtils.TEST_SERVER_HOST, getPort())); 101 io.grpc.internal.TestingAccessor.setStatsImplementation( 102 builder, createClientCensusStatsModule()); 103 try { 104 builder.sslSocketFactory(TestUtils.newSslSocketFactoryForCa(Platform.get().getProvider(), 105 TestUtils.loadCert("ca.pem"))); 106 } catch (Exception e) { 107 throw new RuntimeException(e); 108 } 109 return builder; 110 } 111 112 @Test receivedDataForFinishedStream()113 public void receivedDataForFinishedStream() throws Exception { 114 Messages.ResponseParameters.Builder responseParameters = 115 Messages.ResponseParameters.newBuilder() 116 .setSize(1); 117 Messages.StreamingOutputCallRequest.Builder requestBuilder = 118 Messages.StreamingOutputCallRequest.newBuilder() 119 .setResponseType(Messages.PayloadType.COMPRESSABLE); 120 for (int i = 0; i < 1000; i++) { 121 requestBuilder.addResponseParameters(responseParameters); 122 } 123 124 StreamRecorder<Messages.StreamingOutputCallResponse> recorder = StreamRecorder.create(); 125 StreamObserver<Messages.StreamingOutputCallRequest> requestStream = 126 asyncStub.fullDuplexCall(recorder); 127 Messages.StreamingOutputCallRequest request = requestBuilder.build(); 128 requestStream.onNext(request); 129 recorder.firstValue().get(); 130 requestStream.onError(new Exception("failed")); 131 132 recorder.awaitCompletion(); 133 134 assertEquals(EMPTY, blockingStub.emptyCall(EMPTY)); 135 } 136 137 @Test wrongHostNameFailHostnameVerification()138 public void wrongHostNameFailHostnameVerification() throws Exception { 139 ManagedChannel channel = createChannelBuilder() 140 .overrideAuthority(GrpcUtil.authorityFromHostAndPort( 141 BAD_HOSTNAME, getPort())) 142 .build(); 143 TestServiceGrpc.TestServiceBlockingStub blockingStub = 144 TestServiceGrpc.newBlockingStub(channel); 145 146 Throwable actualThrown = null; 147 try { 148 blockingStub.emptyCall(Empty.getDefaultInstance()); 149 } catch (Throwable t) { 150 actualThrown = t; 151 } 152 assertNotNull("The rpc should have been failed due to hostname verification", actualThrown); 153 Throwable cause = Throwables.getRootCause(actualThrown); 154 assertTrue( 155 "Failed by unexpected exception: " + cause, cause instanceof SSLPeerUnverifiedException); 156 channel.shutdown(); 157 } 158 159 @Test hostnameVerifierWithBadHostname()160 public void hostnameVerifierWithBadHostname() throws Exception { 161 ManagedChannel channel = createChannelBuilder() 162 .overrideAuthority(GrpcUtil.authorityFromHostAndPort( 163 BAD_HOSTNAME, getPort())) 164 .hostnameVerifier(new HostnameVerifier() { 165 @Override 166 public boolean verify(String hostname, SSLSession session) { 167 return true; 168 } 169 }) 170 .build(); 171 TestServiceGrpc.TestServiceBlockingStub blockingStub = 172 TestServiceGrpc.newBlockingStub(channel); 173 174 blockingStub.emptyCall(Empty.getDefaultInstance()); 175 176 channel.shutdown(); 177 } 178 179 @Test hostnameVerifierWithCorrectHostname()180 public void hostnameVerifierWithCorrectHostname() throws Exception { 181 ManagedChannel channel = createChannelBuilder() 182 .overrideAuthority(GrpcUtil.authorityFromHostAndPort( 183 TestUtils.TEST_SERVER_HOST, getPort())) 184 .hostnameVerifier(new HostnameVerifier() { 185 @Override 186 public boolean verify(String hostname, SSLSession session) { 187 return false; 188 } 189 }) 190 .build(); 191 TestServiceGrpc.TestServiceBlockingStub blockingStub = 192 TestServiceGrpc.newBlockingStub(channel); 193 194 Throwable actualThrown = null; 195 try { 196 blockingStub.emptyCall(Empty.getDefaultInstance()); 197 } catch (Throwable t) { 198 actualThrown = t; 199 } 200 assertNotNull("The rpc should have been failed due to hostname verification", actualThrown); 201 Throwable cause = Throwables.getRootCause(actualThrown); 202 assertTrue( 203 "Failed by unexpected exception: " + cause, cause instanceof SSLPeerUnverifiedException); 204 channel.shutdown(); 205 } 206 } 207