Added SSL support.
This commit is contained in:
parent
298605aebd
commit
ffe10f3cf8
|
@ -14,6 +14,8 @@ import java.util.concurrent.ExecutionException;
|
|||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
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.ConnectedEndPoint;
|
||||
|
@ -21,6 +23,7 @@ import org.eclipse.jetty.io.Connection;
|
|||
import org.eclipse.jetty.io.nio.AsyncConnection;
|
||||
import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
|
||||
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.Compressor;
|
||||
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.parser.Parser;
|
||||
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.ThreadPool;
|
||||
|
||||
|
@ -93,6 +97,23 @@ public class SPDYClient
|
|||
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()
|
||||
{
|
||||
return new StandardCompressionFactory();
|
||||
|
@ -118,19 +139,34 @@ public class SPDYClient
|
|||
public static class Factory extends AggregateLifeCycle
|
||||
{
|
||||
private final ThreadPool threadPool;
|
||||
private final SslContextFactory sslContextFactory;
|
||||
private final SelectorManager selector;
|
||||
|
||||
public Factory()
|
||||
{
|
||||
this(null);
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
public Factory(SslContextFactory sslContextFactory)
|
||||
{
|
||||
this(null, sslContextFactory);
|
||||
}
|
||||
|
||||
public Factory(ThreadPool threadPool)
|
||||
{
|
||||
this(threadPool, null);
|
||||
}
|
||||
|
||||
public Factory(ThreadPool threadPool, SslContextFactory sslContextFactory)
|
||||
{
|
||||
if (threadPool == null)
|
||||
threadPool = new QueuedThreadPool();
|
||||
this.threadPool = threadPool;
|
||||
addBean(this.threadPool);
|
||||
addBean(threadPool);
|
||||
|
||||
this.sslContextFactory = sslContextFactory;
|
||||
if (sslContextFactory != null)
|
||||
addBean(sslContextFactory);
|
||||
|
||||
selector = new ClientSelectorManager();
|
||||
addBean(selector);
|
||||
|
@ -164,10 +200,9 @@ public class SPDYClient
|
|||
maxIdleTime = getMaxIdleTime();
|
||||
SelectChannelEndPoint result = new SelectChannelEndPoint(channel, selectSet, key, (int)maxIdleTime);
|
||||
|
||||
// TODO: handle SSL
|
||||
|
||||
AsyncConnection connection = newConnection(channel, result, attachment);
|
||||
result.setConnection(connection);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -193,13 +228,24 @@ public class SPDYClient
|
|||
SessionFuture sessionFuture = (SessionFuture)attachment;
|
||||
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();
|
||||
Parser parser = client.newParser(compressionFactory.newDecompressor());
|
||||
Generator generator = client.newGenerator(compressionFactory.newCompressor());
|
||||
|
||||
AsyncSPDYConnection connection = new AsyncSPDYConnection(endPoint, parser);
|
||||
endPoint.setConnection(connection);
|
||||
|
||||
Session session = client.newSession(connection, sessionFuture.listener, parser, generator);
|
||||
sessionFuture.connected(session);
|
||||
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
package org.eclipse.jetty.spdy.nio;
|
||||
|
||||
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.nio.AsyncConnection;
|
||||
import org.eclipse.jetty.io.nio.SslConnection;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.spdy.CompressionFactory;
|
||||
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.generator.Generator;
|
||||
import org.eclipse.jetty.spdy.parser.Parser;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
public class SPDYServerConnector extends SelectChannelConnector
|
||||
{
|
||||
private final ServerSessionFrameListener listener;
|
||||
private final SslContextFactory sslContextFactory;
|
||||
|
||||
public SPDYServerConnector(ServerSessionFrameListener listener)
|
||||
{
|
||||
this(listener, null);
|
||||
}
|
||||
|
||||
public SPDYServerConnector(ServerSessionFrameListener listener, SslContextFactory sslContextFactory)
|
||||
{
|
||||
this.listener = listener;
|
||||
this.sslContextFactory = sslContextFactory;
|
||||
if (sslContextFactory != null)
|
||||
addBean(sslContextFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
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();
|
||||
Parser parser = newParser(compressionFactory.newDecompressor());
|
||||
Generator generator = newGenerator(compressionFactory.newCompressor());
|
||||
|
||||
AsyncSPDYConnection connection = new AsyncSPDYConnection(endPoint, parser);
|
||||
endPoint.setConnection(connection);
|
||||
|
||||
Session session = newSession(connection, listener, parser, generator);
|
||||
|
||||
// TODO: this is called in the selector thread, which is not good
|
||||
// NPE guard to support tests
|
||||
if (listener != null)
|
||||
listener.onConnect(session);
|
||||
|
@ -40,6 +64,23 @@ public class SPDYServerConnector extends SelectChannelConnector
|
|||
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()
|
||||
{
|
||||
return new StandardCompressionFactory();
|
||||
|
|
|
@ -8,10 +8,12 @@ import org.eclipse.jetty.spdy.api.Session;
|
|||
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.QueuedThreadPool;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
import org.junit.After;
|
||||
|
||||
public class SPDYTest
|
||||
public abstract class SPDYTest
|
||||
{
|
||||
private Server server;
|
||||
private SPDYClient.Factory clientFactory;
|
||||
|
@ -19,24 +21,45 @@ public class SPDYTest
|
|||
protected InetSocketAddress startServer(ServerSessionFrameListener listener) throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
Connector connector = new SPDYServerConnector(listener);
|
||||
Connector connector = newSPDYServerConnector(listener);
|
||||
server.addConnector(connector);
|
||||
server.start();
|
||||
return new InetSocketAddress(connector.getLocalPort());
|
||||
}
|
||||
|
||||
protected Connector newSPDYServerConnector(ServerSessionFrameListener listener)
|
||||
{
|
||||
return new SPDYServerConnector(listener);
|
||||
}
|
||||
|
||||
protected Session startClient(InetSocketAddress socketAddress, Session.FrameListener frameListener) throws Exception
|
||||
{
|
||||
if (clientFactory == null)
|
||||
{
|
||||
QueuedThreadPool threadPool = new QueuedThreadPool();
|
||||
threadPool.setName(threadPool.getName() + "-client");
|
||||
clientFactory = new SPDYClient.Factory(threadPool);
|
||||
clientFactory = newSPDYClientFactory(threadPool);
|
||||
clientFactory.start();
|
||||
}
|
||||
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
|
||||
public void destroy() throws Exception
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
@ -11,3 +11,4 @@ log4j.appender.CONSOLE.target=System.err
|
|||
|
||||
# Level tuning
|
||||
log4j.logger.org.eclipse.jetty=INFO
|
||||
#log4j.logger.org.eclipse.jetty.spdy=DEBUG
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue