package sslnpn;
import static org.junit.Assert.assertEquals;
import java.net.InetSocketAddress;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.net.ssl.SSLContext;
import org.junit.Before;
import org.junit.Test;
import sslnpn.ssl.SSLEngineImpl;
public class SSLEngineTest {
private SSLContext context;
@Before
public void before() throws Exception {
context = SSLContextCreator.newContext();
}
@Test
public void testConnectToServerWithFallback() throws Exception {
PortAndFuture portAndFuture = spawnServer("http/1.1", "spdy/2");
SSLEngineImpl engine = (SSLEngineImpl) context.createSSLEngine();
SocketChannel channel = SocketChannel.open();
try {
channel.connect(new InetSocketAddress("127.0.0.1", portAndFuture.port));
engine.setNextProtocolNegotiationFallbackAndChoices("spdy/3", "spdy/3");
engine.setUseClientMode(true);
SSLEngineHandshaker.negotiateHandshake(engine, channel);
assertEquals("spdy/3", engine.getNegotiatedNextProtocol());
assertEquals("spdy/3", portAndFuture.future.get());
} finally {
channel.close();
}
}
private static class PortAndFuture {
private int port;
private Future<String> future;
public PortAndFuture(int port, Future<String> future) {
this.port = port;
this.future = future;
}
}
private PortAndFuture spawnServer(final String... protocols) throws Exception {
final ServerSocketChannel channel = ServerSocketChannel.open();
channel.bind(null);
int port = ((InetSocketAddress)channel.getLocalAddress()).getPort();
Future<String> future = Executors.newCachedThreadPool().submit(new Callable<String>() {
@Override
public String call() throws Exception {
try {
SocketChannel clientChannel = channel.accept();
try {
final SSLEngineImpl engine = (SSLEngineImpl) context.createSSLEngine();
engine.setUseClientMode(false);
engine.setAdvertisedNextProtocols(protocols);
SSLEngineHandshaker.negotiateHandshake(engine, clientChannel);
return engine.getNegotiatedNextProtocol();
} finally {
clientChannel.close();
}
} finally {
channel.close();
}
}
});
return new PortAndFuture(port, future);
}
}