Ensure no java.lang.UnsupportedClassVersionError are thrown if running on Java7 and try to check if conscrypt is available.
Motivation:
We need to ensure we not try to load any conscrypt classes directly (which means without using reflection) in the same class that is used to check if conscrypt is available. This is needed as otherwise we will have the following problem when try to use netty on java7:
java.lang.UnsupportedClassVersionError: org/conscrypt/BufferAllocator : Unsupported major.minor version 52.0
at io.netty.handler.ssl.ConscryptJdkSslEngineInteropTest.checkConscrypt(ConscryptJdkSslEngineInteropTest.java:49)
This regression was introduced by 4448b8f42f
and detected on the CI when using:
mvn clean package -DtestJavaHome=$JAVA7_HOME
Modifications:
Move the detection code in an extra class and use it.
Result:
Works correctly also when using Java7.
This commit is contained in:
parent
4bb89dcc54
commit
32f497760f
70
handler/src/main/java/io/netty/handler/ssl/Conscrypt.java
Normal file
70
handler/src/main/java/io/netty/handler/ssl/Conscrypt.java
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.handler.ssl;
|
||||||
|
|
||||||
|
import io.netty.util.internal.PlatformDependent;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLEngine;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains methods that can be used to detect if conscrypt is usable.
|
||||||
|
*/
|
||||||
|
final class Conscrypt {
|
||||||
|
// This class exists to avoid loading other conscrypt related classes using features only available in JDK8+,
|
||||||
|
// because we need to maintain JDK6+ runtime compatibility.
|
||||||
|
private static final Class<?> ENGINES_CLASS = getEnginesClass();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether or not conscrypt is available on the current system.
|
||||||
|
*/
|
||||||
|
static boolean isAvailable() {
|
||||||
|
return ENGINES_CLASS != null && PlatformDependent.javaVersion() >= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isEngineSupported(SSLEngine engine) {
|
||||||
|
return isAvailable() && isConscryptEngine(engine, ENGINES_CLASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Class<?> getEnginesClass() {
|
||||||
|
try {
|
||||||
|
// Always use bootstrap class loader.
|
||||||
|
Class<?> engineClass = Class.forName("org.conscrypt.Conscrypt$Engines", true,
|
||||||
|
ConscryptAlpnSslEngine.class.getClassLoader());
|
||||||
|
// Ensure that it also has the isConscrypt method.
|
||||||
|
getIsConscryptMethod(engineClass);
|
||||||
|
return engineClass;
|
||||||
|
} catch (Throwable ignore) {
|
||||||
|
// Conscrypt was not loaded.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isConscryptEngine(SSLEngine engine, Class<?> enginesClass) {
|
||||||
|
try {
|
||||||
|
Method method = getIsConscryptMethod(enginesClass);
|
||||||
|
return (Boolean) method.invoke(null, engine);
|
||||||
|
} catch (Throwable ignore) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Method getIsConscryptMethod(Class<?> enginesClass) throws NoSuchMethodException {
|
||||||
|
return enginesClass.getMethod("isConscrypt", SSLEngine.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Conscrypt() { }
|
||||||
|
}
|
@ -23,7 +23,6 @@ import io.netty.buffer.ByteBuf;
|
|||||||
import io.netty.buffer.ByteBufAllocator;
|
import io.netty.buffer.ByteBufAllocator;
|
||||||
import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
|
import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
|
||||||
import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
|
import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
@ -32,7 +31,6 @@ import javax.net.ssl.SSLEngine;
|
|||||||
import javax.net.ssl.SSLEngineResult;
|
import javax.net.ssl.SSLEngineResult;
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
|
|
||||||
import io.netty.util.internal.PlatformDependent;
|
|
||||||
import io.netty.util.internal.SystemPropertyUtil;
|
import io.netty.util.internal.SystemPropertyUtil;
|
||||||
import org.conscrypt.AllocatedBuffer;
|
import org.conscrypt.AllocatedBuffer;
|
||||||
import org.conscrypt.BufferAllocator;
|
import org.conscrypt.BufferAllocator;
|
||||||
@ -45,18 +43,6 @@ import org.conscrypt.HandshakeListener;
|
|||||||
abstract class ConscryptAlpnSslEngine extends JdkSslEngine {
|
abstract class ConscryptAlpnSslEngine extends JdkSslEngine {
|
||||||
private static final boolean USE_BUFFER_ALLOCATOR = SystemPropertyUtil.getBoolean(
|
private static final boolean USE_BUFFER_ALLOCATOR = SystemPropertyUtil.getBoolean(
|
||||||
"io.netty.handler.ssl.conscrypt.useBufferAllocator", true);
|
"io.netty.handler.ssl.conscrypt.useBufferAllocator", true);
|
||||||
private static final Class<?> ENGINES_CLASS = getEnginesClass();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates whether or not conscrypt is available on the current system.
|
|
||||||
*/
|
|
||||||
static boolean isAvailable() {
|
|
||||||
return ENGINES_CLASS != null && PlatformDependent.javaVersion() >= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean isEngineSupported(SSLEngine engine) {
|
|
||||||
return isAvailable() && isConscryptEngine(engine, ENGINES_CLASS);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ConscryptAlpnSslEngine newClientEngine(SSLEngine engine, ByteBufAllocator alloc,
|
static ConscryptAlpnSslEngine newClientEngine(SSLEngine engine, ByteBufAllocator alloc,
|
||||||
JdkApplicationProtocolNegotiator applicationNegotiator) {
|
JdkApplicationProtocolNegotiator applicationNegotiator) {
|
||||||
@ -168,33 +154,6 @@ abstract class ConscryptAlpnSslEngine extends JdkSslEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Class<?> getEnginesClass() {
|
|
||||||
try {
|
|
||||||
// Always use bootstrap class loader.
|
|
||||||
Class<?> engineClass = Class.forName("org.conscrypt.Conscrypt$Engines", true,
|
|
||||||
ConscryptAlpnSslEngine.class.getClassLoader());
|
|
||||||
// Ensure that it also has the isConscrypt method.
|
|
||||||
getIsConscryptMethod(engineClass);
|
|
||||||
return engineClass;
|
|
||||||
} catch (Throwable ignore) {
|
|
||||||
// Conscrypt was not loaded.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isConscryptEngine(SSLEngine engine, Class<?> enginesClass) {
|
|
||||||
try {
|
|
||||||
Method method = getIsConscryptMethod(enginesClass);
|
|
||||||
return (Boolean) method.invoke(null, engine);
|
|
||||||
} catch (Throwable ignore) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Method getIsConscryptMethod(Class<?> enginesClass) throws NoSuchMethodException {
|
|
||||||
return enginesClass.getMethod("isConscrypt", SSLEngine.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class BufferAllocatorAdapter extends BufferAllocator {
|
private static final class BufferAllocatorAdapter extends BufferAllocator {
|
||||||
private final ByteBufAllocator alloc;
|
private final ByteBufAllocator alloc;
|
||||||
|
|
||||||
@ -214,7 +173,7 @@ abstract class ConscryptAlpnSslEngine extends JdkSslEngine {
|
|||||||
|
|
||||||
BufferAdapter(ByteBuf nettyBuffer) {
|
BufferAdapter(ByteBuf nettyBuffer) {
|
||||||
this.nettyBuffer = nettyBuffer;
|
this.nettyBuffer = nettyBuffer;
|
||||||
this.buffer = nettyBuffer.nioBuffer(0, nettyBuffer.capacity());
|
buffer = nettyBuffer.nioBuffer(0, nettyBuffer.capacity());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -22,7 +22,7 @@ import javax.net.ssl.SSLEngine;
|
|||||||
* The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}.
|
* The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}.
|
||||||
*/
|
*/
|
||||||
public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
|
public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
|
||||||
private static final boolean AVAILABLE = ConscryptAlpnSslEngine.isAvailable() || JettyAlpnSslEngine.isAvailable();
|
private static final boolean AVAILABLE = Conscrypt.isAvailable() || JettyAlpnSslEngine.isAvailable();
|
||||||
private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper();
|
private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -122,7 +122,7 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati
|
|||||||
@Override
|
@Override
|
||||||
public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc,
|
public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc,
|
||||||
JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) {
|
JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) {
|
||||||
if (ConscryptAlpnSslEngine.isEngineSupported(engine)) {
|
if (Conscrypt.isEngineSupported(engine)) {
|
||||||
return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine, alloc, applicationNegotiator)
|
return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine, alloc, applicationNegotiator)
|
||||||
: ConscryptAlpnSslEngine.newClientEngine(engine, alloc, applicationNegotiator);
|
: ConscryptAlpnSslEngine.newClientEngine(engine, alloc, applicationNegotiator);
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ public class ConscryptJdkSslEngineInteropTest extends SSLEngineTest {
|
|||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void checkConscrypt() {
|
public static void checkConscrypt() {
|
||||||
assumeTrue(ConscryptAlpnSslEngine.isAvailable());
|
assumeTrue(Conscrypt.isAvailable());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -46,7 +46,7 @@ public class JdkConscryptSslEngineInteropTest extends SSLEngineTest {
|
|||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void checkConscrypt() {
|
public static void checkConscrypt() {
|
||||||
assumeTrue(ConscryptAlpnSslEngine.isAvailable());
|
assumeTrue(Conscrypt.isAvailable());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -81,7 +81,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean isAvailable() {
|
boolean isAvailable() {
|
||||||
return ConscryptAlpnSslEngine.isAvailable();
|
return Conscrypt.isAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
Reference in New Issue
Block a user