From 48c803b6933524fc6581652ff8c18ff4bfbb9f5a Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Thu, 20 Mar 2014 15:26:09 +0100 Subject: [PATCH 1/2] JDK 8 build fix: now test uses LinkedHashMap to avoid random position of attributes in XML. --- .../eclipse/jetty/xml/XmlAppendableTest.java | 50 ++++++++++++------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlAppendableTest.java b/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlAppendableTest.java index 2639b10deac..6a1556e4ddd 100644 --- a/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlAppendableTest.java +++ b/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlAppendableTest.java @@ -18,7 +18,7 @@ package org.eclipse.jetty.xml; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import org.junit.Assert; @@ -31,24 +31,40 @@ public class XmlAppendableTest { StringBuilder b = new StringBuilder(); XmlAppendable out = new XmlAppendable(b); - Map attr = new HashMap<>(); - + Map attr = new LinkedHashMap<>(); + out.open("test"); - - attr.put("name","attr value"); - attr.put("noval",null); - attr.put("quotes","'\""); - + + attr.put("name", "attr value"); + attr.put("noval", null); + attr.put("quotes", "'\""); + out.tag("tag"); - out.tag("tag",attr); - out.tag("tag",attr,"content"); - - out.open("level1").tag("tag","content").tag("tag","content").close(); - out.open("level1",attr).open("level2").tag("tag","content").tag("tag","content").close().close(); - + out.tag("tag", attr); + out.tag("tag", attr, "content"); + + out.open("level1").tag("tag", "content").tag("tag", "content").close(); + out.open("level1", attr).open("level2").tag("tag", "content").tag("tag", "content").close().close(); + out.close(); - - String s = b.toString(); - Assert.assertEquals("\n\n \n \n content\n \n content\n content\n \n \n \n content\n content\n \n \n\n",s); + + String expected = "" + + "\n" + + "\n" + + " \n" + + " \n" + + " content\n" + + " \n" + + " content\n" + + " content\n" + + " \n" + + " \n" + + " \n" + + " content\n" + + " content\n" + + " \n" + + " \n" + + "\n"; + Assert.assertEquals(expected, b.toString()); } } From b994db698c8e223c92444a49d1fdfb2c27559b04 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Thu, 20 Mar 2014 16:22:43 +0100 Subject: [PATCH 2/2] Refactored NPN code for the soon-to-arrive ALPN code. Moved NPN tests to new module spdy-npn-tests, that now is the only module requiring the -Xbootclasspath configuration for the Maven Surefire Plugin. --- .../eclipse/jetty/embedded/SpdyConnector.java | 2 +- .../eclipse/jetty/embedded/SpdyServer.java | 2 +- jetty-spdy/pom.xml | 26 +- jetty-spdy/spdy-client/pom.xml | 30 -- .../spdy/client/NPNClientConnection.java | 111 ++------ .../client/NPNClientConnectionFactory.java | 19 +- .../client/NegotiatingClientConnection.java | 133 +++++++++ .../NegotiatingClientConnectionFactory.java | 36 +++ .../eclipse/jetty/spdy/client/SPDYClient.java | 30 +- jetty-spdy/spdy-http-client-transport/pom.xml | 30 -- jetty-spdy/spdy-http-server/pom.xml | 33 +-- .../proxy/HTTPSPDYProxyServerConnector.java | 27 +- .../server/http/AbstractHTTPSPDYTest.java | 14 +- .../server/http/ProtocolNegotiationTest.java | 255 ----------------- .../server/proxy/ProxyHTTPToSPDYTest.java | 35 +-- .../server/proxy/ProxySPDYToHTTPLoadTest.java | 46 ++- .../server/proxy/ProxySPDYToHTTPTest.java | 35 +-- .../server/proxy/ProxySPDYToSPDYLoadTest.java | 32 +-- .../server/proxy/ProxySPDYToSPDYTest.java | 29 +- jetty-spdy/spdy-npn-tests/pom.xml | 95 +++++++ .../jetty/spdy/server/AbstractNPNTest.java | 77 +++++ .../jetty/spdy/server/NPNModuleTest.java} | 19 +- .../jetty/spdy/server/NPNNegotiationTest.java | 207 ++++++++++++++ .../jetty/spdy/server/SSLEngineLeakTest.java | 36 +-- .../jetty/spdy/server/SSLSynReplyTest.java | 34 +-- .../proxy/NPNProxySPDYToHTTPLoadTest.java | 29 ++ .../server/proxy/NPNProxySPDYToHTTPTest.java | 27 ++ .../proxy/NPNProxySPDYToSPDYLoadTest.java | 27 ++ .../server/proxy/NPNProxySPDYToSPDYTest.java | 27 ++ .../test/resources/jetty-logging.properties | 2 + .../src/test/resources/keystore.jks | Bin .../src/test/resources/truststore.jks | Bin jetty-spdy/spdy-server/pom.xml | 30 -- .../spdy/server/NPNServerConnection.java | 115 +------- .../server/NPNServerConnectionFactory.java | 87 +----- .../server/NegotiatingServerConnection.java | 163 +++++++++++ .../NegotiatingServerConnectionFactory.java | 103 +++++++ .../server/SPDYServerConnectionFactory.java | 29 +- .../spdy/server/SPDYServerConnector.java | 27 +- pom.xml | 262 +++++++++--------- .../jetty/TestTransparentProxyServer.java | 2 +- 41 files changed, 1282 insertions(+), 1041 deletions(-) create mode 100644 jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NegotiatingClientConnection.java create mode 100644 jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NegotiatingClientConnectionFactory.java delete mode 100644 jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ProtocolNegotiationTest.java create mode 100644 jetty-spdy/spdy-npn-tests/pom.xml create mode 100644 jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/AbstractNPNTest.java rename jetty-spdy/{spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/NpnModuleTest.java => spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNModuleTest.java} (92%) create mode 100644 jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNNegotiationTest.java rename jetty-spdy/{spdy-server => spdy-npn-tests}/src/test/java/org/eclipse/jetty/spdy/server/SSLEngineLeakTest.java (65%) rename jetty-spdy/{spdy-server => spdy-npn-tests}/src/test/java/org/eclipse/jetty/spdy/server/SSLSynReplyTest.java (81%) create mode 100644 jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPLoadTest.java create mode 100644 jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPTest.java create mode 100644 jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYLoadTest.java create mode 100644 jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYTest.java create mode 100644 jetty-spdy/spdy-npn-tests/src/test/resources/jetty-logging.properties rename jetty-spdy/{spdy-server => spdy-npn-tests}/src/test/resources/keystore.jks (100%) rename jetty-spdy/{spdy-server => spdy-npn-tests}/src/test/resources/truststore.jks (100%) create mode 100644 jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NegotiatingServerConnection.java create mode 100644 jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NegotiatingServerConnectionFactory.java diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyConnector.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyConnector.java index 542197be780..05115382c77 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyConnector.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyConnector.java @@ -72,7 +72,7 @@ public class SpdyConnector new HTTPSPDYServerConnectionFactory(3,https_config,new ReferrerPushStrategy()); // NPN Factory - SPDYServerConnectionFactory.checkNPNAvailable(); + SPDYServerConnectionFactory.checkProtocolNegotiationAvailable(); NPNServerConnectionFactory npn = new NPNServerConnectionFactory(spdy3.getProtocol(),spdy2.getProtocol(),http.getDefaultProtocol()); npn.setDefaultProtocol(http.getDefaultProtocol()); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyServer.java index 3ab394230da..a9dfdc488f4 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyServer.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SpdyServer.java @@ -110,7 +110,7 @@ public class SpdyServer // Spdy Connector // Make sure that the required NPN implementations are available. - SPDYServerConnectionFactory.checkNPNAvailable(); + SPDYServerConnectionFactory.checkProtocolNegotiationAvailable(); // A ReferrerPushStrategy is being initialized. // See: http://www.eclipse.org/jetty/documentation/current/spdy-configuring-push.html for more details. diff --git a/jetty-spdy/pom.xml b/jetty-spdy/pom.xml index 61777c87504..d9f4e91da3d 100644 --- a/jetty-spdy/pom.xml +++ b/jetty-spdy/pom.xml @@ -23,13 +23,17 @@ spdy-example-webapp - - - org.eclipse.jetty.toolchain - jetty-test-helper - test - - + + + jdk7-npn + + [1.7,1.8) + + + spdy-npn-tests + + + @@ -70,4 +74,12 @@ + + + org.eclipse.jetty.toolchain + jetty-test-helper + test + + + diff --git a/jetty-spdy/spdy-client/pom.xml b/jetty-spdy/spdy-client/pom.xml index 4ec9956aa00..20bad8ff7b0 100644 --- a/jetty-spdy/spdy-client/pom.xml +++ b/jetty-spdy/spdy-client/pom.xml @@ -17,36 +17,6 @@ http://www.eclipse.org/jetty - - maven-dependency-plugin - - - copy - generate-resources - - copy - - - - - org.mortbay.jetty.npn - npn-boot - ${npn.version} - jar - false - ${project.build.directory}/npn - - - - - - - - maven-surefire-plugin - - -Xbootclasspath/p:${project.build.directory}/npn/npn-boot-${npn.version}.jar - - org.apache.felix maven-bundle-plugin diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnection.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnection.java index fc288894d6a..c8e85f2c0ea 100644 --- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnection.java +++ b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnection.java @@ -18,87 +18,28 @@ package org.eclipse.jetty.spdy.client; -import java.io.IOException; import java.util.List; import java.util.Map; - +import java.util.concurrent.Executor; import javax.net.ssl.SSLEngine; -import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.ClientConnectionFactory; -import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.io.RuntimeIOException; import org.eclipse.jetty.npn.NextProtoNego; -import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -public class NPNClientConnection extends AbstractConnection implements NextProtoNego.ClientProvider +public class NPNClientConnection extends NegotiatingClientConnection implements NextProtoNego.ClientProvider { - private final Logger LOG = Log.getLogger(getClass()); - private final SPDYClient client; - private final ClientConnectionFactory connectionFactory; - private final SSLEngine engine; - private final Map context; - private volatile boolean completed; + private static final Logger LOG = Log.getLogger(NPNClientConnection.class); - public NPNClientConnection(EndPoint endPoint, SPDYClient client, ClientConnectionFactory connectionFactory, SSLEngine sslEngine, Map context) - { - super(endPoint, client.getFactory().getExecutor()); - this.client = client; - this.connectionFactory = connectionFactory; - this.engine = sslEngine; - this.context = context; - NextProtoNego.put(engine, this); - } + private final String protocol; - @Override - public void onOpen() + public NPNClientConnection(EndPoint endPoint, Executor executor, ClientConnectionFactory connectionFactory, SSLEngine sslEngine, Map context, String protocol) { - super.onOpen(); - try - { - getEndPoint().flush(BufferUtil.EMPTY_BUFFER); - if (completed) - replaceConnection(); - else - fillInterested(); - } - catch(IOException e) - { - throw new RuntimeIOException(e); - } - } - - @Override - public void onFillable() - { - while (true) - { - int filled = fill(); - if (filled == 0 && !completed) - fillInterested(); - if (filled <= 0 || completed) - break; - } - if (completed) - replaceConnection(); - } - - private int fill() - { - try - { - return getEndPoint().fill(BufferUtil.EMPTY_BUFFER); - } - catch (IOException x) - { - LOG.debug(x); - NextProtoNego.remove(engine); - close(); - return -1; - } + super(endPoint, executor, sslEngine, connectionFactory, context); + this.protocol = protocol; + NextProtoNego.put(sslEngine, this); } @Override @@ -110,31 +51,31 @@ public class NPNClientConnection extends AbstractConnection implements NextProto @Override public void unsupported() { - NextProtoNego.remove(engine); - completed = true; + NextProtoNego.remove(getSSLEngine()); + completed(); } @Override public String selectProtocol(List protocols) { - NextProtoNego.remove(engine); - completed = true; - return client.selectProtocol(protocols); + if (protocols.contains(protocol)) + { + NextProtoNego.remove(getSSLEngine()); + completed(); + return protocol; + } + else + { + LOG.info("Could not negotiate protocol: server {} - client {}", protocols, protocol); + close(); + return null; + } } - private void replaceConnection() + @Override + public void close() { - EndPoint endPoint = getEndPoint(); - try - { - Connection oldConnection = endPoint.getConnection(); - Connection newConnection = connectionFactory.newConnection(endPoint, context); - ClientConnectionFactory.Helper.replaceConnection(oldConnection, newConnection); - } - catch (Throwable x) - { - LOG.debug(x); - close(); - } + NextProtoNego.remove(getSSLEngine()); + super.close(); } } diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnectionFactory.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnectionFactory.java index ec81cab1565..d0458010c9f 100644 --- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnectionFactory.java +++ b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NPNClientConnectionFactory.java @@ -20,7 +20,7 @@ package org.eclipse.jetty.spdy.client; import java.io.IOException; import java.util.Map; - +import java.util.concurrent.Executor; import javax.net.ssl.SSLEngine; import org.eclipse.jetty.io.ClientConnectionFactory; @@ -28,21 +28,22 @@ import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.ssl.SslClientConnectionFactory; -public class NPNClientConnectionFactory implements ClientConnectionFactory +public class NPNClientConnectionFactory extends NegotiatingClientConnectionFactory { - private final SPDYClient client; - private final ClientConnectionFactory connectionFactory; + private final Executor executor; + private final String protocol; - public NPNClientConnectionFactory(SPDYClient client, ClientConnectionFactory connectionFactory) + public NPNClientConnectionFactory(Executor executor, ClientConnectionFactory connectionFactory, String protocol) { - this.client = client; - this.connectionFactory = connectionFactory; + super(connectionFactory); + this.executor = executor; + this.protocol = protocol; } @Override public Connection newConnection(EndPoint endPoint, Map context) throws IOException { - return new NPNClientConnection(endPoint, client, connectionFactory, - (SSLEngine)context.get(SslClientConnectionFactory.SSL_ENGINE_CONTEXT_KEY), context); + return new NPNClientConnection(endPoint, executor, getClientConnectionFactory(), + (SSLEngine)context.get(SslClientConnectionFactory.SSL_ENGINE_CONTEXT_KEY), context, protocol); } } diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NegotiatingClientConnection.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NegotiatingClientConnection.java new file mode 100644 index 00000000000..a2fc8511f4a --- /dev/null +++ b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NegotiatingClientConnection.java @@ -0,0 +1,133 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.spdy.client; + +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.Executor; +import javax.net.ssl.SSLEngine; + +import org.eclipse.jetty.io.AbstractConnection; +import org.eclipse.jetty.io.ClientConnectionFactory; +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.io.RuntimeIOException; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +public abstract class NegotiatingClientConnection extends AbstractConnection +{ + private static final Logger LOG = Log.getLogger(NegotiatingClientConnection.class); + + private final SSLEngine engine; + private final ClientConnectionFactory connectionFactory; + private final Map context; + private volatile boolean completed; + + protected NegotiatingClientConnection(EndPoint endp, Executor executor, SSLEngine sslEngine, ClientConnectionFactory connectionFactory, Map context) + { + super(endp, executor); + this.engine = sslEngine; + this.connectionFactory = connectionFactory; + this.context = context; + } + + protected SSLEngine getSSLEngine() + { + return engine; + } + + protected void completed() + { + completed = true; + } + + @Override + public void onOpen() + { + super.onOpen(); + try + { + getEndPoint().flush(BufferUtil.EMPTY_BUFFER); + if (completed) + replaceConnection(); + else + fillInterested(); + } + catch (IOException x) + { + close(); + throw new RuntimeIOException(x); + } + } + + @Override + public void onFillable() + { + while (true) + { + int filled = fill(); + if (filled == 0 && !completed) + fillInterested(); + if (filled <= 0 || completed) + break; + } + if (completed) + replaceConnection(); + } + + private int fill() + { + try + { + return getEndPoint().fill(BufferUtil.EMPTY_BUFFER); + } + catch (IOException x) + { + LOG.debug(x); + close(); + return -1; + } + } + + private void replaceConnection() + { + EndPoint endPoint = getEndPoint(); + try + { + Connection oldConnection = endPoint.getConnection(); + Connection newConnection = connectionFactory.newConnection(endPoint, context); + ClientConnectionFactory.Helper.replaceConnection(oldConnection, newConnection); + } + catch (Throwable x) + { + LOG.debug(x); + close(); + } + } + + @Override + public void close() + { + // Gentler close for SSL. + getEndPoint().shutdownOutput(); + super.close(); + } +} diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NegotiatingClientConnectionFactory.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NegotiatingClientConnectionFactory.java new file mode 100644 index 00000000000..50a1e5b2233 --- /dev/null +++ b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/NegotiatingClientConnectionFactory.java @@ -0,0 +1,36 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.spdy.client; + +import org.eclipse.jetty.io.ClientConnectionFactory; + +public abstract class NegotiatingClientConnectionFactory implements ClientConnectionFactory +{ + private final ClientConnectionFactory connectionFactory; + + protected NegotiatingClientConnectionFactory(ClientConnectionFactory connectionFactory) + { + this.connectionFactory = connectionFactory; + } + + public ClientConnectionFactory getClientConnectionFactory() + { + return connectionFactory; + } +} diff --git a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClient.java b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClient.java index 678aa2aac60..d30bc99f4ea 100644 --- a/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClient.java +++ b/jetty-spdy/spdy-client/src/main/java/org/eclipse/jetty/spdy/client/SPDYClient.java @@ -26,7 +26,6 @@ import java.nio.channels.SocketChannel; import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; @@ -86,10 +85,6 @@ public class SPDYClient this.factory = factory; setInitialWindowSize(65536); setDispatchIO(true); - ClientConnectionFactory connectionFactory = new SPDYClientConnectionFactory(); - if (factory.sslContextFactory != null) - connectionFactory = new SslClientConnectionFactory(factory.getSslContextFactory(), factory.getByteBufferPool(), factory.getExecutor(), new NPNClientConnectionFactory(this, connectionFactory)); - setClientConnectionFactory(connectionFactory); } public short getVersion() @@ -239,17 +234,6 @@ public class SPDYClient this.connectionFactory = connectionFactory; } - protected String selectProtocol(List serverProtocols) - { - String protocol = "spdy/" + version; - for (String serverProtocol : serverProtocols) - { - if (serverProtocol.equals(protocol)) - return protocol; - } - return null; - } - protected FlowControlStrategy newFlowControlStrategy() { return FlowControlStrategyFactory.newFlowControlStrategy(version); @@ -357,7 +341,19 @@ public class SPDYClient public SPDYClient newSPDYClient(short version) { - return new SPDYClient(version, this); + return newSPDYClient(version, new NPNClientConnectionFactory(getExecutor(), new SPDYClientConnectionFactory(), "spdy/" + version)); + } + + public SPDYClient newSPDYClient(short version, NegotiatingClientConnectionFactory negotiatingFactory) + { + SPDYClient client = new SPDYClient(version, this); + + ClientConnectionFactory connectionFactory = negotiatingFactory.getClientConnectionFactory(); + if (sslContextFactory != null) + connectionFactory = new SslClientConnectionFactory(getSslContextFactory(), getByteBufferPool(), getExecutor(), negotiatingFactory); + + client.setClientConnectionFactory(connectionFactory); + return client; } @Override diff --git a/jetty-spdy/spdy-http-client-transport/pom.xml b/jetty-spdy/spdy-http-client-transport/pom.xml index eb4fef0c14e..61f978a4c59 100644 --- a/jetty-spdy/spdy-http-client-transport/pom.xml +++ b/jetty-spdy/spdy-http-client-transport/pom.xml @@ -16,36 +16,6 @@ - - maven-dependency-plugin - - - copy - generate-resources - - copy - - - - - org.mortbay.jetty.npn - npn-boot - ${npn.version} - jar - false - ${project.build.directory}/npn - - - - - - - - maven-surefire-plugin - - -Xbootclasspath/p:${project.build.directory}/npn/npn-boot-${npn.version}.jar - - org.apache.felix maven-bundle-plugin diff --git a/jetty-spdy/spdy-http-server/pom.xml b/jetty-spdy/spdy-http-server/pom.xml index 4555f19235e..11740d8fa5c 100644 --- a/jetty-spdy/spdy-http-server/pom.xml +++ b/jetty-spdy/spdy-http-server/pom.xml @@ -33,35 +33,18 @@ - maven-dependency-plugin + org.apache.maven.plugins + maven-jar-plugin - copy - generate-resources + artifact-jars - copy + jar + test-jar - - - - org.mortbay.jetty.npn - npn-boot - ${npn.version} - jar - false - ${project.build.directory}/npn - - - - - maven-surefire-plugin - - -Xbootclasspath/p:${project.build.directory}/npn/npn-boot-${npn.version}.jar - - org.apache.felix maven-bundle-plugin @@ -127,12 +110,6 @@ ${project.version} test - - org.eclipse.jetty - jetty-start - ${project.version} - test - org.mockito mockito-core diff --git a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPSPDYProxyServerConnector.java b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPSPDYProxyServerConnector.java index c9d040a7aa8..4c3015e6c12 100644 --- a/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPSPDYProxyServerConnector.java +++ b/jetty-spdy/spdy-http-server/src/main/java/org/eclipse/jetty/spdy/server/proxy/HTTPSPDYProxyServerConnector.java @@ -19,12 +19,14 @@ package org.eclipse.jetty.spdy.server.proxy; -import org.eclipse.jetty.server.ConnectionFactory; +import java.util.Objects; + import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.spdy.api.SPDY; import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory; +import org.eclipse.jetty.spdy.server.NegotiatingServerConnectionFactory; import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory; import org.eclipse.jetty.util.ssl.SslContextFactory; @@ -37,7 +39,7 @@ public class HTTPSPDYProxyServerConnector extends ServerConnector public HTTPSPDYProxyServerConnector(Server server, HttpConfiguration config, ProxyEngineSelector proxyEngineSelector) { - this(server, null, config, proxyEngineSelector); + super(server, (SslContextFactory)null, new ProxyHTTPConnectionFactory(config, SPDY.V2, proxyEngineSelector)); } public HTTPSPDYProxyServerConnector(Server server, SslContextFactory sslContextFactory, ProxyEngineSelector proxyEngineSelector) @@ -47,16 +49,15 @@ public class HTTPSPDYProxyServerConnector extends ServerConnector public HTTPSPDYProxyServerConnector(Server server, SslContextFactory sslContextFactory, HttpConfiguration config, ProxyEngineSelector proxyEngineSelector) { - super(server, - sslContextFactory, - sslContextFactory == null - ? new ConnectionFactory[]{new ProxyHTTPConnectionFactory(config, SPDY.V2, proxyEngineSelector)} - : new ConnectionFactory[]{new NPNServerConnectionFactory("spdy/3", "spdy/2", "http/1.1"), - new SPDYServerConnectionFactory(SPDY.V3, proxyEngineSelector), - new SPDYServerConnectionFactory(SPDY.V2, proxyEngineSelector), - new ProxyHTTPConnectionFactory(config, SPDY.V2, proxyEngineSelector)}); - NPNServerConnectionFactory npnConnectionFactory = getConnectionFactory(NPNServerConnectionFactory.class); - if (npnConnectionFactory != null) - npnConnectionFactory.setDefaultProtocol("http/1.1"); + this(server, sslContextFactory, config, proxyEngineSelector, new NPNServerConnectionFactory("spdy/3", "spdy/2", "http/1.1")); + } + + public HTTPSPDYProxyServerConnector(Server server, SslContextFactory sslContextFactory, HttpConfiguration config, ProxyEngineSelector proxyEngineSelector, NegotiatingServerConnectionFactory negotiatingFactory) + { + super(server, Objects.requireNonNull(sslContextFactory), negotiatingFactory, + new SPDYServerConnectionFactory(SPDY.V3, proxyEngineSelector), + new SPDYServerConnectionFactory(SPDY.V2, proxyEngineSelector), + new ProxyHTTPConnectionFactory(config, SPDY.V2, proxyEngineSelector)); + negotiatingFactory.setDefaultProtocol("http/1.1"); } } diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/AbstractHTTPSPDYTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/AbstractHTTPSPDYTest.java index f82a58d1b23..cf3ac1cf0ac 100644 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/AbstractHTTPSPDYTest.java +++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/AbstractHTTPSPDYTest.java @@ -73,11 +73,6 @@ public abstract class AbstractHTTPSPDYTest this.version = version; } - protected InetSocketAddress startHTTPServer(Handler handler) throws Exception - { - return startHTTPServer(SPDY.V2, handler, 30000); - } - protected InetSocketAddress startHTTPServer(short version, Handler handler, long idleTimeout) throws Exception { QueuedThreadPool threadPool = new QueuedThreadPool(256); @@ -89,7 +84,6 @@ public abstract class AbstractHTTPSPDYTest server.addConnector(connector); server.setHandler(handler); server.start(); - server.dumpStdErr(); return new InetSocketAddress("localhost", connector.getLocalPort()); } @@ -104,13 +98,7 @@ public abstract class AbstractHTTPSPDYTest HttpConfiguration httpConfiguration = new HttpConfiguration(); httpConfiguration.setSendServerVersion(true); httpConfiguration.setSendXPoweredBy(true); - HTTPSPDYServerConnector connector = new HTTPSPDYServerConnector(server,version, httpConfiguration, new PushStrategy.None()); - return connector; - } - - protected Session startClient(InetSocketAddress socketAddress, SessionFrameListener listener) throws Exception - { - return startClient(SPDY.V2, socketAddress, listener); + return new HTTPSPDYServerConnector(server, version, httpConfiguration, new PushStrategy.None()); } protected Session startClient(short version, InetSocketAddress socketAddress, SessionFrameListener listener) throws Exception diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ProtocolNegotiationTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ProtocolNegotiationTest.java deleted file mode 100644 index 5e9b3730fcb..00000000000 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ProtocolNegotiationTest.java +++ /dev/null @@ -1,255 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - - -package org.eclipse.jetty.spdy.server.http; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.util.List; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocket; - -import org.eclipse.jetty.npn.NextProtoNego; -import org.eclipse.jetty.server.HttpConnectionFactory; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.spdy.server.SPDYServerConnector; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; - -public class ProtocolNegotiationTest -{ - @Rule - public final TestWatcher testName = new TestWatcher() - { - - @Override - public void starting(Description description) - { - super.starting(description); - System.err.printf("Running %s.%s()%n", - description.getClassName(), - description.getMethodName()); - } - }; - - protected Server server; - protected SPDYServerConnector connector; - - protected InetSocketAddress startServer(SPDYServerConnector connector) throws Exception - { - server = new Server(); - if (connector == null) - connector = new SPDYServerConnector(server, newSslContextFactory(), null); - connector.setPort(0); - connector.setIdleTimeout(30000); - this.connector = connector; - server.addConnector(connector); - server.start(); - return new InetSocketAddress("localhost", connector.getLocalPort()); - } - - protected SslContextFactory newSslContextFactory() - { - SslContextFactory sslContextFactory = new SslContextFactory(); - sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); - sslContextFactory.setKeyStorePassword("storepwd"); - sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks"); - sslContextFactory.setTrustStorePassword("storepwd"); - sslContextFactory.setProtocol("TLSv1"); - sslContextFactory.setIncludeProtocols("TLSv1"); - return sslContextFactory; - } - - @Test - public void testServerAdvertisingHTTPSpeaksHTTP() throws Exception - { - InetSocketAddress address = startServer(null); - connector.addConnectionFactory(new HttpConnectionFactory()); - - SslContextFactory sslContextFactory = newSslContextFactory(); - sslContextFactory.start(); - SSLContext sslContext = sslContextFactory.getSslContext(); - SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort()); - client.setUseClientMode(true); - client.setSoTimeout(5000); - - NextProtoNego.put(client, new NextProtoNego.ClientProvider() - { - @Override - public boolean supports() - { - return true; - } - - @Override - public void unsupported() - { - } - - @Override - public String selectProtocol(List strings) - { - Assert.assertNotNull(strings); - String protocol = "http/1.1"; - Assert.assertTrue(strings.contains(protocol)); - return protocol; - } - }); - - client.startHandshake(); - - // Verify that the server really speaks http/1.1 - - OutputStream output = client.getOutputStream(); - output.write(("" + - "GET / HTTP/1.1\r\n" + - "Host: localhost:" + address.getPort() + "\r\n" + - "\r\n" + - "").getBytes(StandardCharsets.UTF_8)); - output.flush(); - - InputStream input = client.getInputStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)); - String line = reader.readLine(); - Assert.assertTrue(line.contains(" 404 ")); - - client.close(); - } - - @Test - public void testServerAdvertisingSPDYAndHTTPSpeaksHTTPWhenNegotiated() throws Exception - { - InetSocketAddress address = startServer(null); - connector.addConnectionFactory(new HttpConnectionFactory()); - - SslContextFactory sslContextFactory = newSslContextFactory(); - sslContextFactory.start(); - SSLContext sslContext = sslContextFactory.getSslContext(); - SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort()); - client.setUseClientMode(true); - client.setSoTimeout(5000); - - NextProtoNego.put(client, new NextProtoNego.ClientProvider() - { - @Override - public boolean supports() - { - return true; - } - - @Override - public void unsupported() - { - } - - @Override - public String selectProtocol(List strings) - { - Assert.assertNotNull(strings); - String spdyProtocol = "spdy/2"; - Assert.assertTrue(strings.contains(spdyProtocol)); - String httpProtocol = "http/1.1"; - Assert.assertTrue(strings.contains(httpProtocol)); - Assert.assertTrue(strings.indexOf(spdyProtocol) < strings.indexOf(httpProtocol)); - return httpProtocol; - } - }); - - client.startHandshake(); - - // Verify that the server really speaks http/1.1 - - OutputStream output = client.getOutputStream(); - output.write(("" + - "GET / HTTP/1.1\r\n" + - "Host: localhost:" + address.getPort() + "\r\n" + - "\r\n" + - "").getBytes(StandardCharsets.UTF_8)); - output.flush(); - - InputStream input = client.getInputStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)); - String line = reader.readLine(); - Assert.assertTrue(line.contains(" 404 ")); - - client.close(); - } - - @Test - public void testServerAdvertisingSPDYAndHTTPSpeaksDefaultProtocolWhenNPNMissing() throws Exception - { - InetSocketAddress address = startServer(null); - connector.addConnectionFactory(new HttpConnectionFactory()); - - SslContextFactory sslContextFactory = newSslContextFactory(); - sslContextFactory.start(); - SSLContext sslContext = sslContextFactory.getSslContext(); - SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort()); - client.setUseClientMode(true); - client.setSoTimeout(5000); - - NextProtoNego.put(client, new NextProtoNego.ClientProvider() - { - @Override - public boolean supports() - { - return false; - } - - @Override - public void unsupported() - { - } - - @Override - public String selectProtocol(List strings) - { - return null; - } - }); - - client.startHandshake(); - - // Verify that the server really speaks http/1.1 - - OutputStream output = client.getOutputStream(); - output.write(("" + - "GET / HTTP/1.1\r\n" + - "Host: localhost:" + address.getPort() + "\r\n" + - "\r\n" + - "").getBytes(StandardCharsets.UTF_8)); - output.flush(); - - InputStream input = client.getInputStream(); - BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)); - String line = reader.readLine(); - Assert.assertTrue(line.contains(" 404 ")); - - client.close(); - } -} diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPToSPDYTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPToSPDYTest.java index 8704e0de99d..0f450e2ce63 100644 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPToSPDYTest.java +++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxyHTTPToSPDYTest.java @@ -18,9 +18,6 @@ package org.eclipse.jetty.spdy.server.proxy; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; - import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -53,49 +50,35 @@ import org.eclipse.jetty.spdy.client.SPDYClient; import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory; import org.eclipse.jetty.spdy.server.SPDYServerConnector; +import org.eclipse.jetty.toolchain.test.TestTracker; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Promise; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + @RunWith(Parameterized.class) public class ProxyHTTPToSPDYTest { - private static final Logger LOG = Log.getLogger(ProxyHTTPToSPDYTest.class); - @Rule - public final TestWatcher testName = new TestWatcher() - { - - @Override - public void starting(Description description) - { - super.starting(description); - System.err.printf("Running %s.%s()%n", - description.getClassName(), - description.getMethodName()); - } - }; - - private final short version; - private HttpClient httpClient; - private HttpClient httpClient2; - @Parameterized.Parameters public static Collection parameters() { return Arrays.asList(new Short[]{SPDY.V2}, new Short[]{SPDY.V3}); } + @Rule + public final TestTracker tracker = new TestTracker(); + private final short version; + private HttpClient httpClient; + private HttpClient httpClient2; private SPDYClient.Factory factory; private Server server; private Server proxy; diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPLoadTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPLoadTest.java index b2048a5acf6..94e481becf0 100644 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPLoadTest.java +++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPLoadTest.java @@ -18,11 +18,6 @@ package org.eclipse.jetty.spdy.server.proxy; -import static junit.framework.Assert.fail; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertThat; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.InetSocketAddress; @@ -38,13 +33,13 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; @@ -58,7 +53,9 @@ import org.eclipse.jetty.spdy.api.StreamFrameListener; import org.eclipse.jetty.spdy.api.StringDataInfo; import org.eclipse.jetty.spdy.api.SynInfo; import org.eclipse.jetty.spdy.client.SPDYClient; +import org.eclipse.jetty.spdy.server.NegotiatingServerConnectionFactory; import org.eclipse.jetty.spdy.server.http.SPDYTestUtils; +import org.eclipse.jetty.toolchain.test.TestTracker; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.IO; @@ -71,33 +68,19 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import static junit.framework.Assert.fail; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; + @Ignore @RunWith(value = Parameterized.class) -public class ProxySPDYToHTTPLoadTest +public abstract class ProxySPDYToHTTPLoadTest { private static final Logger LOG = Log.getLogger(ProxySPDYToHTTPLoadTest.class); - @Rule - public final TestWatcher testName = new TestWatcher() - { - - @Override - public void starting(Description description) - { - super.starting(description); - System.err.printf("Running %s.%s()%n", - description.getClassName(), - description.getMethodName()); - } - }; - - private final short version; - private final String server1String = "server1"; - private final String server2String = "server2"; @Parameterized.Parameters public static Collection parameters() @@ -105,6 +88,12 @@ public class ProxySPDYToHTTPLoadTest return Arrays.asList(new Short[]{SPDY.V2}, new Short[]{SPDY.V3}); } + @Rule + public final TestTracker tracker = new TestTracker(); + private final short version; + private final NegotiatingServerConnectionFactory negotiator; + private final String server1String = "server1"; + private final String server2String = "server2"; private SPDYClient.Factory factory; private Server server1; private Server server2; @@ -112,9 +101,10 @@ public class ProxySPDYToHTTPLoadTest private ServerConnector proxyConnector; private SslContextFactory sslContextFactory = SPDYTestUtils.newSslContextFactory(); - public ProxySPDYToHTTPLoadTest(short version) + public ProxySPDYToHTTPLoadTest(short version, NegotiatingServerConnectionFactory negotiator) { this.version = version; + this.negotiator = negotiator; } @Before @@ -188,7 +178,7 @@ public class ProxySPDYToHTTPLoadTest proxyEngineSelector.putProxyServerInfo("127.0.0.2", new ProxyEngineSelector.ProxyServerInfo("http/1.1", server2.getHostName(), server2.getPort())); - proxyConnector = new HTTPSPDYProxyServerConnector(proxy, sslContextFactory, proxyEngineSelector); + proxyConnector = new HTTPSPDYProxyServerConnector(proxy, sslContextFactory, new HttpConfiguration(), proxyEngineSelector, negotiator); proxyConnector.setPort(0); proxyConnector.setIdleTimeout(proxyConnectorTimeout); proxy.addConnector(proxyConnector); diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPTest.java index 53639186013..700d560150a 100644 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPTest.java +++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToHTTPTest.java @@ -18,11 +18,6 @@ package org.eclipse.jetty.spdy.server.proxy; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertThat; - import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -32,7 +27,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -61,6 +55,7 @@ import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; import org.eclipse.jetty.spdy.client.SPDYClient; import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; import org.eclipse.jetty.spdy.server.http.SPDYTestUtils; +import org.eclipse.jetty.toolchain.test.TestTracker; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.log.Log; @@ -71,36 +66,26 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; + @RunWith(value = Parameterized.class) -public class ProxySPDYToHTTPTest +public abstract class ProxySPDYToHTTPTest { - @Rule - public final TestWatcher testName = new TestWatcher() - { - - @Override - public void starting(Description description) - { - super.starting(description); - System.err.printf("Running %s.%s()%n", - description.getClassName(), - description.getMethodName()); - } - }; - - private final short version; - @Parameterized.Parameters public static Collection parameters() { return Arrays.asList(new Short[]{SPDY.V2}, new Short[]{SPDY.V3}); } + @Rule + public final TestTracker tracker = new TestTracker(); + private final short version; private SPDYClient.Factory factory; private Server server; private Server proxy; diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYLoadTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYLoadTest.java index 1122185e0f3..89f0eced800 100644 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYLoadTest.java +++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYLoadTest.java @@ -18,10 +18,6 @@ package org.eclipse.jetty.spdy.server.proxy; -import static junit.framework.Assert.fail; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - import java.io.ByteArrayOutputStream; import java.net.InetSocketAddress; import java.util.ArrayList; @@ -52,6 +48,7 @@ import org.eclipse.jetty.spdy.client.SPDYClient; import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory; import org.eclipse.jetty.spdy.server.SPDYServerConnector; import org.eclipse.jetty.spdy.server.http.SPDYTestUtils; +import org.eclipse.jetty.toolchain.test.TestTracker; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.ssl.SslContextFactory; @@ -60,36 +57,25 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import static junit.framework.Assert.fail; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + @RunWith(value = Parameterized.class) -public class ProxySPDYToSPDYLoadTest +public abstract class ProxySPDYToSPDYLoadTest { - @Rule - public final TestWatcher testName = new TestWatcher() - { - - @Override - public void starting(Description description) - { - super.starting(description); - System.err.printf("Running %s.%s()%n", - description.getClassName(), - description.getMethodName()); - } - }; - - private final short version; - @Parameterized.Parameters public static Collection parameters() { return Arrays.asList(new Short[]{SPDY.V2}, new Short[]{SPDY.V3}); } + @Rule + public final TestTracker tracker = new TestTracker(); + private final short version; private static final String UUID_HEADER_NAME = "uuidHeader"; private static final String SERVER_ID_HEADER = "serverId"; private SPDYClient.Factory factory; diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYTest.java index a3e1400b375..04e9551cd55 100644 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYTest.java +++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/proxy/ProxySPDYToSPDYTest.java @@ -18,9 +18,6 @@ package org.eclipse.jetty.spdy.server.proxy; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; - import java.io.ByteArrayOutputStream; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; @@ -52,6 +49,7 @@ import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; import org.eclipse.jetty.spdy.server.SPDYServerConnectionFactory; import org.eclipse.jetty.spdy.server.SPDYServerConnector; import org.eclipse.jetty.spdy.server.http.SPDYTestUtils; +import org.eclipse.jetty.toolchain.test.TestTracker; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Promise; @@ -61,35 +59,24 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + @RunWith(value = Parameterized.class) -public class ProxySPDYToSPDYTest +public abstract class ProxySPDYToSPDYTest { - @Rule - public final TestWatcher testName = new TestWatcher() - { - - @Override - public void starting(Description description) - { - super.starting(description); - System.err.printf("Running %s.%s()%n", - description.getClassName(), - description.getMethodName()); - } - }; - private final short version; - @Parameterized.Parameters public static Collection parameters() { return Arrays.asList(new Short[]{SPDY.V2}, new Short[]{SPDY.V3}); } + @Rule + public final TestTracker tracker = new TestTracker(); + private final short version; private SPDYClient.Factory factory; private Server server; private Server proxy; diff --git a/jetty-spdy/spdy-npn-tests/pom.xml b/jetty-spdy/spdy-npn-tests/pom.xml new file mode 100644 index 00000000000..316d5f3788c --- /dev/null +++ b/jetty-spdy/spdy-npn-tests/pom.xml @@ -0,0 +1,95 @@ + + + + org.eclipse.jetty.spdy + spdy-parent + 9.1.4-SNAPSHOT + + + 4.0.0 + spdy-npn-tests + Jetty :: SPDY :: NPN Tests + + + + + maven-dependency-plugin + + + copy + generate-resources + + copy + + + + + org.mortbay.jetty.npn + npn-boot + ${npn.version} + jar + false + ${project.build.directory}/npn + + + + + + + + maven-surefire-plugin + + -Xbootclasspath/p:${project.build.directory}/npn/npn-boot-${npn.version}.jar + + + + + + + + org.eclipse.jetty.npn + npn-api + ${npn.api.version} + provided + + + org.eclipse.jetty + jetty-start + ${project.version} + test + + + org.eclipse.jetty + jetty-server + ${project.version} + test + + + org.eclipse.jetty.spdy + spdy-server + ${project.version} + test + + + org.eclipse.jetty.spdy + spdy-http-server + ${project.version} + test + + + org.eclipse.jetty.spdy + spdy-http-server + ${project.version} + tests + test + + + junit + junit + test + + + + diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/AbstractNPNTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/AbstractNPNTest.java new file mode 100644 index 00000000000..8ed48031029 --- /dev/null +++ b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/AbstractNPNTest.java @@ -0,0 +1,77 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.spdy.server; + +import java.net.InetSocketAddress; + +import org.eclipse.jetty.npn.NextProtoNego; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.spdy.client.SPDYClient; +import org.eclipse.jetty.toolchain.test.TestTracker; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.junit.After; +import org.junit.Rule; + +public class AbstractNPNTest +{ + @Rule + public final TestTracker tracker = new TestTracker(); + protected Server server; + protected SPDYServerConnector connector; + protected SPDYClient.Factory clientFactory; + + protected InetSocketAddress prepare() throws Exception + { + server = new Server(); + connector = new SPDYServerConnector(server, newSslContextFactory(), null); + connector.setPort(0); + connector.setIdleTimeout(30000); + server.addConnector(connector); + server.start(); + + QueuedThreadPool threadPool = new QueuedThreadPool(); + threadPool.setName(threadPool.getName() + "-client"); + clientFactory = new SPDYClient.Factory(threadPool); + clientFactory.start(); + + NextProtoNego.debug = true; + + return new InetSocketAddress("localhost", connector.getLocalPort()); + } + + protected SslContextFactory newSslContextFactory() + { + SslContextFactory sslContextFactory = new SslContextFactory(); + sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); + sslContextFactory.setKeyStorePassword("storepwd"); + sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks"); + sslContextFactory.setTrustStorePassword("storepwd"); + sslContextFactory.setProtocol("TLSv1"); + sslContextFactory.setIncludeProtocols("TLSv1"); + return sslContextFactory; + } + + @After + public void dispose() throws Exception + { + clientFactory.stop(); + server.stop(); + } +} diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/NpnModuleTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNModuleTest.java similarity index 92% rename from jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/NpnModuleTest.java rename to jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNModuleTest.java index ce48352c3bd..c39d1aa58d1 100644 --- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/NpnModuleTest.java +++ b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNModuleTest.java @@ -18,9 +18,6 @@ package org.eclipse.jetty.spdy.server; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; - import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -45,8 +42,14 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + @RunWith(Parameterized.class) -public class NpnModuleTest +public class NPNModuleTest { /** This is here to prevent pointless download attempts */ private static final List KNOWN_GOOD_NPN_URLS = new ArrayList<>(); @@ -66,7 +69,7 @@ public class NpnModuleTest @Parameters(name = "{index}: mod:{0}") public static List data() { - File npnBootModDir = MavenTestingUtils.getProjectDir("src/main/config/modules/npn"); + File npnBootModDir = MavenTestingUtils.getProjectDir("../spdy-http-server/src/main/config/modules/npn"); List data = new ArrayList<>(); for (File file : npnBootModDir.listFiles()) { @@ -86,8 +89,8 @@ public class NpnModuleTest @BeforeClass public static void initBaseHome() { - File homeDir = MavenTestingUtils.getProjectDir("src/main/config"); - File baseDir = MavenTestingUtils.getTargetTestingDir(NpnModuleTest.class.getName()); + File homeDir = MavenTestingUtils.getProjectDir("../spdy-http-server/src/main/config"); + File baseDir = MavenTestingUtils.getTargetTestingDir(NPNModuleTest.class.getName()); FS.ensureEmpty(baseDir); basehome = new BaseHome(homeDir,baseDir); } @@ -139,7 +142,7 @@ public class NpnModuleTest public static void main(String[] args) { - File outputDir = MavenTestingUtils.getTargetTestingDir(NpnModuleTest.class.getSimpleName() + "-main"); + File outputDir = MavenTestingUtils.getTargetTestingDir(NPNModuleTest.class.getSimpleName() + "-main"); FS.ensureEmpty(outputDir); for (String ref : KNOWN_GOOD_NPN_URLS) { diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNNegotiationTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNNegotiationTest.java new file mode 100644 index 00000000000..b8f2f10b865 --- /dev/null +++ b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/NPNNegotiationTest.java @@ -0,0 +1,207 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.spdy.server; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.List; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; + +import org.eclipse.jetty.npn.NextProtoNego; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.junit.Assert; +import org.junit.Test; + +public class NPNNegotiationTest extends AbstractNPNTest +{ + @Test + public void testServerAdvertisingHTTPSpeaksHTTP() throws Exception + { + InetSocketAddress address = prepare(); + connector.addConnectionFactory(new HttpConnectionFactory()); + + SslContextFactory sslContextFactory = newSslContextFactory(); + sslContextFactory.start(); + SSLContext sslContext = sslContextFactory.getSslContext(); + + try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort())) + { + client.setUseClientMode(true); + client.setSoTimeout(5000); + + NextProtoNego.put(client, new NextProtoNego.ClientProvider() + { + @Override + public boolean supports() + { + return true; + } + + @Override + public void unsupported() + { + } + + @Override + public String selectProtocol(List strings) + { + Assert.assertNotNull(strings); + String protocol = "http/1.1"; + Assert.assertTrue(strings.contains(protocol)); + return protocol; + } + }); + + client.startHandshake(); + + // Verify that the server really speaks http/1.1 + + OutputStream output = client.getOutputStream(); + output.write(("" + + "GET / HTTP/1.1\r\n" + + "Host: localhost:" + address.getPort() + "\r\n" + + "\r\n" + + "").getBytes(StandardCharsets.UTF_8)); + output.flush(); + + InputStream input = client.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)); + String line = reader.readLine(); + Assert.assertTrue(line.contains(" 404 ")); + } + } + + @Test + public void testServerAdvertisingSPDYAndHTTPSpeaksHTTPWhenNegotiated() throws Exception + { + InetSocketAddress address = prepare(); + connector.addConnectionFactory(new HttpConnectionFactory()); + + SslContextFactory sslContextFactory = newSslContextFactory(); + sslContextFactory.start(); + SSLContext sslContext = sslContextFactory.getSslContext(); + try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort())) + { + client.setUseClientMode(true); + client.setSoTimeout(5000); + + NextProtoNego.put(client, new NextProtoNego.ClientProvider() + { + @Override + public boolean supports() + { + return true; + } + + @Override + public void unsupported() + { + } + + @Override + public String selectProtocol(List strings) + { + Assert.assertNotNull(strings); + String spdyProtocol = "spdy/2"; + Assert.assertTrue(strings.contains(spdyProtocol)); + String httpProtocol = "http/1.1"; + Assert.assertTrue(strings.contains(httpProtocol)); + Assert.assertTrue(strings.indexOf(spdyProtocol) < strings.indexOf(httpProtocol)); + return httpProtocol; + } + }); + + client.startHandshake(); + + // Verify that the server really speaks http/1.1 + + OutputStream output = client.getOutputStream(); + output.write(("" + + "GET / HTTP/1.1\r\n" + + "Host: localhost:" + address.getPort() + "\r\n" + + "\r\n" + + "").getBytes(StandardCharsets.UTF_8)); + output.flush(); + + InputStream input = client.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)); + String line = reader.readLine(); + Assert.assertTrue(line.contains(" 404 ")); + } + } + + @Test + public void testServerAdvertisingSPDYAndHTTPSpeaksDefaultProtocolWhenNPNMissing() throws Exception + { + InetSocketAddress address = prepare(); + connector.addConnectionFactory(new HttpConnectionFactory()); + + SslContextFactory sslContextFactory = newSslContextFactory(); + sslContextFactory.start(); + SSLContext sslContext = sslContextFactory.getSslContext(); + try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket(address.getAddress(), address.getPort())) + { + client.setUseClientMode(true); + client.setSoTimeout(5000); + + NextProtoNego.put(client, new NextProtoNego.ClientProvider() + { + @Override + public boolean supports() + { + return false; + } + + @Override + public void unsupported() + { + } + + @Override + public String selectProtocol(List strings) + { + return null; + } + }); + + client.startHandshake(); + + // Verify that the server really speaks http/1.1 + + OutputStream output = client.getOutputStream(); + output.write(("" + + "GET / HTTP/1.1\r\n" + + "Host: localhost:" + address.getPort() + "\r\n" + + "\r\n" + + "").getBytes(StandardCharsets.UTF_8)); + output.flush(); + + InputStream input = client.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)); + String line = reader.readLine(); + Assert.assertTrue(line.contains(" 404 ")); + } + } +} diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SSLEngineLeakTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/SSLEngineLeakTest.java similarity index 65% rename from jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SSLEngineLeakTest.java rename to jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/SSLEngineLeakTest.java index c69ba17b8ca..4ce1689ea10 100644 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SSLEngineLeakTest.java +++ b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/SSLEngineLeakTest.java @@ -19,39 +19,20 @@ package org.eclipse.jetty.spdy.server; import java.lang.reflect.Field; +import java.net.InetSocketAddress; import java.util.Map; -import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import org.eclipse.jetty.npn.NextProtoNego; -import org.eclipse.jetty.server.Server; import org.eclipse.jetty.spdy.api.GoAwayInfo; +import org.eclipse.jetty.spdy.api.SPDY; import org.eclipse.jetty.spdy.api.Session; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.spdy.client.SPDYClient; -import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.Assert; -import org.junit.Ignore; import org.junit.Test; -public class SSLEngineLeakTest extends AbstractTest +public class SSLEngineLeakTest extends AbstractNPNTest { - @Override - protected SPDYServerConnector newSPDYServerConnector(Server server, ServerSessionFrameListener listener) - { - SslContextFactory sslContextFactory = newSslContextFactory(); - return new SPDYServerConnector(server, sslContextFactory, listener); - } - - @Override - protected SPDYClient.Factory newSPDYClientFactory(Executor threadPool) - { - SslContextFactory sslContextFactory = newSslContextFactory(); - return new SPDYClient.Factory(threadPool, null, sslContextFactory); - } - @Test - @Ignore public void testSSLEngineLeak() throws Exception { System.gc(); @@ -67,12 +48,12 @@ public class SSLEngineLeakTest extends AbstractTest // Allow the close to arrive to the server and the selector to process it Thread.sleep(1000); - // Perform GC to be sure that the WeakHashMap is cleared - Thread.sleep(1000); + // Perform GC to be sure that the map is cleared System.gc(); + Thread.sleep(1000); - // Check that the WeakHashMap is empty - if (objects.size()!=initialSize) + // Check that the map is empty + if (objects.size() != initialSize) { System.err.println(objects); server.dumpStdErr(); @@ -83,7 +64,8 @@ public class SSLEngineLeakTest extends AbstractTest private void avoidStackLocalVariables() throws Exception { - Session session = startClient(startServer(null), null); + InetSocketAddress address = prepare(); + Session session = clientFactory.newSPDYClient(SPDY.V3).connect(address, null); session.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); } } diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SSLSynReplyTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/SSLSynReplyTest.java similarity index 81% rename from jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SSLSynReplyTest.java rename to jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/SSLSynReplyTest.java index 267d8593b6f..a6649eb746e 100644 --- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/SSLSynReplyTest.java +++ b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/SSLSynReplyTest.java @@ -23,48 +23,20 @@ import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.util.List; -import java.util.concurrent.Executor; - import javax.net.ssl.SSLEngine; import org.eclipse.jetty.npn.NextProtoNego; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener; -import org.eclipse.jetty.spdy.client.SPDYClient; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; -public class SSLSynReplyTest extends SynReplyTest +public class SSLSynReplyTest extends AbstractNPNTest { - @Override - protected SPDYServerConnector newSPDYServerConnector(Server server, ServerSessionFrameListener listener) - { - SslContextFactory sslContextFactory = newSslContextFactory(); - sslContextFactory.setEndpointIdentificationAlgorithm(""); - return new SPDYServerConnector(server, sslContextFactory, listener); - } - - @Override - protected SPDYClient.Factory newSPDYClientFactory(Executor threadPool) - { - SslContextFactory sslContextFactory = newSslContextFactory(); - sslContextFactory.setEndpointIdentificationAlgorithm(""); - return new SPDYClient.Factory(threadPool, null, sslContextFactory); - } - - @Before - public void init() - { - NextProtoNego.debug = true; - } - @Test public void testGentleCloseDuringHandshake() throws Exception { - InetSocketAddress address = startServer(version, null); + InetSocketAddress address = prepare(); SslContextFactory sslContextFactory = newSslContextFactory(); sslContextFactory.start(); SSLEngine sslEngine = sslContextFactory.newSSLEngine(address); @@ -124,7 +96,7 @@ public class SSLSynReplyTest extends SynReplyTest @Test public void testAbruptCloseDuringHandshake() throws Exception { - InetSocketAddress address = startServer(version, null); + InetSocketAddress address = prepare(); SslContextFactory sslContextFactory = newSslContextFactory(); sslContextFactory.start(); SSLEngine sslEngine = sslContextFactory.newSSLEngine(address); diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPLoadTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPLoadTest.java new file mode 100644 index 00000000000..355c597744f --- /dev/null +++ b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPLoadTest.java @@ -0,0 +1,29 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.spdy.server.proxy; + +import org.eclipse.jetty.spdy.server.NPNServerConnectionFactory; + +public class NPNProxySPDYToHTTPLoadTest extends ProxySPDYToHTTPLoadTest +{ + public NPNProxySPDYToHTTPLoadTest(short version) + { + super(version, new NPNServerConnectionFactory("spdy/3", "spdy/2", "http/1.1")); + } +} diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPTest.java new file mode 100644 index 00000000000..8fbcf480ed5 --- /dev/null +++ b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToHTTPTest.java @@ -0,0 +1,27 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.spdy.server.proxy; + +public class NPNProxySPDYToHTTPTest extends ProxySPDYToHTTPTest +{ + public NPNProxySPDYToHTTPTest(short version) + { + super(version); + } +} diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYLoadTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYLoadTest.java new file mode 100644 index 00000000000..2e837be2b07 --- /dev/null +++ b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYLoadTest.java @@ -0,0 +1,27 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.spdy.server.proxy; + +public class NPNProxySPDYToSPDYLoadTest extends ProxySPDYToSPDYLoadTest +{ + public NPNProxySPDYToSPDYLoadTest(short version) + { + super(version); + } +} diff --git a/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYTest.java b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYTest.java new file mode 100644 index 00000000000..08b3bfaa323 --- /dev/null +++ b/jetty-spdy/spdy-npn-tests/src/test/java/org/eclipse/jetty/spdy/server/proxy/NPNProxySPDYToSPDYTest.java @@ -0,0 +1,27 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.spdy.server.proxy; + +public class NPNProxySPDYToSPDYTest extends ProxySPDYToSPDYTest +{ + public NPNProxySPDYToSPDYTest(short version) + { + super(version); + } +} diff --git a/jetty-spdy/spdy-npn-tests/src/test/resources/jetty-logging.properties b/jetty-spdy/spdy-npn-tests/src/test/resources/jetty-logging.properties new file mode 100644 index 00000000000..ead13ec1970 --- /dev/null +++ b/jetty-spdy/spdy-npn-tests/src/test/resources/jetty-logging.properties @@ -0,0 +1,2 @@ +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog +#org.eclipse.jetty.spdy.LEVEL=DEBUG diff --git a/jetty-spdy/spdy-server/src/test/resources/keystore.jks b/jetty-spdy/spdy-npn-tests/src/test/resources/keystore.jks similarity index 100% rename from jetty-spdy/spdy-server/src/test/resources/keystore.jks rename to jetty-spdy/spdy-npn-tests/src/test/resources/keystore.jks diff --git a/jetty-spdy/spdy-server/src/test/resources/truststore.jks b/jetty-spdy/spdy-npn-tests/src/test/resources/truststore.jks similarity index 100% rename from jetty-spdy/spdy-server/src/test/resources/truststore.jks rename to jetty-spdy/spdy-npn-tests/src/test/resources/truststore.jks diff --git a/jetty-spdy/spdy-server/pom.xml b/jetty-spdy/spdy-server/pom.xml index 298cd8c2ae9..3b45def038c 100644 --- a/jetty-spdy/spdy-server/pom.xml +++ b/jetty-spdy/spdy-server/pom.xml @@ -17,36 +17,6 @@ http://www.eclipse.org/jetty - - maven-dependency-plugin - - - copy - generate-resources - - copy - - - - - org.mortbay.jetty.npn - npn-boot - ${npn.version} - jar - false - ${project.build.directory}/npn - - - - - - - - maven-surefire-plugin - - -Xbootclasspath/p:${project.build.directory}/npn/npn-boot-${npn.version}.jar - - org.apache.felix maven-bundle-plugin diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnection.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnection.java index b06bf0d75e4..b58a01e219c 100644 --- a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnection.java +++ b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnection.java @@ -18,146 +18,49 @@ package org.eclipse.jetty.spdy.server; -import java.io.IOException; import java.util.List; - import javax.net.ssl.SSLEngine; -import javax.net.ssl.SSLEngineResult; -import org.eclipse.jetty.io.AbstractConnection; -import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.npn.NextProtoNego; -import org.eclipse.jetty.server.ConnectionFactory; import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -public class NPNServerConnection extends AbstractConnection implements NextProtoNego.ServerProvider +public class NPNServerConnection extends NegotiatingServerConnection implements NextProtoNego.ServerProvider { - private final Logger LOG = Log.getLogger(getClass()); - private final Connector connector; - private final SSLEngine engine; - private final List protocols; - private final String defaultProtocol; - private String nextProtocol; // No need to be volatile: it is modified and read by the same thread + private static final Logger LOG = Log.getLogger(NPNServerConnection.class); public NPNServerConnection(EndPoint endPoint, SSLEngine engine, Connector connector, List protocols, String defaultProtocol) { - super(endPoint, connector.getExecutor()); - this.connector = connector; - this.protocols = protocols; - this.defaultProtocol = defaultProtocol; - this.engine = engine; + super(connector, endPoint, engine, protocols, defaultProtocol); NextProtoNego.put(engine, this); } - @Override - public void onOpen() - { - super.onOpen(); - fillInterested(); - } - - @Override - public void onFillable() - { - int filled = fill(); - - if (filled == 0) - { - if (nextProtocol == null) - { - if (engine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) - { - // Here the SSL handshake is finished, but while the client sent - // the NPN extension, the server application did not select the - // protocol; we need to close as the protocol cannot be negotiated. - LOG.debug("{} missing next protocol. SSLEngine: {}", this, engine); - close(); - } - else - { - // Here the SSL handshake is not finished yet but we filled 0 bytes, - // so we need to read more. - fillInterested(); - } - } - else - { - ConnectionFactory connectionFactory = connector.getConnectionFactory(nextProtocol); - if (connectionFactory == null) - { - LOG.debug("{} application selected protocol '{}', but no correspondent {} has been configured", - this, nextProtocol, ConnectionFactory.class.getName()); - close(); - } - else - { - EndPoint endPoint = getEndPoint(); - Connection oldConnection = endPoint.getConnection(); - Connection newConnection = connectionFactory.newConnection(connector, endPoint); - LOG.debug("{} switching from {} to {}", this, oldConnection, newConnection); - oldConnection.onClose(); - endPoint.setConnection(newConnection); - getEndPoint().getConnection().onOpen(); - } - } - } - else if (filled < 0) - { - // Something went bad, we need to close. - LOG.debug("{} closing on client close", this); - close(); - } - else - { - // Must never happen, since we fill using an empty buffer - throw new IllegalStateException(); - } - } - - private int fill() - { - try - { - return getEndPoint().fill(BufferUtil.EMPTY_BUFFER); - } - catch (IOException x) - { - LOG.debug(x); - close(); - return -1; - } - } - @Override public void unsupported() { - protocolSelected(defaultProtocol); + protocolSelected(getDefaultProtocol()); } @Override public List protocols() { - return protocols; + return getProtocols(); } @Override public void protocolSelected(String protocol) { LOG.debug("{} protocol selected {}", this, protocol); - nextProtocol = protocol != null ? protocol : defaultProtocol; - NextProtoNego.remove(engine); + setProtocol(protocol != null ? protocol : getDefaultProtocol()); + NextProtoNego.remove(getSSLEngine()); } @Override public void close() { - NextProtoNego.remove(engine); - EndPoint endPoint = getEndPoint(); - endPoint.shutdownOutput(); - endPoint.close(); + NextProtoNego.remove(getSSLEngine()); + super.close(); } } diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnectionFactory.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnectionFactory.java index db18ef2f408..f0e9e018961 100644 --- a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnectionFactory.java +++ b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NPNServerConnectionFactory.java @@ -16,106 +16,45 @@ // ======================================================================== // - package org.eclipse.jetty.spdy.server; -import java.util.Arrays; -import java.util.Iterator; import java.util.List; - import javax.net.ssl.SSLEngine; -import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.io.ssl.SslConnection; import org.eclipse.jetty.npn.NextProtoNego; -import org.eclipse.jetty.server.AbstractConnectionFactory; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -public class NPNServerConnectionFactory extends AbstractConnectionFactory +public class NPNServerConnectionFactory extends NegotiatingServerConnectionFactory { private static final Logger LOG = Log.getLogger(NPNServerConnectionFactory.class); - private final List _protocols; - private String _defaultProtocol; - /* ------------------------------------------------------------ */ - /** - * @param protocols List of supported protocols in priority order - */ - public NPNServerConnectionFactory(@Name("protocols")String... protocols) + public NPNServerConnectionFactory(@Name("protocols") String... protocols) { - super("npn"); - _protocols=Arrays.asList(protocols); - + super("npn", protocols); try { - if (NextProtoNego.class.getClassLoader()!=null) + ClassLoader npnClassLoader = NextProtoNego.class.getClassLoader(); + if (npnClassLoader != null) { - LOG.warn("NextProtoNego not from bootloader classloader: "+NextProtoNego.class.getClassLoader()); - throw new IllegalStateException("NextProtoNego not on bootloader"); + LOG.warn("NPN must be in the boot classloader, not in: " + npnClassLoader); + throw new IllegalStateException("NPN must be in the boot classloader"); } } - catch(Throwable th) + catch (Throwable x) { - LOG.warn("NextProtoNego not available: "+th); - throw new IllegalStateException("NextProtoNego not available",th); + LOG.warn("NPN not available: " + x); + throw new IllegalStateException("NPN not available", x); } } - public String getDefaultProtocol() - { - return _defaultProtocol; - } - - public void setDefaultProtocol(String defaultProtocol) - { - _defaultProtocol = defaultProtocol; - } - - public List getProtocols() - { - return _protocols; - } - @Override - public Connection newConnection(Connector connector, EndPoint endPoint) + protected AbstractConnection newServerConnection(Connector connector, EndPoint endPoint, SSLEngine engine, List protocols, String defaultProtocol) { - List protocols=_protocols; - if (protocols==null || protocols.size()==0) - { - protocols=connector.getProtocols(); - for (Iterator i=protocols.iterator();i.hasNext();) - { - String protocol=i.next(); - if (protocol.startsWith("SSL-")||protocol.equals("NPN")) - i.remove(); - } - } - - String dft=_defaultProtocol; - if (dft==null) - dft=_protocols.get(0); - - SSLEngine engine=null; - EndPoint ep=endPoint; - while(engine==null && ep!=null) - { - // TODO make more generic - if (ep instanceof SslConnection.DecryptedEndPoint) - engine=((SslConnection.DecryptedEndPoint)ep).getSslConnection().getSSLEngine(); - else - ep=null; - } - - return configure(new NPNServerConnection(endPoint, engine, connector,protocols,_defaultProtocol),connector,endPoint); - } - - @Override - public String toString() - { - return String.format("%s@%x{%s,%s,%s}",this.getClass().getSimpleName(),hashCode(),getProtocol(),getDefaultProtocol(),getProtocols()); + return new NPNServerConnection(endPoint, engine, connector, protocols, defaultProtocol); } } diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NegotiatingServerConnection.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NegotiatingServerConnection.java new file mode 100644 index 00000000000..b1fb87eb5ed --- /dev/null +++ b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NegotiatingServerConnection.java @@ -0,0 +1,163 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.spdy.server; + +import java.io.IOException; +import java.util.List; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; + +import org.eclipse.jetty.io.AbstractConnection; +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.server.ConnectionFactory; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +public abstract class NegotiatingServerConnection extends AbstractConnection +{ + private static final Logger LOG = Log.getLogger(NegotiatingServerConnection.class); + + private final Connector connector; + private final SSLEngine engine; + private final List protocols; + private final String defaultProtocol; + private String protocol; // No need to be volatile: it is modified and read by the same thread + + protected NegotiatingServerConnection(Connector connector, EndPoint endPoint, SSLEngine engine, List protocols, String defaultProtocol) + { + super(endPoint, connector.getExecutor()); + this.connector = connector; + this.protocols = protocols; + this.defaultProtocol = defaultProtocol; + this.engine = engine; + } + + protected List getProtocols() + { + return protocols; + } + + protected String getDefaultProtocol() + { + return defaultProtocol; + } + + protected SSLEngine getSSLEngine() + { + return engine; + } + + protected String getProtocol() + { + return protocol; + } + + protected void setProtocol(String protocol) + { + this.protocol = protocol; + } + + @Override + public void onOpen() + { + super.onOpen(); + fillInterested(); + } + + @Override + public void onFillable() + { + int filled = fill(); + + if (filled == 0) + { + if (protocol == null) + { + if (engine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) + { + // Here the SSL handshake is finished, but the protocol has not been negotiated. + LOG.debug("{} could not negotiate protocol, SSLEngine: {}", this, engine); + close(); + } + else + { + // Here the SSL handshake is not finished yet but we filled 0 bytes, + // so we need to read more. + fillInterested(); + } + } + else + { + ConnectionFactory connectionFactory = connector.getConnectionFactory(protocol); + if (connectionFactory == null) + { + LOG.debug("{} application selected protocol '{}', but no correspondent {} has been configured", + this, protocol, ConnectionFactory.class.getName()); + close(); + } + else + { + EndPoint endPoint = getEndPoint(); + Connection oldConnection = endPoint.getConnection(); + Connection newConnection = connectionFactory.newConnection(connector, endPoint); + LOG.debug("{} switching from {} to {}", this, oldConnection, newConnection); + oldConnection.onClose(); + endPoint.setConnection(newConnection); + getEndPoint().getConnection().onOpen(); + } + } + } + else if (filled < 0) + { + // Something went bad, we need to close. + LOG.debug("{} closing on client close", this); + close(); + } + else + { + // Must never happen, since we fill using an empty buffer + throw new IllegalStateException(); + } + } + + private int fill() + { + try + { + return getEndPoint().fill(BufferUtil.EMPTY_BUFFER); + } + catch (IOException x) + { + LOG.debug(x); + close(); + return -1; + } + } + + @Override + public void close() + { + // Gentler close for SSL. + getEndPoint().shutdownOutput(); + super.close(); + } +} diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NegotiatingServerConnectionFactory.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NegotiatingServerConnectionFactory.java new file mode 100644 index 00000000000..4ec3e9104b7 --- /dev/null +++ b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/NegotiatingServerConnectionFactory.java @@ -0,0 +1,103 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.spdy.server; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import javax.net.ssl.SSLEngine; + +import org.eclipse.jetty.io.AbstractConnection; +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.io.ssl.SslConnection; +import org.eclipse.jetty.server.AbstractConnectionFactory; +import org.eclipse.jetty.server.Connector; + +public abstract class NegotiatingServerConnectionFactory extends AbstractConnectionFactory +{ + private final List protocols; + private String defaultProtocol; + + public NegotiatingServerConnectionFactory(String protocol, String... protocols) + { + super(protocol); + this.protocols = Arrays.asList(protocols); + } + + public String getDefaultProtocol() + { + return defaultProtocol; + } + + public void setDefaultProtocol(String defaultProtocol) + { + this.defaultProtocol = defaultProtocol; + } + + public List getProtocols() + { + return protocols; + } + + @Override + public Connection newConnection(Connector connector, EndPoint endPoint) + { + List protocols = this.protocols; + if (protocols.isEmpty()) + { + protocols = connector.getProtocols(); + Iterator i = protocols.iterator(); + while (i.hasNext()) + { + String protocol = i.next(); + String prefix = "ssl-"; + if (protocol.regionMatches(true, 0, prefix, 0, prefix.length()) || protocol.equalsIgnoreCase("alpn")) + { + i.remove(); + } + } + } + + String dft = defaultProtocol; + if (dft == null && !protocols.isEmpty()) + dft = protocols.get(0); + + SSLEngine engine = null; + EndPoint ep = endPoint; + while (engine == null && ep != null) + { + // TODO make more generic + if (ep instanceof SslConnection.DecryptedEndPoint) + engine = ((SslConnection.DecryptedEndPoint)ep).getSslConnection().getSSLEngine(); + else + ep = null; + } + + return configure(newServerConnection(connector, endPoint, engine, protocols, dft), connector, endPoint); + } + + protected abstract AbstractConnection newServerConnection(Connector connector, EndPoint endPoint, SSLEngine engine, List protocols, String defaultProtocol); + + @Override + public String toString() + { + return String.format("%s@%x{%s,%s,%s}", getClass().getSimpleName(), hashCode(), getProtocol(), getDefaultProtocol(), getProtocols()); + } +} diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnectionFactory.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnectionFactory.java index 36eaec1a0a8..d6a2a7b92b8 100644 --- a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnectionFactory.java +++ b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnectionFactory.java @@ -47,19 +47,34 @@ import org.eclipse.jetty.util.annotation.ManagedObject; @ManagedObject("SPDY Server Connection Factory") public class SPDYServerConnectionFactory extends AbstractConnectionFactory { - // This method is placed here so as to provide a check for NPN before attempting to load any - // NPN classes. + /** + * @deprecated use {@link #checkProtocolNegotiationAvailable()} instead. + */ + @Deprecated public static void checkNPNAvailable() + { + checkProtocolNegotiationAvailable(); + } + + public static void checkProtocolNegotiationAvailable() + { + if (!isAvailableInBootClassPath("org.eclipse.jetty.alpn.ALPN") && + !isAvailableInBootClassPath("org.eclipse.jetty.npn.NextProtoNego")) + throw new IllegalStateException("No ALPN nor NPN classes available"); + } + + private static boolean isAvailableInBootClassPath(String className) { try { - Class npn = ClassLoader.getSystemClassLoader().loadClass("org.eclipse.jetty.npn.NextProtoNego"); - if (npn.getClassLoader() != null) - throw new IllegalStateException("NextProtoNego must be on JVM boot path"); + Class klass = ClassLoader.getSystemClassLoader().loadClass(className); + if (klass.getClassLoader() != null) + throw new IllegalStateException(className + " must be on JVM boot classpath"); + return true; } - catch (ClassNotFoundException e) + catch (ClassNotFoundException x) { - throw new IllegalStateException("No NextProtoNego on boot path", e); + return false; } } diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnector.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnector.java index f65635f8ec1..35dd6ff148c 100644 --- a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnector.java +++ b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/SPDYServerConnector.java @@ -18,7 +18,8 @@ package org.eclipse.jetty.spdy.server; -import org.eclipse.jetty.server.ConnectionFactory; +import java.util.Objects; + import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; @@ -30,23 +31,21 @@ public class SPDYServerConnector extends ServerConnector { public SPDYServerConnector(Server server, ServerSessionFrameListener listener) { - this(server, null, listener); + super(server, (SslContextFactory)null, new SPDYServerConnectionFactory(SPDY.V2, listener)); } public SPDYServerConnector(Server server, SslContextFactory sslContextFactory, ServerSessionFrameListener listener) { - super(server, - sslContextFactory, - sslContextFactory==null - ?new ConnectionFactory[]{new SPDYServerConnectionFactory(SPDY.V2, listener)} - :new ConnectionFactory[]{ - new NPNServerConnectionFactory("spdy/3","spdy/2","http/1.1"), - new HttpConnectionFactory(), - new SPDYServerConnectionFactory(SPDY.V2, listener), - new SPDYServerConnectionFactory(SPDY.V3, listener)}); - if (getConnectionFactory(NPNServerConnectionFactory.class)!=null) - getConnectionFactory(NPNServerConnectionFactory.class).setDefaultProtocol("http/1.1"); - + this(server, sslContextFactory, listener, new NPNServerConnectionFactory("spdy/3", "spdy/2", "http/1.1")); } + public SPDYServerConnector(Server server, SslContextFactory sslContextFactory, ServerSessionFrameListener listener, NegotiatingServerConnectionFactory negotiator) + { + super(server, Objects.requireNonNull(sslContextFactory), + negotiator, + new SPDYServerConnectionFactory(SPDY.V3, listener), + new SPDYServerConnectionFactory(SPDY.V2, listener), + new HttpConnectionFactory()); + negotiator.setDefaultProtocol("http/1.1"); + } } diff --git a/pom.xml b/pom.xml index fd7ddc0666f..4393f45f742 100644 --- a/pom.xml +++ b/pom.xml @@ -814,137 +814,137 @@ - 7u9 - - - java.version - 1.7.0_9 - - - - 1.1.3.v20130313 - - - - 7u10 - - - java.version - 1.7.0_10 - - - - 1.1.3.v20130313 - - - - 7u11 - - - java.version - 1.7.0_11 - - - - 1.1.3.v20130313 - - - - 7u13 - - - java.version - 1.7.0_13 - - - - 1.1.4.v20130313 - - - - 7u15 - - - java.version - 1.7.0_15 - - - - 1.1.5.v20130313 - - - - 7u17 - - - java.version - 1.7.0_17 - - - - 1.1.5.v20130313 - - - - 7u21 - - - java.version - 1.7.0_21 - - - - 1.1.5.v20130313 - - - - 7u25 - - - java.version - 1.7.0_25 - - - - 1.1.5.v20130313 - - - - 7u40 - - - java.version - 1.7.0_40 - - - - 1.1.6.v20130911 - - - - 7u45 - - - java.version - 1.7.0_45 - - - - 1.1.6.v20130911 - - - - 7u51 - - - java.version - 1.7.0_51 - - - - 1.1.6.v20130911 - - + 7u9 + + + java.version + 1.7.0_9 + + + + 1.1.3.v20130313 + + + + 7u10 + + + java.version + 1.7.0_10 + + + + 1.1.3.v20130313 + + + + 7u11 + + + java.version + 1.7.0_11 + + + + 1.1.3.v20130313 + + + + 7u13 + + + java.version + 1.7.0_13 + + + + 1.1.4.v20130313 + + + + 7u15 + + + java.version + 1.7.0_15 + + + + 1.1.5.v20130313 + + + + 7u17 + + + java.version + 1.7.0_17 + + + + 1.1.5.v20130313 + + + + 7u21 + + + java.version + 1.7.0_21 + + + + 1.1.5.v20130313 + + + + 7u25 + + + java.version + 1.7.0_25 + + + + 1.1.5.v20130313 + + + + 7u40 + + + java.version + 1.7.0_40 + + + + 1.1.6.v20130911 + + + + 7u45 + + + java.version + 1.7.0_45 + + + + 1.1.6.v20130911 + + + + 7u51 + + + java.version + 1.7.0_51 + + + + 1.1.6.v20130911 + + diff --git a/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/TestTransparentProxyServer.java b/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/TestTransparentProxyServer.java index c8b9814d21a..b1be102f65a 100644 --- a/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/TestTransparentProxyServer.java +++ b/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/TestTransparentProxyServer.java @@ -102,7 +102,7 @@ public class TestTransparentProxyServer // Spdy Connector - SPDYServerConnectionFactory.checkNPNAvailable(); + SPDYServerConnectionFactory.checkProtocolNegotiationAvailable(); PushStrategy push = new ReferrerPushStrategy(); HTTPSPDYServerConnectionFactory spdy2 = new HTTPSPDYServerConnectionFactory(2,config,push); spdy2.setInputBufferSize(8192);