blob: 33fea7a3ce6f6a109f6ce3fe717b3170a0442729 [file] [log] [blame]
package org.apache.jmeter.util;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicReference;
import javax.net.ssl.SSLSocket;
/**
* Uses the underlying implementation to support Server Name Indication (SNI).
* @author Michael Locher <cmbntr@gmail.com>
* @see <a href="https://issues.apache.org/jira/browse/HTTPCLIENT-1119">HTTPCLIENT-1119</a>
* @since 3.1 (extracted from JMeterClientConnectionOperator.java)
*/
public class HostNameSetter {
private static final AtomicReference<HostNameSetter> CURRENT = new AtomicReference<>();
private final WeakReference<Class<?>> cls;
private final WeakReference<Method> setter;
private HostNameSetter(Class<?> clazz, Method setter) {
this.cls = new WeakReference<Class<?>>(clazz);
this.setter = setter == null ? null : new WeakReference<>(setter);
}
private static Method init(Class<?> cls) {
Method s = null;
try {
s = cls.getMethod("setHost", String.class);
} catch (Exception e) {
initFail(e);
}
CURRENT.set(new HostNameSetter(cls, s));
return s;
}
private static void initFail(Exception e) {
// ignore
}
private Method reuse(Class<?> cls) {
final boolean wrongClass = this.cls.get() != cls;
if (wrongClass) {
return init(cls);
}
final boolean setterNotSupported = this.setter == null;
if (setterNotSupported) {
return null;
}
final Method s = setter.get();
final boolean setterLost = s == null;
return setterLost ? init(cls) : s;
}
/**
* Invokes the {@code #setName(String)} method if one is present.
*
* @param hostname the name to set
* @param sslsock the socket
*/
public static void setServerNameIndication(String hostname, SSLSocket sslsock) {
final Class<?> cls = sslsock.getClass();
final HostNameSetter current = CURRENT.get();
final Method setter = (current == null) ? init(cls) : current.reuse(cls);
if (setter != null) {
try {
setter.invoke(sslsock, hostname);
} catch (IllegalArgumentException
| IllegalAccessException
| InvocationTargetException e) {
setServerNameIndicationFail(e);
}
}
}
private static void setServerNameIndicationFail(Exception e) {
// ignore
}
}