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.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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -19,24 +21,45 @@ public class SPDYTest
|
||||||
protected InetSocketAddress startServer(ServerSessionFrameListener listener) throws Exception
|
protected InetSocketAddress startServer(ServerSessionFrameListener listener) throws Exception
|
||||||
{
|
{
|
||||||
server = new Server();
|
server = new Server();
|
||||||
Connector connector = new SPDYServerConnector(listener);
|
Connector connector = newSPDYServerConnector(listener);
|
||||||
server.addConnector(connector);
|
server.addConnector(connector);
|
||||||
server.start();
|
server.start();
|
||||||
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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
# 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.
Loading…
Reference in New Issue