Merge branch 'jetty-9.4.x' of github.com:eclipse/jetty.project into jetty-9.4.x

This commit is contained in:
Joakim Erdfelt 2017-09-20 14:46:26 -07:00
commit 14573025f0
51 changed files with 1244 additions and 259 deletions

View File

@ -75,6 +75,16 @@
<artifactId>jetty-alpn-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-openjdk8-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-conscrypt-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-annotations</artifactId>
@ -131,4 +141,20 @@
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>jdk9</id>
<activation>
<jdk>[1.9,)</jdk>
</activation>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-java-server</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</profile>
</profiles>
</project>

View File

@ -19,8 +19,10 @@
package org.eclipse.jetty.embedded;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.nio.file.Files;
import java.util.Date;
import java.util.EnumSet;
@ -64,7 +66,7 @@ import org.eclipse.jetty.util.ssl.SslContextFactory;
public class Http2Server
{
public static void main(String... args) throws Exception
{
{
Server server = new Server();
MBeanContainer mbContainer = new MBeanContainer(
@ -72,7 +74,10 @@ public class Http2Server
server.addBean(mbContainer);
ServletContextHandler context = new ServletContextHandler(server, "/",ServletContextHandler.SESSIONS);
context.setResourceBase("src/main/resources/docroot");
String docroot = "src/main/resources/docroot";
if (!new File(docroot).exists())
docroot = "examples/embedded/src/main/resources/docroot";
context.setResourceBase(docroot);
context.addFilter(PushCacheFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST));
// context.addFilter(PushSessionCacheFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST));
context.addFilter(PushedTilesFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST));
@ -94,11 +99,14 @@ public class Http2Server
// SSL Context Factory for HTTPS and HTTP/2
String jetty_distro = System.getProperty("jetty.distro","../../jetty-distribution/target/distribution");
if (!new File(jetty_distro).exists())
jetty_distro = "jetty-distribution/target/distribution";
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath(jetty_distro + "/demo-base/etc/keystore");
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
sslContextFactory.setCipherComparator(HTTP2Cipher.COMPARATOR);
// sslContextFactory.setProvider("Conscrypt");
// HTTPS Configuration
HttpConfiguration https_config = new HttpConfiguration(http_config);

View File

@ -8,3 +8,4 @@
#org.eclipse.jetty.io.ssl.LEVEL=DEBUG
#org.eclipse.jetty.server.LEVEL=DEBUG
#org.eclipse.jetty.servlets.LEVEL=DEBUG
org.eclipse.jetty.alpn.LEVEL=DEBUG

View File

@ -50,12 +50,6 @@
<artifactId>jetty-io</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.alpn</groupId>
<artifactId>alpn-api</artifactId>
<version>${alpn.api.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>

View File

@ -24,14 +24,13 @@ import java.util.concurrent.Executor;
import javax.net.ssl.SSLEngine;
import org.eclipse.jetty.alpn.ALPN;
import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.NegotiatingClientConnection;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class ALPNClientConnection extends NegotiatingClientConnection implements ALPN.ClientProvider
public class ALPNClientConnection extends NegotiatingClientConnection
{
private static final Logger LOG = Log.getLogger(ALPNClientConnection.class);
@ -41,41 +40,18 @@ public class ALPNClientConnection extends NegotiatingClientConnection implements
{
super(endPoint, executor, sslEngine, connectionFactory, context);
this.protocols = protocols;
ALPN.put(sslEngine, this);
}
@Override
public void unsupported()
{
ALPN.remove(getSSLEngine());
completed();
}
@Override
public List<String> protocols()
public List<String> getProtocols()
{
return protocols;
}
@Override
public void selected(String protocol)
{
if (protocols.contains(protocol))
{
ALPN.remove(getSSLEngine());
completed();
}
else
{
LOG.info("Could not negotiate protocol: server [{}] - client {}", protocol, protocols);
if (protocol==null || !protocols.contains(protocol))
close();
}
}
@Override
public void close()
{
ALPN.remove(getSSLEngine());
super.close();
else
super.completed();
}
}

View File

@ -19,7 +19,7 @@
package org.eclipse.jetty.alpn.client;
import java.io.IOException;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
@ -31,17 +31,19 @@ import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.NegotiatingClientConnectionFactory;
import org.eclipse.jetty.io.ssl.ALPNProcessor;
import org.eclipse.jetty.io.ssl.ALPNProcessor.Client;
import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
import org.eclipse.jetty.io.ssl.SslHandshakeListener;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFactory implements SslHandshakeListener
{
private final SslHandshakeListener alpnListener = new ALPNListener();
private static final Logger LOG = Log.getLogger(ALPNClientConnectionFactory.class);
private final List<Client> processors = new ArrayList<>();
private final Executor executor;
private final List<String> protocols;
private final ALPNProcessor.Client alpnProcessor;
public ALPNClientConnectionFactory(Executor executor, ClientConnectionFactory connectionFactory, List<String> protocols)
{
@ -50,39 +52,49 @@ public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFact
throw new IllegalArgumentException("ALPN protocol list cannot be empty");
this.executor = executor;
this.protocols = protocols;
Iterator<ALPNProcessor.Client> processors = ServiceLoader.load(ALPNProcessor.Client.class).iterator();
alpnProcessor = processors.hasNext() ? processors.next() : ALPNProcessor.Client.NOOP;
}
public ALPNProcessor.Client getALPNProcessor()
{
return alpnProcessor;
IllegalStateException failure = new IllegalStateException("No Client ALPNProcessors!");
for (Client processor : ServiceLoader.load(Client.class))
{
try
{
processor.init();
processors.add(processor);
}
catch (Throwable x)
{
if (LOG.isDebugEnabled())
LOG.debug("Could not initialize " + processor, x);
failure.addSuppressed(x);
}
}
if (LOG.isDebugEnabled())
{
LOG.debug("protocols: {}", protocols);
LOG.debug("processors: {}", processors);
}
if (processors.isEmpty())
throw failure;
}
@Override
public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
{
SSLEngine sslEngine = (SSLEngine)context.get(SslClientConnectionFactory.SSL_ENGINE_CONTEXT_KEY);
getALPNProcessor().configure(sslEngine, protocols);
ContainerLifeCycle connector = (ContainerLifeCycle)context.get(ClientConnectionFactory.CONNECTOR_CONTEXT_KEY);
// Method addBean() has set semantic, so the listener is added only once.
connector.addBean(alpnListener);
ALPNClientConnection connection = new ALPNClientConnection(endPoint, executor, getClientConnectionFactory(),
sslEngine, context, protocols);
return customize(connection, context);
}
private class ALPNListener implements SslHandshakeListener
{
@Override
public void handshakeSucceeded(Event event)
{
getALPNProcessor().process(event.getSSLEngine());
}
@Override
public void handshakeFailed(Event event, Throwable failure)
SSLEngine engine = (SSLEngine)context.get(SslClientConnectionFactory.SSL_ENGINE_CONTEXT_KEY);
for (Client processor : processors)
{
if (processor.appliesTo(engine))
{
if (LOG.isDebugEnabled())
LOG.debug("{} for {} on {}", processor, engine, endPoint);
ALPNClientConnection connection = new ALPNClientConnection(endPoint, executor, getClientConnectionFactory(),
engine, context, protocols);
processor.configure(engine, connection);
return customize(connection, context);
}
}
throw new IllegalStateException("No ALPNProcessor for " + engine);
}
}

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-parent</artifactId>
<version>9.4.8-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-alpn-conscrypt-client</artifactId>
<name>Jetty :: ALPN :: Conscrypt Client Implementation</name>
<properties>
<bundle-symbolic-name>${project.groupId}.alpn.java.client</bundle-symbolic-name>
<conscrypt.version>1.0.0.RC10</conscrypt.version>
</properties>
<dependencies>
<dependency>
<groupId>org.conscrypt</groupId>
<artifactId>conscrypt-openjdk-uber</artifactId>
<version>${conscrypt.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-client</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,107 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.alpn.conscrypt.client;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.security.Security;
import javax.net.ssl.SSLEngine;
import org.conscrypt.OpenSSLProvider;
import org.eclipse.jetty.alpn.client.ALPNClientConnection;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.ssl.ALPNProcessor;
import org.eclipse.jetty.io.ssl.SslConnection;
import org.eclipse.jetty.io.ssl.SslHandshakeListener;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class ConscryptClientALPNProcessor implements ALPNProcessor.Client
{
private static final Logger LOG = Log.getLogger(ConscryptClientALPNProcessor.class);
@Override
public void init()
{
if (Security.getProvider("Conscrypt")==null)
{
Security.addProvider(new OpenSSLProvider());
if (LOG.isDebugEnabled())
LOG.debug("Added Conscrypt provider");
}
}
@Override
public boolean appliesTo(SSLEngine sslEngine)
{
return sslEngine.getClass().getName().startsWith("org.conscrypt.");
}
@Override
public void configure(SSLEngine sslEngine, Connection connection)
{
try
{
Method setAlpnProtocols = sslEngine.getClass().getDeclaredMethod("setAlpnProtocols", String[].class);
setAlpnProtocols.setAccessible(true);
ALPNClientConnection alpn = (ALPNClientConnection)connection;
String[] protocols = alpn.getProtocols().toArray(new String[0]);
setAlpnProtocols.invoke(sslEngine, (Object)protocols);
((SslConnection.DecryptedEndPoint)connection.getEndPoint()).getSslConnection()
.addHandshakeListener(new ALPNListener(alpn));
}
catch (RuntimeException x)
{
throw x;
}
catch (Exception x)
{
throw new RuntimeException(x);
}
}
private final class ALPNListener implements SslHandshakeListener
{
private final ALPNClientConnection alpnConnection;
private ALPNListener(ALPNClientConnection connection)
{
alpnConnection = connection;
}
@Override
public void handshakeSucceeded(Event event)
{
try
{
SSLEngine sslEngine = alpnConnection.getSSLEngine();
Method method = sslEngine.getClass().getDeclaredMethod("getAlpnSelectedProtocol");
method.setAccessible(true);
String protocol = new String((byte[])method.invoke(sslEngine), StandardCharsets.US_ASCII);
alpnConnection.selected(protocol);
}
catch (Throwable e)
{
alpnConnection.selected(null);
LOG.warn(e);
}
}
}
}

View File

@ -0,0 +1 @@
org.eclipse.jetty.alpn.conscrypt.client.ConscryptClientALPNProcessor

View File

@ -0,0 +1,89 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.alpn.java.client;
import java.net.InetSocketAddress;
import java.security.Security;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.conscrypt.OpenSSLProvider;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.api.Stream;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.frames.DataFrame;
import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.Jetty;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.ssl.SslContextFactory;
public class ConscryptHTTP2Client
{
public static void main(String[] args) throws Exception
{
Security.addProvider(new OpenSSLProvider());
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setProvider("Conscrypt");
HTTP2Client client = new HTTP2Client();
client.addBean(sslContextFactory);
client.start();
String host = "webtide.com";
int port = 443;
FuturePromise<Session> sessionPromise = new FuturePromise<>();
client.connect(sslContextFactory, new InetSocketAddress(host, port), new Session.Listener.Adapter(), sessionPromise);
Session session = sessionPromise.get(5, TimeUnit.SECONDS);
HttpFields requestFields = new HttpFields();
requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION);
MetaData.Request metaData = new MetaData.Request("GET", new HttpURI("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields);
HeadersFrame headersFrame = new HeadersFrame(metaData, null, true);
CountDownLatch latch = new CountDownLatch(1);
session.newStream(headersFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@Override
public void onHeaders(Stream stream, HeadersFrame frame)
{
System.err.println(frame);
if (frame.isEndStream())
latch.countDown();
}
@Override
public void onData(Stream stream, DataFrame frame, Callback callback)
{
System.err.println(frame);
callback.succeeded();
if (frame.isEndStream())
latch.countDown();
}
});
latch.await(5, TimeUnit.SECONDS);
client.stop();
}
}

View File

@ -0,0 +1,2 @@
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
#org.eclipse.jetty.LEVEL=DEBUG

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-parent</artifactId>
<version>9.4.8-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-alpn-conscrypt-server</artifactId>
<name>Jetty :: ALPN :: Conscrypt Server Implementation</name>
<properties>
<bundle-symbolic-name>${project.groupId}.alpn.conscrypt.server</bundle-symbolic-name>
<conscrypt.version>1.0.0.RC10</conscrypt.version>
</properties>
<dependencies>
<dependency>
<groupId>org.conscrypt</groupId>
<artifactId>conscrypt-openjdk-uber</artifactId>
<version>${conscrypt.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-io</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,115 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.alpn.conscrypt.server;
import java.lang.reflect.Method;
import java.security.Security;
import java.util.List;
import java.util.function.BiFunction;
import javax.net.ssl.SSLEngine;
import org.conscrypt.OpenSSLProvider;
import org.eclipse.jetty.alpn.server.ALPNServerConnection;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.ssl.ALPNProcessor;
import org.eclipse.jetty.io.ssl.SslConnection.DecryptedEndPoint;
import org.eclipse.jetty.io.ssl.SslHandshakeListener;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class ConscryptServerALPNProcessor implements ALPNProcessor.Server
{
private static final Logger LOG = Log.getLogger(ConscryptServerALPNProcessor.class);
@Override
public void init()
{
if (Security.getProvider("Conscrypt")==null)
{
Security.addProvider(new OpenSSLProvider());
if (LOG.isDebugEnabled())
LOG.debug("Added Conscrypt provider");
}
}
@Override
public boolean appliesTo(SSLEngine sslEngine)
{
return sslEngine.getClass().getName().startsWith("org.conscrypt.");
}
@Override
public void configure(SSLEngine sslEngine,Connection connection)
{
try
{
Method method = sslEngine.getClass().getMethod("setHandshakeApplicationProtocolSelector", BiFunction.class);
method.setAccessible(true);
method.invoke(sslEngine,new ALPNCallback((ALPNServerConnection)connection));
}
catch (RuntimeException x)
{
throw x;
}
catch (Exception x)
{
throw new RuntimeException(x);
}
}
private final class ALPNCallback implements BiFunction<SSLEngine,List<String>,String>, SslHandshakeListener
{
private final ALPNServerConnection alpnConnection;
private ALPNCallback(ALPNServerConnection connection)
{
alpnConnection = connection;
((DecryptedEndPoint)alpnConnection.getEndPoint()).getSslConnection().addHandshakeListener(this);
}
@Override
public String apply(SSLEngine engine, List<String> protocols)
{
if (LOG.isDebugEnabled())
LOG.debug("apply {} {}", alpnConnection, protocols);
alpnConnection.select(protocols);
return alpnConnection.getProtocol();
}
@Override
public void handshakeSucceeded(Event event)
{
if (LOG.isDebugEnabled())
LOG.debug("handshakeSucceeded {} {}", alpnConnection, event);
if (alpnConnection.getProtocol()==null)
{
LOG.warn("No ALPN callback! {} {}",alpnConnection, event);
alpnConnection.unsupported();
}
}
@Override
public void handshakeFailed(Event event, Throwable failure)
{
if (LOG.isDebugEnabled())
LOG.debug("handshakeFailed {} {} {}", alpnConnection, event, failure);
}
}
}

View File

@ -0,0 +1 @@
org.eclipse.jetty.alpn.conscrypt.server.ConscryptServerALPNProcessor

View File

@ -0,0 +1,72 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.alpn.conscrypt.server;
import java.security.Security;
import org.conscrypt.OpenSSLProvider;
import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
import org.eclipse.jetty.http2.HTTP2Cipher;
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.util.ssl.SslContextFactory;
/**
* Test server that verifies that the Conscrypt ALPN mechanism works.
*/
public class ConscryptHTTP2Server
{
public static void main(String[] args) throws Exception
{
Security.addProvider(new OpenSSLProvider());
Server server = new Server();
HttpConfiguration httpsConfig = new HttpConfiguration();
httpsConfig.setSecureScheme("https");
httpsConfig.setSecurePort(8443);
httpsConfig.setSendXPoweredBy(true);
httpsConfig.setSendServerVersion(true);
httpsConfig.addCustomizer(new SecureRequestCustomizer());
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setProvider("Conscrypt");
sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
sslContextFactory.setCipherComparator(HTTP2Cipher.COMPARATOR);
HttpConnectionFactory http = new HttpConnectionFactory(httpsConfig);
HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpsConfig);
ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
alpn.setDefaultProtocol(http.getProtocol());
SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory, alpn.getProtocol());
ServerConnector http2Connector = new ServerConnector(server, ssl, alpn, h2, http);
http2Connector.setPort(8443);
server.addConnector(http2Connector);
server.start();
}
}

View File

@ -0,0 +1,3 @@
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
#org.eclipse.jetty.LEVEL=DEBUG
#org.eclipse.jetty.alpn.LEVEL=DEBUG

View File

@ -33,22 +33,15 @@
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-io</artifactId>
<artifactId>jetty-alpn-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.alpn</groupId>
<artifactId>alpn-api</artifactId>
<version>${alpn.api.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-client</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -18,38 +18,66 @@
package org.eclipse.jetty.alpn.java.client;
import java.io.UncheckedIOException;
import java.util.List;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLParameters;
import org.eclipse.jetty.alpn.ALPN;
import org.eclipse.jetty.alpn.client.ALPNClientConnection;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.ssl.ALPNProcessor;
import org.eclipse.jetty.io.ssl.SslConnection.DecryptedEndPoint;
import org.eclipse.jetty.io.ssl.SslHandshakeListener;
import org.eclipse.jetty.util.JavaVersion;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class JDK9ClientALPNProcessor implements ALPNProcessor.Client
{
private static final Logger LOG = Log.getLogger(JDK9ClientALPNProcessor.class);
@Override
public void configure(SSLEngine sslEngine, List<String> protocols)
public void init()
{
SSLParameters sslParameters = sslEngine.getSSLParameters();
sslParameters.setApplicationProtocols(protocols.toArray(new String[0]));
sslEngine.setSSLParameters(sslParameters);
if (JavaVersion.VERSION.getPlatform()<9)
throw new IllegalStateException(this + " not applicable for java "+JavaVersion.VERSION);
}
@Override
public void process(SSLEngine sslEngine)
public boolean appliesTo(SSLEngine sslEngine)
{
try
Module module = sslEngine.getClass().getModule();
return module!=null && "java.base".equals(module.getName());
}
@Override
public void configure(SSLEngine sslEngine, Connection connection)
{
ALPNClientConnection alpn = (ALPNClientConnection)connection;
SSLParameters sslParameters = sslEngine.getSSLParameters();
List<String> protocols = alpn.getProtocols();
sslParameters.setApplicationProtocols(protocols.toArray(new String[protocols.size()]));
sslEngine.setSSLParameters(sslParameters);
((DecryptedEndPoint)connection.getEndPoint()).getSslConnection()
.addHandshakeListener(new ALPNListener(alpn));
}
private final class ALPNListener implements SslHandshakeListener
{
private final ALPNClientConnection alpnConnection;
private ALPNListener(ALPNClientConnection connection)
{
ALPN.ClientProvider provider = (ALPN.ClientProvider)ALPN.get(sslEngine);
if (provider != null)
provider.selected(sslEngine.getApplicationProtocol());
alpnConnection = connection;
}
catch (SSLException x)
@Override
public void handshakeSucceeded(Event event)
{
throw new UncheckedIOException(x);
String protocol = alpnConnection.getSSLEngine().getApplicationProtocol();
if (LOG.isDebugEnabled())
LOG.debug("selected protocol {}", protocol);
alpnConnection.selected(protocol);
}
}
}

View File

@ -42,16 +42,16 @@ public class JDK9HTTP2Client
public static void main(String[] args) throws Exception
{
HTTP2Client client = new HTTP2Client();
SslContextFactory sslContextFactory = new SslContextFactory(true);
SslContextFactory sslContextFactory = new SslContextFactory();
client.addBean(sslContextFactory);
client.start();
String host = "localhost";
int port = 8443;
String host = "webtide.com";
int port = 443;
FuturePromise<Session> sessionPromise = new FuturePromise<>();
client.connect(sslContextFactory, new InetSocketAddress(host, port), new Session.Listener.Adapter(), sessionPromise);
Session session = sessionPromise.get(555, TimeUnit.SECONDS);
Session session = sessionPromise.get(5, TimeUnit.SECONDS);
HttpFields requestFields = new HttpFields();
requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION);

View File

@ -40,12 +40,10 @@
<artifactId>alpn-api</artifactId>
<version>${alpn.api.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<artifactId>jetty-alpn-server</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
@ -53,12 +51,6 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-server</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>

View File

@ -19,13 +19,16 @@
package org.eclipse.jetty.alpn.java.server;
import java.util.List;
import java.util.function.BiFunction;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import org.eclipse.jetty.alpn.ALPN;
import org.eclipse.jetty.alpn.server.ALPNServerConnection;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.ssl.ALPNProcessor;
import org.eclipse.jetty.io.ssl.SslConnection;
import org.eclipse.jetty.io.ssl.SslHandshakeListener;
import org.eclipse.jetty.util.JavaVersion;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -34,40 +37,61 @@ public class JDK9ServerALPNProcessor implements ALPNProcessor.Server, SslHandsha
private static final Logger LOG = Log.getLogger(JDK9ServerALPNProcessor.class);
@Override
public void configure(SSLEngine sslEngine)
public void init()
{
sslEngine.setHandshakeApplicationProtocolSelector(this::process);
}
private String process(SSLEngine sslEngine, List<String> protocols)
{
try
{
if (LOG.isDebugEnabled())
LOG.debug("ALPN selecting among client{}", protocols);
ALPN.ServerProvider provider = (ALPN.ServerProvider)ALPN.remove(sslEngine);
return provider == null ? "" : provider.select(protocols);
}
catch (SSLException x)
{
return null;
}
if (JavaVersion.VERSION.getPlatform()<9)
throw new IllegalStateException(this + " not applicable for java "+JavaVersion.VERSION);
}
@Override
public void handshakeSucceeded(Event event)
public boolean appliesTo(SSLEngine sslEngine)
{
ALPN.ServerProvider provider = (ALPN.ServerProvider)ALPN.remove(event.getSSLEngine());
if (provider != null)
{
if (LOG.isDebugEnabled())
LOG.debug("ALPN unsupported by client");
provider.unsupported();
}
Module module = sslEngine.getClass().getModule();
return module!=null && "java.base".equals(module.getName());
}
@Override
public void handshakeFailed(Event event, Throwable failure)
public void configure(SSLEngine sslEngine, Connection connection)
{
sslEngine.setHandshakeApplicationProtocolSelector(new ALPNCallback((ALPNServerConnection)connection));
}
private final class ALPNCallback implements BiFunction<SSLEngine,List<String>,String>, SslHandshakeListener
{
private final ALPNServerConnection alpnConnection;
private ALPNCallback(ALPNServerConnection connection)
{
alpnConnection = connection;
((SslConnection.DecryptedEndPoint)alpnConnection.getEndPoint()).getSslConnection().addHandshakeListener(this);
}
@Override
public String apply(SSLEngine engine, List<String> protocols)
{
if (LOG.isDebugEnabled())
LOG.debug("apply {} {}", alpnConnection, protocols);
alpnConnection.select(protocols);
return alpnConnection.getProtocol();
}
@Override
public void handshakeSucceeded(Event event)
{
if (LOG.isDebugEnabled())
LOG.debug("handshakeSucceeded {} {}", alpnConnection, event);
if (alpnConnection.getProtocol()==null)
{
LOG.warn("No ALPN callback! {} {}",alpnConnection, event);
alpnConnection.unsupported();
}
}
@Override
public void handshakeFailed(Event event, Throwable failure)
{
if (LOG.isDebugEnabled())
LOG.debug("handshakeFailed {} {} {}", alpnConnection, event, failure);
}
}
}

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-parent</artifactId>
<version>9.4.8-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-alpn-openjdk8-client</artifactId>
<name>Jetty :: ALPN :: OpenJDK8 Client Implementation</name>
<properties>
<bundle-symbolic-name>${project.groupId}.alpn.java.client</bundle-symbolic-name>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.alpn</groupId>
<artifactId>alpn-api</artifactId>
<version>${alpn.api.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-client</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,104 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.alpn.java.client;
import java.util.List;
import javax.net.ssl.SSLEngine;
import org.eclipse.jetty.alpn.ALPN;
import org.eclipse.jetty.alpn.client.ALPNClientConnection;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.ssl.ALPNProcessor;
import org.eclipse.jetty.util.JavaVersion;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class OpenJDK8ClientALPNProcessor implements ALPNProcessor.Client
{
private static final Logger LOG = Log.getLogger(OpenJDK8ClientALPNProcessor.class);
@Override
public void init()
{
if (JavaVersion.VERSION.getPlatform()!=8)
throw new IllegalStateException(this + " not applicable for java "+JavaVersion.VERSION);
if (ALPN.class.getClassLoader()!=null)
throw new IllegalStateException(this + " must be on JVM boot classpath");
}
@Override
public boolean appliesTo(SSLEngine sslEngine)
{
return sslEngine.getClass().getName().startsWith("sun.security.ssl.");
}
@Override
public void configure(SSLEngine sslEngine, Connection connection)
{
connection.addListener(new ALPNListener((ALPNClientConnection)connection));
}
private final class ALPNListener implements ALPN.ClientProvider, Connection.Listener
{
private final ALPNClientConnection alpnConnection;
private ALPNListener(ALPNClientConnection connection)
{
alpnConnection = connection;
}
@Override
public void onOpened(Connection connection)
{
if (LOG.isDebugEnabled())
LOG.debug("onOpened {}", alpnConnection);
ALPN.put(alpnConnection.getSSLEngine(), this);
}
@Override
public void onClosed(Connection connection)
{
if (LOG.isDebugEnabled())
LOG.debug("onClosed {}", alpnConnection);
ALPN.remove(alpnConnection.getSSLEngine());
}
@Override
public List<String> protocols()
{
return alpnConnection.getProtocols();
}
@Override
public void unsupported()
{
if (LOG.isDebugEnabled())
LOG.debug("unsupported {}", alpnConnection);
ALPN.remove(alpnConnection.getSSLEngine());
alpnConnection.selected(null);
}
@Override
public void selected(String protocol)
{
alpnConnection.selected(protocol);
}
}
}

View File

@ -0,0 +1 @@
org.eclipse.jetty.alpn.java.client.OpenJDK8ClientALPNProcessor

View File

@ -0,0 +1,85 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.alpn.java.client;
import java.net.InetSocketAddress;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.api.Stream;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.frames.DataFrame;
import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.Jetty;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.ssl.SslContextFactory;
public class OpenJDK8HTTP2Client
{
public static void main(String[] args) throws Exception
{
HTTP2Client client = new HTTP2Client();
SslContextFactory sslContextFactory = new SslContextFactory();
client.addBean(sslContextFactory);
client.start();
String host = "webtide.com";
int port = 443;
FuturePromise<Session> sessionPromise = new FuturePromise<>();
client.connect(sslContextFactory, new InetSocketAddress(host, port), new Session.Listener.Adapter(), sessionPromise);
Session session = sessionPromise.get(5, TimeUnit.SECONDS);
HttpFields requestFields = new HttpFields();
requestFields.put("User-Agent", client.getClass().getName() + "/" + Jetty.VERSION);
MetaData.Request metaData = new MetaData.Request("GET", new HttpURI("https://" + host + ":" + port + "/"), HttpVersion.HTTP_2, requestFields);
HeadersFrame headersFrame = new HeadersFrame(metaData, null, true);
CountDownLatch latch = new CountDownLatch(1);
session.newStream(headersFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@Override
public void onHeaders(Stream stream, HeadersFrame frame)
{
System.err.println(frame);
if (frame.isEndStream())
latch.countDown();
}
@Override
public void onData(Stream stream, DataFrame frame, Callback callback)
{
System.err.println(frame);
callback.succeeded();
if (frame.isEndStream())
latch.countDown();
}
});
latch.await(5, TimeUnit.SECONDS);
client.stop();
}
}

View File

@ -0,0 +1,2 @@
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
#org.eclipse.jetty.LEVEL=DEBUG

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-parent</artifactId>
<version>9.4.8-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-alpn-openjdk8-server</artifactId>
<name>Jetty :: ALPN :: OpenJDK8 Server Implementation</name>
<properties>
<bundle-symbolic-name>${project.groupId}.alpn.conscrypt.server</bundle-symbolic-name>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.alpn</groupId>
<artifactId>alpn-api</artifactId>
<version>${alpn.api.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-io</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,104 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.alpn.openjdk8.server;
import java.util.Collections;
import java.util.List;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import org.eclipse.jetty.alpn.ALPN;
import org.eclipse.jetty.alpn.server.ALPNServerConnection;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.ssl.ALPNProcessor;
import org.eclipse.jetty.util.JavaVersion;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class OpenJDK8ServerALPNProcessor implements ALPNProcessor.Server
{
private static final Logger LOG = Log.getLogger(OpenJDK8ServerALPNProcessor.class);
@Override
public void init()
{
if (JavaVersion.VERSION.getPlatform()!=8)
throw new IllegalStateException(this + " not applicable for java "+JavaVersion.VERSION);
if (ALPN.class.getClassLoader()!=null)
throw new IllegalStateException(ALPN.class.getName() + " must be on JVM boot classpath");
if (LOG.isDebugEnabled())
ALPN.debug = true;
}
@Override
public boolean appliesTo(SSLEngine sslEngine)
{
return sslEngine.getClass().getName().startsWith("sun.security.ssl.");
}
@Override
public void configure(SSLEngine sslEngine, Connection connection)
{
connection.addListener(new ALPNListener((ALPNServerConnection)connection));
}
private final class ALPNListener implements ALPN.ServerProvider, Connection.Listener
{
private final ALPNServerConnection alpnConnection;
private ALPNListener(ALPNServerConnection connection)
{
alpnConnection = connection;
}
@Override
public void onOpened(Connection connection)
{
if (LOG.isDebugEnabled())
LOG.debug("onOpened {}", alpnConnection);
ALPN.put(alpnConnection.getSSLEngine(), this);
}
@Override
public void onClosed(Connection connection)
{
if (LOG.isDebugEnabled())
LOG.debug("onClosed {}", alpnConnection);
ALPN.remove(alpnConnection.getSSLEngine());
}
@Override
public void unsupported()
{
if (LOG.isDebugEnabled())
LOG.debug("unsupported {}", alpnConnection);
alpnConnection.select(Collections.emptyList());
}
@Override
public String select(List<String> protocols) throws SSLException
{
if (LOG.isDebugEnabled())
LOG.debug("select {} {}", alpnConnection, protocols);
alpnConnection.select(protocols);
return alpnConnection.getProtocol();
}
}
}

View File

@ -0,0 +1 @@
org.eclipse.jetty.alpn.openjdk8.server.OpenJDK8ServerALPNProcessor

View File

@ -0,0 +1,66 @@
//
// ========================================================================
// Copyright (c) 1995-2017 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.alpn.openjdk8.server;
import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
import org.eclipse.jetty.http2.HTTP2Cipher;
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.util.ssl.SslContextFactory;
/**
* Test server that verifies that the JDK 8 ALPN mechanism works.
*/
public class OpenJDK8HTTP2Server
{
public static void main(String... args) throws Exception
{
Server server = new Server();
HttpConfiguration httpsConfig = new HttpConfiguration();
httpsConfig.setSecureScheme("https");
httpsConfig.setSecurePort(8443);
httpsConfig.setSendXPoweredBy(true);
httpsConfig.setSendServerVersion(true);
httpsConfig.addCustomizer(new SecureRequestCustomizer());
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
sslContextFactory.setCipherComparator(HTTP2Cipher.COMPARATOR);
HttpConnectionFactory http = new HttpConnectionFactory(httpsConfig);
HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpsConfig);
ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
alpn.setDefaultProtocol(http.getProtocol());
SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory, alpn.getProtocol());
ServerConnector http2Connector = new ServerConnector(server, ssl, alpn, h2, http);
http2Connector.setPort(8443);
server.addConnector(http2Connector);
server.start();
}
}

View File

@ -0,0 +1,3 @@
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
#org.eclipse.jetty.LEVEL=DEBUG
#org.eclipse.jetty.alpn.LEVEL=DEBUG

View File

@ -59,12 +59,6 @@
<artifactId>jetty-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.alpn</groupId>
<artifactId>alpn-api</artifactId>
<version>${alpn.api.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>

View File

@ -15,18 +15,9 @@
<Call name="addConnectionFactory">
<Arg>
<New id="alpn" class="org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory">
<Arg type="String">
<Property name="jetty.alpn.protocols" deprecated="alpn.protocols" default="" />
</Arg>
<Set name="defaultProtocol">
<Property name="jetty.alpn.defaultProtocol" deprecated="alpn.defaultProtocol" />
</Set>
<Arg name="protocols" type="String"><Property name="jetty.alpn.protocols" deprecated="alpn.protocols" default="" /></Arg>
<Set name="defaultProtocol"><Property name="jetty.alpn.defaultProtocol" deprecated="alpn.defaultProtocol" /></Set>
</New>
</Arg>
</Call>
<!-- ALPN debugging on System.err -->
<Set class="org.eclipse.jetty.alpn.ALPN" name="debug" type="boolean"><Property name="jetty.alpn.debug" default="false" /></Set>
</Configure>

View File

@ -0,0 +1,5 @@
[description]
Selects an ALPN (Application Layer Protocol Negotiation) implementation by java version.
[depend]
alpn-impl/alpn-${java.version.platform}

View File

@ -17,6 +17,9 @@ specific version of Java.
[depend]
alpn-impl/alpn-${java.version}
[lib]
lib/jetty-alpn-openjdk8-server-${jetty.version}.jar
[files]
lib/
lib/alpn/

View File

@ -3,7 +3,7 @@ Enables the ALPN (Application Layer Protocol Negotiation) TLS extension.
[depend]
ssl
alpn-impl/alpn-${java.version.platform}
alpn-impl
[lib]
lib/jetty-alpn-client-${jetty.version}.jar
@ -21,6 +21,3 @@ etc/jetty-alpn.xml
## Specifies what protocol to use when negotiation fails.
# jetty.alpn.defaultProtocol=http/1.1
## ALPN debug logging on System.err
# jetty.alpn.debug=false

View File

@ -24,7 +24,6 @@ import java.util.List;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSession;
import org.eclipse.jetty.alpn.ALPN;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.ConnectionFactory;
import org.eclipse.jetty.server.Connector;
@ -32,24 +31,21 @@ import org.eclipse.jetty.server.NegotiatingServerConnection;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class ALPNServerConnection extends NegotiatingServerConnection implements ALPN.ServerProvider
public class ALPNServerConnection extends NegotiatingServerConnection
{
private static final Logger LOG = Log.getLogger(ALPNServerConnection.class);
public ALPNServerConnection(Connector connector, EndPoint endPoint, SSLEngine engine, List<String> 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<String> clientProtocols)
public void select(List<String> clientProtocols)
{
SSLEngine sslEngine = getSSLEngine();
List<String> serverProtocols = getProtocols();
@ -70,7 +66,7 @@ public class ALPNServerConnection extends NegotiatingServerConnection implements
if (factory instanceof CipherDiscriminator && !((CipherDiscriminator)factory).isAcceptable(serverProtocol, tlsProtocol, tlsCipher))
{
if (LOG.isDebugEnabled())
LOG.debug("{} protocol {} not acceptable to {} for {}/{}", this, serverProtocol, factory, tlsProtocol, tlsCipher);
LOG.debug("Protocol {} not acceptable to {} for {}/{} on {}", serverProtocol, factory, tlsProtocol, tlsCipher, getEndPoint());
continue;
}
@ -87,21 +83,12 @@ public class ALPNServerConnection extends NegotiatingServerConnection implements
else
{
if (LOG.isDebugEnabled())
LOG.debug("{} could not negotiate protocol among client{} and server{}", this, clientProtocols, serverProtocols);
LOG.debug("Could not negotiate protocol from client{} and server{} on {}", clientProtocols, serverProtocols, getEndPoint());
throw new IllegalStateException();
}
}
if (LOG.isDebugEnabled())
LOG.debug("{} protocol selected {} among client{} and server{}", this, negotiated, clientProtocols, serverProtocols);
LOG.debug("Protocol selected {} from client{} and server{} on {}", negotiated, clientProtocols, serverProtocols, getEndPoint());
setProtocol(negotiated);
ALPN.remove(sslEngine);
return negotiated;
}
@Override
public void close()
{
ALPN.remove(getSSLEngine());
super.close();
}
}

View File

@ -18,7 +18,8 @@
package org.eclipse.jetty.alpn.server;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ServiceLoader;
@ -26,52 +27,68 @@ import javax.net.ssl.SSLEngine;
import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.ssl.ALPNProcessor;
import org.eclipse.jetty.io.ssl.SslHandshakeListener;
import org.eclipse.jetty.io.ssl.ALPNProcessor.Server;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.NegotiatingServerConnectionFactory;
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 implements SslHandshakeListener
public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFactory
{
private final ALPNProcessor.Server alpnProcessor;
private static final Logger LOG = Log.getLogger(ALPNServerConnectionFactory.class);
public ALPNServerConnectionFactory(String protocols)
private final List<Server> processors = new ArrayList<>();
public ALPNServerConnectionFactory(@Name("protocols") String protocols)
{
this(protocols.trim().split(",", 0));
}
public ALPNServerConnectionFactory(@Name("protocols") String... protocols)
{
super("alpn", protocols);
checkProtocolNegotiationAvailable();
Iterator<ALPNProcessor.Server> processors = ServiceLoader.load(ALPNProcessor.Server.class).iterator();
alpnProcessor = processors.hasNext() ? processors.next() : ALPNProcessor.Server.NOOP;
}
public ALPNProcessor.Server getALPNProcessor()
{
return alpnProcessor;
IllegalStateException failure = new IllegalStateException("No Server ALPNProcessors!");
for (Server processor : ServiceLoader.load(Server.class))
{
try
{
processor.init();
processors.add(processor);
}
catch (Throwable x)
{
if (LOG.isDebugEnabled())
LOG.debug("Could not initialize " + processor, x);
failure.addSuppressed(x);
}
}
if (LOG.isDebugEnabled())
{
LOG.debug("protocols: {}", Arrays.asList(protocols));
LOG.debug("processors: {}", processors);
}
if (processors.isEmpty())
throw failure;
}
@Override
protected AbstractConnection newServerConnection(Connector connector, EndPoint endPoint, SSLEngine engine, List<String> protocols, String defaultProtocol)
{
getALPNProcessor().configure(engine);
return new ALPNServerConnection(connector, endPoint, engine, protocols, defaultProtocol);
}
@Override
public void handshakeSucceeded(Event event)
{
if (alpnProcessor instanceof SslHandshakeListener)
((SslHandshakeListener)alpnProcessor).handshakeSucceeded(event);
}
@Override
public void handshakeFailed(Event event, Throwable failure)
{
if (alpnProcessor instanceof SslHandshakeListener)
((SslHandshakeListener)alpnProcessor).handshakeFailed(event, failure);
for (Server processor : processors)
{
if (processor.appliesTo(engine))
{
if (LOG.isDebugEnabled())
LOG.debug("{} for {} on {}", processor, engine, endPoint);
ALPNServerConnection connection = new ALPNServerConnection(connector, endPoint, engine, protocols, defaultProtocol);
processor.configure(engine, connection);
return connection;
}
}
throw new IllegalStateException("No ALPNProcessor for " + engine);
}
}

View File

@ -13,6 +13,10 @@
<modules>
<module>jetty-alpn-server</module>
<module>jetty-alpn-client</module>
<module>jetty-alpn-openjdk8-server</module>
<module>jetty-alpn-openjdk8-client</module>
<module>jetty-alpn-conscrypt-server</module>
<module>jetty-alpn-conscrypt-client</module>
</modules>
<profiles>
<profile>

View File

@ -17,7 +17,7 @@
[[sessions-usecases]]
=== Use Cases
===== Clustering with a Sticky Load Balancer
==== Clustering with a Sticky Load Balancer
Preferably, your cluster will utilize a sticky load balancer.
This will route requests for the same Session to the same Jetty instance.
@ -36,7 +36,7 @@ With this policy, Session objects will remain in the cache until they either exp
If you have a high likelihood of simultaneous requests for the same session object, then the `EVICT_ON_SESSION_EXIT` policy will ensure the Session object stays in the cache as long as it is needed.
===== Clustering Without a Sticky Load Balancer
==== Clustering Without a Sticky Load Balancer
Without a sticky load balancer requests for the same session may arrive on any node in the cluster.
This means it is likely that the copy of the Session object in any `SessionCache` is likely to be out-of-date, as the Session was probably last accessed on a different node.
@ -52,7 +52,7 @@ Again, due to the lack of Session transactionality, the ordering outcome of writ
As the Session is cached while at least one request is accessing it, it is possible for multiple simultaneous requests to share the same Session object.
===== Handling corrupted or unloadable session data
==== Handling corrupted or unloadable session data
For various reasons it might not be possible for the `SessionDataStore` to re-read a stored session.
One scenario is that the session stores a serialized object in it's attributes, and after a redeployment there in an incompatible class change.

View File

@ -20,7 +20,7 @@
This document provides an overview of how to configure SSL and TLS for Jetty.
[[configuring-jetty-for-ssl]]
===== Configuring Jetty for SSL
==== Configuring Jetty for SSL
To configure Jetty for SSL, complete the tasks in the following sections:

View File

@ -499,6 +499,16 @@
<artifactId>jetty-alpn-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-openjdk8-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-conscrypt-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jaspi</artifactId>

View File

@ -7,21 +7,26 @@ Installs the Conscrypt JSSE provider
[depend]
ssl
[provides]
alpn-impl
[files]
maven://org.conscrypt/conscrypt-openjdk-uber/${conscrypt.version}|lib/conscrypt/conscrypt-uber-${conscrypt.version}.jar
#maven://org.conscrypt/conscrypt-openjdk/${conscrypt.version}/jar/linux-x86_64|lib/conscrypt/conscrypt-${conscrypt.version}-linux-x86_64.jar
basehome:modules/conscrypt/conscrypt.xml|etc/conscrypt.xml
[lib]
lib/conscrypt/**.jar
[xml]
etc/conscrypt.xml
[lib]
lib/conscrypt/**.jar
lib/jetty-alpn-conscrypt-server-${jetty.version}.jar
[license]
Conscrypt is distributed under the Apache Licence 2.0
https://github.com/google/conscrypt/blob/master/LICENSE
[ini]
conscrypt.version?=1.0.0.RC9
jetty.sslContext.provider?=AndroidOpenSSL
conscrypt.version?=1.0.0.RC10
jetty.sslContext.provider?=Conscrypt

View File

@ -76,6 +76,7 @@ mov=video/quicktime
movie=video/x-sgi-movie
mp2=audio/mpeg
mp3=audio/mpeg
mp4=video/mp4
mpe=video/mpeg
mpeg=video/mpeg
mpg=video/mpeg

View File

@ -45,7 +45,7 @@ public abstract class NegotiatingClientConnection extends AbstractConnection
this.context = context;
}
protected SSLEngine getSSLEngine()
public SSLEngine getSSLEngine()
{
return engine;
}

View File

@ -18,35 +18,54 @@
package org.eclipse.jetty.io.ssl;
import java.util.List;
import javax.net.ssl.SSLEngine;
import org.eclipse.jetty.io.Connection;
public interface ALPNProcessor
{
public interface Server
/**
* Initializes this ALPNProcessor
*
* @throws RuntimeException if this processor is unavailable (e.g. missing dependencies or wrong JVM)
*/
public default void init()
{
public static final ALPNProcessor.Server NOOP = new ALPNProcessor.Server()
{
};
public default void configure(SSLEngine sslEngine)
{
}
}
public interface Client
/**
* Tests if this processor can be applied to the given SSLEngine.
*
* @param sslEngine the SSLEngine to check
* @return true if the processor can be applied to the given SSLEngine
*/
public default boolean appliesTo(SSLEngine sslEngine)
{
public static final Client NOOP = new Client()
{
};
return false;
}
public default void configure(SSLEngine sslEngine, List<String> protocols)
{
}
/**
* Configures the given SSLEngine and the given Connection for ALPN.
*
* @param sslEngine the SSLEngine to configure
* @param connection the Connection to configure
* @throws RuntimeException if this processor cannot be configured
*/
public default void configure(SSLEngine sslEngine, Connection connection)
{
}
public default void process(SSLEngine sslEngine)
{
}
/**
* Server-side interface used by ServiceLoader.
*/
public interface Server extends ALPNProcessor
{
}
/**
* Client-side interface used by ServiceLoader.
*/
public interface Client extends ALPNProcessor
{
}
}

View File

@ -55,27 +55,27 @@ public abstract class NegotiatingServerConnection extends AbstractConnection
this.engine = engine;
}
protected List<String> getProtocols()
public List<String> getProtocols()
{
return protocols;
}
protected String getDefaultProtocol()
public String getDefaultProtocol()
{
return defaultProtocol;
}
protected Connector getConnector()
public Connector getConnector()
{
return connector;
}
protected SSLEngine getSSLEngine()
public SSLEngine getSSLEngine()
{
return engine;
}
protected String getProtocol()
public String getProtocol()
{
return protocol;
}

View File

@ -32,28 +32,6 @@ import org.eclipse.jetty.io.ssl.SslConnection;
public abstract class NegotiatingServerConnectionFactory extends AbstractConnectionFactory
{
public static void checkProtocolNegotiationAvailable()
{
try
{
String javaVersion = System.getProperty("java.version");
String alpnClassName = "org.eclipse.jetty.alpn.ALPN";
if (javaVersion.startsWith("1."))
{
Class<?> klass = ClassLoader.getSystemClassLoader().loadClass(alpnClassName);
if (klass.getClassLoader() != null)
throw new IllegalStateException(alpnClassName + " must be on JVM boot classpath");
}
else
{
NegotiatingServerConnectionFactory.class.getClassLoader().loadClass(alpnClassName);
}
}
catch (ClassNotFoundException x)
{
throw new IllegalStateException("No ALPN classes available");
}
}
private final List<String> negotiatedProtocols;
private String defaultProtocol;

View File

@ -109,7 +109,8 @@ public class ResourceHandler extends HandlerWrapper implements ResourceFactory,W
{
Context scontext = ContextHandler.getCurrentContext();
_context = (scontext == null?null:scontext.getContextHandler());
_mimeTypes = _context == null?new MimeTypes():_context.getMimeTypes();
if (_mimeTypes==null)
_mimeTypes = _context == null?new MimeTypes():_context.getMimeTypes();
_resourceService.setContentFactory(new ResourceContentFactory(this,_mimeTypes,_resourceService.getPrecompressedFormats()));
_resourceService.setWelcomeFactory(this);