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

This commit is contained in:
Jan Bartel 2017-01-18 15:25:21 +11:00
commit 76df903feb
93 changed files with 2025 additions and 574 deletions

View File

@ -46,7 +46,6 @@ import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
import org.eclipse.jetty.jmx.MBeanContainer; import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.NegotiatingServerConnectionFactory;
import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
@ -56,7 +55,6 @@ import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlets.PushCacheFilter; import org.eclipse.jetty.servlets.PushCacheFilter;
import org.eclipse.jetty.servlets.PushSessionCacheFilter;
import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.ssl.SslContextFactory;
@ -109,7 +107,6 @@ public class Http2Server
// HTTP/2 Connection Factory // HTTP/2 Connection Factory
HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(https_config); HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(https_config);
NegotiatingServerConnectionFactory.checkProtocolNegotiationAvailable();
ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory(); ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
alpn.setDefaultProtocol(http.getDefaultProtocol()); alpn.setDefaultProtocol(http.getDefaultProtocol());

View File

@ -19,8 +19,10 @@
package org.eclipse.jetty.alpn.client; package org.eclipse.jetty.alpn.client;
import java.io.IOException; import java.io.IOException;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngine;
@ -29,27 +31,58 @@ import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.NegotiatingClientConnectionFactory; import org.eclipse.jetty.io.NegotiatingClientConnectionFactory;
import org.eclipse.jetty.io.ssl.ALPNProcessor;
import org.eclipse.jetty.io.ssl.SslClientConnectionFactory; import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
import org.eclipse.jetty.io.ssl.SslHandshakeListener;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFactory public class ALPNClientConnectionFactory extends NegotiatingClientConnectionFactory implements SslHandshakeListener
{ {
private final SslHandshakeListener alpnListener = new ALPNListener();
private final Executor executor; private final Executor executor;
private final List<String> protocols; private final List<String> protocols;
private final ALPNProcessor.Client alpnProcessor;
public ALPNClientConnectionFactory(Executor executor, ClientConnectionFactory connectionFactory, List<String> protocols) public ALPNClientConnectionFactory(Executor executor, ClientConnectionFactory connectionFactory, List<String> protocols)
{ {
super(connectionFactory); super(connectionFactory);
this.executor = executor;
this.protocols = protocols;
if (protocols.isEmpty()) if (protocols.isEmpty())
throw new IllegalArgumentException("ALPN protocol list cannot be empty"); 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;
} }
@Override @Override
public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException 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(), ALPNClientConnection connection = new ALPNClientConnection(endPoint, executor, getClientConnectionFactory(),
(SSLEngine)context.get(SslClientConnectionFactory.SSL_ENGINE_CONTEXT_KEY), context, protocols); sslEngine, context, protocols);
return customize(connection, context); 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)
{
}
}
} }

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-parent</artifactId>
<version>9.4.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-alpn-java-client</artifactId>
<name>Jetty :: ALPN :: JDK9 Client Implementation</name>
<properties>
<bundle-symbolic-name>${project.groupId}.alpn.java.client</bundle-symbolic-name>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.9</source>
<target>1.9</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<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.http2</groupId>
<artifactId>http2-client</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,55 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.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.io.ssl.ALPNProcessor;
public class JDK9ClientALPNProcessor implements ALPNProcessor.Client
{
@Override
public void configure(SSLEngine sslEngine, List<String> protocols)
{
SSLParameters sslParameters = sslEngine.getSSLParameters();
sslParameters.setApplicationProtocols(protocols.toArray(new String[0]));
sslEngine.setSSLParameters(sslParameters);
}
@Override
public void process(SSLEngine sslEngine)
{
try
{
ALPN.ClientProvider provider = (ALPN.ClientProvider)ALPN.get(sslEngine);
if (provider != null)
provider.selected(sslEngine.getApplicationProtocol());
}
catch (SSLException x)
{
throw new UncheckedIOException(x);
}
}
}

View File

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

View File

@ -0,0 +1,85 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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 JDK9HTTP2Client
{
public static void main(String[] args) throws Exception
{
HTTP2Client client = new HTTP2Client();
SslContextFactory sslContextFactory = new SslContextFactory(true);
client.addBean(sslContextFactory);
client.start();
String host = "localhost";
int port = 8443;
FuturePromise<Session> sessionPromise = new FuturePromise<>();
client.connect(sslContextFactory, new InetSocketAddress(host, port), new Session.Listener.Adapter(), sessionPromise);
Session session = sessionPromise.get(555, 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,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-parent</artifactId>
<version>9.4.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-alpn-java-server</artifactId>
<name>Jetty :: ALPN :: JDK9 Server Implementation</name>
<properties>
<bundle-symbolic-name>${project.groupId}.alpn.java.server</bundle-symbolic-name>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.9</source>
<target>1.9</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<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-server</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
<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>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,73 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.server;
import java.util.List;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import org.eclipse.jetty.alpn.ALPN;
import org.eclipse.jetty.io.ssl.ALPNProcessor;
import org.eclipse.jetty.io.ssl.SslHandshakeListener;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class JDK9ServerALPNProcessor implements ALPNProcessor.Server, SslHandshakeListener
{
private static final Logger LOG = Log.getLogger(JDK9ServerALPNProcessor.class);
@Override
public void configure(SSLEngine sslEngine)
{
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;
}
}
@Override
public void handshakeSucceeded(Event event)
{
ALPN.ServerProvider provider = (ALPN.ServerProvider)ALPN.remove(event.getSSLEngine());
if (provider != null)
{
if (LOG.isDebugEnabled())
LOG.debug("ALPN unsupported by client");
provider.unsupported();
}
}
@Override
public void handshakeFailed(Event event, Throwable failure)
{
}
}

View File

@ -0,0 +1 @@
org.eclipse.jetty.alpn.java.server.JDK9ServerALPNProcessor

View File

@ -0,0 +1,166 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.Assert;
import org.junit.Test;
public class JDK9ALPNTest
{
private Server server;
private ServerConnector connector;
public void startServer(Handler handler) throws Exception
{
server = new Server();
HttpConfiguration httpConfiguration = new HttpConfiguration();
HttpConnectionFactory h1 = new HttpConnectionFactory(httpConfiguration);
HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpConfiguration);
ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
alpn.setDefaultProtocol(h1.getProtocol());
connector = new ServerConnector(server, newSslContextFactory(), alpn, h1, h2);
server.addConnector(connector);
server.setHandler(handler);
server.start();
}
private SslContextFactory newSslContextFactory()
{
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
sslContextFactory.setIncludeProtocols("TLSv1.2");
// The mandatory HTTP/2 cipher.
sslContextFactory.setIncludeCipherSuites("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256");
return sslContextFactory;
}
@Test
public void testClientNotSupportingALPNServerSpeaksDefaultProtocol() throws Exception
{
startServer(new AbstractHandler.ErrorDispatchHandler()
{
@Override
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
}
});
SslContextFactory sslContextFactory = new SslContextFactory(true);
sslContextFactory.start();
SSLContext sslContext = sslContextFactory.getSslContext();
try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket("localhost", connector.getLocalPort()))
{
client.setUseClientMode(true);
client.setSoTimeout(5000);
client.startHandshake();
OutputStream output = client.getOutputStream();
output.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Connection: close\r\n" +
"\r\n" +
"").getBytes(StandardCharsets.UTF_8));
output.flush();
InputStream input = client.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
String line = reader.readLine();
Assert.assertTrue(line.contains(" 200 "));
while (true)
{
if (reader.readLine() == null)
break;
}
}
}
@Test
public void testClientSupportingALPNServerSpeaksNegotiatedProtocol() throws Exception
{
startServer(new AbstractHandler.ErrorDispatchHandler()
{
@Override
protected void doNonErrorHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
}
});
SslContextFactory sslContextFactory = new SslContextFactory(true);
sslContextFactory.start();
SSLContext sslContext = sslContextFactory.getSslContext();
try (SSLSocket client = (SSLSocket)sslContext.getSocketFactory().createSocket("localhost", connector.getLocalPort()))
{
client.setUseClientMode(true);
SSLParameters sslParameters = client.getSSLParameters();
sslParameters.setApplicationProtocols(new String[]{"unknown/1.0", "http/1.1"});
client.setSSLParameters(sslParameters);
client.setSoTimeout(5000);
client.startHandshake();
OutputStream output = client.getOutputStream();
output.write(("" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Connection: close\r\n" +
"\r\n" +
"").getBytes(StandardCharsets.UTF_8));
output.flush();
InputStream input = client.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
String line = reader.readLine();
Assert.assertTrue(line.contains(" 200 "));
while (true)
{
if (reader.readLine() == null)
break;
}
}
}
}

View File

@ -0,0 +1,66 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.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 9 ALPN mechanism works.
*/
public class JDK9HTTP2Server
{
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

@ -0,0 +1,28 @@
[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
# http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/
[depend]
alpn-impl/alpn-${java.version}
[files]
lib/
lib/alpn/
[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.
http://github.com/jetty-project/jetty-alpn
http://openjdk.java.net/legal/gplv2+ce.html

View File

@ -0,0 +1,6 @@
[description]
Provides support for ALPN based on JDK 9 APIs.
[lib]
lib/jetty-alpn-java-server-${jetty.version}.jar
lib/alpn-api-*.jar

View File

@ -1,23 +1,9 @@
[description] [description]
Enables the ALPN extension to TLS(SSL) by adding modified classes to Enables the ALPN (Application Layer Protocol Negotiation) TLS extension.
the JVM bootpath.
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).
The alpn 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 alpn-boot can be found at
# http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/
[depend] [depend]
ssl ssl
alpn-impl/alpn-${java.version} alpn-impl/alpn-${java.version.platform}
[lib] [lib]
lib/jetty-alpn-client-${jetty.version}.jar lib/jetty-alpn-client-${jetty.version}.jar
@ -26,15 +12,11 @@ lib/jetty-alpn-server-${jetty.version}.jar
[xml] [xml]
etc/jetty-alpn.xml etc/jetty-alpn.xml
[files]
lib/
lib/alpn/
[ini-template] [ini-template]
## Overrides the order protocols are chosen by the server. ## Overrides the order protocols are chosen by the server.
## The default order is that specified by the order of the ## The default order is that specified by the order of the
## modules declared in start.ini. ## modules declared in start.ini.
# jetty.alpn.protocols=h2-16,http/1.1 # jetty.alpn.protocols=h2,http/1.1
## Specifies what protocol to use when negotiation fails. ## Specifies what protocol to use when negotiation fails.
# jetty.alpn.defaultProtocol=http/1.1 # jetty.alpn.defaultProtocol=http/1.1
@ -42,8 +24,3 @@ lib/alpn/
## ALPN debug logging on System.err ## ALPN debug logging on System.err
# jetty.alpn.debug=false # jetty.alpn.debug=false
[license]
ALPN is a hosted at github under the GPL v2 with ClassPath Exception.
ALPN replaces/modifies OpenJDK classes in the java.sun.security.ssl package.
http://github.com/jetty-project/jetty-alpn
http://openjdk.java.net/legal/gplv2+ce.html

View File

@ -22,6 +22,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSession;
import org.eclipse.jetty.alpn.ALPN; import org.eclipse.jetty.alpn.ALPN;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;
@ -44,7 +45,7 @@ public class ALPNServerConnection extends NegotiatingServerConnection implements
@Override @Override
public void unsupported() public void unsupported()
{ {
select(Collections.<String>emptyList()); select(Collections.emptyList());
} }
@Override @Override
@ -52,8 +53,11 @@ public class ALPNServerConnection extends NegotiatingServerConnection implements
{ {
SSLEngine sslEngine = getSSLEngine(); SSLEngine sslEngine = getSSLEngine();
List<String> serverProtocols = getProtocols(); List<String> serverProtocols = getProtocols();
String tlsProtocol = sslEngine.getHandshakeSession().getProtocol(); SSLSession sslSession = sslEngine.getHandshakeSession();
String tlsCipher = sslEngine.getHandshakeSession().getCipherSuite(); if (sslSession == null)
sslSession = sslEngine.getSession();
String tlsProtocol = sslSession.getProtocol();
String tlsCipher = sslSession.getCipherSuite();
String negotiated = null; String negotiated = null;
// RFC 7301 states that the server picks the protocol // RFC 7301 states that the server picks the protocol
@ -83,12 +87,12 @@ public class ALPNServerConnection extends NegotiatingServerConnection implements
else else
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("{} could not negotiate protocol: C{} | S{}", this, clientProtocols, serverProtocols); LOG.debug("{} could not negotiate protocol among client{} and server{}", this, clientProtocols, serverProtocols);
throw new IllegalStateException(); throw new IllegalStateException();
} }
} }
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("{} protocol selected {}", this, negotiated); LOG.debug("{} protocol selected {} among client{} and server{}", this, negotiated, clientProtocols, serverProtocols);
setProtocol(negotiated); setProtocol(negotiated);
ALPN.remove(sslEngine); ALPN.remove(sslEngine);
return negotiated; return negotiated;

View File

@ -18,22 +18,23 @@
package org.eclipse.jetty.alpn.server; package org.eclipse.jetty.alpn.server;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.ServiceLoader;
import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngine;
import org.eclipse.jetty.alpn.ALPN;
import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.ssl.ALPNProcessor;
import org.eclipse.jetty.io.ssl.SslHandshakeListener;
import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.NegotiatingServerConnectionFactory; import org.eclipse.jetty.server.NegotiatingServerConnectionFactory;
import org.eclipse.jetty.util.annotation.Name; 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 public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFactory implements SslHandshakeListener
{ {
private static final Logger LOG = Log.getLogger(ALPNServerConnectionFactory.class); private final ALPNProcessor.Server alpnProcessor;
public ALPNServerConnectionFactory(String protocols) public ALPNServerConnectionFactory(String protocols)
{ {
@ -43,25 +44,34 @@ public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFact
public ALPNServerConnectionFactory(@Name("protocols") String... protocols) public ALPNServerConnectionFactory(@Name("protocols") String... protocols)
{ {
super("alpn", protocols); super("alpn", protocols);
try checkProtocolNegotiationAvailable();
{ Iterator<ALPNProcessor.Server> processors = ServiceLoader.load(ALPNProcessor.Server.class).iterator();
ClassLoader alpnClassLoader = ALPN.class.getClassLoader(); alpnProcessor = processors.hasNext() ? processors.next() : ALPNProcessor.Server.NOOP;
if (alpnClassLoader != null)
{
LOG.warn("ALPN must be in the boot classloader, not in: " + alpnClassLoader);
throw new IllegalStateException("ALPN must be in the boot classloader");
} }
}
catch (Throwable x) public ALPNProcessor.Server getALPNProcessor()
{ {
LOG.warn("ALPN not available", x); return alpnProcessor;
throw new IllegalStateException("ALPN not available", x);
}
} }
@Override @Override
protected AbstractConnection newServerConnection(Connector connector, EndPoint endPoint, SSLEngine engine, List<String> protocols, String defaultProtocol) 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); 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);
}
} }

View File

@ -1,4 +1,6 @@
<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> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
@ -12,4 +14,16 @@
<module>jetty-alpn-server</module> <module>jetty-alpn-server</module>
<module>jetty-alpn-client</module> <module>jetty-alpn-client</module>
</modules> </modules>
<profiles>
<profile>
<id>jdk9</id>
<activation>
<jdk>[1.9,)</jdk>
</activation>
<modules>
<module>jetty-alpn-java-client</module>
<module>jetty-alpn-java-server</module>
</modules>
</profile>
</profiles>
</project> </project>

View File

@ -38,22 +38,28 @@ import org.hamcrest.Matchers;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
/** /**
* This test class runs tests to make sure that hostname verification (http://www.ietf.org/rfc/rfc2818.txt * This test class runs tests to make sure that hostname verification (http://www.ietf.org/rfc/rfc2818.txt
* section 3.1) is configurable in SslContextFactory and works as expected. * section 3.1) is configurable in SslContextFactory and works as expected.
*/ */
@Ignore
public class HostnameVerificationTest public class HostnameVerificationTest
{ {
private SslContextFactory clientSslContextFactory = new SslContextFactory(); private SslContextFactory clientSslContextFactory = new SslContextFactory();
private Server server = new Server(); private Server server;
private HttpClient client; private HttpClient client;
private NetworkConnector connector; private NetworkConnector connector;
@Before @Before
public void setUp() throws Exception public void setUp() throws Exception
{ {
QueuedThreadPool serverThreads = new QueuedThreadPool();
serverThreads.setName("server");
server = new Server(serverThreads);
SslContextFactory serverSslContextFactory = new SslContextFactory(); SslContextFactory serverSslContextFactory = new SslContextFactory();
serverSslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); serverSslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
serverSslContextFactory.setKeyStorePassword("storepwd"); serverSslContextFactory.setKeyStorePassword("storepwd");
@ -74,10 +80,10 @@ public class HostnameVerificationTest
clientSslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); clientSslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
clientSslContextFactory.setKeyStorePassword("storepwd"); clientSslContextFactory.setKeyStorePassword("storepwd");
QueuedThreadPool executor = new QueuedThreadPool(); QueuedThreadPool clientThreads = new QueuedThreadPool();
executor.setName(executor.getName() + "-client"); clientThreads.setName("client");
client = new HttpClient(clientSslContextFactory); client = new HttpClient(clientSslContextFactory);
client.setExecutor(executor); client.setExecutor(clientThreads);
client.start(); client.start();
} }

View File

@ -258,8 +258,6 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
@Test @Test
public void testAbortOnCommitWithContent() throws Exception public void testAbortOnCommitWithContent() throws Exception
{
try (StacklessLogging suppressor = new StacklessLogging(org.eclipse.jetty.server.HttpChannel.class))
{ {
final AtomicReference<IOException> failure = new AtomicReference<>(); final AtomicReference<IOException> failure = new AtomicReference<>();
start(new AbstractHandler() start(new AbstractHandler()
@ -317,7 +315,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
Assert.assertEquals(0, connectionPool.getConnectionCount()); Assert.assertEquals(0, connectionPool.getConnectionCount());
Assert.assertEquals(0, connectionPool.getActiveConnections().size()); Assert.assertEquals(0, connectionPool.getActiveConnections().size());
Assert.assertEquals(0, connectionPool.getIdleConnections().size()); Assert.assertEquals(0, connectionPool.getIdleConnections().size());
}
} }
@Test @Test

View File

@ -1,18 +1,21 @@
<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"
<modelVersion>4.0.0</modelVersion> 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> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<version>9.4.1-SNAPSHOT</version> <version>9.4.1-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-distribution</artifactId> <artifactId>jetty-distribution</artifactId>
<name>Jetty :: Distribution Assemblies</name> <name>Jetty :: Distribution Assemblies</name>
<url>http://www.eclipse.org/jetty</url>
<packaging>pom</packaging> <packaging>pom</packaging>
<properties> <properties>
<assembly-directory>${basedir}/target/distribution</assembly-directory> <assembly-directory>${basedir}/target/distribution</assembly-directory>
<home-directory>${basedir}/target/home</home-directory> <home-directory>${basedir}/target/home</home-directory>
</properties> </properties>
<build> <build>
<plugins> <plugins>
<!-- <!--
@ -393,6 +396,7 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>

View File

@ -23,7 +23,6 @@ import org.eclipse.jetty.http2.HTTP2Cipher;
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.NegotiatingServerConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.ServerConnector;
@ -54,7 +53,6 @@ public class DrupalHTTP2FastCGIProxyServer
// HTTP2 factory // HTTP2 factory
HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(https_config); HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(https_config);
NegotiatingServerConnectionFactory.checkProtocolNegotiationAvailable();
ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory(); ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
alpn.setDefaultProtocol(h2.getProtocol()); alpn.setDefaultProtocol(h2.getProtocol());

View File

@ -27,7 +27,6 @@ import org.eclipse.jetty.http2.HTTP2Cipher;
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.NegotiatingServerConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.ServerConnector;
@ -61,7 +60,6 @@ public class WordPressHTTP2FastCGIProxyServer
// HTTP2 factory // HTTP2 factory
HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(https_config); HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(https_config);
NegotiatingServerConnectionFactory.checkProtocolNegotiationAvailable();
ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory(); ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
alpn.setDefaultProtocol(h2.getProtocol()); alpn.setDefaultProtocol(h2.getProtocol());

View File

@ -590,4 +590,21 @@
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
</dependencies> </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> </project>

View File

@ -26,6 +26,6 @@ http://www.apache.org/licenses/LICENSE-2.0.html
[ini-template] [ini-template]
## Hawt.io configuration ## Hawt.io configuration
-Dhawtio.authenticationEnabled=false -Dhawtio.authenticationEnabled?=false
-Dhawtio.dirname=/dirname -Dhawtio.dirname?=/dirname
-Dhawtio.config.dir=${jetty.base}/etc/hawtio -Dhawtio.config.dir?=${jetty.base}/etc/hawtio

View File

@ -156,6 +156,7 @@ public class HttpParser
private int _responseStatus; private int _responseStatus;
private int _headerBytes; private int _headerBytes;
private boolean _host; private boolean _host;
private boolean _headerComplete;
/* ------------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------------- */
private volatile State _state=State.START; private volatile State _state=State.START;
@ -730,6 +731,7 @@ public class HttpParser
setState(State.END); setState(State.END);
BufferUtil.clear(buffer); BufferUtil.clear(buffer);
handle=_handler.headerComplete()||handle; handle=_handler.headerComplete()||handle;
_headerComplete=true;
handle=_handler.messageComplete()||handle; handle=_handler.messageComplete()||handle;
return handle; return handle;
} }
@ -800,6 +802,7 @@ public class HttpParser
setState(State.END); setState(State.END);
BufferUtil.clear(buffer); BufferUtil.clear(buffer);
handle=_handler.headerComplete()||handle; handle=_handler.headerComplete()||handle;
_headerComplete=true;
handle=_handler.messageComplete()||handle; handle=_handler.messageComplete()||handle;
return handle; return handle;
} }
@ -1057,22 +1060,26 @@ public class HttpParser
case EOF_CONTENT: case EOF_CONTENT:
setState(State.EOF_CONTENT); setState(State.EOF_CONTENT);
handle=_handler.headerComplete()||handle; handle=_handler.headerComplete()||handle;
_headerComplete=true;
return handle; return handle;
case CHUNKED_CONTENT: case CHUNKED_CONTENT:
setState(State.CHUNKED_CONTENT); setState(State.CHUNKED_CONTENT);
handle=_handler.headerComplete()||handle; handle=_handler.headerComplete()||handle;
_headerComplete=true;
return handle; return handle;
case NO_CONTENT: case NO_CONTENT:
setState(State.END); setState(State.END);
handle=_handler.headerComplete()||handle; handle=_handler.headerComplete()||handle;
_headerComplete=true;
handle=_handler.messageComplete()||handle; handle=_handler.messageComplete()||handle;
return handle; return handle;
default: default:
setState(State.CONTENT); setState(State.CONTENT);
handle=_handler.headerComplete()||handle; handle=_handler.headerComplete()||handle;
_headerComplete=true;
return handle; return handle;
} }
} }
@ -1426,40 +1433,31 @@ public class HttpParser
LOG.warn("parse exception: {} in {} for {}",e.toString(),_state,_handler); LOG.warn("parse exception: {} in {} for {}",e.toString(),_state,_handler);
if (DEBUG) if (DEBUG)
LOG.debug(e); LOG.debug(e);
badMessage();
switch(_state)
{
case CLOSED:
break;
case CLOSE:
_handler.earlyEOF();
break;
default:
setState(State.CLOSE);
_handler.badMessage(400,"Bad Message "+e.toString());
}
} }
catch(Exception|Error e) catch(Exception|Error e)
{ {
BufferUtil.clear(buffer); BufferUtil.clear(buffer);
LOG.warn("parse exception: "+e.toString()+" for "+_handler,e); LOG.warn("parse exception: "+e.toString()+" for "+_handler,e);
badMessage();
switch(_state)
{
case CLOSED:
break;
case CLOSE:
_handler.earlyEOF();
break;
default:
setState(State.CLOSE);
_handler.badMessage(400,null);
}
} }
return false; return false;
} }
protected void badMessage()
{
if (_headerComplete)
{
_handler.earlyEOF();
}
else if (_state!=State.CLOSED)
{
setState(State.CLOSE);
_handler.badMessage(400,_requestHandler!=null?"Bad Request":"Bad Response");
}
}
protected boolean parseContent(ByteBuffer buffer) protected boolean parseContent(ByteBuffer buffer)
{ {
int remaining=buffer.remaining(); int remaining=buffer.remaining();
@ -1677,6 +1675,7 @@ public class HttpParser
_contentChunk=null; _contentChunk=null;
_headerBytes=0; _headerBytes=0;
_host=false; _host=false;
_headerComplete=false;
} }
/* ------------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------------- */

View File

@ -41,11 +41,18 @@ import org.eclipse.jetty.util.log.Logger;
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /** MIME Type enum and utilities
* *
*/ */
public class MimeTypes public class MimeTypes
{ {
/* ------------------------------------------------------------ */
private static final Logger LOG = Log.getLogger(MimeTypes.class);
private static final Trie<ByteBuffer> TYPES= new ArrayTrie<ByteBuffer>(512);
private static final Map<String,String> __dftMimeMap = new HashMap<String,String>();
private static final Map<String,String> __inferredEncodings = new HashMap<String,String>();
private static final Map<String,String> __assumedEncodings = new HashMap<String,String>();
public enum Type public enum Type
{ {
FORM_ENCODED("application/x-www-form-urlencoded"), FORM_ENCODED("application/x-www-form-urlencoded"),
@ -70,8 +77,8 @@ public class MimeTypes
TEXT_JSON_8859_1("text/json;charset=iso-8859-1",TEXT_JSON), TEXT_JSON_8859_1("text/json;charset=iso-8859-1",TEXT_JSON),
TEXT_JSON_UTF_8("text/json;charset=utf-8",TEXT_JSON), TEXT_JSON_UTF_8("text/json;charset=utf-8",TEXT_JSON),
APPLICATION_JSON_8859_1("text/json;charset=iso-8859-1",APPLICATION_JSON), APPLICATION_JSON_8859_1("application/json;charset=iso-8859-1",APPLICATION_JSON),
APPLICATION_JSON_UTF_8("text/json;charset=utf-8",APPLICATION_JSON); APPLICATION_JSON_UTF_8("application/json;charset=utf-8",APPLICATION_JSON);
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@ -177,12 +184,7 @@ public class MimeTypes
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
private static final Logger LOG = Log.getLogger(MimeTypes.class); public static final Trie<MimeTypes.Type> CACHE= new ArrayTrie<>(512);
public final static Trie<MimeTypes.Type> CACHE= new ArrayTrie<>(512);
private final static Trie<ByteBuffer> TYPES= new ArrayTrie<ByteBuffer>(512);
private final static Map<String,String> __dftMimeMap = new HashMap<String,String>();
private final static Map<String,String> __encodings = new HashMap<String,String>();
static static
{ {
for (MimeTypes.Type type : MimeTypes.Type.values()) for (MimeTypes.Type type : MimeTypes.Type.values())
@ -197,6 +199,9 @@ public class MimeTypes
CACHE.put(alt,type); CACHE.put(alt,type);
TYPES.put(alt,type.asBuffer()); TYPES.put(alt,type.asBuffer());
} }
if (type.isCharsetAssumed())
__assumedEncodings.put(type.asString(),type.getCharsetString());
} }
String resourceName = "org/eclipse/jetty/http/mime.properties"; String resourceName = "org/eclipse/jetty/http/mime.properties";
@ -240,7 +245,6 @@ public class MimeTypes
LOG.debug(e); LOG.debug(e);
} }
resourceName = "org/eclipse/jetty/http/encoding.properties"; resourceName = "org/eclipse/jetty/http/encoding.properties";
try (InputStream stream = MimeTypes.class.getClassLoader().getResourceAsStream(resourceName)) try (InputStream stream = MimeTypes.class.getClassLoader().getResourceAsStream(resourceName))
{ {
@ -254,13 +258,20 @@ public class MimeTypes
props.load(reader); props.load(reader);
props.stringPropertyNames().stream() props.stringPropertyNames().stream()
.filter(t->t!=null) .filter(t->t!=null)
.forEach(t->__encodings.put(t, props.getProperty(t))); .forEach(t->
{
String charset = props.getProperty(t);
if (charset.startsWith("-"))
__assumedEncodings.put(t, charset.substring(1));
else
__inferredEncodings.put(t, props.getProperty(t));
});
if (__encodings.size()==0) if (__inferredEncodings.size()==0)
{ {
LOG.warn("Empty encodings at {}", resourceName); LOG.warn("Empty encodings at {}", resourceName);
} }
else if (__encodings.size()<props.keySet().size()) else if ((__inferredEncodings.size()+__assumedEncodings.size())<props.keySet().size())
{ {
LOG.warn("Null or duplicate encodings in resource: {}", resourceName); LOG.warn("Null or duplicate encodings in resource: {}", resourceName);
} }
@ -312,6 +323,43 @@ public class MimeTypes
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** Get the MIME type by filename extension. /** Get the MIME type by filename extension.
* Lookup only the static default mime map.
* @param filename A file name
* @return MIME type matching the longest dot extension of the
* file name.
*/
public static String getDefaultMimeByExtension(String filename)
{
String type=null;
if (filename!=null)
{
int i=-1;
while(type==null)
{
i=filename.indexOf(".",i+1);
if (i<0 || i>=filename.length())
break;
String ext=StringUtil.asciiToLowerCase(filename.substring(i+1));
if (type==null)
type=__dftMimeMap.get(ext);
}
}
if (type==null)
{
if (type==null)
type=__dftMimeMap.get("*");
}
return type;
}
/* ------------------------------------------------------------ */
/** Get the MIME type by filename extension.
* Lookup the content and static default mime maps.
* @param filename A file name * @param filename A file name
* @return MIME type matching the longest dot extension of the * @return MIME type matching the longest dot extension of the
* file name. * file name.
@ -449,9 +497,42 @@ public class MimeTypes
return null; return null;
} }
public static String inferCharsetFromContentType(String value) /**
* Access a mutable map of mime type to the charset inferred from that content type.
* An inferred encoding is used by when encoding/decoding a stream and is
* explicitly set in any metadata (eg Content-Type).
* @return Map of mime type to charset
*/
public static Map<String,String> getInferredEncodings()
{ {
return __encodings.get(value); return __inferredEncodings;
}
/**
* Access a mutable map of mime type to the charset assumed for that content type.
* An assumed encoding is used by when encoding/decoding a stream, but is not
* explicitly set in any metadata (eg Content-Type).
* @return Map of mime type to charset
*/
public static Map<String,String> getAssumedEncodings()
{
return __inferredEncodings;
}
@Deprecated
public static String inferCharsetFromContentType(String contentType)
{
return getCharsetAssumedFromContentType(contentType);
}
public static String getCharsetInferredFromContentType(String contentType)
{
return __inferredEncodings.get(contentType);
}
public static String getCharsetAssumedFromContentType(String contentType)
{
return __assumedEncodings.get(contentType);
} }
public static String getContentTypeWithoutCharset(String value) public static String getContentTypeWithoutCharset(String value)
@ -545,4 +626,5 @@ public class MimeTypes
return builder.toString(); return builder.toString();
} }
} }

View File

@ -1,5 +1,11 @@
# Mapping of mime type to inferred or assumed charset
# inferred charsets are used for encoding/decoding and explicitly set in associated metadata
# assumed charsets are used for encoding/decoding, but are not set in associated metadata
# In this file, assumed charsets are indicatd with a leading '-'
text/html=utf-8 text/html=utf-8
text/plain=iso-8859-1 text/plain=iso-8859-1
text/xml=utf-8 text/xml=utf-8
text/json=utf-8
application/xhtml+xml=utf-8 application/xhtml+xml=utf-8
text/json=-utf-8
application/vnd.api+json=-utf-8

View File

@ -14,12 +14,6 @@
<bundle-symbolic-name>${project.groupId}.alpn.tests</bundle-symbolic-name> <bundle-symbolic-name>${project.groupId}.alpn.tests</bundle-symbolic-name>
</properties> </properties>
<profiles>
<profile>
<id>jdk8</id>
<activation>
<jdk>[1.8,1.9)</jdk>
</activation>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
@ -49,14 +43,11 @@
<plugin> <plugin>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<configuration> <configuration>
<argLine>-Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar <argLine>-Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar</argLine>
</argLine>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
</profile>
</profiles>
<dependencies> <dependencies>
<dependency> <dependency>
@ -69,7 +60,7 @@
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-server</artifactId> <artifactId>jetty-alpn-server</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>provided</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>

View File

@ -51,11 +51,12 @@ import org.eclipse.jetty.http2.api.server.ServerSessionListener;
import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.DataFrame;
import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.http2.frames.ResetFrame;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.HttpOutput; import org.eclipse.jetty.server.HttpOutput;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.FutureCallback; import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.StacklessLogging; import org.eclipse.jetty.util.log.StacklessLogging;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.junit.Assert; import org.junit.Assert;
@ -409,7 +410,7 @@ public class StreamResetTest extends AbstractTest
@Test @Test
public void testServerExceptionConsumesQueuedData() throws Exception public void testServerExceptionConsumesQueuedData() throws Exception
{ {
try (StacklessLogging suppressor = new StacklessLogging(ServletHandler.class)) try (StacklessLogging suppressor = new StacklessLogging(HttpChannel.class))
{ {
start(new HttpServlet() start(new HttpServlet()
{ {
@ -430,6 +431,8 @@ public class StreamResetTest extends AbstractTest
}); });
Session client = newClient(new Session.Listener.Adapter()); Session client = newClient(new Session.Listener.Adapter());
Log.getLogger(HttpChannel.class).info("Expecting java.lang.IllegalStateException: explictly_thrown_by_test");
MetaData.Request request = newRequest("GET", new HttpFields()); MetaData.Request request = newRequest("GET", new HttpFields());
HeadersFrame frame = new HeadersFrame(request, null, false); HeadersFrame frame = new HeadersFrame(request, null, false);
FuturePromise<Stream> promise = new FuturePromise<>(); FuturePromise<Stream> promise = new FuturePromise<>();

View File

@ -49,13 +49,31 @@
<plugin> <plugin>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<configuration> <configuration>
<argLine>-Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar <argLine>-Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar</argLine>
</argLine>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
</profile> </profile>
<profile>
<id>jdk9</id>
<activation>
<jdk>[1.9,)</jdk>
</activation>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-java-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-java-server</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
</profiles> </profiles>
<dependencies> <dependencies>

View File

@ -13,7 +13,6 @@
<name>Jetty :: HTTP2</name> <name>Jetty :: HTTP2</name>
<modules> <modules>
<module>http2-alpn-tests</module>
<module>http2-client</module> <module>http2-client</module>
<module>http2-common</module> <module>http2-common</module>
<module>http2-hpack</module> <module>http2-hpack</module>
@ -21,4 +20,16 @@
<module>http2-server</module> <module>http2-server</module>
</modules> </modules>
<profiles>
<profile>
<id>jdk8</id>
<activation>
<jdk>[1.8,1.9)</jdk>
</activation>
<modules>
<module>http2-alpn-tests</module>
</modules>
</profile>
</profiles>
</project> </project>

View File

@ -27,7 +27,7 @@ import java.io.EOFException;
* the connection, vs and EOF thrown by some application talking to some other file/socket etc. * the connection, vs and EOF thrown by some application talking to some other file/socket etc.
* The only difference in handling is that Jetty EOFs are logged less verbosely. * The only difference in handling is that Jetty EOFs are logged less verbosely.
*/ */
public class EofException extends EOFException public class EofException extends EOFException implements QuietException
{ {
public EofException() public EofException()
{ {

View File

@ -0,0 +1,29 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.io;
/* ------------------------------------------------------------ */
/** A Quiet Exception.
* <p> Exception classes that extend this interface will be logged
* less verbosely.
*/
public interface QuietException
{
}

View File

@ -0,0 +1,52 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.io.ssl;
import java.util.List;
import javax.net.ssl.SSLEngine;
public interface ALPNProcessor
{
public interface Server
{
public static final ALPNProcessor.Server NOOP = new ALPNProcessor.Server()
{
};
public default void configure(SSLEngine sslEngine)
{
}
}
public interface Client
{
public static final Client NOOP = new Client()
{
};
public default void configure(SSLEngine sslEngine, List<String> protocols)
{
}
public default void process(SSLEngine sslEngine)
{
}
}
}

View File

@ -63,11 +63,11 @@ public class SslClientConnectionFactory implements ClientConnectionFactory
SslConnection sslConnection = newSslConnection(byteBufferPool, executor, endPoint, engine); SslConnection sslConnection = newSslConnection(byteBufferPool, executor, endPoint, engine);
endPoint.setConnection(sslConnection); endPoint.setConnection(sslConnection);
customize(sslConnection, context);
EndPoint appEndPoint = sslConnection.getDecryptedEndPoint(); EndPoint appEndPoint = sslConnection.getDecryptedEndPoint();
appEndPoint.setConnection(connectionFactory.newConnection(appEndPoint, context)); appEndPoint.setConnection(connectionFactory.newConnection(appEndPoint, context));
customize(sslConnection, context);
return sslConnection; return sslConnection;
} }

View File

@ -579,6 +579,7 @@ public class SslConnection extends AbstractConnection
{ {
synchronized (this) synchronized (this)
{ {
Throwable failure = null;
try try
{ {
// Do we already have some decrypted data? // Do we already have some decrypted data?
@ -773,6 +774,7 @@ public class SslConnection extends AbstractConnection
catch (SSLHandshakeException x) catch (SSLHandshakeException x)
{ {
notifyHandshakeFailed(_sslEngine, x); notifyHandshakeFailed(_sslEngine, x);
failure = x;
throw x; throw x;
} }
catch (SSLException x) catch (SSLException x)
@ -782,6 +784,12 @@ public class SslConnection extends AbstractConnection
x = (SSLException)new SSLHandshakeException(x.getMessage()).initCause(x); x = (SSLException)new SSLHandshakeException(x.getMessage()).initCause(x);
notifyHandshakeFailed(_sslEngine, x); notifyHandshakeFailed(_sslEngine, x);
} }
failure = x;
throw x;
}
catch (Throwable x)
{
failure = x;
throw x; throw x;
} }
finally finally
@ -790,7 +798,7 @@ public class SslConnection extends AbstractConnection
if (_flushRequiresFillToProgress) if (_flushRequiresFillToProgress)
{ {
_flushRequiresFillToProgress = false; _flushRequiresFillToProgress = false;
getExecutor().execute(_runCompleteWrite); getExecutor().execute(failure == null ? _runCompleteWrite : new FailWrite(failure));
} }
if (_encryptedInput != null && !_encryptedInput.hasRemaining()) if (_encryptedInput != null && !_encryptedInput.hasRemaining())
@ -1132,5 +1140,28 @@ public class SslConnection extends AbstractConnection
{ {
return super.toString()+"->"+getEndPoint().toString(); return super.toString()+"->"+getEndPoint().toString();
} }
private class FailWrite extends RunnableTask
{
private final Throwable failure;
private FailWrite(Throwable failure)
{
super("runFailWrite");
this.failure = failure;
}
@Override
public void run()
{
getWriteFlusher().onFail(failure);
}
@Override
public InvocationType getInvocationType()
{
return getWriteFlusher().getCallbackInvocationType();
}
}
} }
} }

View File

@ -23,6 +23,24 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<profiles>
<profile>
<id>jdk9</id>
<activation>
<jdk>[1.9,)</jdk>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>@{argLine} --add-modules java.se.ee</argLine>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
@ -38,7 +56,6 @@
<groupId>org.eclipse.jetty.orbit</groupId> <groupId>org.eclipse.jetty.orbit</groupId>
<artifactId>javax.security.auth.message</artifactId> <artifactId>javax.security.auth.message</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.geronimo.components</groupId> <groupId>org.apache.geronimo.components</groupId>
<artifactId>geronimo-jaspi</artifactId> <artifactId>geronimo-jaspi</artifactId>

View File

@ -1,15 +1,19 @@
<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"
<modelVersion>4.0.0</modelVersion> 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> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<version>9.4.1-SNAPSHOT</version> <version>9.4.1-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.osgi</groupId> <groupId>org.eclipse.jetty.osgi</groupId>
<artifactId>jetty-osgi-project</artifactId> <artifactId>jetty-osgi-project</artifactId>
<name>Jetty :: OSGi</name> <name>Jetty :: OSGi</name>
<url>http://www.eclipse.org/jetty</url> <url>http://www.eclipse.org/jetty</url>
<packaging>pom</packaging> <packaging>pom</packaging>
<properties> <properties>
<osgi-version>3.6.0.v20100517</osgi-version> <osgi-version>3.6.0.v20100517</osgi-version>
<osgi-services-version>3.2.100.v20100503</osgi-services-version> <osgi-services-version>3.2.100.v20100503</osgi-services-version>
@ -18,6 +22,7 @@
<logback-version>0.9.29</logback-version> <logback-version>0.9.29</logback-version>
<slf4j-version>1.6.1</slf4j-version> <slf4j-version>1.6.1</slf4j-version>
</properties> </properties>
<modules> <modules>
<module>jetty-osgi-boot</module> <module>jetty-osgi-boot</module>
<module>jetty-osgi-boot-jsp</module> <module>jetty-osgi-boot-jsp</module>
@ -28,8 +33,20 @@
<module>test-jetty-osgi-fragment</module> <module>test-jetty-osgi-fragment</module>
<module>test-jetty-osgi-server</module> <module>test-jetty-osgi-server</module>
<module>jetty-osgi-alpn</module> <module>jetty-osgi-alpn</module>
</modules>
<profiles>
<profile>
<id>jdk8</id>
<activation>
<jdk>[1.8,1.9)</jdk>
</activation>
<modules>
<module>test-jetty-osgi</module> <module>test-jetty-osgi</module>
</modules> </modules>
</profile>
</profiles>
<build> <build>
<resources> <resources>
<resource> <resource>
@ -79,6 +96,7 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
@ -180,4 +198,5 @@
</dependency> </dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
</project> </project>

View File

@ -32,15 +32,13 @@
<version>${exam.version}</version> <version>${exam.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- Use the forked container so we can pass it system properties eg for alpn -->
<!-- use the forked container so we can pass it system properties eg for alpn -->
<dependency> <dependency>
<groupId>org.ops4j.pax.exam</groupId> <groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-container-forked</artifactId> <artifactId>pax-exam-container-forked</artifactId>
<version>${exam.version}</version> <version>${exam.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.ops4j.pax.exam</groupId> <groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-junit4</artifactId> <artifactId>pax-exam-junit4</artifactId>
@ -126,7 +124,6 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty.osgi</groupId> <groupId>org.eclipse.jetty.osgi</groupId>
<artifactId>jetty-httpservice</artifactId> <artifactId>jetty-httpservice</artifactId>
@ -139,14 +136,12 @@
<artifactId>jetty-osgi-servlet-api</artifactId> <artifactId>jetty-osgi-servlet-api</artifactId>
<version>3.1.0.M3</version> <version>3.1.0.M3</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.geronimo.specs</groupId> <groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jta_1.1_spec</artifactId> <artifactId>geronimo-jta_1.1_spec</artifactId>
<version>1.1.1</version> <version>1.1.1</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.geronimo.specs</groupId> <groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-atinject_1.0_spec</artifactId> <artifactId>geronimo-atinject_1.0_spec</artifactId>
@ -159,7 +154,6 @@
<version>1.0.1</version> <version>1.0.1</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.glassfish.web</groupId> <groupId>org.glassfish.web</groupId>
<artifactId>javax.servlet.jsp.jstl</artifactId> <artifactId>javax.servlet.jsp.jstl</artifactId>
@ -183,7 +177,6 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty.orbit</groupId> <groupId>org.eclipse.jetty.orbit</groupId>
<artifactId>javax.servlet.jsp.jstl</artifactId> <artifactId>javax.servlet.jsp.jstl</artifactId>
@ -330,7 +323,6 @@
<artifactId>jetty-schemas</artifactId> <artifactId>jetty-schemas</artifactId>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-plus</artifactId> <artifactId>jetty-plus</artifactId>
@ -346,7 +338,6 @@
<classifier>webbundle</classifier> <classifier>webbundle</classifier>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty.tests</groupId> <groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-spec-webapp</artifactId> <artifactId>test-spec-webapp</artifactId>
@ -354,14 +345,12 @@
<type>war</type> <type>war</type>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty.tests</groupId> <groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-container-initializer</artifactId> <artifactId>test-container-initializer</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty.osgi</groupId> <groupId>org.eclipse.jetty.osgi</groupId>
<artifactId>test-jetty-osgi-fragment</artifactId> <artifactId>test-jetty-osgi-fragment</artifactId>
@ -379,7 +368,6 @@
<artifactId>test-mock-resources</artifactId> <artifactId>test-mock-resources</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty.osgi</groupId> <groupId>org.eclipse.jetty.osgi</groupId>
<artifactId>test-jetty-osgi-context</artifactId> <artifactId>test-jetty-osgi-context</artifactId>
@ -404,14 +392,13 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<configuration> <configuration>
<!-- No point defining -Xbootclasspath as the actual OSGi VM is run as a forked process by pax-exam --> <!-- 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 configued inside tests --> <!-- 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</argLine> <argLine>-Dmortbay-alpn-boot=${settings.localRepository}/org/mortbay/jetty/alpn/alpn-boot/${alpn.version}/alpn-boot-${alpn.version}.jar</argLine>
</configuration> </configuration>
</plugin> </plugin>
@ -458,5 +445,4 @@
</plugins> </plugins>
</pluginManagement> </pluginManagement>
</build> </build>
</project> </project>

View File

@ -44,11 +44,11 @@ import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.util.BytesContentProvider; import org.eclipse.jetty.client.util.BytesContentProvider;
import org.eclipse.jetty.client.util.DeferredContentProvider; import org.eclipse.jetty.client.util.DeferredContentProvider;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.toolchain.test.TestTracker; import org.eclipse.jetty.toolchain.test.TestTracker;
import org.eclipse.jetty.toolchain.test.http.SimpleHttpParser; import org.eclipse.jetty.toolchain.test.http.SimpleHttpParser;
@ -93,7 +93,7 @@ public class ProxyServletFailureTest
private void prepareProxy() throws Exception private void prepareProxy() throws Exception
{ {
prepareProxy(new HashMap<String, String>()); prepareProxy(new HashMap<>());
} }
private void prepareProxy(Map<String, String> initParams) throws Exception private void prepareProxy(Map<String, String> initParams) throws Exception
@ -257,7 +257,7 @@ public class ProxyServletFailureTest
public void testProxyRequestStallsContentServerIdlesTimeout() throws Exception public void testProxyRequestStallsContentServerIdlesTimeout() throws Exception
{ {
final byte[] content = new byte[]{'C', '0', 'F', 'F', 'E', 'E'}; final byte[] content = new byte[]{'C', '0', 'F', 'F', 'E', 'E'};
int expected = -1; int expected;
if (proxyServlet instanceof AsyncProxyServlet) if (proxyServlet instanceof AsyncProxyServlet)
{ {
// TODO should this be a 502 also??? // TODO should this be a 502 also???
@ -308,7 +308,7 @@ public class ProxyServletFailureTest
long idleTimeout = 1000; long idleTimeout = 1000;
serverConnector.setIdleTimeout(idleTimeout); serverConnector.setIdleTimeout(idleTimeout);
try(StacklessLogging stackless = new StacklessLogging(ServletHandler.class)) try(StacklessLogging stackless = new StacklessLogging(HttpChannel.class))
{ {
ContentResponse response = client.newRequest("localhost", serverConnector.getLocalPort()) ContentResponse response = client.newRequest("localhost", serverConnector.getLocalPort())
.content(new BytesContentProvider(content)) .content(new BytesContentProvider(content))
@ -397,7 +397,7 @@ public class ProxyServletFailureTest
@Test @Test
public void testServerException() throws Exception public void testServerException() throws Exception
{ {
try (StacklessLogging stackless = new StacklessLogging(ServletHandler.class)) try (StacklessLogging stackless = new StacklessLogging(HttpChannel.class))
{ {
prepareProxy(); prepareProxy();
prepareServer(new HttpServlet() prepareServer(new HttpServlet()

View File

@ -375,7 +375,7 @@ public class CachedContentFactory implements HttpContent.ContentFactory
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
protected ByteBuffer getDirectBuffer(Resource resource) protected ByteBuffer getMappedBuffer(Resource resource)
{ {
// Only use file mapped buffers for cached resources, otherwise too much virtual memory commitment for // Only use file mapped buffers for cached resources, otherwise too much virtual memory commitment for
// a non shared resource. Also ignore max buffer size // a non shared resource. Also ignore max buffer size
@ -383,14 +383,26 @@ public class CachedContentFactory implements HttpContent.ContentFactory
{ {
if (_useFileMappedBuffer && resource.getFile()!=null && resource.length()<Integer.MAX_VALUE) if (_useFileMappedBuffer && resource.getFile()!=null && resource.length()<Integer.MAX_VALUE)
return BufferUtil.toMappedBuffer(resource.getFile()); return BufferUtil.toMappedBuffer(resource.getFile());
}
catch(IOException|IllegalArgumentException e)
{
LOG.warn(e);
}
return null;
}
/* ------------------------------------------------------------ */
protected ByteBuffer getDirectBuffer(Resource resource)
{
try
{
return BufferUtil.toBuffer(resource,true); return BufferUtil.toBuffer(resource,true);
} }
catch(IOException|IllegalArgumentException e) catch(IOException|IllegalArgumentException e)
{ {
LOG.warn(e); LOG.warn(e);
return null;
} }
return null;
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@ -524,6 +536,7 @@ public class CachedContentFactory implements HttpContent.ContentFactory
_cachedSize.addAndGet(-BufferUtil.length(indirect)); _cachedSize.addAndGet(-BufferUtil.length(indirect));
ByteBuffer direct=_directBuffer.get(); ByteBuffer direct=_directBuffer.get();
if (direct!=null && !BufferUtil.isMappedBuffer(direct) && _directBuffer.compareAndSet(direct,null)) if (direct!=null && !BufferUtil.isMappedBuffer(direct) && _directBuffer.compareAndSet(direct,null))
_cachedSize.addAndGet(-BufferUtil.length(direct)); _cachedSize.addAndGet(-BufferUtil.length(direct));
@ -625,15 +638,15 @@ public class CachedContentFactory implements HttpContent.ContentFactory
ByteBuffer buffer = _directBuffer.get(); ByteBuffer buffer = _directBuffer.get();
if (buffer==null) if (buffer==null)
{ {
ByteBuffer buffer2=CachedContentFactory.this.getDirectBuffer(_resource); ByteBuffer mapped = CachedContentFactory.this.getMappedBuffer(_resource);
ByteBuffer direct = mapped==null?CachedContentFactory.this.getDirectBuffer(_resource):mapped;
if (buffer2==null) if (direct==null)
LOG.warn("Could not load "+this); LOG.warn("Could not load "+this);
else if (_directBuffer.compareAndSet(null,buffer2)) else if (_directBuffer.compareAndSet(null,direct))
{ {
buffer=buffer2; buffer=direct;
if (mapped==null && _cachedSize.addAndGet(BufferUtil.length(buffer))>_maxCacheSize)
if (!BufferUtil.isMappedBuffer(buffer) && _cachedSize.addAndGet(BufferUtil.length(buffer))>_maxCacheSize)
shrinkCache(); shrinkCache();
} }
else else

View File

@ -18,6 +18,9 @@
package org.eclipse.jetty.server; package org.eclipse.jetty.server;
import static javax.servlet.RequestDispatcher.ERROR_EXCEPTION;
import static javax.servlet.RequestDispatcher.ERROR_STATUS_CODE;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -39,6 +42,7 @@ import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.ChannelEndPoint; import org.eclipse.jetty.io.ChannelEndPoint;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.QuietException;
import org.eclipse.jetty.io.RuntimeIOException; import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.server.HttpChannelState.Action; import org.eclipse.jetty.server.HttpChannelState.Action;
import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler;
@ -50,9 +54,6 @@ import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.Scheduler; import org.eclipse.jetty.util.thread.Scheduler;
import static javax.servlet.RequestDispatcher.ERROR_EXCEPTION;
import static javax.servlet.RequestDispatcher.ERROR_STATUS_CODE;
/** /**
* HttpChannel represents a single endpoint for HTTP semantic processing. * HttpChannel represents a single endpoint for HTTP semantic processing.
@ -484,7 +485,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
if (failure instanceof RuntimeIOException) if (failure instanceof RuntimeIOException)
failure = failure.getCause(); failure = failure.getCause();
if (failure instanceof QuietServletException || !getServer().isRunning()) if (failure instanceof QuietException || !getServer().isRunning())
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug(_request.getRequestURI(), failure); LOG.debug(_request.getRequestURI(), failure);

View File

@ -219,12 +219,16 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque
@Override @Override
public void earlyEOF() public void earlyEOF()
{ {
_httpConnection.getGenerator().setPersistent(false);
// If we have no request yet, just close // If we have no request yet, just close
if (_metadata.getMethod() == null) if (_metadata.getMethod() == null)
_httpConnection.close(); _httpConnection.close();
else if (onEarlyEOF()) else if (onEarlyEOF() || _delayedForContent)
{
_delayedForContent = false;
handle(); handle();
} }
}
@Override @Override
public boolean content(ByteBuffer content) public boolean content(ByteBuffer content)

View File

@ -19,7 +19,6 @@
package org.eclipse.jetty.server; package org.eclipse.jetty.server;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -34,23 +33,25 @@ import org.eclipse.jetty.io.ssl.SslConnection;
public abstract class NegotiatingServerConnectionFactory extends AbstractConnectionFactory public abstract class NegotiatingServerConnectionFactory extends AbstractConnectionFactory
{ {
public static void checkProtocolNegotiationAvailable() public static void checkProtocolNegotiationAvailable()
{
if (!isAvailableInBootClassPath("org.eclipse.jetty.alpn.ALPN"))
throw new IllegalStateException("No ALPN classes available");
}
private static boolean isAvailableInBootClassPath(String className)
{ {
try try
{ {
Class<?> klass = ClassLoader.getSystemClassLoader().loadClass(className); String javaVersion = System.getProperty("java.version");
String alpnClassName = "org.eclipse.jetty.alpn.ALPN";
if (javaVersion.startsWith("1."))
{
Class<?> klass = ClassLoader.getSystemClassLoader().loadClass(alpnClassName);
if (klass.getClassLoader() != null) if (klass.getClassLoader() != null)
throw new IllegalStateException(className + " must be on JVM boot classpath"); throw new IllegalStateException(alpnClassName + " must be on JVM boot classpath");
return true; }
else
{
NegotiatingServerConnectionFactory.class.getClassLoader().loadClass(alpnClassName);
}
} }
catch (ClassNotFoundException x) catch (ClassNotFoundException x)
{ {
return false; throw new IllegalStateException("No ALPN classes available");
} }
} }

View File

@ -20,6 +20,8 @@ package org.eclipse.jetty.server;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import org.eclipse.jetty.io.QuietException;
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** A ServletException that is logged less verbosely than /** A ServletException that is logged less verbosely than
@ -29,7 +31,7 @@ import javax.servlet.ServletException;
* than a stack trace. * than a stack trace.
* </p> * </p>
*/ */
public class QuietServletException extends ServletException public class QuietServletException extends ServletException implements QuietException
{ {
public QuietServletException() public QuietServletException()
{ {

View File

@ -399,22 +399,11 @@ public class ResourceService
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("welcome={}",welcome); LOG.debug("welcome={}",welcome);
if (_redirectWelcome)
{ RequestDispatcher dispatcher=_redirectWelcome?null:request.getRequestDispatcher(welcome);
// Redirect to the index
response.setContentLength(0);
String q=request.getQueryString();
if (q!=null&&q.length()!=0)
response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(request.getContextPath(),welcome)+"?"+q));
else
response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(request.getContextPath(),welcome)));
}
else
{
// Forward to the index
RequestDispatcher dispatcher=request.getRequestDispatcher(welcome);
if (dispatcher!=null) if (dispatcher!=null)
{ {
// Forward to the index
if (included) if (included)
dispatcher.include(request,response); dispatcher.include(request,response);
else else
@ -423,6 +412,15 @@ public class ResourceService
dispatcher.forward(request,response); dispatcher.forward(request,response);
} }
} }
else
{
// Redirect to the index
response.setContentLength(0);
String q=request.getQueryString();
if (q!=null&&q.length()!=0)
response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(request.getContextPath(),welcome)+"?"+q));
else
response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(request.getContextPath(),welcome)));
} }
return; return;
} }

View File

@ -797,7 +797,12 @@ public class Response implements HttpServletResponse
public String getCharacterEncoding() public String getCharacterEncoding()
{ {
if (_characterEncoding == null) if (_characterEncoding == null)
{
String encoding = MimeTypes.getCharsetAssumedFromContentType(_contentType);
if (encoding!=null)
return encoding;
_characterEncoding = StringUtil.__ISO_8859_1; _characterEncoding = StringUtil.__ISO_8859_1;
}
return _characterEncoding; return _characterEncoding;
} }
@ -837,12 +842,16 @@ public class Response implements HttpServletResponse
encoding=_mimeType.getCharsetString(); encoding=_mimeType.getCharsetString();
else else
{ {
encoding = MimeTypes.inferCharsetFromContentType(_contentType); encoding = MimeTypes.getCharsetAssumedFromContentType(_contentType);
if (encoding == null)
{
encoding = MimeTypes.getCharsetInferredFromContentType(_contentType);
if (encoding == null) if (encoding == null)
encoding = StringUtil.__ISO_8859_1; encoding = StringUtil.__ISO_8859_1;
setCharacterEncoding(encoding,EncodingFrom.INFERRED); setCharacterEncoding(encoding,EncodingFrom.INFERRED);
} }
} }
}
Locale locale = getLocale(); Locale locale = getLocale();

View File

@ -150,7 +150,7 @@ public class BufferedResponseHandler extends HandlerWrapper
} }
// If the mime type is known from the path, then apply mime type filtering // If the mime type is known from the path, then apply mime type filtering
String mimeType = context==null?null:context.getMimeType(path); String mimeType = context==null?MimeTypes.getDefaultMimeByExtension(path):context.getMimeType(path);
if (mimeType!=null) if (mimeType!=null)
{ {
mimeType = MimeTypes.getContentTypeWithoutCharset(mimeType); mimeType = MimeTypes.getContentTypeWithoutCharset(mimeType);

View File

@ -394,6 +394,7 @@ public class ResourceHandler extends HandlerWrapper implements ResourceFactory,W
_resourceService.setCacheControl(new PreEncodedHttpField(HttpHeader.CACHE_CONTROL,cacheControl)); _resourceService.setCacheControl(new PreEncodedHttpField(HttpHeader.CACHE_CONTROL,cacheControl));
} }
/* ------------------------------------------------------------ */
/** /**
* @param dirAllowed * @param dirAllowed
* If true, directory listings are returned if no welcome file is found. Else 403 Forbidden. * If true, directory listings are returned if no welcome file is found. Else 403 Forbidden.
@ -486,6 +487,7 @@ public class ResourceHandler extends HandlerWrapper implements ResourceFactory,W
{ {
} }
/* ------------------------------------------------------------ */
/** /**
* @param pathInfoOnly * @param pathInfoOnly
* true, only the path info will be applied to the resourceBase * true, only the path info will be applied to the resourceBase
@ -495,9 +497,12 @@ public class ResourceHandler extends HandlerWrapper implements ResourceFactory,W
_resourceService.setPathInfoOnly(pathInfoOnly); _resourceService.setPathInfoOnly(pathInfoOnly);
} }
/* ------------------------------------------------------------ */
/** /**
* @param redirectWelcome * @param redirectWelcome
* If true, welcome files are redirected rather than forwarded to. * If true, welcome files are redirected rather than forwarded to.
* redirection is always used if the ResourceHandler is not scoped by
* a ContextHandler
*/ */
public void setRedirectWelcome(boolean redirectWelcome) public void setRedirectWelcome(boolean redirectWelcome)
{ {

View File

@ -20,9 +20,12 @@ package org.eclipse.jetty.server.handler.gzip;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Set; import java.util.Set;
import java.util.zip.Deflater; import java.util.zip.Deflater;
import javax.servlet.DispatcherType;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -66,6 +69,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
private boolean _checkGzExists = true; private boolean _checkGzExists = true;
private boolean _syncFlush = false; private boolean _syncFlush = false;
private int _inflateBufferSize = -1; private int _inflateBufferSize = -1;
private EnumSet<DispatcherType> _dispatchers = EnumSet.of(DispatcherType.REQUEST);
// non-static, as other GzipHandler instances may have different configurations // non-static, as other GzipHandler instances may have different configurations
private final ThreadLocal<Deflater> _deflater = new ThreadLocal<>(); private final ThreadLocal<Deflater> _deflater = new ThreadLocal<>();
@ -130,6 +134,25 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
_methods.exclude(m); _methods.exclude(m);
} }
/* ------------------------------------------------------------ */
public EnumSet<DispatcherType> getDispatcherTypes()
{
return _dispatchers;
}
/* ------------------------------------------------------------ */
public void setDispatcherTypes(EnumSet<DispatcherType> dispatchers)
{
_dispatchers = dispatchers;
}
/* ------------------------------------------------------------ */
public void setDispatcherTypes(DispatcherType... dispatchers)
{
_dispatchers = EnumSet.copyOf(Arrays.asList(dispatchers));
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Set the mime types. * Set the mime types.
@ -395,6 +418,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
return _minGzipSize; return _minGzipSize;
} }
/* ------------------------------------------------------------ */
protected HttpField getVaryField() protected HttpField getVaryField()
{ {
return _vary; return _vary;
@ -429,6 +453,13 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
String path = context==null?baseRequest.getRequestURI():URIUtil.addPaths(baseRequest.getServletPath(),baseRequest.getPathInfo()); String path = context==null?baseRequest.getRequestURI():URIUtil.addPaths(baseRequest.getServletPath(),baseRequest.getPathInfo());
LOG.debug("{} handle {} in {}",this,baseRequest,context); LOG.debug("{} handle {} in {}",this,baseRequest,context);
if (!_dispatchers.contains(baseRequest.getDispatcherType()))
{
LOG.debug("{} excluded by dispatcherType {}",this,baseRequest.getDispatcherType());
_handler.handle(target,baseRequest, request, response);
return;
}
// Handle request inflation // Handle request inflation
if (_inflateBufferSize>0) if (_inflateBufferSize>0)
{ {
@ -442,8 +473,8 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
} }
} }
HttpOutput out = baseRequest.getResponse().getHttpOutput();
// Are we already being gzipped? // Are we already being gzipped?
HttpOutput out = baseRequest.getResponse().getHttpOutput();
HttpOutput.Interceptor interceptor = out.getInterceptor(); HttpOutput.Interceptor interceptor = out.getInterceptor();
while (interceptor!=null) while (interceptor!=null)
{ {
@ -474,7 +505,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
} }
// Exclude non compressible mime-types known from URI extension. - no Vary because no matter what client, this URI is always excluded // Exclude non compressible mime-types known from URI extension. - no Vary because no matter what client, this URI is always excluded
String mimeType = context==null?null:context.getMimeType(path); String mimeType = context==null?MimeTypes.getDefaultMimeByExtension(path):context.getMimeType(path);
if (mimeType!=null) if (mimeType!=null)
{ {
mimeType = MimeTypes.getContentTypeWithoutCharset(mimeType); mimeType = MimeTypes.getContentTypeWithoutCharset(mimeType);

View File

@ -298,6 +298,7 @@ public class AsyncRequestReadTest
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
assertThat(in.readLine(),containsString("HTTP/1.1 200 OK")); assertThat(in.readLine(),containsString("HTTP/1.1 200 OK"));
assertThat(in.readLine(),containsString("Content-Length:")); assertThat(in.readLine(),containsString("Content-Length:"));
assertThat(in.readLine(),containsString("Connection: close"));
assertThat(in.readLine(),containsString("Server:")); assertThat(in.readLine(),containsString("Server:"));
in.readLine(); in.readLine();
assertThat(in.readLine(),containsString("XXXXXXX")); assertThat(in.readLine(),containsString("XXXXXXX"));

View File

@ -216,7 +216,10 @@ public class DumpHandler extends AbstractHandler.ErrorDispatchHandler
} }
catch(IOException e) catch(IOException e)
{ {
e.printStackTrace(); if (LOG.isDebugEnabled())
LOG.warn(e);
else
LOG.warn(e.toString());
writer.write(e.toString()); writer.write(e.toString());
} }
} }

View File

@ -582,6 +582,7 @@ public class HttpConnectionTest
checkContains(response,offset,"12345"); checkContains(response,offset,"12345");
offset=0; offset=0;
Log.getLogger(DumpHandler.class).info("Expecting java.io.UnsupportedEncodingException");
response=connector.getResponse("GET /R1 HTTP/1.1\r\n"+ response=connector.getResponse("GET /R1 HTTP/1.1\r\n"+
"Host: localhost\r\n"+ "Host: localhost\r\n"+
"Transfer-Encoding: chunked\r\n"+ "Transfer-Encoding: chunked\r\n"+
@ -592,6 +593,7 @@ public class HttpConnectionTest
"12345\r\n"+ "12345\r\n"+
"0;\r\n" + "0;\r\n" +
"\r\n"); "\r\n");
offset = checkContains(response,offset,"HTTP/1.1 200"); offset = checkContains(response,offset,"HTTP/1.1 200");
offset = checkContains(response,offset,"encoding=unknown"); offset = checkContains(response,offset,"encoding=unknown");
offset = checkContains(response,offset,"/R1"); offset = checkContains(response,offset,"/R1");

View File

@ -49,6 +49,7 @@ import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.AbstractHandler;
@ -695,6 +696,54 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
} }
} }
@Test
public void testBlockingReadBadChunk() throws Exception
{
configureServer(new ReadHandler());
try (Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort()))
{
client.setSoTimeout(600000);
OutputStream os = client.getOutputStream();
InputStream is = client.getInputStream();
os.write((
"GET /data HTTP/1.1\r\n" +
"host: " + _serverURI.getHost() + ":" + _serverURI.getPort() + "\r\n" +
"content-type: unknown\r\n" +
"transfer-encoding: chunked\r\n" +
"\r\n"
).getBytes());
os.flush();
Thread.sleep(50);
os.write((
"a\r\n" +
"123456890\r\n"
).getBytes());
os.flush();
Thread.sleep(50);
os.write((
"4\r\n" +
"abcd\r\n"
).getBytes());
os.flush();
Thread.sleep(50);
os.write((
"X\r\n" +
"abcd\r\n"
).getBytes());
os.flush();
HttpTester.Response response = HttpTester.parseResponse(HttpTester.from(is));
assertThat(response.getStatus(),is(200));
assertThat(response.getContent(),containsString("EofException"));
assertThat(response.getContent(),containsString("Early EOF"));
}
}
@Test @Test
public void testBlockingWhileWritingResponseContent() throws Exception public void testBlockingWhileWritingResponseContent() throws Exception
{ {

View File

@ -187,6 +187,27 @@ public class HttpServerTestFixture
} }
} }
protected static class ReadHandler extends AbstractHandler
{
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
response.setStatus(200);
try
{
InputStream in = request.getInputStream();
String input= IO.toString(in);
response.getWriter().printf("read %d%n",input.length());
}
catch(Exception e)
{
response.getWriter().printf("caught %s%n",e);
}
}
}
protected static class DataHandler extends AbstractHandler protected static class DataHandler extends AbstractHandler
{ {
@Override @Override

View File

@ -279,6 +279,45 @@ public class ResponseTest
assertEquals("application/json",response.getContentType()); assertEquals("application/json",response.getContentType());
} }
@Test
public void testInferredCharset() throws Exception
{
// Inferred from encoding.properties
Response response = getResponse();
assertEquals(null, response.getContentType());
response.setHeader("Content-Type", "application/xhtml+xml");
assertEquals("application/xhtml+xml", response.getContentType());
response.getWriter();
assertEquals("application/xhtml+xml;charset=utf-8", response.getContentType());
assertEquals("utf-8", response.getCharacterEncoding());
}
@Test
public void testAssumedCharset() throws Exception
{
Response response = getResponse();
// Assumed from known types
assertEquals(null, response.getContentType());
response.setHeader("Content-Type", "text/json");
assertEquals("text/json", response.getContentType());
response.getWriter();
assertEquals("text/json", response.getContentType());
assertEquals("utf-8", response.getCharacterEncoding());
response.recycle();
// Assumed from encoding.properties
assertEquals(null, response.getContentType());
response.setHeader("Content-Type", "application/vnd.api+json");
assertEquals("application/vnd.api+json", response.getContentType());
response.getWriter();
assertEquals("application/vnd.api+json", response.getContentType());
assertEquals("utf-8", response.getCharacterEncoding());
}
@Test @Test
public void testStrangeContentType() throws Exception public void testStrangeContentType() throws Exception
{ {

View File

@ -18,6 +18,14 @@
package org.eclipse.jetty.server.handler; package org.eclipse.jetty.server.handler;
import static org.eclipse.jetty.http.HttpHeader.CONTENT_LENGTH;
import static org.eclipse.jetty.http.HttpHeader.CONTENT_TYPE;
import static org.eclipse.jetty.http.HttpHeader.LAST_MODIFIED;
import static org.eclipse.jetty.http.HttpHeader.LOCATION;
import static org.eclipse.jetty.http.HttpHeader.SERVER;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.startsWith; import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
@ -28,11 +36,11 @@ import java.io.FileOutputStream;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.Socket; import java.net.Socket;
import java.net.URI;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.HttpConnectionFactory;
@ -40,7 +48,6 @@ import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.SimpleRequest;
import org.eclipse.jetty.toolchain.test.annotation.Slow; import org.eclipse.jetty.toolchain.test.annotation.Slow;
import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.IO;
@ -123,6 +130,7 @@ public class ResourceHandlerTest
_resourceHandler = new ResourceHandler(); _resourceHandler = new ResourceHandler();
_resourceHandler.setResourceBase(MavenTestingUtils.getTargetFile("test-classes/simple").getAbsolutePath()); _resourceHandler.setResourceBase(MavenTestingUtils.getTargetFile("test-classes/simple").getAbsolutePath());
_resourceHandler.setWelcomeFiles(new String[]{"welcome.txt"});
_contextHandler = new ContextHandler("/resource"); _contextHandler = new ContextHandler("/resource");
_contextHandler.setHandler(_resourceHandler); _contextHandler.setHandler(_resourceHandler);
@ -143,59 +151,75 @@ public class ResourceHandlerTest
} }
@Test @Test
public void testJettyDirCss() throws Exception public void testJettyDirRedirect() throws Exception
{ {
SimpleRequest sr = new SimpleRequest(new URI("http://localhost:" + _connector.getLocalPort())); HttpTester.Response response = HttpTester.parseResponse(
Assert.assertNotNull(sr.getString("/resource/jetty-dir.css")); _local.getResponse("GET /resource HTTP/1.0\r\n\r\n"));
assertThat(response.getStatus(),equalTo(302));
assertThat(response.get(LOCATION),containsString("/resource/"));
} }
@Test @Test
public void testSimple() throws Exception public void testJettyDirListing() throws Exception
{ {
SimpleRequest sr = new SimpleRequest(new URI("http://localhost:" + _connector.getLocalPort())); HttpTester.Response response = HttpTester.parseResponse(
Assert.assertEquals("simple text",sr.getString("/resource/simple.txt")); _local.getResponse("GET /resource/ HTTP/1.0\r\n\r\n"));
assertThat(response.getStatus(),equalTo(200));
assertThat(response.getContent(),containsString("jetty-dir.css"));
assertThat(response.getContent(),containsString("<H1>Directory: /resource/"));
assertThat(response.getContent(),containsString("big.txt"));
assertThat(response.getContent(),containsString("bigger.txt"));
assertThat(response.getContent(),containsString("directory"));
assertThat(response.getContent(),containsString("simple.txt"));
} }
@Test @Test
public void testHeaders() throws Exception public void testHeaders() throws Exception
{ {
String response = _local.getResponses("GET /resource/simple.txt HTTP/1.0\r\n\r\n"); HttpTester.Response response = HttpTester.parseResponse(
assertThat(response,startsWith("HTTP/1.1 200 OK")); _local.getResponse("GET /resource/simple.txt HTTP/1.0\r\n\r\n"));
assertThat(response,Matchers.containsString("Content-Type: text/plain")); assertThat(response.getStatus(),equalTo(200));
assertThat(response,Matchers.containsString("Last-Modified: ")); assertThat(response.get(CONTENT_TYPE),equalTo("text/plain"));
assertThat(response,Matchers.containsString("Content-Length: 11")); assertThat(response.get(LAST_MODIFIED),Matchers.notNullValue());
assertThat(response,Matchers.containsString("Server: Jetty")); assertThat(response.get(CONTENT_LENGTH),equalTo("11"));
assertThat(response,Matchers.containsString("simple text")); assertThat(response.get(SERVER),containsString("Jetty"));
assertThat(response.getContent(),containsString("simple text"));
} }
@Test @Test
public void testBigFile() throws Exception public void testBigFile() throws Exception
{ {
_config.setOutputBufferSize(2048); _config.setOutputBufferSize(2048);
SimpleRequest sr = new SimpleRequest(new URI("http://localhost:" + _connector.getLocalPort()));
String response = sr.getString("/resource/big.txt"); HttpTester.Response response = HttpTester.parseResponse(
Assert.assertThat(response,Matchers.startsWith(" 1\tThis is a big file")); _local.getResponse("GET /resource/big.txt HTTP/1.0\r\n\r\n"));
Assert.assertThat(response,Matchers.endsWith(" 400\tThis is a big file" + LN)); assertThat(response.getStatus(),equalTo(200));
assertThat(response.getContent(),startsWith(" 1\tThis is a big file"));
assertThat(response.getContent(),endsWith(" 400\tThis is a big file" + LN));
} }
@Test @Test
public void testBigFileBigBuffer() throws Exception public void testBigFileBigBuffer() throws Exception
{ {
_config.setOutputBufferSize(16 * 1024); _config.setOutputBufferSize(16 * 1024);
SimpleRequest sr = new SimpleRequest(new URI("http://localhost:" + _connector.getLocalPort()));
String response = sr.getString("/resource/big.txt"); HttpTester.Response response = HttpTester.parseResponse(
Assert.assertThat(response,Matchers.startsWith(" 1\tThis is a big file")); _local.getResponse("GET /resource/big.txt HTTP/1.0\r\n\r\n"));
Assert.assertThat(response,Matchers.endsWith(" 400\tThis is a big file" + LN)); assertThat(response.getStatus(),equalTo(200));
assertThat(response.getContent(),startsWith(" 1\tThis is a big file"));
assertThat(response.getContent(),endsWith(" 400\tThis is a big file" + LN));
} }
@Test @Test
public void testBigFileLittleBuffer() throws Exception public void testBigFileLittleBuffer() throws Exception
{ {
_config.setOutputBufferSize(8); _config.setOutputBufferSize(8);
SimpleRequest sr = new SimpleRequest(new URI("http://localhost:" + _connector.getLocalPort()));
String response = sr.getString("/resource/big.txt"); HttpTester.Response response = HttpTester.parseResponse(
Assert.assertThat(response,Matchers.startsWith(" 1\tThis is a big file")); _local.getResponse("GET /resource/big.txt HTTP/1.0\r\n\r\n"));
Assert.assertThat(response,Matchers.endsWith(" 400\tThis is a big file" + LN)); assertThat(response.getStatus(),equalTo(200));
assertThat(response.getContent(),startsWith(" 1\tThis is a big file"));
assertThat(response.getContent(),endsWith(" 400\tThis is a big file" + LN));
} }
@Test @Test
@ -212,6 +236,32 @@ public class ResourceHandlerTest
} }
} }
@Test
public void testWelcome() throws Exception
{
HttpTester.Response response = HttpTester.parseResponse(
_local.getResponse("GET /resource/directory/ HTTP/1.0\r\n\r\n"));
assertThat(response.getStatus(),equalTo(200));
assertThat(response.getContent(),containsString("Hello"));
}
@Test
public void testWelcomeRedirect() throws Exception
{
try
{
_resourceHandler.setRedirectWelcome(true);
HttpTester.Response response = HttpTester.parseResponse(
_local.getResponse("GET /resource/directory/ HTTP/1.0\r\n\r\n"));
assertThat(response.getStatus(),equalTo(302));
assertThat(response.get(LOCATION),containsString("/resource/welcome.txt"));
}
finally
{
_resourceHandler.setRedirectWelcome(false);
}
}
@Test @Test
@Slow @Slow
public void testSlowBiggest() throws Exception public void testSlowBiggest() throws Exception
@ -235,12 +285,10 @@ public class ResourceHandlerTest
try (Socket socket = new Socket("localhost",_connector.getLocalPort());OutputStream out=socket.getOutputStream();InputStream in=socket.getInputStream()) try (Socket socket = new Socket("localhost",_connector.getLocalPort());OutputStream out=socket.getOutputStream();InputStream in=socket.getInputStream())
{ {
socket.getOutputStream().write("GET /resource/biggest.txt HTTP/1.0\n\n".getBytes()); socket.getOutputStream().write("GET /resource/biggest.txt HTTP/1.0\n\n".getBytes());
byte[] array = new byte[102400]; byte[] array = new byte[102400];
ByteBuffer buffer=null; ByteBuffer buffer=null;
int i=0;
while(true) while(true)
{ {
Thread.sleep(100); Thread.sleep(100);

View File

@ -259,8 +259,6 @@ public class SelectChannelServerSslTest extends HttpServerTestBase
// Read the response. // Read the response.
String response = readResponse(client); String response = readResponse(client);
System.err.println(response);
assertThat(response, containsString("HTTP/1.1 200 OK")); assertThat(response, containsString("HTTP/1.1 200 OK"));
assertThat(response, containsString("Hello world")); assertThat(response, containsString("Hello world"));
assertThat(response, containsString("scheme='https'")); assertThat(response, containsString("scheme='https'"));

View File

@ -0,0 +1 @@
content

View File

@ -0,0 +1 @@
Hello

View File

@ -51,6 +51,7 @@ import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
@ -315,6 +316,8 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
{ {
// Look for a precompiled JSP Servlet // Look for a precompiled JSP Servlet
String precompiled=getClassNameForJsp(_forcedPath); String precompiled=getClassNameForJsp(_forcedPath);
if (!StringUtil.isBlank(precompiled))
{
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Checking for precompiled servlet {} for jsp {}", precompiled, _forcedPath); LOG.debug("Checking for precompiled servlet {} for jsp {}", precompiled, _forcedPath);
ServletHolder jsp = getServletHandler().getServlet(precompiled); ServletHolder jsp = getServletHandler().getServlet(precompiled);
@ -326,8 +329,6 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
setClassName(jsp.getClassName()); setClassName(jsp.getClassName());
} }
else else
{
if (getClassName() == null)
{ {
// Look for normal JSP servlet // Look for normal JSP servlet
jsp=getServletHandler().getServlet("jsp"); jsp=getServletHandler().getServlet("jsp");
@ -905,13 +906,24 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
private String getNameOfJspClass (String jsp) /**
* @param jsp the jsp-file
* @return the simple classname of the jsp
*/
protected String getNameOfJspClass (String jsp)
{ {
if (jsp == null) if (StringUtil.isBlank(jsp))
return ""; return ""; //empty
int i = jsp.lastIndexOf('/') + 1; jsp = jsp.trim();
jsp = jsp.substring(i); if ("/".equals(jsp))
return ""; //only slash
int i = jsp.lastIndexOf('/');
if (i == jsp.length()-1)
return ""; //ends with slash
jsp = jsp.substring(i+1);
try try
{ {
Class<?> jspUtil = Loader.loadClass("org.apache.jasper.compiler.JspUtil"); Class<?> jspUtil = Loader.loadClass("org.apache.jasper.compiler.JspUtil");
@ -930,7 +942,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
private String getPackageOfJspClass (String jsp) protected String getPackageOfJspClass (String jsp)
{ {
if (jsp == null) if (jsp == null)
return ""; return "";
@ -942,11 +954,13 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
{ {
Class<?> jspUtil = Loader.loadClass("org.apache.jasper.compiler.JspUtil"); Class<?> jspUtil = Loader.loadClass("org.apache.jasper.compiler.JspUtil");
Method makeJavaPackage = jspUtil.getMethod("makeJavaPackage", String.class); Method makeJavaPackage = jspUtil.getMethod("makeJavaPackage", String.class);
return (String)makeJavaPackage.invoke(null, jsp.substring(0,i)); String p = (String)makeJavaPackage.invoke(null, jsp.substring(0,i));
return p;
} }
catch (Exception e) catch (Exception e)
{ {
String tmp = jsp.substring(1).replace('/','.'); String tmp = jsp.substring(1,i).replace('/','.').trim();
tmp = (".".equals(tmp)? "": tmp);
LOG.warn("Unable to make package for jsp "+jsp +" trying "+tmp+" instead"); LOG.warn("Unable to make package for jsp "+jsp +" trying "+tmp+" instead");
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.warn(e); LOG.warn(e);
@ -956,7 +970,10 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
private String getJspPackagePrefix () /**
* @return the package for all jsps
*/
protected String getJspPackagePrefix ()
{ {
String jspPackageName = (String)getServletHandler().getServletContext().getInitParameter(JSP_GENERATED_PACKAGE_NAME ); String jspPackageName = (String)getServletHandler().getServletContext().getInitParameter(JSP_GENERATED_PACKAGE_NAME );
if (jspPackageName == null) if (jspPackageName == null)
@ -967,12 +984,40 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
private String getClassNameForJsp (String jsp) /**
* @param jsp the jsp-file from web.xml
* @return the fully qualified classname
*/
protected String getClassNameForJsp (String jsp)
{ {
if (jsp == null) if (jsp == null)
return null; return null;
return getJspPackagePrefix() + "." +getPackageOfJspClass(jsp) + "." + getNameOfJspClass(jsp); String name = getNameOfJspClass(jsp);
if (StringUtil.isBlank(name))
return null;
StringBuffer fullName = new StringBuffer();
appendPath(fullName, getJspPackagePrefix());
appendPath(fullName, getPackageOfJspClass(jsp));
appendPath(fullName, name);
return fullName.toString();
}
/* ------------------------------------------------------------ */
/**
* Concatenate an element on to fully qualified classname.
*
* @param path the path under construction
* @param element the element of the name to add
*/
protected void appendPath (StringBuffer path, String element)
{
if (StringUtil.isBlank(element))
return;
if (path.length() > 0)
path.append(".");
path.append(element);
} }

View File

@ -162,11 +162,8 @@ public class PostServletTest
req.append("\r\n"); req.append("\r\n");
req.append("\r\n"); req.append("\r\n");
try (StacklessLogging scope = new StacklessLogging(ServletHandler.class)) String resp = connector.getResponse(req.toString());
{ assertThat(resp,startsWith("HTTP/1.1 200 OK")); // exception eaten by handler
String resp = connector.getResponses(req.toString());
assertThat(resp,is("")); // Aborted before response committed
}
assertTrue(complete.await(5,TimeUnit.SECONDS)); assertTrue(complete.await(5,TimeUnit.SECONDS));
assertThat(ex0.get(),not(nullValue())); assertThat(ex0.get(),not(nullValue()));
assertThat(ex1.get(),not(nullValue())); assertThat(ex1.get(),not(nullValue()));
@ -181,8 +178,6 @@ public class PostServletTest
req.append("Transfer-Encoding: chunked\r\n"); req.append("Transfer-Encoding: chunked\r\n");
req.append("\r\n"); req.append("\r\n");
try (StacklessLogging scope = new StacklessLogging(ServletHandler.class))
{
LocalConnector.LocalEndPoint endp=connector.executeRequest(req.toString()); LocalConnector.LocalEndPoint endp=connector.executeRequest(req.toString());
Thread.sleep(1000); Thread.sleep(1000);
assertFalse(posted.get()); assertFalse(posted.get());
@ -199,13 +194,10 @@ public class PostServletTest
endp.waitUntilClosedOrIdleFor(1,TimeUnit.SECONDS); endp.waitUntilClosedOrIdleFor(1,TimeUnit.SECONDS);
String resp = endp.takeOutputString(); String resp = endp.takeOutputString();
assertThat("resp", resp, containsString("HTTP/1.1 400 ")); assertThat(resp,startsWith("HTTP/1.1 200 OK")); // exception eaten by handler
assertTrue(complete.await(5,TimeUnit.SECONDS));
} assertThat(ex0.get(),not(nullValue()));
assertThat(ex1.get(),not(nullValue()));
// null because it was never dispatched!
assertThat(ex0.get(),nullValue());
assertThat(ex1.get(),nullValue());
} }

View File

@ -66,7 +66,7 @@ public class DataRateLimitedServletTest
context.setContextPath("/context"); context.setContextPath("/context");
context.setWelcomeFiles(new String[]{"index.html", "index.jsp", "index.htm"}); context.setWelcomeFiles(new String[]{"index.html", "index.jsp", "index.htm"});
File baseResourceDir = testdir.getEmptyDir(); File baseResourceDir = testdir.getEmptyPathDir().toFile();
// Use resolved real path for Windows and OSX // Use resolved real path for Windows and OSX
Path baseResourcePath = baseResourceDir.toPath().toRealPath(); Path baseResourcePath = baseResourceDir.toPath().toRealPath();
@ -91,7 +91,7 @@ public class DataRateLimitedServletTest
@Test @Test
public void testStream() throws Exception public void testStream() throws Exception
{ {
File content = testdir.getFile("content.txt"); File content = testdir.getPathFile("content.txt").toFile();
String[] results=new String[10]; String[] results=new String[10];
try(OutputStream out = new FileOutputStream(content);) try(OutputStream out = new FileOutputStream(content);)
{ {
@ -109,7 +109,7 @@ public class DataRateLimitedServletTest
} }
long start=System.currentTimeMillis(); long start=System.currentTimeMillis();
String response = connector.getResponses("GET /context/stream/content.txt HTTP/1.0\r\n\r\n"); String response = connector.getResponse("GET /context/stream/content.txt HTTP/1.0\r\n\r\n");
long duration=System.currentTimeMillis()-start; long duration=System.currentTimeMillis()-start;
assertThat("Response",response,containsString("200 OK")); assertThat("Response",response,containsString("200 OK"));

View File

@ -0,0 +1,153 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.start;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class JavaVersion
{
private static final Pattern PRE_JDK9 = Pattern.compile("1\\.(\\d)(\\.(\\d+)(_(\\d+))?)?(-.+)?");
// Regexp from JEP 223 (http://openjdk.java.net/jeps/223).
private static final Pattern JDK9 = Pattern.compile("(\\d+)(\\.(\\d+))?(\\.(\\d+))?((-.+)?(\\+(\\d+)?(-.+)?)?)");
public static JavaVersion parse(String version)
{
if (version.startsWith("1."))
return parsePreJDK9(version);
return parseJDK9(version);
}
private static JavaVersion parsePreJDK9(String version)
{
Matcher matcher = PRE_JDK9.matcher(version);
if (!matcher.matches())
throw new IllegalArgumentException("Invalid Java version " + version);
int major = 1;
int minor = Integer.parseInt(matcher.group(1));
String microGroup = matcher.group(3);
int micro = microGroup == null || microGroup.isEmpty() ? 0 : Integer.parseInt(microGroup);
String updateGroup = matcher.group(5);
int update = updateGroup == null || updateGroup.isEmpty() ? 0 : Integer.parseInt(updateGroup);
String suffix = matcher.group(6);
return new JavaVersion(version, minor, major, minor, micro, update, suffix);
}
private static JavaVersion parseJDK9(String version)
{
Matcher matcher = JDK9.matcher(version);
if (!matcher.matches())
throw new IllegalArgumentException("Invalid Java version " + version);
int major = Integer.parseInt(matcher.group(1));
String minorGroup = matcher.group(3);
int minor = minorGroup == null || minorGroup.isEmpty() ? 0 : Integer.parseInt(minorGroup);
String microGroup = matcher.group(5);
int micro = microGroup == null || microGroup.isEmpty() ? 0 : Integer.parseInt(microGroup);
String suffix = matcher.group(6);
return new JavaVersion(version, major, major, minor, micro, 0, suffix);
}
private final String version;
private final int platform;
private final int major;
private final int minor;
private final int micro;
private final int update;
private final String suffix;
private JavaVersion(String version, int platform, int major, int minor, int micro, int update, String suffix)
{
this.version = version;
this.platform = platform;
this.major = major;
this.minor = minor;
this.micro = micro;
this.update = update;
this.suffix = suffix;
}
/**
* @return the string from which this JavaVersion was created
*/
public String getVersion()
{
return version;
}
/**
* <p>Returns the Java Platform version, such as {@code 8} for JDK 1.8.0_92 and {@code 9} for JDK 9.2.4.</p>
*
* @return the Java Platform version
*/
public int getPlatform()
{
return platform;
}
/**
* <p>Returns the major number version, such as {@code 1} for JDK 1.8.0_92 and {@code 9} for JDK 9.2.4.</p>
*
* @return the major number version
*/
public int getMajor()
{
return major;
}
/**
* <p>Returns the minor number version, such as {@code 8} for JDK 1.8.0_92 and {@code 2} for JDK 9.2.4.</p>
*
* @return the minor number version
*/
public int getMinor()
{
return minor;
}
/**
* <p>Returns the micro number version, such as {@code 0} for JDK 1.8.0_92 and {@code 4} for JDK 9.2.4.</p>
*
* @return the micro number version
*/
public int getMicro()
{
return micro;
}
/**
* <p>Returns the update number version, such as {@code 92} for JDK 1.8.0_92 and {@code 0} for JDK 9.2.4.</p>
*
* @return the update number version
*/
public int getUpdate()
{
return update;
}
/**
* <p>Returns the remaining string after the version numbers, such as {@code -internal} for
* JDK 1.8.0_92-internal and {@code -ea} for JDK 9-ea, or {@code +13} for JDK 9.2.4+13.</p>
*
* @return the remaining string after the version numbers
*/
public String getSuffix()
{
return suffix;
}
}

View File

@ -332,10 +332,10 @@ public class Main
// ------------------------------------------------------------ // ------------------------------------------------------------
// 5) Lib & XML Expansion / Resolution // 5) Lib & XML Expansion / Resolution
args.expandSystemProperties();
args.expandLibs(); args.expandLibs();
args.expandModules(activeModules); args.expandModules(activeModules);
// ------------------------------------------------------------ // ------------------------------------------------------------
// 6) Resolve Extra XMLs // 6) Resolve Extra XMLs
args.resolveExtraXmls(); args.resolveExtraXmls();

View File

@ -179,7 +179,7 @@ public class Module implements Comparable<Module>
return _path.equals(other._path); return _path.equals(other._path);
} }
public void expandProperties(Props props) public void expandDependencies(Props props)
{ {
Function<String,String> expander = d->{return props.expand(d);}; Function<String,String> expander = d->{return props.expand(d);};

View File

@ -322,7 +322,7 @@ public class Modules implements Iterable<Module>
newlyEnabled.add(module.getName()); newlyEnabled.add(module.getName());
// Expand module properties // Expand module properties
module.expandProperties(_args.getProperties()); module.expandDependencies(_args.getProperties());
// Apply default configuration // Apply default configuration
if (module.hasDefaultConfig()) if (module.hasDefaultConfig())
@ -330,7 +330,7 @@ public class Modules implements Iterable<Module>
for(String line:module.getDefaultConfig()) for(String line:module.getDefaultConfig())
_args.parse(line,module.getName()+"[ini]"); _args.parse(line,module.getName()+"[ini]");
for (Module m:_modules) for (Module m:_modules)
m.expandProperties(_args.getProperties()); m.expandDependencies(_args.getProperties());
} }
} }
@ -349,7 +349,7 @@ public class Modules implements Iterable<Module>
if (dependsOn.contains("/")) if (dependsOn.contains("/"))
{ {
Path file = _baseHome.getPath("modules/" + dependsOn + ".mod"); Path file = _baseHome.getPath("modules/" + dependsOn + ".mod");
registerModule(file).expandProperties(_args.getProperties()); registerModule(file).expandDependencies(_args.getProperties());
providers = _provided.get(dependsOn); providers = _provided.get(dependsOn);
if (providers==null || providers.isEmpty()) if (providers==null || providers.isEmpty())
throw new UsageException("Module %s does not provide %s",_baseHome.toShortForm(file),dependsOn); throw new UsageException("Module %s does not provide %s",_baseHome.toShortForm(file),dependsOn);

View File

@ -190,7 +190,7 @@ public final class Props implements Iterable<Prop>
return expand(str,new Stack<String>()); return expand(str,new Stack<String>());
} }
public String expand(String str, Stack<String> seenStack) private String expand(String str, Stack<String> seenStack)
{ {
if (str == null) if (str == null)
{ {

View File

@ -18,8 +18,6 @@
package org.eclipse.jetty.start; package org.eclipse.jetty.start;
import static org.eclipse.jetty.start.UsageException.ERR_BAD_ARG;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -37,6 +35,7 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.function.Function;
import org.eclipse.jetty.start.Props.Prop; import org.eclipse.jetty.start.Props.Prop;
import org.eclipse.jetty.start.config.ConfigSource; import org.eclipse.jetty.start.config.ConfigSource;
@ -180,7 +179,6 @@ public class StartArgs
private boolean createStartd = false; private boolean createStartd = false;
private boolean updateIni = false; private boolean updateIni = false;
private boolean exec = false; private boolean exec = false;
private String exec_properties; private String exec_properties;
private boolean approveAllLicenses = false; private boolean approveAllLicenses = false;
@ -437,6 +435,28 @@ public class StartArgs
} }
} }
/**
* Expand any command line added {@code --lib} lib references.
*
* @throws IOException
* if unable to expand the libraries
*/
public void expandSystemProperties() throws IOException
{
StartLog.debug("Expanding System Properties");
for (String key : systemPropertyKeys)
{
String value = properties.getString(key);
if (value!=null)
{
String expanded = properties.expand(value);
if (!value.equals(expanded))
System.setProperty(key,expanded);
}
}
}
/** /**
* Expand any command line added <code>--lib</code> lib references. * Expand any command line added <code>--lib</code> lib references.
* *
@ -555,15 +575,30 @@ public class StartArgs
{ {
cmd.addRawArg(CommandLineBuilder.findJavaBin()); cmd.addRawArg(CommandLineBuilder.findJavaBin());
for (String x : jvmArgs)
{
cmd.addRawArg(x);
}
cmd.addRawArg("-Djava.io.tmpdir=" + System.getProperty("java.io.tmpdir")); cmd.addRawArg("-Djava.io.tmpdir=" + System.getProperty("java.io.tmpdir"));
cmd.addRawArg("-Djetty.home=" + baseHome.getHome()); cmd.addRawArg("-Djetty.home=" + baseHome.getHome());
cmd.addRawArg("-Djetty.base=" + baseHome.getBase()); cmd.addRawArg("-Djetty.base=" + baseHome.getBase());
for (String x : jvmArgs)
{
if (x.startsWith("-D"))
{
String[] assign = x.substring(2).split("=",2);
String key = assign[0];
String value = assign.length==1?"":assign[1];
Property p = processProperty(key,value,"modules",k->{return System.getProperty(k);});
if (p!=null)
{
cmd.addRawArg("-D"+p.key+"="+getProperties().expand(p.value));
}
}
else
{
cmd.addRawArg(x);
}
}
// System Properties // System Properties
for (String propKey : systemPropertyKeys) for (String propKey : systemPropertyKeys)
{ {
@ -861,7 +896,7 @@ public class StartArgs
Path commands = baseHome.getPath(Props.getValue(arg)); Path commands = baseHome.getPath(Props.getValue(arg));
if (!Files.exists(commands) || !Files.isReadable(commands)) if (!Files.exists(commands) || !Files.isReadable(commands))
throw new UsageException(ERR_BAD_ARG,"--commands file must be readable: %s",commands); throw new UsageException(UsageException.ERR_BAD_ARG,"--commands file must be readable: %s",commands);
try try
{ {
TextFile file = new TextFile(commands); TextFile file = new TextFile(commands);
@ -947,7 +982,7 @@ public class StartArgs
{ {
exec_properties = Props.getValue(arg); exec_properties = Props.getValue(arg);
if (!exec_properties.endsWith(".properties")) if (!exec_properties.endsWith(".properties"))
throw new UsageException(ERR_BAD_ARG,"--exec-properties filename must have .properties suffix: %s",exec_properties); throw new UsageException(UsageException.ERR_BAD_ARG,"--exec-properties filename must have .properties suffix: %s",exec_properties);
return; return;
} }
@ -1057,19 +1092,15 @@ public class StartArgs
if (arg.startsWith("-D")) if (arg.startsWith("-D"))
{ {
String[] assign = arg.substring(2).split("=",2); String[] assign = arg.substring(2).split("=",2);
systemPropertyKeys.add(assign[0]); String key = assign[0];
switch (assign.length) String value = assign.length==1?"":assign[1];
Property p = processProperty(key,value,source,k->{return System.getProperty(k);});
if (p!=null)
{ {
case 2: systemPropertyKeys.add(p.key);
System.setProperty(assign[0],assign[1]); setProperty(p.key,p.value,p.source);
setProperty(assign[0],assign[1],source); System.setProperty(p.key,p.value);
break;
case 1:
System.setProperty(assign[0],"");
setProperty(assign[0],"",source);
break;
default:
break;
} }
return; return;
} }
@ -1092,36 +1123,11 @@ public class StartArgs
String key = arg.substring(0,equals); String key = arg.substring(0,equals);
String value = arg.substring(equals + 1); String value = arg.substring(equals + 1);
if (key.endsWith("+")) Property p = processProperty(key,value,source,k->{return getProperties().getString(k);});
if (p!=null)
{ {
key = key.substring(0,key.length() - 1); setProperty(p.key,p.value,p.source);
String orig = getProperties().getString(key);
if (orig == null || orig.isEmpty())
{
if (value.startsWith(","))
value = value.substring(1);
} }
else
{
value = orig + value;
source = propertySource.get(key) + "," + source;
}
}
if (key.endsWith("?"))
{
key = key.substring(0,key.length() - 1);
if (getProperties().containsKey(key))
return;
}
else if (propertySource.containsKey(key))
{
if (!propertySource.get(key).endsWith("[ini]"))
StartLog.warn("Property %s in %s already set in %s",key,source,propertySource.get(key));
propertySource.put(key,source);
}
setProperty(key,value,source);
return; return;
} }
@ -1147,7 +1153,44 @@ public class StartArgs
} }
// Anything else is unrecognized // Anything else is unrecognized
throw new UsageException(ERR_BAD_ARG,"Unrecognized argument: \"%s\" in %s",arg,source); throw new UsageException(UsageException.ERR_BAD_ARG,"Unrecognized argument: \"%s\" in %s",arg,source);
}
protected Property processProperty(String key,String value,String source, Function<String, String> getter)
{
if (key.endsWith("+"))
{
key = key.substring(0,key.length() - 1);
String orig = getter.apply(key);
if (orig == null || orig.isEmpty())
{
if (value.startsWith(","))
value = value.substring(1);
}
else
{
value = orig + value;
source = propertySource.get(key) + "," + source;
}
}
if (key.endsWith("?"))
{
key = key.substring(0,key.length() - 1);
String preset = getter.apply(key);
if (preset!=null)
{
source = source+"?=";
value = preset;
}
}
else if (propertySource.containsKey(key))
{
if (!propertySource.get(key).endsWith("[ini]"))
StartLog.warn("Property %s in %s already set in %s",key,source,propertySource.get(key));
propertySource.put(key,source);
}
return new Property(key,value,source);
} }
private void enableModules(String source, List<String> moduleNames) private void enableModules(String source, List<String> moduleNames)
@ -1158,7 +1201,7 @@ public class StartArgs
List<String> list = sources.get(moduleName); List<String> list = sources.get(moduleName);
if (list == null) if (list == null)
{ {
list = new ArrayList<String>(); list = new ArrayList<>();
sources.put(moduleName,list); sources.put(moduleName,list);
} }
list.add(source); list.add(source);
@ -1219,14 +1262,21 @@ public class StartArgs
properties.setProperty(key,value,source); properties.setProperty(key,value,source);
if (key.equals("java.version")) if (key.equals("java.version"))
{ {
Version ver = new Version(value); try
{
properties.setProperty("java.version",ver.toShortString(),source); JavaVersion ver = JavaVersion.parse(value);
properties.setProperty("java.version.major",Integer.toString(ver.getLegacyMajor()),source); properties.setProperty("java.version",ver.getVersion(),source);
properties.setProperty("java.version.minor",Integer.toString(ver.getMajor()),source); properties.setProperty("java.version.platform",Integer.toString(ver.getPlatform()),source);
properties.setProperty("java.version.revision",Integer.toString(ver.getRevision()),source); properties.setProperty("java.version.major",Integer.toString(ver.getMajor()),source);
properties.setProperty("java.version.minor",Integer.toString(ver.getMinor()),source);
properties.setProperty("java.version.micro",Integer.toString(ver.getMicro()),source);
properties.setProperty("java.version.update",Integer.toString(ver.getUpdate()),source); properties.setProperty("java.version.update",Integer.toString(ver.getUpdate()),source);
} }
catch (Throwable x)
{
throw new UsageException(UsageException.ERR_BAD_ARG, x.getMessage());
}
}
} }
public void setRun(boolean run) public void setRun(boolean run)
@ -1250,4 +1300,22 @@ public class StartArgs
return builder.toString(); return builder.toString();
} }
static class Property
{
String key;
String value;
String source;
public Property(String key, String value, String source)
{
this.key = key;
this.value = value;
this.source = source;
}
@Override
public String toString()
{
return String.format("%s=%s(%s)",key,value,source);
}
}
} }

View File

@ -172,8 +172,8 @@ Properties:
+ XML files using the <Property name="pname"/> element + XML files using the <Property name="pname"/> element
+ Module files using the ${pname} syntax + Module files using the ${pname} syntax
Propertues may be set on the command line, in a ini file or in a [ini] Properties and System Properties may be set on the command line,
section of a module using the following syntax: in a ini file or in a [ini] section of a module using the following syntax:
name=value name=value
Set a property that can be expanded in XML files with the <Property> element. Set a property that can be expanded in XML files with the <Property> element.
@ -187,7 +187,10 @@ Properties:
name?=value name?=value
Set a property only if it is not already set. Set a property only if it is not already set.
Each module may definte it's own properties. Start properties defined include: If any of the previous formats is preceded by -D, then a system property is set
as well as a start property.
Each module may define it's own properties. Start properties defined include:
jetty.home=[directory] jetty.home=[directory]
Set the home directory of the jetty distribution. Set the home directory of the jetty distribution.

View File

@ -34,6 +34,7 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.eclipse.jetty.start.Props.Prop; import org.eclipse.jetty.start.Props.Prop;
@ -127,7 +128,7 @@ public class ConfigurationAssert
Set<String> expectedProperties = new HashSet<>(); Set<String> expectedProperties = new HashSet<>();
for (String line : textFile) for (String line : textFile)
{ {
if (line.startsWith("PROP|")) if (line.startsWith("PROP|") || line.startsWith("SYS|"))
{ {
expectedProperties.add(getValue(line)); expectedProperties.add(getValue(line));
} }
@ -147,6 +148,17 @@ public class ConfigurationAssert
} }
assertContainsUnordered("Properties", expectedProperties, actualProperties); assertContainsUnordered("Properties", expectedProperties, actualProperties);
// Validate PROPERTIES (order is not important)
for (String line : textFile)
{
if (line.startsWith("SYS|"))
{
String[] expected = getValue(line).split("=",2);
String actual = System.getProperty(expected[0]);
assertThat("System property "+expected[0],actual,Matchers.equalTo(expected[1]));
}
}
// Validate Downloads // Validate Downloads
List<String> expectedDownloads = new ArrayList<>(); List<String> expectedDownloads = new ArrayList<>();
for (String line : textFile) for (String line : textFile)
@ -215,8 +227,8 @@ public class ConfigurationAssert
} }
catch (AssertionError e) catch (AssertionError e)
{ {
System.err.println("Expected: " + expectedSet); System.err.println("Expected: " + expectedSet.stream().sorted().collect(Collectors.toList()));
System.err.println("Actual : " + actualSet); System.err.println("Actual : " + actualSet.stream().sorted().collect(Collectors.toList()));
throw e; throw e;
} }

View File

@ -18,11 +18,6 @@
package org.eclipse.jetty.start; package org.eclipse.jetty.start;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -34,10 +29,14 @@ import org.eclipse.jetty.start.config.JettyBaseConfigSource;
import org.eclipse.jetty.start.config.JettyHomeConfigSource; import org.eclipse.jetty.start.config.JettyHomeConfigSource;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.TestingDir; import org.eclipse.jetty.toolchain.test.TestingDir;
import org.hamcrest.Matchers;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
public class ModulesTest public class ModulesTest
{ {
private final static String TEST_SOURCE = "<test>"; private final static String TEST_SOURCE = "<test>";
@ -71,8 +70,7 @@ public class ModulesTest
modules.registerAll(); modules.registerAll();
// Check versions // Check versions
assertThat("java.version.major", args.getProperties().getString("java.version.major"),equalTo("1")); assertThat("java.version.platform", args.getProperties().getString("java.version.platform"),anyOf(equalTo("8"),equalTo("9")));
assertThat("java.version.minor", args.getProperties().getString("java.version.minor"),anyOf(equalTo("7"),Matchers.equalTo("8"),Matchers.equalTo("9")));
List<String> moduleNames = new ArrayList<>(); List<String> moduleNames = new ArrayList<>();
for (Module mod : modules) for (Module mod : modules)

View File

@ -47,7 +47,7 @@ public class TestBadUseCases
List<Object[]> ret = new ArrayList<>(); List<Object[]> ret = new ArrayList<>();
ret.add(new Object[]{ "http2", ret.add(new Object[]{ "http2",
"Missing referenced dependency: alpn-impl/alpn-0.0.0_0", "Invalid Java version",
new String[]{"java.version=0.0.0_0"}}); new String[]{"java.version=0.0.0_0"}});
ret.add(new Object[]{ "versioned-modules-too-new", ret.add(new Object[]{ "versioned-modules-too-new",

View File

@ -15,3 +15,8 @@ PROP|jetty.http.port=9090
PROP|add=beginningmiddleend PROP|add=beginningmiddleend
PROP|list=one,two,three PROP|list=one,two,three
PROP|name=value PROP|name=value
PROP|name0=/
PROP|name1=/foo
PROP|name2=/foo/bar
SYS|SYSTEM=value
SYS|PRESET=value

View File

@ -8,3 +8,9 @@ list+=,two
list+=,three list+=,three
name?=value name?=value
name?=enoughAlready name?=enoughAlready
name0=/
name1=${name0}foo
name2=${name1}/bar
-DSYSTEM=${name}
-DSYSTEM?=IGNORED
-DPRESET?=${SYSTEM}

View File

@ -14,5 +14,5 @@ jul-impl
basehome:modules/jul-impl basehome:modules/jul-impl
[exec] [exec]
-Djava.util.logging.config.file=etc/java-util-logging.properties -Djava.util.logging.config.file?=${jetty.base}/etc/java-util-logging.properties

View File

@ -23,5 +23,4 @@ basehome:modules/jul-slf4j
lib/slf4j/jul-to-slf4j-${slf4j.version}.jar lib/slf4j/jul-to-slf4j-${slf4j.version}.jar
[exec] [exec]
-Djava.util.logging.config.file=etc/java-util-logging.properties -Djava.util.logging.config.file?=${jetty.base}/etc/java-util-logging.properties

View File

@ -13,7 +13,7 @@ jul-impl
logging logging
[exec] [exec]
-Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
[ini] [ini]
jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/slf4j/ jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/slf4j/

View File

@ -13,7 +13,7 @@ log4j-impl
logging logging
[exec] [exec]
-Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
[ini] [ini]
jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/slf4j/,file:${jetty.base}/lib/log4j/ jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/slf4j/,file:${jetty.base}/lib/log4j/

View File

@ -13,7 +13,7 @@ log4j2-impl
logging logging
[exec] [exec]
-Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
[ini] [ini]
jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/slf4j/,file:${jetty.base}/lib/log4j2/ jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/slf4j/,file:${jetty.base}/lib/log4j2/

View File

@ -13,7 +13,7 @@ logback-impl
logging logging
[exec] [exec]
-Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
[ini] [ini]
jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/slf4j/,file:${jetty.base}/lib/logback/ jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/slf4j/,file:${jetty.base}/lib/logback/

View File

@ -13,7 +13,7 @@ slf4j-impl
logging logging
[exec] [exec]
-Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
[ini] [ini]
jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/slf4j/ jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/slf4j/

View File

@ -913,40 +913,23 @@ public class BufferUtil
} }
} }
static final Field fdMappedByteBuffer;
static
{
Field fd = null;
try
{
fd=MappedByteBuffer.class.getDeclaredField("fd");
fd.setAccessible(true);
}
catch(Exception e)
{
}
fdMappedByteBuffer=fd;
}
public static boolean isMappedBuffer(ByteBuffer buffer) public static boolean isMappedBuffer(ByteBuffer buffer)
{ {
if (!(buffer instanceof MappedByteBuffer)) if (!(buffer instanceof MappedByteBuffer))
return false; return false;
MappedByteBuffer mapped = (MappedByteBuffer) buffer; MappedByteBuffer mapped = (MappedByteBuffer) buffer;
if (fdMappedByteBuffer!=null)
{
try try
{ {
if (fdMappedByteBuffer.get(mapped) instanceof FileDescriptor) // Check if it really is a mapped buffer
mapped.isLoaded();
return true; return true;
} }
catch(Exception e) catch(UnsupportedOperationException e)
{ {
}
}
return false; return false;
} }
}
public static ByteBuffer toBuffer(Resource resource,boolean direct) throws IOException public static ByteBuffer toBuffer(Resource resource,boolean direct) throws IOException

View File

@ -18,12 +18,15 @@
package org.eclipse.jetty.websocket.server; package org.eclipse.jetty.websocket.server;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import org.eclipse.jetty.annotations.AnnotationConfiguration; import org.eclipse.jetty.annotations.AnnotationConfiguration;
@ -35,6 +38,7 @@ import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.toolchain.test.FS; import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.IO; import org.eclipse.jetty.toolchain.test.IO;
import org.eclipse.jetty.toolchain.test.JAR;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.OS; import org.eclipse.jetty.toolchain.test.OS;
import org.eclipse.jetty.toolchain.test.TestingDir; import org.eclipse.jetty.toolchain.test.TestingDir;
@ -47,7 +51,6 @@ import org.eclipse.jetty.webapp.MetaInfConfiguration;
import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration; import org.eclipse.jetty.webapp.WebInfConfiguration;
import org.eclipse.jetty.webapp.WebXmlConfiguration; import org.eclipse.jetty.webapp.WebXmlConfiguration;
import org.junit.Assert;
/** /**
* Utility to build out exploded directory WebApps, in the /target/tests/ directory, for testing out servers that use javax.websocket endpoints. * Utility to build out exploded directory WebApps, in the /target/tests/ directory, for testing out servers that use javax.websocket endpoints.
@ -82,7 +85,7 @@ public class WSServer
ClassLoader cl = Thread.currentThread().getContextClassLoader(); ClassLoader cl = Thread.currentThread().getContextClassLoader();
String endpointPath = clazz.getName().replace('.','/') + ".class"; String endpointPath = clazz.getName().replace('.','/') + ".class";
URL classUrl = cl.getResource(endpointPath); URL classUrl = cl.getResource(endpointPath);
Assert.assertThat("Class URL for: " + clazz,classUrl,notNullValue()); assertThat("Class URL for: " + clazz,classUrl,notNullValue());
File destFile = new File(classesDir,OS.separators(endpointPath)); File destFile = new File(classesDir,OS.separators(endpointPath));
FS.ensureDirExists(destFile.getParentFile()); FS.ensureDirExists(destFile.getParentFile());
File srcFile = new File(classUrl.toURI()); File srcFile = new File(classUrl.toURI());
@ -94,6 +97,30 @@ public class WSServer
copyClass(endpointClass); copyClass(endpointClass);
} }
public void copyLib(Class<?> clazz, String jarFileName) throws URISyntaxException, IOException
{
webinf = new File(contextDir,"WEB-INF");
FS.ensureDirExists(webinf);
File libDir = new File(webinf,"lib");
FS.ensureDirExists(libDir);
File jarFile = new File(libDir, jarFileName);
URL codeSourceURL = clazz.getProtectionDomain().getCodeSource().getLocation();
assertThat("Class CodeSource URL is file scheme", codeSourceURL.getProtocol(), is("file"));
File sourceCodeSourceFile = new File(codeSourceURL.toURI());
if (sourceCodeSourceFile.isDirectory())
{
LOG.info("Creating " + jarFile + " from " + sourceCodeSourceFile);
JAR.create(sourceCodeSourceFile, jarFile);
}
else
{
LOG.info("Copying " + sourceCodeSourceFile + " to " + jarFile);
IO.copy(sourceCodeSourceFile, jarFile);
}
}
public void copyWebInf(String testResourceName) throws IOException public void copyWebInf(String testResourceName) throws IOException
{ {
webinf = new File(contextDir,"WEB-INF"); webinf = new File(contextDir,"WEB-INF");

View File

@ -204,6 +204,33 @@ public class WebSocketUpgradeFilterTest
return server15.getServer(); return server15.getServer();
}}); }});
// WSUF from web.xml, SCI active, apply app-ws configuration via ServletContextListener with WEB-INF/lib/jetty-http.jar
cases.add(new Object[]{"wsuf/WebAppContext/web.xml/ServletContextListener/jetty-http.jar", new ServerProvider()
{
@Override
public Server newServer() throws Exception
{
File testDir = MavenTestingUtils.getTargetTestingDir("WSUF-webxml");
WSServer server = new WSServer(testDir, "/");
server.copyWebInf("wsuf-config-via-listener.xml");
server.copyClass(InfoSocket.class);
server.copyClass(InfoContextAttributeListener.class);
// Add a jetty-http.jar to ensure that the classloader constraints
// and the WebAppClassloader setup is sane and correct
// The odd version string is present to capture bad regex behavior in Jetty
server.copyLib(org.eclipse.jetty.http.pathmap.PathSpec.class, "jetty-http-9.99.999.jar");
server.start();
WebAppContext webapp = server.createWebAppContext();
server.deployWebapp(webapp);
return server.getServer();
}
}});
// WSUF from web.xml, SCI active, apply app-ws configuration via Servlet.init // WSUF from web.xml, SCI active, apply app-ws configuration via Servlet.init
cases.add(new Object[]{"wsuf/WebAppContext/web.xml/Servlet.init", (ServerProvider) () -> cases.add(new Object[]{"wsuf/WebAppContext/web.xml/Servlet.init", (ServerProvider) () ->

84
pom.xml
View File

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?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">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
@ -39,7 +41,6 @@
<connection>scm:git:https://github.com/eclipse/jetty.project.git</connection> <connection>scm:git:https://github.com/eclipse/jetty.project.git</connection>
<developerConnection>scm:git:git@github.com:eclipse/jetty.project.git</developerConnection> <developerConnection>scm:git:git@github.com:eclipse/jetty.project.git</developerConnection>
<url>https://github.com/eclipse/jetty.project</url> <url>https://github.com/eclipse/jetty.project</url>
<tag>jetty-9.3.13.M0</tag>
</scm> </scm>
<modules> <modules>
@ -89,6 +90,7 @@
<module>jetty-osgi</module> <module>jetty-osgi</module>
<module>jetty-alpn</module> <module>jetty-alpn</module>
<module>jetty-home</module> <module>jetty-home</module>
<module>jetty-documentation</module>
<!-- modules that need fixed and added back, or simply dropped and not maintained --> <!-- modules that need fixed and added back, or simply dropped and not maintained -->
<!-- <module>jetty-rhttp</module> --> <!-- <module>jetty-rhttp</module> -->
<!-- <module>jetty-overlay-deployer</module> --> <!-- <module>jetty-overlay-deployer</module> -->
@ -150,7 +152,6 @@
<plugin> <plugin>
<groupId>org.jacoco</groupId> <groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId> <artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.7.201606060606</version>
<configuration> <configuration>
<excludes> <excludes>
<!-- build tools --> <!-- build tools -->
@ -366,15 +367,10 @@
<artifactId>maven-antrun-plugin</artifactId> <artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version> <version>1.8</version>
</plugin> </plugin>
<plugin>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-version-maven-plugin</artifactId>
<version>2.4</version>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId> <artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version> <version>3.0.0</version>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.eclipse.jetty.toolchain</groupId> <groupId>org.eclipse.jetty.toolchain</groupId>
@ -386,7 +382,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version> <version>3.6.0</version>
<configuration> <configuration>
<source>1.8</source> <source>1.8</source>
<target>1.8</target> <target>1.8</target>
@ -395,7 +391,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId> <artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version> <version>3.0.0</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
@ -418,7 +414,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
<version>3.0.0</version> <version>3.0.2</version>
<configuration> <configuration>
<archive> <archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
@ -433,7 +429,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version> <version>2.10.4</version>
<configuration> <configuration>
<docfilessubdirs>true</docfilessubdirs> <docfilessubdirs>true</docfilessubdirs>
<detectLinks>true</detectLinks> <detectLinks>true</detectLinks>
@ -526,12 +522,12 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId> <artifactId>maven-plugin-plugin</artifactId>
<version>3.4</version> <version>3.5</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId> <artifactId>maven-pmd-plugin</artifactId>
<version>3.6</version> <version>3.7</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
@ -561,12 +557,12 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId> <artifactId>maven-site-plugin</artifactId>
<version>3.5.1</version> <version>3.6</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId> <artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version> <version>3.0.1</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
@ -587,7 +583,17 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId> <artifactId>maven-war-plugin</artifactId>
<version>2.6</version> <version>3.0.0</version>
</plugin>
<plugin>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-version-maven-plugin</artifactId>
<version>2.4</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.8</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>com.agilejava.docbkx</groupId> <groupId>com.agilejava.docbkx</groupId>
@ -635,17 +641,17 @@
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId> <artifactId>appassembler-maven-plugin</artifactId>
<version>1.10</version> <version>2.0.0</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId> <artifactId>build-helper-maven-plugin</artifactId>
<version>1.9.1</version> <version>1.12</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>clirr-maven-plugin</artifactId> <artifactId>clirr-maven-plugin</artifactId>
<version>2.7</version> <version>2.8</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
@ -655,7 +661,7 @@
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId> <artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.3</version> <version>3.0.4</version>
<configuration> <configuration>
<findbugsXmlOutput>true</findbugsXmlOutput> <findbugsXmlOutput>true</findbugsXmlOutput>
<xmlOutput>true</xmlOutput> <xmlOutput>true</xmlOutput>
@ -988,9 +994,6 @@
<activation> <activation>
<jdk>[1.8,1.9)</jdk> <jdk>[1.8,1.9)</jdk>
</activation> </activation>
<modules>
<module>jetty-documentation</module>
</modules>
<build> <build>
<pluginManagement> <pluginManagement>
<plugins> <plugins>
@ -1014,37 +1017,6 @@
</pluginManagement> </pluginManagement>
</build> </build>
</profile> </profile>
<profile>
<id>jdk9</id>
<activation>
<jdk>[1.9,)</jdk>
</activation>
<pluginRepositories>
<pluginRepository>
<id>apache-plugins-snapshots</id>
<url>https://repository.apache.org/content/groups/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0-SNAPSHOT</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0-SNAPSHOT</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
<profile> <profile>
<id>config</id> <id>config</id>
<activation> <activation>

View File

@ -50,13 +50,32 @@
<plugin> <plugin>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<configuration> <configuration>
<argLine>-Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar <argLine>-Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar</argLine>
</argLine>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
</profile> </profile>
<profile>
<id>jdk9</id>
<activation>
<jdk>[1.9,)</jdk>
</activation>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-java-client</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-java-server</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
</profiles> </profiles>
<build> <build>

View File

@ -1137,6 +1137,10 @@ public class AsyncIOServletTest extends AbstractTest
break; break;
case H2C: case H2C:
case H2: case H2:
// In case of HTTP/2, we not only send the request, but also the preface and
// SETTINGS frames. SETTINGS frame need to be replied, so we want to wait to
// write the reply before shutting output down, so that the test does not fail.
Thread.sleep(1000);
Session session = ((HttpConnectionOverHTTP2)connection).getSession(); Session session = ((HttpConnectionOverHTTP2)connection).getSession();
((HTTP2Session)session).getEndPoint().shutdownOutput(); ((HTTP2Session)session).getEndPoint().shutdownOutput();
break; break;

View File

@ -43,6 +43,7 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import javax.servlet.AsyncContext; import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream; import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -471,10 +472,10 @@ public class HttpClientStreamTest extends AbstractTest
@Test(expected = ExecutionException.class) @Test(expected = ExecutionException.class)
public void testInputStreamContentProviderThrowingWhileReading() throws Exception public void testInputStreamContentProviderThrowingWhileReading() throws Exception
{ {
start(new AbstractHandler() start(new AbstractHandler.ErrorDispatchHandler()
{ {
@Override @Override
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException public void doNonErrorHandle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{ {
baseRequest.setHandled(true); baseRequest.setHandled(true);
IO.copy(request.getInputStream(), response.getOutputStream()); IO.copy(request.getInputStream(), response.getOutputStream());

View File

@ -28,7 +28,6 @@ import org.eclipse.jetty.server.ForwardedRequestCustomizer;
import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.NegotiatingServerConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.ServerConnector;
@ -106,7 +105,6 @@ public class TestTransparentProxyServer
// HTTP2 factory // HTTP2 factory
HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(https_config); HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(https_config);
NegotiatingServerConnectionFactory.checkProtocolNegotiationAvailable();
ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory(); ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
alpn.setDefaultProtocol(h2.getProtocol()); alpn.setDefaultProtocol(h2.getProtocol());