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

This commit is contained in:
Joakim Erdfelt 2017-04-21 09:00:54 -07:00
commit 849ad7c917
353 changed files with 7721 additions and 2289 deletions

View File

@ -1,10 +1,112 @@
jetty-9.4.3-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
version scope
+ 609 websocket ClientCloseTest testServerNoCloseHandshake is failing
+ 856 Add server/port and auth configuration for mongo sessions
+ 1015 Ensure jetty-distribution excludes git / temp files
+ 1049 test-jetty-osgi test exits/crashes the surefire forked JVM
+ 1184 IllegalStateException for HEAD requests responded with 404
+ 1340 PushCacheFilter question
+ 1351 StringIndexOutOfBoundsException thrown on incomplete Accept-Language
header
+ 1353 A Large ClasspathPattern results in infinite loop
+ 1357 RolloverFileOutputStream: No rollout performed at midnight
+ 1363 HttpInput.read deadlock (async mode)
+ 1374 When `Server.start` fails, beans ought to be stopped
+ 1375 Support pushed resources in HTTP client
+ 1378 Slow TLS clients may hang the server
+ 1379 Misleading javadoc for initialization of SessionIdPathParameterName
+ 1383 javadoc build on JDK 8u121 fails due to scripts
+ 1384 Expose StatisticsServlet to webapp
+ 1387 Windows and paxexam failure due to "renaming bundle"
+ 1389 Update to gcloud datastore-0.9.4-beta
+ 1390 HashLoginService and "this.web-inf.url" property are incompatible
+ 1394 Default OS Locale/Encoding/Charset can cause test failures
+ 1396 Set-Cookie produced by Jetty is invalid for RFC6265 and Chrome
+ 1398 Ensure all SessionDataStores store lastsaved time
+ 1399 SlowClientTest is failing on CI
+ 1401 HttpOutput.recycle() does not clear the write listener
+ 1402 Move RFC syntax validation to jetty-http Syntax class
+ 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
+ 609 websocket ClientCloseTest testServerNoCloseHandshake is failing
+ 1015 Ensure jetty-distribution excludes git / temp files
+ 1047 ReadPendingException and then thread death
+ 1049 test-jetty-osgi test exits/crashes the surefire forked JVM
+ 1282 ByteArrayEndPointTest.testIdle() failure
+ 1296 Introduce HTTP parser "content complete" event
+ 1326 Jetty shutdown command got NullPointerException (http2 module added to
start)
+ 1328 Response.setBufferSize(int) ISE should be more clear on reason
+ 1340 PushCacheFilter question
+ 1342 Improve ByteBufferPool scalability
+ 1351 StringIndexOutOfBoundsException thrown on incomplete Accept-Language
header
+ 1357 RolloverFileOutputStream: No rollout performed at midnight
+ 1374 When `Server.start` fails, beans ought to be stopped
+ 1375 Support pushed resources in HTTP client
+ 1378 Slow TLS clients may hang the server
+ 1383 javadoc build on JDK 8u121 fails due to scripts
+ 1384 Expose StatisticsServlet to webapp
+ 1387 Windows and paxexam failure due to "renaming bundle"
+ 1389 Update to gcloud datastore-0.9.4-beta
+ 1390 HashLoginService and "this.web-inf.url" property are incompatible
+ 1394 Default OS Locale/Encoding/Charset can cause test failures
+ 1396 Set-Cookie produced by Jetty is invalid for RFC6265 and Chrome
+ 1399 SlowClientTest is failing on CI
+ 1401 HttpOutput.recycle() does not clear the write listener
jetty-9.4.2.v20170220 - 20 February 2017 jetty-9.4.2.v20170220 - 20 February 2017
+ 612 Support HTTP Trailer + 612 Support HTTP Trailer
+ 1047 ReadPendingException and then thread death + 1047 ReadPendingException and then thread death
+ 1150 Rationalize the session tests + 1150 Rationalize the session tests
+ 1226 Undefined JETTY_LOGS breaks jetty.sh + 1226 Undefined JETTY_LOGS breaks jetty.sh
+ 1282 ByteArrayEndPointTest.testIdle() failure + 1282 ByteArrayEndPointTest.testIdle() failure
+ 1284 IllegalStateException updating session inactive interval + 1284 IllegalStateException updating session inactive interval
+ 1290 http2-hpack not visible in OSGi + 1290 http2-hpack not visible in OSGi
@ -206,6 +308,13 @@ jetty-9.3.15.v20161220 - 20 December 2016
+ 1186 Where can i find SocketConnector .java and + 1186 Where can i find SocketConnector .java and
BlockingChannelConnector.java etc? BlockingChannelConnector.java etc?
jetty-9.2.21.v20170120 - 20 January 2017
+ 592 Support no-value Host header in HttpParser
+ 1229 ClassLoader constraint issue when using NativeWebSocketConfiguration
with WEB-INF/lib/jetty-http.jar present
+ 1267 Request.getRemoteUser can throw undeclared IllegalStateException via
DeferredAuthentication & FormAuthenticator
jetty-9.4.0.RC3 - 05 December 2016 jetty-9.4.0.RC3 - 05 December 2016
+ 1051 NCSARequestLog/RolloverFileOutputStream does not roll day after DST + 1051 NCSARequestLog/RolloverFileOutputStream does not roll day after DST
ends ends

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>apache-jsp</artifactId> <artifactId>apache-jsp</artifactId>

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>apache-jstl</artifactId> <artifactId>apache-jstl</artifactId>

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>example-async-rest</artifactId> <artifactId>example-async-rest</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.example-async-rest</groupId> <groupId>org.eclipse.jetty.example-async-rest</groupId>

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>example-async-rest</artifactId> <artifactId>example-async-rest</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.example-async-rest</groupId> <groupId>org.eclipse.jetty.example-async-rest</groupId>

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty.examples</groupId> <groupId>org.eclipse.jetty.examples</groupId>
<artifactId>examples-parent</artifactId> <artifactId>examples-parent</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty.examples</groupId> <groupId>org.eclipse.jetty.examples</groupId>
<artifactId>examples-parent</artifactId> <artifactId>examples-parent</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

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

View File

@ -58,6 +58,7 @@ public class ManyServletContexts
other.addServlet(new ServletHolder(new HelloServlet("YO!")), "*.yo"); other.addServlet(new ServletHolder(new HelloServlet("YO!")), "*.yo");
server.start(); server.start();
server.dumpStdErr();
server.join(); server.join();
} }
} }

View File

@ -22,7 +22,6 @@ import java.io.File;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import org.eclipse.jetty.jmx.MBeanContainer; import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker; import org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker;
import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.webapp.WebAppContext;
@ -62,6 +61,8 @@ public class OneWebApp
// Start things up! // Start things up!
server.start(); server.start();
server.dumpStdErr();
// The use of server.join() the will make the current thread join and // The use of server.join() the will make the current thread join and
// wait until the server is done executing. // wait until the server is done executing.
// See http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#join() // See http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#join()

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>org.eclipse.jetty.examples</groupId> <groupId>org.eclipse.jetty.examples</groupId>

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-parent</artifactId> <artifactId>jetty-alpn-parent</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>jetty-alpn-client</artifactId> <artifactId>jetty-alpn-client</artifactId>

View File

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-parent</artifactId> <artifactId>jetty-alpn-parent</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-parent</artifactId> <artifactId>jetty-alpn-parent</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-parent</artifactId> <artifactId>jetty-alpn-parent</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>jetty-alpn-server</artifactId> <artifactId>jetty-alpn-server</artifactId>

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>jetty-alpn-parent</artifactId> <artifactId>jetty-alpn-parent</artifactId>

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>jetty-annotations</artifactId> <artifactId>jetty-annotations</artifactId>

View File

@ -29,6 +29,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.ListIterator;
import java.util.Map; import java.util.Map;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import java.util.Set; import java.util.Set;
@ -344,8 +345,6 @@ public class AnnotationConfiguration extends AbstractConfiguration
{ {
context.getObjectFactory().addDecorator(new AnnotationDecorator(context)); 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 (!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 //If metadata isn't complete, if this is a servlet 3 webapp or isConfigDiscovered is true, we need to search for annotations
@ -860,7 +859,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()) if (LOG.isDebugEnabled())
{ {

Binary file not shown.

View File

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

View File

@ -19,11 +19,20 @@
package org.eclipse.jetty.annotations; package org.eclipse.jetty.annotations;
import static org.junit.Assert.assertNotNull; 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.io.File;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
@ -38,6 +47,148 @@ import org.junit.Test;
*/ */
public class TestAnnotationConfiguration 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 @Test
public void testGetFragmentFromJar() throws Exception public void testGetFragmentFromJar() throws Exception
{ {

View File

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

View File

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

View File

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

View File

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

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>jetty-ant</artifactId> <artifactId>jetty-ant</artifactId>

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

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

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty.cdi</groupId> <groupId>org.eclipse.jetty.cdi</groupId>
<artifactId>jetty-cdi-parent</artifactId> <artifactId>jetty-cdi-parent</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>cdi-core</artifactId> <artifactId>cdi-core</artifactId>

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty.cdi</groupId> <groupId>org.eclipse.jetty.cdi</groupId>
<artifactId>jetty-cdi-parent</artifactId> <artifactId>jetty-cdi-parent</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>cdi-full-servlet</artifactId> <artifactId>cdi-full-servlet</artifactId>

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty.cdi</groupId> <groupId>org.eclipse.jetty.cdi</groupId>
<artifactId>jetty-cdi-parent</artifactId> <artifactId>jetty-cdi-parent</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>cdi-servlet</artifactId> <artifactId>cdi-servlet</artifactId>

View File

@ -13,14 +13,13 @@ lib/cdi/
maven://javax.enterprise/cdi-api/1.2|lib/cdi/javax.enterprise.cdi-api-1.2.jar maven://javax.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.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://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.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.2.9.Final|lib/cdi/weld-environment-common-2.2.9.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.2.9.Final|lib/cdi/weld-core-impl-2.2.9.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.0.5.Final|lib/cdi/jboss-classfilewriter-1.0.5.Final.jar maven://org.jboss.classfilewriter/jboss-classfilewriter/1.1.2.Final|lib/cdi/jboss-classfilewriter-1.1.2.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.4.SP1|lib/cdi/weld-spi-2.4.SP1.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.4.SP1|lib/cdi/weld-api-2.4.SP1.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.2.1.Final|lib/cdi/jboss-logging-3.2.1.Final.jar
maven://org.jboss.logging/jboss-logging/3.1.3.GA|lib/cdi/jboss-logging-3.1.3.GA.jar
[lib] [lib]

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty.cdi</groupId> <groupId>org.eclipse.jetty.cdi</groupId>
<artifactId>jetty-cdi-parent</artifactId> <artifactId>jetty-cdi-parent</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>cdi-websocket</artifactId> <artifactId>cdi-websocket</artifactId>

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.cdi</groupId> <groupId>org.eclipse.jetty.cdi</groupId>
@ -11,7 +11,7 @@
<url>http://www.eclipse.org/jetty</url> <url>http://www.eclipse.org/jetty</url>
<packaging>pom</packaging> <packaging>pom</packaging>
<properties> <properties>
<weld.version>2.2.9.Final</weld.version> <weld.version>2.4.3.Final</weld.version>
</properties> </properties>
<modules> <modules>

View File

@ -3,7 +3,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty.cdi</groupId> <groupId>org.eclipse.jetty.cdi</groupId>
<artifactId>jetty-cdi-parent</artifactId> <artifactId>jetty-cdi-parent</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>test-cdi-webapp</artifactId> <artifactId>test-cdi-webapp</artifactId>

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -41,6 +41,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Supplier;
import org.eclipse.jetty.client.api.ContentProvider; import org.eclipse.jetty.client.api.ContentProvider;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.api.ContentResponse;
@ -83,6 +84,7 @@ public class HttpRequest implements Request
private Map<String, Object> attributes; private Map<String, Object> attributes;
private List<RequestListener> requestListeners; private List<RequestListener> requestListeners;
private BiFunction<Request, Request, Response.CompleteListener> pushListener; private BiFunction<Request, Request, Response.CompleteListener> pushListener;
private Supplier<HttpFields> trailers;
protected HttpRequest(HttpClient client, HttpConversation conversation, URI uri) protected HttpRequest(HttpClient client, HttpConversation conversation, URI uri)
{ {
@ -589,6 +591,12 @@ public class HttpRequest implements Request
return this; return this;
} }
public HttpRequest trailers(Supplier<HttpFields> trailers)
{
this.trailers = trailers;
return this;
}
@Override @Override
public ContentProvider getContent() public ContentProvider getContent()
{ {
@ -725,6 +733,11 @@ public class HttpRequest implements Request
return pushListener; return pushListener;
} }
public Supplier<HttpFields> getTrailers()
{
return trailers;
}
@Override @Override
public boolean abort(Throwable cause) public boolean abort(Throwable cause)
{ {

View File

@ -23,6 +23,7 @@ import java.util.List;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.HttpVersion;
@ -34,6 +35,7 @@ public class HttpResponse implements Response
private HttpVersion version; private HttpVersion version;
private int status; private int status;
private String reason; private String reason;
private HttpFields trailers;
public HttpResponse(Request request, List<ResponseListener> listeners) public HttpResponse(Request request, List<ResponseListener> listeners)
{ {
@ -97,6 +99,19 @@ public class HttpResponse implements Response
return result; return result;
} }
public HttpFields getTrailers()
{
return trailers;
}
public HttpResponse trailer(HttpField trailer)
{
if (trailers == null)
trailers = new HttpFields();
trailers.add(trailer);
return this;
}
@Override @Override
public boolean abort(Throwable cause) public boolean abort(Throwable cause)
{ {

View File

@ -20,10 +20,12 @@ package org.eclipse.jetty.client;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import org.eclipse.jetty.client.api.ContentProvider; import org.eclipse.jetty.client.api.ContentProvider;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.BufferUtil;
@ -31,7 +33,6 @@ import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IteratingCallback; import org.eclipse.jetty.util.IteratingCallback;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.Invocable.InvocationType;
/** /**
* {@link HttpSender} abstracts the algorithm to send HTTP requests, so that subclasses only implement * {@link HttpSender} abstracts the algorithm to send HTTP requests, so that subclasses only implement
@ -42,9 +43,9 @@ import org.eclipse.jetty.util.thread.Invocable.InvocationType;
* {@link HttpSender} governs two state machines. * {@link HttpSender} governs two state machines.
* <p> * <p>
* The request state machine is updated by {@link HttpSender} as the various steps of sending a request * The request state machine is updated by {@link HttpSender} as the various steps of sending a request
* are executed, see <code>RequestState</code>. * are executed, see {@code RequestState}.
* At any point in time, a user thread may abort the request, which may (if the request has not been * At any point in time, a user thread may abort the request, which may (if the request has not been
* completely sent yet) move the request state machine to <code>RequestState#FAILURE</code>. * completely sent yet) move the request state machine to {@code RequestState#FAILURE}.
* The request state machine guarantees that the request steps are executed (by I/O threads) only if * The request state machine guarantees that the request steps are executed (by I/O threads) only if
* the request has not been failed already. * the request has not been failed already.
* <p> * <p>
@ -64,7 +65,8 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
private final AtomicReference<SenderState> senderState = new AtomicReference<>(SenderState.IDLE); private final AtomicReference<SenderState> senderState = new AtomicReference<>(SenderState.IDLE);
private final Callback commitCallback = new CommitCallback(); private final Callback commitCallback = new CommitCallback();
private final IteratingCallback contentCallback = new ContentCallback(); private final IteratingCallback contentCallback = new ContentCallback();
private final Callback lastCallback = new LastContentCallback(); private final Callback trailersCallback = new TrailersCallback();
private final Callback lastCallback = new LastCallback();
private final HttpChannel channel; private final HttpChannel channel;
private HttpContent content; private HttpContent content;
private Throwable failure; private Throwable failure;
@ -407,7 +409,7 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
/** /**
* Implementations should send the content at the {@link HttpContent} cursor position over the wire. * Implementations should send the content at the {@link HttpContent} cursor position over the wire.
* <p> * <p>
* The {@link HttpContent} cursor is advanced by {@link HttpSender} at the right time, and if more * The {@link HttpContent} cursor is advanced by HttpSender at the right time, and if more
* content needs to be sent, this method is invoked again; subclasses need only to send the content * content needs to be sent, this method is invoked again; subclasses need only to send the content
* at the {@link HttpContent} cursor position. * at the {@link HttpContent} cursor position.
* <p> * <p>
@ -422,6 +424,15 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
*/ */
protected abstract void sendContent(HttpExchange exchange, HttpContent content, Callback callback); protected abstract void sendContent(HttpExchange exchange, HttpContent content, Callback callback);
/**
* Implementations should send the HTTP trailers and notify the given {@code callback} of the
* result of this operation.
*
* @param exchange the exchange to send
* @param callback the callback to notify
*/
protected abstract void sendTrailers(HttpExchange exchange, Callback callback);
protected void reset() protected void reset()
{ {
HttpContent content = this.content; HttpContent content = this.content;
@ -674,13 +685,6 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
private class CommitCallback implements Callback private class CommitCallback implements Callback
{ {
@Override
public InvocationType getInvocationType()
{
return content.getInvocationType();
}
@Override @Override
public void succeeded() public void succeeded()
{ {
@ -721,10 +725,20 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
if (content == null) if (content == null)
return; return;
if (!content.hasContent()) HttpRequest request = exchange.getRequest();
Supplier<HttpFields> trailers = request.getTrailers();
boolean hasContent = content.hasContent();
if (!hasContent)
{ {
// No content to send, we are done. if (trailers == null)
someToSuccess(exchange); {
// No trailers or content to send, we are done.
someToSuccess(exchange);
}
else
{
sendTrailers(exchange, lastCallback);
}
} }
else else
{ {
@ -825,7 +839,9 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
if (lastContent) if (lastContent)
{ {
sendContent(exchange, content, lastCallback); HttpRequest request = exchange.getRequest();
Supplier<HttpFields> trailers = request.getTrailers();
sendContent(exchange, content, trailers == null ? lastCallback : trailersCallback);
return Action.IDLE; return Action.IDLE;
} }
@ -884,19 +900,35 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
@Override @Override
protected void onCompleteSuccess() protected void onCompleteSuccess()
{ {
// Nothing to do, since we always return false from process(). // Nothing to do, since we always return IDLE from process().
// Termination is obtained via LastContentCallback. // Termination is obtained via LastCallback.
} }
} }
private class LastContentCallback implements Callback private class TrailersCallback implements Callback
{ {
@Override @Override
public InvocationType getInvocationType() public void succeeded()
{ {
return content.getInvocationType(); HttpExchange exchange = getHttpExchange();
if (exchange == null)
return;
sendTrailers(exchange, lastCallback);
} }
@Override
public void failed(Throwable x)
{
HttpContent content = HttpSender.this.content;
if (content == null)
return;
content.failed(x);
anyToFailure(x);
}
}
private class LastCallback implements Callback
{
@Override @Override
public void succeeded() public void succeeded()
{ {

View File

@ -276,7 +276,17 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
{ {
return false; return false;
} }
@Override
public void parsedTrailer(HttpField trailer)
{
HttpExchange exchange = getHttpExchange();
if (exchange == null)
return;
exchange.getResponse().trailer(trailer);
}
@Override @Override
public boolean messageComplete() public boolean messageComplete()
{ {

View File

@ -23,26 +23,29 @@ import java.nio.ByteBuffer;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpContent; import org.eclipse.jetty.client.HttpContent;
import org.eclipse.jetty.client.HttpExchange; import org.eclipse.jetty.client.HttpExchange;
import org.eclipse.jetty.client.HttpRequest;
import org.eclipse.jetty.client.HttpRequestException; import org.eclipse.jetty.client.HttpRequestException;
import org.eclipse.jetty.client.HttpSender; import org.eclipse.jetty.client.HttpSender;
import org.eclipse.jetty.client.api.ContentProvider; import org.eclipse.jetty.client.api.ContentProvider;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpGenerator;
import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IteratingCallback; import org.eclipse.jetty.util.IteratingCallback;
public class HttpSenderOverHTTP extends HttpSender public class HttpSenderOverHTTP extends HttpSender
{ {
private final HttpGenerator generator = new HttpGenerator(); private final HttpGenerator generator = new HttpGenerator();
private final HttpClient httpClient;
private boolean shutdown; private boolean shutdown;
public HttpSenderOverHTTP(HttpChannelOverHTTP channel) public HttpSenderOverHTTP(HttpChannelOverHTTP channel)
{ {
super(channel); super(channel);
httpClient = channel.getHttpDestination().getHttpClient();
} }
@Override @Override
@ -71,8 +74,7 @@ public class HttpSenderOverHTTP extends HttpSender
{ {
try try
{ {
HttpClient client = getHttpChannel().getHttpDestination().getHttpClient(); ByteBufferPool bufferPool = httpClient.getByteBufferPool();
ByteBufferPool bufferPool = client.getByteBufferPool();
ByteBuffer chunk = null; ByteBuffer chunk = null;
while (true) while (true)
{ {
@ -90,6 +92,11 @@ public class HttpSenderOverHTTP extends HttpSender
chunk = bufferPool.acquire(HttpGenerator.CHUNK_SIZE, false); chunk = bufferPool.acquire(HttpGenerator.CHUNK_SIZE, false);
break; break;
} }
case NEED_CHUNK_TRAILER:
{
callback.succeeded();
return;
}
case FLUSH: case FLUSH:
{ {
EndPoint endPoint = getHttpChannel().getHttpConnection().getEndPoint(); EndPoint endPoint = getHttpChannel().getHttpConnection().getEndPoint();
@ -131,6 +138,21 @@ public class HttpSenderOverHTTP extends HttpSender
} }
} }
@Override
protected void sendTrailers(HttpExchange exchange, Callback callback)
{
try
{
new TrailersCallback(callback).iterate();
}
catch (Throwable x)
{
if (LOG.isDebugEnabled())
LOG.debug(x);
callback.failed(x);
}
}
@Override @Override
protected void reset() protected void reset()
{ {
@ -181,7 +203,7 @@ public class HttpSenderOverHTTP extends HttpSender
this.exchange = exchange; this.exchange = exchange;
this.callback = callback; this.callback = callback;
Request request = exchange.getRequest(); HttpRequest request = exchange.getRequest();
ContentProvider requestContent = request.getContent(); ContentProvider requestContent = request.getContent();
long contentLength = requestContent == null ? -1 : requestContent.getLength(); long contentLength = requestContent == null ? -1 : requestContent.getLength();
String path = request.getPath(); String path = request.getPath();
@ -189,6 +211,7 @@ public class HttpSenderOverHTTP extends HttpSender
if (query != null) if (query != null)
path += "?" + query; path += "?" + query;
metaData = new MetaData.Request(request.getMethod(), new HttpURI(path), request.getVersion(), request.getHeaders(), contentLength); metaData = new MetaData.Request(request.getMethod(), new HttpURI(path), request.getVersion(), request.getHeaders(), contentLength);
metaData.setTrailerSupplier(request.getTrailers());
if (!expects100Continue(request)) if (!expects100Continue(request))
{ {
@ -201,9 +224,6 @@ public class HttpSenderOverHTTP extends HttpSender
@Override @Override
protected Action process() throws Exception protected Action process() throws Exception
{ {
HttpClient client = getHttpChannel().getHttpDestination().getHttpClient();
ByteBufferPool bufferPool = client.getByteBufferPool();
while (true) while (true)
{ {
HttpGenerator.Result result = generator.generateRequest(metaData, headerBuffer, chunkBuffer, contentBuffer, lastContent); HttpGenerator.Result result = generator.generateRequest(metaData, headerBuffer, chunkBuffer, contentBuffer, lastContent);
@ -217,31 +237,28 @@ public class HttpSenderOverHTTP extends HttpSender
{ {
case NEED_HEADER: case NEED_HEADER:
{ {
headerBuffer = bufferPool.acquire(client.getRequestBufferSize(), false); headerBuffer = httpClient.getByteBufferPool().acquire(httpClient.getRequestBufferSize(), false);
break; break;
} }
case NEED_CHUNK: case NEED_CHUNK:
{ {
chunkBuffer = bufferPool.acquire(HttpGenerator.CHUNK_SIZE, false); chunkBuffer = httpClient.getByteBufferPool().acquire(HttpGenerator.CHUNK_SIZE, false);
break; break;
} }
case NEED_CHUNK_TRAILER:
{
return Action.SUCCEEDED;
}
case FLUSH: case FLUSH:
{ {
EndPoint endPoint = getHttpChannel().getHttpConnection().getEndPoint(); EndPoint endPoint = getHttpChannel().getHttpConnection().getEndPoint();
if (headerBuffer == null)
headerBuffer = BufferUtil.EMPTY_BUFFER;
if (chunkBuffer == null) if (chunkBuffer == null)
{ chunkBuffer = BufferUtil.EMPTY_BUFFER;
if (contentBuffer == null) if (contentBuffer == null)
endPoint.write(this, headerBuffer); contentBuffer = BufferUtil.EMPTY_BUFFER;
else endPoint.write(this, headerBuffer, chunkBuffer, contentBuffer);
endPoint.write(this, headerBuffer, contentBuffer);
}
else
{
if (contentBuffer == null)
endPoint.write(this, headerBuffer, chunkBuffer);
else
endPoint.write(this, headerBuffer, chunkBuffer, contentBuffer);
}
generated = true; generated = true;
return Action.SCHEDULED; return Action.SCHEDULED;
} }
@ -296,13 +313,91 @@ public class HttpSenderOverHTTP extends HttpSender
private void release() private void release()
{ {
HttpClient client = getHttpChannel().getHttpDestination().getHttpClient(); ByteBufferPool bufferPool = httpClient.getByteBufferPool();
ByteBufferPool bufferPool = client.getByteBufferPool(); if (headerBuffer != BufferUtil.EMPTY_BUFFER)
bufferPool.release(headerBuffer); bufferPool.release(headerBuffer);
headerBuffer = null; headerBuffer = null;
if (chunkBuffer != null) if (chunkBuffer != BufferUtil.EMPTY_BUFFER)
bufferPool.release(chunkBuffer); bufferPool.release(chunkBuffer);
chunkBuffer = null; chunkBuffer = null;
contentBuffer = null;
}
}
private class TrailersCallback extends IteratingCallback
{
private final Callback callback;
private ByteBuffer chunkBuffer;
public TrailersCallback(Callback callback)
{
this.callback = callback;
}
@Override
protected Action process() throws Throwable
{
while (true)
{
HttpGenerator.Result result = generator.generateRequest(null, null, chunkBuffer, null, true);
if (LOG.isDebugEnabled())
LOG.debug("Generated trailers {}/{}", result, generator);
switch (result)
{
case NEED_CHUNK_TRAILER:
{
chunkBuffer = httpClient.getByteBufferPool().acquire(httpClient.getRequestBufferSize(), false);
break;
}
case FLUSH:
{
EndPoint endPoint = getHttpChannel().getHttpConnection().getEndPoint();
endPoint.write(this, chunkBuffer);
return Action.SCHEDULED;
}
case SHUTDOWN_OUT:
{
shutdownOutput();
return Action.SUCCEEDED;
}
case DONE:
{
return Action.SUCCEEDED;
}
default:
{
throw new IllegalStateException(result.toString());
}
}
}
}
@Override
public void succeeded()
{
release();
super.succeeded();
}
@Override
public void failed(Throwable x)
{
release();
callback.failed(x);
super.failed(x);
}
@Override
protected void onCompleteSuccess()
{
super.onCompleteSuccess();
callback.succeeded();
}
private void release()
{
httpClient.getByteBufferPool().release(chunkBuffer);
chunkBuffer = null;
} }
} }

View File

@ -71,8 +71,6 @@ public abstract class AbstractHttpClientServerTest
sslContextFactory.setEndpointIdentificationAlgorithm(""); sslContextFactory.setEndpointIdentificationAlgorithm("");
sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
sslContextFactory.setKeyStorePassword("storepwd"); sslContextFactory.setKeyStorePassword("storepwd");
sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks");
sslContextFactory.setTrustStorePassword("storepwd");
} }
if (server == null) if (server == null)

View File

@ -72,8 +72,6 @@ public class HttpClientTLSTest
sslContextFactory.setEndpointIdentificationAlgorithm(""); sslContextFactory.setEndpointIdentificationAlgorithm("");
sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
sslContextFactory.setKeyStorePassword("storepwd"); sslContextFactory.setKeyStorePassword("storepwd");
sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks");
sslContextFactory.setTrustStorePassword("storepwd");
return sslContextFactory; return sslContextFactory;
} }

View File

@ -69,8 +69,6 @@ public class TLSServerConnectionCloseTest
sslContextFactory.setEndpointIdentificationAlgorithm(""); sslContextFactory.setEndpointIdentificationAlgorithm("");
sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks"); sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
sslContextFactory.setKeyStorePassword("storepwd"); sslContextFactory.setKeyStorePassword("storepwd");
sslContextFactory.setTrustStorePath("src/test/resources/truststore.jks");
sslContextFactory.setTrustStorePassword("storepwd");
QueuedThreadPool clientThreads = new QueuedThreadPool(); QueuedThreadPool clientThreads = new QueuedThreadPool();
clientThreads.setName("client"); clientThreads.setName("client");

View File

@ -0,0 +1,233 @@
//
// ========================================================================
// 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.client.ssl;
import java.security.cert.Certificate;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession;
import org.eclipse.jetty.client.EmptyServerHandler;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.ssl.SslHandshakeListener;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
/**
* In order to work, client authentication needs a certificate
* signed by a CA that also signed the server certificate.
* <p>
* For this test, the client certificate is signed with the server
* certificate, and the server certificate is self-signed.
*/
public class NeedWantClientAuthTest
{
private Server server;
private ServerConnector connector;
private HttpClient client;
private void startServer(SslContextFactory sslContextFactory, Handler handler) throws Exception
{
QueuedThreadPool serverThreads = new QueuedThreadPool();
serverThreads.setName("server");
server = new Server(serverThreads);
connector = new ServerConnector(server, sslContextFactory);
server.addConnector(connector);
server.setHandler(handler);
server.start();
}
private void startClient(SslContextFactory sslContextFactory) throws Exception
{
QueuedThreadPool clientThreads = new QueuedThreadPool();
clientThreads.setName("client");
client = new HttpClient(sslContextFactory);
client.setExecutor(clientThreads);
client.start();
}
private SslContextFactory createSslContextFactory()
{
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setEndpointIdentificationAlgorithm("");
sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
sslContextFactory.setKeyStorePassword("storepwd");
return sslContextFactory;
}
@After
public void dispose() throws Exception
{
if (client != null)
client.stop();
if (server != null)
server.stop();
}
@Test
public void testWantClientAuthWithoutAuth() throws Exception
{
SslContextFactory serverSSL = new SslContextFactory();
serverSSL.setKeyStorePath("src/test/resources/keystore.jks");
serverSSL.setKeyStorePassword("storepwd");
serverSSL.setWantClientAuth(true);
startServer(serverSSL, new EmptyServerHandler());
SslContextFactory clientSSL = new SslContextFactory(true);
startClient(clientSSL);
ContentResponse response = client.newRequest("https://localhost:" + connector.getLocalPort())
.timeout(5, TimeUnit.SECONDS)
.send();
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
}
@Test
public void testWantClientAuthWithAuth() throws Exception
{
SslContextFactory serverSSL = new SslContextFactory();
serverSSL.setKeyStorePath("src/test/resources/keystore.jks");
serverSSL.setKeyStorePassword("storepwd");
serverSSL.setWantClientAuth(true);
startServer(serverSSL, new EmptyServerHandler());
CountDownLatch handshakeLatch = new CountDownLatch(1);
connector.addBean(new SslHandshakeListener()
{
@Override
public void handshakeSucceeded(Event event)
{
try
{
SSLSession session = event.getSSLEngine().getSession();
Certificate[] clientCerts = session.getPeerCertificates();
Assert.assertNotNull(clientCerts);
Assert.assertThat(clientCerts.length, Matchers.greaterThan(0));
handshakeLatch.countDown();
}
catch (Throwable x)
{
x.printStackTrace();
}
}
});
SslContextFactory clientSSL = new SslContextFactory(true);
clientSSL.setKeyStorePath("src/test/resources/client_keystore.jks");
clientSSL.setKeyStorePassword("storepwd");
startClient(clientSSL);
ContentResponse response = client.newRequest("https://localhost:" + connector.getLocalPort())
.timeout(5, TimeUnit.SECONDS)
.send();
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
Assert.assertTrue(handshakeLatch.await(5, TimeUnit.SECONDS));
}
@Test
public void testNeedClientAuthWithoutAuth() throws Exception
{
SslContextFactory serverSSL = new SslContextFactory();
serverSSL.setKeyStorePath("src/test/resources/keystore.jks");
serverSSL.setKeyStorePassword("storepwd");
serverSSL.setNeedClientAuth(true);
startServer(serverSSL, new EmptyServerHandler());
SslContextFactory clientSSL = new SslContextFactory(true);
startClient(clientSSL);
CountDownLatch handshakeLatch = new CountDownLatch(1);
client.addBean(new SslHandshakeListener()
{
@Override
public void handshakeFailed(Event event, Throwable failure)
{
Assert.assertThat(failure, Matchers.instanceOf(SSLHandshakeException.class));
handshakeLatch.countDown();
}
});
CountDownLatch latch = new CountDownLatch(1);
client.newRequest("https://localhost:" + connector.getLocalPort())
.timeout(5, TimeUnit.SECONDS)
.send(result ->
{
if (result.isFailed())
latch.countDown();
});
Assert.assertTrue(handshakeLatch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
}
@Test
public void testNeedClientAuthWithAuth() throws Exception
{
SslContextFactory serverSSL = new SslContextFactory();
serverSSL.setKeyStorePath("src/test/resources/keystore.jks");
serverSSL.setKeyStorePassword("storepwd");
serverSSL.setNeedClientAuth(true);
startServer(serverSSL, new EmptyServerHandler());
CountDownLatch handshakeLatch = new CountDownLatch(1);
connector.addBean(new SslHandshakeListener()
{
@Override
public void handshakeSucceeded(Event event)
{
try
{
SSLSession session = event.getSSLEngine().getSession();
Certificate[] clientCerts = session.getPeerCertificates();
Assert.assertNotNull(clientCerts);
Assert.assertThat(clientCerts.length, Matchers.greaterThan(0));
handshakeLatch.countDown();
}
catch (Throwable x)
{
x.printStackTrace();
}
}
});
SslContextFactory clientSSL = new SslContextFactory(true);
clientSSL.setKeyStorePath("src/test/resources/client_keystore.jks");
clientSSL.setKeyStorePassword("storepwd");
startClient(clientSSL);
ContentResponse response = client.newRequest("https://localhost:" + connector.getLocalPort())
.timeout(5, TimeUnit.SECONDS)
.send();
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
Assert.assertTrue(handshakeLatch.await(5, TimeUnit.SECONDS));
}
}

Binary file not shown.

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>jetty-continuation</artifactId> <artifactId>jetty-continuation</artifactId>

View File

@ -19,7 +19,6 @@
package org.eclipse.jetty.continuation; package org.eclipse.jetty.continuation;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
import javax.servlet.Servlet;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.ServletResponseWrapper; import javax.servlet.ServletResponseWrapper;
@ -138,8 +137,10 @@ import javax.servlet.ServletResponseWrapper;
* *
* @see ContinuationSupport * @see ContinuationSupport
* @see ContinuationListener * @see ContinuationListener
* *
* @deprecated use Servlet 3.0 {@link javax.servlet.AsyncContext} instead
*/ */
@Deprecated
public interface Continuation public interface Continuation
{ {
public final static String ATTRIBUTE = "org.eclipse.jetty.continuation"; public final static String ATTRIBUTE = "org.eclipse.jetty.continuation";

View File

@ -48,7 +48,9 @@ import javax.servlet.ServletResponse;
* {@link Continuation#complete()} is called.</p> * {@link Continuation#complete()} is called.</p>
* <p>Faux continuations are not threadless continuations (they are "faux" - fake - for this reason) * <p>Faux continuations are not threadless continuations (they are "faux" - fake - for this reason)
* and as such they will scale less than proper continuations.</p> * and as such they will scale less than proper continuations.</p>
* @deprecated use Servlet 3.0 {@link javax.servlet.AsyncContext} instead
*/ */
@Deprecated
public class ContinuationFilter implements Filter public class ContinuationFilter implements Filter
{ {
static boolean _initialized; static boolean _initialized;
@ -60,6 +62,7 @@ public class ContinuationFilter implements Filter
public void init(FilterConfig filterConfig) throws ServletException public void init(FilterConfig filterConfig) throws ServletException
{ {
filterConfig.getServletContext().log("WARNING: " + this.getClass().getName() + " is now DEPRECATED, use Servlet 3.0 AsyncContext instead.");
boolean jetty_7_or_greater="org.eclipse.jetty.servlet".equals(filterConfig.getClass().getPackage().getName()); boolean jetty_7_or_greater="org.eclipse.jetty.servlet".equals(filterConfig.getClass().getPackage().getName());
_context = filterConfig.getServletContext(); _context = filterConfig.getServletContext();

View File

@ -27,7 +27,9 @@ import javax.servlet.ServletRequestListener;
* <p> * <p>
* A ContinuationListener may be registered with a call to * A ContinuationListener may be registered with a call to
* {@link Continuation#addContinuationListener(ContinuationListener)}. * {@link Continuation#addContinuationListener(ContinuationListener)}.
* @deprecated use Servlet 3.0 {@link javax.servlet.AsyncContext} instead
*/ */
@Deprecated
public interface ContinuationListener extends EventListener public interface ContinuationListener extends EventListener
{ {
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */

View File

@ -29,7 +29,9 @@ import javax.servlet.ServletResponse;
* *
* Factory class for accessing Continuation instances, which with either be * Factory class for accessing Continuation instances, which with either be
* a servlet 3.0 or a faux continuation. * a servlet 3.0 or a faux continuation.
* @deprecated use Servlet 3.0 {@link javax.servlet.AsyncContext} instead
*/ */
@Deprecated
public class ContinuationSupport public class ContinuationSupport
{ {
static final boolean __servlet3; static final boolean __servlet3;

View File

@ -41,7 +41,9 @@ package org.eclipse.jetty.continuation;
* to be uncaught (or rethrown) by a Filter/Servlet. A ContinuationThrowable * to be uncaught (or rethrown) by a Filter/Servlet. A ContinuationThrowable
* does not represent and error condition. * does not represent and error condition.
* </p> * </p>
* @deprecated use Servlet 3.0 {@link javax.servlet.AsyncContext} instead
*/ */
@Deprecated
public class ContinuationThrowable extends Error public class ContinuationThrowable extends Error
{ {
public ContinuationThrowable() public ContinuationThrowable()

View File

@ -33,7 +33,9 @@ import org.eclipse.jetty.continuation.ContinuationFilter.FilteredContinuation;
* A blocking implementation of Continuation. * A blocking implementation of Continuation.
* This implementation of Continuation is used by the {@link ContinuationFilter} * This implementation of Continuation is used by the {@link ContinuationFilter}
* when there are is no native or asynchronous continuation type available. * when there are is no native or asynchronous continuation type available.
* @deprecated use Servlet 3.0 {@link javax.servlet.AsyncContext} instead
*/ */
@Deprecated
class FauxContinuation implements FilteredContinuation class FauxContinuation implements FilteredContinuation
{ {
// common exception used for all continuations. // common exception used for all continuations.

View File

@ -36,7 +36,9 @@ import javax.servlet.ServletResponseWrapper;
* This implementation of Continuation is used by {@link ContinuationSupport} * This implementation of Continuation is used by {@link ContinuationSupport}
* when it detects that the application has been deployed in a Servlet 3 * when it detects that the application has been deployed in a Servlet 3
* server. * server.
* @deprecated use Servlet 3.0 {@link javax.servlet.AsyncContext} instead
*/ */
@Deprecated
public class Servlet3Continuation implements Continuation, AsyncListener public class Servlet3Continuation implements Continuation, AsyncListener
{ {
// Exception reused for all continuations // Exception reused for all continuations

View File

@ -17,7 +17,8 @@
// //
/** /**
* Jetty Continuation : Generic Async Servlet Method * Jetty Continuation : <em>DEPRECATED: use Servlet 3.0 {@link javax.servlet.AsyncContext} instead</em>
*/ */
@Deprecated
package org.eclipse.jetty.continuation; package org.eclipse.jetty.continuation;

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>jetty-deploy</artifactId> <artifactId>jetty-deploy</artifactId>

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>jetty-distribution</artifactId> <artifactId>jetty-distribution</artifactId>

View File

@ -14,6 +14,36 @@
<excludes> <excludes>
<exclude>**/META-INF/**</exclude> <exclude>**/META-INF/**</exclude>
<exclude>*-config.jar</exclude> <exclude>*-config.jar</exclude>
<!-- common OS detritus -->
<exclude>**/.DS_Store</exclude>
<exclude>**/Thumbs.db</exclude>
<exclude>**/desktop.ini</exclude>
<!-- common temp files -->
<exclude>**/*~</exclude>
<exclude>**/*.bak</exclude>
<exclude>**/*.backup</exclude>
<exclude>**/*.old</exclude>
<exclude>**/*.swp</exclude>
<exclude>**/*.debug</exclude>
<exclude>**/*.dump</exclude>
<exclude>**/*.log</exclude>
<exclude>**/~*</exclude>
<!-- common git/scm files -->
<exclude>**/*.orig</exclude>
<exclude>**/*.diff</exclude>
<exclude>**/*.patch</exclude>
<exclude>**/.gitignore</exclude>
<!-- various editor files -->
<exclude>**/*.iml</exclude>
<exclude>**/*.ipr</exclude>
<exclude>**/*.iws</exclude>
<exclude>**/*.idea</exclude>
<exclude>**/.classpath</exclude>
<exclude>**/.project</exclude>
<exclude>**/.settings</exclude>
<!-- maven dust -->
<exclude>**/*.versionsBackup</exclude>
<exclude>**/*.releaseBackup</exclude>
</excludes> </excludes>
</fileSet> </fileSet>
</fileSets> </fileSets>

View File

@ -12,6 +12,36 @@
</includes> </includes>
<excludes> <excludes>
<exclude>**/target/**</exclude> <exclude>**/target/**</exclude>
<!-- common OS detritus -->
<exclude>**/.DS_Store</exclude>
<exclude>**/Thumbs.db</exclude>
<exclude>**/desktop.ini</exclude>
<!-- common temp files -->
<exclude>**/*~</exclude>
<exclude>**/*.bak</exclude>
<exclude>**/*.backup</exclude>
<exclude>**/*.old</exclude>
<exclude>**/*.swp</exclude>
<exclude>**/*.debug</exclude>
<exclude>**/*.dump</exclude>
<exclude>**/*.log</exclude>
<exclude>**/~*</exclude>
<!-- common git/scm files -->
<exclude>**/*.orig</exclude>
<exclude>**/*.diff</exclude>
<exclude>**/*.patch</exclude>
<exclude>**/.gitignore</exclude>
<!-- various editor files -->
<exclude>**/*.iml</exclude>
<exclude>**/*.ipr</exclude>
<exclude>**/*.iws</exclude>
<exclude>**/*.idea</exclude>
<exclude>**/.classpath</exclude>
<exclude>**/.project</exclude>
<exclude>**/.settings</exclude>
<!-- maven dust -->
<exclude>**/*.versionsBackup</exclude>
<exclude>**/*.releaseBackup</exclude>
</excludes> </excludes>
</fileSet> </fileSet>
</fileSets> </fileSets>

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<artifactId>jetty-documentation</artifactId> <artifactId>jetty-documentation</artifactId>
<name>Jetty :: Documentation</name> <name>Jetty :: Documentation</name>
@ -58,7 +58,7 @@
<allow-uri-read>true</allow-uri-read> <allow-uri-read>true</allow-uri-read>
<toc>true</toc> <toc>true</toc>
<revnumber>${project.version}</revnumber> <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> <JXURL>http://download.eclipse.org/jetty/stable-9/xref</JXURL>
<SRCDIR>${basedir}/..</SRCDIR> <SRCDIR>${basedir}/..</SRCDIR>
<GITBROWSEURL>https://github.com/eclipse/jetty.project/tree/jetty-9.4.x</GITBROWSEURL> <GITBROWSEURL>https://github.com/eclipse/jetty.project/tree/jetty-9.4.x</GITBROWSEURL>

View File

@ -34,9 +34,9 @@ Jetty currently has two levels of request statistic collection:
* Subclasses of `AbstractConnector` class optionally can collect statistics about connections as well as number of requests. * 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. * 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. The `StatisticsHandler` is not included in default Jetty configuration, and needs to be configured manually.
_____ _____

View File

@ -19,7 +19,7 @@
This chapter discusses various options for configuring logging. 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::default-logging-with-stderrlog.adoc[]
include::configuring-jetty-request-logs.adoc[] include::configuring-jetty-request-logs.adoc[]
include::configuring-logging-modules.adoc[] include::configuring-logging-modules.adoc[]

View File

@ -58,6 +58,12 @@ INFO: Base directory was modified
The above command will add a new `requestlog.ini` file to your link:#start-vs-startd[`{$jetty.base}/start.d` directory]. The above command will add a new `requestlog.ini` file to your link:#start-vs-startd[`{$jetty.base}/start.d` directory].
____
[NOTE]
By default, request logs are not set to be appended, meaning a the log file is wiped clean upon sever restart.
You can change this setting by editing the `requestlog.ini` and un-commenting the line that reads `jetty.requestlog.append=true`.
____
The equivalent code for embedded usages of Jetty is: The equivalent code for embedded usages of Jetty is:
[source, java, subs="{sub-order}"] [source, java, subs="{sub-order}"]

View File

@ -45,6 +45,13 @@ INFO : Base directory was modified
The default configuration for logging output will create a file `${jetty.base}/logs/yyyy_mm_dd.stderrout.log` which allows configuration of the output directory by setting the `jetty.logs` property. The default configuration for logging output will create a file `${jetty.base}/logs/yyyy_mm_dd.stderrout.log` which allows configuration of the output directory by setting the `jetty.logs` property.
____
[NOTE]
By default, logs are not set to be appended, meaning a the log file is wiped clean upon sever restart.
You can change this setting by editing the `console-capture.ini` and un-commenting the line that reads `jetty.console-capture.append=true`.
____
Just enabling the `console-capture` will simply output the values of STDERR and STDOUT to a log file. Just enabling the `console-capture` will simply output the values of STDERR and STDOUT to a log file.
To customize the log further, a module named `logging-jetty` is available to provides a default properties file to configure. To customize the log further, a module named `logging-jetty` is available to provides a default properties file to configure.
As with `console-capture`, you activate the `logging-jetty` on the command line. As with `console-capture`, you activate the `logging-jetty` on the command line.

View File

@ -51,7 +51,7 @@ INFO: resources enabled in ${jetty.base}/start.ini
The replacement `logging.mod` performs a number of tasks. The replacement `logging.mod` performs a number of tasks.
. `mybase` is a `${jetty.base}` directory . `mybase` is a `${jetty.base}` directory
. The jetty-distribution is unpacked (and untouched) into `/opt/jetty-dist/ `and becomes the `${jetty.home}` directory for this demonstration. . The jetty-distribution is unpacked (and untouched) into `/opt/jetty-dist/` and becomes the `${jetty.home}` directory for this demonstration.
. The `curl` command downloads the replacement `logging.mod` and puts it into the `${jetty.base}/modules/` directory for use by `mybase` only. . The `curl` command downloads the replacement `logging.mod` and puts it into the `${jetty.base}/modules/` directory for use by `mybase` only.
. The `start.jar --add-to-start=logging` command performs a number of steps to make the logging module available to the `${jetty.base}` configuration. . The `start.jar --add-to-start=logging` command performs a number of steps to make the logging module available to the `${jetty.base}` configuration.
.. The `--module=logging` command is added to the `${jetty.base}/start.ini` configuration. .. The `--module=logging` command is added to the `${jetty.base}/start.ini` configuration.

View File

@ -81,7 +81,7 @@ INFO: resources enabled in ${jetty.base}/start.ini
The replacement `logging.mod` performs a number of tasks. The replacement `logging.mod` performs a number of tasks.
. `mybase` is a `${jetty.base}` directory. . `mybase` is a `${jetty.base}` directory.
. The jetty-distribution is unpacked (and untouched) into `/opt/jetty-dist/ `and becomes the `${jetty.home}` directory for this demonstration. . The jetty-distribution is unpacked (and untouched) into `/opt/jetty-dist/` and becomes the `${jetty.home}` directory for this demonstration.
. The `curl` command downloads the replacement `logging.mod` and puts it into the `${jetty.base}/modules/` directory for use by mybase only. . The `curl` command downloads the replacement `logging.mod` and puts it into the `${jetty.base}/modules/` directory for use by mybase only.
. The `start.jar --add-to-start=logging,webapp-logging` command performs a number of steps to make the logging module available to the `${jetty.base}` configuration. . The `start.jar --add-to-start=logging,webapp-logging` command performs a number of steps to make the logging module available to the `${jetty.base}` configuration.
.. Several entries are added to the `${jetty.base}/start.ini` configuration. .. Several entries are added to the `${jetty.base}/start.ini` configuration.

View File

@ -47,7 +47,7 @@ DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master
The replacement `logging.mod` performs a number of tasks. The replacement `logging.mod` performs a number of tasks.
. `mybase` is a `${jetty.base}` directory. . `mybase` is a `${jetty.base}` directory.
. The jetty-distribution is unpacked (and untouched) into `/opt/jetty-dist/ `and becomes the `${jetty.home}` directory for this demonstration. . The jetty-distribution is unpacked (and untouched) into `/opt/jetty-dist/` and becomes the `${jetty.home}` directory for this demonstration.
. The `curl` command downloads the replacement `logging.mod` and puts it into the `${jetty.base}/modules/` directory for use by `mybase` only. . The `curl` command downloads the replacement `logging.mod` and puts it into the `${jetty.base}/modules/` directory for use by `mybase` only.
. The `start.jar --add-to-start=logging` command performs a number of steps to make the logging module available to the `${jetty.base}` configuration. . The `start.jar --add-to-start=logging` command performs a number of steps to make the logging module available to the `${jetty.base}` configuration.
.. The `--module=logging` command is added to the `${jetty.base}/start.ini` configuration. .. The `--module=logging` command is added to the `${jetty.base}/start.ini` configuration.

View File

@ -70,7 +70,7 @@ Logging API::
Slf4j Binding JAR:: Slf4j Binding JAR::
* Special JARs, created and maintained by the Slf4j project, that pretend to be the various Logging API implementation classes, but instead just route that Logging API's events to Slf4j to handle. * Special JARs, created and maintained by the Slf4j project, that pretend to be the various Logging API implementation classes, but instead just route that Logging API's events to Slf4j to handle.
* There MAY be multiple Slf4j binding JARs present on the classpath at the same time. * There MAY be multiple Slf4j binding JARs present on the classpath at the same time.
* For a single logging API, if you choose to use the Slf4j binding JAR, then you MUST NOT include the SLf4j adapter JAR or underlying logging framework in the classpath as well. * For a single logging API, if you choose to use the Slf4j binding JAR, then you MUST NOT include the SLf4j adapter JAR or underlying logging framework in the classpath as well.
Slf4j Adapter Jar:: Slf4j Adapter Jar::
* These JARs are created and maintained by the Slf4j project and route Slf4j logging events to a specific underlying logging framework. * These JARs are created and maintained by the Slf4j project and route Slf4j logging events to a specific underlying logging framework.
@ -118,7 +118,7 @@ INFO: resources enabled in ${jetty.base}/start.ini
The replacement `logging.mod` performs a number of tasks. The replacement `logging.mod` performs a number of tasks.
. `mybase` is a `${jetty.base}` directory. . `mybase` is a `${jetty.base}` directory.
. The jetty-distribution is unpacked (and untouched) into `/opt/jetty-dist/ `and becomes the `${jetty.home}` directory for this demonstration. . The jetty-distribution is unpacked (and untouched) into `/opt/jetty-dist/` and becomes the `${jetty.home}` directory for this demonstration.
. The `curl` command downloads the replacement `logging.mod` and puts it into the `${jetty.base}/modules/` directory for use by `mybase` only. . The `curl` command downloads the replacement `logging.mod` and puts it into the `${jetty.base}/modules/` directory for use by `mybase` only.
. The `start.jar --add-to-start=logging` command performs a number of steps to make the logging module available to the `${jetty.base}` configuration. . The `start.jar --add-to-start=logging` command performs a number of steps to make the logging module available to the `${jetty.base}` configuration.
.. The `--module=logging` command is added to the `${jetty.base}/start.ini` configuration. .. The `--module=logging` command is added to the `${jetty.base}/start.ini` configuration.

View File

@ -52,7 +52,7 @@ META-INF/web-fragment.xml
===== Anatomy of a Configuration Class ===== 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:: preConfigure::
As the `WebAppContext` is starting up this phase is executed. As the `WebAppContext` is starting up this phase is executed.

View File

@ -27,9 +27,9 @@ Authorization::
==== Configuring an Authentication mechanism ==== Configuring an Authentication mechanism
The jetty server supports several standard authentication mechanisms: http://en.wikipedia.org/wiki/Basic_access_authentication[BASIC]; http://en.wikipedia.org/wiki/Digest_authentication[DIGEST]; http://en.wikipedia.org/wiki/Form-based_authentication[FORM]; CLIENT-CERT; and other mechanisms can be plugged in using the extensible http://docs.oracle.com/cd/E19462-01/819-6717/gcszc/index.html[JASPI] or http://en.wikipedia.org/wiki/SPNEGO[SPNEGO] mechanisms. Jetty server supports several standard authentication mechanisms: http://en.wikipedia.org/wiki/Basic_access_authentication[BASIC]; http://en.wikipedia.org/wiki/Digest_authentication[DIGEST]; http://en.wikipedia.org/wiki/Form-based_authentication[FORM]; CLIENT-CERT; and other mechanisms can be plugged in using the extensible http://docs.oracle.com/cd/E19462-01/819-6717/gcszc/index.html[JASPI] or http://en.wikipedia.org/wiki/SPNEGO[SPNEGO] mechanisms.
Internally, configuring an authentication mechanism is done by setting an instance of a the link:{JDURL}/org/eclipse/jetty/security/Authenticator.html[Authenticator] interface onto the link:{JDURL}/org/eclipse/jetty/security/SecurityHandler.html[SecurityHandler] of the context, but in most cases it is done by declaring a `< login-config>` element in the standard web.xml descriptor or via annotations. Internally, configuring an authentication mechanism is done by setting an instance of a the link:{JDURL}/org/eclipse/jetty/security/Authenticator.html[Authenticator] interface onto the link:{JDURL}/org/eclipse/jetty/security/SecurityHandler.html[SecurityHandler] of the context, but in most cases it is done by declaring a `<login-config>` element in the standard web.xml descriptor or via annotations.
Below is an example taken from the link:{GITBROWSEURL}/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml?h=release-9[jetty-test-webapp web.xml] that configures BASIC authentication: Below is an example taken from the link:{GITBROWSEURL}/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml?h=release-9[jetty-test-webapp web.xml] that configures BASIC authentication:
@ -103,7 +103,7 @@ When a request is received for a protected resource, the web container checks if
The Servlet Specification does not address how the static security information in the `WEB-INF/web.xml` file is mapped to the runtime environment of the container. The Servlet Specification does not address how the static security information in the `WEB-INF/web.xml` file is mapped to the runtime environment of the container.
For Jetty, the link:{JDURL}/org/eclipse/jetty/security/LoginService.html[LoginService] performs this function. For Jetty, the link:{JDURL}/org/eclipse/jetty/security/LoginService.html[LoginService] performs this function.
A LoginService has a unique name, and gives access to information about a set of users. A `LoginService` has a unique name, and gives access to information about a set of users.
Each user has authentication information (e.g. a password) and a set of roles associated with him/herself. Each user has authentication information (e.g. a password) and a set of roles associated with him/herself.
You may configure one or many different LoginServices depending on your needs. You may configure one or many different LoginServices depending on your needs.
@ -114,7 +114,8 @@ When a request to a web application requires authentication or authorization, Je
==== Scoping Security Realms ==== Scoping Security Realms
A LoginService has a unique name, and is composed of a set of users. Each user has authentication information (for example, a password) and a set of roles associated with him/herself. A `LoginService` has a unique name, and is composed of a set of users.
Each user has authentication information (for example, a password) and a set of roles associated with him/herself.
You can configure one or many different realms depending on your needs. You can configure one or many different realms depending on your needs.
* Configure a single LoginService to share common security information across all of your web applications. * Configure a single LoginService to share common security information across all of your web applications.
@ -144,8 +145,8 @@ Here's an example of an xml file that defines an in-memory type of LoginService
---- ----
If you define more than one LoginService on a Server, you will need to specify which one you want used for each context. If you define more than one `LoginService` on a Server, you will need to specify which one you want used for each context.
You can do that by telling the context the name of the LoginService, or passing it the LoginService instance. You can do that by telling the context the name of the `LoginService`, or passing it the `LoginService` instance.
Here's an example of doing both of these, using a link:#deployable-descriptor-file[context xml file]: Here's an example of doing both of these, using a link:#deployable-descriptor-file[context xml file]:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
@ -170,7 +171,7 @@ Here's an example of doing both of these, using a link:#deployable-descriptor-fi
===== Per-Webapp Scoped ===== Per-Webapp Scoped
Alternatively, you can define a LoginService for just a single web application. Alternatively, you can define a `LoginService` for just a single web application.
Here's how to define the same HashLoginService, but inside a link:#deployable-descriptor-file[context xml file]: Here's how to define the same HashLoginService, but inside a link:#deployable-descriptor-file[context xml file]:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
@ -192,12 +193,12 @@ Here's how to define the same HashLoginService, but inside a link:#deployable-de
---- ----
Jetty provides a number of different LoginService types which can be seen in the next section. Jetty provides a number of different `LoginService` types which can be seen in the next section.
[[configuring-login-service]] [[configuring-login-service]]
==== Configuring a LoginService ==== Configuring a LoginService
A link:{JDURL}/org/eclipse/jetty/security/LoginService.html[LoginService] instance is required by each context/webapp that has a authentication mechanism, which is used to check the validity of the username and credentials collected by the authentication mechanism. Jetty provides the following implementations of LoginService: A link:{JDURL}/org/eclipse/jetty/security/LoginService.html[`LoginService`] instance is required by each context/webapp that has a authentication mechanism, which is used to check the validity of the username and credentials collected by the authentication mechanism. Jetty provides the following implementations of `LoginService`:
link:{JDURL}/org/eclipse/jetty/security/HashLoginService.html[HashLoginService]:: link:{JDURL}/org/eclipse/jetty/security/HashLoginService.html[HashLoginService]::
A user realm that is backed by a hash map that is filled either programatically or from a Java properties file. A user realm that is backed by a hash map that is filled either programatically or from a Java properties file.
@ -211,16 +212,16 @@ link:{JDURL}/org/eclipse/jetty/jaas/JAASLoginService.html[JAASLoginService]::
link:{JDURL}/org/eclipse/jetty/security/SpnegoLoginService.html[SpnegoLoginService]:: link:{JDURL}/org/eclipse/jetty/security/SpnegoLoginService.html[SpnegoLoginService]::
http://en.wikipedia.org/wiki/SPNEGO[SPNEGO] Authentication; see the section on link:#spnego-support[SPNEGO support] for more information. http://en.wikipedia.org/wiki/SPNEGO[SPNEGO] Authentication; see the section on link:#spnego-support[SPNEGO support] for more information.
An instance of a LoginService can be matched to a context/webapp by: An instance of a `LoginService` can be matched to a context/webapp by:
* A LoginService instance may be set directly on the SecurityHandler instance via embedded code or IoC XML * A `LoginService` instance may be set directly on the `SecurityHandler` instance via embedded code or IoC XML
* Matching the realm-name defined in web.xml with the name of a LoginService instance that has been added to the Server instance as a dependent bean * Matching the realm-name defined in web.xml with the name of a `LoginService` instance that has been added to the Server instance as a dependent bean
* If only a single LoginService instance has been set on the Server then it is used as the login service for the context * If only a single `LoginService` instance has been set on the Server then it is used as the login service for the context
[[hash-login-service]] [[hash-login-service]]
===== HashLoginService ===== HashLoginService
The HashLoginService is a simple and efficient login service that loads usernames, credentials and roles from a Java properties file in the format: The `HashLoginService` is a simple and efficient login service that loads usernames, credentials and roles from a Java properties file in the format:
[source,properties] [source,properties]
---- ----
@ -249,7 +250,7 @@ guest: guest,read-only
---- ----
You configure the HashLoginService with a name and a reference to the location of the properties file: You configure the `HashLoginService` with a name and a reference to the location of the properties file:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -378,12 +379,12 @@ When a user requests a resource that is access protected, the LoginService will
Until Servlet 3.1, role-based authorization could define: Until Servlet 3.1, role-based authorization could define:
* access granted to a set of named roles * Access granted to a set of named roles
* access totally forbidden, regardless of role * Access totally forbidden, regardless of role
* access granted to a user in any of the roles defined in the effective web.xml. * Access granted to a user in any of the roles defined in the effective web.xml.
This is indicated by the special value of "*" for the `<role-name>` of a `<auth-constraint> `in the `<security-constraint>` This is indicated by the special value of `*` for the `<role-name>` of a `<auth-constraint>` in the `<security-constraint>`
With the advent of Servlet 3.1, there is now another authorization: With the advent of Servlet 3.1, there is now another authorization:
* access granted to any user who is authenticated, regardless of roles. * Access granted to any user who is authenticated, regardless of roles.
This is indicated by the special value of "**" for the `<role-name>` of a `<auth-constraint>` in the `<security-constraint>` This is indicated by the special value of `**` for the `<role-name>` of a `<auth-constraint>` in the `<security-constraint>`

View File

@ -226,10 +226,10 @@ As `LoginModules` are free to use their own implementation of the JAAS Principal
===== Sample LoginModules ===== Sample LoginModules
* link:{JXURL}/org/eclipse/jetty/jaas/spi/JDBCLoginModule.html[`org.eclipse.jetty.jaas.spi.JDBCLoginModule`] * link:{JDURL}/org/eclipse/jetty/jaas/spi/JDBCLoginModule.html[`org.eclipse.jetty.jaas.spi.JDBCLoginModule`]
* link:{JXURL}/org/eclipse/jetty/jaas/spi/PropertyFileLoginModule.html[`org.eclipse.jetty.jaas.spi.PropertyFileLoginModule`] * link:{JDURL}/org/eclipse/jetty/jaas/spi/PropertyFileLoginModule.html[`org.eclipse.jetty.jaas.spi.PropertyFileLoginModule`]
* link:{JXURL}/org/eclipse/jetty/jaas/spi/DataSourceLoginModule.html[`org.eclipse.jetty.jaas.spi.DataSourceLoginModule`] * link:{JDURL}/org/eclipse/jetty/jaas/spi/DataSourceLoginModule.html[`org.eclipse.jetty.jaas.spi.DataSourceLoginModule`]
* link:{JXURL}/org/eclipse/jetty/jaas/spi/LdapLoginModule.html[`org.eclipse.jetty.jaas.ldap.LdapLoginModule`] * link:{JDURL}/org/eclipse/jetty/jaas/spi/LdapLoginModule.html[`org.eclipse.jetty.jaas.ldap.LdapLoginModule`]
____ ____
[NOTE] [NOTE]

View File

@ -30,6 +30,12 @@ When you download and unpack the binary, it is extracted into a directory called
Put this directory in a convenient location. Put this directory in a convenient location.
The rest of the instructions in this documentation refer to this location as either `JETTY_HOME` or as `$(jetty.home).` The rest of the instructions in this documentation refer to this location as either `JETTY_HOME` or as `$(jetty.home).`
_____
[IMPORTANT]
It is important that only stable releases are used in production environments.
Versions that have been deprecated or are released as Milestones (M) or Release Candidates (RC) are not suitable for production as they may contain security flaws or incomplete/non-functioning feature sets.
_____
[[distribution-content]] [[distribution-content]]
==== Distribution Content ==== Distribution Content

View File

@ -17,6 +17,12 @@
[[quickstart-jetty-coordinates]] [[quickstart-jetty-coordinates]]
=== Finding Jetty in Maven === Finding Jetty in Maven
_____
[IMPORTANT]
It is important that only stable releases are used in production environments.
Versions that have been deprecated or are released as Milestones (M) or Release Candidates (RC) are not suitable for production as they may contain security flaws or incomplete/non-functioning feature sets.
_____
==== Maven Coordinates ==== Maven Coordinates
Jetty has existed in Maven Central almost since its inception, though the coordinates have changed over the years. Jetty has existed in Maven Central almost since its inception, though the coordinates have changed over the years.
@ -34,7 +40,7 @@ The top level Project Object Model (POM) for the Jetty project is located under
</dependency> </dependency>
---- ----
==== Changelogs in Central ==== Changelogs in Maven Central
The changes between versions of Jetty are tracked in a file called VERSIONS.txt, which is under source control and is generated on release. The changes between versions of Jetty are tracked in a file called VERSIONS.txt, which is under source control and is generated on release.
Those generated files are also uploaded into Maven Central during the release of the top level POM. You can find them as a classifier marked artifact. Those generated files are also uploaded into Maven Central during the release of the top level POM. You can find them as a classifier marked artifact.

View File

@ -21,6 +21,12 @@ Jetty 9 is the most recent version of Jetty and has a great many improvements ov
This documentation which focuses on Jetty 9. This documentation which focuses on Jetty 9.
While many people continue to use older versions of Jetty, we generally recommend using Jetty 9 as it represents the version of Jetty that we will actively maintain and improve over the next few years. While many people continue to use older versions of Jetty, we generally recommend using Jetty 9 as it represents the version of Jetty that we will actively maintain and improve over the next few years.
_____
[IMPORTANT]
It is important that only stable releases are used in production environments.
Versions that have been deprecated or are released as Milestones (M) or Release Candidates (RC) are not suitable for production as they may contain security flaws or incomplete/non-functioning feature sets.
_____
.Jetty Versions .Jetty Versions
[width="100%",cols="12%,9%,15%,6%,21%,10%,6%,21%",options="header",] [width="100%",cols="12%,9%,15%,6%,21%,10%,6%,21%",options="header",]
|======================================================================= |=======================================================================

View File

@ -3,7 +3,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty.fcgi</groupId> <groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>fcgi-parent</artifactId> <artifactId>fcgi-parent</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -125,4 +125,10 @@ public class HttpSenderOverFCGI extends HttpSender
getHttpChannel().flush(result); getHttpChannel().flush(result);
} }
} }
@Override
protected void sendTrailers(HttpExchange exchange, Callback callback)
{
callback.succeeded();
}
} }

View File

@ -3,7 +3,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty.fcgi</groupId> <groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>fcgi-parent</artifactId> <artifactId>fcgi-parent</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -3,7 +3,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -3,7 +3,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty.gcloud</groupId> <groupId>org.eclipse.jetty.gcloud</groupId>
<artifactId>gcloud-parent</artifactId> <artifactId>gcloud-parent</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -11,6 +11,7 @@
<Arg> <Arg>
<New id="sessionDataStoreFactory" class="org.eclipse.jetty.gcloud.session.GCloudSessionDataStoreFactory"> <New id="sessionDataStoreFactory" class="org.eclipse.jetty.gcloud.session.GCloudSessionDataStoreFactory">
<Set name="gracePeriodSec"><Property name="jetty.session.gracePeriod.seconds" default="3600" /></Set> <Set name="gracePeriodSec"><Property name="jetty.session.gracePeriod.seconds" default="3600" /></Set>
<Set name="savePeriodSec"><Property name="jetty.session.savePeriod.seconds" default="0" /></Set>
<Set name="maxRetries"><Property name="jetty.session.gcloud.maxRetries" default="5"/></Set> <Set name="maxRetries"><Property name="jetty.session.gcloud.maxRetries" default="5"/></Set>
<Set name="backoffMs"><Property name="jetty.session.gcloud.backoffMs" default="1000"/></Set> <Set name="backoffMs"><Property name="jetty.session.gcloud.backoffMs" default="1000"/></Set>
<Set name="namespace"><Property name="jetty.session.gcloud.namespace" default=""/></Set> <Set name="namespace"><Property name="jetty.session.gcloud.namespace" default=""/></Set>

View File

@ -26,6 +26,8 @@ etc/sessions/gcloud/session-store.xml
[ini-template] [ini-template]
## GCloudDatastore Session config ## GCloudDatastore Session config
#jetty.session.gracePeriod.seconds=3600
#jetty.session.savePeriod.seconds=0
#jetty.session.gcloud.maxRetries=5 #jetty.session.gcloud.maxRetries=5
#jetty.session.gcloud.backoffMs=1000 #jetty.session.gcloud.backoffMs=1000
#jetty.session.gcloud.namespace= #jetty.session.gcloud.namespace=

View File

@ -33,6 +33,8 @@ import org.eclipse.jetty.server.session.UnreadableSessionDataException;
import org.eclipse.jetty.server.session.UnwriteableSessionDataException; import org.eclipse.jetty.server.session.UnwriteableSessionDataException;
import org.eclipse.jetty.util.ClassLoadingObjectInputStream; import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
@ -55,6 +57,7 @@ import com.google.cloud.datastore.StructuredQuery.PropertyFilter;
* *
* *
*/ */
@ManagedObject
public class GCloudSessionDataStore extends AbstractSessionDataStore public class GCloudSessionDataStore extends AbstractSessionDataStore
{ {
private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session"); private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
@ -98,6 +101,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
public static final String EXPIRY = "expiry"; public static final String EXPIRY = "expiry";
public static final String MAXINACTIVE = "maxInactive"; public static final String MAXINACTIVE = "maxInactive";
public static final String ATTRIBUTES = "attributes"; public static final String ATTRIBUTES = "attributes";
public static final String LASTSAVED = "lastSaved";
public static final String KIND = "GCloudSession"; public static final String KIND = "GCloudSession";
protected String _kind = KIND; protected String _kind = KIND;
@ -107,6 +111,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
protected String _accessed = ACCESSED; protected String _accessed = ACCESSED;
protected String _lastAccessed = LASTACCESSED; protected String _lastAccessed = LASTACCESSED;
protected String _lastNode = LASTNODE; protected String _lastNode = LASTNODE;
protected String _lastSaved = LASTSAVED;
protected String _createTime = CREATETIME; protected String _createTime = CREATETIME;
protected String _cookieSetTime = COOKIESETTIME; protected String _cookieSetTime = COOKIESETTIME;
protected String _expiry = EXPIRY; protected String _expiry = EXPIRY;
@ -302,6 +307,23 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
_attributes = attributes; _attributes = attributes;
} }
/**
* @return the lastSaved
*/
public String getLastSaved()
{
return _lastSaved;
}
/**
* @param lastSaved the lastSaved to set
*/
public void setLastSaved(String lastSaved)
{
checkNotNull(lastSaved);
_lastSaved = lastSaved;
}
/** /**
* @see java.lang.Object#toString() * @see java.lang.Object#toString()
*/ */
@ -391,11 +413,13 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
_namespace = namespace; _namespace = namespace;
} }
@ManagedAttribute(value="gclound namespace", readonly=true)
public String getNamespace () public String getNamespace ()
{ {
return _namespace; return _namespace;
} }
@ManagedAttribute(value="unit in ms of exponential backoff")
public int getBackoffMs () public int getBackoffMs ()
{ {
return _backoff; return _backoff;
@ -407,7 +431,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
_maxRetries = retries; _maxRetries = retries;
} }
@ManagedAttribute(value="max number of retries for failed writes")
public int getMaxRetries () public int getMaxRetries ()
{ {
return _maxRetries; return _maxRetries;
@ -461,6 +485,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
_dsProvided = true; _dsProvided = true;
} }
@ManagedAttribute(value="max number of results to return from gcloud searches")
public int getMaxResults() public int getMaxResults()
{ {
return _maxResults; return _maxResults;
@ -529,11 +554,15 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
for (ExpiryInfo item:info) for (ExpiryInfo item:info)
{ {
if (StringUtil.isBlank(item.getLastNode())) if (StringUtil.isBlank(item.getLastNode()))
{
expired.add(item.getId()); //nobody managing it expired.add(item.getId()); //nobody managing it
}
else else
{ {
if (_context.getWorkerName().equals(item.getLastNode())) if (_context.getWorkerName().equals(item.getLastNode()))
{
expired.add(item.getId()); //we're managing it, we can expire it expired.add(item.getId()); //we're managing it, we can expire it
}
else else
{ {
if (_lastExpiryCheckTime <= 0) if (_lastExpiryCheckTime <= 0)
@ -541,8 +570,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
//our first check, just look for sessions that we managed by another node that //our first check, just look for sessions that we managed by another node that
//expired at least 3 graceperiods ago //expired at least 3 graceperiods ago
if (item.getExpiry() < (now - (1000L * (3 * _gracePeriodSec)))) if (item.getExpiry() < (now - (1000L * (3 * _gracePeriodSec))))
expired.add(item.getId()); expired.add(item.getId()); }
}
else else
{ {
//another node was last managing it, only expire it if it expired a graceperiod ago //another node was last managing it, only expire it if it expired a graceperiod ago
@ -636,11 +664,12 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
*/ */
protected Set<ExpiryInfo> queryExpiryByIndex () throws Exception protected Set<ExpiryInfo> queryExpiryByIndex () throws Exception
{ {
long now = System.currentTimeMillis();
Set<ExpiryInfo> info = new HashSet<>(); Set<ExpiryInfo> info = new HashSet<>();
Query<ProjectionEntity> query = Query.newProjectionEntityQueryBuilder() Query<ProjectionEntity> query = Query.newProjectionEntityQueryBuilder()
.setKind(_model.getKind()) .setKind(_model.getKind())
.setProjection(_model.getId(), _model.getLastNode(), _model.getExpiry()) .setProjection(_model.getId(), _model.getLastNode(), _model.getExpiry())
.setFilter(CompositeFilter.and(PropertyFilter.gt(_model.getExpiry(), 0), PropertyFilter.le(_model.getExpiry(), System.currentTimeMillis()))) .setFilter(CompositeFilter.and(PropertyFilter.gt(_model.getExpiry(), 0), PropertyFilter.le(_model.getExpiry(), now)))
.setLimit(_maxResults) .setLimit(_maxResults)
.build(); .build();
@ -746,7 +775,6 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
public void doStore(String id, SessionData data, long lastSaveTime) throws Exception public void doStore(String id, SessionData data, long lastSaveTime) throws Exception
{ {
if (LOG.isDebugEnabled()) LOG.debug("Writing session {} to DataStore", data.getId()); if (LOG.isDebugEnabled()) LOG.debug("Writing session {} to DataStore", data.getId());
Entity entity = entityFromSession(data, makeKey(id, _context)); Entity entity = entityFromSession(data, makeKey(id, _context));
//attempt the update with exponential back-off //attempt the update with exponential back-off
@ -868,6 +896,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
.set(_model.getLastNode(),session.getLastNode()) .set(_model.getLastNode(),session.getLastNode())
.set(_model.getExpiry(), session.getExpiry()) .set(_model.getExpiry(), session.getExpiry())
.set(_model.getMaxInactive(), session.getMaxInactiveMs()) .set(_model.getMaxInactive(), session.getMaxInactiveMs())
.set(_model.getLastSaved(), session.getLastSaved())
.set(_model.getAttributes(), BlobValue.newBuilder(Blob.copyFrom(baos.toByteArray())).setExcludeFromIndexes(true).build()).build(); .set(_model.getAttributes(), BlobValue.newBuilder(Blob.copyFrom(baos.toByteArray())).setExcludeFromIndexes(true).build()).build();
@ -902,6 +931,17 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
long createTime = entity.getLong(_model.getCreateTime()); long createTime = entity.getLong(_model.getCreateTime());
long cookieSet = entity.getLong(_model.getCookieSetTime()); long cookieSet = entity.getLong(_model.getCookieSetTime());
String lastNode = entity.getString(_model.getLastNode()); String lastNode = entity.getString(_model.getLastNode());
long lastSaved = 0;
//for compatibility with previously saved sessions, lastSaved may not be present
try
{
lastSaved = entity.getLong(_model.getLastSaved());
}
catch (DatastoreException e)
{
LOG.ignore(e);
}
long expiry = entity.getLong(_model.getExpiry()); long expiry = entity.getLong(_model.getExpiry());
long maxInactive = entity.getLong(_model.getMaxInactive()); long maxInactive = entity.getLong(_model.getMaxInactive());
Blob blob = (Blob) entity.getBlob(_model.getAttributes()); Blob blob = (Blob) entity.getBlob(_model.getAttributes());
@ -912,6 +952,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
session.setVhost(vhost); session.setVhost(vhost);
session.setCookieSet(cookieSet); session.setCookieSet(cookieSet);
session.setLastNode(lastNode); session.setLastNode(lastNode);
session.setLastSaved(lastSaved);
session.setExpiry(expiry); session.setExpiry(expiry);
try (ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(blob.asInputStream())) try (ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(blob.asInputStream()))
{ {
@ -943,6 +984,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
/** /**
* @see org.eclipse.jetty.server.session.SessionDataStore#isPassivating() * @see org.eclipse.jetty.server.session.SessionDataStore#isPassivating()
*/ */
@ManagedAttribute(value="does gcloud serialize session data", readonly=true)
@Override @Override
public boolean isPassivating() public boolean isPassivating()
{ {

View File

@ -94,6 +94,7 @@ public class GCloudSessionDataStoreFactory extends AbstractSessionDataStoreFacto
ds.setMaxRetries(getMaxRetries()); ds.setMaxRetries(getMaxRetries());
ds.setGracePeriodSec(getGracePeriodSec()); ds.setGracePeriodSec(getGracePeriodSec());
ds.setNamespace(_namespace); ds.setNamespace(_namespace);
ds.setSavePeriodSec(getSavePeriodSec());
return ds; return ds;
} }

View File

@ -3,7 +3,7 @@
<parent> <parent>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -13,7 +13,7 @@
<name>Jetty :: GCloud</name> <name>Jetty :: GCloud</name>
<properties> <properties>
<gcloud.version>0.9.4-beta</gcloud.version> <gcloud.version>0.10.0-beta</gcloud.version>
</properties> </properties>
<modules> <modules>

View File

@ -3,7 +3,7 @@
<parent> <parent>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>jetty-home</artifactId> <artifactId>jetty-home</artifactId>

View File

@ -2,7 +2,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>jetty-http-spi</artifactId> <artifactId>jetty-http-spi</artifactId>

View File

@ -3,7 +3,7 @@
<parent> <parent>
<artifactId>jetty-project</artifactId> <artifactId>jetty-project</artifactId>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>jetty-http</artifactId> <artifactId>jetty-http</artifactId>
@ -37,7 +37,7 @@
<extensions>true</extensions> <extensions>true</extensions>
<configuration> <configuration>
<instructions> <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> <Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
--> -->

View File

@ -45,6 +45,11 @@ public class BadMessageException extends RuntimeException
this(400,reason); this(400,reason);
} }
public BadMessageException(String reason, Throwable cause)
{
this(400, reason, cause);
}
public BadMessageException(int code, String reason) public BadMessageException(int code, String reason)
{ {
super(code+": "+reason); super(code+": "+reason);

View File

@ -16,10 +16,10 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.server; package org.eclipse.jetty.http;
/** /**
* The compliance for Cookie handling. * The compliance for Cookie handling.
* *
*/ */
public enum CookieCompliance { RFC6265, RFC2965 } public enum CookieCompliance { RFC6265, RFC2965 }

View File

@ -18,8 +18,6 @@
package org.eclipse.jetty.http; package org.eclipse.jetty.http;
import static org.eclipse.jetty.http.HttpStatus.INTERNAL_SERVER_ERROR_500;
import java.io.IOException; import java.io.IOException;
import java.nio.BufferOverflowException; import java.nio.BufferOverflowException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -34,6 +32,8 @@ import org.eclipse.jetty.util.Trie;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import static org.eclipse.jetty.http.HttpStatus.INTERNAL_SERVER_ERROR_500;
/** /**
* HttpGenerator. Builds HTTP Messages. * HttpGenerator. Builds HTTP Messages.
* <p> * <p>
@ -764,7 +764,7 @@ public class HttpGenerator
} }
// Else if we are HTTP/1.1 and the content length is unknown and we are either persistent // Else if we are HTTP/1.1 and the content length is unknown and we are either persistent
// or it is a request with content (which cannot EOF) or the app has requested chunking // or it is a request with content (which cannot EOF) or the app has requested chunking
else if (http11 && content_length<0 && (_persistent || assumed_content_request || chunked_hint)) else if (http11 && (chunked_hint || content_length<0 && (_persistent || assumed_content_request)))
{ {
// we use chunking // we use chunking
_endOfContent = EndOfContent.CHUNKED_CONTENT; _endOfContent = EndOfContent.CHUNKED_CONTENT;

View File

@ -73,7 +73,7 @@ public class HttpStatus
public final static int REQUESTED_RANGE_NOT_SATISFIABLE_416 = 416; public final static int REQUESTED_RANGE_NOT_SATISFIABLE_416 = 416;
public final static int RANGE_NOT_SATISFIABLE_416 = 416; public final static int RANGE_NOT_SATISFIABLE_416 = 416;
public final static int EXPECTATION_FAILED_417 = 417; public final static int EXPECTATION_FAILED_417 = 417;
public final static int IM_A_TEAPOT_418 = 417; public final static int IM_A_TEAPOT_418 = 418;
public final static int ENHANCE_YOUR_CALM_420 = 420; public final static int ENHANCE_YOUR_CALM_420 = 420;
public final static int MISDIRECTED_REQUEST_421 = 421; public final static int MISDIRECTED_REQUEST_421 = 421;
public final static int UNPROCESSABLE_ENTITY_422 = 422; public final static int UNPROCESSABLE_ENTITY_422 = 422;
@ -153,7 +153,7 @@ public class HttpStatus
UNSUPPORTED_MEDIA_TYPE(UNSUPPORTED_MEDIA_TYPE_415, "Unsupported Media Type"), UNSUPPORTED_MEDIA_TYPE(UNSUPPORTED_MEDIA_TYPE_415, "Unsupported Media Type"),
RANGE_NOT_SATISFIABLE(RANGE_NOT_SATISFIABLE_416, "Range Not Satisfiable"), RANGE_NOT_SATISFIABLE(RANGE_NOT_SATISFIABLE_416, "Range Not Satisfiable"),
EXPECTATION_FAILED(EXPECTATION_FAILED_417, "Expectation Failed"), EXPECTATION_FAILED(EXPECTATION_FAILED_417, "Expectation Failed"),
IM_A_TEAPOT(IM_A_TEAPOT_418, "Im a Teapot"), IM_A_TEAPOT(IM_A_TEAPOT_418, "I'm a Teapot"),
ENHANCE_YOUR_CALM(ENHANCE_YOUR_CALM_420, "Enhance your Calm"), ENHANCE_YOUR_CALM(ENHANCE_YOUR_CALM_420, "Enhance your Calm"),
MISDIRECTED_REQUEST(MISDIRECTED_REQUEST_421, "Misdirected Request"), MISDIRECTED_REQUEST(MISDIRECTED_REQUEST_421, "Misdirected Request"),
UNPROCESSABLE_ENTITY(UNPROCESSABLE_ENTITY_422, "Unprocessable Entity"), UNPROCESSABLE_ENTITY(UNPROCESSABLE_ENTITY_422, "Unprocessable Entity"),

View File

@ -0,0 +1,142 @@
//
// ========================================================================
// 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.http;
import java.util.Objects;
/**
* Collection of Syntax validation methods.
* <p>
* Use in a similar way as you would {@link java.util.Objects#requireNonNull(Object)}
* </p>
*/
public final class Syntax
{
/**
* Per RFC2616: Section 2.2, a token follows these syntax rules
* <pre>
* token = 1*&lt;any CHAR except CTLs or separators&gt;
* CHAR = &lt;any US-ASCII character (octets 0 - 127)&gt;
* CTL = &lt;any US-ASCII control character
* (octets 0 - 31) and DEL (127)&gt;
* separators = "(" | ")" | "&lt;" | "&gt;" | "@"
* | "," | ";" | ":" | "\" | &lt;"&gt;
* | "/" | "[" | "]" | "?" | "="
* | "{" | "}" | SP | HT
* </pre>
*
* @param value the value to test
* @param msg the message to be prefixed if an {@link IllegalArgumentException} is thrown.
* @throws IllegalArgumentException if the value is invalid per spec
*/
public static void requireValidRFC2616Token(String value, String msg)
{
Objects.requireNonNull(msg, "msg cannot be null");
if (value == null)
{
return;
}
int valueLen = value.length();
if (valueLen == 0)
{
return;
}
for (int i = 0; i < valueLen; i++)
{
char c = value.charAt(i);
// 0x00 - 0x1F are low order control characters
// 0x7F is the DEL control character
if ((c <= 0x1F) || (c == 0x7F))
throw new IllegalArgumentException(msg + ": RFC2616 tokens may not contain control characters");
if (c == '(' || c == ')' || c == '<' || c == '>' || c == '@'
|| c == ',' || c == ';' || c == ':' || c == '\\' || c == '"'
|| c == '/' || c == '[' || c == ']' || c == '?' || c == '='
|| c == '{' || c == '}' || c == ' ')
{
throw new IllegalArgumentException(msg + ": RFC2616 tokens may not contain separator character: [" + c + "]");
}
if (c >= 0x80)
throw new IllegalArgumentException(msg + ": RFC2616 tokens characters restricted to US-ASCII: 0x" + Integer.toHexString(c));
}
}
/**
* Per RFC6265, Cookie.value follows these syntax rules
* <pre>
* cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
* cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
* ; US-ASCII characters excluding CTLs,
* ; whitespace DQUOTE, comma, semicolon,
* ; and backslash
* </pre>
*
* @param value the value to test
* @throws IllegalArgumentException if the value is invalid per spec
*/
public static void requireValidRFC6265CookieValue(String value)
{
if (value == null)
{
return;
}
int valueLen = value.length();
if (valueLen == 0)
{
return;
}
int i = 0;
if (value.charAt(0) == '"')
{
// Has starting DQUOTE
if (valueLen <= 1 || (value.charAt(valueLen - 1) != '"'))
{
throw new IllegalArgumentException("RFC6265 Cookie values must have balanced DQUOTES (if used)");
}
// adjust search range to exclude DQUOTES
i++;
valueLen--;
}
for (; i < valueLen; i++)
{
char c = value.charAt(i);
// 0x00 - 0x1F are low order control characters
// 0x7F is the DEL control character
if ((c <= 0x1F) || (c == 0x7F))
throw new IllegalArgumentException("RFC6265 Cookie values may not contain control characters");
if ((c == ' ' /* 0x20 */) ||
(c == '"' /* 0x2C */) ||
(c == ';' /* 0x3B */) ||
(c == '\\' /* 0x5C */))
{
throw new IllegalArgumentException("RFC6265 Cookie values may not contain character: [" + c + "]");
}
if (c >= 0x80)
throw new IllegalArgumentException("RFC6265 Cookie values characters restricted to US-ASCII: 0x" + Integer.toHexString(c));
}
}
}

View File

@ -30,6 +30,7 @@ doc=application/msword
dtd=application/xml-dtd dtd=application/xml-dtd
dvi=application/x-dvi dvi=application/x-dvi
dxr=application/x-director dxr=application/x-director
eot=application/vnd.ms-fontobject
eps=application/postscript eps=application/postscript
etx=text/x-setext etx=text/x-setext
exe=application/octet-stream exe=application/octet-stream
@ -171,6 +172,8 @@ wml=text/vnd.wap.wml
wmlc=application/vnd.wap.wmlc wmlc=application/vnd.wap.wmlc
wmls=text/vnd.wap.wmlscript wmls=text/vnd.wap.wmlscript
wmlsc=application/vnd.wap.wmlscriptc wmlsc=application/vnd.wap.wmlscriptc
woff=application/font-woff
woff2=font/woff2
wrl=model/vrml wrl=model/vrml
wtls-ca-certificate=application/vnd.wap.wtls-ca-certificate wtls-ca-certificate=application/vnd.wap.wtls-ca-certificate
xbm=image/x-xbitmap xbm=image/x-xbitmap

View File

@ -31,6 +31,14 @@ public class HttpStatusCodeTest
assertNull("Invalid code: 800", HttpStatus.getCode(800)); assertNull("Invalid code: 800", HttpStatus.getCode(800));
assertNull("Invalid code: 190", HttpStatus.getCode(190)); assertNull("Invalid code: 190", HttpStatus.getCode(190));
} }
@Test
public void testImATeapot()
{
assertEquals("I'm a Teapot", HttpStatus.getMessage(418));
assertEquals("Expectation Failed", HttpStatus.getMessage(417));
}
public void testHttpMethod() public void testHttpMethod()
{ {

View File

@ -21,16 +21,15 @@ package org.eclipse.jetty.http;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.util.Utf8Appendable;
import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
public class HttpURITest public class HttpURITest
@ -100,33 +99,6 @@ public class HttpURITest
assertThat(uri.getHost(),is("foo")); assertThat(uri.getHost(),is("foo"));
assertThat(uri.getPath(),is("/bar")); assertThat(uri.getPath(),is("/bar"));
} }
@Test
public void testUnicodeErrors() throws UnsupportedEncodingException
{
String uri="http://server/path?invalid=data%uXXXXhere%u000";
try
{
URLDecoder.decode(uri,"UTF-8");
Assert.assertTrue(false);
}
catch (IllegalArgumentException e)
{
}
HttpURI huri=new HttpURI(uri);
MultiMap<String> params = new MultiMap<>();
huri.decodeQueryTo(params);
assertEquals("data"+Utf8Appendable.REPLACEMENT+"here"+Utf8Appendable.REPLACEMENT,params.getValue("invalid",0));
huri=new HttpURI(uri);
params = new MultiMap<>();
huri.decodeQueryTo(params,StandardCharsets.UTF_8);
assertEquals("data"+Utf8Appendable.REPLACEMENT+"here"+Utf8Appendable.REPLACEMENT,params.getValue("invalid",0));
}
@Test @Test
public void testExtB() throws Exception public void testExtB() throws Exception

View File

@ -0,0 +1,134 @@
//
// ========================================================================
// 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.http;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import org.junit.Test;
public class SyntaxTest
{
@Test
public void testRequireValidRFC2616Token_Good()
{
String tokens[] = {
"name",
"",
null,
"n.a.m.e",
"na-me",
"+name",
"na*me",
"na$me",
"#name"
};
for (String token : tokens)
{
Syntax.requireValidRFC2616Token(token, "Test Based");
// No exception should occur here
}
}
@Test
public void testRequireValidRFC2616Token_Bad()
{
String tokens[] = {
"\"name\"",
"name\t",
"na me",
"name\u0082",
"na\tme",
"na;me",
"{name}",
"[name]",
"\""
};
for (String token : tokens)
{
try
{
Syntax.requireValidRFC2616Token(token, "Test Based");
fail("RFC2616 Token [" + token + "] Should have thrown " + IllegalArgumentException.class.getName());
}
catch (IllegalArgumentException e)
{
assertThat("Testing Bad RFC2616 Token [" + token + "]", e.getMessage(),
allOf(containsString("Test Based"),
containsString("RFC2616")));
}
}
}
@Test
public void testRequireValidRFC6265CookieValue_Good()
{
String values[] = {
"value",
"",
null,
"val=ue",
"val-ue",
"\"value\"",
"val/ue",
"v.a.l.u.e"
};
for (String value : values)
{
Syntax.requireValidRFC6265CookieValue(value);
// No exception should occur here
}
}
@Test
public void testRequireValidRFC6265CookieValue_Bad()
{
String values[] = {
"va\tlue",
"\t",
"value\u0000",
"val\u0082ue",
"va lue",
"va;lue",
"\"value",
"value\"",
"val\\ue",
"val\"ue",
"\""
};
for (String value : values)
{
try
{
Syntax.requireValidRFC6265CookieValue(value);
fail("RFC6265 Cookie Value [" + value + "] Should have thrown " + IllegalArgumentException.class.getName());
}
catch (IllegalArgumentException e)
{
assertThat("Testing Bad RFC6265 Cookie Value [" + value + "]", e.getMessage(), containsString("RFC6265"));
}
}
}
}

View File

@ -3,7 +3,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty.http2</groupId> <groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-parent</artifactId> <artifactId>http2-parent</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -3,7 +3,7 @@
<parent> <parent>
<groupId>org.eclipse.jetty.http2</groupId> <groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-parent</artifactId> <artifactId>http2-parent</artifactId>
<version>9.4.3-SNAPSHOT</version> <version>9.4.5-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

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