From cf1c2451d64bf7ee53a23a59c203bf4deb4fb6ad Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 18 Mar 2014 16:15:08 +0100 Subject: [PATCH] Implemented ALPNServerConnection and refactored common code with NPN. --- .../eclipse/jetty/embedded/SpdyConnector.java | 2 +- .../eclipse/jetty/embedded/SpdyServer.java | 2 +- jetty-spdy/spdy-server/pom.xml | 6 + .../spdy/server/ALPNServerConnection.java | 76 ++++++++ .../server/ALPNServerConnectionFactory.java | 60 +++++++ .../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 | 1 + .../jetty/TestTransparentProxyServer.java | 2 +- 13 files changed, 469 insertions(+), 204 deletions(-) create mode 100644 jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/ALPNServerConnection.java create mode 100644 jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/ALPNServerConnectionFactory.java 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/spdy-server/pom.xml b/jetty-spdy/spdy-server/pom.xml index 298cd8c2ae9..1d3b0a76b96 100644 --- a/jetty-spdy/spdy-server/pom.xml +++ b/jetty-spdy/spdy-server/pom.xml @@ -91,6 +91,12 @@ ${npn.api.version} provided + + org.eclipse.jetty.alpn + alpn-api + ${alpn.api.version} + provided + diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/ALPNServerConnection.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/ALPNServerConnection.java new file mode 100644 index 00000000000..68c134bf6b3 --- /dev/null +++ b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/ALPNServerConnection.java @@ -0,0 +1,76 @@ +// +// ======================================================================== +// 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.Collections; +import java.util.List; +import javax.net.ssl.SSLEngine; + +import org.eclipse.jetty.alpn.ALPN; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +public class ALPNServerConnection extends NegotiatingServerConnection implements ALPN.ServerProvider +{ + private static final Logger LOG = Log.getLogger(ALPNServerConnection.class); + + public ALPNServerConnection(Connector connector, EndPoint endPoint, SSLEngine engine, List protocols, String defaultProtocol) + { + super(connector, endPoint, engine, protocols, defaultProtocol); + ALPN.put(engine, this); + } + + @Override + public void unsupported() + { + select(Collections.emptyList()); + } + + @Override + public String select(List clientProtocols) + { + List serverProtocols = getProtocols(); + String negotiated = null; + for (String clientProtocol : clientProtocols) + { + if (serverProtocols.contains(clientProtocol)) + { + negotiated = clientProtocol; + break; + } + } + if (negotiated == null) + { + negotiated = getDefaultProtocol(); + } + LOG.debug("{} protocol selected {}", this, negotiated); + setProtocol(negotiated); + ALPN.remove(getSSLEngine()); + return negotiated; + } + + @Override + public void close() + { + ALPN.remove(getSSLEngine()); + super.close(); + } +} diff --git a/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/ALPNServerConnectionFactory.java b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/ALPNServerConnectionFactory.java new file mode 100644 index 00000000000..a4b73c5393e --- /dev/null +++ b/jetty-spdy/spdy-server/src/main/java/org/eclipse/jetty/spdy/server/ALPNServerConnectionFactory.java @@ -0,0 +1,60 @@ +// +// ======================================================================== +// 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.List; +import javax.net.ssl.SSLEngine; + +import org.eclipse.jetty.alpn.ALPN; +import org.eclipse.jetty.io.AbstractConnection; +import org.eclipse.jetty.io.EndPoint; +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 ALPNServerConnectionFactory extends NegotiatingServerConnectionFactory +{ + private static final Logger LOG = Log.getLogger(ALPNServerConnectionFactory.class); + + public ALPNServerConnectionFactory(@Name("protocols") String... protocols) + { + super("alpn", protocols); + try + { + ClassLoader alpnClassLoader = ALPN.class.getClassLoader(); + if (alpnClassLoader != null) + { + LOG.warn("ALPN must be in the boot classloader, not in: " + alpnClassLoader); + throw new IllegalStateException("ALPN must be in the boot classloader"); + } + } + catch (Throwable x) + { + LOG.warn("ALPN not available", x); + throw new IllegalStateException("ALPN not available", x); + } + } + + @Override + protected AbstractConnection newServerConnection(Connector connector, EndPoint endPoint, SSLEngine engine, List protocols, String defaultProtocol) + { + return new ALPNServerConnection(connector, endPoint, engine, protocols, defaultProtocol); + } +} 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..01652df7c5d --- /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 + + public 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..920b41eac36 100644 --- a/pom.xml +++ b/pom.xml @@ -17,6 +17,7 @@ 1.6.1 1.2 1.1.0.v20120525 + 1.0.0-SNAPSHOT scm:git:http://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project.git 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);