1 /* 2 * Copyright 2015 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.netty; 18 19 import java.lang.reflect.Method; 20 import java.security.AccessController; 21 import java.security.PrivilegedExceptionAction; 22 import javax.net.ssl.SSLContext; 23 import javax.net.ssl.SSLEngine; 24 25 /** 26 * Utility class for determining support for Jetty TLS ALPN/NPN. 27 */ 28 final class JettyTlsUtil { JettyTlsUtil()29 private JettyTlsUtil() { 30 } 31 32 private static Throwable jettyAlpnUnavailabilityCause; 33 private static Throwable jettyNpnUnavailabilityCause; 34 35 private static class Java9AlpnUnavailabilityCauseHolder { 36 37 @SuppressWarnings("StaticAssignmentOfThrowable") 38 static final Throwable cause = checkAlpnAvailability(); 39 checkAlpnAvailability()40 static Throwable checkAlpnAvailability() { 41 try { 42 SSLContext context = SSLContext.getInstance("TLS"); 43 context.init(null, null, null); 44 SSLEngine engine = context.createSSLEngine(); 45 Method getApplicationProtocol = 46 AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() { 47 @Override 48 public Method run() throws Exception { 49 return SSLEngine.class.getMethod("getApplicationProtocol"); 50 } 51 }); 52 getApplicationProtocol.invoke(engine); 53 return null; 54 } catch (Throwable t) { 55 return t; 56 } 57 } 58 } 59 60 /** Indicates whether or not the Jetty ALPN jar is installed in the boot classloader. */ 61 @SuppressWarnings("StaticAssignmentOfThrowable") isJettyAlpnConfigured()62 static synchronized boolean isJettyAlpnConfigured() { 63 try { 64 Class.forName("org.eclipse.jetty.alpn.ALPN", true, null); 65 return true; 66 } catch (ClassNotFoundException e) { 67 jettyAlpnUnavailabilityCause = e; 68 return false; 69 } 70 } 71 getJettyAlpnUnavailabilityCause()72 static synchronized Throwable getJettyAlpnUnavailabilityCause() { 73 // This case should be unlikely 74 if (jettyAlpnUnavailabilityCause == null) { 75 @SuppressWarnings("UnusedVariable") 76 boolean discard = isJettyAlpnConfigured(); 77 } 78 return jettyAlpnUnavailabilityCause; 79 } 80 81 /** Indicates whether or not the Jetty NPN jar is installed in the boot classloader. */ 82 @SuppressWarnings("StaticAssignmentOfThrowable") isJettyNpnConfigured()83 static synchronized boolean isJettyNpnConfigured() { 84 try { 85 Class.forName("org.eclipse.jetty.npn.NextProtoNego", true, null); 86 return true; 87 } catch (ClassNotFoundException e) { 88 jettyNpnUnavailabilityCause = e; 89 return false; 90 } 91 } 92 getJettyNpnUnavailabilityCause()93 static synchronized Throwable getJettyNpnUnavailabilityCause() { 94 // This case should be unlikely 95 if (jettyNpnUnavailabilityCause == null) { 96 @SuppressWarnings("UnusedVariable") 97 boolean discard = isJettyNpnConfigured(); 98 } 99 return jettyNpnUnavailabilityCause; 100 } 101 102 /** 103 * Indicates whether Java 9 ALPN is available. 104 */ isJava9AlpnAvailable()105 static boolean isJava9AlpnAvailable() { 106 return getJava9AlpnUnavailabilityCause() == null; 107 } 108 getJava9AlpnUnavailabilityCause()109 static Throwable getJava9AlpnUnavailabilityCause() { 110 return Java9AlpnUnavailabilityCauseHolder.cause; 111 } 112 } 113