Merge remote-tracking branch 'origin/jetty-9.4.x'

This commit is contained in:
Greg Wilkins 2017-09-23 00:22:57 +10:00
commit 1b7ebf5599
167 changed files with 5484 additions and 2453 deletions

View File

@ -1,5 +1,101 @@
jetty-10.0.0-SNAPSHOT
jetty-9.4.7.v20170914 - 14 September 2017
+ 215 Consider native ALPN/SSL provider
+ 487 JDK 9 build compatibility
+ 1116 Support empty HTTP header values
+ 1200 Use PathWatcher in DeploymentManager
+ 1357 RolloverFileOutputStream: No rollout performed at midnight
+ 1416 GzipHandler generated ETag suffix has problems with If-Match header
logic
+ 1468 Configure PKIX Revocation Checker for SslContextFactory
+ 1469 RolloverFileOutputStream: IllegalStateException Task already scheduled
+ 1498 Add JRTResource to support future Java 9 classloader behaviors
+ 1499 ClasspathPattern needs MODULE ruleset to support future Java 9
classloader behaviors
+ 1503 IPv6 address needs normalization (without brackets) in
ForwardedRequestCustomizer
+ 1507 RolloverFileOutputStream: Negative delay Timer.schedule exception
+ 1513 RolloverFileOutputStream: can't handle multiple instances
+ 1515 Improved RollOverFileOutputStream removeOldFiles() behavior
+ 1520 PropertyUserStore should extract packed config file
+ 1556 Remove a timing channel in Password matching
+ 1571 Support Hazelcast session management in 9.4
+ 1590 Improve RolloverFileOutputStream functionality with multiple TimeZones
+ 1591 JDBCSessionDataStore doesn't work with root context on Oracle DB
+ 1592 CompressedContentFormat.tagEquals() - incorrect comparison of entity
tag hashes
+ 1595 HTTP/2: Avoid sending unnecessary stream WINDOW_UPDATE frames
+ 1600 Update jndi.mod and plus.mod
+ 1603 WebSocketServerFactory NPE in toString()
+ 1604 WebSocketContainer stop needs improvement
+ 1605 ContainerProvider.getWebSocketContainer() behavior is not to spec
+ 1618 AsyncContext.dispatch() does not use raw/encoded URI
+ 1622 HeaderFilter doesn't work if the response has been committed
+ 1623 JettyRunMojo use dependencies from reactor (outputdirectory)
+ 1625 Support new IANA declared Websocket Close Status Codes
+ 1637 Thread per connection retained in HTTP/2
+ 1638 Add it test for Maven Plugin
+ 1642 Using RewriteHandler with AsyncContext.dispatch() and
HttpServletRequestWrapper not possible
+ 1643 ProxyServlet always uses default number of selector threads -
constructor should allow to overwrite the default.
+ 1645 NotSerializableException: DoSFilter when using Non-Clustered Session
Management: File System
+ 1655 Improve extensibility of ServerConnector
+ 1656 Improve configurability of ConnectionPools
+ 1661 AbstractProxyServlet onProxyResponseFailure Error
+ 1662 NPE with WebSocket Compress Extensions
+ 1664 IPAccessHandler CIDR IP range check is incorrect
+ 1671 Asymmetric usage of trailers in MetaData.Request
+ 1675 Session id should not be logged with INFO level in AbstractSessionCache
+ 1679 DeploymentManagerMBean not usable through JMX
+ 1682 Jetty-WarFragmentFolderPath directive has no effect in eclipse runtime
mode except for the first launch
+ 1685 Update ALPN support for Java 8u141
+ 1687 HTTP2: Correcting missing callback notification when channel not found
+ 1692 Annotation scanning should ignore `module-info.class` files
+ 1698 Missing WWW-Authenticate from SpnegoAuthenticator when other
Authorization header provided
+ 1702 Update ALPN support for Java 8u144
+ 1703 Improve HttpInput failure logging
+ 1706 Log Implementation ignored when executing under OSGi
+ 1709 SpnegoAuthenticator improperly handling case-insensitive Negotiate
header
+ 1713 Do not over allocate selectors for small thread pools
+ 1715 Standardise properties and ids in jetty XML files
+ 1717 DoSFilter getRateTracker IP/Port loadId minor improvement
+ 1718 QueuedThreadPool not exposed on JMX
+ 1719 HTTP/2: Improve handling of queued requests
+ 1721 Async I/O POST fails with big files
+ 1724 Add dependency on jetty-annotations for apache-jsp
+ 1732 Allow pause accepting new connections during high load
+ 1737 DefaultServlet wrong welcome dispatcher using non-root URL path
+ 1738 jetty-bom fails oss.sonatype.org validation
+ 1741 Java 9 javadoc failure in build
+ 1749 Dump HttpDestination exchange queue
+ 1750 PoolingHttpDestination creates ConnectionPool twice
+ 1759 HTTP/2: producer can block in onReset
+ 1766 JettyClientContainerProvider does not actually use common objects
correctly
+ 1789 PropertyUserStoreTest failures in Windows
+ 1790 HTTP/2: 100% CPU usage seen during close/shutdown of endpoint
+ 1792 Accept ISO-8859-1 characters in response reason
+ 1794 Config properties typos in session-store-cache.mod
+ 1795 Fix session id manager workerName
+ 1796 ReservedThreadExecutor defaulting to capacity=1 only
+ 1797 JEP 238 - Multi-Release JAR files break bytecode scanning
+ 1798 JMXify EatWhatYouKill
+ 1804 Make EndPoint creation and destroy a non-blocking task
+ 1805 ReservedThreadExecutor should start ReservedThreads lazily
+ 1809 NPE: StandardDescriptorProcessor.visitSecurityConstraint() with null/no
security manager
+ 1814 Move JavaVersion to jetty-util for future Java 9 support requirements
+ 1816 HttpClientTest.testClientCannotValidateServerCertificate() hangs with
JDK 9
+ 475546 ClosedChannelException when connection to HTTPS over HTTP proxy
with CONNECT
jetty-9.4.6.v20170531 - 31 May 2017
+ 523 TLS close behaviour breaking session resumption
+ 1108 Please improve logging in SslContextFactory when there are no approved
@ -28,26 +124,59 @@ jetty-9.4.6.v20170531 - 31 May 2017
+ 1569 Allow setting of maxBinaryMessageSize to 0 in WebSocketPolicy
+ 1579 NPE in Quoted Quality CSV
jetty-9.2.22.v20170606 - 06 June 2017
+ 920 no main manifest attribute, in jetty-runner-9.2.19.v20160908.jar
+ 1108 Please improve logging in SslContextFactory when there are no approved
cipher suites
jetty-9.3.21.v20170918 - 18 September 2017
+ 487 JDK 9 build compatibility
+ 1116 Support empty HTTP header values
+ 1357 RolloverFileOutputStream: No rollout performed at midnight
+ 1469 IllegalStateException in RolloverFileOutputStream
+ 1507 Negative delay Timer.schedule exception due to mismatched local and
_logTimeZone values
+ 1532 RolloverFileOutputStream can't handle multiple instances
+ 1523 Update ALPN support for Java 8u131
+ 1556 A timing channel in Password.java
+ 1590 RolloverFileOutputStream not functioning in Jetty 9.2.21+
+ 1469 RolloverFileOutputStream: IllegalStateException Task already scheduled
+ 1507 RolloverFileOutputStream: Negative delay Timer.schedule exception
+ 1513 RolloverFileOutputStream: can't handle multiple instances
+ 1515 Improved RollOverFileOutputStream removeOldFiles() behavior
+ 1556 Remove a timing channel in Password matching
+ 1590 Improve RolloverFileOutputStream functionality with multiple TimeZones
+ 1655 Improve extensibility of ServerConnector
+ 1661 AbstractProxyServlet onProxyResponseFailure Error
+ 1664 IPAccessHandler CIDR IP range check is incorrect
+ 1685 Update ALPN support for Java 8u141
+ 1687 HTTP2: Correcting missing callback notification when channel not found
+ 1702 Update ALPN support for Java 8u144
+ 1703 Improve HttpInput failure logging
+ 1719 HTTP/2: Improve handling of queued requests
+ 1741 Java 9 javadoc failure in build
+ 1749 Dump HttpDestination exchange queue
+ 1750 PoolingHttpDestination creates ConnectionPool twice
+ 1759 HTTP/2: producer can block in onReset
+ 1790 HTTP/2: 100% CPU usage seen during close/shutdown of endpoint
+ 475546 ClosedChannelException when connection to HTTPS over HTTP proxy
with CONNECT
jetty-9.3.20.v20170531 - 31 May 2017
jetty-9.4.6.v20170531 - 31 May 2017
+ 523 TLS close behaviour breaking session resumption
+ 1108 Please improve logging in SslContextFactory when there are no approved
cipher suites
+ 1505 Adding jetty.base.uri and jetty.home.uri
+ 1514 websocket dump badly formatted
+ 1516 Delay starting of WebSocketClient until an attempt to connect is made
+ 1520 PropertyUserStore should extract packed config file
+ 1526 MongoSessionDataStore old session scavenging is broken due to the
missing $ sign in "and" operation
+ 1527 Jetty BOM should not depend on jetty-parent
+ 1528 Internal HttpClient usages should have common configurable technique
+ 1536 Jetty BOM should include more artifacts
+ 1538 NPE in Response.putHeaders
+ 1539 JarFileResource mishandles paths with spaces
+ 1544 Disabling JSR-356 doesn't indicate context it was disabled for
+ 1546 Improve handling of quotes in cookies
+ 1553 X509.isCertSign() can throw ArrayIndexOutOfBoundsException on
non-standard implementations
+ 1556 A timing channel in Password.java
+ 1558 When creating WebAppContext without session-config and with NO_SESSIONS
throws NPE
+ 1567 XmlConfiguration will start the same object multiple times
+ 1568 ServletUpgradeRequest mangles query strings containing percent-escapes
by re-escaping them
+ 1569 Allow setting of maxBinaryMessageSize to 0 in WebSocketPolicy
+ 1579 NPE in Quoted Quality CSV
jetty-9.4.5.v20170502 - 02 May 2017
+ 304 Review dead code - StringUtil.sidBytesToString
@ -81,6 +210,27 @@ jetty-9.4.5.v20170502 - 02 May 2017
+ 1521 Prevent copy of jetty jars to lib/gcloud
+ 1523 Update ALPN support for Java 8u131
jetty-9.3.20.v20170531 - 31 May 2017
+ 523 TLS close behaviour breaking session resumption
+ 1108 Please improve logging in SslContextFactory when there are no approved
cipher suites
+ 1527 Jetty BOM should not depend on jetty-parent
+ 1556 A timing channel in Password.java
+ 1567 XmlConfiguration will start the same object multiple times
jetty-9.2.22.v20170606 - 06 June 2017
+ 920 no main manifest attribute, in jetty-runner-9.2.19.v20160908.jar
+ 1108 Please improve logging in SslContextFactory when there are no approved
cipher suites
+ 1357 RolloverFileOutputStream: No rollout performed at midnight
+ 1469 IllegalStateException in RolloverFileOutputStream
+ 1507 Negative delay Timer.schedule exception due to mismatched local and
_logTimeZone values
+ 1532 RolloverFileOutputStream can't handle multiple instances
+ 1523 Update ALPN support for Java 8u131
+ 1556 A timing channel in Password.java
+ 1590 RolloverFileOutputStream not functioning in Jetty 9.2.21+
jetty-9.3.19.v20170502 - 02 May 2017
+ 877 Programmatic servlet mappings cannot override mappings from
webdefault.xml using quickstart

View File

@ -18,11 +18,6 @@
package org.eclipse.jetty.jstl;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@ -37,15 +32,22 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.JAR;
import org.eclipse.jetty.toolchain.test.JDK;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.AfterClass;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
public class JstlTest
{
private static Server server;
@ -54,6 +56,8 @@ public class JstlTest
@BeforeClass
public static void startServer() throws Exception
{
Assume.assumeFalse(JDK.IS_9);
// Setup Server
server = new Server();
ServerConnector connector = new ServerConnector(server);
@ -98,7 +102,8 @@ public class JstlTest
@AfterClass
public static void stopServer() throws Exception
{
server.stop();
if (server != null)
server.stop();
}
@Test

View File

@ -15,13 +15,6 @@
<bundle-symbolic-name>${project.groupId}.embedded</bundle-symbolic-name>
</properties>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util-ajax</artifactId>
@ -82,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>
@ -138,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);
@ -122,7 +130,6 @@ public class Http2Server
ALPN.debug=false;
server.start();
//server.dumpStdErr();
server.join();
}

View File

@ -20,12 +20,8 @@ package org.eclipse.jetty.embedded;
import java.io.File;
import java.io.FileNotFoundException;
import java.lang.reflect.Method;
import java.security.Provider;
import java.security.Security;
import java.util.function.BiFunction;
import javax.net.ssl.SSLEngine;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.server.Connector;
@ -43,7 +39,7 @@ import org.eclipse.jetty.util.ssl.SslContextFactory;
public class ManyConnectors
{
public static void main( String[] args ) throws Exception
{
{
// Since this example shows off SSL configuration, we need a keystore
// with the appropriate key. These lookup of jetty.home is purely a hack
// to get access to a keystore that we use in many unit tests and should
@ -97,7 +93,6 @@ public class ManyConnectors
sslContextFactory.setKeyStorePath(keystoreFile.getAbsolutePath());
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
sslContextFactory.setProvider("Conscrypt");
// HTTPS Configuration
// A new HttpConfiguration object is needed for the next connector and
@ -137,18 +132,6 @@ public class ManyConnectors
// Start the server
server.start();
SSLEngine engine = sslContextFactory.newSSLEngine();
System.err.println(engine);
System.err.println(engine.getClass());
for (Method m : engine.getClass().getMethods())
{
System.err.println(m);
}
server.join();
}
}

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,6 +19,7 @@
package org.eclipse.jetty.alpn.client;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@ -31,17 +32,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 +53,64 @@ 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!");
// Use a for loop on iterator so load exceptions can be caught and ignored
for (Iterator<Client> i = ServiceLoader.load(Client.class).iterator(); i.hasNext();)
{
Client processor;
try
{
processor = i.next();
}
catch(Throwable x)
{
if (LOG.isDebugEnabled())
LOG.debug(x);
failure.addSuppressed(x);
continue;
}
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>10.0.0-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>10.0.0-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>10.0.0-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>10.0.0-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" default="" />
</Arg>
<Set name="defaultProtocol">
<Property name="jetty.alpn.defaultProtocol" />
</Set>
<Arg name="protocols" type="String"><Property name="jetty.alpn.protocols" default="" /></Arg>
<Set name="defaultProtocol"><Property name="jetty.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,6 +18,8 @@
package org.eclipse.jetty.alpn.server;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
@ -26,52 +28,82 @@ 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!");
// Use a for loop on iterator so load exceptions can be caught and ignored
for (Iterator<Server> i = ServiceLoader.load(Server.class).iterator(); i.hasNext();)
{
Server processor;
try
{
processor = i.next();
}
catch(Throwable x)
{
if (LOG.isDebugEnabled())
LOG.debug(x);
failure.addSuppressed(x);
continue;
}
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

@ -24,16 +24,23 @@ import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.MultiReleaseJarFile;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
@ -45,7 +52,6 @@ import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* AnnotationParser
* <p>
@ -68,10 +74,29 @@ public class AnnotationParser
{
private static final Logger LOG = Log.getLogger(AnnotationParser.class);
protected Set<String> _parsedClassNames = ConcurrentHashMap.newKeySet();
private static final int JVM_MAJOR_VER;
protected static int ASM_OPCODE_VERSION = Opcodes.ASM5; //compatibility of api
protected Map<String, List<String>> _parsedClassNames = new ConcurrentHashMap<>();
static
{
// Determine JVM spec version
// Using guidance from http://openjdk.java.net/jeps/223
String jvmSpecVer = System.getProperty("java.vm.specification.version");
if (jvmSpecVer.indexOf('.') >= 0)
{
// Old spec version (Java 1.8 and older)
String parts[] = jvmSpecVer.split("\\.");
JVM_MAJOR_VER = Integer.parseInt(parts[1]);
}
else
{
// Newer spec version (Java 9+)
JVM_MAJOR_VER = Integer.parseInt(jvmSpecVer);
}
}
/**
* Convert internal name to simple name
@ -110,12 +135,8 @@ public class AnnotationParser
return normalList;
}
/**
* ClassInfo
*
* Immutable information gathered by parsing class header.
*
*/
public class ClassInfo
{
@ -175,10 +196,7 @@ public class AnnotationParser
}
}
/**
* MethodInfo
*
* Immutable information gathered by parsing a method on a class.
*/
public class MethodInfo
@ -231,14 +249,9 @@ public class AnnotationParser
return _exceptions;
}
}
/**
* FieldInfo
*
* Immutable information gathered by parsing a field on a class.
*
*/
public class FieldInfo
{
@ -292,8 +305,6 @@ public class AnnotationParser
}
/**
* Handler
*
* Signature for all handlers that respond to parsing class files.
*/
public static interface Handler
@ -307,13 +318,10 @@ public class AnnotationParser
}
/**
* AbstractHandler
*
* Convenience base class to provide no-ops for all Handler methods.
*/
public static abstract class AbstractHandler implements Handler
{
@Override
public void handle(ClassInfo classInfo)
{
@ -347,15 +355,11 @@ public class AnnotationParser
@Override
public void handle(FieldInfo info, String annotationName)
{
// no-op
}
// no-op
}
}
/**
* MyMethodVisitor
*
* ASM Visitor for parsing a method. We are only interested in the annotations on methods.
*/
public class MyMethodVisitor extends MethodVisitor
@ -376,11 +380,8 @@ public class AnnotationParser
_mi = new MethodInfo(classInfo, name, access, methodDesc,signature, exceptions);
}
/**
* We are only interested in finding the annotations on methods.
*
* @see org.objectweb.asm.MethodVisitor#visitAnnotation(java.lang.String, boolean)
*/
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible)
@ -392,21 +393,15 @@ public class AnnotationParser
}
}
/**
* MyFieldVisitor
*
* An ASM visitor for parsing Fields.
* An ASM visitor for parsing Fields.
* We are only interested in visiting annotations on Fields.
*
*/
public class MyFieldVisitor extends FieldVisitor
{
final FieldInfo _fieldInfo;
final Set<? extends Handler> _handlers;
public MyFieldVisitor(final Set<? extends Handler> handlers,
final ClassInfo classInfo,
final int access,
@ -420,11 +415,8 @@ public class AnnotationParser
_fieldInfo = new FieldInfo(classInfo, fieldName, access, fieldType, signature, value);
}
/**
* Parse an annotation found on a Field.
*
* @see org.objectweb.asm.FieldVisitor#visitAnnotation(java.lang.String, boolean)
*/
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible)
@ -437,17 +429,11 @@ public class AnnotationParser
}
}
/**
* MyClassVisitor
*
* ASM visitor for a class.
*/
public class MyClassVisitor extends ClassVisitor
{
final Resource _containingResource;
final Set<? extends Handler> _handlers;
ClassInfo _ci;
@ -459,7 +445,6 @@ public class AnnotationParser
_containingResource = containingResource;
}
@Override
public void visit (final int version,
final int access,
@ -469,18 +454,12 @@ public class AnnotationParser
final String[] interfaces)
{
_ci = new ClassInfo(_containingResource, normalize(name), version, access, signature, normalize(superName), normalize(interfaces));
_parsedClassNames.add(_ci.getClassName());
for (Handler h:_handlers)
h.handle(_ci);
}
/**
* Visit an annotation on a Class
*
* @see org.objectweb.asm.ClassVisitor#visitAnnotation(java.lang.String, boolean)
*/
@Override
public AnnotationVisitor visitAnnotation (String desc, boolean visible)
@ -488,15 +467,11 @@ public class AnnotationParser
String annotationName = normalize(desc);
for (Handler h : _handlers)
h.handle(_ci, annotationName);
return null;
}
/**
* Visit a method to extract its annotations
*
* @see org.objectweb.asm.ClassVisitor#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
*/
@Override
public MethodVisitor visitMethod (final int access,
@ -505,14 +480,11 @@ public class AnnotationParser
final String signature,
final String[] exceptions)
{
return new MyMethodVisitor(_handlers, _ci, access, name, methodDesc, signature, exceptions);
}
/**
* Visit a field to extract its annotations
*
* @see org.objectweb.asm.ClassVisitor#visitField(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object)
*/
@Override
public FieldVisitor visitField (final int access,
@ -525,20 +497,41 @@ public class AnnotationParser
}
}
/**
* True if the class has already been processed, false otherwise
* @param className the classname
* @return true if class was parsed, false if not
* Add a class as having been parsed.
*
* @param classname the name of the class
* @param location the fully qualified location of the class
*/
public boolean isParsed (String className)
public void addParsedClass (String classname, Resource location)
{
return _parsedClassNames.contains(className);
List<String> list = new ArrayList<>(1);
if (location != null)
list.add(location.toString());
List<String> existing = _parsedClassNames.putIfAbsent(classname, list);
if (existing != null)
{
existing.addAll(list);
LOG.warn("{} scanned from multiple locations: {}", classname, existing);
}
}
/**
* Get the locations of the given classname. There may be more than one
* location if there are duplicates of the same class.
*
* @param classname the name of the class
* @return an immutable list of locations
*/
public List<String> getParsedLocations (String classname)
{
List<String> list = _parsedClassNames.get(classname);
if (list == null)
return Collections.emptyList();
return Collections.unmodifiableList(list);
}
/**
* Parse a given class
*
@ -546,29 +539,25 @@ public class AnnotationParser
* @param className the class name to parse
* @throws Exception if unable to parse
*/
public void parse (Set<? extends Handler> handlers, String className)
throws Exception
public void parse (Set<? extends Handler> handlers, String className) throws Exception
{
if (className == null)
return;
if (!isParsed(className))
String tmp = className;
className = className.replace('.', '/')+".class";
URL resource = Loader.getResource(className);
if (resource!= null)
{
className = className.replace('.', '/')+".class";
URL resource = Loader.getResource(className);
if (resource!= null)
Resource r = Resource.newResource(resource);
addParsedClass(tmp, r);
try (InputStream is = r.getInputStream())
{
Resource r = Resource.newResource(resource);
try (InputStream is = r.getInputStream())
{
scanClass(handlers, null, is);
}
scanClass(handlers, null, is);
}
}
}
/**
* Parse the given class, optionally walking its inheritance hierarchy
*
@ -577,27 +566,23 @@ public class AnnotationParser
* @param visitSuperClasses if true, also visit super classes for parse
* @throws Exception if unable to parse class
*/
public void parse (Set<? extends Handler> handlers, Class<?> clazz, boolean visitSuperClasses)
throws Exception
public void parse (Set<? extends Handler> handlers, Class<?> clazz, boolean visitSuperClasses) throws Exception
{
Class<?> cz = clazz;
while (cz != Object.class)
{
if (!isParsed(cz.getName()))
String nameAsResource = cz.getName().replace('.', '/')+".class";
URL resource = Loader.getResource(nameAsResource);
if (resource!= null)
{
String nameAsResource = cz.getName().replace('.', '/')+".class";
URL resource = Loader.getResource(nameAsResource);
if (resource!= null)
Resource r = Resource.newResource(resource);
addParsedClass(clazz.getName(), r);
try (InputStream is = r.getInputStream())
{
Resource r = Resource.newResource(resource);
try (InputStream is = r.getInputStream())
{
scanClass(handlers, null, is);
}
scanClass(handlers, null, is);
}
}
if (visitSuperClasses)
cz = cz.getSuperclass();
else
@ -605,8 +590,6 @@ public class AnnotationParser
}
}
/**
* Parse the given classes
*
@ -614,8 +597,7 @@ public class AnnotationParser
* @param classNames the class name
* @throws Exception if unable to parse
*/
public void parse (Set<? extends Handler> handlers, String[] classNames)
throws Exception
public void parse (Set<? extends Handler> handlers, String[] classNames) throws Exception
{
if (classNames == null)
return;
@ -623,7 +605,6 @@ public class AnnotationParser
parse(handlers, Arrays.asList(classNames));
}
/**
* Parse the given classes
*
@ -631,26 +612,24 @@ public class AnnotationParser
* @param classNames the class names
* @throws Exception if unable to parse
*/
public void parse (Set<? extends Handler> handlers, List<String> classNames)
throws Exception
public void parse (Set<? extends Handler> handlers, List<String> classNames) throws Exception
{
MultiException me = new MultiException();
for (String s:classNames)
{
try
{
if (!isParsed(s))
String name = s;
s = s.replace('.', '/')+".class";
URL resource = Loader.getResource(s);
if (resource!= null)
{
s = s.replace('.', '/')+".class";
URL resource = Loader.getResource(s);
if (resource!= null)
Resource r = Resource.newResource(resource);
addParsedClass(name, r);
try (InputStream is = r.getInputStream())
{
Resource r = Resource.newResource(resource);
try (InputStream is = r.getInputStream())
{
scanClass(handlers, null, is);
}
scanClass(handlers, null, is);
}
}
}
@ -662,67 +641,65 @@ public class AnnotationParser
me.ifExceptionThrow();
}
/**
* Parse all classes in a directory
*
* @param handlers the set of handlers to look for classes in
* @param dir the resource directory to look for classes
* @param root the resource directory to look for classes
* @throws Exception if unable to parse
*/
protected void parseDir (Set<? extends Handler> handlers, Resource dir)
throws Exception
protected void parseDir (Set<? extends Handler> handlers, Resource root) throws Exception
{
// skip dirs whose name start with . (ie hidden)
if (!dir.isDirectory() || !dir.exists() || dir.getName().startsWith("."))
if (!root.isDirectory() || !root.exists() || root.getName().startsWith("."))
return;
if (LOG.isDebugEnabled()) {LOG.debug("Scanning dir {}", dir);};
MultiException me = new MultiException();
if (LOG.isDebugEnabled())
LOG.debug("Scanning dir {}", root);
String[] files=dir.list();
for (int f=0;files!=null && f<files.length;f++)
File rootFile = root.getFile();
MultiException me = new MultiException();
Collection<Resource> resources = root.getAllResources();
if (resources != null)
{
Resource res = dir.addPath(files[f]);
if (res.isDirectory())
parseDir(handlers, res);
else
for (Resource r:resources)
{
//we've already verified the directories, so just verify the class file name
File file = res.getFile();
if (r.isDirectory())
continue;
File file = r.getFile();
if (isValidClassFileName((file==null?null:file.getName())))
{
Path classpath = rootFile.toPath().relativize(file.toPath());
String str = classpath.toString();
str = str.substring(0, str.lastIndexOf(".class")).replace('/', '.').replace('\\', '.');
try
{
String name = res.getName();
if (!isParsed(name))
if (LOG.isDebugEnabled())
LOG.debug("Scanning class {}", r);
addParsedClass(str, r);
try (InputStream is=r.getInputStream())
{
Resource r = Resource.newResource(res.getURL());
if (LOG.isDebugEnabled()) {LOG.debug("Scanning class {}", r);};
try (InputStream is=r.getInputStream())
{
scanClass(handlers, dir, is);
}
scanClass(handlers, Resource.newResource(file.getParentFile()), is);
}
}
catch (Exception ex)
{
if (LOG.isDebugEnabled()) LOG.debug("Error scanning file "+files[f], ex);
me.add(new RuntimeException("Error scanning file "+files[f],ex));
if (LOG.isDebugEnabled()) LOG.debug("Error scanning file "+file, ex);
me.add(new RuntimeException("Error scanning file "+file,ex));
}
}
else
{
if (LOG.isDebugEnabled()) LOG.debug("Skipping scan on invalid file {}", res);
if (LOG.isDebugEnabled()) LOG.debug("Skipping scan on invalid file {}", file);
}
}
}
me.ifExceptionThrow();
}
/**
* Parse classes in the supplied classloader.
* Only class files in jar files will be scanned.
@ -733,39 +710,12 @@ public class AnnotationParser
* @param nullInclusive if true, an empty pattern means all names match, if false, none match
* @throws Exception if unable to parse
*/
public void parse (final Set<? extends Handler> handlers, ClassLoader loader, boolean visitParents, boolean nullInclusive)
throws Exception
@Deprecated
public void parse (final Set<? extends Handler> handlers, ClassLoader loader, boolean visitParents, boolean nullInclusive) throws Exception
{
if (loader==null)
return;
if (!(loader instanceof URLClassLoader))
return; //can't extract classes?
final MultiException me = new MultiException();
JarScanner scanner = new JarScanner()
{
@Override
public void processEntry(URI jarUri, JarEntry entry)
{
try
{
parseJarEntry(handlers, Resource.newResource(jarUri), entry);
}
catch (Exception e)
{
me.add(new RuntimeException("Error parsing entry "+entry.getName()+" from jar "+ jarUri, e));
}
}
};
scanner.scan(null, loader, nullInclusive, visitParents);
me.ifExceptionThrow();
throw new UnsupportedOperationException();
}
/**
* Parse classes in the supplied uris.
*
@ -773,8 +723,7 @@ public class AnnotationParser
* @param uris the uris for the jars
* @throws Exception if unable to parse
*/
public void parse (final Set<? extends Handler> handlers, final URI[] uris)
throws Exception
public void parse (final Set<? extends Handler> handlers, final URI[] uris) throws Exception
{
if (uris==null)
return;
@ -802,8 +751,7 @@ public class AnnotationParser
* @param uri the uri for the jar
* @throws Exception if unable to parse
*/
public void parse (final Set<? extends Handler> handlers, URI uri)
throws Exception
public void parse (final Set<? extends Handler> handlers, URI uri) throws Exception
{
if (uri == null)
return;
@ -811,7 +759,6 @@ public class AnnotationParser
parse (handlers, Resource.newResource(uri));
}
/**
* Parse a resource
*
@ -819,8 +766,7 @@ public class AnnotationParser
* @param r the resource to parse
* @throws Exception if unable to parse
*/
public void parse (final Set<? extends Handler> handlers, Resource r)
throws Exception
public void parse (final Set<? extends Handler> handlers, Resource r) throws Exception
{
if (r == null)
return;
@ -850,9 +796,6 @@ public class AnnotationParser
if (LOG.isDebugEnabled()) LOG.warn("Resource not scannable for classes: {}", r);
}
/**
* Parse a resource that is a jar file.
*
@ -860,47 +803,31 @@ public class AnnotationParser
* @param jarResource the jar resource to parse
* @throws Exception if unable to parse
*/
protected void parseJar (Set<? extends Handler> handlers, Resource jarResource)
throws Exception
protected void parseJar (Set<? extends Handler> handlers, Resource jarResource) throws Exception
{
if (jarResource == null)
return;
if (jarResource.toString().endsWith(".jar"))
{
if (LOG.isDebugEnabled()) {LOG.debug("Scanning jar {}", jarResource);};
//treat it as a jar that we need to open and scan all entries from
InputStream in = jarResource.getInputStream();
if (in==null)
return;
if (LOG.isDebugEnabled())
LOG.debug("Scanning jar {}", jarResource);
MultiException me = new MultiException();
JarInputStream jar_in = new JarInputStream(in);
try
{
JarEntry entry = jar_in.getNextJarEntry();
while (entry!=null)
{
try
{
parseJarEntry(handlers, jarResource, entry);
}
catch (Exception e)
{
me.add(new RuntimeException("Error scanning entry "+entry.getName()+" from jar "+jarResource, e));
}
entry = jar_in.getNextJarEntry();
// TODO do not force version 8 once ASM can scan 9
MultiReleaseJarFile jarFile = new MultiReleaseJarFile(jarResource.getFile(),8,false);
jarFile.stream().forEach(e->
{
try
{
parseJarEntry(handlers, jarResource, e);
}
}
catch (Exception e)
{
me.add(new RuntimeException("Error scanning jar "+jarResource, e));
}
finally
{
jar_in.close();
}
catch (Exception ex)
{
me.add(new RuntimeException("Error scanning entry " + e.getName() + " from jar " + jarResource, ex));
}
});
me.ifExceptionThrow();
}
@ -910,12 +837,10 @@ public class AnnotationParser
* Parse a single entry in a jar file
*
* @param handlers the handlers to look for classes in
* @param jar the jar resource to parse
* @param entry the entry in the jar resource to parse
* @param entry the entry in the potentially MultiRelease jar resource to parse
* @throws Exception if unable to parse
*/
protected void parseJarEntry (Set<? extends Handler> handlers, Resource jar, JarEntry entry)
throws Exception
protected void parseJarEntry (Set<? extends Handler> handlers, Resource jar, MultiReleaseJarFile.VersionedJarEntry entry) throws Exception
{
if (jar == null || entry == null)
return;
@ -930,20 +855,15 @@ public class AnnotationParser
if (isValidClassFileName(name) && isValidClassFilePath(name))
{
String shortName = name.replace('/', '.').substring(0,name.length()-6);
if (!isParsed(shortName))
addParsedClass(shortName, Resource.newResource("jar:"+jar.getURI()+"!/"+entry.getNameInJar()));
if (LOG.isDebugEnabled())
LOG.debug("Scanning class from jar {}!/{}", jar, entry);
try (InputStream is = entry.getInputStream())
{
Resource clazz = Resource.newResource("jar:"+jar.getURI()+"!/"+name);
if (LOG.isDebugEnabled()) {LOG.debug("Scanning class from jar {}", clazz);};
try (InputStream is = clazz.getInputStream())
{
scanClass(handlers, jar, is);
}
scanClass(handlers, jar, is);
}
}
}
/**
* Use ASM on a class
@ -953,13 +873,20 @@ public class AnnotationParser
* @param is the input stream to parse
* @throws IOException if unable to parse
*/
protected void scanClass (Set<? extends Handler> handlers, Resource containingResource, InputStream is)
throws IOException
protected void scanClass (Set<? extends Handler> handlers, Resource containingResource, InputStream is) throws IOException
{
ClassReader reader = new ClassReader(is);
reader.accept(new MyClassVisitor(handlers, containingResource), ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES);
}
/**
* Remove any parsed class names.
*/
public void resetParsedClasses ()
{
_parsedClassNames.clear();
}
/**
* Check that the given path represents a valid class file name.
* The check is fairly cursory, checking that:
@ -968,8 +895,8 @@ public class AnnotationParser
* <li> it isn't a dot file or in a hidden directory </li>
* <li> the name of the class at least begins with a valid identifier for a class name </li>
* </ul>
* @param name
* @return
* @param name the class file name
* @return whether the class file name is valid
*/
private boolean isValidClassFileName (String name)
{
@ -1003,13 +930,12 @@ public class AnnotationParser
return true;
}
/**
* Check that the given path does not contain hidden directories
*
* @param path
* @return
* @param path the class file path
* @return whether the class file path is valid
*/
private boolean isValidClassFilePath (String path)
{
@ -1017,14 +943,13 @@ public class AnnotationParser
if (path == null || path.length()==0)
return false;
//skip any classfiles that are in a hidden directory
// skip any classfiles that are in a hidden directory
if (path.startsWith(".") || path.contains("/."))
{
if (LOG.isDebugEnabled()) LOG.debug("Contains hidden dirs: {}"+path);
if (LOG.isDebugEnabled()) LOG.debug("Contains hidden dirs: " + path);
return false;
}
return true;
}
}

View File

@ -18,11 +18,15 @@
package org.eclipse.jetty.annotations;
import javax.annotation.security.DeclareRoles;
import javax.servlet.Servlet;
import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler;
import org.eclipse.jetty.security.ConstraintAware;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.webapp.WebAppContext;
/**
@ -30,6 +34,7 @@ import org.eclipse.jetty.webapp.WebAppContext;
*/
public class DeclareRolesAnnotationHandler extends AbstractIntrospectableAnnotationHandler
{
private static final Logger LOG = Log.getLogger(DeclareRolesAnnotationHandler.class);
protected WebAppContext _context;
@ -48,6 +53,12 @@ public class DeclareRolesAnnotationHandler extends AbstractIntrospectableAnnotat
if (!Servlet.class.isAssignableFrom(clazz))
return; //only applicable on javax.servlet.Servlet derivatives
if (!(_context.getSecurityHandler() instanceof ConstraintAware))
{
LOG.warn("SecurityHandler not ConstraintAware, skipping security annotation processing");
return;
}
DeclareRoles declareRoles = (DeclareRoles) clazz.getAnnotation(DeclareRoles.class);
if (declareRoles == null)
return;

View File

@ -0,0 +1,35 @@
package org.acme;
//
// ========================================================================
// 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.
// ========================================================================
//
/**
* ClassOne
*
*
*/
public class ClassOne
{
public void one()
{
}
}

View File

@ -29,6 +29,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
@ -44,6 +45,7 @@ import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.IO;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.TestingDir;
import org.eclipse.jetty.util.resource.Resource;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
@ -163,6 +165,26 @@ public class TestAnnotationParser
// only the valid classes inside bad-classes.jar should be parsed. If any invalid classes are parsed and exception would be thrown here
}
@Test
public void testModuleInfoClassInJar() throws Exception
{
File badClassesJar = MavenTestingUtils.getTestResourceFile("jdk9/slf4j-api-1.8.0-alpha2.jar");
AnnotationParser parser = new AnnotationParser();
Set<Handler> emptySet = Collections.emptySet();
parser.parse(emptySet, badClassesJar.toURI());
// Should throw no exceptions, and happily skip the module-info.class files
}
@Test
public void testJep238MultiReleaseInJar() throws Exception
{
File badClassesJar = MavenTestingUtils.getTestResourceFile("jdk9/log4j-api-2.9.0.jar");
AnnotationParser parser = new AnnotationParser();
Set<Handler> emptySet = Collections.emptySet();
parser.parse(emptySet, badClassesJar.toURI());
// Should throw no exceptions, and skip the META-INF/versions/9/* files
}
@Test
public void testBasedirExclusion() throws Exception
{
@ -189,6 +211,40 @@ public class TestAnnotationParser
// Validate
Assert.assertThat("Found Class", tracker.foundClasses, contains(ClassA.class.getName()));
}
@Test
public void testScanDuplicateClassesInJars() throws Exception
{
Resource testJar = Resource.newResource(MavenTestingUtils.getTestResourceFile("tinytest.jar"));
Resource testJar2 = Resource.newResource(MavenTestingUtils.getTestResourceFile("tinytest_copy.jar"));
AnnotationParser parser = new AnnotationParser();
Set<Handler> emptySet = Collections.emptySet();
parser.parse(emptySet, testJar);
parser.parse(emptySet, testJar2);
List<String> locations = parser.getParsedLocations("org.acme.ClassOne");
Assert.assertNotNull(locations);
Assert.assertEquals(2, locations.size());
Assert.assertTrue(!(locations.get(0).equals(locations.get(1))));
}
@Test
public void testScanDuplicateClasses() throws Exception
{
Resource testJar = Resource.newResource(MavenTestingUtils.getTestResourceFile("tinytest.jar"));
File testClasses = new File(MavenTestingUtils.getTargetDir(), "test-classes");
AnnotationParser parser = new AnnotationParser();
Set<Handler> emptySet = Collections.emptySet();
parser.parse(emptySet, testJar);
parser.parse(emptySet, Resource.newResource(testClasses));
List<String> locations = parser.getParsedLocations("org.acme.ClassOne");
Assert.assertNotNull(locations);
Assert.assertEquals(2, locations.size());
Assert.assertTrue(!(locations.get(0).equals(locations.get(1))));
}
private void copyClass(Class<?> clazz, File basedir) throws IOException
{

Binary file not shown.

Binary file not shown.

View File

@ -169,12 +169,12 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>jetty-fcgi-client</artifactId>
<artifactId>fcgi-client</artifactId>
<version>10.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>jetty-fcgi-server</artifactId>
<artifactId>fcgi-server</artifactId>
<version>10.0.0-SNAPSHOT</version>
</dependency>
<dependency>
@ -262,11 +262,6 @@
<artifactId>jetty-memcached-sessions</artifactId>
<version>10.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-monitor</artifactId>
<version>10.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-nosql</artifactId>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>org.eclipse.jetty.cdi</groupId>
<artifactId>jetty-cdi-parent</artifactId>
<version>9.4.7-SNAPSHOT</version>
<version>10.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cdi-webapp-it</artifactId>

View File

@ -73,6 +73,7 @@ import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
import org.eclipse.jetty.util.thread.Scheduler;
import org.eclipse.jetty.util.thread.ThreadPool;
/**
* <p>{@link HttpClient} provides an efficient, asynchronous, non-blocking implementation
@ -118,33 +119,33 @@ public class HttpClient extends ContainerLifeCycle
private final ConcurrentMap<Origin, HttpDestination> destinations = new ConcurrentHashMap<>();
private final ProtocolHandlers handlers = new ProtocolHandlers();
private final List<Request.Listener> requestListeners = new ArrayList<>();
private final AuthenticationStore authenticationStore = new HttpAuthenticationStore();
private final Set<ContentDecoder.Factory> decoderFactories = new ContentDecoderFactorySet();
private final ProxyConfiguration proxyConfig = new ProxyConfiguration();
private final HttpClientTransport transport;
private final SslContextFactory sslContextFactory;
private volatile CookieManager cookieManager;
private volatile CookieStore cookieStore;
private volatile Executor executor;
private volatile ByteBufferPool byteBufferPool;
private volatile Scheduler scheduler;
private volatile SocketAddressResolver resolver;
private volatile HttpField agentField = new HttpField(HttpHeader.USER_AGENT, "Jetty/" + Jetty.VERSION);
private volatile boolean followRedirects = true;
private volatile int maxConnectionsPerDestination = 64;
private volatile int maxRequestsQueuedPerDestination = 1024;
private volatile int requestBufferSize = 4096;
private volatile int responseBufferSize = 16384;
private volatile int maxRedirects = 8;
private volatile SocketAddress bindAddress;
private volatile long connectTimeout = 15000;
private volatile long addressResolutionTimeout = 15000;
private volatile long idleTimeout;
private volatile boolean tcpNoDelay = true;
private volatile boolean strictEventOrdering = false;
private volatile HttpField encodingField;
private volatile boolean removeIdleDestinations = false;
private volatile boolean connectBlocking = false;
private AuthenticationStore authenticationStore = new HttpAuthenticationStore();
private CookieManager cookieManager;
private CookieStore cookieStore;
private Executor executor;
private ByteBufferPool byteBufferPool;
private Scheduler scheduler;
private SocketAddressResolver resolver;
private HttpField agentField = new HttpField(HttpHeader.USER_AGENT, "Jetty/" + Jetty.VERSION);
private boolean followRedirects = true;
private int maxConnectionsPerDestination = 64;
private int maxRequestsQueuedPerDestination = 1024;
private int requestBufferSize = 4096;
private int responseBufferSize = 16384;
private int maxRedirects = 8;
private SocketAddress bindAddress;
private long connectTimeout = 15000;
private long addressResolutionTimeout = 15000;
private long idleTimeout;
private boolean tcpNoDelay = true;
private boolean strictEventOrdering = false;
private HttpField encodingField;
private boolean removeIdleDestinations = false;
private boolean connectBlocking = false;
/**
* Creates a {@link HttpClient} instance that can perform requests to non-TLS destinations only
@ -204,9 +205,12 @@ public class HttpClient extends ContainerLifeCycle
executor = threadPool;
}
addBean(executor);
if (byteBufferPool == null)
byteBufferPool = new MappedByteBufferPool();
byteBufferPool = new MappedByteBufferPool(2048,
executor instanceof ThreadPool.SizedThreadPool
? ((ThreadPool.SizedThreadPool)executor).getMaxThreads()/2
: Runtime.getRuntime().availableProcessors()*2);
addBean(byteBufferPool);
if (scheduler == null)
@ -302,6 +306,14 @@ public class HttpClient extends ContainerLifeCycle
return authenticationStore;
}
/**
* @param authenticationStore the authentication store associated with this instance
*/
public void setAuthenticationStore(AuthenticationStore authenticationStore)
{
this.authenticationStore = authenticationStore;
}
/**
* Returns a <em>non</em> thread-safe set of {@link ContentDecoder.Factory}s that can be modified before
* performing requests.

View File

@ -29,9 +29,7 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.client.util.DeferredContentProvider;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.util.ssl.SslContextFactory;
@ -53,22 +51,11 @@ public class HttpResponseAbortTest extends AbstractHttpClientServerTest
final CountDownLatch latch = new CountDownLatch(1);
client.newRequest("localhost", connector.getLocalPort())
.scheme(scheme)
.onResponseBegin(new Response.BeginListener()
.onResponseBegin(response -> response.abort(new Exception()))
.send(result ->
{
@Override
public void onBegin(Response response)
{
response.abort(new Exception());
}
})
.send(new Response.CompleteListener()
{
@Override
public void onComplete(Result result)
{
Assert.assertTrue(result.isFailed());
latch.countDown();
}
Assert.assertTrue(result.isFailed());
latch.countDown();
});
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
}
@ -81,23 +68,15 @@ public class HttpResponseAbortTest extends AbstractHttpClientServerTest
final CountDownLatch latch = new CountDownLatch(1);
client.newRequest("localhost", connector.getLocalPort())
.scheme(scheme)
.onResponseHeader(new Response.HeaderListener()
.onResponseHeader((response, field) ->
{
@Override
public boolean onHeader(Response response, HttpField field)
{
response.abort(new Exception());
return true;
}
response.abort(new Exception());
return true;
})
.send(new Response.CompleteListener()
.send(result ->
{
@Override
public void onComplete(Result result)
{
Assert.assertTrue(result.isFailed());
latch.countDown();
}
Assert.assertTrue(result.isFailed());
latch.countDown();
});
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
}
@ -110,23 +89,11 @@ public class HttpResponseAbortTest extends AbstractHttpClientServerTest
final CountDownLatch latch = new CountDownLatch(1);
client.newRequest("localhost", connector.getLocalPort())
.scheme(scheme)
.onResponseHeaders(new Response.HeadersListener()
.onResponseHeaders(response -> response.abort(new Exception()))
.send(result ->
{
@Override
public void onHeaders(Response response)
{
response.abort(new Exception());
}
})
.send(new Response.CompleteListener()
{
@Override
public void onComplete(Result result)
{
Assert.assertTrue(result.isFailed());
latch.countDown();
}
Assert.assertTrue(result.isFailed());
latch.countDown();
});
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
}
@ -158,22 +125,11 @@ public class HttpResponseAbortTest extends AbstractHttpClientServerTest
final CountDownLatch latch = new CountDownLatch(1);
client.newRequest("localhost", connector.getLocalPort())
.scheme(scheme)
.onResponseContent(new Response.ContentListener()
.onResponseContent((response, content) -> response.abort(new Exception()))
.send(result ->
{
@Override
public void onContent(Response response, ByteBuffer content)
{
response.abort(new Exception());
}
})
.send(new Response.CompleteListener()
{
@Override
public void onComplete(Result result)
{
Assert.assertTrue(result.isFailed());
latch.countDown();
}
Assert.assertTrue(result.isFailed());
latch.countDown();
});
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
}
@ -202,53 +158,31 @@ public class HttpResponseAbortTest extends AbstractHttpClientServerTest
}
});
final CountDownLatch abortLatch = new CountDownLatch(1);
final DeferredContentProvider contentProvider = new DeferredContentProvider(ByteBuffer.allocate(1));
final AtomicInteger completes = new AtomicInteger();
final CountDownLatch completeLatch = new CountDownLatch(1);
client.newRequest("localhost", connector.getLocalPort())
.scheme(scheme)
.onRequestSuccess(new org.eclipse.jetty.client.api.Request.SuccessListener()
.content(contentProvider)
.onResponseContent((response, content) ->
{
@Override
public void onSuccess(org.eclipse.jetty.client.api.Request request)
try
{
try
{
abortLatch.await(5, TimeUnit.SECONDS);
}
catch (InterruptedException x)
{
x.printStackTrace();
}
response.abort(new Exception());
contentProvider.close();
// Delay to let the request side to finish its processing.
Thread.sleep(1000);
}
catch (InterruptedException x)
{
x.printStackTrace();
}
})
.onResponseContent(new Response.ContentListener()
.send(result ->
{
@Override
public void onContent(Response response, ByteBuffer content)
{
try
{
response.abort(new Exception());
abortLatch.countDown();
// Delay to let the request side to finish its processing.
Thread.sleep(1000);
}
catch (InterruptedException x)
{
x.printStackTrace();
}
}
})
.send(new Response.CompleteListener()
{
@Override
public void onComplete(Result result)
{
completes.incrementAndGet();
Assert.assertTrue(result.isFailed());
completeLatch.countDown();
}
completes.incrementAndGet();
Assert.assertTrue(result.isFailed());
completeLatch.countDown();
});
Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS));

View File

@ -207,7 +207,7 @@ INFO : logging-log4j initialized in ${jetty.base}/start.d/logging-log4j.ini
MKDIR : ${jetty.base}/lib/slf4j
DOWNLD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
MKDIR : ${jetty.base}/lib/log4j
COPY : /Users/chris/.m2/repository/log4j/log4j/1.2.17/log4j-1.2.17.jar to ${jetty.base}/lib/log4j/log4j-1.2.17.jar
COPY : /Users/admin/.m2/repository/log4j/log4j/1.2.17/log4j-1.2.17.jar to ${jetty.base}/lib/log4j/log4j-1.2.17.jar
MKDIR : ${jetty.base}/resources
COPY : ${jetty.home}/modules/log4j-impl/resources/log4j.xml to ${jetty.base}/resources/log4j.xml
DOWNLD: http://central.maven.org/maven2/org/slf4j/slf4j-log4j12/1.7.21/slf4j-log4j12-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-log4j12-1.7.21.jar

View File

@ -25,6 +25,8 @@ Jetty also offers more niche session managers that leverage backends such as Mon
include::session-hierarchy.adoc[]
include::sessions-details.adoc[]
include::session-configuration-housekeeper.adoc[]
include::session-configuration-sessioncache.adoc[]
include::session-configuration-memory.adoc[]
include::session-configuration-file-system.adoc[]
include::session-configuration-jdbc.adoc[]
@ -32,6 +34,8 @@ include::session-configuration-mongodb.adoc[]
include::session-configuration-infinispan.adoc[]
include::session-configuration-hazelcast.adoc[]
include::session-configuration-gcloud.adoc[]
include::session-configuration-memcachedsessiondatastore.adoc[]
include::sessions-usecases.adoc[]
//include::setting-session-characteristics.adoc[]
//include::using-persistent-sessions.adoc[]
//include::session-clustering-jdbc.adoc[]

View File

@ -16,7 +16,9 @@
[[configuring-sessions-file-system]]
=== Non-Clustered Session Management: File System
=== Persistent Sessions: File System
Note: Persisting sessions to the local file system should *not* be used in a clustered environment.
==== Enabling File System Sessions

View File

@ -15,7 +15,8 @@
// ========================================================================
[[configuring-sessions-gcloud]]
=== Clustered Session Management: Google Cloud DataStore
=== Persistent Sessions: Google Cloud DataStore
==== Preparation
@ -122,49 +123,49 @@ COPY : ${jetty.home}/modules/jul-impl/etc/java-util-logging.properties to ${jet
MKDIR : ${jetty.base}/lib/slf4j
DOWNLD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
MKDIR : ${jetty.base}/lib/gcloud
COPY : /Users/chris/.m2/repository/aopalliance/aopalliance/1.0/aopalliance-1.0.jar to ${jetty.base}/lib/gcloud/aopalliance-1.0.jar
COPY : /Users/chris/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.1.3/jackson-core-2.1.3.jar to ${jetty.base}/lib/gcloud/jackson-core-2.1.3.jar
COPY : /Users/chris/.m2/repository/com/google/api-client/google-api-client-appengine/1.21.0/google-api-client-appengine-1.21.0.jar to ${jetty.base}/lib/gcloud/google-api-client-appengine-1.21.0.jar
COPY : /Users/chris/.m2/repository/com/google/api-client/google-api-client/1.20.0/google-api-client-1.20.0.jar to ${jetty.base}/lib/gcloud/google-api-client-1.20.0.jar
COPY : /Users/chris/.m2/repository/com/google/api-client/google-api-client-servlet/1.21.0/google-api-client-servlet-1.21.0.jar to ${jetty.base}/lib/gcloud/google-api-client-servlet-1.21.0.jar
COPY : /Users/admin/.m2/repository/aopalliance/aopalliance/1.0/aopalliance-1.0.jar to ${jetty.base}/lib/gcloud/aopalliance-1.0.jar
COPY : /Users/admin/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.1.3/jackson-core-2.1.3.jar to ${jetty.base}/lib/gcloud/jackson-core-2.1.3.jar
COPY : /Users/admin/.m2/repository/com/google/api-client/google-api-client-appengine/1.21.0/google-api-client-appengine-1.21.0.jar to ${jetty.base}/lib/gcloud/google-api-client-appengine-1.21.0.jar
COPY : /Users/admin/.m2/repository/com/google/api-client/google-api-client/1.20.0/google-api-client-1.20.0.jar to ${jetty.base}/lib/gcloud/google-api-client-1.20.0.jar
COPY : /Users/admin/.m2/repository/com/google/api-client/google-api-client-servlet/1.21.0/google-api-client-servlet-1.21.0.jar to ${jetty.base}/lib/gcloud/google-api-client-servlet-1.21.0.jar
DOWNLD: http://central.maven.org/maven2/com/google/api/gax/0.0.21/gax-0.0.21.jar to ${jetty.base}/lib/gcloud/gax-0.0.21.jar
COPY : /Users/chris/.m2/repository/com/google/api/grpc/grpc-google-common-protos/0.1.0/grpc-google-common-protos-0.1.0.jar to ${jetty.base}/lib/gcloud/grpc-google-common-protos-0.1.0.jar
COPY : /Users/chris/.m2/repository/com/google/api/grpc/grpc-google-iam-v1/0.1.0/grpc-google-iam-v1-0.1.0.jar to ${jetty.base}/lib/gcloud/grpc-google-iam-v1-0.1.0.jar
COPY : /Users/chris/.m2/repository/com/google/auth/google-auth-library-credentials/0.3.1/google-auth-library-credentials-0.3.1.jar to ${jetty.base}/lib/gcloud/google-auth-library-credentials-0.3.1.jar
COPY : /Users/chris/.m2/repository/com/google/auth/google-auth-library-oauth2-http/0.3.1/google-auth-library-oauth2-http-0.3.1.jar to ${jetty.base}/lib/gcloud/google-auth-library-oauth2-http-0.3.1.jar
COPY : /Users/admin/.m2/repository/com/google/api/grpc/grpc-google-common-protos/0.1.0/grpc-google-common-protos-0.1.0.jar to ${jetty.base}/lib/gcloud/grpc-google-common-protos-0.1.0.jar
COPY : /Users/admin/.m2/repository/com/google/api/grpc/grpc-google-iam-v1/0.1.0/grpc-google-iam-v1-0.1.0.jar to ${jetty.base}/lib/gcloud/grpc-google-iam-v1-0.1.0.jar
COPY : /Users/admin/.m2/repository/com/google/auth/google-auth-library-credentials/0.3.1/google-auth-library-credentials-0.3.1.jar to ${jetty.base}/lib/gcloud/google-auth-library-credentials-0.3.1.jar
COPY : /Users/admin/.m2/repository/com/google/auth/google-auth-library-oauth2-http/0.3.1/google-auth-library-oauth2-http-0.3.1.jar to ${jetty.base}/lib/gcloud/google-auth-library-oauth2-http-0.3.1.jar
DOWNLD: http://central.maven.org/maven2/com/google/auto/value/auto-value/1.2/auto-value-1.2.jar to ${jetty.base}/lib/gcloud/auto-value-1.2.jar
DOWNLD: http://central.maven.org/maven2/com/google/cloud/datastore/datastore-v1-proto-client/1.3.0/datastore-v1-proto-client-1.3.0.jar to ${jetty.base}/lib/gcloud/datastore-v1-proto-client-1.3.0.jar
DOWNLD: http://central.maven.org/maven2/com/google/cloud/datastore/datastore-v1-protos/1.3.0/datastore-v1-protos-1.3.0.jar to ${jetty.base}/lib/gcloud/datastore-v1-protos-1.3.0.jar
DOWNLD: http://central.maven.org/maven2/com/google/cloud/google-cloud-core/0.5.1/google-cloud-core-0.5.1.jar to ${jetty.base}/lib/gcloud/google-cloud-core-0.5.0.jar
DOWNLD: http://central.maven.org/maven2/com/google/cloud/google-cloud-datastore/0.5.1/google-cloud-datastore-0.5.1.jar to ${jetty.base}/lib/gcloud/google-cloud-datastore-0.5.1.jar
COPY : /Users/chris/.m2/repository/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar to ${jetty.base}/lib/gcloud/jsr305-1.3.9.jar
COPY : /Users/chris/.m2/repository/com/google/code/gson/gson/2.3/gson-2.3.jar to ${jetty.base}/lib/gcloud/gson-2.3.jar
COPY : /Users/chris/.m2/repository/com/google/guava/guava/19.0/guava-19.0.jar to ${jetty.base}/lib/gcloud/guava-19.0.jar
COPY : /Users/chris/.m2/repository/com/google/http-client/google-http-client-appengine/1.21.0/google-http-client-appengine-1.21.0.jar to ${jetty.base}/lib/gcloud/google-http-client-appengine-1.21.0.jar
COPY : /Users/chris/.m2/repository/com/google/http-client/google-http-client-jackson2/1.19.0/google-http-client-jackson2-1.19.0.jar to ${jetty.base}/lib/gcloud/google-http-client-jackson2-1.19.0.jar
COPY : /Users/chris/.m2/repository/com/google/http-client/google-http-client-jackson/1.21.0/google-http-client-jackson-1.21.0.jar to ${jetty.base}/lib/gcloud/google-http-client-jackson-1.21.0.jar
COPY : /Users/chris/.m2/repository/com/google/http-client/google-http-client/1.21.0/google-http-client-1.21.0.jar to ${jetty.base}/lib/gcloud/google-http-client-1.21.0.jar
COPY : /Users/chris/.m2/repository/com/google/http-client/google-http-client-jdo/1.21.0/google-http-client-jdo-1.21.0.jar to ${jetty.base}/lib/gcloud/google-http-client-jdo-1.21.0.jar
COPY : /Users/chris/.m2/repository/com/google/http-client/google-http-client-protobuf/1.20.0/google-http-client-protobuf-1.20.0.jar to ${jetty.base}/lib/gcloud/google-http-client-protobuf-1.20.0.jar
COPY : /Users/chris/.m2/repository/com/google/inject/guice/4.0/guice-4.0.jar to ${jetty.base}/lib/gcloud/guice-4.0.jar
COPY : /Users/chris/.m2/repository/com/google/oauth-client/google-oauth-client-appengine/1.21.0/google-oauth-client-appengine-1.21.0.jar to ${jetty.base}/lib/gcloud/google-oauth-client-appengine-1.21.0.jar
COPY : /Users/chris/.m2/repository/com/google/oauth-client/google-oauth-client/1.21.0/google-oauth-client-1.21.0.jar to ${jetty.base}/lib/gcloud/google-oauth-client-1.21.0.jar
COPY : /Users/chris/.m2/repository/com/google/oauth-client/google-oauth-client-servlet/1.21.0/google-oauth-client-servlet-1.21.0.jar to ${jetty.base}/lib/gcloud/google-oauth-client-servlet-1.21.0.jar
COPY : /Users/chris/.m2/repository/com/google/protobuf/protobuf-java/3.0.0/protobuf-java-3.0.0.jar to ${jetty.base}/lib/gcloud/protobuf-java-3.0.0.jar
COPY : /Users/chris/.m2/repository/com/google/protobuf/protobuf-java-util/3.0.0/protobuf-java-util-3.0.0.jar to ${jetty.base}/lib/gcloud/protobuf-java-util-3.0.0.jar
COPY : /Users/chris/.m2/repository/commons-codec/commons-codec/1.3/commons-codec-1.3.jar to ${jetty.base}/lib/gcloud/commons-codec-1.3.jar
COPY : /Users/chris/.m2/repository/io/grpc/grpc-context/1.0.1/grpc-context-1.0.1.jar to ${jetty.base}/lib/gcloud/grpc-context-1.0.1.jar
COPY : /Users/chris/.m2/repository/io/grpc/grpc-core/1.0.1/grpc-core-1.0.1.jar to ${jetty.base}/lib/gcloud/grpc-core-1.0.1.jar
COPY : /Users/chris/.m2/repository/io/grpc/grpc-protobuf/1.0.1/grpc-protobuf-1.0.1.jar to ${jetty.base}/lib/gcloud/grpc-protobuf-1.0.1.jar
COPY : /Users/chris/.m2/repository/io/grpc/grpc-protobuf-lite/1.0.1/grpc-protobuf-lite-1.0.1.jar to ${jetty.base}/lib/gcloud/grpc-protobuf-lite-1.0.1.jar
COPY : /Users/chris/.m2/repository/javax/inject/javax.inject/1/javax.inject-1.jar to ${jetty.base}/lib/gcloud/javax.inject-1.jar
COPY : /Users/chris/.m2/repository/javax/jdo/jdo2-api/2.3-eb/jdo2-api-2.3-eb.jar to ${jetty.base}/lib/gcloud/jdo2-api-2.3-eb.jar
COPY : /Users/chris/.m2/repository/javax/transaction/transaction-api/1.1/transaction-api-1.1.jar to ${jetty.base}/lib/gcloud/transaction-api-1.1.jar
COPY : /Users/chris/.m2/repository/joda-time/joda-time/2.9.2/joda-time-2.9.2.jar to ${jetty.base}/lib/gcloud/joda-time-2.9.2.jar
COPY : /Users/chris/.m2/repository/org/apache/httpcomponents/httpclient/4.0.1/httpclient-4.0.1.jar to ${jetty.base}/lib/gcloud/httpclient-4.0.1.jar
COPY : /Users/chris/.m2/repository/org/apache/httpcomponents/httpcore/4.0.1/httpcore-4.0.1.jar to ${jetty.base}/lib/gcloud/httpcore-4.0.1.jar
COPY : /Users/chris/.m2/repository/org/codehaus/jackson/jackson-core-asl/1.9.11/jackson-core-asl-1.9.11.jar to ${jetty.base}/lib/gcloud/jackson-core-asl-1.9.11.jar
COPY : /Users/chris/.m2/repository/org/json/json/20151123/json-20151123.jar to ${jetty.base}/lib/gcloud/json-20151123.jar
COPY : /Users/admin/.m2/repository/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar to ${jetty.base}/lib/gcloud/jsr305-1.3.9.jar
COPY : /Users/admin/.m2/repository/com/google/code/gson/gson/2.3/gson-2.3.jar to ${jetty.base}/lib/gcloud/gson-2.3.jar
COPY : /Users/admin/.m2/repository/com/google/guava/guava/19.0/guava-19.0.jar to ${jetty.base}/lib/gcloud/guava-19.0.jar
COPY : /Users/admin/.m2/repository/com/google/http-client/google-http-client-appengine/1.21.0/google-http-client-appengine-1.21.0.jar to ${jetty.base}/lib/gcloud/google-http-client-appengine-1.21.0.jar
COPY : /Users/admin/.m2/repository/com/google/http-client/google-http-client-jackson2/1.19.0/google-http-client-jackson2-1.19.0.jar to ${jetty.base}/lib/gcloud/google-http-client-jackson2-1.19.0.jar
COPY : /Users/admin/.m2/repository/com/google/http-client/google-http-client-jackson/1.21.0/google-http-client-jackson-1.21.0.jar to ${jetty.base}/lib/gcloud/google-http-client-jackson-1.21.0.jar
COPY : /Users/admin/.m2/repository/com/google/http-client/google-http-client/1.21.0/google-http-client-1.21.0.jar to ${jetty.base}/lib/gcloud/google-http-client-1.21.0.jar
COPY : /Users/admin/.m2/repository/com/google/http-client/google-http-client-jdo/1.21.0/google-http-client-jdo-1.21.0.jar to ${jetty.base}/lib/gcloud/google-http-client-jdo-1.21.0.jar
COPY : /Users/admin/.m2/repository/com/google/http-client/google-http-client-protobuf/1.20.0/google-http-client-protobuf-1.20.0.jar to ${jetty.base}/lib/gcloud/google-http-client-protobuf-1.20.0.jar
COPY : /Users/admin/.m2/repository/com/google/inject/guice/4.0/guice-4.0.jar to ${jetty.base}/lib/gcloud/guice-4.0.jar
COPY : /Users/admin/.m2/repository/com/google/oauth-client/google-oauth-client-appengine/1.21.0/google-oauth-client-appengine-1.21.0.jar to ${jetty.base}/lib/gcloud/google-oauth-client-appengine-1.21.0.jar
COPY : /Users/admin/.m2/repository/com/google/oauth-client/google-oauth-client/1.21.0/google-oauth-client-1.21.0.jar to ${jetty.base}/lib/gcloud/google-oauth-client-1.21.0.jar
COPY : /Users/admin/.m2/repository/com/google/oauth-client/google-oauth-client-servlet/1.21.0/google-oauth-client-servlet-1.21.0.jar to ${jetty.base}/lib/gcloud/google-oauth-client-servlet-1.21.0.jar
COPY : /Users/admin/.m2/repository/com/google/protobuf/protobuf-java/3.0.0/protobuf-java-3.0.0.jar to ${jetty.base}/lib/gcloud/protobuf-java-3.0.0.jar
COPY : /Users/admin/.m2/repository/com/google/protobuf/protobuf-java-util/3.0.0/protobuf-java-util-3.0.0.jar to ${jetty.base}/lib/gcloud/protobuf-java-util-3.0.0.jar
COPY : /Users/admin/.m2/repository/commons-codec/commons-codec/1.3/commons-codec-1.3.jar to ${jetty.base}/lib/gcloud/commons-codec-1.3.jar
COPY : /Users/admin/.m2/repository/io/grpc/grpc-context/1.0.1/grpc-context-1.0.1.jar to ${jetty.base}/lib/gcloud/grpc-context-1.0.1.jar
COPY : /Users/admin/.m2/repository/io/grpc/grpc-core/1.0.1/grpc-core-1.0.1.jar to ${jetty.base}/lib/gcloud/grpc-core-1.0.1.jar
COPY : /Users/admin/.m2/repository/io/grpc/grpc-protobuf/1.0.1/grpc-protobuf-1.0.1.jar to ${jetty.base}/lib/gcloud/grpc-protobuf-1.0.1.jar
COPY : /Users/admin/.m2/repository/io/grpc/grpc-protobuf-lite/1.0.1/grpc-protobuf-lite-1.0.1.jar to ${jetty.base}/lib/gcloud/grpc-protobuf-lite-1.0.1.jar
COPY : /Users/admin/.m2/repository/javax/inject/javax.inject/1/javax.inject-1.jar to ${jetty.base}/lib/gcloud/javax.inject-1.jar
COPY : /Users/admin/.m2/repository/javax/jdo/jdo2-api/2.3-eb/jdo2-api-2.3-eb.jar to ${jetty.base}/lib/gcloud/jdo2-api-2.3-eb.jar
COPY : /Users/admin/.m2/repository/javax/transaction/transaction-api/1.1/transaction-api-1.1.jar to ${jetty.base}/lib/gcloud/transaction-api-1.1.jar
COPY : /Users/admin/.m2/repository/joda-time/joda-time/2.9.2/joda-time-2.9.2.jar to ${jetty.base}/lib/gcloud/joda-time-2.9.2.jar
COPY : /Users/admin/.m2/repository/org/apache/httpcomponents/httpclient/4.0.1/httpclient-4.0.1.jar to ${jetty.base}/lib/gcloud/httpclient-4.0.1.jar
COPY : /Users/admin/.m2/repository/org/apache/httpcomponents/httpcore/4.0.1/httpcore-4.0.1.jar to ${jetty.base}/lib/gcloud/httpcore-4.0.1.jar
COPY : /Users/admin/.m2/repository/org/codehaus/jackson/jackson-core-asl/1.9.11/jackson-core-asl-1.9.11.jar to ${jetty.base}/lib/gcloud/jackson-core-asl-1.9.11.jar
COPY : /Users/admin/.m2/repository/org/json/json/20151123/json-20151123.jar to ${jetty.base}/lib/gcloud/json-20151123.jar
DOWNLD: http://central.maven.org/maven2/org/slf4j/jcl-over-slf4j/1.7.21/jcl-over-slf4j-1.7.21.jar to ${jetty.base}/lib/slf4j/jcl-over-slf4j-1.7.21.jar
COPY : ${jetty.home}/modules/gcloud/index.yaml to ${jetty.base}/etc/index.yaml
INFO : Base directory was modified

View File

@ -16,7 +16,7 @@
[[configuring-sessions-hazelcast]]
=== Clustered Session Management: Hazelcast
=== Persistent Sessions: Hazelcast
==== Enabling Hazelcast Sessions
@ -24,10 +24,11 @@ When using the Jetty distribution, you will first need to enable the `session-st
[source, screen, subs="{sub-order}"]
----
mb-olamy:tmp-base olamy$ java -jar ../start.jar --create-startd
$ java -jar ../start.jar --create-startd
MKDIR : ${jetty.base}/start.d
INFO : Base directory was modified
mb-olamy:tmp-base olamy$ java -jar ../start.jar --add-to-start=session-store-hazelcast-remote
$ java -jar ../start.jar --add-to-start=session-store-hazelcast-remote
ALERT: There are enabled module(s) with licenses.
The following 1 module(s):
@ -44,11 +45,11 @@ Proceed (y/N)? y
INFO : server transitively enabled, ini template available with --add-to-start=server
INFO : sessions transitively enabled, ini template available with --add-to-start=sessions
INFO : session-store-hazelcast-remote initialized in ${jetty.base}/start.d/session-store-hazelcast-remote.ini
MKDIR : /Users/olamy/mvn-repo/com/hazelcast/hazelcast/3.8.2
DOWNLD: http://central.maven.org/maven2/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar to /Users/olamy/mvn-repo/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar
MKDIR : /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2
DOWNLD: http://central.maven.org/maven2/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar to /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar
MKDIR : ${jetty.base}/lib/hazelcast
COPY : /Users/olamy/mvn-repo/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar to ${jetty.base}/lib/hazelcast/hazelcast-3.8.2.jar
COPY : /Users/olamy/mvn-repo/com/hazelcast/hazelcast-client/3.8.2/hazelcast-client-3.8.2.jar to ${jetty.base}/lib/hazelcast/hazelcast-client-3.8.2.jar
COPY : /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar to ${jetty.base}/lib/hazelcast/hazelcast-3.8.2.jar
COPY : /Users/admin/mvn-repo/com/hazelcast/hazelcast-client/3.8.2/hazelcast-client-3.8.2.jar to ${jetty.base}/lib/hazelcast/hazelcast-client-3.8.2.jar
INFO : Base directory was modified
----
@ -112,10 +113,10 @@ To enable this you will first need to enable the `session-store-hazelcast-embedd
[source, screen, subs="{sub-order}"]
----
mb-olamy:tmp-base olamy$ java -jar ../start.jar --create-startd
$ java -jar ../start.jar --create-startd
MKDIR : ${jetty.base}/start.d
INFO : Base directory was modified
mb-olamy:tmp-base olamy$ java -jar ../start.jar --add-to-start=session-store-hazelcast-embedded
$ java -jar ../start.jar --add-to-start=session-store-hazelcast-embedded
ALERT: There are enabled module(s) with licenses.
The following 1 module(s):
@ -132,11 +133,11 @@ Proceed (y/N)? y
INFO : server transitively enabled, ini template available with --add-to-start=server
INFO : sessions transitively enabled, ini template available with --add-to-start=sessions
INFO : session-store-hazelcast-embedded initialized in ${jetty.base}/start.d/session-store-hazelcast-embedded.ini
MKDIR : /Users/olamy/mvn-repo/com/hazelcast/hazelcast/3.8.2
DOWNLD: http://central.maven.org/maven2/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar to /Users/olamy/mvn-repo/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar
MKDIR : /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2
DOWNLD: http://central.maven.org/maven2/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar to /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar
MKDIR : ${jetty.base}/lib/hazelcast
COPY : /Users/olamy/mvn-repo/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar to ${jetty.base}/lib/hazelcast/hazelcast-3.8.2.jar
COPY : /Users/olamy/mvn-repo/com/hazelcast/hazelcast-client/3.8.2/hazelcast-client-3.8.2.jar to ${jetty.base}/lib/hazelcast/hazelcast-client-3.8.2.jar
COPY : /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar to ${jetty.base}/lib/hazelcast/hazelcast-3.8.2.jar
COPY : /Users/admin/mvn-repo/com/hazelcast/hazelcast-client/3.8.2/hazelcast-client-3.8.2.jar to ${jetty.base}/lib/hazelcast/hazelcast-client-3.8.2.jar
----
Doing this enables the embedded Hazelcast Session module and any dependent modules or files needed for it to run on the server.

View File

@ -0,0 +1,54 @@
// ========================================================================
// 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.
// ========================================================================
[[session-configuration-housekeeper]]
=== The SessionIdManager and the Housekeeper
==== Default Settings
By default, Jetty will instantiate a single instance of the `DefaultSessionIdManager` and `HouseKeeper` at startup with default settings.
The default settings are:
DefaultSessionIdManager: worker name::
This uniquely identifies the jetty server instance within a cluster.
It is set from the value of the `JETTY_WORKER_INSTANCE` environment variable, or `node0` if the environment value is not set.
If you have more than one Jetty instance, it is *crucial* that you explicitly configure the worker name on each Jetty instance (see link:#session-idmanager-housekeeper-config[below] for how to configure).
HouseKeeper: scavenge interval::
This is the period in seconds between runs of the session scavenger, and by default is set to the equivalent of 10 minutes.
As a rule of thumb, you should ensure that the scavenge interval is shorter than the `maxInactiveInterval` of your sessions to ensure that they are promptly scavenged.
See below for instructions on how to configure this.
[[session-idmanager-housekeeper-config]]
==== Configuration
To change the default values, use the link:#startup-modules[module system] to link:#startup-modules[enable] the `sessions` module.
This will enable the `$jetty.home/etc/sessions/id-manager.xml` file and generate a `$jetty.base/start.d/sessions.ini` file.
The `id-manager.xml` file instantiates a single `DefaultSessionIdManager` and `HouseKeeper` and configures them using the properties from the `sessions.ini` file.
Edit the ini file to change the properties to easily customize the `DefaultSessionIdManager` and `HouseKeeper`:
jetty.sessionIdManager.workerName::
By default it is `node1`.
This uniquely identifies the Jetty server instance within a cluster.
If you have more than one Jetty instance, it is crucial that you configure the worker name differently on each jetty instance.
jetty.sessionScavengeInterval.seconds::
This is the period in seconds between runs of the session scavenger.
By default it will run every 600 secs (ie 10 mins).
As a rule of thumb, you should ensure that the scavenge interval is shorter than the maxInactiveInterval of your sessions to ensure that they are promptly scavenged.

View File

@ -16,12 +16,17 @@
[[configuring-sessions-infinispan]]
=== Clustered Session Management: Inifinspan
=== Persistent Sessions: Inifinspan
==== Enabling Infinispan Sessions
When using the Jetty distribution, you will first need to enable the `session-store-infinispan-remote` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line.
____
[IMPORTANT]
If you are running Jetty with JDK 9 or greater, enable `session-store-infinispan-remote-910.mod` instead.
____
[source, screen, subs="{sub-order}"]
----
$ java -jar ../start.jar --create-startd
@ -106,6 +111,11 @@ ____
During testing, it can be helpful to run an in-process instance of Infinispan.
To enable this you will first need to enable the `session-store-infinispan-embedded` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line.
____
[IMPORTANT]
If you are running Jetty with JDK 9 or greater, enable `session-store-infinispan-embedded-910.mod` instead.
____
[source, screen, subs="{sub-order}"]
----
java -jar ../start.jar --add-to-start=session-store-infinispan-embedded

View File

@ -16,7 +16,7 @@
[[configuring-sessions-jdbc]]
=== Clustered Session Management: JDBC
=== Persistent Sessions: JDBC
==== Enabling JDBC Sessions

View File

@ -0,0 +1,62 @@
// ========================================================================
// 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.
// ========================================================================
[[session-configuration-memcachedsessiondatastore]]
=== Persistent Sessions: The L2 Session Data Cache
If your chosen persistence technology is slow, it can be helpful to locally cache the session data.
The `CachingSessionDataStore` is a special type of `SessionDataStore` that locally caches session data, which makes reads faster. It writes-through to your chosen type of `SessionDataStore` when session data changes.
==== MemcachedSessionDataMap
The `MemcachedSessionDataMap` uses `memcached` to perform caching.
To enable it with the Jetty distribution, enable the `session-store-cache` link:#startup-modules[module], along with your chosen `session-store-xxxx` module, and optionally the `session-cache-hash` or `session-cache-null` modules.
After enabling, the `$jetty.base/start.d/session-store-cache.ini` file will be generated:
[source, screen, subs="{sub-order}"]
----
--module=session-store-cache
## Session Data Cache type: xmemcached
session-data-cache=xmemcached
#jetty.session.memcached.host=localhost
#jetty.session.memcached.port=11211
#jetty.session.memcached.expirySec=
#jetty.session.memcached.heartbeats=true
----
The configuration properties are:
jetty.session.memcached.host::
Default value is `localhost`.
This is the host on which the memcached server resides.
jetty.session.memcached.port::
Default value is `11211`.
This is the port on which the memcached server is listening.
jetty.session.memcached.expirySec::
Default value `0`.
This is the length of time in seconds that an item can remain in the memcached cache, where 0 indicates indefinitely.
jetty.session.memcached.heartbeats::
Default value `true`.
Whether or not the memcached system should generate heartbeats.

View File

@ -16,21 +16,16 @@
[[configuring-sessions-memory]]
=== Non-Clustered Session Management: Memory
=== Non-Persistent Sessions
Non-clustered, in-memory-only is the default style of Session Management.
In previous versions of Jetty this was referred to as "hash" sessions, as they were stored in a `HashMap` in memory.
When using the Jetty distribution, if you do not configure any session module, this will be enabled by default.
Non-clustered, non-persistent, in-memory-only is the default style of session management.
In previous versions of Jetty this was referred to as "hash" sessions, as they were stored in a `HashMap` in memory.
Specifically, Jetty will hook up:
This is delivered by a combination of the `DefaultSessionCache` (to keep sessions in memory) and a `NullSessionDataStore` (to avoid session persistence).
A `DefaultSessionIdManager`::
* Produces unique session ids and supports cross-context dispatch re-use of session ids
A `HouseKeeper`::
* Scavenges for expired sessions every 10 mins
A `DefaultSessionCache` per context::
* Keeps session objects in memory
A `NullSessionDataStore` per context::
* No persistence of sessions
If you do nothing, Jetty will instantiate one of each of these objects for each context at startup time using hard-coded defaults.
If you wish to change any of the default configuration, enable the `session-cache-hash` module.
To explicitly set up non-persisted sessions using modules, use both the `session-cache-hash` and the `session-store-null` modules.
Enabling the modules allows you to configure behavior - see link:#session-configuration-sessioncache[the L1 Session Cache] for detailed information on configuration options for the `DefaultSessionCache`.
The `NullSessionDataStore` has no customizable options.

View File

@ -16,7 +16,7 @@
[[configuring-sessions-mongo]]
=== Clustered Session Management: MongoDB
=== Persistent Sessions: MongoDB
==== Enabling MongoDB Sessions

View File

@ -0,0 +1,73 @@
// ========================================================================
// 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.
// ========================================================================
[[session-configuration-sessioncache]]
=== The L1 Session Cache
==== The DefaultSessionCache
In the absence of any explicit configuration, Jetty will instantiate an instance of the `DefaultSessionCache` per context.
If you wish to change any of the default values, you need to enable the `session-cache-hash` link:#startup-modules[module].
Once the `session-cache-hash` module has been enabled, you can view a list of all the configurable values by opening `start.d/session-cache-hash.ini`:
[source, screen, subs="{sub-order}"]
----
--module=session-cache-hash
#jetty.session.evictionPolicy=-1
#jetty.session.saveOnInactiveEvict=false
#jetty.session.saveOnCreate=false
#jetty.session.removeUnloadableSessions=false
----
jetty.session.evictionPolicy::
Integer.
Controls whether session objects that are held in memory are subject to eviction from the memory cache.
Evicting sessions can reduce the memory footprint of the cache.
Eviction is usually used in conjunction with a `SessionDataStore` that persists sessions.
Values are:
* -1 : sessions are never evicted from the cache
* 0 : sessions are evicted from the cache as soon as the last active request for it finishes
* >= 1 : any positive number is the time in seconds after which a session that is in the cache but has not experienced any activity will be evicted
____
[NOTE]
If you are not using a `SessionDataStore` that persists sessions, be aware that evicted sessions will be lost.
____
jetty.session.saveOnInactiveEvict::
Boolean, default `false`.
Controls whether a session will be saved to the `SessionDataStore` just prior to its eviction.
jetty.session.saveOnCreate::
Boolean, default `false`.
Controls whether a session that is newly created will be immediately saved to the `SessionDataStore` or lazily saved as the last request for the session exits.
jetty.session.removeUnloadableSessions::
Boolean, default `false`.
Controls whether a session that cannot be restored - for example because it is corrupted - from the `SessionDataStore` is deleted by the `SessionDataStore`.
For more general information on the uses of these configuration properties, see link:#sessions-details[Session Components].
==== The NullSessionCache
The `NullSessionCache` is a trivial implementation of the `SessionCache` that does not cache any session information.
You may need to use it if your clustering setup does not have a sticky load balancer, or if you want absolutely minimal support for sessions.
If you use this in conjunction with the `NullSessionDataStore`, then sessions will neither be retained in memory nor persisted.
To enable the `NullSessionCache`, enable the `sesssion-cache-null` link:#startup-modules[module].

View File

@ -49,8 +49,11 @@ image::images/SessionsHierarchy.png[]
==== Configuring Sessions in the Jetty Distribution
Jetty provides support for several different Session Management technologies.
Both link:#configuring-sessions-file-system[local file storage] and in-memory session management can be implemented for standard implementations.
For implementations using clustered technologies, link:#configuring-sessions-jdbc[JDBC], link:#configuring-sessions-mongo[MongoDB], link:#configuring-sessions-infinispan[Inifinispan] and link:#configuring-sessions-gcloud[Google Cloud Datastore] are all supported.
Setting up these technologies is as easy as enabling it's link:#startup-modules[module] and editing it's associated ini file with any usernames, passwords or changes you need to make for your instance.
The following sections will cover how exactly to enable the required modules as well as an overview of what options are available for customization.
Configuring session management involves selecting a link:#startup-modules[module] for the desired type of link:#session-configuration-sessioncache[session caching] behavior, and a module for the type of session persistence.
Jetty provides two different session caches: the `DefaultSessionCache` which holds sessions in memory, and the `NullSessionCache` which does not.
There is more information on both of these types of session caching and the circumstances which would lead you to select one or the other in the link:#sessions-details[Session Components] section, and more information on the configuration options of each in link:#session-configuration-sessioncache[the L1 Session Cache] section.
For session persistence, Jetty provides a number of different implementations from which to choose including link:#configuring-sessions-memory[non-persistence], link:#configuring-sessions-file-system[local file storage], clustered technologies such as link:#configuring-sessions-jdbc[JDBC], link:#configuring-sessions-mongo[MongoDB], link:#configuring-sessions-infinispan[Inifinispan], link:#configuring-sessions-gcloud[Google Cloud Datastore], and link:#configuring-sessions-hazelcast[Hazelcast].
Depending on your persistence technology, to enhance performance, you may want to use an L2 cache for session data, in which case Jetty provides the link:#session-configuration-memcachedsessiondatastore[memcached L2 session data cache].

View File

@ -15,40 +15,43 @@
// ========================================================================
[[sessions-details]]
=== Session Configuration and Use Cases
=== Session Components
==== Configuration
==== SessionIdManager
===== SessionIdManager
There is a maximum of 1 `SessionIdManager` per jetty Server instance.
There is a maximum of one (1) `SessionIdManager` per Jetty Server instance.
Its purpose is to generate fresh, unique session ids and to coordinate the re-use of session ids amongst co-operating contexts.
Unlike in previous versions of Jetty, the `SessionIdManager` is agnostic with respect to the type of clustering technology chosen.
Jetty provides a default implementation - the `DefaultSessionIdManager` - which should meet the needs of most users.
If you do not explicitly enable one of the session modules, or otherwise configure a `SessionIdManager`, the `DefaultSessionIdManager` will be used.
If you do not explicitly enable one of the session modules or otherwise configure a `SessionIdManager`, the `DefaultSessionIdManager` will be used.
If the `DefaultSessionIdManager` does not meet your needs, you can extend the `org.eclipse.jetty.server.session.AbstractSessionIdManager` or do a fresh implementation of the `org.eclipse.jetty.server.session.SessionIdManager` interface.
===== HouseKeeper
See link:#session-configuration-housekeeper[Configuring the SessionIdManager and HouseKeeper] for details on configuration.
There is a maximum of 1 `HouseKeeper` per `SessionIdManager`.
==== HouseKeeper
There is a maximum of one (1) `HouseKeeper` per `SessionIdManager`.
Its purpose is to periodically poll the `SessionHandlers` to clean out expired sessions.
By default the `HouseKeeper` will poll the `SessionHandlers` every 10 mins to find and delete expired sessions, although this interval is configurable.
See link:#session-configuration-housekeeper[Configuring the SessionIdManager and HouseKeeper] for details on configuration.
===== SessionCache
There is 1 `SessionCache` per context.
==== SessionCache
There is one (1) `SessionCache` *per context.*
Its purpose is to provide an L1 cache of Session objects.
Having a working set of Session objects in memory allows multiple simultaneous requests for the same session to share the same Session object.
Jetty provides 2 `SessionCache` implementations: the `DefaultSessionCache` and the `NullSessionCache`.
The `DefaultSessionCache` retains Session objects in memory in a cache and has a number of configuration options to control cache behavior.
Jetty provides two (2) `SessionCache` implementations: the `DefaultSessionCache` and the `NullSessionCache`.
The `DefaultSessionCache` retains Session objects in memory in a cache and has a number of link:#session-configuration-sessioncache[configuration options] to control cache behavior.
It is the default that is used if no other `SessionCache` has been configured.
It is suitable for non-clustered and clustered deployments with a sticky load balancer, as well as clustered deployments with a non-sticky load balancer, with some caveats.
The `NullSessionCache` does not actually cache any objects: each request uses a fresh Session object.
It is suitable for clustered deployments without a sticky load balancer and non-clustered deployments when purely minimal support for sessions is needed.
@ -58,16 +61,19 @@ They can also be configured to do an immediate, eager write of a freshly created
This can be useful if you are likely to experience multiple, near simultaneous requests referencing the same session, e.g. with HTTP/2 and you don't have a sticky load balancer.
Alternatively, if the eager write is not done, application paths which create and then invalidate a session within a single request never incur the cost of writing to persistent storage.
Additionally, if the `EVICT_ON_INACTIVITY` eviction policy is in use, you can configure the `DefaultSessionCache` to force a write of the Session to the SessionDataStore just before the Session is evicted.
Additionally, if the `EVICT_ON_INACTIVITY` eviction policy is in use, you can link:#session-configuration-sessioncache[configure] the `DefaultSessionCache` to force a write of the Session to the `SessionDataStore` just before the Session is evicted.
===== SessionDataStore
See link:#session-configuration-sessioncache[the L1 Session Cache] for more information.
There is 1 `SessionDataStore` per context. Its purpose is to handle all persistence related operations on sessions.
==== SessionDataStore
There is one (1) `SessionDataStore` per context.
Its purpose is to handle all persistence related operations on sessions.
The common characteristics for all `SessionDataStores` are whether or not they support passivation, and the length of the grace period.
Supporting passivation means that session data is serialized.
Some persistence mechanisms serialize, such as JDBC, GCloud Datastore etc, whereas others may store an object in shared memory eg Infinispan when configured with a local cache.
Some persistence mechanisms serialize, such as JDBC, GCloud Datastore etc, whereas others may store an object in shared memory, e.g. Infinispan, when configured with a local cache.
Whether or not a clustering technology entails passivation controls whether or not the session passivation/activation listeners will be called.
@ -79,56 +85,17 @@ When `SessionDataStores` search their persistent store to find sessions that hav
* The second finds sessions in the store that have expired which were last live on the current node
* The third finds sessions that expired a "while" ago, irrespective of on which node they were last used: the definition of "a while" is based on the grace period.
Jetty instantiates the trivial `NullSessionDataStore` - which does not persist sessions - as the default.
===== CachingSessionDataStore
The distribution provides a number of alternative `SessionDataStore` implementations such as link:#configuring-sessions-file-system[FileSessionDataStore], link:#configuring-sessions-gcloud[GCloudSessionDataStore], link:#configuring-sessions-jdbc[JDBCSessionDataStore], link:#configuring-sessions-mongodb[MongoSessionDataStore], link:#configuring-sessions-infinispan[InfinispanSessionDataStore], link:#configuring-sessions-hazelcast[HazelcastSessionDataStore].
The `CachingSessionDataStore` is a special type of `SessionDataStore` that inserts an L2 cache of SessionData - the `SessionDataMap` - in front of a delegate `SessionDataStore`.
==== CachingSessionDataStore
The `CachingSessionDataStore` is a special type of `SessionDataStore` that inserts an L2 cache of Session data - the `SessionDataMap` - in front of a delegate `SessionDataStore`.
The `SessionDataMap` is preferentially consulted before the actual SessionDataStore on reads.
This can improve the performance of slow stores.
Jetty provides one implementation of the this L2 cache based on `Memcached`, the `MemcachedSessionDataMap`.
==== Use Cases
===== 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.
In this case, the `DefaultSessionCache` can be used to keep in-use Session objects in memory.
You can fine-tune the cache by controlling how long Session objects remain in memory with the eviction policy settings.
If you have a large number of Sessions or very large Session objects, then you might want to manage your memory allocation by controlling the amount of time Session objects spend in the cache.
The `EVICT_ON_SESSION_EXIT` eviction policy will remove a Session object from the cache as soon as the last simultaneous request referencing it exits.
Alternatively, the `EVICT_ON_INACTIVITY` policy will remove a Session object from the cache after a configurable amount of time has passed without a request referencing it.
If your Sessions are very long lived and infrequently referenced, you might use the `EVICT_ON_INACTIVITY_POLICY` to control the size of the cache.
If your Sessions are small, or relatively few or stable in number or they are read-mostly, then you might select the `NEVER_EVICT` policy.
With this policy, Session objects will remain in the cache until they either expire or are explicitly invalidated.
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
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.
In this case, your `choices` are to use either the `NullSessionCache` or to de-tuned the `DefaultSessionCache`.
If you use the NullSessionCache all Session object caching is avoided.
This means that every time a request references a session it must be brought in from persistent storage.
It also means that there can be no sharing of Session objects for multiple requests for the same session: each will have their own Session object.
Furthermore, the outcome of session writes are indeterminate because the Servlet Specification does not mandate ACID transactions for sessions.
If you use the `DefaultSessionCache`, there is a risk that the caches on some nodes will contain out-of-date session information as simultaneous requests for the same session are scattered over the cluster.
To mitigate this somewhat you can use the `EVICT_ON_SESSION_EXIT` eviction policy: this will ensure that the Session is removed from the cache as soon as the last simultaneous request for it exits.
Again, due to the lack of session transactionality, the ordering outcome of write operations cannot be guaranteed.
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
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.
Using the setter `SessionCache.setRemoveUnloadableSessions(true)` will allow the `SessionDataStore` to delete the unreadable session from persistent storage.
This can be useful from preventing the scavenger from continually generating errors on the same expired, but un-restorable, session.
See link:#session-configuration-memcachedsessiondatastore[the L2 SessionData Cache]for additional information.

View File

@ -0,0 +1,60 @@
// ========================================================================
// 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.
// ========================================================================
[[sessions-usecases]]
=== Use Cases
==== 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.
In this case, the `DefaultSessionCache` can be used to keep in-use Session objects in memory.
You can fine-tune the cache by controlling how long Session objects remain in memory with the eviction policy settings.
If you have a large number of Sessions or very large Session objects, then you may want to manage your memory allocation by controlling the amount of time Session objects spend in the cache.
The `EVICT_ON_SESSION_EXIT` eviction policy will remove a Session object from the cache as soon as the last simultaneous request referencing it exits.
Alternatively, the `EVICT_ON_INACTIVITY` policy will remove a Session object from the cache after a configurable amount of time has passed without a request referencing it.
If your Sessions are very long lived and infrequently referenced, you might use the `EVICT_ON_INACTIVITY_POLICY` to control the size of the cache.
If your Sessions are small, or relatively few or stable in number or they are read-mostly, then you might select the `NEVER_EVICT` policy.
With this policy, Session objects will remain in the cache until they either expire or are explicitly invalidated.
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
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.
In this case, your `choices` are to use either the `NullSessionCache` or to de-tune the `DefaultSessionCache`.
If you use the NullSessionCache all Session object caching is avoided.
This means that every time a request references a session it must be brought in from persistent storage.
It also means that there can be no sharing of Session objects for multiple requests for the same session: each will have their own Session object.
Furthermore, the outcome of session writes are indeterminate because the Servlet Specification does not mandate ACID transactions for sessions.
If you use the `DefaultSessionCache`, there is a risk that the caches on some nodes will contain out-of-date Session information as simultaneous requests for the same session are scattered over the cluster.
To mitigate this somewhat you can use the `EVICT_ON_SESSION_EXIT` eviction policy: this will ensure that the Session is removed from the cache as soon as the last simultaneous request for it exits.
Again, due to the lack of Session transactionality, the ordering outcome of write operations cannot be guaranteed.
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
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.
Using the setter `SessionCache.setRemoveUnloadableSessions(true)` will allow the `SessionDataStore` to delete the unreadable session from persistent storage.
This can be useful from preventing the scavenger from continually generating errors on the same expired, but un-restorable, session.

View File

@ -115,8 +115,8 @@ Jetty Environment:
Config Search Order:
--------------------
<command-line>
${jetty.base} -> /home/user/jetty-distribution-9.4.1.v20170120/demo-base
${jetty.home} -> /home/user/Desktop/jetty-distribution-9.4.1.v20170120
${jetty.base} -> /home/user/jetty-distribution-{VERSION}/demo-base
${jetty.home} -> /home/user/Desktop/jetty-distribution-{VERSION}
JVM Arguments:
--------------
@ -152,26 +152,26 @@ Jetty Server Classpath:
Version Information on 42 entries in the classpath.
Note: order presented here is how they would appear on the classpath.
changes to the --module=name command line options will be reflected here.
0: {VERSION} | ${jetty.home}/lib/jetty-client-{VERSION}.jar
0: {VERSION} | ${jetty.home}/lib/jetty-client-{VERSION}.jar
1: 1.4.1.v201005082020 | ${jetty.base}/lib/ext/javax.mail.glassfish-1.4.1.v201005082020.jar
2: {VERSION} | ${jetty.base}/lib/ext/test-mock-resources-{VERSION}.jar
2: {VERSION} | ${jetty.base}/lib/ext/test-mock-resources-{VERSION}.jar
3: (dir) | ${jetty.home}/resources
4: 3.1.0 | ${jetty.home}/lib/servlet-api-3.1.jar
5: 3.1.RC0 | ${jetty.home}/lib/jetty-schemas-3.1.jar
6: {VERSION} | ${jetty.home}/lib/jetty-http-{VERSION}.jar
7: {VERSION} | ${jetty.home}/lib/jetty-continuation-{VERSION}.jar
8: {VERSION} | ${jetty.home}/lib/jetty-server-{VERSION}.jar
9: {VERSION} | ${jetty.home}/lib/jetty-xml-{VERSION}.jar
10: {VERSION} | ${jetty.home}/lib/jetty-util-{VERSION}.jar
11: {VERSION} | ${jetty.home}/lib/jetty-io-{VERSION}.jar
12: {VERSION} | ${jetty.home}/lib/jetty-jaas-{VERSION}.jar
13: {VERSION} | ${jetty.home}/lib/jetty-jndi-{VERSION}.jar
6: {VERSION} | ${jetty.home}/lib/jetty-http-{VERSION}.jar
7: {VERSION} | ${jetty.home}/lib/jetty-continuation-{VERSION}.jar
8: {VERSION} | ${jetty.home}/lib/jetty-server-{VERSION}.jar
9: {VERSION} | ${jetty.home}/lib/jetty-xml-{VERSION}.jar
10: {VERSION} | ${jetty.home}/lib/jetty-util-{VERSION}.jar
11: {VERSION} | ${jetty.home}/lib/jetty-io-{VERSION}.jar
12: {VERSION} | ${jetty.home}/lib/jetty-jaas-{VERSION}.jar
13: {VERSION} | ${jetty.home}/lib/jetty-jndi-{VERSION}.jar
14: 1.1.0.v201105071233 | ${jetty.home}/lib/jndi/javax.activation-1.1.0.v201105071233.jar
15: 1.4.1.v201005082020 | ${jetty.home}/lib/jndi/javax.mail.glassfish-1.4.1.v201005082020.jar
16: 1.2 | ${jetty.home}/lib/jndi/javax.transaction-api-1.2.jar
17: {VERSION} | ${jetty.home}/lib/jetty-rewrite-{VERSION}.jar
18: {VERSION} | ${jetty.home}/lib/jetty-security-{VERSION}.jar
19: {VERSION} | ${jetty.home}/lib/jetty-servlet-{VERSION}.jar
17: {VERSION} | ${jetty.home}/lib/jetty-rewrite-{VERSION}.jar
18: {VERSION} | ${jetty.home}/lib/jetty-security-{VERSION}.jar
19: {VERSION} | ${jetty.home}/lib/jetty-servlet-{VERSION}.jar
20: 3.0.0 | ${jetty.home}/lib/jsp/javax.el-3.0.0.jar
21: 1.2.0.v201105211821 | ${jetty.home}/lib/jsp/javax.servlet.jsp.jstl-1.2.0.v201105211821.jar
22: 2.3.2 | ${jetty.home}/lib/jsp/javax.servlet.jsp-2.3.2.jar
@ -179,21 +179,21 @@ Note: order presented here is how they would appear on the classpath.
24: 2.3.3 | ${jetty.home}/lib/jsp/jetty-jsp-jdt-2.3.3.jar
25: 1.2.0.v201112081803 | ${jetty.home}/lib/jsp/org.apache.taglibs.standard.glassfish-1.2.0.v201112081803.jar
26: 3.8.2.v20130121-145325 | ${jetty.home}/lib/jsp/org.eclipse.jdt.core-3.8.2.v20130121.jar
27: {VERSION} | ${jetty.home}/lib/jetty-plus-{VERSION}.jar
28: {VERSION} | ${jetty.home}/lib/jetty-webapp-{VERSION}.jar
29: {VERSION} | ${jetty.home}/lib/jetty-annotations-{VERSION}.jar
27: {VERSION} | ${jetty.home}/lib/jetty-plus-{VERSION}.jar
28: {VERSION} | ${jetty.home}/lib/jetty-webapp-{VERSION}.jar
29: {VERSION} | ${jetty.home}/lib/jetty-annotations-{VERSION}.jar
30: 4.1 | ${jetty.home}/lib/annotations/asm-4.1.jar
31: 4.1 | ${jetty.home}/lib/annotations/asm-commons-4.1.jar
32: 1.2 | ${jetty.home}/lib/annotations/javax.annotation-api-1.2.jar
33: {VERSION} | ${jetty.home}/lib/jetty-deploy-{VERSION}.jar
33: {VERSION} | ${jetty.home}/lib/jetty-deploy-{VERSION}.jar
34: 1.0 | ${jetty.home}/lib/websocket/javax.websocket-api-1.0.jar
35: {VERSION} | ${jetty.home}/lib/websocket/javax-websocket-client-impl-{VERSION}.jar
36: {VERSION} | ${jetty.home}/lib/websocket/javax-websocket-server-impl-{VERSION}.jar
37: {VERSION} | ${jetty.home}/lib/websocket/websocket-api-{VERSION}.jar
38: {VERSION} | ${jetty.home}/lib/websocket/websocket-client-{VERSION}.jar
39: {VERSION} | ${jetty.home}/lib/websocket/websocket-common-{VERSION}.jar
40: {VERSION} | ${jetty.home}/lib/websocket/websocket-server-{VERSION}.jar
41: {VERSION} | ${jetty.home}/lib/websocket/websocket-servlet-{VERSION}.jar
35: {VERSION} | ${jetty.home}/lib/websocket/javax-websocket-client-impl-{VERSION}.jar
36: {VERSION} | ${jetty.home}/lib/websocket/javax-websocket-server-impl-{VERSION}.jar
37: {VERSION} | ${jetty.home}/lib/websocket/websocket-api-{VERSION}.jar
38: {VERSION} | ${jetty.home}/lib/websocket/websocket-client-{VERSION}.jar
39: {VERSION} | ${jetty.home}/lib/websocket/websocket-common-{VERSION}.jar
40: {VERSION} | ${jetty.home}/lib/websocket/websocket-server-{VERSION}.jar
41: {VERSION} | ${jetty.home}/lib/websocket/websocket-servlet-{VERSION}.jar
Jetty Active XMLs:
------------------

View File

@ -17,57 +17,39 @@
[[garbage-collection]]
=== Garbage Collection
Tuning the JVM garbage collection (GC) can greatly improve Jetty performance.
Specifically, you can avoid pauses while the system performs full garbage collections.
Optimal tuning of the GC depends on the behavior of the application and requires detailed analysis, however there are general recommendations.
Tuning the JVM garbage collection (GC) can greatly improve the performance of the JVM where Jetty and your application are running.
Optimal tuning of the GC depends on the behavior of the application(s) and requires detailed analysis, but there are general recommendations to follow to at least obtain comprehensive GC logs that can be later analyzed.
See official https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/[Java 8 Garbage Collection documentation] for further assistance.
See official https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/[Java 8] and https://docs.oracle.com/javase/9/gctuning/introduction-garbage-collection-tuning.htm[Java 9] Garbage Collection documentation for further assistance.
[[tuning-examples]]
==== Tuning Examples
[[garbage-collection-logging-configuration]]
==== Garbage Collection Logging Configuration
These options are general to the Oracle JVM, and work in a Java 8 installation.
They provide good information about how your JVM is running; based on that initial information, you can then tune more finely.
The most important thing you can do for yourself when considering GC is to capture the GC activity so that you can analyze what is happening and how often it happens.
These options are general to OpenJDK (and therefore also for the Oracle JVM).
They provide good information about the GC activity of your JVM, producing logs that can later be analyzed to perform finer tuning.
.JDK 8 Garbage Collection Logging Configuration
[source,screen, subs="{sub-order}"]
....
-verbose:gc
-Xloggc:/path/to/myjettybase/logs/gc.log
-XX:+PrintGCDateStamps
-XX:+PrintGCTimeStamps
-XX:+PrintGCDetails
-XX:+PrintTenuringDistribution
-XX:+PrintCommandLineFlags
-XX:+ParallelRefProcEnabled
-XX:+PrintReferenceGC
-XX:+PrintTenuringDistribution
-XX:+PrintAdaptiveSizePolicy
....
There are not many recommended options for GC that can apply to nearly all users.
.JDK 9 Garbage Collection Logging Configuration
[source,screen, subs="{sub-order}"]
....
Xlog:gc*,ergo*=trace,ref*=debug,age*=trace:file=/path/to/myjettybase/logs/gc.log:time,level,tags
....
There are not many recommended options for GC that can apply to all users.
However, the most obvious one is to disable explicit GC (this is performed regularly by RMI and can introduce an abnormal amount of GC pauses).
[source,screen, subs="{sub-order}"]
....
-XX:+DisableExplicitGC
....
Before you apply any other GC tuning options, monitor your GC logs to see if https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/cms.html[tuning the CMS] makes sense for your environment.
A common setup for those just starting out with GC tuning is included below for reference.
____
[CAUTION]
This example configuration below could have a negative effect on your application performance, so continued monitoring of your GC log before and after is highly recommended to know if the configuration was beneficial or not.
____
[source,screen, subs="{sub-order}"]
....
-XX:MaxGCPauseMillis=250
-XX:+UseConcMarkSweepGC
-XX:ParallelCMSThreads=2
-XX:+CMSClassUnloadingEnabled
-XX:+UseCMSCompactAtFullCollection
-XX:CMSInitiatingOccupancyFraction=80
....

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

@ -60,8 +60,8 @@ Unfortunately this approach denies all aliases, including symbolic links, which
==== Serving Aliases and Symbolic Links
Not all aliases are bad nor should be seen as attempts to subvert security constraints.
Specifically symbolic links can be very useful when assembling complex web applications, yet by default Jetty will not serve them.
Thus Jetty contexts support an extensible `AliasCheck` mechanism to allow aliases resources to be inspected an conditionally served.
Specifically, symbolic links can be very useful when assembling complex web applications.
As such, Jetty contexts support an extensible `AliasCheck` mechanism to allow aliases resources to be inspected and conditionally served.
In this way, "good" aliases can be detected and served.
Jetty provides several utility implementations of the `AliasCheck` interface as nested classes with `ContextHandler`:
@ -70,6 +70,11 @@ ApproveAliases::
AllowSymLinkAliasChecker::
Approve Aliases using the java-7 `Files.readSymbolicLink(path)` and `Path.toRealPath(...)` APIs to check that aliases are valid symbolic links.
____
[NOTE]
By default, Jetty serves aliased files for implementations running on UNIX as Contexts are created with both the {JDURL}/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.html[`AllowSymLinkAliasChecker`] and {JDURL}/org/eclipse/jetty/server/handler/ContextHandler.ApproveNonExistentDirectoryAliases.html[`ApproveNonExistentDirectoryAliases`] alias checkers.
____
An application is free to implement its own Alias checking.
Alias Checkers can be installed in a context via the following XML used in a context deployer file or `WEB-INF/jetty-web.xml`:

View File

@ -26,8 +26,8 @@ To start Jetty on the default port of 8080, run the following command:
2015-06-04 10:50:44.806:INFO::main: Logging initialized @334ms
2015-06-04 10:50:44.858:WARN:oejs.HomeBaseWarning:main: This instance of Jetty is not running from a separate {jetty.base} directory, this is not recommended. See documentation at http://www.eclipse.org/jetty/documentation/current/startup.html
2015-06-04 10:50:44.995:INFO:oejs.Server:main: jetty-9.3.0.v20150601
2015-06-04 10:50:45.012:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:///opt/jetty-distribution-9.3.0.v20150601/webapps/] at interval 1
2015-06-04 10:50:44.995:INFO:oejs.Server:main: jetty-{VERSION}
2015-06-04 10:50:45.012:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:///opt/jetty-distribution-{VERSION}/webapps/] at interval 1
2015-06-04 10:50:45.030:INFO:oejs.ServerConnector:main: Started ServerConnector@19dfb72a{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2015-06-04 10:50:45.030:INFO:oejs.Server:main: Started @558ms
----
@ -57,13 +57,13 @@ Within the standard Jetty distribution there is the `demo-base` directory, which
2017-08-16 16:55:15.571:INFO::main: Logging initialized @521ms to org.eclipse.jetty.util.log.StdErrLog
2017-08-16 16:55:15.907:WARN::main: demo test-realm is deployed. DO NOT USE IN PRODUCTION!
2017-08-16 16:55:15.910:INFO:oejs.Server:main: jetty-9.4.7-SNAPSHOT
2017-08-16 16:55:15.931:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:///tmp/jetty-distribution-9.4.7-SNAPSHOT/demo-base/webapps/] at interval 1
2017-08-16 16:55:15.910:INFO:oejs.Server:main: jetty-{VERSION}
2017-08-16 16:55:15.931:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:///tmp/jetty-distribution-{VERSION}/demo-base/webapps/] at interval 1
2017-08-16 16:55:16.151:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=50ms
2017-08-16 16:55:16.369:INFO:oejs.session:main: DefaultSessionIdManager workerName=node0
2017-08-16 16:55:16.369:INFO:oejs.session:main: No SessionScavenger set, using defaults
2017-08-16 16:55:16.370:INFO:oejs.session:main: Scavenging every 660000ms
2017-08-16 16:55:16.416:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@7113b13f{/,file:///tmp/jetty-distribution-9.4.7-SNAPSHOT/demo-base/webapps/ROOT/,AVAILABLE}{/ROOT}
2017-08-16 16:55:16.416:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@7113b13f{/,file:///tmp/jetty-distribution-{VERSION}/demo-base/webapps/ROOT/,AVAILABLE}{/ROOT}
2017-08-16 16:55:16.625:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=82ms
2017-08-16 16:55:16.631:WARN::main: test webapp is deployed. DO NOT USE IN PRODUCTION!
2017-08-16 16:55:16.751:INFO:oejsh.ManagedAttributeListener:main: update PushFilter null->org.eclipse.jetty.servlets.PushCacheFilter@1a677343 on o.e.j.w.WebAppContext@2d7275fc{/test,file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test.war-_test-any-7157753932050220016.dir/webapp/,STARTING}{/test.war}
@ -72,7 +72,7 @@ Within the standard Jetty distribution there is the `demo-base` directory, which
2017-08-16 16:55:16.809:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@2d7275fc{/test,file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test.war-_test-any-7157753932050220016.dir/webapp/,AVAILABLE}{/test.war}
2017-08-16 16:55:16.816:INFO:oejsh.ContextHandler:main: Started o.e.j.s.h.MovedContextHandler@7c9d8e2{/oldContextPath,null,AVAILABLE}
2017-08-16 16:55:16.854:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=23ms
2017-08-16 16:55:16.891:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@69453e37{/doc,file:///tmp/jetty-distribution-9.4.7-SNAPSHOT/demo-base/webapps/doc/,AVAILABLE}{/doc}
2017-08-16 16:55:16.891:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@69453e37{/doc,file:///tmp/jetty-distribution-{VERSION}/demo-base/webapps/doc/,AVAILABLE}{/doc}
2017-08-16 16:55:16.942:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=25ms
2017-08-16 16:55:16.945:WARN::main: test-jaas webapp is deployed. DO NOT USE IN PRODUCTION!
2017-08-16 16:55:16.983:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@4e3958e7{/test-jaas,file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test-jaas.war-_test-jaas-any-6953571893682159674.dir/webapp/,AVAILABLE}{/test-jaas.war}
@ -81,15 +81,15 @@ Within the standard Jetty distribution there is the `demo-base` directory, which
2017-08-16 16:55:17.192:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@1d8bd0de{/test-jndi,file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test-jndi.war-_test-jndi-any-1246461885510956986.dir/webapp/,AVAILABLE}{/test-jndi.war}
2017-08-16 16:55:17.307:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=53ms
2017-08-16 16:55:17.310:WARN::main: test-spec webapp is deployed. DO NOT USE IN PRODUCTION!
2017-08-16 16:55:17.388:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@51dcb805{/test-spec,[file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test-spec.war-_test-spec-any-3750193079644252256.dir/webapp/, jar:file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test-spec.war-_test-spec-any-3750193079644252256.dir/webapp/WEB-INF/lib/test-web-fragment-9.4.7-SNAPSHOT.jar!/META-INF/resources],AVAILABLE}{/test-spec.war}
2017-08-16 16:55:17.388:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@51dcb805{/test-spec,[file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test-spec.war-_test-spec-any-3750193079644252256.dir/webapp/, jar:file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-test-spec.war-_test-spec-any-3750193079644252256.dir/webapp/WEB-INF/lib/test-web-fragment-{VERSION}.jar!/META-INF/resources],AVAILABLE}{/test-spec.war}
2017-08-16 16:55:17.490:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=53ms
2017-08-16 16:55:17.493:WARN::main: async-rest webapp is deployed. DO NOT USE IN PRODUCTION!
2017-08-16 16:55:17.516:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@1de76cc7{/async-rest,[file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-async-rest.war-_async-rest-any-8972552397332323832.dir/webapp/, jar:file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-async-rest.war-_async-rest-any-8972552397332323832.dir/webapp/WEB-INF/lib/example-async-rest-jar-9.4.7-SNAPSHOT.jar!/META-INF/resources],AVAILABLE}{/async-rest.war}
2017-08-16 16:55:17.516:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@1de76cc7{/async-rest,[file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-async-rest.war-_async-rest-any-8972552397332323832.dir/webapp/, jar:file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-async-rest.war-_async-rest-any-8972552397332323832.dir/webapp/WEB-INF/lib/example-async-rest-jar-{VERSION}.jar!/META-INF/resources],AVAILABLE}{/async-rest.war}
2017-08-16 16:55:17.643:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=83ms
2017-08-16 16:55:17.921:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@242b836{/proxy,file:///private/var/folders/h6/yb_lbnnn11g0y1jjlvqg631h0000gn/T/jetty-0.0.0.0-8080-javadoc-proxy.war-_javadoc-proxy-any-4521643038409884891.dir/webapp/,AVAILABLE}{/javadoc-proxy.war}
2017-08-16 16:55:17.936:INFO:oejs.AbstractConnector:main: Started ServerConnector@6f15d60e{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2017-08-16 16:55:17.944:INFO:oejus.SslContextFactory:main: x509=X509@58e1d9d(jetty,h=[jetty.eclipse.org],w=[]) for SslContextFactory@446a1e84(file:///tmp/jetty-distribution-9.4.7-SNAPSHOT/demo-base/etc/keystore,file:///tmp/jetty-distribution-9.4.7-SNAPSHOT/demo-base/etc/keystore)
2017-08-16 16:55:17.944:INFO:oejus.SslContextFactory:main: x509=X509@4f0f2942(mykey,h=[],w=[]) for SslContextFactory@446a1e84(file:///tmp/jetty-distribution-9.4.7-SNAPSHOT/demo-base/etc/keystore,file:///tmp/jetty-distribution-9.4.7-SNAPSHOT/demo-base/etc/keystore)
2017-08-16 16:55:17.944:INFO:oejus.SslContextFactory:main: x509=X509@58e1d9d(jetty,h=[jetty.eclipse.org],w=[]) for SslContextFactory@446a1e84(file:///tmp/jetty-distribution-{VERSION}/demo-base/etc/keystore,file:///tmp/jetty-distribution-{VERSION}/demo-base/etc/keystore)
2017-08-16 16:55:17.944:INFO:oejus.SslContextFactory:main: x509=X509@4f0f2942(mykey,h=[],w=[]) for SslContextFactory@446a1e84(file:///tmp/jetty-distribution-{VERSION}/demo-base/etc/keystore,file:///tmp/jetty-distribution-{VERSION}/demo-base/etc/keystore)
2017-08-16 16:55:18.071:INFO:oejs.AbstractConnector:main: Started ServerConnector@41488b16{SSL,[ssl, http/1.1]}{0.0.0.0:8443}
2017-08-16 16:55:18.072:INFO:oejs.Server:main: Started @3022ms
----
@ -179,7 +179,7 @@ INFO: Base directory was modified
2015-06-04 11:10:16.460:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:///tmp/mybase/webapps/] at interval 1
2015-06-04 11:10:16.581:WARN::main: async-rest webapp is deployed. DO NOT USE IN PRODUCTION!
2015-06-04 11:10:16.589:INFO:oejw.StandardDescriptorProcessor:main: NO JSP Support for /, did not find org.eclipse.jetty.jsp.JettyJspServlet
2015-06-04 11:10:16.628:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@1a407d53{/,[file:///tmp/jetty-0.0.0.0-8080-ROOT.war-_-any-4510228025526425427.dir/webapp/, jar:file:///tmp/jetty-0.0.0.0-8080-ROOT.war-_-any-4510228025526425427.dir/webapp/WEB-INF/lib/example-async-rest-jar-9.3.0.v20150601.jar!/META-INF/resources],AVAILABLE}{/ROOT.war}
2015-06-04 11:10:16.628:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@1a407d53{/,[file:///tmp/jetty-0.0.0.0-8080-ROOT.war-_-any-4510228025526425427.dir/webapp/, jar:file:///tmp/jetty-0.0.0.0-8080-ROOT.war-_-any-4510228025526425427.dir/webapp/WEB-INF/lib/example-async-rest-jar-{VERSION}.jar!/META-INF/resources],AVAILABLE}{/ROOT.war}
2015-06-04 11:10:16.645:INFO:oejs.ServerConnector:main: Started ServerConnector@3abbfa04{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2015-06-04 11:10:16.646:INFO:oejs.Server:main: Started @634ms
----

View File

@ -86,7 +86,7 @@ The default system classes are:
.Default System Classes
[width="100%",cols="8%,92%",options="header",]
|=======================================================================
|System Classes
|System Classes | Note
|java. |Java SE classes (per servlet spec v2.5 / SRV.9.7.2).
|javax. |Java SE classes (per servlet spec v2.5 / SRV.9.7.2).
|org.xml. |Needed by javax.xml.
@ -98,7 +98,7 @@ The default system classes are:
|org.eclipse.jetty.servlet.DefaultServlet |Webapp can see and not change default servlet.
|=======================================================================
Absolute classname can be passed, names ending with . are treated as packages names, and names starting with - are treated as negative matches and must be listed before any enclosing packages.
Absolute classname can be passed, names ending with `.` are treated as packages names, and names starting with `-` are treated as negative matches and must be listed before any enclosing packages.
[[setting-server-classes]]
===== Setting Server Classes

View File

@ -1,5 +1,7 @@
<?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/maven-v4_0_0.xsd">
<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/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty.gcloud</groupId>
<artifactId>gcloud-parent</artifactId>
@ -22,12 +24,12 @@
<version>${gcloud.version}</version>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</exclusion>
</exclusions>
@ -57,50 +59,51 @@
</dependency>
</dependencies>
<properties>
<bundle-symbolic-name>${project.groupId}.session</bundle-symbolic-name>
</properties>
<properties>
<bundle-symbolic-name>${project.groupId}.session</bundle-symbolic-name>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Export-Package>org.eclipse.jetty.gcloud.session.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}";</Export-Package>
</instructions>
</configuration>
</execution>
</executions>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Export-Package>
org.eclipse.jetty.gcloud.session.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}";
</Export-Package>
</instructions>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>build-deps-file</id>
<phase>generate-resources</phase>
<goals>
<goal>list</goal>
</goals>
<configuration>
<appendOutput>false</appendOutput>
<outputFile>${project.build.directory}/deps.txt</outputFile>
<sort>true</sort>
<excludeGroupIds>org.eclipse.jetty</excludeGroupIds>
<prependGroupId>true</prependGroupId>
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>build-deps-file</id>
<phase>generate-resources</phase>
<goals>
<goal>list</goal>
</goals>
<configuration>
<appendOutput>false</appendOutput>
<outputFile>${project.build.directory}/deps.txt</outputFile>
<sort>true</sort>
<excludeGroupIds>org.eclipse.jetty</excludeGroupIds>
<prependGroupId>true</prependGroupId>
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -118,15 +121,15 @@
match=" *(.*):(.*):jar:(.*):[a-z]*"
replace="maven://\1/\2/\3|lib/gcloud/\2-\3.jar"
byline="true"
/>
/>
<replaceregexp file="${project.build.directory}/deps.txt"
match="The following files have been resolved:"
replace="[files]"
/>
</tasks>
</configuration>
</execution>
<execution>
</execution>
<execution>
<id>process-mod</id>
<phase>process-resources</phase>
<goals>
@ -141,8 +144,7 @@
</tasks>
</configuration>
</execution>
</executions>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -161,7 +163,7 @@
</execution>
</executions>
</plugin>
</plugins>
</plugins>
</build>
</project>

View File

@ -486,6 +486,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

@ -26,6 +26,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
@ -98,6 +99,12 @@ public class HttpFields implements Iterable<HttpField>
{
return new Itr();
}
public ListIterator<HttpField> listIterator()
{
return new Itr();
}
public Stream<HttpField> stream()
{
@ -935,7 +942,7 @@ public class HttpFields implements Iterable<HttpField>
return value.substring(0, i).trim();
}
private class Itr implements Iterator<HttpField>
private class Itr implements ListIterator<HttpField>
{
int _cursor; // index of next element to return
int _last=-1;
@ -963,6 +970,49 @@ public class HttpFields implements Iterable<HttpField>
_cursor=_last;
_last=-1;
}
@Override
public boolean hasPrevious()
{
return _cursor>0;
}
@Override
public HttpField previous()
{
if (_cursor == 0)
throw new NoSuchElementException();
return _fields[_last=--_cursor];
}
@Override
public int nextIndex()
{
return _cursor+1;
}
@Override
public int previousIndex()
{
return _cursor-1;
}
@Override
public void set(HttpField field)
{
if (_last<0)
throw new IllegalStateException();
_fields[_last] = field;
}
@Override
public void add(HttpField field)
{
_fields = Arrays.copyOf(_fields,_fields.length+1);
System.arraycopy(_fields,_cursor,_fields,_cursor+1,_size++);
_fields[_cursor++] = field;
_last=-1;
}
}
}

View File

@ -28,6 +28,7 @@ import org.eclipse.jetty.http.HttpTokens.EndOfContent;
import org.eclipse.jetty.util.ArrayTernaryTrie;
import org.eclipse.jetty.util.ArrayTrie;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.Trie;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.Utf8StringBuilder;
@ -601,8 +602,8 @@ public class HttpParser
while (_state.ordinal()<State.HEADER.ordinal() && buffer.hasRemaining() && !handle)
{
// process each character
byte ch=next(buffer);
if (ch==0)
byte b=next(buffer);
if (b==0)
break;
if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
@ -625,7 +626,7 @@ public class HttpParser
switch (_state)
{
case METHOD:
if (ch == SPACE)
if (b == SPACE)
{
_length=_string.length();
_methodString=takeString();
@ -634,19 +635,19 @@ public class HttpParser
_methodString=legacyString(_methodString,method.asString());
setState(State.SPACE1);
}
else if (ch < SPACE)
else if (b < SPACE)
{
if (ch==LINE_FEED)
if (b==LINE_FEED)
throw new BadMessageException("No URI");
else
throw new IllegalCharacterException(_state,ch,buffer);
throw new IllegalCharacterException(_state,b,buffer);
}
else
_string.append((char)ch);
_string.append((char)b);
break;
case RESPONSE_VERSION:
if (ch == HttpTokens.SPACE)
if (b == HttpTokens.SPACE)
{
_length=_string.length();
String version=takeString();
@ -655,19 +656,19 @@ public class HttpParser
throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Unknown Version");
setState(State.SPACE1);
}
else if (ch < HttpTokens.SPACE)
throw new IllegalCharacterException(_state,ch,buffer);
else if (b < HttpTokens.SPACE)
throw new IllegalCharacterException(_state,b,buffer);
else
_string.append((char)ch);
_string.append((char)b);
break;
case SPACE1:
if (ch > HttpTokens.SPACE || ch<0)
if (b > HttpTokens.SPACE || b<0)
{
if (_responseHandler!=null)
{
setState(State.STATUS);
setResponseStatus(ch-'0');
setResponseStatus(b-'0');
}
else
{
@ -695,25 +696,25 @@ public class HttpParser
buffer.position(i-buffer.arrayOffset());
}
else
_uri.append(ch);
_uri.append(b);
}
}
else if (ch < HttpTokens.SPACE)
else if (b < HttpTokens.SPACE)
{
throw new BadMessageException(HttpStatus.BAD_REQUEST_400,_requestHandler!=null?"No URI":"No Status");
}
break;
case STATUS:
if (ch == HttpTokens.SPACE)
if (b == HttpTokens.SPACE)
{
setState(State.SPACE2);
}
else if (ch>='0' && ch<='9')
else if (b>='0' && b<='9')
{
_responseStatus=_responseStatus*10+(ch-'0');
_responseStatus=_responseStatus*10+(b-'0');
}
else if (ch < HttpTokens.SPACE && ch>=0)
else if (b < HttpTokens.SPACE && b>=0)
{
setState(State.HEADER);
handle=_responseHandler.startResponse(_version, _responseStatus, null)||handle;
@ -725,11 +726,11 @@ public class HttpParser
break;
case URI:
if (ch == HttpTokens.SPACE)
if (b == HttpTokens.SPACE)
{
setState(State.SPACE2);
}
else if (ch < HttpTokens.SPACE && ch>=0)
else if (b < HttpTokens.SPACE && b>=0)
{
// HTTP/0.9
if (complianceViolation(RFC7230,"HTTP/0.9"))
@ -741,15 +742,15 @@ public class HttpParser
}
else
{
_uri.append(ch);
_uri.append(b);
}
break;
case SPACE2:
if (ch > HttpTokens.SPACE)
if (b > HttpTokens.SPACE)
{
_string.setLength(0);
_string.append((char)ch);
_string.append((char)b);
if (_responseHandler!=null)
{
_length=1;
@ -789,7 +790,7 @@ public class HttpParser
}
}
}
else if (ch == HttpTokens.LINE_FEED)
else if (b == HttpTokens.LINE_FEED)
{
if (_responseHandler!=null)
{
@ -808,12 +809,12 @@ public class HttpParser
handle= handleHeaderContentMessage() || handle;
}
}
else if (ch<0)
else if (b<0)
throw new BadMessageException();
break;
case REQUEST_VERSION:
if (ch == HttpTokens.LINE_FEED)
if (b == HttpTokens.LINE_FEED)
{
if (_version==null)
{
@ -835,25 +836,25 @@ public class HttpParser
handle=_requestHandler.startRequest(_methodString,_uri.toString(), _version)||handle;
continue;
}
else if (ch>=HttpTokens.SPACE)
_string.append((char)ch);
else if (b>=HttpTokens.SPACE)
_string.append((char)b);
else
throw new BadMessageException();
break;
case REASON:
if (ch == HttpTokens.LINE_FEED)
if (b == HttpTokens.LINE_FEED)
{
String reason=takeString();
setState(State.HEADER);
handle=_responseHandler.startResponse(_version, _responseStatus, reason)||handle;
continue;
}
else if (ch>=HttpTokens.SPACE)
else if (b>=HttpTokens.SPACE || ((b<0) && (b>=-96)))
{
_string.append((char)ch);
if (ch!=' '&&ch!='\t')
_string.append((char)(0xff&b));
if (b!=' '&&b!='\t')
_length=_string.length();
}
else
@ -991,8 +992,8 @@ public class HttpParser
while ((_state==State.HEADER || _state==State.TRAILER) && buffer.hasRemaining())
{
// process each character
byte ch=next(buffer);
if (ch==0)
byte b=next(buffer);
if (b==0)
break;
if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
@ -1007,7 +1008,7 @@ public class HttpParser
switch (_fieldState)
{
case FIELD:
switch(ch)
switch(b)
{
case HttpTokens.COLON:
case HttpTokens.SPACE:
@ -1110,7 +1111,7 @@ public class HttpParser
default:
{
// now handle the ch
if (ch<HttpTokens.SPACE)
if (b<HttpTokens.SPACE)
throw new BadMessageException();
// process previous header
@ -1168,15 +1169,15 @@ public class HttpParser
{
// Header and value
int pos=buffer.position()+n.length()+v.length()+1;
byte b=buffer.get(pos);
byte peek=buffer.get(pos);
if (b==HttpTokens.CARRIAGE_RETURN || b==HttpTokens.LINE_FEED)
if (peek==HttpTokens.CARRIAGE_RETURN || peek==HttpTokens.LINE_FEED)
{
_field=field;
_valueString=v;
setState(FieldState.IN_VALUE);
if (b==HttpTokens.CARRIAGE_RETURN)
if (peek==HttpTokens.CARRIAGE_RETURN)
{
_cr=true;
buffer.position(pos+1);
@ -1199,7 +1200,7 @@ public class HttpParser
// New header
setState(FieldState.IN_NAME);
_string.setLength(0);
_string.append((char)ch);
_string.append((char)b);
_length=1;
}
@ -1207,7 +1208,7 @@ public class HttpParser
break;
case IN_NAME:
if (ch==HttpTokens.COLON)
if (b==HttpTokens.COLON)
{
if (_headerString==null)
{
@ -1220,7 +1221,7 @@ public class HttpParser
break;
}
if (ch>HttpTokens.SPACE)
if (b>HttpTokens.SPACE)
{
if (_header!=null)
{
@ -1229,13 +1230,13 @@ public class HttpParser
_headerString=null;
}
_string.append((char)ch);
if (ch>HttpTokens.SPACE)
_string.append((char)b);
if (b>HttpTokens.SPACE)
_length=_string.length();
break;
}
if (ch==HttpTokens.LINE_FEED && !complianceViolation(RFC7230,"name only header"))
if (b==HttpTokens.LINE_FEED && !complianceViolation(RFC7230,"name only header"))
{
if (_headerString==null)
{
@ -1251,21 +1252,21 @@ public class HttpParser
break;
}
throw new IllegalCharacterException(_state,ch,buffer);
throw new IllegalCharacterException(_state,b,buffer);
case VALUE:
if (ch>HttpTokens.SPACE || ch<0)
if (b>HttpTokens.SPACE || b<0)
{
_string.append((char)(0xff&ch));
_string.append((char)(0xff&b));
_length=_string.length();
setState(FieldState.IN_VALUE);
break;
}
if (ch==HttpTokens.SPACE || ch==HttpTokens.TAB)
if (b==HttpTokens.SPACE || b==HttpTokens.TAB)
break;
if (ch==HttpTokens.LINE_FEED)
if (b==HttpTokens.LINE_FEED)
{
_value=null;
_string.setLength(0);
@ -1275,10 +1276,10 @@ public class HttpParser
setState(FieldState.FIELD);
break;
}
throw new IllegalCharacterException(_state,ch,buffer);
throw new IllegalCharacterException(_state,b,buffer);
case IN_VALUE:
if (ch>=HttpTokens.SPACE || ch<0 || ch==HttpTokens.TAB)
if (b>=HttpTokens.SPACE || b<0 || b==HttpTokens.TAB)
{
if (_valueString!=null)
{
@ -1286,13 +1287,13 @@ public class HttpParser
_valueString=null;
_field=null;
}
_string.append((char)(0xff&ch));
if (ch>HttpTokens.SPACE || ch<0)
_string.append((char)(0xff&b));
if (b>HttpTokens.SPACE || b<0)
_length=_string.length();
break;
}
if (ch==HttpTokens.LINE_FEED)
if (b==HttpTokens.LINE_FEED)
{
if (_length > 0)
{
@ -1304,7 +1305,7 @@ public class HttpParser
break;
}
throw new IllegalCharacterException(_state,ch,buffer);
throw new IllegalCharacterException(_state,b,buffer);
default:
throw new IllegalStateException(_state.toString());

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

@ -144,7 +144,7 @@ public class CookieCutterTest
* Example from RFC2965
*/
@Test
@Ignore("comma separation no longer supported by RFC6265")
@Ignore("comma separation no longer supported by new RFC6265")
public void testRFC2965_CookieSpoofingExample()
{
String rawCookie = "$Version=\"1\"; session_id=\"1234\", " +

View File

@ -21,7 +21,9 @@ package org.eclipse.jetty.http;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.NoSuchElementException;
@ -31,6 +33,7 @@ import org.junit.Assert;
import org.junit.Test;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
@ -628,4 +631,68 @@ public class HttpFieldsTest
assertFalse(header.containsKey("n11"));
}
@Test
public void testIteration() throws Exception
{
HttpFields header = new HttpFields();
Iterator<HttpField> i = header.iterator();
assertThat(i.hasNext(),is(false));
header.put("name1", "valueA");
header.put("name2", "valueB");
header.add("name3", "valueC");
i = header.iterator();
assertThat(i.hasNext(),is(true));
assertThat(i.next().getName(),is("name1"));
assertThat(i.next().getName(),is("name2"));
i.remove();
assertThat(i.next().getName(),is("name3"));
assertThat(i.hasNext(),is(false));
i = header.iterator();
assertThat(i.hasNext(),is(true));
assertThat(i.next().getName(),is("name1"));
assertThat(i.next().getName(),is("name3"));
assertThat(i.hasNext(),is(false));
ListIterator<HttpField> l = header.listIterator();
assertThat(l.hasNext(),is(true));
l.add(new HttpField("name0","value"));
assertThat(l.hasNext(),is(true));
assertThat(l.next().getName(),is("name1"));
l.set(new HttpField("NAME1","value"));
assertThat(l.hasNext(),is(true));
assertThat(l.hasPrevious(),is(true));
assertThat(l.previous().getName(),is("NAME1"));
assertThat(l.hasNext(),is(true));
assertThat(l.hasPrevious(),is(true));
assertThat(l.previous().getName(),is("name0"));
assertThat(l.hasNext(),is(true));
assertThat(l.hasPrevious(),is(false));
assertThat(l.next().getName(),is("name0"));
assertThat(l.hasNext(),is(true));
assertThat(l.hasPrevious(),is(true));
assertThat(l.next().getName(),is("NAME1"));
l.add(new HttpField("name2","value"));
assertThat(l.next().getName(),is("name3"));
assertThat(l.hasNext(),is(false));
assertThat(l.hasPrevious(),is(true));
l.add(new HttpField("name4","value"));
assertThat(l.hasNext(),is(false));
assertThat(l.hasPrevious(),is(true));
assertThat(l.previous().getName(),is("name4"));
i = header.iterator();
assertThat(i.hasNext(),is(true));
assertThat(i.next().getName(),is("name0"));
assertThat(i.next().getName(),is("NAME1"));
assertThat(i.next().getName(),is("name2"));
assertThat(i.next().getName(),is("name3"));
assertThat(i.next().getName(),is("name4"));
assertThat(i.hasNext(),is(false));
}
}

View File

@ -155,7 +155,7 @@ public class HttpGeneratorServerTest
assertEquals(HttpGenerator.Result.NEED_INFO, result);
assertEquals(HttpGenerator.State.START, gen.getState());
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, null, new HttpFields(), 10);
MetaData.Response info = new MetaData.Response(HttpVersion.HTTP_1_1, 200, "ØÆ", new HttpFields(), 10);
info.getFields().add("Content-Type", "test/data;\r\nextra=value");
info.getFields().add("Last-Modified", DateGenerator.__01Jan1970);
@ -176,7 +176,7 @@ public class HttpGeneratorServerTest
assertEquals(10, gen.getContentPrepared());
assertThat(response, containsString("HTTP/1.1 200 OK"));
assertThat(response, containsString("HTTP/1.1 200 ØÆ"));
assertThat(response, containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT"));
assertThat(response, containsString("Content-Type: test/data; extra=value"));
assertThat(response, containsString("Content-Length: 10"));

View File

@ -573,7 +573,9 @@ public class HttpParserTest
BufferUtil.put(BufferUtil.toBuffer(" HTTP/1.0\r\n"), buffer);
BufferUtil.put(BufferUtil.toBuffer("Header1: "), buffer);
buffer.put("\u00e6 \u00e6".getBytes(StandardCharsets.ISO_8859_1));
BufferUtil.put(BufferUtil.toBuffer(" \r\n\r\n"), buffer);
BufferUtil.put(BufferUtil.toBuffer(" \r\nHeader2: "), buffer);
buffer.put((byte)-1);
BufferUtil.put(BufferUtil.toBuffer("\r\n\r\n"), buffer);
BufferUtil.flipToFlush(buffer, 0);
HttpParser.RequestHandler handler = new Handler();
@ -585,7 +587,9 @@ public class HttpParserTest
Assert.assertEquals("HTTP/1.0", _versionOrReason);
Assert.assertEquals("Header1", _hdr[0]);
Assert.assertEquals("\u00e6 \u00e6", _val[0]);
Assert.assertEquals(0, _headers);
Assert.assertEquals("Header2", _hdr[1]);
Assert.assertEquals(""+(char)255, _val[1]);
Assert.assertEquals(1, _headers);
Assert.assertEquals(null, _bad);
}
@ -1304,6 +1308,22 @@ public class HttpParserTest
Assert.assertTrue(_messageCompleted);
}
@Test
public void testResponseReasonIso8859_1() throws Exception
{
ByteBuffer buffer = BufferUtil.toBuffer(
"HTTP/1.1 302 déplacé temporairement\r\n"
+ "Content-Length: 0\r\n"
+ "\r\n",StandardCharsets.ISO_8859_1);
HttpParser.ResponseHandler handler = new Handler();
HttpParser parser = new HttpParser(handler);
parser.parseNext(buffer);
Assert.assertEquals("HTTP/1.1", _methodOrVersion);
Assert.assertEquals("302", _uriOrStatus);
Assert.assertEquals("déplacé temporairement", _versionOrReason);
}
@Test
public void testSeekEOF() throws Exception
{

View File

@ -50,15 +50,15 @@
</build>
<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.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>
<artifactId>jetty-alpn-openjdk8-server</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
@ -86,4 +86,21 @@
</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>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
</profiles>
</project>

View File

@ -47,7 +47,6 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
public static final String CLIENT_CONTEXT_KEY = "http2.client";
public static final String BYTE_BUFFER_POOL_CONTEXT_KEY = "http2.client.byteBufferPool";
public static final String EXECUTOR_CONTEXT_KEY = "http2.client.executor";
public static final String PREALLOCATED_EXECUTOR_CONTEXT_KEY = "http2.client.preallocatedExecutor";
public static final String SCHEDULER_CONTEXT_KEY = "http2.client.scheduler";
public static final String SESSION_LISTENER_CONTEXT_KEY = "http2.client.sessionListener";
public static final String SESSION_PROMISE_CONTEXT_KEY = "http2.client.sessionPromise";
@ -60,7 +59,6 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
HTTP2Client client = (HTTP2Client)context.get(CLIENT_CONTEXT_KEY);
ByteBufferPool byteBufferPool = (ByteBufferPool)context.get(BYTE_BUFFER_POOL_CONTEXT_KEY);
Executor executor = (Executor)context.get(EXECUTOR_CONTEXT_KEY);
ReservedThreadExecutor preallocatedExecutor = (ReservedThreadExecutor)context.get(PREALLOCATED_EXECUTOR_CONTEXT_KEY);
Scheduler scheduler = (Scheduler)context.get(SCHEDULER_CONTEXT_KEY);
Session.Listener listener = (Session.Listener)context.get(SESSION_LISTENER_CONTEXT_KEY);
@SuppressWarnings("unchecked")
@ -71,37 +69,29 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
HTTP2ClientSession session = new HTTP2ClientSession(scheduler, endPoint, generator, listener, flowControl);
Parser parser = new Parser(byteBufferPool, session, 4096, 8192);
if (preallocatedExecutor==null)
{
// TODO move this to non lazy construction
preallocatedExecutor=client.getBean(ReservedThreadExecutor.class);
if (preallocatedExecutor==null)
{
synchronized (this)
{
if (preallocatedExecutor==null)
{
try
{
preallocatedExecutor = new ReservedThreadExecutor(executor,1); // TODO configure size
preallocatedExecutor.start();
client.addBean(preallocatedExecutor,true);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
}
}
}
HTTP2ClientConnection connection = new HTTP2ClientConnection(client, byteBufferPool, preallocatedExecutor, endPoint,
ReservedThreadExecutor reservedExecutor = provideReservedThreadExecutor(client, executor);
HTTP2ClientConnection connection = new HTTP2ClientConnection(client, byteBufferPool, reservedExecutor, endPoint,
parser, session, client.getInputBufferSize(), promise, listener);
connection.addListener(connectionListener);
return customize(connection, context);
}
protected ReservedThreadExecutor provideReservedThreadExecutor(HTTP2Client client, Executor executor)
{
synchronized (this)
{
ReservedThreadExecutor reservedExecutor = client.getBean(ReservedThreadExecutor.class);
if (reservedExecutor == null)
{
// TODO: see HTTP2Connection.FillableCallback
reservedExecutor = new ReservedThreadExecutor(executor, 0);
client.addManaged(reservedExecutor);
}
return reservedExecutor;
}
}
private class HTTP2ClientConnection extends HTTP2Connection implements Callback
{
private final HTTP2Client client;

View File

@ -58,7 +58,6 @@ public class HTTP2Connection extends AbstractConnection
this.session = session;
this.bufferSize = bufferSize;
this.strategy = new EatWhatYouKill(producer, executor.getExecutor(), executor);
LifeCycle.start(strategy);
}
@ -274,6 +273,8 @@ public class HTTP2Connection extends AbstractConnection
@Override
public InvocationType getInvocationType()
{
// TODO: see also AbstractHTTP2ServerConnectionFactory.reservedThreads.
// TODO: it's non blocking here because reservedThreads=0.
return InvocationType.NON_BLOCKING;
}
}

View File

@ -154,6 +154,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
public void setReservedThreads(int threads)
{
// TODO: see also HTTP2Connection.FillableCallback.
// TODO: currently disabled since the only value that works is 0.
// this.reservedThreads = threads;
}
@ -182,29 +183,8 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
streamIdleTimeout = endPoint.getIdleTimeout();
session.setStreamIdleTimeout(streamIdleTimeout);
session.setInitialSessionRecvWindow(getInitialSessionRecvWindow());
ReservedThreadExecutor executor = connector.getBean(ReservedThreadExecutor.class);
if (executor==null)
{
synchronized (this)
{
executor = connector.getBean(ReservedThreadExecutor.class);
if (executor==null)
{
try
{
executor = new ReservedThreadExecutor(connector.getExecutor(), getReservedThreads());
executor.start();
connector.addBean(executor,true);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
}
}
ReservedThreadExecutor executor = provideReservedThreadExecutor(connector);
ServerParser parser = newServerParser(connector, session);
HTTP2Connection connection = new HTTP2ServerConnection(connector.getByteBufferPool(), executor,
@ -213,6 +193,20 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
return configure(connection, connector, endPoint);
}
protected ReservedThreadExecutor provideReservedThreadExecutor(Connector connector)
{
synchronized (this)
{
ReservedThreadExecutor executor = getBean(ReservedThreadExecutor.class);
if (executor == null)
{
executor = new ReservedThreadExecutor(connector.getExecutor(), getReservedThreads());
addManaged(executor);
}
return executor;
}
}
protected abstract ServerSessionListener newSessionListener(Connector connector, EndPoint endPoint);
protected ServerParser newServerParser(Connector connector, ServerParser.Listener listener)

View File

@ -9,6 +9,7 @@
<!-- Get a reference to the default local cache. -->
<!-- ===================================================================== -->
<New id="local" class="org.infinispan.manager.DefaultCacheManager">
<Arg><Property name="jetty.base" default="."/>/etc/infinispan-embedded.xml</Arg>
<Get id="cache" name="cache"></Get>
</New>

View File

@ -0,0 +1,33 @@
[description]
Enables session data store in a local Infinispan cache
[tags]
session
[provides]
session-store
session-store-infinispan-embedded
[depend]
sessions
[files]
maven://org.infinispan/infinispan-embedded/9.1.0.Final|lib/infinispan/infinispan-embedded-9.1.0.Final.jar
basehome:modules/session-store-infinispan-embedded/infinispan-embedded.xml|etc/infinispan-embedded.xml
[xml]
etc/sessions/infinispan/default.xml
[lib]
lib/jetty-infinispan-${jetty.version}.jar
lib/infinispan/*.jar
[license]
Infinispan is an open source project hosted on Github and released under the Apache 2.0 license.
http://infinispan.org/
http://www.apache.org/licenses/LICENSE-2.0.html
[ini-template]
#jetty.session.gracePeriod.seconds=3600
#jetty.session.savePeriod.seconds=0

View File

@ -6,12 +6,15 @@ session
[provides]
session-store
session-store-infnispan-embedded
[depend]
sessions
[files]
maven://org.infinispan/infinispan-embedded/7.1.1.Final|lib/infinispan/infinispan-embedded-7.1.1.Final.jar
basehome:modules/session-store-infinispan-embedded/infinispan-embedded.xml|etc/infinispan-embedded.xml
[xml]
etc/sessions/infinispan/default.xml

View File

@ -0,0 +1,5 @@
<infinispan>
<cache-container default-cache="jetty-sessions">
<local-cache name="jetty-sessions"/>
</cache-container>
</infinispan>

View File

@ -0,0 +1,35 @@
[description]
Enables session data store in a remote Infinispan cache
[tags]
session
[provides]
session-store
session-store-infinispan-remote
[depend]
sessions
[files]
maven://org.infinispan/infinispan-remote/9.1.0.Final|lib/infinispan/infinispan-remote-9.1.0.Final.jar
basehome:modules/session-store-infinispan-remote/
[xml]
etc/sessions/infinispan/remote.xml
[lib]
lib/jetty-infinispan-${jetty.version}.jar
lib/infinispan/*.jar
[license]
Infinispan is an open source project hosted on Github and released under the Apache 2.0 license.
http://infinispan.org/
http://www.apache.org/licenses/LICENSE-2.0.html
[ini-template]
#jetty.session.infinispan.remoteCacheName=sessions
#jetty.session.infinispan.idleTimeout.seconds=0
#jetty.session.gracePeriod.seconds=3600
#jetty.session.savePeriod.seconds=0

View File

@ -79,6 +79,11 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
setStopTimeout(5000);
}
public Selector getSelector()
{
return _selector;
}
@Override
protected void doStart() throws Exception
{
@ -140,6 +145,116 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
selector.wakeup();
}
private Runnable processConnect(SelectionKey key, final Connect connect)
{
SelectableChannel channel = key.channel();
try
{
key.attach(connect.attachment);
boolean connected = _selectorManager.doFinishConnect(channel);
if (LOG.isDebugEnabled())
LOG.debug("Connected {} {}", connected, channel);
if (connected)
{
if (connect.timeout.cancel())
{
key.interestOps(0);
return new CreateEndPoint(channel, key)
{
@Override
protected void failed(Throwable failure)
{
super.failed(failure);
connect.failed(failure);
}
};
}
else
{
throw new SocketTimeoutException("Concurrent Connect Timeout");
}
}
else
{
throw new ConnectException();
}
}
catch (Throwable x)
{
connect.failed(x);
return null;
}
}
private void closeNoExceptions(Closeable closeable)
{
try
{
if (closeable != null)
closeable.close();
}
catch (Throwable x)
{
LOG.ignore(x);
}
}
private EndPoint createEndPoint(SelectableChannel channel, SelectionKey selectionKey) throws IOException
{
EndPoint endPoint = _selectorManager.newEndPoint(channel, this, selectionKey);
endPoint.onOpen();
_selectorManager.endPointOpened(endPoint);
Connection connection = _selectorManager.newConnection(channel, endPoint, selectionKey.attachment());
endPoint.setConnection(connection);
selectionKey.attach(endPoint);
_selectorManager.connectionOpened(connection);
if (LOG.isDebugEnabled())
LOG.debug("Created {}", endPoint);
return endPoint;
}
public void destroyEndPoint(final EndPoint endPoint)
{
submit(new DestroyEndPoint(endPoint));
}
@Override
public String dump()
{
super.dump();
return ContainerLifeCycle.dump(this);
}
@Override
public void dump(Appendable out, String indent) throws IOException
{
Selector selector = _selector;
if (selector == null || !selector.isOpen())
dumpBeans(out, indent);
else
{
final ArrayList<Object> dump = new ArrayList<>(selector.keys().size() * 2);
DumpKeys dumpKeys = new DumpKeys(dump);
submit(dumpKeys);
dumpKeys.await(5, TimeUnit.SECONDS);
if (dump.isEmpty())
dumpBeans(out, indent);
else
dumpBeans(out, indent, dump);
}
}
@Override
public String toString()
{
Selector selector = _selector;
return String.format("%s id=%s keys=%d selected=%d",
super.toString(),
_id,
selector != null && selector.isOpen() ? selector.keys().size() : -1,
selector != null && selector.isOpen() ? selector.selectedKeys().size() : -1);
}
/**
* A {@link Selectable} is an {@link EndPoint} that wish to be
* notified of non-blocking events by the {@link ManagedSelector}.
@ -161,7 +276,6 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
void updateKey();
}
private class SelectorProducer implements ExecutionStrategy.Producer
{
private Set<SelectionKey> _keys = Collections.emptySet();
@ -331,7 +445,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
return String.format("%s@%x", getClass().getSimpleName(), hashCode());
}
}
private abstract static class NonBlockingAction implements Runnable, Invocable
{
@Override
@ -341,124 +455,6 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
}
}
private Runnable processConnect(SelectionKey key, final Connect connect)
{
SelectableChannel channel = key.channel();
try
{
key.attach(connect.attachment);
boolean connected = _selectorManager.doFinishConnect(channel);
if (LOG.isDebugEnabled())
LOG.debug("Connected {} {}", connected, channel);
if (connected)
{
if (connect.timeout.cancel())
{
key.interestOps(0);
return new CreateEndPoint(channel, key)
{
@Override
protected void failed(Throwable failure)
{
super.failed(failure);
connect.failed(failure);
}
};
}
else
{
throw new SocketTimeoutException("Concurrent Connect Timeout");
}
}
else
{
throw new ConnectException();
}
}
catch (Throwable x)
{
connect.failed(x);
return null;
}
}
private void closeNoExceptions(Closeable closeable)
{
try
{
if (closeable != null)
closeable.close();
}
catch (Throwable x)
{
LOG.ignore(x);
}
}
private EndPoint createEndPoint(SelectableChannel channel, SelectionKey selectionKey) throws IOException
{
EndPoint endPoint = _selectorManager.newEndPoint(channel, this, selectionKey);
endPoint.onOpen();
_selectorManager.endPointOpened(endPoint);
Connection connection = _selectorManager.newConnection(channel, endPoint, selectionKey.attachment());
endPoint.setConnection(connection);
selectionKey.attach(endPoint);
_selectorManager.connectionOpened(connection);
if (LOG.isDebugEnabled())
LOG.debug("Created {}", endPoint);
return endPoint;
}
public void destroyEndPoint(final EndPoint endPoint)
{
final Connection connection = endPoint.getConnection();
submit(() ->
{
if (LOG.isDebugEnabled())
LOG.debug("Destroyed {}", endPoint);
if (connection != null)
_selectorManager.connectionClosed(connection);
_selectorManager.endPointClosed(endPoint);
});
}
@Override
public String dump()
{
super.dump();
return ContainerLifeCycle.dump(this);
}
@Override
public void dump(Appendable out, String indent) throws IOException
{
Selector selector = _selector;
if (selector == null || !selector.isOpen())
dumpBeans(out, indent);
else
{
final ArrayList<Object> dump = new ArrayList<>(selector.keys().size() * 2);
DumpKeys dumpKeys = new DumpKeys(dump);
submit(dumpKeys);
dumpKeys.await(5, TimeUnit.SECONDS);
if (dump.isEmpty())
dumpBeans(out, indent);
else
dumpBeans(out, indent, dump);
}
}
@Override
public String toString()
{
Selector selector = _selector;
return String.format("%s id=%s keys=%d selected=%d",
super.toString(),
_id,
selector != null && selector.isOpen() ? selector.keys().size() : -1,
selector != null && selector.isOpen() ? selector.selectedKeys().size() : -1);
}
private class DumpKeys implements Runnable
{
private final CountDownLatch latch = new CountDownLatch(1);
@ -523,8 +519,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
if (_key==null)
{
_key = _channel.register(_selector, SelectionKey.OP_ACCEPT, this);
}
}
if (LOG.isDebugEnabled())
LOG.debug("{} acceptor={}", this, _key);
@ -609,7 +604,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
}
}
private class CreateEndPoint implements Runnable, Closeable
private class CreateEndPoint extends NonBlockingAction implements Closeable
{
private final SelectableChannel channel;
private final SelectionKey key;
@ -800,8 +795,24 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
}
}
public Selector getSelector()
private class DestroyEndPoint extends NonBlockingAction
{
return _selector;
private final EndPoint endPoint;
public DestroyEndPoint(EndPoint endPoint)
{
this.endPoint = endPoint;
}
@Override
public void run()
{
if (LOG.isDebugEnabled())
LOG.debug("Destroyed {}", endPoint);
Connection connection = endPoint.getConnection();
if (connection != null)
_selectorManager.connectionClosed(connection);
_selectorManager.endPointClosed(endPoint);
}
}
}

View File

@ -45,7 +45,7 @@ public abstract class NegotiatingClientConnection extends AbstractConnection
this.context = context;
}
protected SSLEngine getSSLEngine()
public SSLEngine getSSLEngine()
{
return engine;
}
@ -80,13 +80,17 @@ public abstract class NegotiatingClientConnection extends AbstractConnection
while (true)
{
int filled = fill();
if (filled == 0 && !completed)
fillInterested();
if (filled <= 0 || completed)
if (completed || filled < 0)
{
replaceConnection();
break;
}
if (filled == 0)
{
fillInterested();
break;
}
}
if (completed)
replaceConnection();
}
private int fill()

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

@ -178,11 +178,11 @@ public class LdapLoginModule extends AbstractLoginModule
private DirContext _rootContext;
public class LDAPUserInfo extends UserInfo
{
Attributes attributes;
Attributes attributes;
/**
* @param userName
* @param credential
@ -198,10 +198,10 @@ public class LdapLoginModule extends AbstractLoginModule
{
return getUserRoles(_rootContext, getUserName(), attributes);
}
}
/**
* get the available information about the user
* <p>
@ -216,7 +216,7 @@ public class LdapLoginModule extends AbstractLoginModule
*/
public UserInfo getUserInfo(String username) throws Exception
{
Attributes attributes = getUserAttributes(username);
Attributes attributes = getUserAttributes(username);
String pwdCredential = getUserCredentials(attributes);
if (pwdCredential == null)
@ -271,30 +271,32 @@ public class LdapLoginModule extends AbstractLoginModule
*/
private Attributes getUserAttributes(String username) throws LoginException
{
Attributes attributes = null;
Attributes attributes = null;
SearchResult result;
try {
result = findUser(username);
attributes = result.getAttributes();
}
catch (NamingException e) {
SearchResult result;
try
{
result = findUser(username);
attributes = result.getAttributes();
}
catch (NamingException e)
{
throw new LoginException("Root context binding failure.");
}
return attributes;
}
}
return attributes;
}
private String getUserCredentials(Attributes attributes) throws LoginException
{
String ldapCredential = null;
String ldapCredential = null;
Attribute attribute = attributes.get(_userPasswordAttribute);
if (attribute != null)
{
try
{
byte[] value = (byte[]) attribute.get();
byte[] value = (byte[])attribute.get();
ldapCredential = new String(value);
}
@ -323,16 +325,16 @@ public class LdapLoginModule extends AbstractLoginModule
{
String rdnValue = username;
Attribute attribute = attributes.get(_userRdnAttribute);
if (attribute != null)
{
try
{
rdnValue = (String) attribute.get(); // switch to the value stored in the _userRdnAttribute if we can
}
catch (NamingException e)
{
}
}
if (attribute != null)
{
try
{
rdnValue = (String)attribute.get(); // switch to the value stored in the _userRdnAttribute if we can
}
catch (NamingException e)
{
}
}
String userDn = _userRdnAttribute + "=" + rdnValue + "," + _userBaseDn;
@ -361,7 +363,7 @@ public class LdapLoginModule extends AbstractLoginModule
while (results.hasMoreElements())
{
SearchResult result = (SearchResult) results.nextElement();
SearchResult result = (SearchResult)results.nextElement();
Attributes attributes = result.getAttributes();
@ -410,8 +412,8 @@ public class LdapLoginModule extends AbstractLoginModule
Callback[] callbacks = configureCallbacks();
getCallbackHandler().handle(callbacks);
String webUserName = ((NameCallback) callbacks[0]).getName();
Object webCredential = ((ObjectCallback) callbacks[1]).getObject();
String webUserName = ((NameCallback)callbacks[0]).getName();
Object webCredential = ((ObjectCallback)callbacks[1]).getObject();
if (webUserName == null || webCredential == null)
{
@ -424,8 +426,7 @@ public class LdapLoginModule extends AbstractLoginModule
if (_forceBindingLogin)
{
authed = bindingLogin(webUserName, webCredential);
}
else
} else
{
// This sets read and the credential
UserInfo userInfo = getUserInfo(webUserName);
@ -439,7 +440,7 @@ public class LdapLoginModule extends AbstractLoginModule
setCurrentUser(new JAASUserInfo(userInfo));
if (webCredential instanceof String)
authed = credentialLogin(Credential.getCredential((String) webCredential));
authed = credentialLogin(Credential.getCredential((String)webCredential));
else
authed = credentialLogin(webCredential);
}
@ -494,7 +495,7 @@ public class LdapLoginModule extends AbstractLoginModule
* @param username the user name
* @param password the password
* @return true always
* @throws LoginException if unable to bind the login
* @throws LoginException if unable to bind the login
* @throws NamingException if failure to bind login
*/
public boolean bindingLogin(String username, Object password) throws LoginException, NamingException
@ -505,15 +506,15 @@ public class LdapLoginModule extends AbstractLoginModule
LOG.info("Attempting authentication: " + userDn);
Hashtable<Object,Object> environment = getEnvironment();
Hashtable<Object, Object> environment = getEnvironment();
if ( userDn == null || "".equals(userDn) )
if (userDn == null || "".equals(userDn))
{
throw new NamingException("username may not be empty");
}
environment.put(Context.SECURITY_PRINCIPAL, userDn);
// RFC 4513 section 6.3.1, protect against ldap server implementations that allow successful binding on empty passwords
if ( password == null || "".equals(password))
if (password == null || "".equals(password))
{
throw new NamingException("password may not be empty");
}
@ -542,9 +543,9 @@ public class LdapLoginModule extends AbstractLoginModule
LOG.debug("Searching for user " + username + " with filter: \'" + filter + "\'" + " from base dn: " + _userBaseDn);
Object[] filterArguments = new Object[]{
_userObjectClass,
_userIdAttribute,
username
_userObjectClass,
_userIdAttribute,
username
};
NamingEnumeration<SearchResult> results = _rootContext.search(_userBaseDn, filter, filterArguments, ctls);
@ -556,7 +557,7 @@ public class LdapLoginModule extends AbstractLoginModule
throw new LoginException("User not found.");
}
return (SearchResult) results.nextElement();
return (SearchResult)results.nextElement();
}
@ -565,37 +566,37 @@ public class LdapLoginModule extends AbstractLoginModule
* <p>
* Called once by JAAS after new instance is created.
*
* @param subject the subect
* @param subject the subect
* @param callbackHandler the callback handler
* @param sharedState the shared state map
* @param options the option map
* @param sharedState the shared state map
* @param options the option map
*/
public void initialize(Subject subject,
CallbackHandler callbackHandler,
Map<String,?> sharedState,
Map<String,?> options)
Map<String, ?> sharedState,
Map<String, ?> options)
{
super.initialize(subject, callbackHandler, sharedState, options);
_hostname = (String) options.get("hostname");
_port = Integer.parseInt((String) options.get("port"));
_contextFactory = (String) options.get("contextFactory");
_bindDn = (String) options.get("bindDn");
_bindPassword = (String) options.get("bindPassword");
_authenticationMethod = (String) options.get("authenticationMethod");
_hostname = (String)options.get("hostname");
_port = Integer.parseInt((String)options.get("port"));
_contextFactory = (String)options.get("contextFactory");
_bindDn = (String)options.get("bindDn");
_bindPassword = (String)options.get("bindPassword");
_authenticationMethod = (String)options.get("authenticationMethod");
_userBaseDn = (String) options.get("userBaseDn");
_userBaseDn = (String)options.get("userBaseDn");
_roleBaseDn = (String) options.get("roleBaseDn");
_roleBaseDn = (String)options.get("roleBaseDn");
if (options.containsKey("forceBindingLogin"))
{
_forceBindingLogin = Boolean.parseBoolean((String) options.get("forceBindingLogin"));
_forceBindingLogin = Boolean.parseBoolean((String)options.get("forceBindingLogin"));
}
if (options.containsKey("useLdaps"))
{
_useLdaps = Boolean.parseBoolean((String) options.get("useLdaps"));
_useLdaps = Boolean.parseBoolean((String)options.get("useLdaps"));
}
_userObjectClass = getOption(options, "userObjectClass", _userObjectClass);
@ -625,7 +626,7 @@ public class LdapLoginModule extends AbstractLoginModule
}
catch (NamingException e)
{
throw new LoginException( "error closing root context: " + e.getMessage() );
throw new LoginException("error closing root context: " + e.getMessage());
}
return super.commit();
@ -639,13 +640,13 @@ public class LdapLoginModule extends AbstractLoginModule
}
catch (NamingException e)
{
throw new LoginException( "error closing root context: " + e.getMessage() );
throw new LoginException("error closing root context: " + e.getMessage());
}
return super.abort();
}
private String getOption(Map<String,?> options, String key, String defaultValue)
private String getOption(Map<String, ?> options, String key, String defaultValue)
{
Object value = options.get(key);
@ -654,7 +655,7 @@ public class LdapLoginModule extends AbstractLoginModule
return defaultValue;
}
return (String) value;
return (String)value;
}
/**
@ -670,7 +671,7 @@ public class LdapLoginModule extends AbstractLoginModule
if (_hostname != null)
{
env.put(Context.PROVIDER_URL, (_useLdaps?"ldaps://":"ldap://") + _hostname + (_port==0?"":":"+_port) +"/");
env.put(Context.PROVIDER_URL, (_useLdaps ? "ldaps://" : "ldap://") + _hostname + (_port == 0 ? "" : ":" + _port) + "/");
}
if (_authenticationMethod != null)

Some files were not shown because too many files have changed in this diff Show More