Merge remote-tracking branch 'origin/jetty-9.4.x'
This commit is contained in:
commit
68caf72835
52
VERSION.txt
52
VERSION.txt
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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.
|
@ -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
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
org.eclipse.jetty.annotations.ServerServletContainerInitializer
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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]
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
|
||||
_____
|
||||
|
|
|
@ -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[]
|
||||
|
|
|
@ -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.]
|
||||
|
||||
|
|
|
@ -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`.
|
||||
____
|
||||
|
|
|
@ -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::
|
||||
|
|
|
@ -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`.
|
||||
____
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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::
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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]
|
||||
----
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
-->
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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('/');
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,12 @@ public class ContextHandlerCollection extends HandlerCollection
|
|||
{
|
||||
super(true);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public ContextHandlerCollection(ContextHandler... contexts)
|
||||
{
|
||||
super(true,contexts);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"+
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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")));
|
||||
}
|
||||
|
|
|
@ -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":""));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<>();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
--module=main,convenience
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
[depends]
|
||||
replacement
|
||||
something-else
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
|
||||
[ini]
|
||||
impl=original
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
|
||||
[provides]
|
||||
original
|
||||
|
||||
[ini]
|
||||
impl=replacement
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
[depends]
|
||||
original
|
|
@ -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/
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue