Added SSL support.

This commit is contained in:
Simone Bordet 2012-01-27 22:02:39 +01:00
parent 298605aebd
commit ffe10f3cf8
9 changed files with 143 additions and 76992 deletions

View File

@ -14,6 +14,8 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import org.eclipse.jetty.io.AsyncEndPoint; import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.io.ConnectedEndPoint; import org.eclipse.jetty.io.ConnectedEndPoint;
@ -21,6 +23,7 @@ import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.nio.AsyncConnection; import org.eclipse.jetty.io.nio.AsyncConnection;
import org.eclipse.jetty.io.nio.SelectChannelEndPoint; import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
import org.eclipse.jetty.io.nio.SelectorManager; import org.eclipse.jetty.io.nio.SelectorManager;
import org.eclipse.jetty.io.nio.SslConnection;
import org.eclipse.jetty.spdy.CompressionFactory; import org.eclipse.jetty.spdy.CompressionFactory;
import org.eclipse.jetty.spdy.CompressionFactory.Compressor; import org.eclipse.jetty.spdy.CompressionFactory.Compressor;
import org.eclipse.jetty.spdy.CompressionFactory.Decompressor; import org.eclipse.jetty.spdy.CompressionFactory.Decompressor;
@ -32,6 +35,7 @@ import org.eclipse.jetty.spdy.api.Session.FrameListener;
import org.eclipse.jetty.spdy.generator.Generator; import org.eclipse.jetty.spdy.generator.Generator;
import org.eclipse.jetty.spdy.parser.Parser; import org.eclipse.jetty.spdy.parser.Parser;
import org.eclipse.jetty.util.component.AggregateLifeCycle; import org.eclipse.jetty.util.component.AggregateLifeCycle;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ThreadPool; import org.eclipse.jetty.util.thread.ThreadPool;
@ -93,6 +97,23 @@ public class SPDYClient
this.maxIdleTime = maxIdleTime; this.maxIdleTime = maxIdleTime;
} }
protected SSLEngine newSSLEngine(SslContextFactory sslContextFactory, SocketChannel channel)
{
try
{
String peerHost = channel.socket().getInetAddress().getHostAddress();
int peerPort = channel.socket().getPort();
SSLEngine engine = sslContextFactory.newSslEngine(peerHost, peerPort);
engine.setUseClientMode(true);
engine.beginHandshake();
return engine;
}
catch (SSLException x)
{
throw new RuntimeException(x);
}
}
protected CompressionFactory newCompressionFactory() protected CompressionFactory newCompressionFactory()
{ {
return new StandardCompressionFactory(); return new StandardCompressionFactory();
@ -118,19 +139,34 @@ public class SPDYClient
public static class Factory extends AggregateLifeCycle public static class Factory extends AggregateLifeCycle
{ {
private final ThreadPool threadPool; private final ThreadPool threadPool;
private final SslContextFactory sslContextFactory;
private final SelectorManager selector; private final SelectorManager selector;
public Factory() public Factory()
{ {
this(null); this(null, null);
}
public Factory(SslContextFactory sslContextFactory)
{
this(null, sslContextFactory);
} }
public Factory(ThreadPool threadPool) public Factory(ThreadPool threadPool)
{
this(threadPool, null);
}
public Factory(ThreadPool threadPool, SslContextFactory sslContextFactory)
{ {
if (threadPool == null) if (threadPool == null)
threadPool = new QueuedThreadPool(); threadPool = new QueuedThreadPool();
this.threadPool = threadPool; this.threadPool = threadPool;
addBean(this.threadPool); addBean(threadPool);
this.sslContextFactory = sslContextFactory;
if (sslContextFactory != null)
addBean(sslContextFactory);
selector = new ClientSelectorManager(); selector = new ClientSelectorManager();
addBean(selector); addBean(selector);
@ -164,10 +200,9 @@ public class SPDYClient
maxIdleTime = getMaxIdleTime(); maxIdleTime = getMaxIdleTime();
SelectChannelEndPoint result = new SelectChannelEndPoint(channel, selectSet, key, (int)maxIdleTime); SelectChannelEndPoint result = new SelectChannelEndPoint(channel, selectSet, key, (int)maxIdleTime);
// TODO: handle SSL
AsyncConnection connection = newConnection(channel, result, attachment); AsyncConnection connection = newConnection(channel, result, attachment);
result.setConnection(connection); result.setConnection(connection);
return result; return result;
} }
@ -193,13 +228,24 @@ public class SPDYClient
SessionFuture sessionFuture = (SessionFuture)attachment; SessionFuture sessionFuture = (SessionFuture)attachment;
SPDYClient client = sessionFuture.client; SPDYClient client = sessionFuture.client;
if (sslContextFactory != null)
{
SSLEngine engine = client.newSSLEngine(sslContextFactory, channel);
SslConnection sslConnection = new SslConnection(engine, endPoint);
endPoint.setConnection(sslConnection);
endPoint = sslConnection.getSslEndPoint();
}
CompressionFactory compressionFactory = client.newCompressionFactory(); CompressionFactory compressionFactory = client.newCompressionFactory();
Parser parser = client.newParser(compressionFactory.newDecompressor()); Parser parser = client.newParser(compressionFactory.newDecompressor());
Generator generator = client.newGenerator(compressionFactory.newCompressor()); Generator generator = client.newGenerator(compressionFactory.newCompressor());
AsyncSPDYConnection connection = new AsyncSPDYConnection(endPoint, parser); AsyncSPDYConnection connection = new AsyncSPDYConnection(endPoint, parser);
endPoint.setConnection(connection);
Session session = client.newSession(connection, sessionFuture.listener, parser, generator); Session session = client.newSession(connection, sessionFuture.listener, parser, generator);
sessionFuture.connected(session); sessionFuture.connected(session);
return connection; return connection;
} }
} }

View File

@ -1,9 +1,12 @@
package org.eclipse.jetty.spdy.nio; package org.eclipse.jetty.spdy.nio;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import org.eclipse.jetty.io.AsyncEndPoint; import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.io.nio.AsyncConnection; import org.eclipse.jetty.io.nio.AsyncConnection;
import org.eclipse.jetty.io.nio.SslConnection;
import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.spdy.CompressionFactory; import org.eclipse.jetty.spdy.CompressionFactory;
import org.eclipse.jetty.spdy.ISession; import org.eclipse.jetty.spdy.ISession;
@ -13,26 +16,47 @@ import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.spdy.generator.Generator; import org.eclipse.jetty.spdy.generator.Generator;
import org.eclipse.jetty.spdy.parser.Parser; import org.eclipse.jetty.spdy.parser.Parser;
import org.eclipse.jetty.util.ssl.SslContextFactory;
public class SPDYServerConnector extends SelectChannelConnector public class SPDYServerConnector extends SelectChannelConnector
{ {
private final ServerSessionFrameListener listener; private final ServerSessionFrameListener listener;
private final SslContextFactory sslContextFactory;
public SPDYServerConnector(ServerSessionFrameListener listener) public SPDYServerConnector(ServerSessionFrameListener listener)
{
this(listener, null);
}
public SPDYServerConnector(ServerSessionFrameListener listener, SslContextFactory sslContextFactory)
{ {
this.listener = listener; this.listener = listener;
this.sslContextFactory = sslContextFactory;
if (sslContextFactory != null)
addBean(sslContextFactory);
} }
@Override @Override
protected AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endPoint) protected AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endPoint)
{ {
if (sslContextFactory != null)
{
SSLEngine engine = newSSLEngine(sslContextFactory, channel);
SslConnection sslConnection = new SslConnection(engine, endPoint);
endPoint.setConnection(sslConnection);
endPoint = sslConnection.getSslEndPoint();
}
CompressionFactory compressionFactory = newCompressionFactory(); CompressionFactory compressionFactory = newCompressionFactory();
Parser parser = newParser(compressionFactory.newDecompressor()); Parser parser = newParser(compressionFactory.newDecompressor());
Generator generator = newGenerator(compressionFactory.newCompressor()); Generator generator = newGenerator(compressionFactory.newCompressor());
AsyncSPDYConnection connection = new AsyncSPDYConnection(endPoint, parser); AsyncSPDYConnection connection = new AsyncSPDYConnection(endPoint, parser);
endPoint.setConnection(connection);
Session session = newSession(connection, listener, parser, generator); Session session = newSession(connection, listener, parser, generator);
// TODO: this is called in the selector thread, which is not good
// NPE guard to support tests // NPE guard to support tests
if (listener != null) if (listener != null)
listener.onConnect(session); listener.onConnect(session);
@ -40,6 +64,23 @@ public class SPDYServerConnector extends SelectChannelConnector
return connection; return connection;
} }
protected SSLEngine newSSLEngine(SslContextFactory sslContextFactory, SocketChannel channel)
{
try
{
String peerHost = channel.socket().getInetAddress().getHostAddress();
int peerPort = channel.socket().getPort();
SSLEngine engine = sslContextFactory.newSslEngine(peerHost, peerPort);
engine.setUseClientMode(false);
engine.beginHandshake();
return engine;
}
catch (SSLException x)
{
throw new RuntimeException(x);
}
}
protected CompressionFactory newCompressionFactory() protected CompressionFactory newCompressionFactory()
{ {
return new StandardCompressionFactory(); return new StandardCompressionFactory();

View File

@ -8,10 +8,12 @@ import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.spdy.nio.SPDYClient; import org.eclipse.jetty.spdy.nio.SPDYClient;
import org.eclipse.jetty.spdy.nio.SPDYServerConnector; import org.eclipse.jetty.spdy.nio.SPDYServerConnector;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ThreadPool;
import org.junit.After; import org.junit.After;
public class SPDYTest public abstract class SPDYTest
{ {
private Server server; private Server server;
private SPDYClient.Factory clientFactory; private SPDYClient.Factory clientFactory;
@ -25,18 +27,39 @@ public class SPDYTest
return new InetSocketAddress(connector.getLocalPort()); return new InetSocketAddress(connector.getLocalPort());
} }
protected Connector newSPDYServerConnector(ServerSessionFrameListener listener)
{
return new SPDYServerConnector(listener);
}
protected Session startClient(InetSocketAddress socketAddress, Session.FrameListener frameListener) throws Exception protected Session startClient(InetSocketAddress socketAddress, Session.FrameListener frameListener) throws Exception
{ {
if (clientFactory == null) if (clientFactory == null)
{ {
QueuedThreadPool threadPool = new QueuedThreadPool(); QueuedThreadPool threadPool = new QueuedThreadPool();
threadPool.setName(threadPool.getName() + "-client"); threadPool.setName(threadPool.getName() + "-client");
clientFactory = new SPDYClient.Factory(threadPool); clientFactory = newSPDYClientFactory(threadPool);
clientFactory.start(); clientFactory.start();
} }
return clientFactory.newSPDYClient().connect(socketAddress, frameListener).get(); return clientFactory.newSPDYClient().connect(socketAddress, frameListener).get();
} }
protected SPDYClient.Factory newSPDYClientFactory(ThreadPool threadPool)
{
return new SPDYClient.Factory(threadPool);
}
protected SslContextFactory newSslContextFactory()
{
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
sslContextFactory.setKeyStorePassword("storepwd");
sslContextFactory.setTrustStore("src/test/resources/truststore.jks");
sslContextFactory.setTrustStorePassword("storepwd");
sslContextFactory.setProtocol("TLSv1");
return sslContextFactory;
}
@After @After
public void destroy() throws Exception public void destroy() throws Exception
{ {

View File

@ -0,0 +1,25 @@
package org.eclipse.jetty.spdy;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.spdy.nio.SPDYClient;
import org.eclipse.jetty.spdy.nio.SPDYServerConnector;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.ThreadPool;
public class SSLSPDYSynReplyTest extends SPDYSynReplyTest
{
@Override
protected Connector newSPDYServerConnector(ServerSessionFrameListener listener)
{
SslContextFactory sslContextFactory = newSslContextFactory();
return new SPDYServerConnector(listener, sslContextFactory);
}
@Override
protected SPDYClient.Factory newSPDYClientFactory(ThreadPool threadPool)
{
SslContextFactory sslContextFactory = newSslContextFactory();
return new SPDYClient.Factory(threadPool, sslContextFactory);
}
}

View File

@ -1,13 +0,0 @@
package org.eclipse.jetty.spdy;
import org.junit.Ignore;
import org.junit.Test;
public class SSLWithNPNTest
{
@Ignore
@Test
public void testSSLWithNPN()
{
}
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -11,3 +11,4 @@ log4j.appender.CONSOLE.target=System.err
# Level tuning # Level tuning
log4j.logger.org.eclipse.jetty=INFO log4j.logger.org.eclipse.jetty=INFO
#log4j.logger.org.eclipse.jetty.spdy=DEBUG

Binary file not shown.