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

This commit is contained in:
Greg Wilkins 2017-05-01 13:30:41 +02:00
commit 68caf72835
142 changed files with 3117 additions and 874 deletions

View File

@ -1,6 +1,39 @@
jetty-10.0.0-SNAPSHOT
jetty-9.4.4-SNAPSHOT
jetty-9.4.5-SNAPSHOT
jetty-9.4.4.v20170414 - 14 April 2017
+ 612 Support HTTP Trailer
+ 877 Programmatic servlet mappings cannot override mappings from
webdefault.xml using quickstart
+ 1201 X-Forwarded-For incorrectly set in jetty-http-forwarded.xml
+ 1334 Dispatcher.commitResponse() failure is unreported
+ 1386 Optimise session writes
+ 1411 Use short-circuit operator in websocket Frame
+ 1417 Improve classloader dumping
+ 1418 setWriteListener causes race
+ 1423 Update to gcloud datastore 0.10.0-beta
+ 1433 Wrong status message for code 417
+ 1434 Improve properties in jetty-gzip.xml
+ 1435 Apply setCharacterEncoding to static content without an assumed encoding
+ 1436 NullPointerException when calling changeSessionId
+ 1439 Allow UNC paths to function as Resource bases
+ 1440 Improve lock contention for low resources scheduling strategy
+ 1444 Deprecate Continuations
+ 1448 StackOverflowError when using URLStreamHandlerFactory in
WebAppClassloader
+ 1449 Unable to find the JVM Lib directory in WebAppContext
+ 1450 JMX does not export session statistics
+ 1452 Add tests for [want|need]ClientAuth
+ 1454 CachedContentFactory locks filesystem after first read of file
+ 1456 Error dispatch race with async write
+ 1463 SSL Renegotiate limit
+ 1466 Only use ServletContainerInitializers from server path for web.xml <
3.0
+ 1467 Change default for WebAppContext.isConfiguredDiscovered to false
+ 1469 IllegalStateException in RolloverFileOutputStream
+ 1472 Broken *.gz symlinks cause NPE in DefaultServlet.
+ 1475 SIOOBE in ContextHandler startup
jetty-9.4.3.v20170317 - 17 March 2017
+ 329 Javadoc for HttpTester and ServletTester needs to reference limited HTTP
@ -34,6 +67,13 @@ jetty-9.4.3.v20170317 - 17 March 2017
+ 1403 Move new CookieCompliance class to jetty-http
+ 1405 Cookie name cannot be blank or null
jetty-9.3.18.v20170406 - 06 April 2017
+ 877 Programmatic servlet mappings cannot override mappings from
webdefault.xml using quickstart
+ 1201 X-Forwarded-For incorrectly set in jetty-http-forwarded.xml
+ 1417 Improve classloader dumping
+ 1439 Allow UNC paths to function as Resource bases
jetty-9.3.17.v20170317 - 17 March 2017
+ 329 Javadoc for HttpTester and ServletTester needs to reference limited HTTP
version scope
@ -144,19 +184,19 @@ jetty-9.4.1.v20170120 - 20 January 2017
with WEB-INF/lib/jetty-http.jar present
+ 1234 onBadMessage called from with handled message
+ 1239 Charset=unknown produces Exception during testing
+ 1242
+ 1242
org.eclipse.jetty.client.HttpRequestAbortTest.testAbortOnCommitWithContent[1]()
results in EofException
+ 1243
+ 1243
org.eclipse.jetty.proxy.ProxyServletFailureTest.testServerException[0]()
results in ServletException
+ 1244
+ 1244
ProxyServletFailureTest.testProxyRequestStallsContentServerIdlesTimeout()
has TimeoutException visible
+ 1248
+ 1248
org.eclipse.jetty.http2.client.StreamResetTest.testServerExceptionConsumesQueuedData
results in visible Stacktrace
+ 1252
+ 1252
HttpClientStreamTest.testInputStreamContentProviderThrowingWhileReading[transport:
HTTPS]() results in Early EOF
+ 1254 9.4.x Server resource handler welcome files forwarding not working

View File

@ -111,8 +111,7 @@ public class FastFileServer
{
if (!request.getPathInfo().endsWith(URIUtil.SLASH))
{
response.sendRedirect(response.encodeRedirectURL(URIUtil
.addPaths(request.getRequestURI(), URIUtil.SLASH)));
response.sendRedirect(response.encodeRedirectURL(request.getRequestURI()+URIUtil.SLASH));
return;
}
String listing = Resource.newResource(file).getListHTML(

View File

@ -29,6 +29,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
@ -358,8 +359,6 @@ public class AnnotationConfiguration extends AbstractConfiguration
{
context.getObjectFactory().addDecorator(new AnnotationDecorator(context));
//Even if metadata is complete, we still need to scan for ServletContainerInitializers - if there are any
if (!context.getMetaData().isMetaDataComplete())
{
//If metadata isn't complete, if this is a servlet 3 webapp or isConfigDiscovered is true, we need to search for annotations
@ -655,7 +654,10 @@ public class AnnotationConfiguration extends AbstractConfiguration
public Resource getJarFor (ServletContainerInitializer service)
throws MalformedURLException, IOException
{
return TypeUtil.getLoadedFrom(service.getClass());
URI uri = TypeUtil.getLocationOfClass(service.getClass());
if (uri == null)
return null;
return Resource.newResource(uri);
}
/**
@ -875,7 +877,26 @@ public class AnnotationConfiguration extends AbstractConfiguration
}
}
}
}
}
//final pass over the non-excluded SCIs if the webapp version is < 3, in which case
//we will only call SCIs that are on the server's classpath
if (context.getServletContext().getEffectiveMajorVersion() < 3 && !context.isConfigurationDiscovered())
{
ListIterator<ServletContainerInitializer> it = nonExcludedInitializers.listIterator();
while (it.hasNext())
{
ServletContainerInitializer sci = it.next();
if (!isFromContainerClassPath(context, sci))
{
if (LOG.isDebugEnabled())
LOG.debug("Ignoring SCI {}: old web.xml version {}.{}", sci.getClass().getName(),
context.getServletContext().getEffectiveMajorVersion(),
context.getServletContext().getEffectiveMinorVersion());
it.remove();
}
}
}
if (LOG.isDebugEnabled())
{

View File

@ -581,7 +581,7 @@ public class AnnotationParser
throws Exception
{
Class<?> cz = clazz;
while (cz != null)
while (cz != Object.class)
{
if (!isParsed(cz.getName()))
{
@ -601,7 +601,7 @@ public class AnnotationParser
if (visitSuperClasses)
cz = cz.getSuperclass();
else
cz = null;
break;
}
}

Binary file not shown.

View File

@ -0,0 +1,54 @@
//
// ========================================================================
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.annotations;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
/**
* ServerServletContainerInitializer
*
*
*/
public class ServerServletContainerInitializer implements ServletContainerInitializer
{
/**
*
*/
public ServerServletContainerInitializer()
{
// TODO Auto-generated constructor stub
}
/**
* @see javax.servlet.ServletContainerInitializer#onStartup(java.util.Set, javax.servlet.ServletContext)
*/
@Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException
{
// TODO Auto-generated method stub
}
}

View File

@ -19,11 +19,20 @@
package org.eclipse.jetty.annotations;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.resource.Resource;
@ -38,6 +47,148 @@ import org.junit.Test;
*/
public class TestAnnotationConfiguration
{
public class TestableAnnotationConfiguration extends AnnotationConfiguration
{
public void assertAnnotationDiscovery (boolean b)
{
if (!b)
assertTrue(_discoverableAnnotationHandlers.isEmpty());
else
assertFalse(_discoverableAnnotationHandlers.isEmpty());
}
}
@Test
public void testAnnotationScanControl() throws Exception
{
File web25 = MavenTestingUtils.getTestResourceFile("web25.xml");
File web31true = MavenTestingUtils.getTestResourceFile("web31true.xml");
File web31false = MavenTestingUtils.getTestResourceFile("web31false.xml");
//check that a 2.5 webapp won't discover annotations
TestableAnnotationConfiguration config25 = new TestableAnnotationConfiguration();
WebAppContext context25 = new WebAppContext();
context25.setClassLoader(Thread.currentThread().getContextClassLoader());
context25.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE);
context25.setAttribute(AnnotationConfiguration.MAX_SCAN_WAIT, new Integer(0));
context25.getMetaData().setWebXml(Resource.newResource(web25));
context25.getServletContext().setEffectiveMajorVersion(2);
context25.getServletContext().setEffectiveMinorVersion(5);
config25.configure(context25);
config25.assertAnnotationDiscovery(false);
//check that a 2.5 webapp with configurationDiscovered will discover annotations
TestableAnnotationConfiguration config25b = new TestableAnnotationConfiguration();
WebAppContext context25b = new WebAppContext();
context25b.setClassLoader(Thread.currentThread().getContextClassLoader());
context25b.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE);
context25b.setAttribute(AnnotationConfiguration.MAX_SCAN_WAIT, new Integer(0));
context25b.setConfigurationDiscovered(true);
context25b.getMetaData().setWebXml(Resource.newResource(web25));
context25b.getServletContext().setEffectiveMajorVersion(2);
context25b.getServletContext().setEffectiveMinorVersion(5);
config25b.configure(context25b);
config25b.assertAnnotationDiscovery(true);
//check that a 3.x webapp with metadata true won't discover annotations
TestableAnnotationConfiguration config31 = new TestableAnnotationConfiguration();
WebAppContext context31 = new WebAppContext();
context31.setClassLoader(Thread.currentThread().getContextClassLoader());
context31.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE);
context31.setAttribute(AnnotationConfiguration.MAX_SCAN_WAIT, new Integer(0));
context31.getMetaData().setWebXml(Resource.newResource(web31true));
context31.getServletContext().setEffectiveMajorVersion(3);
context31.getServletContext().setEffectiveMinorVersion(1);
config31.configure(context31);
config31.assertAnnotationDiscovery(false);
//check that a 3.x webapp with metadata false will discover annotations
TestableAnnotationConfiguration config31b = new TestableAnnotationConfiguration();
WebAppContext context31b = new WebAppContext();
context31b.setClassLoader(Thread.currentThread().getContextClassLoader());
context31b.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE);
context31b.setAttribute(AnnotationConfiguration.MAX_SCAN_WAIT, new Integer(0));
context31b.getMetaData().setWebXml(Resource.newResource(web31false));
context31b.getServletContext().setEffectiveMajorVersion(3);
context31b.getServletContext().setEffectiveMinorVersion(1);
config31b.configure(context31b);
config31b.assertAnnotationDiscovery(true);
}
@Test
public void testSCIControl ()
throws Exception
{
File web25 = MavenTestingUtils.getTestResourceFile("web25.xml");
File web31false = MavenTestingUtils.getTestResourceFile("web31false.xml");
File web31true = MavenTestingUtils.getTestResourceFile("web31true.xml");
Set<String> sciNames = new HashSet<>(Arrays.asList("org.eclipse.jetty.annotations.ServerServletContainerInitializer", "com.acme.initializer.FooInitializer"));
//prepare an sci that will be on the webapp's classpath
File jarDir = new File(MavenTestingUtils.getTestResourcesDir().getParentFile(), "jar");
File testSciJar = new File(jarDir, "test-sci.jar");
assertTrue(testSciJar.exists());
URLClassLoader webAppLoader = new URLClassLoader(new URL[] {testSciJar.toURI().toURL()}, Thread.currentThread().getContextClassLoader());
//test 3.1 webapp loads both server and app scis
AnnotationConfiguration config = new AnnotationConfiguration();
WebAppContext context = new WebAppContext();
context.setClassLoader(webAppLoader);
context.getMetaData().setWebXml(Resource.newResource(web31true));
context.getServletContext().setEffectiveMajorVersion(3);
context.getServletContext().setEffectiveMinorVersion(1);
List<ServletContainerInitializer> scis = config.getNonExcludedInitializers(context);
assertNotNull(scis);
assertEquals(2, scis.size());
assertTrue (sciNames.contains(scis.get(0).getClass().getName()));
assertTrue (sciNames.contains(scis.get(1).getClass().getName()));
//test a 3.1 webapp with metadata-complete=false loads both server and webapp scis
config = new AnnotationConfiguration();
context = new WebAppContext();
context.setClassLoader(webAppLoader);
context.getMetaData().setWebXml(Resource.newResource(web31false));
context.getServletContext().setEffectiveMajorVersion(3);
context.getServletContext().setEffectiveMinorVersion(1);
scis = config.getNonExcludedInitializers(context);
assertNotNull(scis);
assertEquals(2, scis.size());
assertTrue (sciNames.contains(scis.get(0).getClass().getName()));
assertTrue (sciNames.contains(scis.get(1).getClass().getName()));
//test 2.5 webapp with configurationDiscovered=false loads only server scis
config = new AnnotationConfiguration();
context = new WebAppContext();
context.setClassLoader(webAppLoader);
context.getMetaData().setWebXml(Resource.newResource(web25));
context.getServletContext().setEffectiveMajorVersion(2);
context.getServletContext().setEffectiveMinorVersion(5);
scis = config.getNonExcludedInitializers(context);
assertNotNull(scis);
assertEquals(1, scis.size());
assertTrue ("org.eclipse.jetty.annotations.ServerServletContainerInitializer".equals(scis.get(0).getClass().getName()));
//test 2.5 webapp with configurationDiscovered=true loads both server and webapp scis
config = new AnnotationConfiguration();
context = new WebAppContext();
context.setConfigurationDiscovered(true);
context.setClassLoader(webAppLoader);
context.getMetaData().setWebXml(Resource.newResource(web25));
context.getServletContext().setEffectiveMajorVersion(2);
context.getServletContext().setEffectiveMinorVersion(5);
scis = config.getNonExcludedInitializers(context);
assertNotNull(scis);
assertEquals(2, scis.size());
assertTrue (sciNames.contains(scis.get(0).getClass().getName()));
assertTrue (sciNames.contains(scis.get(1).getClass().getName()));
}
@Test
public void testGetFragmentFromJar() throws Exception
{

View File

@ -0,0 +1 @@
org.eclipse.jetty.annotations.ServerServletContainerInitializer

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>Test 2.5 WebApp</display-name>
</web-app>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
metadata-complete="false"
version="3.1">
<display-name>Test 31 WebApp</display-name>
</web-app>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
metadata-complete="true"
version="3.1">
<display-name>Test 31 WebApp</display-name>
</web-app>

243
jetty-bom/pom.xml Normal file
View File

@ -0,0 +1,243 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>10.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-bom</artifactId>
<name>Jetty :: Bom</name>
<description>Jetty BOM artifact</description>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-annotations</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>cdi-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>cdi-full-servlet</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>cdi-servlet</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>cdi-websocket</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-continuation</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-gcloud-session-manager</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-home</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-http</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-http-spi</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-infinispan</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-io</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jaas</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jaspi</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jmx</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jndi</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-memcached-sessions</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-monitor</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-nosql</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-osgi-boot</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-osgi-boot-jsp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-osgi-boot-warurl</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-plus</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-proxy</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-quickstart</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-rewrite</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-security</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-spring</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-start</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-unixsocket</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util-ajax</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>javax-websocket-client-impl</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>javax-websocket-server-impl</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>javax-websocket-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>javax-websocket-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>javax-websocket-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>javax-websocket-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>javax-websocket-servlet</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-xml</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>

View File

@ -13,14 +13,13 @@ lib/cdi/
maven://javax.enterprise/cdi-api/1.2|lib/cdi/javax.enterprise.cdi-api-1.2.jar
maven://javax.interceptor/javax.interceptor-api/1.2|lib/cdi/javax.interceptor-api-1.2.jar
maven://javax.inject/javax.inject/1|lib/cdi/javax.inject-1.0.jar
maven://org.jboss.weld.servlet/weld-servlet-core/2.2.9.Final|lib/cdi/weld-servlet-core-2.2.9.Final.jar
maven://org.jboss.weld.environment/weld-environment-common/2.2.9.Final|lib/cdi/weld-environment-common-2.2.9.Final.jar
maven://org.jboss.weld/weld-core-impl/2.2.9.Final|lib/cdi/weld-core-impl-2.2.9.Final.jar
maven://org.jboss.classfilewriter/jboss-classfilewriter/1.0.5.Final|lib/cdi/jboss-classfilewriter-1.0.5.Final.jar
maven://com.google.guava/guava/13.0.1|lib/cdi/com.google.guava.guava-13.0.1.jar
maven://org.jboss.weld/weld-spi/2.2.SP3|lib/cdi/weld-spi-2.2.SP3.jar
maven://org.jboss.weld/weld-api/2.2.SP3|lib/cdi/weld-api-2.2.SP3.jar
maven://org.jboss.logging/jboss-logging/3.1.3.GA|lib/cdi/jboss-logging-3.1.3.GA.jar
maven://org.jboss.weld.servlet/weld-servlet-core/2.4.3.Final|lib/cdi/weld-servlet-core-2.4.3.Final.jar
maven://org.jboss.weld.environment/weld-environment-common/2.4.3.Final|lib/cdi/weld-environment-common-2.4.3.Final.jar
maven://org.jboss.weld/weld-core-impl/2.4.3.Final|lib/cdi/weld-core-impl-2.4.3.Final.jar
maven://org.jboss.classfilewriter/jboss-classfilewriter/1.1.2.Final|lib/cdi/jboss-classfilewriter-1.1.2.Final.jar
maven://org.jboss.weld/weld-spi/2.4.SP1|lib/cdi/weld-spi-2.4.SP1.jar
maven://org.jboss.weld/weld-api/2.4.SP1|lib/cdi/weld-api-2.4.SP1.jar
maven://org.jboss.logging/jboss-logging/3.2.1.Final|lib/cdi/jboss-logging-3.2.1.Final.jar
[lib]

View File

@ -11,7 +11,7 @@
<url>http://www.eclipse.org/jetty</url>
<packaging>pom</packaging>
<properties>
<weld.version>2.2.9.Final</weld.version>
<weld.version>2.4.3.Final</weld.version>
</properties>
<modules>

View File

@ -18,6 +18,7 @@
package org.eclipse.jetty.deploy;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -45,6 +46,8 @@ import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.xml.XmlConfiguration;
/**
* The Deployment Manager.
@ -595,4 +598,20 @@ public class DeploymentManager extends ContainerLifeCycle
{
return getApps(_lifecycle.getNodeByName(nodeName));
}
public void scope(XmlConfiguration xmlc, Resource webapp)
throws IOException
{
xmlc.getIdMap().put("Server", getServer());
Resource home = Resource.newResource(System.getProperty("jetty.home","."));
xmlc.getProperties().put("jetty.home",home.toString());
xmlc.getProperties().put("jetty.home.uri",home.getURI().toString());
Resource base = Resource.newResource(System.getProperty("jetty.base",home.toString()));
xmlc.getProperties().put("jetty.base",base.toString());
xmlc.getProperties().put("jetty.base.uri",base.getURI().toString());
xmlc.getProperties().put("jetty.webapp",webapp.toString());
xmlc.getProperties().put("jetty.webapps",webapp.getFile().toPath().getParent().toString());
}
}

View File

@ -94,15 +94,8 @@ public class GlobalWebappConfigBinding implements AppLifeCycle.Binding
if (globalContextSettings.exists())
{
XmlConfiguration jettyXmlConfig = new XmlConfiguration(globalContextSettings.getInputStream());
Resource resource = Resource.newResource(app.getOriginId());
File file = resource.getFile();
jettyXmlConfig.getIdMap().put("Server",app.getDeploymentManager().getServer());
jettyXmlConfig.getProperties().put("jetty.home",System.getProperty("jetty.home","."));
jettyXmlConfig.getProperties().put("jetty.base",System.getProperty("jetty.base","."));
jettyXmlConfig.getProperties().put("jetty.webapp",file.getCanonicalPath());
jettyXmlConfig.getProperties().put("jetty.webapps",file.getParentFile().getCanonicalPath());
app.getDeploymentManager().scope(jettyXmlConfig,resource);
WebAppClassLoader.runWithServerClassAccess(()->{jettyXmlConfig.configure(context);return null;});
}
else

View File

@ -294,11 +294,7 @@ public class WebAppProvider extends ScanningAppProvider
}
};
xmlc.getIdMap().put("Server", getDeploymentManager().getServer());
xmlc.getProperties().put("jetty.home",System.getProperty("jetty.home","."));
xmlc.getProperties().put("jetty.base",System.getProperty("jetty.base","."));
xmlc.getProperties().put("jetty.webapp",file.getCanonicalPath());
xmlc.getProperties().put("jetty.webapps",file.getParentFile().getCanonicalPath());
getDeploymentManager().scope(xmlc,resource);
if (getConfigurationManager() != null)
xmlc.getProperties().putAll(getConfigurationManager().getProperties());
@ -354,7 +350,6 @@ public class WebAppProvider extends ScanningAppProvider
return webAppContext;
}
/* ------------------------------------------------------------ */
@Override
protected void fileChanged(String filename) throws Exception

View File

@ -58,7 +58,7 @@
<allow-uri-read>true</allow-uri-read>
<toc>true</toc>
<revnumber>${project.version}</revnumber>
<JDURL>http://download.eclipse.org/jetty/stable-9/apidocs</JDURL>
<JDURL>http://www.eclipse.org/jetty/javadoc/${project.version}</JDURL>
<JXURL>http://download.eclipse.org/jetty/stable-9/xref</JXURL>
<SRCDIR>${basedir}/..</SRCDIR>
<GITBROWSEURL>https://github.com/eclipse/jetty.project/tree/master</GITBROWSEURL>

View File

@ -34,9 +34,9 @@ Jetty currently has two levels of request statistic collection:
* Subclasses of `AbstractConnector` class optionally can collect statistics about connections as well as number of requests.
* The `StatisticsHandler` class may be used to collect request statistics.
In addition to these, subclasses of the `AbstractSessionHandler` class optionally can collect session statistics.
In addition to these, subclasses of the `SessionHandler` and `DefaultSessionCache` classes optionally can collect session statistics.
`AbstractConnector` and `AbstractSessionHandler` statistics are turned off by default and must either be configured manually for each instance or turned on via JMX interface.
`AbstractConnector`, `SessionHandler` and `DefaultSessionCache` statistics are turned off by default and must either be configured manually for each instance or turned on via JMX interface.
The `StatisticsHandler` is not included in default Jetty configuration, and needs to be configured manually.
_____

View File

@ -19,7 +19,7 @@
This chapter discusses various options for configuring logging.
//include::configuring-jetty-logging.adoc[]
include::configuring-jetty-logging.adoc[]
include::default-logging-with-stderrlog.adoc[]
include::configuring-jetty-request-logs.adoc[]
include::configuring-logging-modules.adoc[]

View File

@ -63,14 +63,14 @@ By default, `jetty-runner` implements all Configuration Classes so that users ca
If you wish to only implement certain Configuration Classes, they will need to be defined in the context xml for the webapp/context.
The default Configuration Classes are:
`org.eclipse.jetty.webapp.WebInfConfiguration`
`org.eclipse.jetty.webapp.WebXmlConfiguration`
`org.eclipse.jetty.webapp.MetaInfConfiguration`
`org.eclipse.jetty.webapp.FragmentConfiguration`
`org.eclipse.jetty.webapp.JettyWebXmlConfiguration`
`org.eclipse.jetty.plus.webapp.EnvConfiguration`
`org.eclipse.jetty.plus.webapp.PlusConfiguration`
`org.eclipse.jetty.annotations.AnnotationConfiguration`
`org.eclipse.jetty.webapp.WebInfConfiguration`
`org.eclipse.jetty.webapp.WebXmlConfiguration`
`org.eclipse.jetty.webapp.MetaInfConfiguration`
`org.eclipse.jetty.webapp.FragmentConfiguration`
`org.eclipse.jetty.webapp.JettyWebXmlConfiguration`
`org.eclipse.jetty.plus.webapp.EnvConfiguration`
`org.eclipse.jetty.plus.webapp.PlusConfiguration`
`org.eclipse.jetty.annotations.AnnotationConfiguration`
You can learn more about implementing specific Configuration Classes link:https://www.eclipse.org/jetty/documentation/current/configuring-webapps.html#webapp-configurations[here.]

View File

@ -18,6 +18,8 @@
=== Non-Clustered Session Management: File System
==== Enabling File System Sessions
When using the Jetty distribution, you will first need to enable the `session-store-file` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line.
[source, screen, subs="{sub-order}"]
@ -33,16 +35,19 @@ MKDIR : ${jetty.base}/sessions
INFO : Base directory was modified
----
//TODO - Callout default Session file location - note it is configurable
Doing this enables the File System Session module and any dependent modules or files needed for it to run on the server.
The example above is running an fresh `${jetty.base}` with nothing enabled.
The example above is using a fresh `${jetty.base}` with nothing else enabled.
When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-file` module as well as the `sessions` and `server` modules, which are required for the File System session management to operate.
Additionally a `${jetty.base}/sessions` directory was created.
By default Session files will be saved to this directory.
In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `${jetty.base}`.
In addition to adding these modules to the classpath of the server, several ini configuration files were added to the `${jetty.base}/start.d` directory.
Opening the `start.d/session-store-file.ini` will show a list of all the configurable options for the file system session module:
==== Configuring File System Session Properties
Opening `start.d/session-store-file.ini` will show a list of all the configurable options for the file system session module:
[source, screen, subs="{sub-order}"]
----
@ -54,6 +59,7 @@ Opening the `start.d/session-store-file.ini` will show a list of all the configu
jetty.session.file.storeDir=${jetty.base}/sessions
#jetty.session.file.deleteUnrestorableFiles=false
#jetty.session.savePeriod.seconds=0
----
jetty.session.storeDir::
@ -61,3 +67,14 @@ This defines the location for storage of Session files.
jetty.session.file.deleteUnrestorableFiles::
Boolean.
If set to true, unreadable files will be deleted: this is useful to prevent repeated logging of the same error when the scavenger periodically (re-) attempts to load the corrupted information for a session in order to expire it.
jetty.session.savePeriod.seconds=0::
By default whenever the last concurrent request leaves a session, that session is always persisted via the `SessionDataStore`, even if the only thing that changed on the session is its updated last access time.
A non-zero value means that the `SessionDataStore` will skip persisting the session if only the access time changed, and it has been less than `savePeriod` seconds since the last time the session was written.
+
____
[NOTE]
Configuring `savePeriod` is useful if your persistence technology is very slow/costly for writes.
In a clustered environment, there is a risk of the last access time of the session being out-of-date in the shared store for up to `savePeriod` seconds.
This allows the possibility that a node may prematurely expire the session, even though it is in use by another node.
Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - there is no point in setting a `savePeriod` that is larger than the `maxIdleTime`.
____

View File

@ -58,7 +58,7 @@ To enable communication using the GCloud Emulator:
* Ensure you have the GCloud SDK installed: https://cloud.google.com/sdk/?hl=en
* Follow the instructions link:https://cloud.google.com/datastore/docs/tools/datastore-emulator[here] on how to start the GCloud datastore emulator, and how to propagate the environment variables that it creates to the terminal in which you run Jetty.
==== Configuring the Google Cloud DataStore Module
==== Enabling the Google Cloud DataStore Module
When using the Jetty distribution, you will first need to enable the `session-store-gcloud` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line.
@ -177,7 +177,7 @@ Usage: java -jar $JETTY_HOME/start.jar [options] [properties] [configs]
----
Doing this enables the GCloud Session module and any dependent session modules or files needed for it to run on the server.
The example above is running an fresh `${jetty.base}` with nothing enabled.
The example above is using a fresh `${jetty.base}` with nothing else enabled.
Because the Google Cloud DataStore is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case).
You will notice, however, that the above output presented a warning: GCloud requires certain Java Commons Logging features to work correctly.
@ -200,13 +200,16 @@ INFO : Base directory was modified
----
When the `--add-to-start` argument was added to the command line the first time, it enabled the the `session-store-gcloud` module as well as several others, such as as `server`, `sessions`, `webapp` and others which are required for GCloud session management to operate; the `slf4j-simple-impl` and its dependent modules were added when the the command was run the second time.
In addition to adding these modules to the classpath of the server it also added the respective configuration files to the `start.d` directory of the `${jetty.base}`.
In addition to adding these modules to the classpath of the server it also added the respective configuration files to the `${jetty.base}start.d` directory.
____
[NOTE]
If you have updated versions of the jar files automatically downloaded by Jetty, you can place them in the associated `${jetty.base}/lib/` directory and use the `--skip-file-validation=<module name>` command line option to prevent errors when starting your server.
____
==== Configuring GCloud Session Properties
Opening the `start.d/session-store-gcloud.ini` will display a list of all the configurable properties for the Google Cloud DataStore module:
[source, screen, subs="{sub-order}"]
@ -219,6 +222,8 @@ Opening the `start.d/session-store-gcloud.ini` will display a list of all the co
## GCloudDatastore Session config
#jetty.session.gracePeriod.seconds=3600
#jetty.session.savePeriod.seconds=0
#jetty.session.gcloud.maxRetries=5
#jetty.session.gcloud.backoffMs=1000
#jetty.session.gcloud.namespace=
@ -236,6 +241,20 @@ Opening the `start.d/session-store-gcloud.ini` will display a list of all the co
#jetty.session.gcloud.model.attributes=attributes
----
jetty.session.gracePeriod.seconds::
Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
jetty.session.savePeriod.seconds=0::
By default whenever the last concurrent request leaves a session, that session is always persisted via the `SessionDataStore`, even if the only thing that changed on the session is its updated last access time.
A non-zero value means that the `SessionDataStore` will skip persisting the session if only the access time changed, and it has been less than `savePeriod` seconds since the last time the session was written.
+
____
[NOTE]
Configuring `savePeriod` is useful if your persistence technology is very slow/costly for writes.
In a clustered environment, there is a risk of the last access time of the session being out-of-date in the shared store for up to `savePeriod` seconds.
This allows the possibility that a node may prematurely expire the session, even though it is in use by another node.
Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - there is no point in setting a `savePeriod` that is larger than the `maxIdleTime`.
____
jetty.session.gcloud.maxRetries::
Maxmium number of tries to connect to GCloud DataStore to write sessions.
jetty.session.gcloud.backoffMs::

View File

@ -18,6 +18,8 @@
=== Clustered Session Management: Inifinspan
==== Enabling Infinispan Sessions
When using the Jetty distribution, you will first need to enable the `session-store-infinispan-remote` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line.
[source, screen, subs="{sub-order}"]
@ -50,17 +52,21 @@ INFO : Base directory was modified
----
Doing this enables the remote Infinispan Session module and any dependent modules or files needed for it to run on the server.
The example above is running an fresh `${jetty.base}` with nothing enabled.
The example above is using a fresh `${jetty.base}` with nothing else enabled.
Because Infinispan is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case).
When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-infinispan-remote` module as well as the `sessions` and `server` modules, which are required for Infinispan session management to operate.
It also downloaded the needed Infinispan-specific jar files and created a directory named `${jetty.base}/lib/infinispan/` to house them.
In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `${jetty.base}`.
In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `${jetty.base}/start.d` directory.
____
[NOTE]
If you have updated versions of the jar files automatically downloaded by Jetty, you can place them in the associated `${jetty.base}/lib/` directory and use the `--skip-file-validation=<module name>` command line option to prevent errors when starting your server.
____
==== Configuring Inifinspan Remote Properties
Opening the `start.d/session-store-infinispan-remote.ini` will show a list of all the configurable options for the JDBC module:
[source, screen, subs="{sub-order}"]
@ -74,6 +80,7 @@ Opening the `start.d/session-store-infinispan-remote.ini` will show a list of al
#jetty.session.infinispan.remoteCacheName=sessions
#jetty.session.infinispan.idleTimeout.seconds=0
#jetty.session.gracePeriod.seconds=3600
#jetty.session.savePeriod.seconds=0
----
jetty.session.infinispan.remoteCacheName::
@ -82,7 +89,17 @@ jetty.session.infinispan.idleTimeout.seconds::
Amount of time, in seconds, that the system allows the connector to remain idle before closing the connection.
jetty.session.gracePeriod.seconds::
Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
jetty.session.savePeriod.seconds=0::
By default whenever the last concurrent request leaves a session, that session is always persisted via the `SessionDataStore`, even if the only thing that changed on the session is its updated last access time.
A non-zero value means that the `SessionDataStore` will skip persisting the session if only the access time changed, and it has been less than `savePeriod` seconds since the last time the session was written.
+
____
[NOTE]
Configuring `savePeriod` is useful if your persistence technology is very slow/costly for writes.
In a clustered environment, there is a risk of the last access time of the session being out-of-date in the shared store for up to `savePeriod` seconds.
This allows the possibility that a node may prematurely expire the session, even though it is in use by another node.
Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - there is no point in setting a `savePeriod` that is larger than the `maxIdleTime`.
____
==== Configuring Embedded Inifinspan Clustering
@ -113,8 +130,40 @@ INFO : Base directory was modified
----
Doing this enables the embedded Infinispan Session module and any dependent modules or files needed for it to run on the server.
The example above is running an fresh `${jetty.base}` with nothing enabled.
The example above is using a fresh `${jetty.base}` with nothing else enabled.
Because Infinispan is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case).
When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-infinispan-embedded` module as well as the `sessions` and `server` modules, which are required for Infinispan session management to operate.
It also downloaded the needed Infinispan-specific jar files and created a directory named `${jetty.base}/lib/infinispan/` to house them.
In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `${jetty.base}`.
In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `${jetty.base}/start.d` directory.
==== Configuring Inifinspan Embedded Properties
Opening the `start.d/session-store-infinispan-remote.ini` will show a list of all the configurable options for the JDBC module:
[source, screen, subs="{sub-order}"]
----
# ---------------------------------------
# Module: session-store-infinispan-embedded
# Enables session data store in a local Infinispan cache
# ---------------------------------------
--module=session-store-infinispan-embedded
#jetty.session.gracePeriod.seconds=3600
#jetty.session.savePeriod.seconds=0
----
jetty.session.gracePeriod.seconds::
Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
jetty.session.savePeriod.seconds=0::
By default whenever the last concurrent request leaves a session, that session is always persisted via the `SessionDataStore`, even if the only thing that changed on the session is its updated last access time.
A non-zero value means that the `SessionDataStore` will skip persisting the session if only the access time changed, and it has been less than `savePeriod` seconds since the last time the session was written.
+
____
[NOTE]
Configuring `savePeriod` is useful if your persistence technology is very slow/costly for writes.
In a clustered environment, there is a risk of the last access time of the session being out-of-date in the shared store for up to `savePeriod` seconds.
This allows the possibility that a node may prematurely expire the session, even though it is in use by another node.
Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - there is no point in setting a `savePeriod` that is larger than the `maxIdleTime`.
____

View File

@ -18,6 +18,8 @@
=== Clustered Session Management: JDBC
==== Enabling JDBC Sessions
When using the Jetty distribution, you will first need to enable the `session-store-jdbc` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line.
[source, screen, subs="{sub-order}"]
@ -34,9 +36,13 @@ INFO : Base directory was modified
----
Doing this enables the JDBC Session module and any dependent modules or files needed for it to run on the server.
The example above is running an fresh `${jetty.base}` with nothing enabled.
The example above is using a fresh `${jetty.base}` with nothing else enabled.
When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-jdbc` module as well as the `sessions` and `server` modules, which are required for JDBC session management to operate.
In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `${jetty.base}`.
In addition to adding these modules to the classpath of the server, several ini configuration files were added to the `${jetty.base}/start.d` directory.
==== Configuring JDBC Session Properties
Opening the `start.d/session-store-jdbc.ini` will show a list of all the configurable options for the JDBC module:
@ -81,6 +87,17 @@ db-connection-type=datasource
jetty.session.gracePeriod.seconds::
Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
jetty.session.savePeriod.seconds=0::
By default whenever the last concurrent request leaves a session, that session is always persisted via the `SessionDataStore`, even if the only thing that changed on the session is its updated last access time.
A non-zero value means that the `SessionDataStore` will skip persisting the session if only the access time changed, and it has been less than `savePeriod` seconds since the last time the session was written.
+
____
[NOTE]
Configuring `savePeriod` is useful if your persistence technology is very slow/costly for writes.
In a clustered environment, there is a risk of the last access time of the session being out-of-date in the shared store for up to `savePeriod` seconds.
This allows the possibility that a node may prematurely expire the session, even though it is in use by another node.
Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - there is no point in setting a `savePeriod` that is larger than the `maxIdleTime`.
____
db-connection-type::
Set to either `datasource` or `driver` depending on the type of connection being used.

View File

@ -18,6 +18,8 @@
=== Clustered Session Management: MongoDB
==== Enabling MongoDB Sessions
When using the Jetty distribution, you will first need to enable the `session-store-mongo` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line.
[source, screen, subs="{sub-order}"]
@ -49,17 +51,21 @@ INFO : Base directory was modified
----
Doing this enables the MongoDB Session module and any dependent modules or files needed for it to run on the server.
The example above is running an fresh `${jetty.base}` with nothing enabled.
The example above is using a fresh `${jetty.base}` with nothing else enabled.
Because MongoDB is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case).
When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-mongo` module as well as the `sessions` and `server` modules, which are required for MongoDB session management to operate..
It also downloaded the needed Mongo-specific jar file and created a directory named `${jetty.base}/lib/nosql/` to house it.
In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `${jetty.base}`.
In addition to adding these modules to the classpath of the server, several ini configuration files were added to the `${jetty.base}/start.d` directory.
____
[NOTE]
If you have updated versions of the jar files automatically downloaded by Jetty, you can place them in the associated `${jetty.base}/lib/` directory and use the `--skip-file-validation=<module name>` command line option to prevent errors when starting your server.
____
==== Configuring MongoDB Session Properties
Opening the `start.d/session-store-mongo.ini` will show a list of all the configurable options for the MongoDB module:
[source, screen, subs="{sub-order}"]
@ -73,6 +79,7 @@ Opening the `start.d/session-store-mongo.ini` will show a list of all the config
#jetty.session.mongo.dbName=HttpSessions
#jetty.session.mongo.collectionName=jettySessions
#jetty.session.gracePeriod.seconds=3600
#jetty.session.savePeriod.seconds=0
connection-type=address
#jetty.session.mongo.host=localhost
@ -82,6 +89,20 @@ connection-type=address
#jetty.session.mongo.connectionString=mongodb://localhost
----
jetty.session.gracePeriod.seconds::
Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
jetty.session.savePeriod.seconds=0::
By default whenever the last concurrent request leaves a session, that session is always persisted via the `SessionDataStore`, even if the only thing that changed on the session is its updated last access time.
A non-zero value means that the `SessionDataStore` will skip persisting the session if only the access time changed, and it has been less than `savePeriod` seconds since the last time the session was written.
+
____
[NOTE]
Configuring `savePeriod` is useful if your persistence technology is very slow/costly for writes.
In a clustered environment, there is a risk of the last access time of the session being out-of-date in the shared store for up to `savePeriod` seconds.
This allows the possibility that a node may prematurely expire the session, even though it is in use by another node.
Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - there is no point in setting a `savePeriod` that is larger than the `maxIdleTime`.
____
jetty.session.mongo.dbName::
Name of the database in Mongo used to store the Session collection.
jetty.session.mongo.collectionName::

View File

@ -52,7 +52,7 @@ META-INF/web-fragment.xml
===== Anatomy of a Configuration Class
A Configuration class is called 5 times in different phases of the link:http://download.eclipse.org/jetty/stable-9/apidocs/org/eclipse/jetty/webapp/WebAppContext.html[`WebAppContext's`] lifecycle:
A Configuration class is called 5 times in different phases of the link:{JDURL}/org/eclipse/jetty/webapp/WebAppContext.html[`WebAppContext's`] lifecycle:
preConfigure::
As the `WebAppContext` is starting up this phase is executed.

View File

@ -122,7 +122,7 @@ An example:
[[jaas-step-2]]
===== Step 2
Set up your `LoginModule` in a configuration file, following the http://java.sun.com/j2se/1.4.2/docs/api/javax/security/auth/login/Configuration.html[syntax rules] :
Set up your `LoginModule` in a configuration file, following the https://docs.oracle.com/javase/7/docs/api/javax/security/auth/login/Configuration.html[syntax rules] :
[source,ini]
----

View File

@ -13,7 +13,7 @@
<name>Jetty :: GCloud</name>
<properties>
<gcloud.version>0.10.0-beta</gcloud.version>
<gcloud.version>1.0.0</gcloud.version>
</properties>
<modules>

View File

@ -37,7 +37,7 @@
<extensions>true</extensions>
<configuration>
<instructions>
<Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.http.HttpFieldPreEncoder)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
<Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.http.HttpFieldPreEncoder)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
<!--
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
-->

View File

@ -47,11 +47,9 @@ import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.ExecutionStrategy;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
import org.eclipse.jetty.util.thread.Scheduler;
import org.eclipse.jetty.util.thread.strategy.ProduceConsume;
/**
* <p>{@link HTTP2Client} provides an asynchronous, non-blocking implementation
@ -126,8 +124,8 @@ public class HTTP2Client extends ContainerLifeCycle
private long connectTimeout = 10000;
private int inputBufferSize = 8192;
private List<String> protocols = Arrays.asList("h2", "h2-17", "h2-16", "h2-15", "h2-14");
private int initialSessionRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
private int initialStreamRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
private int initialSessionRecvWindow = 16 * 1024 * 1024;
private int initialStreamRecvWindow = 8 * 1024 * 1024;
private FlowControlStrategy.Factory flowControlStrategyFactory = () -> new BufferingFlowControlStrategy(0.5F);
@Override

View File

@ -28,6 +28,7 @@ import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http2.FlowControlStrategy;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.api.server.ServerSessionListener;
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
@ -55,7 +56,10 @@ public class AbstractTest
protected void start(HttpServlet servlet) throws Exception
{
prepareServer(new HTTP2ServerConnectionFactory(new HttpConfiguration()));
HTTP2ServerConnectionFactory connectionFactory = new HTTP2ServerConnectionFactory(new HttpConfiguration());
connectionFactory.setInitialSessionRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
connectionFactory.setInitialStreamRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
prepareServer(connectionFactory);
ServletContextHandler context = new ServletContextHandler(server, "/", true, false);
context.addServlet(new ServletHolder(servlet), servletPath + "/*");
customizeContext(context);
@ -71,7 +75,10 @@ public class AbstractTest
protected void start(ServerSessionListener listener) throws Exception
{
prepareServer(new RawHTTP2ServerConnectionFactory(new HttpConfiguration(), listener));
RawHTTP2ServerConnectionFactory connectionFactory = new RawHTTP2ServerConnectionFactory(new HttpConfiguration(), listener);
connectionFactory.setInitialSessionRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
connectionFactory.setInitialStreamRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
prepareServer(connectionFactory);
server.start();
prepareClient();
@ -93,6 +100,8 @@ public class AbstractTest
QueuedThreadPool clientExecutor = new QueuedThreadPool();
clientExecutor.setName("client");
client.setExecutor(clientExecutor);
client.setInitialSessionRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
client.setInitialStreamRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
}
protected Session newClient(Session.Listener listener) throws Exception

View File

@ -72,6 +72,8 @@ public class FlowControlStalledTest
serverExecutor.setName("server");
server = new Server(serverExecutor);
RawHTTP2ServerConnectionFactory connectionFactory = new RawHTTP2ServerConnectionFactory(new HttpConfiguration(), listener);
connectionFactory.setInitialSessionRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
connectionFactory.setInitialStreamRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
connectionFactory.setFlowControlStrategyFactory(flowControlFactory);
connector = new ServerConnector(server, connectionFactory);
server.addConnector(connector);
@ -81,6 +83,8 @@ public class FlowControlStalledTest
QueuedThreadPool clientExecutor = new QueuedThreadPool();
clientExecutor.setName("client");
client.setExecutor(clientExecutor);
client.setInitialSessionRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
client.setInitialStreamRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
client.setFlowControlStrategyFactory(flowControlFactory);
client.start();
}

View File

@ -63,7 +63,6 @@ import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.Invocable.InvocationType;
import org.junit.After;
import org.junit.Assert;
import org.junit.Ignore;
@ -86,6 +85,8 @@ public abstract class FlowControlStrategyTest
serverExecutor.setName("server");
server = new Server(serverExecutor);
RawHTTP2ServerConnectionFactory connectionFactory = new RawHTTP2ServerConnectionFactory(new HttpConfiguration(), listener);
connectionFactory.setInitialSessionRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
connectionFactory.setInitialStreamRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
connectionFactory.setFlowControlStrategyFactory(FlowControlStrategyTest.this::newFlowControlStrategy);
connector = new ServerConnector(server, connectionFactory);
server.addConnector(connector);
@ -95,6 +96,8 @@ public abstract class FlowControlStrategyTest
QueuedThreadPool clientExecutor = new QueuedThreadPool();
clientExecutor.setName("client");
client.setExecutor(clientExecutor);
client.setInitialSessionRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
client.setInitialStreamRecvWindow(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
client.setFlowControlStrategyFactory(FlowControlStrategyTest.this::newFlowControlStrategy);
client.start();
}

View File

@ -42,8 +42,8 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
private final Connection.Listener connectionListener = new ConnectionListener();
private final HttpConfiguration httpConfiguration;
private int maxDynamicTableSize = 4096;
private int initialStreamRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
private int initialSessionRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
private int initialSessionRecvWindow = 1024 * 1024;
private int initialStreamRecvWindow = 512 * 1024;
private int maxConcurrentStreams = 128;
private int maxHeaderBlockFragment = 0;
private FlowControlStrategy.Factory flowControlStrategyFactory = () -> new BufferingFlowControlStrategy(0.5F);
@ -54,7 +54,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
this(httpConfiguration,"h2");
}
protected AbstractHTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration, String... protocols)
protected AbstractHTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration, @Name("protocols") String... protocols)
{
super(protocols);
for (String p:protocols)

View File

@ -54,7 +54,7 @@ public class HTTP2CServerConnectionFactory extends HTTP2ServerConnectionFactory
this(httpConfiguration,"h2c");
}
public HTTP2CServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration, String... protocols)
public HTTP2CServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration, @Name("protocols") String... protocols)
{
super(httpConfiguration,protocols);
for (String p:protocols)

View File

@ -89,6 +89,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection
private final AtomicLong totalResponses = new AtomicLong();
private final ServerSessionListener listener;
private final HttpConfiguration httpConfig;
private boolean recycleHttpChannels;
public HTTP2ServerConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, HttpConfiguration httpConfig, ServerParser parser, ISession session, int inputBufferSize, ServerSessionListener listener)
{
@ -115,6 +116,16 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection
return (ServerParser)super.getParser();
}
public boolean isRecycleHttpChannels()
{
return recycleHttpChannels;
}
public void setRecycleHttpChannels(boolean recycleHttpChannels)
{
this.recycleHttpChannels = recycleHttpChannels;
}
@Override
public void onUpgradeTo(ByteBuffer buffer)
{
@ -234,7 +245,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection
private HttpChannelOverHTTP2 provideHttpChannel(Connector connector, IStream stream)
{
HttpChannelOverHTTP2 channel = pollChannel();
HttpChannelOverHTTP2 channel = pollHttpChannel();
if (channel != null)
{
channel.getHttpTransport().setStream(stream);
@ -258,19 +269,29 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection
return new ServerHttpChannelOverHTTP2(connector, httpConfig, getEndPoint(), transport);
}
private void offerChannel(HttpChannelOverHTTP2 channel)
private void offerHttpChannel(HttpChannelOverHTTP2 channel)
{
synchronized (this)
if (isRecycleHttpChannels())
{
channels.offer(channel);
synchronized (this)
{
channels.offer(channel);
}
}
}
private HttpChannelOverHTTP2 pollChannel()
private HttpChannelOverHTTP2 pollHttpChannel()
{
synchronized (this)
if (isRecycleHttpChannels())
{
return channels.poll();
synchronized (this)
{
return channels.poll();
}
}
else
{
return null;
}
}
@ -336,7 +357,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection
{
getStream().removeAttribute(IStream.CHANNEL_ATTRIBUTE);
super.recycle();
offerChannel(this);
offerHttpChannel(this);
}
@Override

View File

@ -53,7 +53,7 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF
super(httpConfiguration);
}
public HTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration,String... protocols)
public HTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration, @Name("protocols") String... protocols)
{
super(httpConfiguration,protocols);
}

View File

@ -40,6 +40,7 @@ import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpInput;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.log.Log;
@ -329,9 +330,17 @@ public class HttpChannelOverHTTP2 extends HttpChannel
{
getHttpTransport().onStreamFailure(failure);
if (onEarlyEOF())
handle();
{
ContextHandler handler = getState().getContextHandler();
if (handler != null)
handler.handle(getRequest(), this);
else
handle();
}
else
{
getState().asyncError(failure);
}
}
protected void consumeInput()

View File

@ -268,14 +268,17 @@ public class HttpTransportOverHTTP2 implements HttpTransport
{
private State state = State.IDLE;
private Callback callback;
private Throwable failure;
private boolean commit;
public boolean start(Callback callback, boolean commit)
{
State state;
Throwable failure;
synchronized (this)
{
state = this.state;
failure = this.failure;
if (state == State.IDLE)
{
this.state = State.WRITING;
@ -284,7 +287,9 @@ public class HttpTransportOverHTTP2 implements HttpTransport
return true;
}
}
callback.failed(new IllegalStateException("Invalid transport state: " + state));
if (failure == null)
failure = new IllegalStateException("Invalid transport state: " + state);
callback.failed(failure);
return false;
}
@ -304,32 +309,36 @@ public class HttpTransportOverHTTP2 implements HttpTransport
}
}
if (LOG.isDebugEnabled())
LOG.debug("HTTP2 Response #{}/{} {}",
LOG.debug("HTTP2 Response #{}/{} {} {}",
stream.getId(), Integer.toHexString(stream.getSession().hashCode()),
commit ? "committed" : "flushed content");
commit ? "commit" : "flush",
callback == null ? "failure" : "success");
if (callback != null)
callback.succeeded();
}
@Override
public void failed(Throwable x)
public void failed(Throwable failure)
{
boolean commit;
Callback callback = null;
synchronized (this)
{
commit = this.commit;
// Only fail pending writes, as we
// may need to write an error page.
if (state == State.WRITING)
{
this.state = State.FAILED;
callback = this.callback;
this.callback = null;
this.state = State.FAILED;
this.failure = failure;
}
}
if (LOG.isDebugEnabled())
LOG.debug("HTTP2 Response #" + stream.getId() + " failed to " + (commit ? "commit" : "flush"), x);
LOG.debug(String.format("HTTP2 Response #%d/%h failed to %s", stream.getId(), stream.getSession(), commit ? "commit" : "flush"), failure);
if (callback != null)
callback.failed(x);
callback.failed(failure);
}
@Override
@ -340,7 +349,7 @@ public class HttpTransportOverHTTP2 implements HttpTransport
{
callback = this.callback;
}
return callback.getInvocationType();
return callback != null ? callback.getInvocationType() : Callback.super.getInvocationType();
}
private boolean onIdleTimeout(Throwable failure)
@ -349,16 +358,19 @@ public class HttpTransportOverHTTP2 implements HttpTransport
Callback callback = null;
synchronized (this)
{
// Ignore idle timeouts if not writing,
// as the application may be suspended.
result = state == State.WRITING;
if (result)
{
this.state = State.TIMEOUT;
callback = this.callback;
this.callback = null;
this.state = State.TIMEOUT;
this.failure = failure;
}
}
if (LOG.isDebugEnabled())
LOG.debug("HTTP2 Response #" + stream.getId() + " idle timeout", failure);
LOG.debug(String.format("HTTP2 Response #%d/%h idle timeout", stream.getId(), stream.getSession()), failure);
if (result)
callback.failed(failure);
return result;

View File

@ -83,6 +83,7 @@ public class SslClientConnectionFactory implements ClientConnectionFactory
{
SslConnection sslConnection = (SslConnection)connection;
sslConnection.setRenegotiationAllowed(sslContextFactory.isRenegotiationAllowed());
sslConnection.setRenegotiationLimit(sslContextFactory.getRenegotiationLimit());
ContainerLifeCycle connector = (ContainerLifeCycle)context.get(ClientConnectionFactory.CONNECTOR_CONTEXT_KEY);
connector.getBeans(SslHandshakeListener.class).forEach(sslConnection::addHandshakeListener);
}

View File

@ -91,6 +91,7 @@ public class SslConnection extends AbstractConnection
private final boolean _encryptedDirectBuffers = true;
private final boolean _decryptedDirectBuffers = false;
private boolean _renegotiationAllowed;
private int _renegotiationLimit = -1;
private boolean _closedOutbound;
private abstract class RunnableTask implements Runnable, Invocable
@ -208,7 +209,26 @@ public class SslConnection extends AbstractConnection
public void setRenegotiationAllowed(boolean renegotiationAllowed)
{
this._renegotiationAllowed = renegotiationAllowed;
_renegotiationAllowed = renegotiationAllowed;
}
/**
* @return The number of renegotions allowed for this connection. When the limit
* is 0 renegotiation will be denied. If the limit is less than 0 then no limit is applied.
*/
public int getRenegotiationLimit()
{
return _renegotiationLimit;
}
/**
* @param renegotiationLimit The number of renegotions allowed for this connection.
* When the limit is 0 renegotiation will be denied. If the limit is less than 0 then no limit is applied.
* Default -1.
*/
public void setRenegotiationLimit(int renegotiationLimit)
{
_renegotiationLimit = renegotiationLimit;
}
@Override
@ -357,7 +377,7 @@ public class SslConnection extends AbstractConnection
synchronized (DecryptedEndPoint.this)
{
if (LOG.isDebugEnabled())
LOG.debug("{} write failed", SslConnection.this, x);
LOG.debug("write failed {}", SslConnection.this, x);
BufferUtil.clear(_encryptedOutput);
releaseEncryptedOutputBuffer();
@ -627,8 +647,8 @@ public class SslConnection extends AbstractConnection
}
if (LOG.isDebugEnabled())
{
LOG.debug("{} net={} unwrap {}", SslConnection.this, net_filled, unwrapResult.toString().replace('\n',' '));
LOG.debug("{} filled {}",SslConnection.this,BufferUtil.toHexSummary(buffer));
LOG.debug("net={} unwrap {} {}", net_filled, unwrapResult.toString().replace('\n',' '), SslConnection.this);
LOG.debug("filled {} {}",BufferUtil.toHexSummary(buffer), SslConnection.this);
}
HandshakeStatus handshakeStatus = _sslEngine.getHandshakeStatus();
@ -686,25 +706,13 @@ public class SslConnection extends AbstractConnection
case BUFFER_UNDERFLOW:
case OK:
{
if (unwrapHandshakeStatus == HandshakeStatus.FINISHED && !_handshaken)
{
_handshaken = true;
if (LOG.isDebugEnabled())
LOG.debug("{} {} handshake succeeded {}/{}", SslConnection.this,
_sslEngine.getUseClientMode() ? "client" : "resumed server",
_sslEngine.getSession().getProtocol(),_sslEngine.getSession().getCipherSuite());
notifyHandshakeSucceeded(_sslEngine);
}
if (unwrapHandshakeStatus == HandshakeStatus.FINISHED)
handshakeFinished();
// Check whether renegotiation is allowed
if (_handshaken && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING && !isRenegotiationAllowed())
{
if (LOG.isDebugEnabled())
LOG.debug("{} renegotiation denied", SslConnection.this);
closeInbound();
// Check whether re-negotiation is allowed
if (!allowRenegotiate(handshakeStatus))
return -1;
}
// If bytes were produced, don't bother with the handshake status;
// pass the decrypted data to the application, which will perform
// another call to fill() or flush().
@ -822,6 +830,51 @@ public class SslConnection extends AbstractConnection
}
}
private void handshakeFinished()
{
if (_handshaken)
{
if (LOG.isDebugEnabled())
LOG.debug("Renegotiated {}", SslConnection.this);
if (_renegotiationLimit>0)
_renegotiationLimit--;
}
else
{
_handshaken = true;
if (LOG.isDebugEnabled())
LOG.debug("{} handshake succeeded {}/{} {}",
_sslEngine.getUseClientMode() ? "client" : "resumed server",
_sslEngine.getSession().getProtocol(),_sslEngine.getSession().getCipherSuite(),
SslConnection.this);
notifyHandshakeSucceeded(_sslEngine);
}
}
private boolean allowRenegotiate(HandshakeStatus handshakeStatus)
{
if (!_handshaken || handshakeStatus == HandshakeStatus.NOT_HANDSHAKING)
return true;
if (!isRenegotiationAllowed())
{
if (LOG.isDebugEnabled())
LOG.debug("Renegotiation denied {}", SslConnection.this);
closeInbound();
return false;
}
if (_renegotiationLimit==0)
{
if (LOG.isDebugEnabled())
LOG.debug("Renegotiation limit exceeded {}", SslConnection.this);
closeInbound();
return false;
}
return true;
}
private void closeInbound()
{
try
@ -847,7 +900,7 @@ public class SslConnection extends AbstractConnection
if (LOG.isDebugEnabled())
{
for (ByteBuffer b : appOuts)
LOG.debug("{} flush {}", SslConnection.this, BufferUtil.toHexSummary(b));
LOG.debug("flush {} {}", BufferUtil.toHexSummary(b), SslConnection.this);
}
try
@ -882,7 +935,7 @@ public class SslConnection extends AbstractConnection
BufferUtil.flipToFlush(_encryptedOutput, pos);
}
if (LOG.isDebugEnabled())
LOG.debug("{} wrap {}", SslConnection.this, wrapResult.toString().replace('\n',' '));
LOG.debug("wrap {} {}", wrapResult.toString().replace('\n',' '), SslConnection.this);
Status wrapResultStatus = wrapResult.getStatus();
@ -923,29 +976,20 @@ public class SslConnection extends AbstractConnection
default:
{
if (LOG.isDebugEnabled())
LOG.debug("{} wrap {} {}", SslConnection.this, wrapResultStatus, BufferUtil.toHexSummary(_encryptedOutput));
LOG.debug("wrap {} {} {}", wrapResultStatus, BufferUtil.toHexSummary(_encryptedOutput), SslConnection.this);
if (wrapResult.getHandshakeStatus() == HandshakeStatus.FINISHED && !_handshaken)
{
_handshaken = true;
if (LOG.isDebugEnabled())
LOG.debug("{} {} handshake succeeded {}/{}", SslConnection.this,
_sslEngine.getUseClientMode() ? "resumed client" : "server",
_sslEngine.getSession().getProtocol(),_sslEngine.getSession().getCipherSuite());
notifyHandshakeSucceeded(_sslEngine);
}
if (wrapResult.getHandshakeStatus() == HandshakeStatus.FINISHED)
handshakeFinished();
HandshakeStatus handshakeStatus = _sslEngine.getHandshakeStatus();
// Check whether renegotiation is allowed
if (_handshaken && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING && !isRenegotiationAllowed())
// Check whether re-negotiation is allowed
if (!allowRenegotiate(handshakeStatus))
{
if (LOG.isDebugEnabled())
LOG.debug("{} renegotiation denied", SslConnection.this);
getEndPoint().shutdownOutput();
return allConsumed;
}
// if we have net bytes, let's try to flush them
if (BufferUtil.hasContent(_encryptedOutput))
if (!getEndPoint().flush(_encryptedOutput))
@ -1035,7 +1079,7 @@ public class SslConnection extends AbstractConnection
boolean ishut = isInputShutdown();
boolean oshut = isOutputShutdown();
if (LOG.isDebugEnabled())
LOG.debug("{} shutdownOutput: oshut={}, ishut={}", SslConnection.this, oshut, ishut);
LOG.debug("shutdownOutput: oshut={}, ishut={} {}", oshut, ishut, SslConnection.this);
if (oshut)
return;

View File

@ -18,10 +18,6 @@
package org.eclipse.jetty.io;
import static org.hamcrest.Matchers.greaterThan;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.io.File;
import java.io.IOException;
import java.net.Socket;
@ -37,15 +33,21 @@ import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSocket;
import org.eclipse.jetty.io.ssl.SslConnection;
import org.eclipse.jetty.toolchain.test.JDK;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.annotation.Stress;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import static org.hamcrest.Matchers.greaterThan;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest
{
@ -78,6 +80,7 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest
engine.setUseClientMode(false);
SslConnection sslConnection = new SslConnection(__byteBufferPool, _threadPool, endpoint, engine);
sslConnection.setRenegotiationAllowed(__sslCtxFactory.isRenegotiationAllowed());
sslConnection.setRenegotiationLimit(__sslCtxFactory.getRenegotiationLimit());
Connection appConnection = super.newConnection(channel,sslConnection.getDecryptedEndPoint());
sslConnection.getDecryptedEndPoint().setConnection(appConnection);
return sslConnection;
@ -260,6 +263,8 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest
@Test
public void checkSslEngineBehaviour() throws Exception
{
Assume.assumeFalse(JDK.IS_9);
SSLEngine server = __sslCtxFactory.newSSLEngine();
SSLEngine client = __sslCtxFactory.newSSLEngine();
@ -296,13 +301,11 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest
netC2S.flip();
assertEquals(netC2S.remaining(),result.bytesProduced());
// start the server
server.setUseClientMode(false);
server.beginHandshake();
Assert.assertEquals(HandshakeStatus.NEED_UNWRAP,server.getHandshakeStatus());
// what if we try a needless wrap?
serverOut.put(BufferUtil.toBuffer("Hello World"));
serverOut.flip();
@ -313,7 +316,6 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest
assertEquals(0,result.bytesProduced());
assertEquals(HandshakeStatus.NEED_UNWRAP,result.getHandshakeStatus());
// Do the needed unwrap, to an empty buffer
result=server.unwrap(netC2S,BufferUtil.EMPTY_BUFFER);
assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW,result.getStatus());
@ -321,7 +323,6 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest
assertEquals(0,result.bytesProduced());
assertEquals(HandshakeStatus.NEED_UNWRAP,result.getHandshakeStatus());
// Do the needed unwrap, to a full buffer
serverIn.position(serverIn.limit());
result=server.unwrap(netC2S,serverIn);
@ -330,7 +331,6 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest
assertEquals(0,result.bytesProduced());
assertEquals(HandshakeStatus.NEED_UNWRAP,result.getHandshakeStatus());
// Do the needed unwrap, to an empty buffer
serverIn.clear();
result=server.unwrap(netC2S,serverIn);
@ -342,9 +342,5 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest
server.getDelegatedTask().run();
assertEquals(HandshakeStatus.NEED_WRAP,server.getHandshakeStatus());
}
}

View File

@ -34,6 +34,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSocket;
import org.eclipse.jetty.io.ssl.SslConnection;
@ -82,6 +83,7 @@ public class SslConnectionTest
engine.setUseClientMode(false);
SslConnection sslConnection = new SslConnection(__byteBufferPool, getExecutor(), endpoint, engine);
sslConnection.setRenegotiationAllowed(__sslCtxFactory.isRenegotiationAllowed());
sslConnection.setRenegotiationLimit(__sslCtxFactory.getRenegotiationLimit());
Connection appConnection = new TestConnection(sslConnection.getDecryptedEndPoint());
sslConnection.getDecryptedEndPoint().setConnection(appConnection);
return sslConnection;
@ -151,6 +153,8 @@ public class SslConnectionTest
_threadPool.start();
_scheduler.start();
_manager.start();
__sslCtxFactory.setRenegotiationAllowed(true);
__sslCtxFactory.setRenegotiationLimit(-1);
}
@ -250,7 +254,7 @@ public class SslConnectionTest
}
}
}
protected Socket newClient() throws IOException
protected SSLSocket newClient() throws IOException
{
SSLSocket socket = __sslCtxFactory.newSslSocket();
socket.connect(_connector.socket().getLocalSocketAddress());
@ -282,6 +286,112 @@ public class SslConnectionTest
client.close();
}
@Test
public void testRenegotiate() throws Exception
{
SSLSocket client = newClient();
client.setSoTimeout(60000);
SocketChannel server = _connector.accept();
server.configureBlocking(false);
_manager.accept(server);
client.getOutputStream().write("Hello".getBytes(StandardCharsets.UTF_8));
byte[] buffer = new byte[1024];
int len=client.getInputStream().read(buffer);
Assert.assertEquals(5, len);
Assert.assertEquals("Hello",new String(buffer,0,len,StandardCharsets.UTF_8));
client.startHandshake();
client.getOutputStream().write("World".getBytes(StandardCharsets.UTF_8));
len=client.getInputStream().read(buffer);
Assert.assertEquals(5, len);
Assert.assertEquals("World",new String(buffer,0,len,StandardCharsets.UTF_8));
client.close();
}
@Test
public void testRenegotiateNotAllowed() throws Exception
{
__sslCtxFactory.setRenegotiationAllowed(false);
SSLSocket client = newClient();
client.setSoTimeout(60000);
SocketChannel server = _connector.accept();
server.configureBlocking(false);
_manager.accept(server);
client.getOutputStream().write("Hello".getBytes(StandardCharsets.UTF_8));
byte[] buffer = new byte[1024];
int len=client.getInputStream().read(buffer);
Assert.assertEquals(5, len);
Assert.assertEquals("Hello",new String(buffer,0,len,StandardCharsets.UTF_8));
client.startHandshake();
client.getOutputStream().write("World".getBytes(StandardCharsets.UTF_8));
try
{
client.getInputStream().read(buffer);
Assert.fail();
}
catch(SSLException e)
{
// expected
}
}
@Test
public void testRenegotiateLimit() throws Exception
{
__sslCtxFactory.setRenegotiationAllowed(true);
__sslCtxFactory.setRenegotiationLimit(2);
SSLSocket client = newClient();
client.setSoTimeout(60000);
SocketChannel server = _connector.accept();
server.configureBlocking(false);
_manager.accept(server);
client.getOutputStream().write("Good".getBytes(StandardCharsets.UTF_8));
byte[] buffer = new byte[1024];
int len=client.getInputStream().read(buffer);
Assert.assertEquals(4, len);
Assert.assertEquals("Good",new String(buffer,0,len,StandardCharsets.UTF_8));
client.startHandshake();
client.getOutputStream().write("Bye".getBytes(StandardCharsets.UTF_8));
len=client.getInputStream().read(buffer);
Assert.assertEquals(3, len);
Assert.assertEquals("Bye",new String(buffer,0,len,StandardCharsets.UTF_8));
client.startHandshake();
client.getOutputStream().write("Cruel".getBytes(StandardCharsets.UTF_8));
len=client.getInputStream().read(buffer);
Assert.assertEquals(5, len);
Assert.assertEquals("Cruel",new String(buffer,0,len,StandardCharsets.UTF_8));
client.startHandshake();
client.getOutputStream().write("World".getBytes(StandardCharsets.UTF_8));
try
{
client.getInputStream().read(buffer);
Assert.fail();
}
catch(SSLException e)
{
// expected
}
}
@Test
public void testWriteOnConnect() throws Exception

View File

@ -82,6 +82,11 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>

View File

@ -0,0 +1,57 @@
//
// ========================================================================
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.quickstart;
import static org.junit.Assert.assertTrue;
import java.util.Collection;
import java.util.Set;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRegistration;
/**
* FooContextListener
*
*
*/
public class FooContextListener implements ServletContextListener
{
@Override
public void contextInitialized(ServletContextEvent sce)
{
ServletRegistration defaultRego = sce.getServletContext().getServletRegistration("default");
Collection<String> mappings = defaultRego.getMappings();
assertTrue(mappings.contains("/"));
Set<String> otherMappings = sce.getServletContext().getServletRegistration("foo").addMapping("/");
assertTrue(otherMappings.isEmpty());
Collection<String> fooMappings = sce.getServletContext().getServletRegistration("foo").getMappings();
assertTrue(fooMappings.contains("/"));
}
@Override
public void contextDestroyed(ServletContextEvent sce)
{
// TODO Auto-generated method stub
}
}

View File

@ -0,0 +1,42 @@
//
// ========================================================================
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.quickstart;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FooServlet extends HttpServlet
{
/**
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
resp.setContentType("text/html");
resp.getWriter().println("FOO");
}
}

View File

@ -0,0 +1,99 @@
//
// ========================================================================
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.quickstart;
import static org.junit.Assert.*;
import java.io.File;
import java.nio.file.Path;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.Before;
import org.junit.Test;
/**
* TestQuickStart
*
*
*/
public class TestQuickStart
{
File testDir;
File webInf;
@Before
public void setUp()
{
testDir = MavenTestingUtils.getTargetTestingDir("foo");
FS.ensureEmpty(testDir);
webInf = new File(testDir, "WEB-INF");
FS.ensureDirExists(webInf);
}
@Test
public void testProgrammaticOverrideOfDefaultServletMapping() throws Exception
{
File quickstartXml = new File(webInf, "quickstart-web.xml");
assertFalse(quickstartXml.exists());
Server server = new Server();
//generate a quickstart-web.xml
QuickStartWebApp quickstart = new QuickStartWebApp();
quickstart.setResourceBase(testDir.getAbsolutePath());
quickstart.setPreconfigure(true);
quickstart.setGenerateOrigin(true);
ServletHolder fooHolder = new ServletHolder();
fooHolder.setServlet(new FooServlet());
fooHolder.setName("foo");
quickstart.getServletHandler().addServlet(fooHolder);
quickstart.addEventListener(new FooContextListener());
server.setHandler(quickstart);
server.start();
server.stop();
assertTrue(quickstartXml.exists());
//now run the webapp again purely from the generated quickstart
QuickStartWebApp webapp = new QuickStartWebApp();
webapp.setResourceBase(testDir.getAbsolutePath());
webapp.setPreconfigure(false);
webapp.setClassLoader(Thread.currentThread().getContextClassLoader()); //only necessary for junit testing
server.setHandler(webapp);
server.start();
//verify that FooServlet is now mapped to / and not the DefaultServlet
ServletHolder sh = webapp.getServletHandler().getHolderEntry("/").getResource();
assertNotNull(sh);
assertEquals("foo", sh.getName());
server.stop();
}
}

View File

@ -47,14 +47,14 @@ public final class RedirectUtil
if (location.startsWith("/"))
{
// absolute in context
location = URIUtil.canonicalPath(location);
location = URIUtil.canonicalEncodedPath(location);
}
else
{
// relative to request
String path = request.getRequestURI();
String parent = (path.endsWith("/")) ? path : URIUtil.parentPath(path);
location = URIUtil.canonicalPath(URIUtil.addPaths(parent,location));
location = URIUtil.canonicalPath(URIUtil.addEncodedPaths(parent,location));
if (!location.startsWith("/"))
url.append('/');
}

View File

@ -22,6 +22,7 @@ import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.util.log.Log;
@ -49,11 +50,12 @@ public class HashLoginService extends AbstractLoginService
{
private static final Logger LOG = Log.getLogger(HashLoginService.class);
private PropertyUserStore _propertyUserStore;
private File _configFile;
private Resource _configResource;
private boolean hotReload = false; // default is not to reload
private UserStore _userStore;
private boolean _userStoreAutoCreate = false;
/* ------------------------------------------------------------ */
public HashLoginService()
@ -139,13 +141,21 @@ public class HashLoginService extends AbstractLoginService
this.hotReload = enable;
}
/**
* Configure the {@link UserStore} implementation to use.
* If none, for backward compat if none the {@link PropertyUserStore} will be used
* @param userStore the {@link UserStore} implementation to use
*/
public void setUserStore(UserStore userStore)
{
this._userStore = userStore;
}
/* ------------------------------------------------------------ */
@Override
protected String[] loadRoleInfo(UserPrincipal user)
{
UserIdentity id = _propertyUserStore.getUserIdentity(user.getName());
UserIdentity id = _userStore.getUserIdentity(user.getName());
if (id == null)
return null;
@ -154,21 +164,19 @@ public class HashLoginService extends AbstractLoginService
if (roles == null)
return null;
List<String> list = new ArrayList<>();
for (RolePrincipal r:roles)
list.add(r.getName());
List<String> list = roles.stream()
.map( rolePrincipal -> rolePrincipal.getName() )
.collect( Collectors.toList() );
return list.toArray(new String[roles.size()]);
}
/* ------------------------------------------------------------ */
@Override
protected UserPrincipal loadUserInfo(String userName)
{
UserIdentity id = _propertyUserStore.getUserIdentity(userName);
UserIdentity id = _userStore.getUserIdentity(userName);
if (id != null)
{
return (UserPrincipal)id.getUserPrincipal();
@ -187,16 +195,19 @@ public class HashLoginService extends AbstractLoginService
protected void doStart() throws Exception
{
super.doStart();
if (_propertyUserStore == null)
// can be null so we switch to previous behaviour using PropertyUserStore
if (_userStore == null)
{
if(LOG.isDebugEnabled())
LOG.debug("doStart: Starting new PropertyUserStore. PropertiesFile: " + _configFile + " hotReload: " + hotReload);
_propertyUserStore = new PropertyUserStore();
_propertyUserStore.setHotReload(hotReload);
_propertyUserStore.setConfigPath(_configFile);
_propertyUserStore.start();
PropertyUserStore propertyUserStore = new PropertyUserStore();
propertyUserStore.setHotReload(hotReload);
propertyUserStore.setConfigPath(_configFile);
propertyUserStore.start();
_userStore = propertyUserStore;
_userStoreAutoCreate = true;
}
}
@ -208,8 +219,8 @@ public class HashLoginService extends AbstractLoginService
protected void doStop() throws Exception
{
super.doStop();
if (_propertyUserStore != null)
_propertyUserStore.stop();
_propertyUserStore = null;
if (_userStore != null && _userStoreAutoCreate)
_userStore.stop();
_userStore = null;
}
}

View File

@ -18,12 +18,19 @@
package org.eclipse.jetty.security;
import org.eclipse.jetty.util.PathWatcher;
import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.PathResource;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.security.Credential;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.security.Principal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@ -31,20 +38,6 @@ import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.security.auth.Subject;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.util.PathWatcher;
import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.PathResource;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.security.Credential;
/**
* PropertyUserStore
* <p>
@ -59,7 +52,7 @@ import org.eclipse.jetty.util.security.Credential;
*
* If DIGEST Authentication is used, the password must be in a recoverable format, either plain text or OBF:.
*/
public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher.Listener
public class PropertyUserStore extends UserStore implements PathWatcher.Listener
{
private static final Logger LOG = Log.getLogger(PropertyUserStore.class);
@ -69,10 +62,7 @@ public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher.
protected PathWatcher pathWatcher;
protected boolean hotReload = false; // default is not to reload
protected IdentityService _identityService = new DefaultIdentityService();
protected boolean _firstLoad = true; // true if first load, false from that point on
protected final List<String> _knownUsers = new ArrayList<String>();
protected final Map<String, UserIdentity> _knownUserIdentities = new HashMap<String, UserIdentity>();
protected List<UserListener> _listeners;
/**
@ -145,12 +135,6 @@ public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher.
{
_configPath = configPath;
}
/* ------------------------------------------------------------ */
public UserIdentity getUserIdentity(String userName)
{
return _knownUserIdentities.get(userName);
}
/* ------------------------------------------------------------ */
/**
@ -199,8 +183,8 @@ public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher.
StringBuilder s = new StringBuilder();
s.append(this.getClass().getName());
s.append("[");
s.append("users.count=").append(this._knownUsers.size());
s.append("identityService=").append(this._identityService);
s.append("users.count=").append(this.getKnownUserIdentities().size());
s.append("identityService=").append(this.getIdentityService());
s.append("]");
return s.toString();
}
@ -220,7 +204,7 @@ public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher.
if (getConfigResource().exists())
properties.load(getConfigResource().getInputStream());
Set<String> known = new HashSet<String>();
Set<String> known = new HashSet<>();
for (Map.Entry<Object, Object> entry : properties.entrySet())
{
@ -243,60 +227,36 @@ public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher.
}
known.add(username);
Credential credential = Credential.getCredential(credentials);
Principal userPrincipal = new AbstractLoginService.UserPrincipal(username,credential);
Subject subject = new Subject();
subject.getPrincipals().add(userPrincipal);
subject.getPrivateCredentials().add(credential);
if (roles != null)
{
for (String role : roleArray)
{
subject.getPrincipals().add(new AbstractLoginService.RolePrincipal(role));
}
}
subject.setReadOnly();
_knownUserIdentities.put(username,_identityService.newUserIdentity(subject,userPrincipal,roleArray));
addUser( username, credential, roleArray );
notifyUpdate(username,credential,roleArray);
}
}
synchronized (_knownUsers)
final List<String> currentlyKnownUsers = new ArrayList<String>(getKnownUserIdentities().keySet());
/*
*
* if its not the initial load then we want to process removed users
*/
if (!_firstLoad)
{
/*
* if its not the initial load then we want to process removed users
*/
if (!_firstLoad)
Iterator<String> users = currentlyKnownUsers.iterator();
while (users.hasNext())
{
Iterator<String> users = _knownUsers.iterator();
while (users.hasNext())
String user = users.next();
if (!known.contains(user))
{
String user = users.next();
if (!known.contains(user))
{
_knownUserIdentities.remove(user);
notifyRemove(user);
}
removeUser( user );
notifyRemove(user);
}
}
/*
* reset the tracked _users list to the known users we just processed
*/
_knownUsers.clear();
_knownUsers.addAll(known);
}
/*
* set initial load to false as there should be no more initial loads
*/
_firstLoad = false;
if (LOG.isDebugEnabled())
{
LOG.debug("Loaded " + this + " from " + _configPath);
@ -332,6 +292,10 @@ public class PropertyUserStore extends AbstractLifeCycle implements PathWatcher.
{
try
{
if (LOG.isDebugEnabled())
{
LOG.debug( "PATH WATCH EVENT: {}", event.getType() );
}
loadUsers();
}
catch (IOException e)

View File

@ -0,0 +1,76 @@
//
// ========================================================================
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.security;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.security.Credential;
import javax.security.auth.Subject;
import java.security.Principal;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Base class to store User
*/
public class UserStore extends AbstractLifeCycle
{
private IdentityService _identityService = new DefaultIdentityService();
private final Map<String, UserIdentity> _knownUserIdentities = new ConcurrentHashMap<>();
public void addUser( String username, Credential credential, String[] roles)
{
Principal userPrincipal = new AbstractLoginService.UserPrincipal( username, credential);
Subject subject = new Subject();
subject.getPrincipals().add(userPrincipal);
subject.getPrivateCredentials().add(credential);
if (roles != null)
{
for (String role : roles)
{
subject.getPrincipals().add(new AbstractLoginService.RolePrincipal(role));
}
}
subject.setReadOnly();
_knownUserIdentities.put(username,_identityService.newUserIdentity(subject,userPrincipal,roles));
}
public void removeUser(String username)
{
_knownUserIdentities.remove(username);
}
public UserIdentity getUserIdentity(String userName)
{
return _knownUserIdentities.get(userName);
}
public IdentityService getIdentityService()
{
return _identityService;
}
public Map<String, UserIdentity> getKnownUserIdentities()
{
return _knownUserIdentities;
}
}

View File

@ -19,9 +19,14 @@
package org.eclipse.jetty.security;
import java.security.Principal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.util.security.Credential;
/**
@ -31,9 +36,8 @@ import org.eclipse.jetty.util.security.Credential;
*/
public class TestLoginService extends AbstractLoginService
{
protected Map<String, UserPrincipal> _users = new HashMap<>();
protected Map<String, String[]> _roles = new HashMap<>();
UserStore userStore = new UserStore();
public TestLoginService(String name)
@ -43,9 +47,7 @@ public class TestLoginService extends AbstractLoginService
public void putUser (String username, Credential credential, String[] roles)
{
UserPrincipal userPrincipal = new UserPrincipal(username,credential);
_users.put(username, userPrincipal);
_roles.put(username, roles);
userStore.addUser( username, credential, roles );
}
/**
@ -54,7 +56,16 @@ public class TestLoginService extends AbstractLoginService
@Override
protected String[] loadRoleInfo(UserPrincipal user)
{
return _roles.get(user.getName());
UserIdentity userIdentity = userStore.getUserIdentity( user.getName() );
Set<RolePrincipal> roles = userIdentity.getSubject().getPrincipals( RolePrincipal.class);
if (roles == null)
return null;
List<String> list = new ArrayList<>();
for (RolePrincipal r:roles)
list.add(r.getName());
return list.toArray(new String[roles.size()]);
}
/**
@ -63,7 +74,8 @@ public class TestLoginService extends AbstractLoginService
@Override
protected UserPrincipal loadUserInfo(String username)
{
return _users.get(username);
UserIdentity userIdentity = userStore.getUserIdentity( username );
return userIdentity == null ? null : (UserPrincipal) userIdentity.getUserPrincipal();
}
}

View File

@ -0,0 +1,70 @@
//
// ========================================================================
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.security;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.util.security.Credential;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class UserStoreTest
{
UserStore userStore;
@Before
public void setup() {
userStore = new UserStore();
}
@Test
public void addUser()
{
this.userStore.addUser( "foo", Credential.getCredential( "beer" ), new String[]{"pub"} );
Assert.assertEquals(1, this.userStore.getKnownUserIdentities().size());
UserIdentity userIdentity = this.userStore.getUserIdentity( "foo" );
Assert.assertNotNull( userIdentity );
Assert.assertEquals( "foo", userIdentity.getUserPrincipal().getName() );
Set<AbstractLoginService.RolePrincipal>
roles = userIdentity.getSubject().getPrincipals( AbstractLoginService.RolePrincipal.class);
List<String> list = roles.stream()
.map( rolePrincipal -> rolePrincipal.getName() )
.collect( Collectors.toList() );
Assert.assertEquals(1, list.size());
Assert.assertEquals( "pub", list.get( 0 ) );
}
@Test
public void removeUser()
{
this.userStore.addUser( "foo", Credential.getCredential( "beer" ), new String[]{"pub"} );
Assert.assertEquals(1, this.userStore.getKnownUserIdentities().size());
UserIdentity userIdentity = this.userStore.getUserIdentity( "foo" );
Assert.assertNotNull( userIdentity );
Assert.assertEquals( "foo", userIdentity.getUserPrincipal().getName() );
userStore.removeUser( "foo" );
userIdentity = this.userStore.getUserIdentity( "foo" );
Assert.assertNull( userIdentity );
}
}

View File

@ -26,4 +26,6 @@
<Set name="useCipherSuitesOrder"><Property name="jetty.sslContext.useCipherSuitesOrder" default="true"/></Set>
<Set name="sslSessionCacheSize"><Property name="jetty.sslContext.sslSessionCacheSize" default="-1"/></Set>
<Set name="sslSessionTimeout"><Property name="jetty.sslContext.sslSessionTimeout" default="-1"/></Set>
<Set name="RenegotiationAllowed"><Property name="jetty.sslContext.renegotiationAllowed" default="true"/></Set>
<Set name="RenegotiationLimit"><Property name="jetty.sslContext.renegotiationLimit" default="5"/></Set>
</Configure>

View File

@ -97,3 +97,7 @@ basehome:modules/ssl/keystore|etc/keystore
## Set the timeout (in seconds) of the SslSession cache timeout
# jetty.sslContext.sslSessionTimeout=-1
## Allow SSL renegotiation
# jetty.sslContext.renegotiationAllowed=true
# jetty.sslContext.renegotiationLimit=5

View File

@ -344,7 +344,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
{
try
{
_response.reset();
_response.reset(true);
Integer icode = (Integer)_request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
int code = icode != null ? icode : HttpStatus.INTERNAL_SERVER_ERROR_500;
_response.setStatus(code);
@ -367,8 +367,15 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
if (LOG.isDebugEnabled())
LOG.debug("Could not perform ERROR dispatch, aborting", x);
Throwable failure = (Throwable)_request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
failure.addSuppressed(x);
minimalErrorResponse(failure);
if (failure==null)
{
minimalErrorResponse(x);
}
else
{
failure.addSuppressed(x);
minimalErrorResponse(failure);
}
}
break;
}
@ -528,7 +535,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
try
{
Integer code=(Integer)_request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
_response.reset();
_response.reset(true);
_response.setStatus(code == null ? 500 : code);
_response.flushBuffer();
}

View File

@ -1255,7 +1255,7 @@ public class Request implements HttpServletRequest
relTo = relTo.substring(0,slash + 1);
else
relTo = "/";
path = URIUtil.addPaths(URIUtil.encodePath(relTo),path);
path = URIUtil.addPaths(relTo,path);
}
return _context.getRequestDispatcher(path);
@ -1700,7 +1700,7 @@ public class Request implements HttpServletRequest
*/
public void setMetaData(org.eclipse.jetty.http.MetaData.Request request)
{
_metaData=request;
_metaData = request;
HttpURI uri = request.getURI();
_originalUri = uri.isAbsolute() && request.getHttpVersion()!=HttpVersion.HTTP_2
? uri.toString()
@ -1719,26 +1719,33 @@ public class Request implements HttpServletRequest
}
}
String pathInfo = uri.getDecodedPath();
if (pathInfo==null || pathInfo.length()==0)
String encoded = uri.getPath();
String path;
if (encoded==null)
{
// If null path was not from an absolute http without a path
if (!request.getURI().isAbsolute() || uri.getPath()!=null)
{
setPathInfo("");
throw new BadMessageException(400,"Bad URI");
}
pathInfo="/";
uri.setDecodedPath(pathInfo);
path = uri.isAbsolute()?"/":null;
uri.setPath(path);
}
else if (!(pathInfo.startsWith("/") || "*".equals(request.getURI().getPath()) || HttpMethod.CONNECT.is(getMethod())))
else if (encoded.startsWith("/"))
{
setPathInfo(pathInfo);
path = (encoded.length()==1)?"/":URIUtil.canonicalPath(URIUtil.decodePath(encoded));
}
else if ("*".equals(encoded) || HttpMethod.CONNECT.is(getMethod()))
{
path = encoded;
}
else
{
path = null;
}
if (path==null || path.isEmpty())
{
setPathInfo(encoded==null?"":encoded);
throw new BadMessageException(400,"Bad URI");
}
setPathInfo(path);
setPathInfo(pathInfo);
}
/* ------------------------------------------------------------ */

View File

@ -82,7 +82,7 @@ public class ResourceContentFactory implements ContentFactory
{
String compressedPathInContext = pathInContext + format._extension;
Resource compressedResource = _factory.getResource(compressedPathInContext);
if (compressedResource.exists() && compressedResource.lastModified() >= resource.lastModified()
if (compressedResource != null && compressedResource.exists() && compressedResource.lastModified() >= resource.lastModified()
&& compressedResource.length() < resource.length())
compressedContents.put(format,
new ResourceHttpContent(compressedResource,_mimeTypes.getMimeByExtension(compressedPathInContext),maxBufferSize));

View File

@ -20,8 +20,6 @@ package org.eclipse.jetty.server;
import static java.util.Arrays.stream;
import static java.util.Collections.emptyList;
import static org.eclipse.jetty.http.CompressedContentFormat.BR;
import static org.eclipse.jetty.http.CompressedContentFormat.GZIP;
import static org.eclipse.jetty.http.HttpHeaderValue.IDENTITY;
import java.io.FileNotFoundException;
@ -416,11 +414,13 @@ public class ResourceService
{
// Redirect to the index
response.setContentLength(0);
String uri = URIUtil.encodePath(URIUtil.addPaths(request.getContextPath(),welcome));
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)));
if (q!=null&&!q.isEmpty())
uri+="?"+q;
response.sendRedirect(response.encodeRedirectURL(uri));
}
return;
}
@ -614,7 +614,7 @@ public class ResourceService
}
byte[] data=null;
String base = URIUtil.addPaths(request.getRequestURI(),URIUtil.SLASH);
String base = URIUtil.addEncodedPaths(request.getRequestURI(),URIUtil.SLASH);
String dir = resource.getListHTML(base,pathInContext.length()>1);
if (dir==null)
{

View File

@ -653,9 +653,9 @@ public class Response implements HttpServletResponse
ErrorHandler error_handler = ErrorHandler.getErrorHandler(_channel.getServer(), contextHandler);
if (error_handler!=null)
error_handler.handle(null, request, request, this);
else
closeOutput();
}
if (!request.isAsyncStarted())
closeOutput();
}
/**
@ -698,14 +698,14 @@ public class Response implements HttpServletResponse
if (location.startsWith("/"))
{
// absolute in context
location=URIUtil.canonicalPath(location);
location=URIUtil.canonicalEncodedPath(location);
}
else
{
// relative to request
String path=_channel.getRequest().getRequestURI();
String parent=(path.endsWith("/"))?path:URIUtil.parentPath(path);
location=URIUtil.canonicalPath(URIUtil.addPaths(parent,location));
location=URIUtil.canonicalEncodedPath(URIUtil.addEncodedPaths(parent,location));
if (!location.startsWith("/"))
buf.append('/');
}
@ -1040,10 +1040,12 @@ public class Response implements HttpServletResponse
_out.close();
break;
case STREAM:
getOutputStream().close();
if (!_out.isClosed())
getOutputStream().close();
break;
default:
_out.close();
if (!_out.isClosed())
_out.close();
}
}

View File

@ -593,7 +593,7 @@ public class Server extends HandlerWrapper implements Attributes
// this is a dispatch with a path
ServletContext context=event.getServletContext();
String query=baseRequest.getQueryString();
baseRequest.setURIPathQuery(URIUtil.addPaths(context==null?null:URIUtil.encodePath(context.getContextPath()), path));
baseRequest.setURIPathQuery(URIUtil.addEncodedPaths(context==null?null:URIUtil.encodePath(context.getContextPath()), path));
HttpURI uri = baseRequest.getHttpURI();
baseRequest.setPathInfo(uri.getDecodedPath());
if (uri.getQuery()!=null)

View File

@ -87,6 +87,7 @@ public class SslConnectionFactory extends AbstractConnectionFactory
SslConnection sslConnection = newSslConnection(connector, endPoint, engine);
sslConnection.setRenegotiationAllowed(_sslContextFactory.isRenegotiationAllowed());
sslConnection.setRenegotiationLimit(_sslContextFactory.getRenegotiationLimit());
configure(sslConnection, connector, endPoint);
ConnectionFactory next = connector.getConnectionFactory(_nextProtocol);

View File

@ -753,20 +753,12 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
if (_contextPath == null)
throw new IllegalStateException("Null contextPath");
if (_logger==null)
if (_logger == null)
{
String log_name = getDisplayName();
if (log_name == null || log_name.isEmpty())
{
log_name = getContextPath();
if (log_name!=null || log_name.startsWith("/"))
log_name = log_name.substring(1);
if (log_name==null || log_name.isEmpty())
log_name = Integer.toHexString(hashCode());
}
_logger = Log.getLogger("org.eclipse.jetty.ContextHandler."+log_name);
_logger = Log.getLogger(ContextHandler.class.getName() + getLogNameSuffix());
}
ClassLoader old_classloader = null;
Thread current_thread = null;
Context old_context = null;
@ -806,6 +798,34 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
current_thread.setContextClassLoader(old_classloader);
}
}
private String getLogNameSuffix()
{
// Use display name first
String log_name = getDisplayName();
if (StringUtil.isBlank(log_name))
{
// try context path
log_name = getContextPath();
if (log_name != null)
{
// Strip prefix slash
if (log_name.startsWith("/"))
{
log_name = log_name.substring(1);
}
}
if (StringUtil.isBlank(log_name))
{
// an empty context path is the ROOT context
log_name = "ROOT";
}
}
// Replace bad characters.
return '.' + log_name.replaceAll("\\W", "_");
}
/* ------------------------------------------------------------ */
/**
@ -1023,9 +1043,9 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
// context request must end with /
baseRequest.setHandled(true);
if (baseRequest.getQueryString() != null)
response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH) + "?" + baseRequest.getQueryString());
response.sendRedirect(baseRequest.getRequestURI() + "/?" + baseRequest.getQueryString());
else
response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH));
response.sendRedirect(baseRequest.getRequestURI() + "/");
return false;
}

View File

@ -68,6 +68,12 @@ public class ContextHandlerCollection extends HandlerCollection
{
super(true);
}
/* ------------------------------------------------------------ */
public ContextHandlerCollection(ContextHandler... contexts)
{
super(true,contexts);
}
/* ------------------------------------------------------------ */

View File

@ -52,15 +52,23 @@ public class HandlerCollection extends AbstractHandlerContainer
/* ------------------------------------------------------------ */
public HandlerCollection()
{
_mutableWhenRunning=false;
this(false);
}
/* ------------------------------------------------------------ */
public HandlerCollection(boolean mutableWhenRunning)
public HandlerCollection(Handler... handlers)
{
this(false,handlers);
}
/* ------------------------------------------------------------ */
public HandlerCollection(boolean mutableWhenRunning, Handler... handlers)
{
_mutableWhenRunning=mutableWhenRunning;
if (handlers.length>0)
setHandlers(handlers);
}
/* ------------------------------------------------------------ */
/**
* @return Returns the handlers.
@ -153,6 +161,16 @@ public class HandlerCollection extends AbstractHandlerContainer
setHandlers(ArrayUtil.addToArray(getHandlers(), handler, Handler.class));
}
/* ------------------------------------------------------------ */
/* Prepend a handler.
* This implementation adds the passed handler to the start of the existing collection of handlers.
* @see org.eclipse.jetty.server.server.HandlerContainer#addHandler(org.eclipse.jetty.server.server.Handler)
*/
public void prependHandler(Handler handler)
{
setHandlers(ArrayUtil.prependToArray(handler, getHandlers(), Handler.class));
}
/* ------------------------------------------------------------ */
public void removeHandler(Handler handler)
{

View File

@ -35,6 +35,15 @@ import org.eclipse.jetty.server.Request;
*/
public class HandlerList extends HandlerCollection
{
public HandlerList()
{
}
public HandlerList(Handler... handlers)
{
super(handlers);
}
/* ------------------------------------------------------------ */
/**
* @see Handler#handle(String, Request, HttpServletRequest, HttpServletResponse)

View File

@ -519,15 +519,11 @@ public class DefaultSessionIdManager extends ContainerLifeCycle implements Sessi
public Set<SessionHandler> getSessionHandlers()
{
Set<SessionHandler> handlers = new HashSet<>();
Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
for (int i=0; contexts!=null && i<contexts.length; i++)
Handler[] tmp = _server.getChildHandlersByClass(SessionHandler.class);
if (tmp != null)
{
SessionHandler sessionHandler = ((ContextHandler)contexts[i]).getChildHandlerByClass(SessionHandler.class);
if (sessionHandler != null)
{
handlers.add(sessionHandler);
}
for (Handler h:tmp)
handlers.add((SessionHandler)h);
}
return handlers;
}

View File

@ -1257,7 +1257,7 @@ public class SessionHandler extends ScopedHandler
if (isStopping() || isStopped())
return;
if (LOG.isDebugEnabled()) LOG.debug("Scavenging sessions");
if (LOG.isDebugEnabled()) LOG.debug("{} scavenging sessions", this);
//Get a snapshot of the candidates as they are now. Others that
//arrive during this processing will be dealt with on
//subsequent call to scavenge

View File

@ -372,6 +372,7 @@ public class HttpConnectionTest
@Test
public void testChunkNoTrailer() throws Exception
{
// Expect TimeoutException logged
String response=connector.getResponse("GET /R1 HTTP/1.1\r\n"+
"Host: localhost\r\n"+
"Transfer-Encoding: chunked\r\n"+

View File

@ -18,6 +18,9 @@
package org.eclipse.jetty.server.handler;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
@ -448,10 +451,95 @@ public class ContextHandlerTest
}
@Test
public void testIsShutdown() {
public void testIsShutdown()
{
ContextHandler handler = new ContextHandler();
Assert.assertEquals(false, handler.isShutdown());
}
@Test
public void testLogNameFromDisplayName() throws Exception
{
ContextHandler handler = new ContextHandler();
handler.setServer(new Server());
handler.setDisplayName("An Interesting Project: app.tast.ic");
try
{
handler.start();
assertThat("handler.get", handler.getLogger().getName(), is(ContextHandler.class.getName() + ".An_Interesting_Project__app_tast_ic"));
}
finally
{
handler.stop();
}
}
@Test
public void testLogNameFromContextPath_Deep() throws Exception
{
ContextHandler handler = new ContextHandler();
handler.setServer(new Server());
handler.setContextPath("/app/tast/ic");
try
{
handler.start();
assertThat("handler.get", handler.getLogger().getName(), is(ContextHandler.class.getName() + ".app_tast_ic"));
}
finally
{
handler.stop();
}
}
@Test
public void testLogNameFromContextPath_Root() throws Exception
{
ContextHandler handler = new ContextHandler();
handler.setServer(new Server());
handler.setContextPath("");
try
{
handler.start();
assertThat("handler.get", handler.getLogger().getName(), is(ContextHandler.class.getName() + ".ROOT"));
}
finally
{
handler.stop();
}
}
@Test
public void testLogNameFromContextPath_Undefined() throws Exception
{
ContextHandler handler = new ContextHandler();
handler.setServer(new Server());
try
{
handler.start();
assertThat("handler.get", handler.getLogger().getName(), is(ContextHandler.class.getName() + ".ROOT"));
}
finally
{
handler.stop();
}
}
@Test
public void testLogNameFromContextPath_Empty() throws Exception
{
ContextHandler handler = new ContextHandler();
handler.setServer(new Server());
handler.setContextPath("");
try
{
handler.start();
assertThat("handler.get", handler.getLogger().getName(), is(ContextHandler.class.getName() + ".ROOT"));
}
finally
{
handler.stop();
}
}
private void checkResourcePathsForExampleWebApp(String root) throws IOException
{

View File

@ -129,6 +129,8 @@ import org.eclipse.jetty.util.resource.ResourceFactory;
*/
public class DefaultServlet extends HttpServlet implements ResourceFactory, WelcomeFactory
{
public static final String CONTEXT_INIT = "org.eclipse.jetty.servlet.Default.";
private static final Logger LOG = Log.getLogger(DefaultServlet.class);
private static final long serialVersionUID = 4930458713846881193L;
@ -371,7 +373,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc
@Override
public String getInitParameter(String name)
{
String value=getServletContext().getInitParameter("org.eclipse.jetty.servlet.Default."+name);
String value=getServletContext().getInitParameter(CONTEXT_INIT+name);
if (value==null)
value=super.getInitParameter(name);
return value;
@ -507,7 +509,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc
String welcome_in_context=URIUtil.addPaths(pathInContext,_welcomes[i]);
Resource welcome=getResource(welcome_in_context);
if (welcome!=null && welcome.exists())
return _welcomes[i];
return welcome_in_context;
if ((_welcomeServlets || _welcomeExactServlets) && welcome_servlet==null)
{

View File

@ -22,6 +22,7 @@ import static java.nio.charset.StandardCharsets.ISO_8859_1;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
@ -624,7 +625,6 @@ public class AsyncServletIOTest
.append("Content-Length: 20\r\n")
.append("\r\n")
.append("12345678\r\n");
int port=_port;
List<String> list = new ArrayList<>();
try (Socket socket = new Socket("localhost",port))
@ -682,7 +682,7 @@ public class AsyncServletIOTest
LOG.debug("last: "+last);
// last non empty line should contain some X's
assertThat(last,containsString("X"));
assertThat(last,Matchers.anyOf(containsString("X"),is("")));
// last non empty line should not contain end chunk
assertThat(last,not(containsString("0")));
}

View File

@ -52,7 +52,6 @@ import javax.servlet.http.HttpServletResponseWrapper;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.DebugListener;
import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.QuietServletException;
import org.eclipse.jetty.server.Request;
@ -753,7 +752,6 @@ public class AsyncServletTest
// ignored
}
// System.err.println(request.getDispatcherType()+" "+request.getRequestURI());
historyAdd(request.getDispatcherType()+" "+request.getRequestURI());
if (request instanceof ServletRequestWrapper || response instanceof ServletResponseWrapper)
historyAdd("wrapped"+((request instanceof ServletRequestWrapper)?" REQ":"")+((response instanceof ServletResponseWrapper)?" RSP":""));

View File

@ -259,7 +259,7 @@ public class DefaultServletTest
defholder.setInitParameter("resourceBase", resBasePath);
String response;
response = connector.getResponse("GET /context/ HTTP/1.0\r\n\r\n");
assertResponseContains("<h1>Hello Index</h1>", response);
@ -326,11 +326,13 @@ public class DefaultServletTest
testdir.ensureEmpty();
File resBase = testdir.getPathFile("docroot").toFile();
FS.ensureDirExists(resBase);
File inde = new File(resBase, "index.htm");
File index = new File(resBase, "index.html");
File dir = new File(resBase, "dir");
assertTrue(dir.mkdirs());
File inde = new File(dir, "index.htm");
File index = new File(dir, "index.html");
String resBasePath = resBase.getAbsolutePath();
ServletHolder defholder = context.addServlet(DefaultServlet.class, "/");
defholder.setInitParameter("dirAllowed", "false");
defholder.setInitParameter("redirectWelcome", "false");
@ -344,25 +346,98 @@ public class DefaultServletTest
@SuppressWarnings("unused")
ServletHolder jspholder = context.addServlet(NoJspServlet.class, "*.jsp");
String response = connector.getResponse("GET /context/ HTTP/1.0\r\n\r\n");
String response = connector.getResponse("GET /context/dir/ HTTP/1.0\r\n\r\n");
assertResponseContains("403", response);
createFile(index, "<h1>Hello Index</h1>");
response = connector.getResponse("GET /context/ HTTP/1.0\r\n\r\n");
response = connector.getResponse("GET /context/dir/ HTTP/1.0\r\n\r\n");
assertResponseContains("<h1>Hello Index</h1>", response);
createFile(inde, "<h1>Hello Inde</h1>");
response = connector.getResponse("GET /context/ HTTP/1.0\r\n\r\n");
response = connector.getResponse("GET /context/dir/ HTTP/1.0\r\n\r\n");
assertResponseContains("<h1>Hello Index</h1>", response);
assertTrue(index.delete());
response = connector.getResponse("GET /context/ HTTP/1.0\r\n\r\n");
response = connector.getResponse("GET /context/dir/ HTTP/1.0\r\n\r\n");
assertResponseContains("<h1>Hello Inde</h1>", response);
assertTrue(inde.delete());
response = connector.getResponse("GET /context/ HTTP/1.0\r\n\r\n");
response = connector.getResponse("GET /context/dir/ HTTP/1.0\r\n\r\n");
assertResponseContains("403", response);
}
@Test
public void testWelcomeRedirect() throws Exception
{
testdir.ensureEmpty();
File resBase = testdir.getPathFile("docroot").toFile();
FS.ensureDirExists(resBase);
File dir = new File(resBase, "dir");
assertTrue(dir.mkdirs());
File inde = new File(dir, "index.htm");
File index = new File(dir, "index.html");
String resBasePath = resBase.getAbsolutePath();
ServletHolder defholder = context.addServlet(DefaultServlet.class, "/");
defholder.setInitParameter("dirAllowed", "false");
defholder.setInitParameter("redirectWelcome", "true");
defholder.setInitParameter("welcomeServlets", "false");
defholder.setInitParameter("gzip", "false");
defholder.setInitParameter("resourceBase", resBasePath);
defholder.setInitParameter("maxCacheSize", "1024000");
defholder.setInitParameter("maxCachedFileSize", "512000");
defholder.setInitParameter("maxCachedFiles", "100");
@SuppressWarnings("unused")
ServletHolder jspholder = context.addServlet(NoJspServlet.class, "*.jsp");
String response = connector.getResponses("GET /context/dir/ HTTP/1.0\r\n\r\n");
assertResponseContains("403", response);
createFile(index, "<h1>Hello Index</h1>");
response = connector.getResponses("GET /context/dir/ HTTP/1.0\r\n\r\n");
assertResponseContains("Location: http://0.0.0.0/context/dir/index.html", response);
createFile(inde, "<h1>Hello Inde</h1>");
response = connector.getResponses("GET /context/dir/ HTTP/1.0\r\n\r\n");
assertResponseContains("Location: http://0.0.0.0/context/dir/index.html", response);
assertTrue(index.delete());
response = connector.getResponses("GET /context/dir/ HTTP/1.0\r\n\r\n");
assertResponseContains("Location: http://0.0.0.0/context/dir/index.htm", response);
assertTrue(inde.delete());
response = connector.getResponses("GET /context/dir/ HTTP/1.0\r\n\r\n");
assertResponseContains("403", response);
}
@Test
public void testWelcomeDirWithQuestion() throws Exception
{
testdir.ensureEmpty();
File resBase = testdir.getPathFile("docroot").toFile();
FS.ensureDirExists(resBase);
context.setBaseResource(Resource.newResource(resBase));
File dir = new File(resBase, "dir?");
assertTrue(dir.mkdirs());
File index = new File(dir, "index.html");
createFile(index, "<h1>Hello Index</h1>");
ServletHolder defholder = context.addServlet(DefaultServlet.class, "/");
defholder.setInitParameter("dirAllowed", "false");
defholder.setInitParameter("redirectWelcome", "true");
defholder.setInitParameter("welcomeServlets", "false");
defholder.setInitParameter("gzip", "false");
String response = connector.getResponse("GET /context/dir%3F HTTP/1.0\r\n\r\n");
assertResponseContains("Location: http://0.0.0.0/context/dir%3F/", response);
response = connector.getResponse("GET /context/dir%3F/ HTTP/1.0\r\n\r\n");
assertResponseContains("Location: http://0.0.0.0/context/dir%3F/index.html", response);
}
@Test
public void testWelcomeServlet() throws Exception

View File

@ -18,9 +18,12 @@
package org.eclipse.jetty.servlet;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
@ -31,7 +34,6 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.QuietServletException;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.log.StacklessLogging;
import org.hamcrest.Matchers;
@ -39,9 +41,6 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
*
*/
public class ErrorPageTest
{
private Server _server;
@ -62,6 +61,7 @@ public class ErrorPageTest
context.addServlet(DefaultServlet.class, "/");
context.addServlet(FailServlet.class, "/fail/*");
context.addServlet(FailClosedServlet.class, "/fail-closed/*");
context.addServlet(ErrorServlet.class, "/error/*");
ErrorPageErrorHandler error = new ErrorPageErrorHandler();
@ -81,7 +81,24 @@ public class ErrorPageTest
_server.stop();
_server.join();
}
@Test
public void testSendErrorClosedResponse() throws Exception
{
String response = _connector.getResponse("GET /fail-closed/ HTTP/1.0\r\n\r\n");
System.out.println(response);
assertThat(response,Matchers.containsString("HTTP/1.1 599 599"));
assertThat(response,Matchers.containsString("DISPATCH: ERROR"));
assertThat(response,Matchers.containsString("ERROR_PAGE: /599"));
assertThat(response,Matchers.containsString("ERROR_CODE: 599"));
assertThat(response,Matchers.containsString("ERROR_EXCEPTION: null"));
assertThat(response,Matchers.containsString("ERROR_EXCEPTION_TYPE: null"));
assertThat(response,Matchers.containsString("ERROR_SERVLET: org.eclipse.jetty.servlet.ErrorPageTest$FailClosedServlet-"));
assertThat(response,Matchers.containsString("ERROR_REQUEST_URI: /fail-closed/"));
assertThat(response,not(containsString("This shouldn't be seen")));
}
@Test
public void testErrorCode() throws Exception
{
@ -152,17 +169,36 @@ public class ErrorPageTest
}
}
public static class FailClosedServlet extends HttpServlet implements Servlet
{
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.sendError(599);
// The below should result in no operation, as response should be closed.
try
{
response.setStatus(200); // this status code should not be seen
response.getWriter().append("This shouldn't be seen");
}
catch (Throwable ignore)
{
}
}
}
public static class ErrorServlet extends HttpServlet implements Servlet
{
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.getWriter().println("ERROR_PAGE: "+request.getPathInfo());
response.getWriter().println("ERROR_MESSAGE: "+request.getAttribute(Dispatcher.ERROR_MESSAGE));
response.getWriter().println("ERROR_CODE: "+request.getAttribute(Dispatcher.ERROR_STATUS_CODE));
response.getWriter().println("ERROR_EXCEPTION: "+request.getAttribute(Dispatcher.ERROR_EXCEPTION));
response.getWriter().println("ERROR_EXCEPTION_TYPE: "+request.getAttribute(Dispatcher.ERROR_EXCEPTION_TYPE));
response.getWriter().println("ERROR_SERVLET: "+request.getAttribute(Dispatcher.ERROR_SERVLET_NAME));
response.getWriter().println("ERROR_REQUEST_URI: "+request.getAttribute(Dispatcher.ERROR_REQUEST_URI));
PrintWriter writer = response.getWriter();
writer.println("DISPATCH: " + request.getDispatcherType().name());
writer.println("ERROR_PAGE: " + request.getPathInfo());
writer.println("ERROR_MESSAGE: " + request.getAttribute(Dispatcher.ERROR_MESSAGE));
writer.println("ERROR_CODE: " + request.getAttribute(Dispatcher.ERROR_STATUS_CODE));
writer.println("ERROR_EXCEPTION: " + request.getAttribute(Dispatcher.ERROR_EXCEPTION));
writer.println("ERROR_EXCEPTION_TYPE: " + request.getAttribute(Dispatcher.ERROR_EXCEPTION_TYPE));
writer.println("ERROR_SERVLET: " + request.getAttribute(Dispatcher.ERROR_SERVLET_NAME));
writer.println("ERROR_REQUEST_URI: " + request.getAttribute(Dispatcher.ERROR_REQUEST_URI));
}
}

View File

@ -295,7 +295,7 @@ public class PutFilter implements Filter
public void handleMove(HttpServletRequest request, HttpServletResponse response, String pathInContext, File file)
throws ServletException, IOException, URISyntaxException
{
String newPath = URIUtil.canonicalPath(request.getHeader("new-uri"));
String newPath = URIUtil.canonicalEncodedPath(request.getHeader("new-uri"));
if (newPath == null)
{
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
@ -312,7 +312,7 @@ public class PutFilter implements Filter
if (contextPath != null)
newInfo = newInfo.substring(contextPath.length());
String new_resource = URIUtil.addPaths(_baseURI,newInfo);
String new_resource = URIUtil.addEncodedPaths(_baseURI,newInfo);
File new_file=new File(new URI(new_resource));
file.renameTo(new_file);

View File

@ -18,7 +18,6 @@
package org.eclipse.jetty.start;
import static org.eclipse.jetty.start.UsageException.ERR_BAD_GRAPH;
import static org.eclipse.jetty.start.UsageException.ERR_BAD_STOP_PROPS;
import static org.eclipse.jetty.start.UsageException.ERR_INVOKE_MAIN;
import static org.eclipse.jetty.start.UsageException.ERR_NOT_STOPPED;
@ -295,6 +294,20 @@ public class Main
StartArgs args = new StartArgs(baseHome);
args.parse(baseHome.getConfigSources());
Props props = baseHome.getConfigSources().getProps();
Props.Prop home = props.getProp(BaseHome.JETTY_HOME);
if (!args.getProperties().containsKey(BaseHome.JETTY_HOME))
args.getProperties().setProperty(home);
args.getProperties().setProperty(BaseHome.JETTY_HOME+".uri",
baseHome.getHomePath().toUri().toString(),
home.origin);
Props.Prop base = props.getProp(BaseHome.JETTY_BASE);
if (!args.getProperties().containsKey(BaseHome.JETTY_BASE))
args.getProperties().setProperty(base);
args.getProperties().setProperty(BaseHome.JETTY_BASE+".uri",
baseHome.getBasePath().toUri().toString(),
base.origin);
// ------------------------------------------------------------
// 3) Module Registration
Modules modules = new Modules(baseHome,args);

View File

@ -116,7 +116,7 @@ public class Module implements Comparable<Module>
private final List<String> _license=new ArrayList<>();
/** Dependencies */
private final Set<String> _depends=new HashSet<>();
private final List<String> _depends=new ArrayList<>();
/** Optional */
private final Set<String> _optional=new HashSet<>();
@ -183,10 +183,10 @@ public class Module implements Comparable<Module>
{
Function<String,String> expander = d->{return props.expand(d);};
Set<String> tmp=_depends.stream().map(expander).collect(Collectors.toSet());
List<String> tmp=_depends.stream().map(expander).collect(Collectors.toList());
_depends.clear();
_depends.addAll(tmp);
tmp=_optional.stream().map(expander).collect(Collectors.toSet());
tmp=_optional.stream().map(expander).collect(Collectors.toList());
_optional.clear();
_optional.addAll(tmp);
}
@ -329,7 +329,8 @@ public class Module implements Comparable<Module>
break;
case "DEPEND":
case "DEPENDS":
_depends.add(line);
if (!_depends.contains(line))
_depends.add(line);
break;
case "FILE":
case "FILES":
@ -437,9 +438,9 @@ public class Module implements Comparable<Module>
return str.toString();
}
public Set<String> getDepends()
public List<String> getDepends()
{
return new HashSet<>(_depends);
return new ArrayList<>(_depends);
}
public Set<String> getProvides()

View File

@ -335,12 +335,13 @@ public class Modules implements Iterable<Module>
}
// Process module dependencies (always processed as may be dynamic)
StartLog.debug("Enabled module %s depends on %s",module.getName(),module.getDepends());
for(String dependsOn:module.getDepends())
{
// Look for modules that provide that dependency
Set<Module> providers = getAvailableProviders(dependsOn);
StartLog.debug("Module %s depends on %s provided by ",module,dependsOn,providers);
StartLog.debug("Module %s depends on %s provided by %s",module,dependsOn,providers);
// If there are no known providers of the module
if (providers.isEmpty())
@ -381,11 +382,11 @@ public class Modules implements Iterable<Module>
private Set<Module> getAvailableProviders(String name)
{
// Get all available providers
Set<Module> providers = _provided.get(name);
StartLog.debug("Providers of %s are %s",name,providers);
if (providers==null || providers.isEmpty())
return Collections.emptySet();
providers = new HashSet<>(providers);
// find all currently provided names by other modules
@ -409,13 +410,15 @@ public class Modules implements Iterable<Module>
{
if (provided.contains(p))
{
StartLog.debug("Removing provider %s because %s already enabled",provider,p);
i.remove();
break;
}
}
}
}
StartLog.debug("Available providers of %s are %s",name,providers);
return providers;
}

View File

@ -120,7 +120,7 @@ public class StartArgs
private Set<String> skipFileValidationModules = new HashSet<>();
/** Map of enabled modules to the source of where that activation occurred */
private Map<String, List<String>> sources = new HashMap<>();
Map<String, List<String>> sources = new HashMap<>();
/** Map of properties to where that property was declared */
private Map<String, String> propertySource = new HashMap<>();

View File

@ -41,6 +41,7 @@ public class CommandLineConfigSource implements ConfigSource
{
public static final String ORIGIN_INTERNAL_FALLBACK = "<internal-fallback>";
public static final String ORIGIN_CMD_LINE = "<command-line>";
public static final String ORIGIN_SYSTEM_PROPERTY = "<system-property>";
private final RawArgs args;
private final Props props;
@ -79,6 +80,7 @@ public class CommandLineConfigSource implements ConfigSource
String val = System.getProperty(BaseHome.JETTY_BASE);
if (!Utils.isBlank(val))
{
setProperty(BaseHome.JETTY_BASE,val,ORIGIN_SYSTEM_PROPERTY);
return FS.toPath(val);
}
@ -101,6 +103,7 @@ public class CommandLineConfigSource implements ConfigSource
String val = System.getProperty(BaseHome.JETTY_HOME);
if (!Utils.isBlank(val))
{
setProperty(BaseHome.JETTY_HOME,val,ORIGIN_SYSTEM_PROPERTY);
return FS.toPath(val);
}
@ -116,7 +119,9 @@ public class CommandLineConfigSource implements ConfigSource
// ${jetty.home} is relative to found BaseHome class
try
{
return new File(new URI(m.group(1))).getParentFile().toPath();
Path home = new File(new URI(m.group(1))).getParentFile().toPath();
setProperty(BaseHome.JETTY_HOME,home.toString(),ORIGIN_INTERNAL_FALLBACK);
return home;
}
catch (URISyntaxException e)
{
@ -127,7 +132,7 @@ public class CommandLineConfigSource implements ConfigSource
// Lastly, fall back to ${user.dir} default
Path home = FS.toPath(System.getProperty("user.dir","."));
setProperty(BaseHome.JETTY_HOME,home.toString(),ORIGIN_INTERNAL_FALLBACK);
setProperty(BaseHome.JETTY_HOME,home.toString(),"<user.dir>");
return home;
}

View File

@ -50,7 +50,6 @@ public class ConfigSources implements Iterable<ConfigSource>
}
private LinkedList<ConfigSource> sources = new LinkedList<>();
private Props props = new Props();
private AtomicInteger sourceWeight = new AtomicInteger(1);
public void add(ConfigSource source) throws IOException
@ -61,18 +60,15 @@ public class ConfigSources implements Iterable<ConfigSource>
throw new UsageException(ERR_BAD_ARG,"Duplicate Configuration Source Reference: " + source);
}
sources.add(source);
Collections.sort(sources,new WeightedConfigSourceComparator());
updateProps();
// look for --include-jetty-dir entries
for (RawArgs.Entry arg : source.getArgs())
{
if (arg.startsWith("--include-jetty-dir"))
{
String ref = getValue(arg.getLine());
String dirName = props.expand(ref);
String dirName = getProps().expand(ref);
Path dir = FS.toPath(dirName).normalize().toAbsolutePath();
DirConfigSource dirsource = new DirConfigSource(ref,dir,sourceWeight.incrementAndGet(),true);
add(dirsource);
@ -94,11 +90,20 @@ public class ConfigSources implements Iterable<ConfigSource>
public Prop getProp(String key)
{
return props.getProp(key);
return getProps().getProp(key);
}
public Props getProps()
{
Props props = new Props();
// add all properties from config sources (in reverse order)
ListIterator<ConfigSource> iter = sources.listIterator(sources.size());
while (iter.hasPrevious())
{
ConfigSource source = iter.previous();
props.addAll(source.getProps());
}
return props;
}
@ -147,17 +152,4 @@ public class ConfigSources implements Iterable<ConfigSource>
str.append(']');
return str.toString();
}
private void updateProps()
{
props.reset();
// add all properties from config sources (in reverse order)
ListIterator<ConfigSource> iter = sources.listIterator(sources.size());
while (iter.hasPrevious())
{
ConfigSource source = iter.previous();
props.addAll(source.getProps());
}
}
}

View File

@ -137,9 +137,13 @@ public class ConfigurationAssert
for (Prop prop : args.getProperties())
{
String name = prop.key;
if ("jetty.home".equals(name) || "jetty.base".equals(name) ||
"user.dir".equals(name) || prop.origin.equals(Props.ORIGIN_SYSPROP) ||
name.startsWith("java."))
if ("jetty.home".equals(name) ||
"jetty.base".equals(name) ||
"jetty.home.uri".equals(name) ||
"jetty.base.uri".equals(name) ||
"user.dir".equals(name) ||
prop.origin.equals(Props.ORIGIN_SYSPROP) ||
name.startsWith("java."))
{
// strip these out from assertion, to make assertions easier.
continue;

View File

@ -60,9 +60,19 @@ public class MainTest
Main main = new Main();
StartArgs args = main.processCommandLine(cmdLineArgs.toArray(new String[cmdLineArgs.size()]));
BaseHome baseHome = main.getBaseHome();
System.err.println(args);
// System.err.println(args);
ConfigurationAssert.assertConfiguration(baseHome,args,"assert-home.txt");
// System.err.println("StartArgs.props:");
// args.getProperties().forEach(p->System.err.println(p));
// System.err.println("BaseHome.props:");
// baseHome.getConfigSources().getProps().forEach(p->System.err.println(p));
assertThat(args.getProperties().getString("jetty.home"),is(baseHome.getHome()));
assertThat(args.getProperties().getString("jetty.home.uri"),is(baseHome.getHomePath().toUri().toString()));
assertThat(args.getProperties().getString("jetty.base"),is(baseHome.getBase()));
assertThat(args.getProperties().getString("jetty.base.uri"),is(baseHome.getBasePath().toUri().toString()));
}
@Test
@ -76,7 +86,7 @@ public class MainTest
Main main = new Main();
StartArgs args = main.processCommandLine(cmdLineArgs.toArray(new String[cmdLineArgs.size()]));
System.err.println(args);
// System.err.println(args);
// Assert.assertEquals("--stop should not build module tree", 0, args.getEnabledModules().size());
assertEquals("--stop missing port","10000",args.getProperties().getString("STOP.PORT"));

View File

@ -0,0 +1,12 @@
## The XMLs we expect (order is important)
XML|${jetty.home}/etc/base.xml
XML|${jetty.home}/etc/main.xml
# The LIBs we expect (order is irrelevant)
LIB|${jetty.home}/lib/base.jar
LIB|${jetty.home}/lib/main.jar
LIB|${jetty.home}/lib/other.jar
# The Properties we expect (order is irrelevant)
PROP|main.prop=value0
PROP|impl=replacement

View File

@ -0,0 +1,2 @@
--module=main,convenience

View File

@ -0,0 +1,4 @@
[depends]
replacement
something-else

View File

@ -0,0 +1,4 @@
[ini]
impl=original

View File

@ -0,0 +1,7 @@
[provides]
original
[ini]
impl=replacement

View File

@ -0,0 +1,3 @@
[depends]
original

View File

@ -26,5 +26,5 @@ Log4j is released under the Apache 2.0 license.
http://www.apache.org/licenses/LICENSE-2.0.html
[ini]
log4j.version=1.2.17
log4j.version?=1.2.17
jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/log4j/

View File

@ -21,5 +21,5 @@ Log4j is released under the Apache 2.0 license.
http://www.apache.org/licenses/LICENSE-2.0.html
[ini]
log4j2.version=2.6.1
log4j2.version?=2.6.1
jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/log4j2/

View File

@ -34,5 +34,5 @@ or (per the licensee's choosing) under
http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
[ini]
logback.version=1.1.7
logback.version?=1.1.7
jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/logback/

View File

@ -14,6 +14,3 @@ logging
[exec]
-Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
[ini]
jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/slf4j/

View File

@ -14,6 +14,3 @@ logging
[exec]
-Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
[ini]
jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/slf4j/,${jetty.base.uri}/lib/log4j/

View File

@ -14,6 +14,3 @@ logging
[exec]
-Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
[ini]
jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/slf4j/,${jetty.base.uri}/lib/log4j2/

View File

@ -14,6 +14,3 @@ logging
[exec]
-Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
[ini]
jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/slf4j/,${jetty.base.uri}/lib/logback/

View File

@ -14,6 +14,3 @@ logging
[exec]
-Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
[ini]
jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/slf4j/

View File

@ -14,7 +14,8 @@ maven://org.slf4j/slf4j-api/${slf4j.version}|lib/slf4j/slf4j-api-${slf4j.version
lib/slf4j/slf4j-api-${slf4j.version}.jar
[ini]
slf4j.version=1.7.21
slf4j.version?=1.7.21
jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/slf4j/
[license]
SLF4J is distributed under the MIT License.

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