Merged branch 'jetty-9.4.x' into 'jetty-9.4.x-4628-start-module-non-required'.

This commit is contained in:
Simone Bordet 2020-03-19 11:06:09 +01:00
commit fda99cfd1e
120 changed files with 1174 additions and 985 deletions

View File

@ -171,7 +171,7 @@
<profile>
<id>jdk9</id>
<activation>
<jdk>[1.9,)</jdk>
<jdk>[9,)</jdk>
</activation>
<dependencies>
<dependency>

View File

@ -20,8 +20,8 @@
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.9</source>
<target>1.9</target>
<source>9</source>
<target>9</target>
<release>9</release>
</configuration>
</plugin>

View File

@ -19,8 +19,8 @@
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.9</source>
<target>1.9</target>
<source>9</source>
<target>9</target>
<release>9</release>
</configuration>
</plugin>
@ -46,11 +46,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>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-server</artifactId>

View File

@ -25,6 +25,7 @@
<groupId>org.eclipse.jetty.alpn</groupId>
<artifactId>alpn-api</artifactId>
<version>${alpn.api.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>

View File

@ -18,13 +18,20 @@
package org.eclipse.jetty.alpn.openjdk8.client;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
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;
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;
@ -33,11 +40,31 @@ public class OpenJDK8ClientALPNProcessor implements ALPNProcessor.Client
{
private static final Logger LOG = Log.getLogger(OpenJDK8ClientALPNProcessor.class);
private Method alpnProtocols;
private Method alpnProtocol;
@Override
public void init()
{
if (JavaVersion.VERSION.getPlatform() != 8)
throw new IllegalStateException(this + " not applicable for java " + JavaVersion.VERSION);
try
{
// JDK 8u252 has the JDK 9 ALPN API backported.
// Use reflection so we can build with a JDK version less than 8u252.
alpnProtocols = SSLParameters.class.getMethod("setApplicationProtocols", String[].class);
alpnProtocol = SSLEngine.class.getMethod("getApplicationProtocol");
if (LOG.isDebugEnabled())
LOG.debug("Using OpenJDK ALPN APIs instead of Jetty ALPN APIs");
return;
}
catch (NoSuchMethodException x)
{
LOG.ignore(x);
}
// Backported ALPN APIs not available.
if (ALPN.class.getClassLoader() != null)
throw new IllegalStateException(ALPN.class.getName() + " must be on JVM boot classpath");
if (LOG.isDebugEnabled())
@ -53,14 +80,34 @@ public class OpenJDK8ClientALPNProcessor implements ALPNProcessor.Client
@Override
public void configure(SSLEngine sslEngine, Connection connection)
{
connection.addListener(new ALPNListener((ALPNClientConnection)connection));
ALPNClientConnection alpnConnection = (ALPNClientConnection)connection;
if (alpnProtocols == null)
{
connection.addListener(new ALPNConnectionListener(alpnConnection));
}
else
{
try
{
Object protocols = alpnConnection.getProtocols().toArray(new String[0]);
SSLParameters sslParameters = sslEngine.getSSLParameters();
alpnProtocols.invoke(sslParameters, protocols);
sslEngine.setSSLParameters(sslParameters);
((SslConnection.DecryptedEndPoint)connection.getEndPoint()).getSslConnection()
.addHandshakeListener(new ALPNSSLListener(alpnConnection));
}
catch (IllegalAccessException | InvocationTargetException x)
{
throw new IllegalStateException(this + " unable to set ALPN protocols", x);
}
}
}
private final class ALPNListener implements ALPN.ClientProvider, Connection.Listener
private static final class ALPNConnectionListener implements ALPN.ClientProvider, Connection.Listener
{
private final ALPNClientConnection alpnConnection;
private ALPNListener(ALPNClientConnection connection)
private ALPNConnectionListener(ALPNClientConnection connection)
{
alpnConnection = connection;
}
@ -102,4 +149,32 @@ public class OpenJDK8ClientALPNProcessor implements ALPNProcessor.Client
alpnConnection.selected(protocol);
}
}
private final class ALPNSSLListener implements SslHandshakeListener
{
private final ALPNClientConnection alpnConnection;
private ALPNSSLListener(ALPNClientConnection connection)
{
alpnConnection = connection;
}
@Override
public void handshakeSucceeded(Event event) throws SSLException
{
try
{
SSLEngine sslEngine = alpnConnection.getSSLEngine();
String protocol = (String)alpnProtocol.invoke(sslEngine);
if (LOG.isDebugEnabled())
LOG.debug("selected protocol {}", protocol);
alpnConnection.selected(protocol);
}
catch (IllegalAccessException | InvocationTargetException x)
{
SSLHandshakeException failure = new SSLHandshakeException(this + " unable to get ALPN protocol");
throw (SSLHandshakeException)failure.initCause(x);
}
}
}
}

View File

@ -18,15 +18,19 @@
package org.eclipse.jetty.alpn.openjdk8.server;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
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;
@ -35,11 +39,29 @@ public class OpenJDK8ServerALPNProcessor implements ALPNProcessor.Server
{
private static final Logger LOG = Log.getLogger(OpenJDK8ServerALPNProcessor.class);
private Method alpnSelector;
@Override
public void init()
{
if (JavaVersion.VERSION.getPlatform() != 8)
throw new IllegalStateException(this + " not applicable for java " + JavaVersion.VERSION);
try
{
// JDK 8u252 has the JDK 9 ALPN API backported.
// Use reflection so we can build with a JDK version less than 8u252.
alpnSelector = SSLEngine.class.getMethod("setHandshakeApplicationProtocolSelector", BiFunction.class);
if (LOG.isDebugEnabled())
LOG.debug("Using OpenJDK ALPN APIs instead of Jetty ALPN APIs");
return;
}
catch (NoSuchMethodException x)
{
LOG.ignore(x);
}
// Backported ALPN APIs not available.
if (ALPN.class.getClassLoader() != null)
throw new IllegalStateException(ALPN.class.getName() + " must be on JVM boot classpath");
if (LOG.isDebugEnabled())
@ -55,10 +77,26 @@ public class OpenJDK8ServerALPNProcessor implements ALPNProcessor.Server
@Override
public void configure(SSLEngine sslEngine, Connection connection)
{
connection.addListener(new ALPNListener((ALPNServerConnection)connection));
if (alpnSelector == null)
{
ALPNListener listener = new ALPNListener((ALPNServerConnection)connection);
connection.addListener(listener);
}
else
{
try
{
ALPNCallback callback = new ALPNCallback((ALPNServerConnection)connection);
alpnSelector.invoke(sslEngine, callback);
}
catch (IllegalAccessException | InvocationTargetException x)
{
throw new IllegalStateException(this + " unable to set ALPN selector", x);
}
}
}
private final class ALPNListener implements ALPN.ServerProvider, Connection.Listener
private static final class ALPNListener implements ALPN.ServerProvider, Connection.Listener
{
private final ALPNServerConnection alpnConnection;
@ -92,7 +130,7 @@ public class OpenJDK8ServerALPNProcessor implements ALPNProcessor.Server
}
@Override
public String select(List<String> protocols) throws SSLException
public String select(List<String> protocols)
{
if (LOG.isDebugEnabled())
LOG.debug("select {} {}", alpnConnection, protocols);
@ -100,4 +138,50 @@ public class OpenJDK8ServerALPNProcessor implements ALPNProcessor.Server
return alpnConnection.getProtocol();
}
}
private static 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)
{
try
{
if (LOG.isDebugEnabled())
LOG.debug("apply {} {}", alpnConnection, protocols);
alpnConnection.select(protocols);
return alpnConnection.getProtocol();
}
catch (Throwable x)
{
// Cannot negotiate the protocol, return null to have
// JSSE send Alert.NO_APPLICATION_PROTOCOL to the client.
return null;
}
}
@Override
public void handshakeSucceeded(Event event)
{
String protocol = alpnConnection.getProtocol();
if (LOG.isDebugEnabled())
LOG.debug("TLS handshake succeeded, protocol={} for {}", protocol, alpnConnection);
if (protocol == null)
alpnConnection.unsupported();
}
@Override
public void handshakeFailed(Event event, Throwable failure)
{
if (LOG.isDebugEnabled())
LOG.debug("TLS handshake failed " + alpnConnection, failure);
}
}
}

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.0.v20141016|lib/alpn/alpn-boot-8.1.0.v20141016.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.0.v20141016|lib/alpn/alpn-boot-8.1.0.v20141016.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.9.v20160720|lib/alpn/alpn-boot-8.1.9.v20160720.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.9.v20160720.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.9.v20160720|lib/alpn/alpn-boot-8.1.9.v20160720.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.9.v20160720.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.0.v20141016|lib/alpn/alpn-boot-8.1.0.v20141016.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.9.v20160720|lib/alpn/alpn-boot-8.1.9.v20160720.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.9.v20160720.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.10.v20161026|lib/alpn/alpn-boot-8.1.10.v20161026.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.10.v20161026.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.11.v20170118|lib/alpn/alpn-boot-8.1.11.v20170118.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.11.v20170118|lib/alpn/alpn-boot-8.1.11.v20170118.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.11.v20170118|lib/alpn/alpn-boot-8.1.11.v20170118.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.11.v20170118|lib/alpn/alpn-boot-8.1.11.v20170118.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.11.v20170118|lib/alpn/alpn-boot-8.1.11.v20170118.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.11.v20170118|lib/alpn/alpn-boot-8.1.11.v20170118.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.12.v20180117|lib/alpn/alpn-boot-8.1.12.v20180117.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.12.v20180117.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.12.v20180117|lib/alpn/alpn-boot-8.1.12.v20180117.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.12.v20180117.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.12.v20180117|lib/alpn/alpn-boot-8.1.12.v20180117.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.12.v20180117.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.12.v20180117|lib/alpn/alpn-boot-8.1.12.v20180117.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.12.v20180117.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.12.v20180117|lib/alpn/alpn-boot-8.1.12.v20180117.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.12.v20180117.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.0.v20141016|lib/alpn/alpn-boot-8.1.0.v20141016.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.0.v20141016.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.2.v20141202|lib/alpn/alpn-boot-8.1.2.v20141202.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.2.v20141202.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.3.v20150130|lib/alpn/alpn-boot-8.1.3.v20150130.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.3.v20150130.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.3.v20150130|lib/alpn/alpn-boot-8.1.3.v20150130.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.3.v20150130.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.3.v20150130|lib/alpn/alpn-boot-8.1.3.v20150130.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.3.v20150130.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.4.v20150727|lib/alpn/alpn-boot-8.1.4.v20150727.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.4.v20150727.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.5.v20150921|lib/alpn/alpn-boot-8.1.5.v20150921.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.5.v20150921.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.6.v20151105|lib/alpn/alpn-boot-8.1.6.v20151105.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.6.v20151105.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.6.v20151105|lib/alpn/alpn-boot-8.1.6.v20151105.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.6.v20151105.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.7.v20160121|lib/alpn/alpn-boot-8.1.7.v20160121.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.7.v20160121.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.7.v20160121|lib/alpn/alpn-boot-8.1.7.v20160121.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.7.v20160121.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.7.v20160121|lib/alpn/alpn-boot-8.1.7.v20160121.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.7.v20160121.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.7.v20160121|lib/alpn/alpn-boot-8.1.7.v20160121.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.7.v20160121.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.7.v20160121|lib/alpn/alpn-boot-8.1.7.v20160121.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.7.v20160121.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.7.v20160121|lib/alpn/alpn-boot-8.1.7.v20160121.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.7.v20160121.jar

View File

@ -1,7 +0,0 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.8.v20160420|lib/alpn/alpn-boot-8.1.8.v20160420.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.8.v20160420.jar

View File

@ -0,0 +1,4 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[depend]
alpn-impl/alpn-11

View File

@ -1,33 +1,22 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[description]
Provides ALPN support for JDK 8, modifying the sun.security.ssl
classes and adding them to the JVM boot classpath.
This modification has a tight dependency on specific recent updates of
Java 1.7 and Java 1.8 (Java versions prior to 1.7u40 are not supported).
This module will use an appropriate alpn-boot jar for your
specific version of Java.
# IMPORTANT: Versions of Java that exist after this module was created are
# not guaranteed to work with existing alpn-boot jars, and might
# need a new alpn-boot to be created / tested / deployed by the
# Jetty project in order to provide support for these future
# Java versions.
#
# All versions of the alpn-boot jar can be found at
# https://repo1.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/
[depend]
alpn-impl/alpn-${java.version}
[lib]
lib/jetty-alpn-openjdk8-server-${jetty.version}.jar
Provides ALPN support for JDK 8, using the Jetty ALPN Agent.
[files]
lib/
lib/alpn/
maven://org.mortbay.jetty.alpn/jetty-alpn-agent/2.0.10|lib/alpn/jetty-alpn-agent-2.0.10.jar
[lib]
lib/jetty-alpn-openjdk8-server-${jetty.version}.jar
[license]
ALPN is a hosted at github under the GPL v2 with ClassPath Exception.
ALPN replaces/modifies OpenJDK classes in the sun.security.ssl package.
The ALPN implementation for Java 8u242 and earlier replaces/modifies OpenJDK classes
in the sun.security.ssl package.
These modified classes are hosted at GitHub under the GPL v2 with ClassPath Exception.
http://github.com/jetty-project/jetty-alpn
http://openjdk.java.net/legal/gplv2+ce.html
[exec]
-javaagent:lib/alpn/jetty-alpn-agent-2.0.10.jar

View File

@ -21,7 +21,7 @@
<profile>
<id>jdk9</id>
<activation>
<jdk>[1.9,)</jdk>
<jdk>[9,)</jdk>
</activation>
<modules>
<module>jetty-alpn-java-client</module>

View File

@ -33,20 +33,21 @@ When using Jetty as a standalone server via the Jetty distribution, the `jetty-a
When using Jetty embedded, the `jetty-alpn-client` and `jetty-alpn-server` artifacts must be included in the classpath, respectively for client and server use cases.
The ALPN implementation is _provided_ to these two artifacts with the following three options:
The ALPN implementation is _provided_ to these two artifacts with the following options:
* For JDK 8 only, a provider based on modified OpenJDK classes
** Only works with JDK 8, pure Java implementation
** Requires the `-Xbootclasspath/p` option on command line
* For JDK 8 or later, a provider based on the link:#conscrypt[Conscrypt security provider]
* For Java 8 only, a provider based on a pure Java implementation (no native code)
** For Java 8 up to `1.8.0_242` included, this provider uses modified OpenJDK classes
and requires the `-Xbootclasspath/p:` option on command line
** For Java 8 from `1.8.0_252` included and later, this provider uses the standard OpenJDK
ALPN APIs introduced in Java 9 (see below) that have been backported to `1.8.0_252` and
does not require the `-Xbootclasspath/p:` option on command line
* For Java 8 or later, a provider based on the link:#conscrypt[Conscrypt security provider]
** Works with JDK 8 or later and provides improved performance
** Binds to the OpenSSL native library shipped by Conscrypt and is therefore only available on the platforms supported by Conscrypt
* For JDK 9 or later, a provider based on the ALPN APIs present in the JDK
** Works with JDK 9 or later, pure Java implementation
* For Java 9 or later, a provider based on the standard OpenJDK ALPN APIs
** Works with JDK 9 or later, pure Java implementation (no native code)
** Lower performance than Conscrypt
The first, although hosted under the umbrella of the Jetty project, is independent of Jetty (the Servlet Container); you can use it in any other Java network server.
Each provider above provides an ALPN _service_ implementation; Jetty uses the `ServiceLoader` mechanism to load these service implementations.
At least one valid provider must be present in the server classpath.
For example, using JDK 8 with the JDK 9 ALPN provider is an _invalid_ combination.
@ -60,7 +61,18 @@ It is therefore possible to have multiple providers active at the same time, for
[[alpn-openjdk8]]
==== ALPN and OpenJDK 8
When using JDKs based on OpenJDK 8 (for JDK 9 see link:#alpn-jdk9[above]), and you do not or cannot use link:#conscrypt[Conscrypt], you can use Jetty's ALPN boot library to provide the ALPN service implementation, via the `alpn-boot` artifact.
When using JDKs based on OpenJDK 8 (for JDK 9 see link:#alpn-jdk9[here]), and you do not or
cannot use link:#conscrypt[Conscrypt], the ALPN implementation is provided by the
`jetty-alpn-openjdk8-client` or `jetty-alpn-openjdk8-server` artifacts.
For Java 8 versions up to `1.8.0_242` included, you also need the Jetty's ALPN boot library
to provide the ALPN service implementation, via the `alpn-boot` artifact.
For Java 8 versions from `1.8.0_252` included and later, Jetty's ALPN boot library is not
necessary because the OpenJDK ALPN APIs have been backported to `1.8.0_252` and the
`jetty-alpn-openjdk8-*` artifacts can use these backported APIs if their presence is detected.
Alternatively, you can use the link:#alpn-openjdk8-agent[Jetty ALPN agent], that in turn uses
theJetty ALPN boot library to transform the relevant OpenJDK classes when they are loaded.
The Jetty ALPN boot library modifies the relevant OpenJDK classes to add ALPN support and provides an ALPN API that application can use to enable ALPN.
@ -69,13 +81,14 @@ This enables transitively the `alpn-8` module which puts the `jetty-alpn-openjdk
When using Jetty embedded, the ALPN support is provided by the `jetty-alpn-openjdk8-client` and `jetty-alpn-openjdk8-server` artifacts, respectively for client usage and server usage.
To get ALPN working with the Jetty ALPN Boot library, you need:
To get ALPN working with Java 8, you must have the `jetty-alpn-openjdk8-client` artifact or
the `jetty-alpn-openjdk8-server` artifact in the classpath.
* to start the JVM with the Jetty ALPN Boot library in the boot classpath
* to have the `jetty-alpn-openjdk8-client` artifact or the `jetty-alpn-openjdk8-server`
artifact in the classpath
Additionally, if you are using OpenJDK `1.8.0_242` or earlier, you need the Jetty ALPN boot
library (corresponding to the exact OpenJDK version you are using) in the boot classpath,
or alternatively you need the link:#alpn-openjdk8-agent[Jetty ALPN agent].
Start the JVM as follows:
In the case of the Jetty ALPN boot library, start the JVM as follows:
[source, plain, subs="{sub-order}"]
----
@ -84,7 +97,45 @@ java -Xbootclasspath/p:<path_to_alpn_boot_jar> ...
Where `path_to_alpn_boot_jar` is the path on the file system for the `alpn-boot` artifact, such as the one at the Maven coordinates `org.mortbay.jetty.alpn:alpn-boot`.
Be certain to get the link:#alpn-versions[ALPN boot artifact version that matches the version of your JRE].
____
[IMPORTANT]
Be certain to get the
link:#alpn-versions[ALPN boot artifact version that matches the version of your JRE].
____
[[alpn-openjdk8-agent]]
==== ALPN agent and OpenJDK 8
The Jetty Project also maintains the
https://github.com/jetty-project/jetty-alpn-agent[Jetty ALPN agent], which is a JVM
agent that provides the ALPN implementation.
The Jetty ALPN agent can be use in alternative (never together) with the
link:#alpn-openjdk8[ALPN boot library].
The Jetty ALPN agent contains the ALPN boot libraries for every JDK 8 version.
The agent can be used only with Java 8, but works with _any_ Java 8 version.
The Jetty ALPN agent detects the JDK version currently running, picks the correspondent
ALPN boot library (or picks none if the JDK version is `1.8.0_252` or later), and
transforms, if necessary, the relevant OpenJDK classes to provide the ALPN support.
To use the Jetty ALPN agent, start the JVM as follows:
[source, plain, subs="{sub-order}"]
----
java -javaagent:<path_to_alpn_agent_jar> ...
----
____
[NOTE]
The Jetty ALPN agent works with any Java 8 version. It is _required_ if you use
an OpenJDK version up to `1.8.0_242` included, and it is _optional_ if you use an
OpenJDK version equal or greater than `1.8.0_252`.
The Jetty ALPN agent can be left on the command line even when using an OpenJDK version
equal or greater than `1.8.0_252` but we recommend to remove it from the command line
when you use OpenJDK `1.8.0_252` or later.
____
[[alpn-conscrypt]]
==== ALPN and Conscrypt
@ -359,6 +410,7 @@ The ALPN implementation, relying on modifications of OpenJDK classes, updates ev
|1.8.0u232 |8.1.13.v20181017
|1.8.0u241^[1]^ |8.1.13.v20181017
|1.8.0u242 |8.1.13.v20181017
|1.8.0u252 and later | NOT NECESSARY
|=============================
^[1]^ These are Oracle releases for which the source code is not available,
or it is unclear what exactly is because there is no correspondent tag in

View File

@ -4,7 +4,7 @@
<!-- ===================================================================== -->
<!-- Configure a factory for HazelcastSessionDataStore using -->
<!-- an embedded Hazelcast Instance -->
<!-- an remote Hazelcast Instance -->
<!-- ===================================================================== -->
<Call name="addBean">
<Arg>
@ -15,6 +15,7 @@
<Set name="gracePeriodSec"><Property name="jetty.session.gracePeriod.seconds" default="3600" /></Set>
<Set name="savePeriodSec"><Property name="jetty.session.savePeriod.seconds" default="0" /></Set>
<Set name="onlyClient"><Property name="jetty.session.hazelcast.onlyClient" default="true" /></Set>
<Set name="addresses"><Property name="jetty.session.hazelcast.addresses" default="" /></Set>
</New>
</Arg>
</Call>

View File

@ -13,7 +13,7 @@ session-store
sessions
[files]
maven://com.hazelcast/hazelcast/3.9.4|lib/hazelcast/hazelcast-3.9.4.jar
maven://com.hazelcast/hazelcast/3.12.6|lib/hazelcast/hazelcast-3.12.6.jar
[xml]
etc/sessions/hazelcast/default.xml
@ -31,7 +31,6 @@ http://www.apache.org/licenses/LICENSE-2.0.html
[ini-template]
jetty.session.hazelcast.mapName=jetty-distributed-session-map
jetty.session.hazelcast.hazelcastInstanceName=JETTY_DISTRIBUTED_SESSION_INSTANCE
#jetty.session.hazelcast.configurationLocation=
jetty.session.hazelcast.scavengeZombies=false
jetty.session.gracePeriod.seconds=3600
jetty.session.savePeriod.seconds=0

View File

@ -13,8 +13,8 @@ session-store
sessions
[files]
maven://com.hazelcast/hazelcast/3.9.4|lib/hazelcast/hazelcast-3.9.4.jar
maven://com.hazelcast/hazelcast-client/3.9.4|lib/hazelcast/hazelcast-client-3.9.4.jar
maven://com.hazelcast/hazelcast/3.12.6|lib/hazelcast/hazelcast-3.12.6.jar
maven://com.hazelcast/hazelcast-client/3.12.6|lib/hazelcast/hazelcast-client-3.12.6.jar
[xml]
etc/sessions/hazelcast/remote.xml
@ -34,6 +34,6 @@ jetty.session.hazelcast.mapName=jetty-distributed-session-map
jetty.session.hazelcast.hazelcastInstanceName=JETTY_DISTRIBUTED_SESSION_INSTANCE
jetty.session.hazelcast.onlyClient=true
jetty.session.hazelcast.scavengeZombies=false
#jetty.session.hazelcast.configurationLocation=
jetty.session.gracePeriod.seconds=3600
jetty.session.savePeriod.seconds=0
#jetty.session.hazelcast.addresses=

View File

@ -19,6 +19,7 @@
package org.eclipse.jetty.hazelcast.session;
import java.io.IOException;
import java.util.Arrays;
import com.hazelcast.client.HazelcastClient;
import com.hazelcast.client.config.ClientConfig;
@ -29,6 +30,7 @@ import com.hazelcast.config.SerializerConfig;
import com.hazelcast.config.XmlConfigBuilder;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import org.eclipse.jetty.server.session.AbstractSessionDataStoreFactory;
import org.eclipse.jetty.server.session.SessionData;
import org.eclipse.jetty.server.session.SessionDataStore;
@ -57,6 +59,8 @@ public class HazelcastSessionDataStoreFactory
private boolean scavengeZombies = false;
private String addresses;
public boolean isScavengeZombies()
{
return scavengeZombies;
@ -81,6 +85,12 @@ public class HazelcastSessionDataStoreFactory
if (configurationLocation == null)
{
ClientConfig config = new ClientConfig();
if (addresses != null && !addresses.isEmpty())
{
config.getNetworkConfig().setAddresses(Arrays.asList(addresses.split(",")));
}
SerializerConfig sc = new SerializerConfig()
.setImplementation(new SessionDataSerializer())
.setTypeClass(SessionData.class);
@ -201,4 +211,14 @@ public class HazelcastSessionDataStoreFactory
{
this.hazelcastInstanceName = hazelcastInstanceName;
}
public String getAddresses()
{
return addresses;
}
public void setAddresses(String addresses)
{
this.addresses = addresses;
}
}

View File

@ -774,7 +774,7 @@
<profile>
<id>jdk9</id>
<activation>
<jdk>[1.9,)</jdk>
<jdk>[9,)</jdk>
</activation>
<dependencies>
<dependency>

View File

@ -78,7 +78,7 @@
<profile>
<id>jdk9</id>
<activation>
<jdk>[1.9,)</jdk>
<jdk>[9,)</jdk>
</activation>
<dependencies>
<dependency>

View File

@ -23,6 +23,8 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicInteger;
@ -33,6 +35,8 @@ import javax.servlet.http.Part;
import org.eclipse.jetty.http.MultiPartFormInputStream.MultiPart;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.IO;
import org.junit.jupiter.api.Test;
@ -885,6 +889,97 @@ public class MultiPartFormInputStreamTest
assertEquals("the end", baos.toString("US-ASCII"));
}
@Test
public void testFragmentation() throws IOException
{
String contentType = "multipart/form-data, boundary=----WebKitFormBoundaryhXfFAMfUnUKhmqT8";
String payload1 =
"------WebKitFormBoundaryhXfFAMfUnUKhmqT8\r\n" +
"Content-Disposition: form-data; name=\"field1\"\r\n\r\n" +
"value1" +
"\r\n--";
String payload2 = "----WebKitFormBoundaryhXfFAMfUnUKhmqT8\r\n" +
"Content-Disposition: form-data; name=\"field2\"\r\n\r\n" +
"value2" +
"\r\n------WebKitFormBoundaryhXfFAMfUnUKhmqT8--\r\n";
// Split the content into separate reads, with the content broken up on the boundary string.
AppendableInputStream stream = new AppendableInputStream();
stream.append(payload1);
stream.append("");
stream.append(payload2);
stream.endOfContent();
MultipartConfigElement config = new MultipartConfigElement(_dirname);
MultiPartFormInputStream mpis = new MultiPartFormInputStream(stream, contentType, config, _tmpDir);
mpis.setDeleteOnExit(true);
// Check size.
Collection<Part> parts = mpis.getParts();
assertThat(parts.size(), is(2));
// Check part content.
assertThat(IO.toString(mpis.getPart("field1").getInputStream()), is("value1"));
assertThat(IO.toString(mpis.getPart("field2").getInputStream()), is("value2"));
}
static class AppendableInputStream extends InputStream
{
private static final ByteBuffer EOF = ByteBuffer.allocate(0);
private final BlockingArrayQueue<ByteBuffer> buffers = new BlockingArrayQueue<>();
private ByteBuffer current;
public void append(String data)
{
append(data.getBytes(StandardCharsets.US_ASCII));
}
public void append(byte[] data)
{
buffers.add(BufferUtil.toBuffer(data));
}
public void endOfContent()
{
buffers.add(EOF);
}
@Override
public int read() throws IOException
{
byte[] buf = new byte[1];
while (true)
{
int len = read(buf, 0, 1);
if (len < 0)
return -1;
if (len > 0)
return buf[0];
}
}
@Override
public int read(byte[] b, int off, int len) throws IOException
{
if (current == null)
current = buffers.poll();
if (current == EOF)
return -1;
if (BufferUtil.isEmpty(current))
{
current = null;
return 0;
}
ByteBuffer buffer = ByteBuffer.wrap(b, off, len);
buffer.flip();
int read = BufferUtil.append(buffer, current);
if (BufferUtil.isEmpty(current))
current = buffers.poll();
return read;
}
}
@Test
public void testQuotedPrintableEncoding() throws Exception
{

View File

@ -20,7 +20,7 @@
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<id>copy-alpn-agent</id>
<phase>generate-resources</phase>
<goals>
<goal>copy</goal>
@ -29,8 +29,8 @@
<artifactItems>
<artifactItem>
<groupId>org.mortbay.jetty.alpn</groupId>
<artifactId>alpn-boot</artifactId>
<version>${alpn.version}</version>
<artifactId>jetty-alpn-agent</artifactId>
<version>${alpn.agent.version}</version>
<type>jar</type>
<overWrite>false</overWrite>
<outputDirectory>${project.build.directory}/alpn</outputDirectory>
@ -43,7 +43,7 @@
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar</argLine>
<argLine>-javaagent:${project.build.directory}/alpn/jetty-alpn-agent-${alpn.agent.version}.jar=debug=true</argLine>
</configuration>
</plugin>
</plugins>
@ -54,12 +54,6 @@
<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-openjdk8-server</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
@ -68,6 +62,18 @@
<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>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-openjdk8-server</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
@ -81,21 +87,4 @@
</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

@ -18,7 +18,7 @@
<profile>
<id>jdk8</id>
<activation>
<jdk>[1.8,1.9)</jdk>
<jdk>[1.8,9)</jdk>
</activation>
<build>
<plugins>
@ -26,7 +26,7 @@
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<id>copy-alpn-agent</id>
<phase>generate-resources</phase>
<goals>
<goal>copy</goal>
@ -35,8 +35,8 @@
<artifactItems>
<artifactItem>
<groupId>org.mortbay.jetty.alpn</groupId>
<artifactId>alpn-boot</artifactId>
<version>${alpn.version}</version>
<artifactId>jetty-alpn-agent</artifactId>
<version>${alpn.agent.version}</version>
<type>jar</type>
<overWrite>false</overWrite>
<outputDirectory>${project.build.directory}/alpn</outputDirectory>
@ -49,16 +49,29 @@
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar</argLine>
<argLine>-javaagent:${project.build.directory}/alpn/jetty-alpn-agent-${alpn.agent.version}.jar=debug=true</argLine>
</configuration>
</plugin>
</plugins>
</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</groupId>
<artifactId>jetty-alpn-openjdk8-client</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>jdk9</id>
<activation>
<jdk>[1.9,)</jdk>
<jdk>[9,)</jdk>
</activation>
<dependencies>
<dependency>

View File

@ -24,9 +24,10 @@
<profile>
<id>jdk8</id>
<activation>
<jdk>[1.8,1.9)</jdk>
<jdk>[1.8,9)</jdk>
</activation>
<modules>
<!-- These tests can only be run in Java 8 -->
<module>http2-alpn-tests</module>
</modules>
</profile>

View File

@ -129,7 +129,7 @@
<profile>
<id>jdk9+</id>
<activation>
<jdk>[1.9,)</jdk>
<jdk>[9,)</jdk>
</activation>
<build>
<pluginManagement>

View File

@ -17,7 +17,6 @@
<exam.version>4.13.1</exam.version>
<url.version>2.6.1</url.version>
<injection.bundle.version>1.0</injection.bundle.version>
<skipTests>true</skipTests>
</properties>
<dependencies>
<!-- Pax Exam Dependencies -->
@ -446,7 +445,6 @@
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>${skipTests}</skipTests>
<systemPropertyVariables>
<mavenRepoPath>${settings.localRepository}</mavenRepoPath>
<settingsFilePath>${env.GLOBAL_MVN_SETTINGS}</settingsFilePath>
@ -541,20 +539,17 @@
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<skipTests>false</skipTests>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- No point defining -javaagent as the actual OSGi VM is run as a forked process by pax-exam -->
<!-- But we do pass the sys property of the jetty-alpn-agent jar so that it can be configured inside tests -->
<argLine>-Dmortbay-alpn-agent=${settings.localRepository}/org/mortbay/jetty/alpn/jetty-alpn-agent/${alpn.agent.version}/jetty-alpn-agent-${alpn.agent.version}.jar -Dconscrypt-version=${conscrypt.version}</argLine>
<excludes>
<exclude>**/TestJettyOSGiBootHTTP2JDK9*</exclude>
</excludes>
<!-- No point defining -Xbootclasspath as the actual OSGi VM is run as a forked process by pax-exam -->
<!-- But we do pass the sys property of the alpn-boot jar so that it can be configured inside tests -->
<argLine>-Dmortbay-alpn-boot=${settings.localRepository}/org/mortbay/jetty/alpn/alpn-boot/${alpn.version}/alpn-boot-${alpn.version}.jar -Dconscrypt-version=${conscrypt.version}</argLine>
</configuration>
</plugin>
</plugins>
@ -591,15 +586,11 @@
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<skipTests>false</skipTests>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>${skipTests}</skipTests>
<excludes>
<exclude>**/TestJettyOSGiBootHTTP2</exclude>
</excludes>

View File

@ -47,7 +47,6 @@ import org.osgi.framework.ServiceReference;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.systemProperty;
@ -93,18 +92,13 @@ public class TestJettyOSGiBootHTTP2
List<Option> res = new ArrayList<>();
res.add(CoreOptions.systemProperty("jetty.alpn.protocols").value("h2,http/1.1"));
String alpnBoot = System.getProperty("mortbay-alpn-boot");
if (alpnBoot == null)
{
throw new IllegalStateException("Define path to alpn boot jar as system property -Dmortbay-alpn-boot");
}
File checkALPNBoot = new File(alpnBoot);
if (!checkALPNBoot.exists())
{
throw new IllegalStateException("Unable to find the alpn boot jar here: " + alpnBoot);
}
res.add(CoreOptions.vmOptions("-Xbootclasspath/p:" + checkALPNBoot.getAbsolutePath()));
String alpnAgent = System.getProperty("mortbay-alpn-agent");
if (alpnAgent == null)
throw new IllegalStateException("Define path to alpn agent jar as system property -Dmortbay-alpn-agent");
File alpnAgentFile = new File(alpnAgent);
if (!alpnAgentFile.exists())
throw new IllegalStateException("Unable to find the alpn agent jar here: " + alpnAgent);
res.add(CoreOptions.vmOptions("-javaagent:" + alpnAgentFile.getAbsolutePath() + "=debug=true"));
res.add(mavenBundle().groupId("org.eclipse.jetty.osgi").artifactId("jetty-osgi-alpn").versionAsInProject().noStart());
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-alpn-openjdk8-server").versionAsInProject().start());
@ -116,20 +110,13 @@ public class TestJettyOSGiBootHTTP2
return res;
}
public void checkALPNBootOnBootstrapClasspath() throws Exception
{
Class<?> alpn = Thread.currentThread().getContextClassLoader().loadClass("org.eclipse.jetty.alpn.ALPN");
assertNotNull(alpn);
assertNull(alpn.getClassLoader());
}
public void assertAllBundlesActiveOrResolved()
{
TestOSGiUtil.debugBundles(bundleContext);
TestOSGiUtil.assertAllBundlesActiveOrResolved(bundleContext);
Bundle openjdk8 = TestOSGiUtil.getBundle(bundleContext, "org.eclipse.jetty.alpn.openjdk8.server");
assertNotNull(openjdk8);
ServiceReference[] services = openjdk8.getRegisteredServices();
ServiceReference<?>[] services = openjdk8.getRegisteredServices();
assertNotNull(services);
Bundle server = TestOSGiUtil.getBundle(bundleContext, "org.eclipse.jetty.alpn.server");
assertNotNull(server);
@ -139,10 +126,7 @@ public class TestJettyOSGiBootHTTP2
public void testHTTP2() throws Exception
{
if (Boolean.getBoolean(TestOSGiUtil.BUNDLE_DEBUG))
{
checkALPNBootOnBootstrapClasspath();
assertAllBundlesActiveOrResolved();
}
HttpClient httpClient = null;
HTTP2Client http2Client = null;
@ -151,7 +135,7 @@ public class TestJettyOSGiBootHTTP2
//get the port chosen for https
String tmp = System.getProperty("boot.https.port");
assertNotNull(tmp);
int port = Integer.valueOf(tmp.trim());
int port = Integer.parseInt(tmp.trim());
Path path = Paths.get("src", "test", "config");
File keys = path.resolve("etc").resolve("keystore").toFile();

View File

@ -19,9 +19,12 @@
package org.eclipse.jetty.plus.webapp;
import java.util.Iterator;
import java.util.Objects;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import org.eclipse.jetty.jndi.NamingUtil;
import org.eclipse.jetty.plus.annotation.Injection;
@ -35,6 +38,7 @@ import org.eclipse.jetty.plus.jndi.EnvEntry;
import org.eclipse.jetty.plus.jndi.Link;
import org.eclipse.jetty.plus.jndi.NamingEntry;
import org.eclipse.jetty.plus.jndi.NamingEntryUtil;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -121,14 +125,6 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor
String type = node.getString("env-entry-type", false, true);
String valueStr = node.getString("env-entry-value", false, true);
//if there's no value there's no point in making a jndi entry
//nor processing injection entries
if (valueStr == null || valueStr.equals(""))
{
LOG.warn("No value for env-entry-name " + name);
return;
}
Origin o = context.getMetaData().getOrigin("env-entry." + name);
switch (o)
{
@ -136,14 +132,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor
{
//no descriptor has configured an env-entry of this name previously
context.getMetaData().setOrigin("env-entry." + name, descriptor);
//the javaee_5.xsd says that the env-entry-type is optional
//if there is an <injection> element, because you can get
//type from the element, but what to do if there is more
//than one <injection> element, do you just pick the type
//of the first one?
addInjections(context, descriptor, node, name, TypeUtil.fromName(type));
Object value = TypeUtil.valueOf(type, valueStr);
bindEnvEntry(name, value);
makeEnvEntryInjectionsAndBindings(context, descriptor, node, name, type, valueStr);
break;
}
case WebXml:
@ -158,9 +147,7 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor
//We're processing web-defaults, web.xml or web-override. Any of them can
//set or change the env-entry.
context.getMetaData().setOrigin("env-entry." + name, descriptor);
addInjections(context, descriptor, node, name, TypeUtil.fromName(type));
Object value = TypeUtil.valueOf(type, valueStr);
bindEnvEntry(name, value);
makeEnvEntryInjectionsAndBindings(context, descriptor, node, name, type, valueStr);
}
else
{
@ -705,6 +692,9 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor
*/
public void addInjections(WebAppContext context, Descriptor descriptor, XmlParser.Node node, String jndiName, Class<?> valueClass)
{
Objects.requireNonNull(context);
Objects.requireNonNull(node);
Iterator<XmlParser.Node> itor = node.iterator("injection-target");
while (itor.hasNext())
@ -755,31 +745,59 @@ public class PlusDescriptorProcessor extends IterativeDescriptorProcessor
*/
public void bindEnvEntry(String name, Object value) throws Exception
{
InitialContext ic = null;
boolean bound = false;
//check to see if we bound a value and an EnvEntry with this name already
//when we processed the server and the webapp's naming environment
//@see EnvConfiguration.bindEnvEntries()
ic = new InitialContext();
InitialContext ic = new InitialContext();
Context envCtx = (Context)ic.lookup("java:comp/env");
NamingUtil.bind(envCtx, name, value);
}
/**
* Make injections and any java:comp/env bindings necessary given an env-entry declaration.
* The handling of env-entries is different to other resource declarations like resource-ref, resource-env-ref etc
* because we allow the EnvEntry (@see org.eclipse.jetty.plus.jndi.EnvEntry) class that is configured externally to the webapp
* to specify a value that can override a value present in a web.xml descriptor.
*
* @param context the WebAppContext of the env-entry
* @param descriptor the web.xml, web-default.xml, web-override.xml or web-fragment.xml
* @param node the parsed xml representation of the env-entry declaration
* @param name the name field of the env-entry
* @param type the type field of the env-entry
* @param value the value field of the env-entry
* @throws Exception
*/
public void makeEnvEntryInjectionsAndBindings(WebAppContext context, Descriptor descriptor, XmlParser.Node node, String name, String type, String value) throws Exception
{
InitialContext ic = new InitialContext();
try
{
NamingEntry ne = (NamingEntry)ic.lookup("java:comp/env/" + NamingEntryUtil.makeNamingEntryName(ic.getNameParser(""), name));
if (ne != null && ne instanceof EnvEntry)
EnvEntry envEntry = (EnvEntry)ic.lookup("java:comp/env/" + NamingEntryUtil.makeNamingEntryName(ic.getNameParser(""), name));
if (StringUtil.isEmpty(value))
{
EnvEntry ee = (EnvEntry)ne;
bound = ee.isOverrideWebXml();
//There is an empty or missing value in the env-entry:
//If there is an existing EnvEntry (eg from a declaration in jetty-env.xml) that is override=true, then
//we make the injection, but we can skip the rebinding becase we want to use the value already bound.
//If there isn't an existing EnvEntry then there is nothing to do: according to the spec we do not make
//an injection if the env-entry value is missing, and of course there is no value to rebind.
if (envEntry != null && envEntry.isOverrideWebXml())
addInjections(context, descriptor, node, name, TypeUtil.fromName(type));
}
else
{
//There is a value for the env-entry:
//According to the spec, we need to make an injection (if one is present).
//If there is an existing EnvEntry(eg from a declaration in jetty-env.xml) that is override=false, then
//we need to rebind name with the value from web.xml.
addInjections(context, descriptor, node, name, TypeUtil.fromName(type));
if (envEntry == null || !envEntry.isOverrideWebXml())
bindEnvEntry(name, TypeUtil.valueOf(type, value));
}
}
catch (NameNotFoundException e)
{
bound = false;
}
if (!bound)
{
//either nothing was bound or the value from web.xml should override
Context envCtx = (Context)ic.lookup("java:comp/env");
NamingUtil.bind(envCtx, name, value);
//No matching EnvEntry has previously been bound so make the injection and do the binding with the value from web.xml
addInjections(context, descriptor, node, name, TypeUtil.fromName(type));
bindEnvEntry(name, TypeUtil.valueOf(type, value));
}
}

View File

@ -22,7 +22,14 @@ import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import org.eclipse.jetty.jndi.NamingUtil;
import org.eclipse.jetty.plus.annotation.Injection;
import org.eclipse.jetty.plus.annotation.InjectionCollection;
import org.eclipse.jetty.plus.jndi.EnvEntry;
import org.eclipse.jetty.plus.jndi.NamingEntryUtil;
import org.eclipse.jetty.util.IntrospectionUtil;
import org.eclipse.jetty.webapp.Descriptor;
import org.eclipse.jetty.webapp.FragmentDescriptor;
import org.eclipse.jetty.webapp.Origin;
@ -39,6 +46,7 @@ import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
@ -48,6 +56,7 @@ import static org.junit.jupiter.api.Assertions.fail;
*/
public class PlusDescriptorProcessorTest
{
protected static final Class<?>[] STRING_ARG = new Class[]{String.class};
protected WebDescriptor webDescriptor;
protected FragmentDescriptor fragDescriptor1;
protected FragmentDescriptor fragDescriptor2;
@ -55,19 +64,95 @@ public class PlusDescriptorProcessorTest
protected FragmentDescriptor fragDescriptor4;
protected WebAppContext context;
public static class TestInjections
{
private String foo;
private String bah;
private String empty;
private String vacuum;
private String webXmlOnly;
public String getWebXmlOnly()
{
return webXmlOnly;
}
public void setWebXmlOnly(String webXmlOnly)
{
this.webXmlOnly = webXmlOnly;
}
public String getVacuum()
{
return vacuum;
}
public void setVacuum(String val)
{
vacuum = val;
}
public String getEmpty()
{
return empty;
}
public void setEmpty(String val)
{
empty = val;
}
public void setFoo(String val)
{
foo = val;
}
public String getFoo()
{
return foo;
}
public String getBah()
{
return bah;
}
public void setBah(String val)
{
bah = val;
}
}
@BeforeEach
public void setUp() throws Exception
{
context = new WebAppContext();
context.setClassLoader(new WebAppClassLoader(Thread.currentThread().getContextClassLoader(), context));
context.getServerClasspathPattern().add("-org.eclipse.jetty.plus.webapp."); //need visbility of the TestInjections class
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(context.getClassLoader());
Context icontext = new InitialContext();
Context compCtx = (Context)icontext.lookup("java:comp");
compCtx.createSubcontext("env");
Thread.currentThread().setContextClassLoader(oldLoader);
Context envCtx = compCtx.createSubcontext("env");
@SuppressWarnings("unused")
org.eclipse.jetty.plus.jndi.Resource ds = new org.eclipse.jetty.plus.jndi.Resource(context, "jdbc/mydatasource", new Object());
//An EnvEntry that should override any value supplied in a web.xml file
org.eclipse.jetty.plus.jndi.EnvEntry fooStringEnvEntry = new org.eclipse.jetty.plus.jndi.EnvEntry("foo", "FOO", true);
doEnvConfiguration(envCtx, fooStringEnvEntry);
//An EnvEntry that should NOT override any value supplied in a web.xml file
org.eclipse.jetty.plus.jndi.EnvEntry bahStringEnvEntry = new org.eclipse.jetty.plus.jndi.EnvEntry("bah", "BAH", false);
doEnvConfiguration(envCtx, bahStringEnvEntry);
//An EnvEntry that will override an empty value in web.xml
org.eclipse.jetty.plus.jndi.EnvEntry emptyStringEnvEntry = new org.eclipse.jetty.plus.jndi.EnvEntry("empty", "EMPTY", true);
doEnvConfiguration(envCtx, emptyStringEnvEntry);
//An EnvEntry that will NOT override an empty value in web.xml
org.eclipse.jetty.plus.jndi.EnvEntry vacuumStringEnvEntry = new org.eclipse.jetty.plus.jndi.EnvEntry("vacuum", "VACUUM", false);
doEnvConfiguration(envCtx, vacuumStringEnvEntry);
URL webXml = Thread.currentThread().getContextClassLoader().getResource("web.xml");
webDescriptor = new WebDescriptor(org.eclipse.jetty.util.resource.Resource.newResource(webXml));
@ -85,6 +170,22 @@ public class PlusDescriptorProcessorTest
URL frag4Xml = Thread.currentThread().getContextClassLoader().getResource("web-fragment-4.xml");
fragDescriptor4 = new FragmentDescriptor(org.eclipse.jetty.util.resource.Resource.newResource(frag4Xml));
fragDescriptor4.parse();
Thread.currentThread().setContextClassLoader(oldLoader);
}
/**
* Do the kind of processing that EnvConfiguration would do.
*
* @param envCtx the java:comp/env context
* @param envEntry the EnvEntry
* @throws Exception
*/
private void doEnvConfiguration(Context envCtx, EnvEntry envEntry) throws Exception
{
envEntry.bindToENC(envEntry.getJndiName());
Name namingEntryName = NamingEntryUtil.makeNamingEntryName(null, envEntry);
NamingUtil.bind(envCtx, namingEntryName.toString(), envEntry);
}
@AfterEach
@ -140,6 +241,59 @@ public class PlusDescriptorProcessorTest
Thread.currentThread().setContextClassLoader(oldLoader);
}
}
@Test
public void testEnvEntries() throws Exception
{
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(context.getClassLoader());
try
{
PlusDescriptorProcessor pdp = new PlusDescriptorProcessor();
//process web.xml
pdp.process(context, webDescriptor);
InjectionCollection injections = (InjectionCollection)context.getAttribute(InjectionCollection.INJECTION_COLLECTION);
assertNotNull(injections);
//check that there is an injection for "foo" with the value from the overriding EnvEntry of "FOO"
Injection foo = injections.getInjection("foo", TestInjections.class,
IntrospectionUtil.findMethod(TestInjections.class, "setFoo", STRING_ARG, false, true),
String.class);
assertNotNull(foo);
assertEquals("FOO", foo.lookupInjectedValue());
//check that there is an injection for "bah" with the value from web.xml of "beer"
Injection bah = injections.getInjection("bah", TestInjections.class,
IntrospectionUtil.findMethod(TestInjections.class, "setBah", STRING_ARG, false, true),
String.class);
assertNotNull(bah);
assertEquals("beer", bah.lookupInjectedValue());
//check that there is an injection for "empty" with the value from the overriding EnvEntry of "EMPTY"
Injection empty = injections.getInjection("empty", TestInjections.class,
IntrospectionUtil.findMethod(TestInjections.class, "setEmpty", STRING_ARG, false, true),
String.class);
assertNotNull(empty);
assertEquals("EMPTY", empty.lookupInjectedValue());
//check that there is NOT an injection for "vacuum"
Injection vacuum = injections.getInjection("vacuum", TestInjections.class,
IntrospectionUtil.findMethod(TestInjections.class, "setVacuum", STRING_ARG, false, true),
String.class);
assertNull(vacuum);
//check that there is an injection for "webxmlonly" with the value from web.xml of "WEBXMLONLY"
Injection webXmlOnly = injections.getInjection("webxmlonly", TestInjections.class,
IntrospectionUtil.findMethod(TestInjections.class, "setWebXmlOnly", STRING_ARG, false, true),
String.class);
assertNotNull(webXmlOnly);
assertEquals("WEBXMLONLY", webXmlOnly.lookupInjectedValue());
}
finally
{
Thread.currentThread().setContextClassLoader(oldLoader);
}
}
@Test
public void testMismatchedFragmentResourceDeclarations()

View File

@ -1,136 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
// ------------------------------------------------------------------------
// 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.plus.webapp;
import javax.naming.Context;
import javax.naming.InitialContext;
import org.eclipse.jetty.plus.jndi.EnvEntry;
import org.eclipse.jetty.plus.jndi.NamingEntry;
import org.eclipse.jetty.plus.jndi.NamingEntryUtil;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.MetaData;
import org.eclipse.jetty.webapp.WebAppClassLoader;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class TestConfiguration
{
@Test
public void testIt() throws Exception
{
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
try
{
InitialContext ic = new InitialContext();
Server server = new Server();
WebAppContext wac = new WebAppContext();
wac.setServer(server);
wac.setClassLoader(new WebAppClassLoader(Thread.currentThread().getContextClassLoader(), wac));
MetaData metaData = new MetaData();
PlusDescriptorProcessor plusProcessor = new PlusDescriptorProcessor();
//bind some EnvEntrys at the server level
EnvEntry ee1 = new EnvEntry(server, "xxx/a", "100", true);
EnvEntry ee2 = new EnvEntry(server, "yyy/b", "200", false);
EnvEntry ee3 = new EnvEntry(server, "zzz/c", "300", false);
EnvEntry ee4 = new EnvEntry(server, "zzz/d", "400", false);
EnvEntry ee5 = new EnvEntry(server, "zzz/f", "500", true);
//bind some EnvEntrys at the webapp level
EnvEntry ee6 = new EnvEntry(wac, "xxx/a", "900", true);
EnvEntry ee7 = new EnvEntry(wac, "yyy/b", "910", true);
EnvEntry ee8 = new EnvEntry(wac, "zzz/c", "920", false);
EnvEntry ee9 = new EnvEntry(wac, "zzz/e", "930", false);
assertNotNull(NamingEntryUtil.lookupNamingEntry(server, "xxx/a"));
assertNotNull(NamingEntryUtil.lookupNamingEntry(server, "yyy/b"));
assertNotNull(NamingEntryUtil.lookupNamingEntry(server, "zzz/c"));
assertNotNull(NamingEntryUtil.lookupNamingEntry(server, "zzz/d"));
assertNotNull(NamingEntryUtil.lookupNamingEntry(wac, "xxx/a"));
assertNotNull(NamingEntryUtil.lookupNamingEntry(wac, "yyy/b"));
assertNotNull(NamingEntryUtil.lookupNamingEntry(wac, "zzz/c"));
assertNotNull(NamingEntryUtil.lookupNamingEntry(wac, "zzz/e"));
//make a new env configuration
EnvConfiguration envConfig = new EnvConfiguration();
Thread.currentThread().setContextClassLoader(wac.getClassLoader());
MetaData metadata = new MetaData();
envConfig.preConfigure(wac);
envConfig.configure(wac);
envConfig.bindEnvEntries(wac);
String val = (String)ic.lookup("java:comp/env/xxx/a");
assertEquals("900", val); //webapp naming overrides server
val = (String)ic.lookup("java:comp/env/yyy/b");
assertEquals("910", val);//webapp overrides server
val = (String)ic.lookup("java:comp/env/zzz/c");
assertEquals("920", val);//webapp overrides server
val = (String)ic.lookup("java:comp/env/zzz/d");
assertEquals("400", val);//from server naming
val = (String)ic.lookup("java:comp/env/zzz/e");
assertEquals("930", val);//from webapp naming
NamingEntry ne = (NamingEntry)ic.lookup("java:comp/env/" + NamingEntry.__contextName + "/xxx/a");
assertNotNull(ne);
ne = (NamingEntry)ic.lookup("java:comp/env/" + NamingEntry.__contextName + "/yyy/b");
assertNotNull(ne);
ne = (NamingEntry)ic.lookup("java:comp/env/" + NamingEntry.__contextName + "/zzz/c");
assertNotNull(ne);
ne = (NamingEntry)ic.lookup("java:comp/env/" + NamingEntry.__contextName + "/zzz/d");
assertNotNull(ne);
ne = (NamingEntry)ic.lookup("java:comp/env/" + NamingEntry.__contextName + "/zzz/e");
assertNotNull(ne);
plusProcessor.bindEnvEntry("foo", "99");
assertEquals("99", ic.lookup("java:comp/env/foo"));
plusProcessor.bindEnvEntry("xxx/a", "7");
assertEquals("900", ic.lookup("java:comp/env/xxx/a")); //webapp overrides web.xml
plusProcessor.bindEnvEntry("yyy/b", "7");
assertEquals("910", ic.lookup("java:comp/env/yyy/b"));//webapp overrides web.xml
plusProcessor.bindEnvEntry("zzz/c", "7");
assertEquals("7", ic.lookup("java:comp/env/zzz/c"));//webapp does NOT override web.xml
plusProcessor.bindEnvEntry("zzz/d", "7");
assertEquals("7", ic.lookup("java:comp/env/zzz/d"));//server does NOT override web.xml
plusProcessor.bindEnvEntry("zzz/e", "7");
assertEquals("7", ic.lookup("java:comp/env/zzz/e"));//webapp does NOT override web.xml
plusProcessor.bindEnvEntry("zzz/f", "7");
assertEquals("500", ic.lookup("java:comp/env/zzz/f"));//server overrides web.xml
((Context)ic.lookup("java:comp")).destroySubcontext("env");
ic.destroySubcontext("xxx");
ic.destroySubcontext("yyy");
ic.destroySubcontext("zzz");
}
finally
{
Thread.currentThread().setContextClassLoader(oldLoader);
}
}
}

View File

@ -4,20 +4,70 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
metadata-complete="false"
version="3.0">
version="3.0">
<display-name>Test WebApp</display-name>
<display-name>Test WebApp</display-name>
<resource-ref>
<res-ref-name>jdbc/mydatasource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<!--
<injection-target>
<injection-target-class>com.acme.JNDITest</injection-target-class>
<injection-target-name>myDatasource</injection-target-name>
</injection-target>
-->
<!-- <injection-target> <injection-target-class>com.acme.JNDITest</injection-target-class>
<injection-target-name>myDatasource</injection-target-name> </injection-target> -->
</resource-ref>
<!-- env entry for which is there is an overriding EnvEntry -->
<env-entry>
<env-entry-name>foo</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>beer</env-entry-value>
<injection-target>
<injection-target-class>org.eclipse.jetty.plus.webapp.PlusDescriptorProcessorTest$TestInjections</injection-target-class>
<injection-target-name>foo</injection-target-name>
</injection-target>
</env-entry>
<!-- env entry for which the EnvEntry does not override -->
<env-entry>
<env-entry-name>bah</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>beer</env-entry-value>
<injection-target>
<injection-target-class>org.eclipse.jetty.plus.webapp.PlusDescriptorProcessorTest$TestInjections</injection-target-class>
<injection-target-name>bah</injection-target-name>
</injection-target>
</env-entry>
<!-- env entry with no value for which the EnvEntry should override -->
<env-entry>
<env-entry-name>empty</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value></env-entry-value>
<injection-target>
<injection-target-class>org.eclipse.jetty.plus.webapp.PlusDescriptorProcessorTest$TestInjections</injection-target-class>
<injection-target-name>empty</injection-target-name>
</injection-target>
</env-entry>
<!-- env entry with no value and EnvEntry does not override -->
<env-entry>
<env-entry-name>vacuum</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value></env-entry-value>
<injection-target>
<injection-target-class>org.eclipse.jetty.plus.webapp.PlusDescriptorProcessorTest$TestInjections</injection-target-class>
<injection-target-name>vacuum</injection-target-name>
</injection-target>
</env-entry>
<!-- env entry with no matching EnvEntry -->
<env-entry>
<env-entry-name>webxmlonly</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>WEBXMLONLY</env-entry-value>
<injection-target>
<injection-target-class>org.eclipse.jetty.plus.webapp.PlusDescriptorProcessorTest$TestInjections</injection-target-class>
<injection-target-name>webXmlOnly</injection-target-name>
</injection-target>
</env-entry>
</web-app>

View File

@ -1,8 +1,27 @@
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<!-- =============================================================== --><!-- Documentation of this file format can be found at: --><!-- https://www.eclipse.org/jetty/documentation/current/ --><!-- --><!-- Additional configuration files are available in $JETTY_HOME/etc --><!-- and can be mixed in. See start.ini file for the default --><!-- configuration files. --><!-- --><!-- For a description of the configuration mechanism, see the --><!-- output of: --><!-- java -jar start.jar -? --><!-- =============================================================== -->
<!-- =============================================================== -->
<!-- Documentation of this file format can be found at: -->
<!-- https://www.eclipse.org/jetty/documentation/current/ -->
<!-- -->
<!-- Additional configuration files are available in $JETTY_HOME/etc -->
<!-- and can be mixed in. See start.ini file for the default -->
<!-- configuration files. -->
<!-- -->
<!-- For a description of the configuration mechanism, see the -->
<!-- output of: -->
<!-- java -jar start.jar -? -->
<!-- =============================================================== -->
<!-- =============================================================== --><!-- Configure a Jetty Server instance with an ID "Server" --><!-- Other configuration files may also configure the "Server" --><!-- ID, in which case they are adding configuration to the same --><!-- instance. If other configuration have a different ID, they --><!-- will create and configure another instance of Jetty. --><!-- Consult the javadoc of o.e.j.server.Server for all --><!-- configuration that may be set here. --><!-- =============================================================== -->
<!-- =============================================================== -->
<!-- Configure a Jetty Server instance with an ID "Server" -->
<!-- Other configuration files may also configure the "Server" -->
<!-- ID, in which case they are adding configuration to the same -->
<!-- instance. If other configuration have a different ID, they -->
<!-- will create and configure another instance of Jetty. -->
<!-- Consult the javadoc of o.e.j.server.Server for all -->
<!-- configuration that may be set here. -->
<!-- =============================================================== -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Arg name="threadpool"><Ref refid="threadPool"/></Arg>

View File

@ -1029,12 +1029,16 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
private static void logRequestCookie(String arg, StringBuilder b, Request request, Response response)
{
for (Cookie c : request.getCookies())
Cookie[] cookies = request.getCookies();
if (cookies != null)
{
if (arg.equals(c.getName()))
for (Cookie c : cookies)
{
b.append(c.getValue());
return;
if (arg.equals(c.getName()))
{
b.append(c.getValue());
return;
}
}
}

View File

@ -24,6 +24,7 @@ import java.lang.invoke.MethodType;
import java.net.InetSocketAddress;
import javax.servlet.ServletRequest;
import org.eclipse.jetty.http.BadMessageException;
import org.eclipse.jetty.http.HostPortHttpField;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
@ -376,18 +377,18 @@ public class ForwardedRequestCustomizer implements Customizer
// Do a single pass through the header fields as it is a more efficient single iteration.
Forwarded forwarded = new Forwarded(request, config);
try
for (HttpField field : httpFields)
{
for (HttpField field : httpFields)
try
{
MethodHandle handle = _handles.get(field.getName());
if (handle != null)
handle.invoke(forwarded, field);
}
}
catch (Throwable e)
{
throw new RuntimeException(e);
catch (Throwable t)
{
onError(field, t);
}
}
if (forwarded._proto != null)
@ -420,6 +421,11 @@ public class ForwardedRequestCustomizer implements Customizer
}
}
protected void onError(HttpField field, Throwable t)
{
throw new BadMessageException("Bad header value for " + field.getName(), t);
}
protected String getLeftMost(String headerValue)
{
if (headerValue == null)
@ -623,35 +629,37 @@ public class ForwardedRequestCustomizer implements Customizer
@SuppressWarnings("unused")
public void handleFor(HttpField field)
{
String authority = getLeftMost(field.getValue());
if (!getForwardedPortAsAuthority() && !StringUtil.isEmpty(getForwardedPortHeader()))
{
if (_for == null)
_for = new PossiblyPartialHostPort(getLeftMost(field.getValue()));
_for = new PossiblyPartialHostPort(authority);
else if (_for instanceof PortSetHostPort)
_for = new HostPort(HostPort.normalizeHost(getLeftMost(field.getValue())), _for.getPort());
_for = new HostPort(HostPort.normalizeHost(authority), _for.getPort());
}
else if (_for == null)
{
_for = new HostPort(getLeftMost(field.getValue()));
_for = new HostPort(authority);
}
}
@SuppressWarnings("unused")
public void handlePort(HttpField field)
{
int port = HostPort.parsePort(getLeftMost(field.getValue()));
if (!getForwardedPortAsAuthority())
{
if (_for == null)
_for = new PortSetHostPort(_request.getRemoteHost(), Integer.parseInt(getLeftMost(field.getValue())));
_for = new PortSetHostPort(_request.getRemoteHost(), port);
else if (_for instanceof PossiblyPartialHostPort && _for.getPort() <= 0)
_for = new HostPort(HostPort.normalizeHost(_for.getHost()), Integer.parseInt(getLeftMost(field.getValue())));
_for = new HostPort(HostPort.normalizeHost(_for.getHost()), port);
}
else
{
if (_host == null)
_host = new PortSetHostPort(_request.getServerName(), Integer.parseInt(getLeftMost(field.getValue())));
_host = new PortSetHostPort(_request.getServerName(), port);
else if (_host instanceof PossiblyPartialHostPort && _host.getPort() <= 0)
_host = new HostPort(HostPort.normalizeHost(_host.getHost()), Integer.parseInt(getLeftMost(field.getValue())));
_host = new HostPort(HostPort.normalizeHost(_host.getHost()), port);
}
}

View File

@ -708,8 +708,16 @@ public class DetectorConnectionTest
sb.append("AAAA");
}
String request = sb.toString();
String response = getResponse(request);
assertThat(response, Matchers.nullValue());
try
{
String response = getResponse(request);
assertThat(response, Matchers.nullValue());
}
catch (SocketException expected)
{
// The test may fail writing the "request"
// bytes as the server sends back a TCP RST.
}
}
}

View File

@ -32,6 +32,7 @@ import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
@ -619,6 +620,25 @@ public class ForwardedRequestCustomizerTest
expectations.accept(actual);
}
@Test
public void testBadInput() throws Exception
{
Request request = new Request("Bad port value")
.headers(
"GET / HTTP/1.1",
"Host: myhost",
"X-Forwarded-Port: "
);
request.configure(customizer);
String rawRequest = request.getRawRequest((header) -> header);
System.out.println(rawRequest);
HttpTester.Response response = HttpTester.parseResponse(connector.getResponse(rawRequest));
assertThat("status", response.getStatus(), is(400));
}
private static class Request
{
String description;

View File

@ -23,7 +23,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.Filter;
@ -157,8 +159,10 @@ public class CrossOriginFilter implements Filter
private boolean anyOriginAllowed;
private boolean anyTimingOriginAllowed;
private boolean anyHeadersAllowed;
private List<String> allowedOrigins = new ArrayList<String>();
private List<String> allowedTimingOrigins = new ArrayList<String>();
private Set<String> allowedOrigins = new HashSet<String>();
private List<Pattern> allowedOriginPatterns = new ArrayList<Pattern>();
private Set<String> allowedTimingOrigins = new HashSet<String>();
private List<Pattern> allowedTimingOriginPatterns = new ArrayList<Pattern>();
private List<String> allowedMethods = new ArrayList<String>();
private List<String> allowedHeaders = new ArrayList<String>();
private List<String> exposedHeaders = new ArrayList<String>();
@ -172,8 +176,8 @@ public class CrossOriginFilter implements Filter
String allowedOriginsConfig = config.getInitParameter(ALLOWED_ORIGINS_PARAM);
String allowedTimingOriginsConfig = config.getInitParameter(ALLOWED_TIMING_ORIGINS_PARAM);
anyOriginAllowed = generateAllowedOrigins(allowedOrigins, allowedOriginsConfig, DEFAULT_ALLOWED_ORIGINS);
anyTimingOriginAllowed = generateAllowedOrigins(allowedTimingOrigins, allowedTimingOriginsConfig, DEFAULT_ALLOWED_TIMING_ORIGINS);
anyOriginAllowed = generateAllowedOrigins(allowedOrigins, allowedOriginPatterns, allowedOriginsConfig, DEFAULT_ALLOWED_ORIGINS);
anyTimingOriginAllowed = generateAllowedOrigins(allowedTimingOrigins, allowedTimingOriginPatterns, allowedTimingOriginsConfig, DEFAULT_ALLOWED_TIMING_ORIGINS);
String allowedMethodsConfig = config.getInitParameter(ALLOWED_METHODS_PARAM);
if (allowedMethodsConfig == null)
@ -235,7 +239,7 @@ public class CrossOriginFilter implements Filter
}
}
private boolean generateAllowedOrigins(List<String> allowedOriginStore, String allowedOriginsConfig, String defaultOrigin)
private boolean generateAllowedOrigins(Set<String> allowedOriginStore, List<Pattern> allowedOriginPatternStore, String allowedOriginsConfig, String defaultOrigin)
{
if (allowedOriginsConfig == null)
allowedOriginsConfig = defaultOrigin;
@ -247,8 +251,13 @@ public class CrossOriginFilter implements Filter
if (ANY_ORIGIN.equals(allowedOrigin))
{
allowedOriginStore.clear();
allowedOriginPatternStore.clear();
return true;
}
else if (allowedOrigin.contains("*"))
{
allowedOriginPatternStore.add(Pattern.compile(parseAllowedWildcardOriginToRegex(allowedOrigin)));
}
else
{
allowedOriginStore.add(allowedOrigin);
@ -270,7 +279,7 @@ public class CrossOriginFilter implements Filter
// Is it a cross origin request ?
if (origin != null && isEnabled(request))
{
if (anyOriginAllowed || originMatches(allowedOrigins, origin))
if (anyOriginAllowed || originMatches(allowedOrigins, allowedOriginPatterns, origin))
{
if (isSimpleRequest(request))
{
@ -292,7 +301,7 @@ public class CrossOriginFilter implements Filter
handleSimpleResponse(request, response, origin);
}
if (anyTimingOriginAllowed || originMatches(allowedTimingOrigins, origin))
if (anyTimingOriginAllowed || originMatches(allowedTimingOrigins, allowedTimingOriginPatterns, origin))
{
response.setHeader(TIMING_ALLOW_ORIGIN_HEADER, origin);
}
@ -330,7 +339,7 @@ public class CrossOriginFilter implements Filter
return true;
}
private boolean originMatches(List<String> allowedOrigins, String originList)
private boolean originMatches(Set<String> allowedOrigins, List<Pattern> allowedOriginPatterns, String originList)
{
if (originList.trim().length() == 0)
return false;
@ -341,30 +350,18 @@ public class CrossOriginFilter implements Filter
if (origin.trim().length() == 0)
continue;
for (String allowedOrigin : allowedOrigins)
if (allowedOrigins.contains(origin))
return true;
for (Pattern allowedOrigin : allowedOriginPatterns)
{
if (allowedOrigin.contains("*"))
{
Matcher matcher = createMatcher(origin, allowedOrigin);
if (matcher.matches())
return true;
}
else if (allowedOrigin.equals(origin))
{
if (allowedOrigin.matcher(origin).matches())
return true;
}
}
}
return false;
}
private Matcher createMatcher(String origin, String allowedOrigin)
{
String regex = parseAllowedWildcardOriginToRegex(allowedOrigin);
Pattern pattern = Pattern.compile(regex);
return pattern.matcher(origin);
}
private String parseAllowedWildcardOriginToRegex(String allowedOrigin)
{
String regex = StringUtil.replace(allowedOrigin, ".", "\\.");
@ -505,7 +502,11 @@ public class CrossOriginFilter implements Filter
public void destroy()
{
anyOriginAllowed = false;
anyTimingOriginAllowed = false;
allowedOrigins.clear();
allowedOriginPatterns.clear();
allowedTimingOrigins.clear();
allowedTimingOriginPatterns.clear();
allowedMethods.clear();
allowedHeaders.clear();
preflightMaxAge = 0;

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.9.v20160720|lib/alpn/alpn-boot-8.1.9.v20160720.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.9.v20160720.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.9.v20160720|lib/alpn/alpn-boot-8.1.9.v20160720.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.9.v20160720.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.9.v20160720|lib/alpn/alpn-boot-8.1.9.v20160720.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.9.v20160720.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.10.v20161026|lib/alpn/alpn-boot-8.1.10.v20161026.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.10.v20161026.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.11.v20170118|lib/alpn/alpn-boot-8.1.11.v20170118.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.11.v20170118|lib/alpn/alpn-boot-8.1.11.v20170118.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.11.v20170118|lib/alpn/alpn-boot-8.1.11.v20170118.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.11.v20170118|lib/alpn/alpn-boot-8.1.11.v20170118.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.11.v20170118|lib/alpn/alpn-boot-8.1.11.v20170118.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.11.v20170118|lib/alpn/alpn-boot-8.1.11.v20170118.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.12.v20180117|lib/alpn/alpn-boot-8.1.12.v20180117.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.12.v20180117.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.12.v20180117|lib/alpn/alpn-boot-8.1.12.v20180117.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.12.v20180117.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.12.v20180117|lib/alpn/alpn-boot-8.1.12.v20180117.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.12.v20180117.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.12.v20180117|lib/alpn/alpn-boot-8.1.12.v20180117.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.12.v20180117.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.12.v20180117|lib/alpn/alpn-boot-8.1.12.v20180117.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.12.v20180117.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar

View File

@ -1,5 +0,0 @@
[files]
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.13.v20181017|lib/alpn/alpn-boot-8.1.13.v20181017.jar
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.13.v20181017.jar

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