Merge branch 'jetty-9.4.x' of https://github.com/eclipse/jetty.project into issues/644

This commit is contained in:
WalkerWatch 2016-10-12 10:40:45 -04:00
commit ba8c9ed178
146 changed files with 4594 additions and 2197 deletions

View File

@ -225,6 +225,20 @@ jetty-9.4.0.M0 - 03 June 2016
+ 609 ignore failing test
+ 610 Ignore failing test
jetty-9.3.13.M0 - 30 September 2016
+ 277 Proxy servlet does not handle HTTP status 100 correctly
+ 870 TLS protocol exclusion broken for SslContextFactory(String)
+ 915 The jetty-maven-plugin:stop goal doesn't stop everything completely
+ 918 Support certificates hot reload
+ 930 Add module instructions to SSL section
+ 943 Docs: Error in 'Embedding Jetty' page - example 'FileServer'
+ 948 9.4.0.RC0 jetty-distribution invalid config etc/jetty-http2c.xml
+ 955 Response listeners not invoked when using Connection.send()
+ 959 CompleteListener invoked twice for HTTP/2 transport and response content
+ 960 Async I/O spin when reading early EOF
+ 965 Link from High Load docs to Garbage Collection Tuning is broken
+ 966 Remove usages of ConcurrentArrayQueue
jetty-9.3.12.v20160915 - 15 September 2016
+ 56 Fix authn issues in LdapLoginModule
+ 131 Improve Connector Statistic names and values

View File

@ -21,7 +21,6 @@ package org.eclipse.jetty.annotations;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -48,6 +47,7 @@ import org.eclipse.jetty.plus.annotation.ContainerInitializer;
import org.eclipse.jetty.util.ConcurrentHashSet;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
@ -81,8 +81,6 @@ public class AnnotationConfiguration extends AbstractConfiguration
protected List<ContainerInitializerAnnotationHandler> _containerInitializerAnnotationHandlers = new ArrayList<ContainerInitializerAnnotationHandler>();
protected List<ParserTask> _parserTasks;
protected WebAppClassNameResolver _webAppClassNameResolver;
protected ContainerClassNameResolver _containerClassNameResolver;
protected CounterStatistic _containerPathStats;
protected CounterStatistic _webInfLibStats;
@ -138,15 +136,13 @@ public class AnnotationConfiguration extends AbstractConfiguration
protected Exception _exception;
protected final AnnotationParser _parser;
protected final Set<? extends Handler> _handlers;
protected final ClassNameResolver _resolver;
protected final Resource _resource;
protected TimeStatistic _stat;
public ParserTask (AnnotationParser parser, Set<? extends Handler>handlers, Resource resource, ClassNameResolver resolver)
public ParserTask (AnnotationParser parser, Set<? extends Handler>handlers, Resource resource)
{
_parser = parser;
_handlers = handlers;
_resolver = resolver;
_resource = resource;
}
@ -160,7 +156,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (_stat != null)
_stat.start();
if (_parser != null)
_parser.parse(_handlers, _resource, _resolver);
_parser.parse(_handlers, _resource);
if (_stat != null)
_stat.end();
return null;
@ -174,83 +170,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
public Resource getResource()
{
return _resource;
}
}
/**
* WebAppClassNameResolver
*
* Checks to see if a classname belongs to hidden or visible packages when scanning,
* and whether a classname that is a duplicate should override a previously
* scanned classname.
*
* This is analogous to the management of classes that the WebAppClassLoader is doing,
* however we don't want to load the classes at this point so we are doing it on
* the name only.
*
*/
public class WebAppClassNameResolver implements ClassNameResolver
{
private WebAppContext _context;
public WebAppClassNameResolver (WebAppContext context)
{
_context = context;
}
public boolean isExcluded (String name)
{
if (_context.isSystemClass(name)) return true;
if (_context.isServerClass(name)) return false;
return false;
}
public boolean shouldOverride (String name)
{
//looking at webapp classpath, found already-parsed class
//of same name - did it come from system or duplicate in webapp?
if (_context.isParentLoaderPriority())
return false;
return true;
}
}
/**
* ContainerClassNameResolver
*
* Checks to see if a classname belongs to a hidden or visible package
* when scanning for annotations and thus whether it should be excluded from
* consideration or not.
*
* This is analogous to the management of classes that the WebAppClassLoader is doing,
* however we don't want to load the classes at this point so we are doing it on
* the name only.
*
*/
public class ContainerClassNameResolver implements ClassNameResolver
{
private WebAppContext _context;
public ContainerClassNameResolver (WebAppContext context)
{
_context = context;
}
public boolean isExcluded (String name)
{
if (_context.isSystemClass(name)) return false;
if (_context.isServerClass(name)) return true;
return false;
}
public boolean shouldOverride (String name)
{
//visiting the container classpath,
if (_context.isParentLoaderPriority())
return true;
return false;
}
}
}
@ -390,8 +310,6 @@ public class AnnotationConfiguration extends AbstractConfiguration
@Override
public void preConfigure(final WebAppContext context) throws Exception
{
_webAppClassNameResolver = new WebAppClassNameResolver(context);
_containerClassNameResolver = new ContainerClassNameResolver(context);
String tmp = (String)context.getAttribute(SERVLET_CONTAINER_INITIALIZER_EXCLUSION_PATTERN);
_sciExcludePattern = (tmp==null?null:Pattern.compile(tmp));
}
@ -445,15 +363,15 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (!_discoverableAnnotationHandlers.isEmpty() || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty())
scanForAnnotations(context);
// Resolve container initializers
List<ContainerInitializer> initializers =
(List<ContainerInitializer>)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS);
(List<ContainerInitializer>)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS);
if (initializers != null && initializers.size()>0)
{
Map<String, Set<String>> map = ( Map<String, Set<String>>) context.getAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP);
for (ContainerInitializer i : initializers)
i.resolveClasses(context,map);
i.resolveClasses(context,map);
}
}
@ -723,23 +641,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
public Resource getJarFor (ServletContainerInitializer service)
throws MalformedURLException, IOException
{
//try the thread context classloader to get the jar that loaded the class
URL jarURL = Thread.currentThread().getContextClassLoader().getResource(service.getClass().getName().replace('.','/')+".class");
//if for some reason that failed (eg we're in osgi and the TCCL does not know about the service) try the classloader that
//loaded the class
if (jarURL == null)
jarURL = service.getClass().getClassLoader().getResource(service.getClass().getName().replace('.','/')+".class");
String loadingJarName = jarURL.toString();
int i = loadingJarName.indexOf(".jar");
if (i < 0)
return null; //not from a jar
loadingJarName = loadingJarName.substring(0,i+4);
loadingJarName = (loadingJarName.startsWith("jar:")?loadingJarName.substring(4):loadingJarName);
return Resource.newResource(loadingJarName);
return TypeUtil.getLoadedFrom(service.getClass());
}
/**
@ -760,26 +662,41 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (context == null)
throw new IllegalArgumentException("WebAppContext null");
if (LOG.isDebugEnabled()) LOG.debug("Checking {} for jar exclusion", sci);
//A ServletContainerInitializer that came from the container's classpath cannot be excluded by an ordering
//of WEB-INF/lib jars
if (isFromContainerClassPath(context, sci))
{
if (LOG.isDebugEnabled())
LOG.debug("!Excluded {} from container classpath", sci);
return false;
}
//If no ordering, nothing is excluded
if (context.getMetaData().getOrdering() == null)
{
if (LOG.isDebugEnabled())
LOG.debug("!Excluded {} no ordering", sci);
return false;
}
List<Resource> orderedJars = context.getMetaData().getOrderedWebInfJars();
//there is an ordering, but there are no jars resulting from the ordering, everything excluded
if (orderedJars.isEmpty())
{
if (LOG.isDebugEnabled())
LOG.debug("Excluded {} empty ordering", sci);
return true;
}
if (sciResource == null)
return false; //not from a jar therefore not from WEB-INF so not excludable
{
//not from a jar therefore not from WEB-INF so not excludable
if (LOG.isDebugEnabled())
LOG.debug("!Excluded {} not from jar", sci);
return false;
}
URI loadingJarURI = sciResource.getURI();
boolean found = false;
@ -790,10 +707,11 @@ public class AnnotationConfiguration extends AbstractConfiguration
found = r.getURI().equals(loadingJarURI);
}
if (LOG.isDebugEnabled())
LOG.debug("{}Excluded {} found={}",found?"!":"",sci,found);
return !found;
}
/**
* Test if the ServletContainerIntializer is excluded by the
* o.e.j.containerInitializerExclusionPattern
@ -808,7 +726,8 @@ public class AnnotationConfiguration extends AbstractConfiguration
return false;
//test if name of class matches the regex
if (LOG.isDebugEnabled()) LOG.debug("Checking {} against containerInitializerExclusionPattern",sci.getClass().getName());
if (LOG.isDebugEnabled())
LOG.debug("Checking {} against containerInitializerExclusionPattern",sci.getClass().getName());
return _sciExcludePattern.matcher(sci.getClass().getName()).matches();
}
@ -866,17 +785,18 @@ public class AnnotationConfiguration extends AbstractConfiguration
//because containerInitializerOrdering omits it
for (ServletContainerInitializer sci:_loadedInitializers)
{
if (matchesExclusionPattern(sci))
{
if (LOG.isDebugEnabled()) LOG.debug("{} excluded by pattern", sci);
if (LOG.isDebugEnabled())
LOG.debug("{} excluded by pattern", sci);
continue;
}
Resource sciResource = getJarFor(sci);
if (isFromExcludedJar(context, sci, sciResource))
{
if (LOG.isDebugEnabled()) LOG.debug("{} is from excluded jar", sci);
if (LOG.isDebugEnabled())
LOG.debug("{} is from excluded jar", sci);
continue;
}
@ -885,7 +805,8 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (initializerOrdering != null
&& (!initializerOrdering.hasWildcard() && initializerOrdering.getIndexOf(name) < 0))
{
if (LOG.isDebugEnabled()) LOG.debug("{} is excluded by ordering", sci);
if (LOG.isDebugEnabled())
LOG.debug("{} is excluded by ordering", sci);
continue;
}
@ -912,12 +833,14 @@ public class AnnotationConfiguration extends AbstractConfiguration
//no web.xml ordering defined, add SCIs in any order
if (context.getMetaData().getOrdering() == null)
{
if (LOG.isDebugEnabled()) LOG.debug("No web.xml ordering, ServletContainerInitializers in random order");
if (LOG.isDebugEnabled())
LOG.debug("No web.xml ordering, ServletContainerInitializers in random order");
nonExcludedInitializers.addAll(sciResourceMap.keySet());
}
else
{
if (LOG.isDebugEnabled()) LOG.debug("Ordering ServletContainerInitializers with ordering {}",context.getMetaData().getOrdering());
if (LOG.isDebugEnabled())
LOG.debug("Ordering ServletContainerInitializers with ordering {}",context.getMetaData().getOrdering());
for (Map.Entry<ServletContainerInitializer, Resource> entry:sciResourceMap.entrySet())
{
//add in SCIs from the container classpath
@ -992,7 +915,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
//queue it up for scanning if using multithreaded mode
if (_parserTasks != null)
{
ParserTask task = new ParserTask(parser, handlers, r, _containerClassNameResolver);
ParserTask task = new ParserTask(parser, handlers, r);
_parserTasks.add(task);
_containerPathStats.increment();
if (LOG.isDebugEnabled())
@ -1054,7 +977,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
if (_parserTasks != null)
{
ParserTask task = new ParserTask(parser, handlers,r, _webAppClassNameResolver);
ParserTask task = new ParserTask(parser, handlers,r);
_parserTasks.add (task);
_webInfLibStats.increment();
if (LOG.isDebugEnabled())
@ -1087,7 +1010,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
{
if (_parserTasks != null)
{
ParserTask task = new ParserTask(parser, handlers, dir, _webAppClassNameResolver);
ParserTask task = new ParserTask(parser, handlers, dir);
_parserTasks.add(task);
_webInfClassesStats.increment();
if (LOG.isDebugEnabled())

View File

@ -544,28 +544,24 @@ public class AnnotationParser
*
* @param handlers the set of handlers to find class
* @param className the class name to parse
* @param resolver the class name resolver to use
* @throws Exception if unable to parse
*/
public void parse (Set<? extends Handler> handlers, String className, ClassNameResolver resolver)
public void parse (Set<? extends Handler> handlers, String className)
throws Exception
{
if (className == null)
return;
if (!resolver.isExcluded(className))
if (!isParsed(className))
{
if (!isParsed(className) || resolver.shouldOverride(className))
className = className.replace('.', '/')+".class";
URL resource = Loader.getResource(className);
if (resource!= null)
{
className = className.replace('.', '/')+".class";
URL resource = Loader.getResource(className);
if (resource!= null)
Resource r = Resource.newResource(resource);
try (InputStream is = r.getInputStream())
{
Resource r = Resource.newResource(resource);
try (InputStream is = r.getInputStream())
{
scanClass(handlers, null, is);
}
scanClass(handlers, null, is);
}
}
}
@ -578,33 +574,30 @@ public class AnnotationParser
*
* @param handlers the handlers to look for class in
* @param clazz the class to look for
* @param resolver the resolver to look up class with
* @param visitSuperClasses if true, also visit super classes for parse
* @throws Exception if unable to parse class
*/
public void parse (Set<? extends Handler> handlers, Class<?> clazz, ClassNameResolver resolver, boolean visitSuperClasses)
public void parse (Set<? extends Handler> handlers, Class<?> clazz, boolean visitSuperClasses)
throws Exception
{
Class<?> cz = clazz;
while (cz != null)
{
if (!resolver.isExcluded(cz.getName()))
if (!isParsed(cz.getName()))
{
if (!isParsed(cz.getName()) || resolver.shouldOverride(cz.getName()))
String nameAsResource = cz.getName().replace('.', '/')+".class";
URL resource = Loader.getResource(nameAsResource);
if (resource!= null)
{
String nameAsResource = cz.getName().replace('.', '/')+".class";
URL resource = Loader.getResource(nameAsResource);
if (resource!= null)
Resource r = Resource.newResource(resource);
try (InputStream is = r.getInputStream())
{
Resource r = Resource.newResource(resource);
try (InputStream is = r.getInputStream())
{
scanClass(handlers, null, is);
}
scanClass(handlers, null, is);
}
}
}
if (visitSuperClasses)
cz = cz.getSuperclass();
else
@ -619,16 +612,15 @@ public class AnnotationParser
*
* @param handlers the set of handlers to look for class in
* @param classNames the class name
* @param resolver the class name resolver
* @throws Exception if unable to parse
*/
public void parse (Set<? extends Handler> handlers, String[] classNames, ClassNameResolver resolver)
public void parse (Set<? extends Handler> handlers, String[] classNames)
throws Exception
{
if (classNames == null)
return;
parse(handlers, Arrays.asList(classNames), resolver);
parse(handlers, Arrays.asList(classNames));
}
@ -637,10 +629,9 @@ public class AnnotationParser
*
* @param handlers the set of handlers to look for class in
* @param classNames the class names
* @param resolver the class name resolver
* @throws Exception if unable to parse
*/
public void parse (Set<? extends Handler> handlers, List<String> classNames, ClassNameResolver resolver)
public void parse (Set<? extends Handler> handlers, List<String> classNames)
throws Exception
{
MultiException me = new MultiException();
@ -649,7 +640,7 @@ public class AnnotationParser
{
try
{
if ((resolver == null) || (!resolver.isExcluded(s) && (!isParsed(s) || resolver.shouldOverride(s))))
if (!isParsed(s))
{
s = s.replace('.', '/')+".class";
URL resource = Loader.getResource(s);
@ -677,10 +668,9 @@ public class AnnotationParser
*
* @param handlers the set of handlers to look for classes in
* @param dir the resource directory to look for classes
* @param resolver the class name resolver
* @throws Exception if unable to parse
*/
protected void parseDir (Set<? extends Handler> handlers, Resource dir, ClassNameResolver resolver)
protected void parseDir (Set<? extends Handler> handlers, Resource dir)
throws Exception
{
// skip dirs whose name start with . (ie hidden)
@ -696,7 +686,7 @@ public class AnnotationParser
{
Resource res = dir.addPath(files[f]);
if (res.isDirectory())
parseDir(handlers, res, resolver);
parseDir(handlers, res);
else
{
//we've already verified the directories, so just verify the class file name
@ -706,7 +696,7 @@ public class AnnotationParser
try
{
String name = res.getName();
if ((resolver == null)|| (!resolver.isExcluded(name) && (!isParsed(name) || resolver.shouldOverride(name))))
if (!isParsed(name))
{
Resource r = Resource.newResource(res.getURL());
if (LOG.isDebugEnabled()) {LOG.debug("Scanning class {}", r);};
@ -741,10 +731,9 @@ public class AnnotationParser
* @param loader the classloader for the classes
* @param visitParents if true, visit parent classloaders too
* @param nullInclusive if true, an empty pattern means all names match, if false, none match
* @param resolver the class name resolver
* @throws Exception if unable to parse
*/
public void parse (final Set<? extends Handler> handlers, ClassLoader loader, boolean visitParents, boolean nullInclusive, final ClassNameResolver resolver)
public void parse (final Set<? extends Handler> handlers, ClassLoader loader, boolean visitParents, boolean nullInclusive)
throws Exception
{
if (loader==null)
@ -762,7 +751,7 @@ public class AnnotationParser
{
try
{
parseJarEntry(handlers, Resource.newResource(jarUri), entry, resolver);
parseJarEntry(handlers, Resource.newResource(jarUri), entry);
}
catch (Exception e)
{
@ -782,10 +771,9 @@ public class AnnotationParser
*
* @param handlers the handlers to look for classes in
* @param uris the uris for the jars
* @param resolver the class name resolver
* @throws Exception if unable to parse
*/
public void parse (final Set<? extends Handler> handlers, final URI[] uris, final ClassNameResolver resolver)
public void parse (final Set<? extends Handler> handlers, final URI[] uris)
throws Exception
{
if (uris==null)
@ -797,7 +785,7 @@ public class AnnotationParser
{
try
{
parse(handlers, uri, resolver);
parse(handlers, uri);
}
catch (Exception e)
{
@ -812,16 +800,15 @@ public class AnnotationParser
*
* @param handlers the handlers to look for classes in
* @param uri the uri for the jar
* @param resolver the class name resolver
* @throws Exception if unable to parse
*/
public void parse (final Set<? extends Handler> handlers, URI uri, final ClassNameResolver resolver)
public void parse (final Set<? extends Handler> handlers, URI uri)
throws Exception
{
if (uri == null)
return;
parse (handlers, Resource.newResource(uri), resolver);
parse (handlers, Resource.newResource(uri));
}
@ -830,10 +817,9 @@ public class AnnotationParser
*
* @param handlers the handlers to look for classes in
* @param r the resource to parse
* @param resolver the class name resolver
* @throws Exception if unable to parse
*/
public void parse (final Set<? extends Handler> handlers, Resource r, final ClassNameResolver resolver)
public void parse (final Set<? extends Handler> handlers, Resource r)
throws Exception
{
if (r == null)
@ -841,14 +827,14 @@ public class AnnotationParser
if (r.exists() && r.isDirectory())
{
parseDir(handlers, r, resolver);
parseDir(handlers, r);
return;
}
String fullname = r.toString();
if (fullname.endsWith(".jar"))
{
parseJar(handlers, r, resolver);
parseJar(handlers, r);
return;
}
@ -872,10 +858,9 @@ public class AnnotationParser
*
* @param handlers the handlers to look for classes in
* @param jarResource the jar resource to parse
* @param resolver the class name resolver
* @throws Exception if unable to parse
*/
protected void parseJar (Set<? extends Handler> handlers, Resource jarResource, final ClassNameResolver resolver)
protected void parseJar (Set<? extends Handler> handlers, Resource jarResource)
throws Exception
{
if (jarResource == null)
@ -899,7 +884,7 @@ public class AnnotationParser
{
try
{
parseJarEntry(handlers, jarResource, entry, resolver);
parseJarEntry(handlers, jarResource, entry);
}
catch (Exception e)
{
@ -927,10 +912,9 @@ public class AnnotationParser
* @param handlers the handlers to look for classes in
* @param jar the jar resource to parse
* @param entry the entry in the jar resource to parse
* @param resolver the class name resolver
* @throws Exception if unable to parse
*/
protected void parseJarEntry (Set<? extends Handler> handlers, Resource jar, JarEntry entry, final ClassNameResolver resolver)
protected void parseJarEntry (Set<? extends Handler> handlers, Resource jar, JarEntry entry)
throws Exception
{
if (jar == null || entry == null)
@ -947,9 +931,7 @@ public class AnnotationParser
{
String shortName = name.replace('/', '.').substring(0,name.length()-6);
if ((resolver == null)
||
(!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
if (!isParsed(shortName))
{
Resource clazz = Resource.newResource("jar:"+jar.getURI()+"!/"+name);
if (LOG.isDebugEnabled()) {LOG.debug("Scanning class from jar {}", clazz);};

View File

@ -1,42 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.annotations;
public interface ClassNameResolver
{
/**
* Based on the execution context, should the class represented
* by "name" be excluded from consideration?
* @param name the name to test
* @return true if classname is excluded
*/
public boolean isExcluded (String name);
/**
* Based on the execution context, if a duplicate class
* represented by "name" is detected, should the existing
* one be overridden or not?
* @param name the name to test
* @return true if name should be overridden
*/
public boolean shouldOverride (String name);
}

View File

@ -74,6 +74,12 @@ public class TestAnnotationInheritance
return;
annotatedMethods.add(info.getClassInfo().getClassName()+"."+info.getMethodName());
}
@Override
public String toString()
{
return annotatedClassNames.toString()+annotatedMethods+annotatedFields;
}
}
@After
@ -93,18 +99,7 @@ public class TestAnnotationInheritance
SampleHandler handler = new SampleHandler();
AnnotationParser parser = new AnnotationParser();
parser.parse(Collections.singleton(handler), classNames, new ClassNameResolver ()
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
});
parser.parse(Collections.singleton(handler), classNames);
//check we got 2 class annotations
assertEquals(2, handler.annotatedClassNames.size());
@ -129,18 +124,7 @@ public class TestAnnotationInheritance
{
SampleHandler handler = new SampleHandler();
AnnotationParser parser = new AnnotationParser();
parser.parse(Collections.singleton(handler), ClassB.class, new ClassNameResolver ()
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
}, true);
parser.parse(Collections.singleton(handler), ClassB.class, true);
//check we got 2 class annotations
assertEquals(2, handler.annotatedClassNames.size());
@ -160,46 +144,6 @@ public class TestAnnotationInheritance
assertEquals("org.eclipse.jetty.annotations.ClassA.m", handler.annotatedFields.get(0));
}
@Test
public void testExclusions() throws Exception
{
AnnotationParser parser = new AnnotationParser();
SampleHandler handler = new SampleHandler();
parser.parse(Collections.singleton(handler), ClassA.class.getName(), new ClassNameResolver()
{
public boolean isExcluded(String name)
{
return true;
}
public boolean shouldOverride(String name)
{
return false;
}
});
assertEquals (0, handler.annotatedClassNames.size());
assertEquals (0, handler.annotatedFields.size());
assertEquals (0, handler.annotatedMethods.size());
handler.annotatedClassNames.clear();
handler.annotatedFields.clear();
handler.annotatedMethods.clear();
parser.parse (Collections.singleton(handler), ClassA.class.getName(), new ClassNameResolver()
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
});
assertEquals (1, handler.annotatedClassNames.size());
}
@Test
public void testTypeInheritanceHandling() throws Exception
{
@ -218,7 +162,7 @@ public class TestAnnotationInheritance
classNames.add(InterfaceD.class.getName());
classNames.add(Foo.class.getName());
parser.parse(Collections.singleton(handler), classNames, null);
parser.parse(Collections.singleton(handler), classNames);
assertNotNull(map);
assertFalse(map.isEmpty());

View File

@ -111,19 +111,7 @@ public class TestAnnotationParser
}
//long start = System.currentTimeMillis();
parser.parse(Collections.singleton(new SampleAnnotationHandler()), classNames,new ClassNameResolver()
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
});
parser.parse(Collections.singleton(new SampleAnnotationHandler()), classNames);
//long end = System.currentTimeMillis();
//System.err.println("Time to parse class: " + ((end - start)));
@ -162,7 +150,7 @@ public class TestAnnotationParser
}
}
parser.parse(Collections.singleton(new MultiAnnotationHandler()), classNames,null);
parser.parse(Collections.singleton(new MultiAnnotationHandler()), classNames);
}
@Test
@ -171,7 +159,7 @@ public class TestAnnotationParser
File badClassesJar = MavenTestingUtils.getTestResourceFile("bad-classes.jar");
AnnotationParser parser = new AnnotationParser();
Set<Handler> emptySet = Collections.emptySet();
parser.parse(emptySet, badClassesJar.toURI(),null);
parser.parse(emptySet, badClassesJar.toURI());
// only the valid classes inside bad-classes.jar should be parsed. If any invalid classes are parsed and exception would be thrown here
}
@ -196,7 +184,7 @@ public class TestAnnotationParser
AnnotationParser parser = new AnnotationParser();
// Parse
parser.parse(Collections.singleton(tracker), basedir.toURI(),null);
parser.parse(Collections.singleton(tracker), basedir.toURI());
// Validate
Assert.assertThat("Found Class", tracker.foundClasses, contains(ClassA.class.getName()));

View File

@ -73,18 +73,7 @@ public class TestServletAnnotations
TestWebServletAnnotationHandler handler = new TestWebServletAnnotationHandler(wac, results);
parser.parse(Collections.singleton(handler), classes, new ClassNameResolver ()
{
public boolean isExcluded(String name)
{
return false;
}
public boolean shouldOverride(String name)
{
return false;
}
});
parser.parse(Collections.singleton(handler), classes);
assertEquals(1, results.size());

View File

@ -18,26 +18,13 @@
package org.eclipse.jetty.client;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import java.util.zip.ZipException;
import org.eclipse.jetty.util.BufferUtil;
/**
* {@link ContentDecoder} for the "gzip" encoding.
*
*/
public class GZIPContentDecoder implements ContentDecoder
public class GZIPContentDecoder extends org.eclipse.jetty.http.GZIPContentDecoder implements ContentDecoder
{
private final Inflater inflater = new Inflater(true);
private final byte[] bytes;
private byte[] output;
private State state;
private int size;
private int value;
private byte flags;
public GZIPContentDecoder()
{
@ -46,285 +33,7 @@ public class GZIPContentDecoder implements ContentDecoder
public GZIPContentDecoder(int bufferSize)
{
this.bytes = new byte[bufferSize];
reset();
}
/**
* {@inheritDoc}
* <p>If the decoding did not produce any output, for example because it consumed gzip header
* or trailer bytes, it returns a buffer with zero capacity.</p>
* <p>This method never returns null.</p>
* <p>The given {@code buffer}'s position will be modified to reflect the bytes consumed during
* the decoding.</p>
* <p>The decoding may be finished without consuming the buffer completely if the buffer contains
* gzip bytes plus other bytes (either plain or gzipped).</p>
*/
@Override
public ByteBuffer decode(ByteBuffer buffer)
{
try
{
while (buffer.hasRemaining())
{
byte currByte = buffer.get();
switch (state)
{
case INITIAL:
{
buffer.position(buffer.position() - 1);
state = State.ID;
break;
}
case ID:
{
value += (currByte & 0xFF) << 8 * size;
++size;
if (size == 2)
{
if (value != 0x8B1F)
throw new ZipException("Invalid gzip bytes");
state = State.CM;
}
break;
}
case CM:
{
if ((currByte & 0xFF) != 0x08)
throw new ZipException("Invalid gzip compression method");
state = State.FLG;
break;
}
case FLG:
{
flags = currByte;
state = State.MTIME;
size = 0;
value = 0;
break;
}
case MTIME:
{
// Skip the 4 MTIME bytes
++size;
if (size == 4)
state = State.XFL;
break;
}
case XFL:
{
// Skip XFL
state = State.OS;
break;
}
case OS:
{
// Skip OS
state = State.FLAGS;
break;
}
case FLAGS:
{
buffer.position(buffer.position() - 1);
if ((flags & 0x04) == 0x04)
{
state = State.EXTRA_LENGTH;
size = 0;
value = 0;
}
else if ((flags & 0x08) == 0x08)
state = State.NAME;
else if ((flags & 0x10) == 0x10)
state = State.COMMENT;
else if ((flags & 0x2) == 0x2)
{
state = State.HCRC;
size = 0;
value = 0;
}
else
state = State.DATA;
break;
}
case EXTRA_LENGTH:
{
value += (currByte & 0xFF) << 8 * size;
++size;
if (size == 2)
state = State.EXTRA;
break;
}
case EXTRA:
{
// Skip EXTRA bytes
--value;
if (value == 0)
{
// Clear the EXTRA flag and loop on the flags
flags &= ~0x04;
state = State.FLAGS;
}
break;
}
case NAME:
{
// Skip NAME bytes
if (currByte == 0)
{
// Clear the NAME flag and loop on the flags
flags &= ~0x08;
state = State.FLAGS;
}
break;
}
case COMMENT:
{
// Skip COMMENT bytes
if (currByte == 0)
{
// Clear the COMMENT flag and loop on the flags
flags &= ~0x10;
state = State.FLAGS;
}
break;
}
case HCRC:
{
// Skip HCRC
++size;
if (size == 2)
{
// Clear the HCRC flag and loop on the flags
flags &= ~0x02;
state = State.FLAGS;
}
break;
}
case DATA:
{
buffer.position(buffer.position() - 1);
while (true)
{
int decoded = inflate(bytes);
if (decoded == 0)
{
if (inflater.needsInput())
{
if (buffer.hasRemaining())
{
byte[] input = new byte[buffer.remaining()];
buffer.get(input);
inflater.setInput(input);
}
else
{
if (output != null)
{
ByteBuffer result = ByteBuffer.wrap(output);
output = null;
return result;
}
break;
}
}
else if (inflater.finished())
{
int remaining = inflater.getRemaining();
buffer.position(buffer.limit() - remaining);
state = State.CRC;
size = 0;
value = 0;
break;
}
else
{
throw new ZipException("Invalid inflater state");
}
}
else
{
if (output == null)
{
// Save the inflated bytes and loop to see if we have finished
output = Arrays.copyOf(bytes, decoded);
}
else
{
// Accumulate inflated bytes and loop to see if we have finished
byte[] newOutput = Arrays.copyOf(output, output.length + decoded);
System.arraycopy(bytes, 0, newOutput, output.length, decoded);
output = newOutput;
}
}
}
break;
}
case CRC:
{
value += (currByte & 0xFF) << 8 * size;
++size;
if (size == 4)
{
// From RFC 1952, compliant decoders need not to verify the CRC
state = State.ISIZE;
size = 0;
value = 0;
}
break;
}
case ISIZE:
{
value += (currByte & 0xFF) << 8 * size;
++size;
if (size == 4)
{
if (value != inflater.getBytesWritten())
throw new ZipException("Invalid input size");
ByteBuffer result = output == null ? BufferUtil.EMPTY_BUFFER : ByteBuffer.wrap(output);
reset();
return result;
}
break;
}
default:
throw new ZipException();
}
}
return BufferUtil.EMPTY_BUFFER;
}
catch (ZipException x)
{
throw new RuntimeException(x);
}
}
private int inflate(byte[] bytes) throws ZipException
{
try
{
return inflater.inflate(bytes);
}
catch (DataFormatException x)
{
throw new ZipException(x.getMessage());
}
}
private void reset()
{
inflater.reset();
Arrays.fill(bytes, (byte)0);
output = null;
state = State.INITIAL;
size = 0;
value = 0;
flags = 0;
}
protected boolean isFinished()
{
return state == State.INITIAL;
super(null,bufferSize);
}
/**
@ -351,9 +60,4 @@ public class GZIPContentDecoder implements ContentDecoder
return new GZIPContentDecoder(bufferSize);
}
}
private enum State
{
INITIAL, ID, CM, FLG, MTIME, XFL, OS, FLAGS, EXTRA_LENGTH, EXTRA, NAME, COMMENT, HCRC, DATA, CRC, ISIZE
}
}

View File

@ -37,6 +37,7 @@ import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.CountingCallback;
import org.eclipse.jetty.util.component.Destroyable;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -470,6 +471,7 @@ public abstract class HttpReceiver
*/
protected void reset()
{
destroyDecoder(decoder);
decoder = null;
}
@ -482,9 +484,18 @@ public abstract class HttpReceiver
*/
protected void dispose()
{
destroyDecoder(decoder);
decoder = null;
}
private static void destroyDecoder(ContentDecoder decoder)
{
if (decoder instanceof Destroyable)
{
((Destroyable)decoder).destroy();
}
}
public boolean abort(HttpExchange exchange, Throwable failure)
{
// Update the state to avoid more response processing.

View File

@ -33,6 +33,7 @@ import org.eclipse.jetty.toolchain.test.TestTracker;
import org.junit.Rule;
import org.junit.Test;
@Deprecated
public class GZIPContentDecoderTest
{
@Rule

View File

@ -329,7 +329,7 @@
<arguments>
<argument>jetty.home=${assembly-directory}</argument>
<argument>jetty.base=${assembly-directory}</argument>
<argument>--add-to-start=deploy,websocket,ext,resources,jsp,jstl,http</argument>
<argument>--add-to-start=server,deploy,websocket,ext,resources,jsp,jstl,http</argument>
</arguments>
</configuration>
<goals>

View File

@ -31,18 +31,24 @@ Not only does the `quickstart-web.xml` contain all the discovered Servlets, Filt
With the quickstart mechanism, Jetty is able to entirely bypass all scanning and discovery modes and start a webapp in a predictable and fast way.
Tests have shown that webapps that took many seconds to scan and deploy can now be deployed in a few hundred milliseconds.
Additionally, if debug logging is enabled, the generated quickstart information is tagged with the origin of every element, which can be useful for debugging purposes.
==== Setting up Quickstart
To use quickstart the module has to be available to the Jetty instance.
In a standard Jetty distribution it can be configured with the following command:
===== Prerequisites
====== Jetty Distribution
In a standard Jetty distribution the quickstart module can be configured with the following command:
[source, screen, subs="{sub-order}"]
----
$ java -jar $JETTY_HOME/start.jar --add-to-start=quickstart
----
In a Maven project this is done by adding a dependency on the artifact ID `jetty-quickstart`.
====== Embedded
In a Maven project you add a dependency on the artifact `jetty-quickstart`.
[source, xml, subs="{sub-order}"]
----
@ -53,26 +59,62 @@ In a Maven project this is done by adding a dependency on the artifact ID `jetty
</dependency>
----
Additionally, for those using Maven, the link:#get-up-and-running[Jetty Maven Plugin] has a goal, link:#jetty-effective-web-xml[`jetty:effective-web-xml`], which performs quickstart operations.
It should be noted, however, that the Jetty Maven Plugin also includes additional items on it's classpath which may not be needed by the webapp.
Deployed webapps need to be instances of link:{JDURL}/org/eclipse/jetty/quickstart/QuickStartWebApp.html[`org.eclipse.jetty.quickstart.QuickStartWebApp`] rather than the normal `org.eclipse.jetty.webapp.WebAppContext`.
If a web application already has a `webapps/myapp.xml` file, simply change the class in the `Configure` element.
Otherwise, create a `webapps/myapp.xml` file as follows:
===== Configuration
Webapps need to be instances of link:{JDURL}/org/eclipse/jetty/quickstart/QuickStartWebApp.html[`org.eclipse.jetty.quickstart.QuickStartWebApp`] rather than the normal `org.eclipse.jetty.webapp.WebAppContext`.
`org.eclipse.jetty.quickstart.QuickStartWebApp` instances offer the same setters as the familiar `org.eclipse.jetty.webapp.WebAppContext`, with the addition of:
autoPreconfigure::
(true/false).
If true, the first time the webapp is run, the WEB-INF/quickstart-web.xml is generated BEFORE the webapp is deployed.
Subsequent runs use the previously generated quickstart file.
====== In XML
If a web application already has a context xml file, eg `webapps/myapp.xml` file, simply change the class in the `Configure` element.
Otherwise, create a context xml file with the following information (in addition to the usual setting of contextPath, war etc):
[source, xml, subs="{sub-order}"]
----
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.quickstart.QuickStartWebApp">
<Set name="war"><Property name="jetty.webapps" default="."/>/benchmark.war</Set>
<Set name="contextPath">/benchmark</Set>
<Set name="autoPreconfigure">true</Set>
</Configure>
----
For embedded implementations of Jetty, invoking the link:{JDURL}/org/eclipse/jetty/quickstart/PreconfigureQuickStartWar.html[`org.eclipse.jetty.quickstart.PreconfigureQuickStartWar`] class can be used to configure war files for quickstart deployment.
This will create the `quickstart-web.xml` before the first deployment.
====== In Code
Create an instance of link:{JDURL}/org/eclipse/jetty/quickstart/QuickStartWebApp.html[`org.eclipse.jetty.quickstart.QuickStartWebApp`] rather than the normal `org.eclipse.jetty.webapp.WebAppContext`. You then use the QuickStartWebApp instance in exactly the same way that you would a WebAppContext.
Here's a snippet:
[source, java]
----
QuickStartWebApp webapp = new QuickStartWebApp();
webapp.setAutoPreconfigure(true);
----
====== Pre-generating the quickstart-web.xml file
Rather than use the `autoPreconfigure` feature of the QuickStartWebApp - which lazily generates the `quickstart-web.xml` file - you can eagerly pre-generate it for an existing war by invoking as a main class link:{JDURL}/org/eclipse/jetty/quickstart/PreconfigureQuickStartWar.html[`org.eclipse.jetty.quickstart.PreconfigureQuickStartWar`].
Note that you will need to provide all necessary jetty jars on the command line classpath.
This will unpack the war if necessary, and create the `quickstart-web.xml` before the first deployment:
[source, screen, subs="{sub-order}"]
----
$ java -cp [jetty classpath] org.eclipse.jetty.quickstart.PreconfigureQuickStartWar myapp.war
----
Run the class with no arguments to see other runtime options.
Alternatively, you could use the link:#get-up-and-running[Jetty Maven Plugin] goal link:#jetty-effective-web-xml[`jetty:effective-web-xml`]: this will generate quickstart information, but print it to stderr.
The goal provides a configuration option to save the output to a file, which you can then copy into your webapp's WEB-INF dir.
Note that as the Jetty Maven Plugin is a general tool for running webapps, it may have more jars on its classpath than are needed by your application, and thus may generate extra quickstart information: we recommend that you use this goal only as a quick guide to the type of information that quickstart generates.
// ==== Preconfiguring the web application
//
@ -81,14 +123,8 @@ This will create the `quickstart-web.xml` before the first deployment.
//
// It is also possible to preconfigure a war file manually by running the class link:{JDURL}/org/eclipse/jetty/quickstart/PreconfigureQuickStartWar.html[org.eclipse.jetty.quickstart.PreconfigureQuickStartWar] with the jetty-all-uber (aggregate) jar:
//
// [source, screen, subs="{sub-order}"]
// ----
// $ java -cp jetty-all-{VERSION}-uber.jar org.eclipse.jetty.quickstart.PreconfigureQuickStartWar myapp.war
// ----
//
// This will create the `quickstart-web.xml` file before the first deployment.
// Note that this can also be a good debugging tool for discovered configuration and if run with debug turned on the origin of every element is included in the `quickstart-web.xml` file.
// Run the class with no arguments to see other runtime options.
==== Avoiding TLD Scans with precompiled JSPs

View File

@ -0,0 +1,72 @@
[description]
Enables GCloud Datastore API and implementation
[Tags]
3rdparty
gcloud
[depends]
gcloud
jcl-api
jcl-impl
[files]
maven://com.google.cloud/google-cloud-datastore/0.3.0|lib/gcloud/google-cloud-datastore-0.3.0.jar
maven://com.google.cloud/google-cloud-core/0.3.0|lib/gcloud/google-cloud-core-0.3.0.jar
maven://com.google.auth/google-auth-library-credentials/0.3.1|lib/gcloud/google-auth-library-credentials-0.3.1.jar
maven://com.google.auth/google-auth-library-oauth2-http/0.3.1|lib/gcloud/google-auth-library-oauth2-http-0.3.1.jar
maven://com.google.http-client/google-http-client-jackson2/1.19.0|lib/gcloud/google-http-client-jackson2-1.19.0.jar
maven://com.fasterxml.jackson.core/jackson-core/2.1.3|lib/gcloud/jackson-core-2.1.3.jar
maven://com.google.http-client/google-http-client/1.21.0|lib/gcloud/google-http-client-1.21.0.jar
maven://com.google.code.findbugs/jsr305/1.3.9|lib/gcloud/jsr305-1.3.9.jar
maven://org.apache.httpcomponents/httpclient/4.0.1|lib/gcloud/httpclient-4.0.1.jar
maven://org.apache.httpcomponents/httpcore/4.0.1|lib/gcloud/httpcore-4.0.1.jar
maven://commons-codec/commons-codec/1.3|lib/gcloud/commons-codec-1.3.jar
maven://com.google.oauth-client/google-oauth-client/1.21.0|lib/gcloud/google-oauth-client-1.21.0.jar
maven://com.google.guava/guava/19.0|lib/gcloud/guava-19.0.jar
maven://com.google.api-client/google-api-client-appengine/1.21.0|lib/gcloud/google-api-client-appengine-1.21.0.jar
maven://com.google.oauth-client/google-oauth-client-appengine/1.21.0|lib/gcloud/google-oauth-client-appengine-1.21.0.jar
maven://com.google.oauth-client/google-oauth-client-servlet/1.21.0|lib/gcloud/google-oauth-client-servlet-1.21.0.jar
maven://com.google.http-client/google-http-client-jdo/1.21.0|lib/gcloud/google-http-client-jdo-1.21.0.jar
maven://com.google.api-client/google-api-client-servlet/1.21.0|lib/gcloud/google-api-client-servlet-1.21.0.jar
maven://javax.jdo/jdo2-api/2.3-eb|lib/gcloud/jdo2-api-2.3-eb.jar
maven://javax.transaction/transaction-api/1.1|lib/gcloud/transaction-api-1.1.jar
maven://com.google.http-client/google-http-client-appengine/1.21.0|lib/gcloud/google-http-client-appengine-1.21.0.jar
maven://com.google.http-client/google-http-client-jackson/1.21.0|lib/gcloud/google-http-client-jackson-1.21.0.jar
maven://org.codehaus.jackson/jackson-core-asl/1.9.11|lib/gcloud/jackson-core-asl-1.9.11.jar
maven://joda-time/joda-time/2.9.2|lib/gcloud/joda-time-2.9.2.jar
maven://com.google.protobuf/protobuf-java/3.0.0-beta-3|lib/gcloud/protobuf-java-3.0.0-beta-3.jar
maven://com.google.api/gax/0.0.16|lib/gcloud/gax-0.0.16.jar
maven://io.grpc/grpc-all/0.15.0|lib/gcloud/grpc-all-0.15.0.jar
maven://io.grpc/grpc-auth/0.15.0|lib/gcloud/grpc-auth-0.15.0.jar
maven://io.grpc/grpc-netty/0.15.0|lib/gcloud/grpc-netty-0.15.0.jar
maven://io.netty/netty-codec-http2/4.1.1.Final|lib/gcloud/netty-codec-http2-4.1.1.jar
maven://io.netty/netty-codec-http/4.1.1.Final|lib/gcloud/netty-codec-http-4.1.1.Final.jar
maven://io.netty/netty-codec/4.1.1.Final|lib/gcloud/netty-codec-4.1.1.Final.jar
maven://io.netty/netty-handler/4.1.1.Final|lib/gcloud/netty-handler-4.1.1.Final.jar
maven://io.netty/netty-buffer/4.1.1.Final|lib/gcloud/netty-buffer-4.1.1.Final.jar
maven://io.netty/netty-common/4.1.1.Final|lib/gcloud/netty-common-4.1.1.Final.jar
maven://io.netty/netty-transport/4.1.1.Final|lib/gcloud/netty-transport-4.1.1.Final.jar
maven://io.netty/netty-resolver/4.1.1.Final|lib/gcloud/netty-resolver-4.1.1.Final.jar
maven://io.grpc/grpc-okhttp/0.15.0|lib/gcloud/grpc-okhttp-0.15.0.jar
maven://com.squareup.okio/okio/1.6.0|lib/gcloud/okio-1.6.0.jar
maven://com.squareup.okhttp/okhttp/2.5.0|lib/gcloud/okhttp-2.5.0.jar
maven://io.grpc/grpc-protobuf-nano/0.15.0|lib/gcloud/grpc-protobuf-nano-0.15.0.jar
maven://com.google.protobuf.nano/protobuf-javanano/3.0.0-alpha-5|lib/gcloud/protobuf-javanano-3.0.0-alpha-5.jar
maven://io.grpc/grpc-stub/0.15.0|lib/gcloud/grpc-stub-0.15.0.jar
maven://io.grpc/grpc-protobuf/0.15.0|lib/gcloud/grpc-protobuf-0.15.0.jar
maven://com.google.protobuf/protobuf-java-util/3.0.0-beta-3|lib/gcloud/protobuf-java-util-3.0.0-beta-3.jar
maven://com.google.code.gson/gson/2.3|lib/gcloud/gson-2.3.jar
maven://io.grpc/grpc-protobuf-lite/0.15.0|lib/gcloud/grpc-protobuf-lite-0.15.0.jar
maven://io.grpc/grpc-core/0.15.0|lib/gcloud/grpc-core-0.15.0.jar
maven://com.google.auto.value/auto-value/1.1|lib/gcloud/auto-value-1.1.jar
maven://com.google.inject/guice/4.0|lib/gcloud/guice-4.0.jar
maven://javax.inject/javax.inject/1|lib/gcloud/javax.inject-1.jar
maven://aopalliance/aopalliance/1.0|lib/gcloud/aopalliance-1.0.jar
maven://com.google.api.grpc/grpc-google-common-protos/0.0.7|lib/gcloud/grpc-google-common-protos-0.0.7.jar
maven://org.json/json/20151123|lib/gcloud/json-20151123.jar
maven://com.google.cloud.datastore/datastore-v1-protos/1.0.1|lib/gcloud/datastore-v1-protos-1.0.1-beta.jar
maven://com.google.cloud.datastore/datastore-v1-proto-client/1.1.0|lib/gcloud/datastore-v1-proto-client-1.1.0.jar
maven://com.google.http-client/google-http-client-protobuf/1.20.0|lib/gcloud/google-http-client-protobuf-1.20.0.jar
maven://com.google.api-client/google-api-client/1.20.0|lib/gcloud/google-api-client-1.20.0.jar
maven://com.google.guava/guava-jdk5/13.0|lib/gcloud/guava-jdk5-13.0.jar

View File

@ -0,0 +1,18 @@
[description]
Control GCloud API classpath
[Tags]
3rdparty
gcloud
[lib]
lib/gcloud/*.jar
[license]
GCloudDatastore is an open source project hosted on Github and released under the Apache 2.0 license.
https://github.com/GoogleCloudPlatform/gcloud-java
http://www.apache.org/licenses/LICENSE-2.0.html
[ini-template]
## Hide the gcloud libraries from deployed webapps
jetty.webapp.addServerClasses,=file:${jetty.base}/lib/gcloud/

View File

@ -1,92 +1,28 @@
[description]
Enables GCloudDatastore session management.
[Tags]
session
gcloud
[provides]
session-store
[depends]
gcloud-datastore
annotations
webapp
sessions
jcl-api
jcl-impl
[files]
basehome:etc/sessions/gcloud/index.yaml|etc/index.yaml
maven://com.google.cloud/google-cloud-datastore/0.3.0|lib/gcloud/google-cloud-datastore-0.3.0.jar
maven://com.google.cloud/google-cloud-core/0.3.0|lib/gcloud/google-cloud-core-0.3.0.jar
maven://com.google.auth/google-auth-library-credentials/0.3.1|lib/gcloud/google-auth-library-credentials-0.3.1.jar
maven://com.google.auth/google-auth-library-oauth2-http/0.3.1|lib/gcloud/google-auth-library-oauth2-http-0.3.1.jar
maven://com.google.http-client/google-http-client-jackson2/1.19.0|lib/gcloud/google-http-client-jackson2-1.19.0.jar
maven://com.fasterxml.jackson.core/jackson-core/2.1.3|lib/gcloud/jackson-core-2.1.3.jar
maven://com.google.http-client/google-http-client/1.21.0|lib/gcloud/google-http-client-1.21.0.jar
maven://com.google.code.findbugs/jsr305/1.3.9|lib/gcloud/jsr305-1.3.9.jar
maven://org.apache.httpcomponents/httpclient/4.0.1|lib/gcloud/httpclient-4.0.1.jar
maven://org.apache.httpcomponents/httpcore/4.0.1|lib/gcloud/httpcore-4.0.1.jar
maven://commons-codec/commons-codec/1.3|lib/gcloud/commons-codec-1.3.jar
maven://com.google.oauth-client/google-oauth-client/1.21.0|lib/gcloud/google-oauth-client-1.21.0.jar
maven://com.google.guava/guava/19.0|lib/gcloud/guava-19.0.jar
maven://com.google.api-client/google-api-client-appengine/1.21.0|lib/gcloud/google-api-client-appengine-1.21.0.jar
maven://com.google.oauth-client/google-oauth-client-appengine/1.21.0|lib/gcloud/google-oauth-client-appengine-1.21.0.jar
maven://com.google.oauth-client/google-oauth-client-servlet/1.21.0|lib/gcloud/google-oauth-client-servlet-1.21.0.jar
maven://com.google.http-client/google-http-client-jdo/1.21.0|lib/gcloud/google-http-client-jdo-1.21.0.jar
maven://com.google.api-client/google-api-client-servlet/1.21.0|lib/gcloud/google-api-client-servlet-1.21.0.jar
maven://javax.jdo/jdo2-api/2.3-eb|lib/gcloud/jdo2-api-2.3-eb.jar
maven://javax.transaction/transaction-api/1.1|lib/gcloud/transaction-api-1.1.jar
maven://com.google.http-client/google-http-client-appengine/1.21.0|lib/gcloud/google-http-client-appengine-1.21.0.jar
maven://com.google.http-client/google-http-client-jackson/1.21.0|lib/gcloud/google-http-client-jackson-1.21.0.jar
maven://org.codehaus.jackson/jackson-core-asl/1.9.11|lib/gcloud/jackson-core-asl-1.9.11.jar
maven://joda-time/joda-time/2.9.2|lib/gcloud/joda-time-2.9.2.jar
maven://com.google.protobuf/protobuf-java/3.0.0-beta-3|lib/gcloud/protobuf-java-3.0.0-beta-3.jar
maven://com.google.api/gax/0.0.16|lib/gcloud/gax-0.0.16.jar
maven://io.grpc/grpc-all/0.15.0|lib/gcloud/grpc-all-0.15.0.jar
maven://io.grpc/grpc-auth/0.15.0|lib/gcloud/grpc-auth-0.15.0.jar
maven://io.grpc/grpc-netty/0.15.0|lib/gcloud/grpc-netty-0.15.0.jar
maven://io.netty/netty-codec-http2/4.1.1.Final|lib/gcloud/netty-codec-http2-4.1.1.jar
maven://io.netty/netty-codec-http/4.1.1.Final|lib/gcloud/netty-codec-http-4.1.1.Final.jar
maven://io.netty/netty-codec/4.1.1.Final|lib/gcloud/netty-codec-4.1.1.Final.jar
maven://io.netty/netty-handler/4.1.1.Final|lib/gcloud/netty-handler-4.1.1.Final.jar
maven://io.netty/netty-buffer/4.1.1.Final|lib/gcloud/netty-buffer-4.1.1.Final.jar
maven://io.netty/netty-common/4.1.1.Final|lib/gcloud/netty-common-4.1.1.Final.jar
maven://io.netty/netty-transport/4.1.1.Final|lib/gcloud/netty-transport-4.1.1.Final.jar
maven://io.netty/netty-resolver/4.1.1.Final|lib/gcloud/netty-resolver-4.1.1.Final.jar
maven://io.grpc/grpc-okhttp/0.15.0|lib/gcloud/grpc-okhttp-0.15.0.jar
maven://com.squareup.okio/okio/1.6.0|lib/gcloud/okio-1.6.0.jar
maven://com.squareup.okhttp/okhttp/2.5.0|lib/gcloud/okhttp-2.5.0.jar
maven://io.grpc/grpc-protobuf-nano/0.15.0|lib/gcloud/grpc-protobuf-nano-0.15.0.jar
maven://com.google.protobuf.nano/protobuf-javanano/3.0.0-alpha-5|lib/gcloud/protobuf-javanano-3.0.0-alpha-5.jar
maven://io.grpc/grpc-stub/0.15.0|lib/gcloud/grpc-stub-0.15.0.jar
maven://io.grpc/grpc-protobuf/0.15.0|lib/gcloud/grpc-protobuf-0.15.0.jar
maven://com.google.protobuf/protobuf-java-util/3.0.0-beta-3|lib/gcloud/protobuf-java-util-3.0.0-beta-3.jar
maven://com.google.code.gson/gson/2.3|lib/gcloud/gson-2.3.jar
maven://io.grpc/grpc-protobuf-lite/0.15.0|lib/gcloud/grpc-protobuf-lite-0.15.0.jar
maven://io.grpc/grpc-core/0.15.0|lib/gcloud/grpc-core-0.15.0.jar
maven://com.google.auto.value/auto-value/1.1|lib/gcloud/auto-value-1.1.jar
maven://com.google.inject/guice/4.0|lib/gcloud/guice-4.0.jar
maven://javax.inject/javax.inject/1|lib/gcloud/javax.inject-1.jar
maven://aopalliance/aopalliance/1.0|lib/gcloud/aopalliance-1.0.jar
maven://com.google.api.grpc/grpc-google-common-protos/0.0.7|lib/gcloud/grpc-google-common-protos-0.0.7.jar
maven://org.json/json/20151123|lib/gcloud/json-20151123.jar
maven://com.google.cloud.datastore/datastore-v1-protos/1.0.1|lib/gcloud/datastore-v1-protos-1.0.1-beta.jar
maven://com.google.cloud.datastore/datastore-v1-proto-client/1.1.0|lib/gcloud/datastore-v1-proto-client-1.1.0.jar
maven://com.google.http-client/google-http-client-protobuf/1.20.0|lib/gcloud/google-http-client-protobuf-1.20.0.jar
maven://com.google.api-client/google-api-client/1.20.0|lib/gcloud/google-api-client-1.20.0.jar
maven://com.google.guava/guava-jdk5/13.0|lib/gcloud/guava-jdk5-13.0.jar
basehome:modules/gcloud/index.yaml|etc/index.yaml
[lib]
lib/jetty-gcloud-session-manager-${jetty.version}.jar
lib/gcloud/*.jar
[xml]
etc/sessions/gcloud/session-store.xml
[license]
GCloudDatastore is an open source project hosted on Github and released under the Apache 2.0 license.
https://github.com/GoogleCloudPlatform/gcloud-java
http://www.apache.org/licenses/LICENSE-2.0.html
[ini-template]
## GCloudDatastore Session config

View File

@ -808,6 +808,9 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore
{
//need to assume that the problem is the index doesn't exist, because there
//is no specific code for that
if (LOG.isDebugEnabled())
LOG.debug("Check for indexes", e);
return false;
}
}

View File

@ -13,7 +13,7 @@
<name>Jetty :: GCloud</name>
<properties>
<gcloud.version>0.3.0</gcloud.version>
<gcloud.version>0.4.0</gcloud.version>
</properties>
<modules>

View File

@ -1,6 +1,9 @@
[description]
Deploys the Hawtio console as a webapplication.
[Tags]
3rdparty
[depend]
stats
deploy
@ -13,6 +16,7 @@ etc/hawtio.xml
etc/hawtio/
lib/hawtio/
https://oss.sonatype.org/content/repositories/public/io/hawt/hawtio-default/1.4.16/hawtio-default-1.4.16.war|lib/hawtio/hawtio.war
basehome:modules/hawtio/hawtio.xml|etc/hawtio.xml
[license]
Hawtio is a redhat JBoss project released under the Apache License, v2.0

View File

@ -1,6 +1,9 @@
[description]
Deploys the JAMon webapplication
[Tags]
3rdparty
[depend]
stats
deploy
@ -14,6 +17,7 @@ etc/jamon.xml
lib/jamon/
maven://com.jamonapi/jamon/2.81|lib/jamon/jamon-2.81.jar
maven://com.jamonapi/jamon_war/2.81/war|lib/jamon/jamon.war
basehome:modules/jamon/jamon.xml|etc/jamon.xml
[lib]
lib/jamon/**.jar

View File

@ -1,6 +1,9 @@
[description]
Deploys the Jminix JMX Console within the server
[Tags]
3rdparty
[depend]
stats
jmx
@ -26,6 +29,7 @@ maven://commons-collections/commons-collections/3.2|lib/jminix/commons-collectio
maven://net.sf.ezmorph/ezmorph/1.0.6|lib/jminix/ezmorph-1.0.6.jar
maven://org.jgroups/jgroups/2.12.1.3.Final|lib/jminix/jgroups-2.12.1.3.Final.jar
maven://org.jasypt/jasypt/1.8|lib/jminix/jasypt-1.8.jar
basehome:modules/jminix/jminix.xml|etc/jminix.xml
[lib]
lib/jminix/**.jar

View File

@ -1,6 +1,9 @@
[description]
Deploys the Jolokia console as a web application.
[Tags]
3rdparty
[depend]
stats
deploy
@ -11,6 +14,7 @@ etc/jolokia.xml
[files]
maven://org.jolokia/jolokia-war/1.2.2/war|lib/jolokia/jolokia.war
basehome:modules/jolokia/jolokia.xml|etc/jolokia.xml
[license]
Jolokia is released under the Apache License 2.0

View File

@ -18,6 +18,11 @@
<artifactId>jetty-util</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.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>

View File

@ -0,0 +1,423 @@
//
// ========================================================================
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.http;
import java.nio.ByteBuffer;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import java.util.zip.ZipException;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.component.Destroyable;
/**
* Decoder for the "gzip" encoding.
* <p>
* A decoder that inflates gzip compressed data that has been
* optimized for async usage with minimal data copies.
*/
public class GZIPContentDecoder implements Destroyable
{
private final Inflater _inflater = new Inflater(true);
private final ByteBufferPool _pool;
private final int _bufferSize;
private State _state;
private int _size;
private int _value;
private byte _flags;
private ByteBuffer _inflated;
public GZIPContentDecoder()
{
this(null,2048);
}
public GZIPContentDecoder(int bufferSize)
{
this(null,bufferSize);
}
public GZIPContentDecoder(ByteBufferPool pool, int bufferSize)
{
_bufferSize = bufferSize;
_pool = pool;
reset();
}
/** Inflate compressed data from a buffer.
*
* @param compressed Buffer containing compressed data.
* @return Buffer containing inflated data.
*/
public ByteBuffer decode(ByteBuffer compressed)
{
decodeChunks(compressed);
if (BufferUtil.isEmpty(_inflated) || _state==State.CRC || _state==State.ISIZE )
return BufferUtil.EMPTY_BUFFER;
ByteBuffer result = _inflated;
_inflated = null;
return result;
}
/** Called when a chunk of data is inflated.
* <p>The default implementation aggregates all the chunks
* into a single buffer returned from {@link #decode(ByteBuffer)}.
* Derived implementations may choose to consume chunks individually
* and return false to prevent further inflation until a subsequent
* call to {@link #decode(ByteBuffer)} or {@link #decodeChunks(ByteBuffer)}.
*
* @param chunk The inflated chunk of data
* @return False if inflating should continue, or True if the call
* to {@link #decodeChunks(ByteBuffer)} or {@link #decode(ByteBuffer)}
* should return, allowing back pressure of compressed data.
*/
protected boolean decodedChunk(ByteBuffer chunk)
{
if (_inflated==null)
{
_inflated=chunk;
}
else
{
int size = _inflated.remaining() + chunk.remaining();
if (size<=_inflated.capacity())
{
BufferUtil.append(_inflated,chunk);
BufferUtil.put(chunk,_inflated);
release(chunk);
}
else
{
ByteBuffer bigger=acquire(size);
int pos=BufferUtil.flipToFill(bigger);
BufferUtil.put(_inflated,bigger);
BufferUtil.put(chunk,bigger);
BufferUtil.flipToFlush(bigger,pos);
release(_inflated);
release(chunk);
_inflated = bigger;
}
}
return false;
}
/**
* Inflate compressed data.
* <p>Inflation continues until the compressed block end is reached, there is no
* more compressed data or a call to {@link #decodedChunk(ByteBuffer)} returns true.
* @param compressed Buffer of compressed data to inflate
*/
protected void decodeChunks(ByteBuffer compressed)
{
ByteBuffer buffer = null;
try
{
while (true)
{
switch (_state)
{
case INITIAL:
{
_state = State.ID;
break;
}
case FLAGS:
{
if ((_flags & 0x04) == 0x04)
{
_state = State.EXTRA_LENGTH;
_size = 0;
_value = 0;
}
else if ((_flags & 0x08) == 0x08)
_state = State.NAME;
else if ((_flags & 0x10) == 0x10)
_state = State.COMMENT;
else if ((_flags & 0x2) == 0x2)
{
_state = State.HCRC;
_size = 0;
_value = 0;
}
else
{
_state = State.DATA;
continue;
}
break;
}
case DATA:
{
while (true)
{
if (buffer==null)
buffer = acquire(_bufferSize);
try
{
int length = _inflater.inflate(buffer.array(),buffer.arrayOffset(),buffer.capacity());
buffer.limit(length);
}
catch (DataFormatException x)
{
throw new ZipException(x.getMessage());
}
if (buffer.hasRemaining())
{
ByteBuffer chunk = buffer;
buffer = null;
if (decodedChunk(chunk))
return;
}
else if (_inflater.needsInput())
{
if (!compressed.hasRemaining())
return;
if (compressed.hasArray())
{
_inflater.setInput(compressed.array(),compressed.arrayOffset()+compressed.position(),compressed.remaining());
compressed.position(compressed.limit());
}
else
{
// TODO use the pool
byte[] input = new byte[compressed.remaining()];
compressed.get(input);
_inflater.setInput(input);
}
}
else if (_inflater.finished())
{
int remaining = _inflater.getRemaining();
compressed.position(compressed.limit() - remaining);
_state = State.CRC;
_size = 0;
_value = 0;
break;
}
}
continue;
}
default:
break;
}
if (!compressed.hasRemaining())
break;
byte currByte = compressed.get();
switch (_state)
{
case ID:
{
_value += (currByte & 0xFF) << 8 * _size;
++_size;
if (_size == 2)
{
if (_value != 0x8B1F)
throw new ZipException("Invalid gzip bytes");
_state = State.CM;
}
break;
}
case CM:
{
if ((currByte & 0xFF) != 0x08)
throw new ZipException("Invalid gzip compression method");
_state = State.FLG;
break;
}
case FLG:
{
_flags = currByte;
_state = State.MTIME;
_size = 0;
_value = 0;
break;
}
case MTIME:
{
// Skip the 4 MTIME bytes
++_size;
if (_size == 4)
_state = State.XFL;
break;
}
case XFL:
{
// Skip XFL
_state = State.OS;
break;
}
case OS:
{
// Skip OS
_state = State.FLAGS;
break;
}
case EXTRA_LENGTH:
{
_value += (currByte & 0xFF) << 8 * _size;
++_size;
if (_size == 2)
_state = State.EXTRA;
break;
}
case EXTRA:
{
// Skip EXTRA bytes
--_value;
if (_value == 0)
{
// Clear the EXTRA flag and loop on the flags
_flags &= ~0x04;
_state = State.FLAGS;
}
break;
}
case NAME:
{
// Skip NAME bytes
if (currByte == 0)
{
// Clear the NAME flag and loop on the flags
_flags &= ~0x08;
_state = State.FLAGS;
}
break;
}
case COMMENT:
{
// Skip COMMENT bytes
if (currByte == 0)
{
// Clear the COMMENT flag and loop on the flags
_flags &= ~0x10;
_state = State.FLAGS;
}
break;
}
case HCRC:
{
// Skip HCRC
++_size;
if (_size == 2)
{
// Clear the HCRC flag and loop on the flags
_flags &= ~0x02;
_state = State.FLAGS;
}
break;
}
case CRC:
{
_value += (currByte & 0xFF) << 8 * _size;
++_size;
if (_size == 4)
{
// From RFC 1952, compliant decoders need not to verify the CRC
_state = State.ISIZE;
_size = 0;
_value = 0;
}
break;
}
case ISIZE:
{
_value += (currByte & 0xFF) << 8 * _size;
++_size;
if (_size == 4)
{
if (_value != _inflater.getBytesWritten())
throw new ZipException("Invalid input size");
// TODO ByteBuffer result = output == null ? BufferUtil.EMPTY_BUFFER : ByteBuffer.wrap(output);
reset();
return ;
}
break;
}
default:
throw new ZipException();
}
}
}
catch (ZipException x)
{
throw new RuntimeException(x);
}
finally
{
if (buffer!=null)
release(buffer);
}
}
private void reset()
{
_inflater.reset();
_state = State.INITIAL;
_size = 0;
_value = 0;
_flags = 0;
}
@Override
public void destroy()
{
_inflater.end();
}
public boolean isFinished()
{
return _state == State.INITIAL;
}
private enum State
{
INITIAL, ID, CM, FLG, MTIME, XFL, OS, FLAGS, EXTRA_LENGTH, EXTRA, NAME, COMMENT, HCRC, DATA, CRC, ISIZE
}
/**
* @return An indirect buffer of the configured buffersize either from the pool or freshly allocated.
*/
public ByteBuffer acquire(int capacity)
{
return _pool==null?BufferUtil.allocate(capacity):_pool.acquire(capacity,false);
}
/**
* Release an allocated buffer.
* <p>This method will called {@link ByteBufferPool#release(ByteBuffer)} if a buffer pool has
* been configured. This method should be called once for all buffers returned from {@link #decode(ByteBuffer)}
* or passed to {@link #decodedChunk(ByteBuffer)}.
* @param buffer The buffer to release.
*/
public void release(ByteBuffer buffer)
{
if (_pool!=null && buffer!=BufferUtil.EMPTY_BUFFER)
_pool.release(buffer);
}
}

View File

@ -0,0 +1,343 @@
//
// ========================================================================
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.http;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import org.eclipse.jetty.io.ArrayByteBufferPool;
import org.eclipse.jetty.toolchain.test.TestTracker;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
public class GZIPContentDecoderTest
{
@Rule
public final TestTracker tracker = new TestTracker();
ArrayByteBufferPool pool;
AtomicInteger buffers = new AtomicInteger(0);
@Before
public void beforeClass() throws Exception
{
buffers.set(0);
pool = new ArrayByteBufferPool()
{
@Override
public ByteBuffer acquire(int size, boolean direct)
{
buffers.incrementAndGet();
return super.acquire(size,direct);
}
@Override
public void release(ByteBuffer buffer)
{
buffers.decrementAndGet();
super.release(buffer);
}
};
}
@After
public void afterClass() throws Exception
{
assertEquals(0,buffers.get());
}
@Test
public void testStreamNoBlocks() throws Exception
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.close();
byte[] bytes = baos.toByteArray();
GZIPInputStream input = new GZIPInputStream(new ByteArrayInputStream(bytes), 1);
int read = input.read();
assertEquals(-1, read);
}
@Test
public void testStreamBigBlockOneByteAtATime() throws Exception
{
String data = "0123456789ABCDEF";
for (int i = 0; i < 10; ++i)
data += data;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes = baos.toByteArray();
baos = new ByteArrayOutputStream();
GZIPInputStream input = new GZIPInputStream(new ByteArrayInputStream(bytes), 1);
int read;
while ((read = input.read()) >= 0)
baos.write(read);
assertEquals(data, new String(baos.toByteArray(), StandardCharsets.UTF_8));
}
@Test
public void testNoBlocks() throws Exception
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.close();
byte[] bytes = baos.toByteArray();
GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048);
ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes));
assertEquals(0, decoded.remaining());
}
@Test
public void testSmallBlock() throws Exception
{
String data = "0";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes = baos.toByteArray();
GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048);
ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes));
assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString());
decoder.release(decoded);
}
@Test
public void testSmallBlockWithGZIPChunkedAtBegin() throws Exception
{
String data = "0";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes = baos.toByteArray();
// The header is 10 bytes, chunk at 11 bytes
byte[] bytes1 = new byte[11];
System.arraycopy(bytes, 0, bytes1, 0, bytes1.length);
byte[] bytes2 = new byte[bytes.length - bytes1.length];
System.arraycopy(bytes, bytes1.length, bytes2, 0, bytes2.length);
GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048);
ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1));
assertEquals(0, decoded.capacity());
decoded = decoder.decode(ByteBuffer.wrap(bytes2));
assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString());
decoder.release(decoded);
}
@Test
public void testSmallBlockWithGZIPChunkedAtEnd() throws Exception
{
String data = "0";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes = baos.toByteArray();
// The trailer is 8 bytes, chunk the last 9 bytes
byte[] bytes1 = new byte[bytes.length - 9];
System.arraycopy(bytes, 0, bytes1, 0, bytes1.length);
byte[] bytes2 = new byte[bytes.length - bytes1.length];
System.arraycopy(bytes, bytes1.length, bytes2, 0, bytes2.length);
GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048);
ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1));
assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString());
assertFalse(decoder.isFinished());
decoder.release(decoded);
decoded = decoder.decode(ByteBuffer.wrap(bytes2));
assertEquals(0, decoded.remaining());
assertTrue(decoder.isFinished());
decoder.release(decoded);
}
@Test
public void testSmallBlockWithGZIPTrailerChunked() throws Exception
{
String data = "0";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes = baos.toByteArray();
// The trailer is 4+4 bytes, chunk the last 3 bytes
byte[] bytes1 = new byte[bytes.length - 3];
System.arraycopy(bytes, 0, bytes1, 0, bytes1.length);
byte[] bytes2 = new byte[bytes.length - bytes1.length];
System.arraycopy(bytes, bytes1.length, bytes2, 0, bytes2.length);
GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048);
ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1));
assertEquals(0, decoded.capacity());
decoder.release(decoded);
decoded = decoder.decode(ByteBuffer.wrap(bytes2));
assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString());
decoder.release(decoded);
}
@Test
public void testTwoSmallBlocks() throws Exception
{
String data1 = "0";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data1.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes1 = baos.toByteArray();
String data2 = "1";
baos = new ByteArrayOutputStream();
output = new GZIPOutputStream(baos);
output.write(data2.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes2 = baos.toByteArray();
byte[] bytes = new byte[bytes1.length + bytes2.length];
System.arraycopy(bytes1, 0, bytes, 0, bytes1.length);
System.arraycopy(bytes2, 0, bytes, bytes1.length, bytes2.length);
GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048);
ByteBuffer buffer = ByteBuffer.wrap(bytes);
ByteBuffer decoded = decoder.decode(buffer);
assertEquals(data1, StandardCharsets.UTF_8.decode(decoded).toString());
assertTrue(decoder.isFinished());
assertTrue(buffer.hasRemaining());
decoder.release(decoded);
decoded = decoder.decode(buffer);
assertEquals(data2, StandardCharsets.UTF_8.decode(decoded).toString());
assertTrue(decoder.isFinished());
assertFalse(buffer.hasRemaining());
decoder.release(decoded);
}
@Test
public void testBigBlock() throws Exception
{
String data = "0123456789ABCDEF";
for (int i = 0; i < 10; ++i)
data += data;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes = baos.toByteArray();
String result = "";
GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048);
ByteBuffer buffer = ByteBuffer.wrap(bytes);
while (buffer.hasRemaining())
{
ByteBuffer decoded = decoder.decode(buffer);
result += StandardCharsets.UTF_8.decode(decoded).toString();
decoder.release(decoded);
}
assertEquals(data, result);
}
@Test
public void testBigBlockOneByteAtATime() throws Exception
{
String data = "0123456789ABCDEF";
for (int i = 0; i < 10; ++i)
data += data;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes = baos.toByteArray();
String result = "";
GZIPContentDecoder decoder = new GZIPContentDecoder(64);
ByteBuffer buffer = ByteBuffer.wrap(bytes);
while (buffer.hasRemaining())
{
ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(new byte[]{buffer.get()}));
if (decoded.hasRemaining())
result += StandardCharsets.UTF_8.decode(decoded).toString();
decoder.release(decoded);
}
assertEquals(data, result);
assertTrue(decoder.isFinished());
}
@Test
public void testBigBlockWithExtraBytes() throws Exception
{
String data1 = "0123456789ABCDEF";
for (int i = 0; i < 10; ++i)
data1 += data1;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data1.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes1 = baos.toByteArray();
String data2 = "HELLO";
byte[] bytes2 = data2.getBytes(StandardCharsets.UTF_8);
byte[] bytes = new byte[bytes1.length + bytes2.length];
System.arraycopy(bytes1, 0, bytes, 0, bytes1.length);
System.arraycopy(bytes2, 0, bytes, bytes1.length, bytes2.length);
String result = "";
GZIPContentDecoder decoder = new GZIPContentDecoder(64);
ByteBuffer buffer = ByteBuffer.wrap(bytes);
while (buffer.hasRemaining())
{
ByteBuffer decoded = decoder.decode(buffer);
if (decoded.hasRemaining())
result += StandardCharsets.UTF_8.decode(decoded).toString();
decoder.release(decoded);
if (decoder.isFinished())
break;
}
assertEquals(data1, result);
assertTrue(buffer.hasRemaining());
assertEquals(data2, StandardCharsets.UTF_8.decode(buffer).toString());
}
}

View File

@ -118,6 +118,14 @@ public class SessionFailureTest extends AbstractTest
Assert.assertTrue(writeLatch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(serverFailureLatch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(clientFailureLatch.await(5, TimeUnit.SECONDS));
Assert.assertFalse(((HTTP2Session)session).getEndPoint().isOpen());
long start = System.nanoTime();
long now = System.nanoTime();
while (((HTTP2Session)session).getEndPoint().isOpen())
{
if (TimeUnit.NANOSECONDS.toSeconds(now-start)>5)
Assert.fail();
Thread.sleep(10);
now = System.nanoTime();
}
}
}

View File

@ -2,6 +2,12 @@
Enables HTTP2 protocol support on the TLS(SSL) Connector,
using the ALPN extension to select which protocol to use.
[Tags]
connector
http2
http
ssl
[depend]
ssl
alpn

View File

@ -2,6 +2,11 @@
Enables the HTTP2C protocol on the HTTP Connector
The connector will accept both HTTP/1 and HTTP/2 connections.
[Tags]
connector
http2
http
[depend]
http

View File

@ -1,6 +1,9 @@
[description]
Enables session data store in a local Infinispan cache
[Tags]
session
[provides]
session-store

View File

@ -1,6 +1,9 @@
[description]
Enables session data store in a remote Infinispan cache
[Tags]
session
[provides]
session-store

View File

@ -1,6 +1,9 @@
[description]
Memcache cache for SessionData
[Tags]
session
[depends]
session-store
slf4j-api

View File

@ -1,6 +1,9 @@
[description]
Enables NoSql session management with a MongoDB driver.
[Tags]
session
[provides]
session-store

View File

@ -18,11 +18,14 @@
package org.eclipse.jetty.osgi.annotations;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import org.eclipse.jetty.annotations.AnnotationParser.Handler;
import org.eclipse.jetty.annotations.ClassNameResolver;
import org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration;
import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
import org.eclipse.jetty.util.log.Log;
@ -44,9 +47,9 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot
public class BundleParserTask extends ParserTask
{
public BundleParserTask (AnnotationParser parser, Set<? extends Handler>handlers, Resource resource, ClassNameResolver resolver)
public BundleParserTask (AnnotationParser parser, Set<? extends Handler>handlers, Resource resource)
{
super(parser, handlers, resource, resolver);
super(parser, handlers, resource);
}
public Void call() throws Exception
@ -57,7 +60,7 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot
Bundle bundle = osgiAnnotationParser.getBundle(_resource);
if (_stat != null)
_stat.start();
osgiAnnotationParser.parse(_handlers, bundle, _resolver);
osgiAnnotationParser.parse(_handlers, bundle);
if (_stat != null)
_stat.end();
}
@ -79,6 +82,17 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot
return new AnnotationParser();
}
@Override
public Resource getJarFor(ServletContainerInitializer service) throws MalformedURLException, IOException
{
Resource resource = super.getJarFor(service);
// TODO This is not correct, but implemented like this to be bug for bug compatible
// with previous implementation that could only handle actual jars and not bundles.
if (resource!=null && !resource.toString().endsWith(".jar"))
return null;
return resource;
}
/**
* Here is the order in which jars and osgi artifacts are scanned for discoverable annotations.
* <ol>
@ -195,47 +209,13 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot
handlers.add(_classInheritanceHandler);
handlers.addAll(_containerInitializerAnnotationHandlers);
ClassNameResolver classNameResolver = createClassNameResolver(context);
if (_parserTasks != null)
{
BundleParserTask task = new BundleParserTask(parser, handlers, bundleRes, classNameResolver);
BundleParserTask task = new BundleParserTask(parser, handlers, bundleRes);
_parserTasks.add(task);
if (LOG.isDebugEnabled())
task.setStatistic(new TimeStatistic());
}
}
/**
* Returns the same classname resolver than for the webInfjar scanner
* @param context the web app context
* @return the class name resolver
*/
protected ClassNameResolver createClassNameResolver(final WebAppContext context)
{
return createClassNameResolver(context,true,false,false,false);
}
protected ClassNameResolver createClassNameResolver(final WebAppContext context,
final boolean excludeSysClass, final boolean excludeServerClass, final boolean excludeEverythingElse,
final boolean overrideIsParenLoaderIsPriority)
{
return new ClassNameResolver ()
{
public boolean isExcluded (String name)
{
if (context.isSystemClass(name)) return excludeSysClass;
if (context.isServerClass(name)) return excludeServerClass;
return excludeEverythingElse;
}
public boolean shouldOverride (String name)
{
//looking at system classpath
if (context.isParentLoaderPriority())
return overrideIsParenLoaderIsPriority;
return !overrideIsParenLoaderIsPriority;
}
};
}
}

View File

@ -29,7 +29,6 @@ import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jetty.annotations.ClassNameResolver;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.util.ConcurrentHashSet;
import org.eclipse.jetty.util.resource.Resource;
@ -85,7 +84,7 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa
*
*/
@Override
public void parse (Set<? extends Handler> handlers, URI[] uris, ClassNameResolver resolver)
public void parse (Set<? extends Handler> handlers, URI[] uris)
throws Exception
{
for (URI uri : uris)
@ -99,16 +98,16 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa
}
//a jar in WEB-INF/lib or the WEB-INF/classes
//use the behavior of the super class for a standard jar.
super.parse(handlers, new URI[] {uri},resolver);
super.parse(handlers, new URI[] {uri});
}
else
{
parse(handlers, associatedBundle,resolver);
parse(handlers, associatedBundle);
}
}
}
protected void parse(Set<? extends Handler> handlers, Bundle bundle, ClassNameResolver resolver)
protected void parse(Set<? extends Handler> handlers, Bundle bundle)
throws Exception
{
URI uri = _bundleToUri.get(bundle);
@ -205,7 +204,7 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa
}
//transform into a classname to pass to the resolver
String shortName = name.replace('/', '.').substring(0,name.length()-6);
if ((resolver == null) || (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
if (!isParsed(shortName))
{
try (InputStream classInputStream = classUrl.openStream())
{

View File

@ -47,18 +47,16 @@ public abstract class AbstractOSGiApp extends App
private static final Logger LOG = Log.getLogger(AbstractOSGiApp.class);
protected Bundle _bundle;
protected Dictionary _properties;
protected Dictionary<?,?> _properties;
protected ServiceRegistration _registration;
/* ------------------------------------------------------------ */
public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, String originId)
{
super(manager, provider, originId);
_properties = bundle.getHeaders();
_bundle = bundle;
this (manager, provider, bundle, bundle.getHeaders(), originId);
}
/* ------------------------------------------------------------ */
public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String originId)
public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary<?,?> properties, String originId)
{
super(manager, provider, originId);
_properties = properties;

View File

@ -38,6 +38,7 @@ import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.JarResource;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppClassLoader;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.xml.XmlConfiguration;
import org.osgi.framework.Bundle;
@ -436,18 +437,23 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement
}
}
}
if (contextXmlUrl == null) return;
if (contextXmlUrl == null)
return;
// Apply it just as the standard jetty ContextProvider would do
LOG.info("Applying " + contextXmlUrl + " to " + _webApp);
XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXmlUrl);
HashMap properties = new HashMap();
properties.put("Server", getDeploymentManager().getServer());
properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString());
properties.put(OSGiServerConstants.JETTY_HOME, getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME));
xmlConfiguration.getProperties().putAll(properties);
xmlConfiguration.configure(_webApp);
WebAppClassLoader.runWithServerClassAccess(()->
{
HashMap<String,String> properties = new HashMap<>();
xmlConfiguration.getIdMap().put("Server",getDeploymentManager().getServer());
properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString());
properties.put(OSGiServerConstants.JETTY_HOME, (String)getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME));
xmlConfiguration.getProperties().putAll(properties);
xmlConfiguration.configure(_webApp);
return null;
});
}
finally
{

View File

@ -175,7 +175,7 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund
String contextPath = null;
try
{
Dictionary headers = bundle.getHeaders();
Dictionary<String,String> headers = bundle.getHeaders();
//does the bundle have a OSGiWebappConstants.JETTY_WAR_FOLDER_PATH
String resourcePath = Util.getManifestHeaderValue(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH, OSGiWebappConstants.JETTY_WAR_RESOURCE_PATH, headers);
@ -217,7 +217,7 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund
{
//Could be a static webapp with no web.xml
String base = ".";
contextPath = (String)headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
contextPath = headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
String originId = getOriginId(bundle,base);
OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle, originId);

View File

@ -78,8 +78,6 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
private Bundle _contributor;
private boolean _lookInOsgiFirst = true;
/* ------------------------------------------------------------ */
/**
* @param parent The parent classloader.
@ -96,11 +94,26 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
}
/* ------------------------------------------------------------ */
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException
{
return super.loadClass(name);
try
{
return _osgiBundleClassLoader.loadClass(name);
}
catch (ClassNotFoundException cne)
{
try
{
return super.loadClass(name);
}
catch (ClassNotFoundException cne2)
{
throw cne;
}
}
}
/* ------------------------------------------------------------ */
@ -121,36 +134,18 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
{
Enumeration<URL> osgiUrls = _osgiBundleClassLoader.getResources(name);
Enumeration<URL> urls = super.getResources(name);
if (_lookInOsgiFirst)
{
return Collections.enumeration(toList(osgiUrls, urls));
}
else
{
return Collections.enumeration(toList(urls, osgiUrls));
}
List<URL> resources = toList(osgiUrls, urls);
return Collections.enumeration(resources);
}
/* ------------------------------------------------------------ */
@Override
public URL getResource(String name)
{
if (_lookInOsgiFirst)
{
URL url = _osgiBundleClassLoader.getResource(name);
return url != null ? url : super.getResource(name);
}
else
{
URL url = super.getResource(name);
return url != null ? url : _osgiBundleClassLoader.getResource(name);
}
URL url = _osgiBundleClassLoader.getResource(name);
return url != null ? url : super.getResource(name);
}
/* ------------------------------------------------------------ */
private List<URL> toList(Enumeration<URL> e, Enumeration<URL> e2)
{
@ -160,30 +155,7 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
while (e2 != null && e2.hasMoreElements())
list.add(e2.nextElement());
return list;
}
/* ------------------------------------------------------------ */
protected Class<?> findClass(String name) throws ClassNotFoundException
{
try
{
return _lookInOsgiFirst ? _osgiBundleClassLoader.loadClass(name) : super.findClass(name);
}
catch (ClassNotFoundException cne)
{
try
{
return _lookInOsgiFirst ? super.findClass(name) : _osgiBundleClassLoader.loadClass(name);
}
catch (ClassNotFoundException cne2)
{
throw cne;
}
}
}
}
/* ------------------------------------------------------------ */
/**

View File

@ -15,6 +15,8 @@
<Set name="minGzipSize"><Property name="jetty.gzip.minGzipSize" deprecated="gzip.minGzipSize" default="2048"/></Set>
<Set name="checkGzExists"><Property name="jetty.gzip.checkGzExists" deprecated="gzip.checkGzExists" default="false"/></Set>
<Set name="compressionLevel"><Property name="jetty.gzip.compressionLevel" deprecated="gzip.compressionLevel" default="-1"/></Set>
<Set name="inflateBufferSize"><Property name="jetty.gzip.inflateBufferSize" default="0/></Set>
<Set name="excludedAgentPatterns">
<Array type="String">
<Item><Property name="jetty.gzip.excludedUserAgent" deprecated="gzip.excludedUserAgent" default=".*MSIE.6\.0.*"/></Item>

View File

@ -12,7 +12,18 @@
<Arg>
<Ref refid="Server"/>
</Arg>
<Set name="workerName"><Property name="jetty.sessionIdManager.workerName"><Default>node<Env name="JETTY_WORKER_INSTANCE" default="0"/></Default></Property></Set>
<Set name="workerName">
<Property name="jetty.sessionIdManager.workerName">
<Default>node<Env name="JETTY_WORKER_INSTANCE">
<Default>
<Env name="GAE_MODULE_INSTANCE">
<Default>0</Default>
</Env>
</Default>
</Env>
</Default>
</Property>
</Set>
<!-- ===================================================================== -->
<!-- Configure a session housekeeper to help with scavenging -->

View File

@ -3,6 +3,9 @@ Enables the DebugListener to generate additional
logging regarding detailed request handling events.
Renames threads to include request URI.
[Tags]
debug
[depend]
deploy

View File

@ -2,6 +2,9 @@
Deprecated Debug Log using the DebugHandle.
Replaced with the debug module.
[Tags]
debug
[depend]
server

View File

@ -2,6 +2,9 @@
Adds all jar files discovered in $JETTY_HOME/lib/ext
and $JETTY_BASE/lib/ext to the servers classpath.
[Tags]
classpath
[lib]
lib/ext/**.jar

View File

@ -2,6 +2,9 @@
Enable GzipHandler for dynamic gzip compression
for the entire server.
[Tags]
handler
[depend]
server
@ -20,3 +23,6 @@ etc/jetty-gzip.xml
## User agents for which gzip is disabled
# jetty.gzip.excludedUserAgent=.*MSIE.6\.0.*
## Inflate request buffer size, or 0 for no request inflation
# jetty.gzip.inflateBufferSize=0

View File

@ -2,6 +2,9 @@
Adds a forwarded request customizer to the HTTP Connector
to process forwarded-for style headers from a proxy.
[Tags]
connector
[depend]
http

View File

@ -3,6 +3,10 @@ Enables a HTTP connector on the server.
By default HTTP/1 is support, but HTTP2C can
be added to the connector with the http2c module.
[Tags]
connector
http
[depend]
server

View File

@ -1,6 +1,12 @@
[description]
Adds HTTPS protocol support to the TLS(SSL) Connector
[Tags]
connector
https
http
ssl
[depend]
ssl

View File

@ -2,6 +2,9 @@
Enable the ipaccess handler to apply a white/black list
control of the remote IP of requests.
[Tags]
handler
[depend]
server

View File

@ -1,6 +1,7 @@
[description]
A noop module that creates an ini template useful for
setting JVM arguments (eg -Xmx )
[ini-template]
## JVM Configuration
## If JVM args are include in an ini file then --exec is needed
@ -16,7 +17,7 @@ setting JVM arguments (eg -Xmx )
# -XX:+CMSClassUnloadingEnabled
# -XX:+UseCMSCompactAtFullCollection
# -XX:CMSInitiatingOccupancyFraction=80
# -verbose:gc
# -internal:gc
# -XX:+PrintGCDateStamps
# -XX:+PrintGCTimeStamps
# -XX:+PrintGCDetails

View File

@ -1,6 +1,11 @@
[description]
Enables logback request log.
[Tags]
requestlog
logging
logback
[depend]
server
logback-core

View File

@ -5,6 +5,10 @@ This allows a Proxy operating in TCP mode to transport
details of the proxied connection to the server.
Both V1 and V2 versions of the protocol are supported.
[Tags]
connector
ssl
[depend]
ssl

View File

@ -1,6 +1,9 @@
[description]
Enables a NCSA style request log.
[Tags]
requestlog
[depend]
server
@ -36,4 +39,4 @@ logs/
# jetty.requestlog.timezone=GMT
## Whether to log LogLatency
# jetty.requestlog.loglatency=false
# jetty.requestlog.loglatency=false

View File

@ -3,6 +3,9 @@ Adds the $JETTY_HOME/resources and/or $JETTY_BASE/resources
directory to the server classpath. Useful for configuration
property files (eg jetty-logging.properties)
[Tags]
classpath
[lib]
resources/

View File

@ -4,6 +4,9 @@ If not enabled, sessions will use a HashSessionCache by default, so enabling
via this module is only needed if the configuration properties need to be
changed.
[Tags]
session
[provides]
session-cache

View File

@ -1,6 +1,9 @@
[description]
A trivial SessionCache that does not actually cache sessions.
[Tags]
session
[provides]
session-cache

View File

@ -1,6 +1,9 @@
[description]
Enables caching of SessionData in front of a SessionDataStore.
[Tags]
session
[depend]
session-store

View File

@ -1,6 +1,9 @@
[description]
Enables session persistent storage in files.
[Tags]
session
[provides]
session-store

View File

@ -1,6 +1,9 @@
[description]
Enables JDBC peristent/distributed session storage.
[Tags]
session
[provides]
session-store

View File

@ -5,6 +5,9 @@ created or by enabling other session-cache or session-store
modules. Without this module enabled, the server may still
use sessions, but their management cannot be configured.
[Tags]
session
[depends]
server

View File

@ -3,6 +3,10 @@ Enables a TLS(SSL) Connector on the server.
This may be used for HTTPS and/or HTTP2 by enabling
the associated support modules.
[Tags]
connector
ssl
[depend]
server

View File

@ -2,6 +2,9 @@
Enable detailed statistics collection for the server,
available via JMX.
[Tags]
handler
[depend]
server

View File

@ -3,6 +3,9 @@
# Applies ThreadLimiteHandler to entire server
#
[Tags]
handler
[depend]
server

View File

@ -37,25 +37,94 @@ import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.component.Destroyable;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.Invocable.InvocationType;
/**
* {@link HttpInput} provides an implementation of {@link ServletInputStream} for {@link HttpChannel}.
* <p>
* Content may arrive in patterns such as [content(), content(), messageComplete()] so that this class
* maintains two states: the content state that tells whether there is content to consume and the EOF
* state that tells whether an EOF has arrived.
* Only once the content has been consumed the content state is moved to the EOF state.
* Content may arrive in patterns such as [content(), content(), messageComplete()] so that this class maintains two states: the content state that tells
* whether there is content to consume and the EOF state that tells whether an EOF has arrived. Only once the content has been consumed the content state is
* moved to the EOF state.
*/
public class HttpInput extends ServletInputStream implements Runnable
{
/**
* An interceptor for HTTP Request input.
* <p>
* Unlike inputstream wrappers that can be applied by filters, an interceptor
* is entirely transparent and works with async IO APIs.
* <p>
* An Interceptor may consume data from the passed content and the interceptor
* will continue to be called for the same content until the interceptor returns
* null or an empty content. Thus even if the passed content is completely consumed
* the interceptor will be called with the same content until it can no longer
* produce more content.
* @see HttpInput#setInterceptor(Interceptor)
* @see HttpInput#addInterceptor(Interceptor)
*/
public interface Interceptor
{
/**
* @param content The content to be intercepted (may be empty or a {@link SentinelContent}.
* The content will be modified with any data the interceptor consumes, but there is no requirement
* that all the data is consumed by the interceptor.
* @return The intercepted content or null if interception is completed for that content.
*/
Content readFrom(Content content);
}
/**
* An {@link Interceptor} that chains two other {@link Interceptor}s together.
* The {@link #readFrom(Content)} calls the previous {@link Interceptor}'s
* {@link #readFrom(Content)} and then passes any {@link Content} returned
* to the next {@link Interceptor}.
*/
public static class ChainedInterceptor implements Interceptor, Destroyable
{
private final Interceptor _prev;
private final Interceptor _next;
public ChainedInterceptor(Interceptor prev, Interceptor next)
{
_prev = prev;
_next = next;
}
public Interceptor getPrev()
{
return _prev;
}
public Interceptor getNext()
{
return _next;
}
@Override
public Content readFrom(Content content)
{
return getNext().readFrom(getPrev().readFrom(content));
}
@Override
public void destroy()
{
if (_prev instanceof Destroyable)
((Destroyable)_prev).destroy();
if (_next instanceof Destroyable)
((Destroyable)_next).destroy();
}
}
private final static Logger LOG = Log.getLogger(HttpInput.class);
private final static Content EOF_CONTENT = new EofContent("EOF");
private final static Content EARLY_EOF_CONTENT = new EofContent("EARLY_EOF");
private final byte[] _oneByteBuffer = new byte[1];
private Content _content;
private Content _intercepted;
private final Deque<Content> _inputQ = new ArrayDeque<>();
private final HttpChannelState _channelState;
private ReadListener _listener;
@ -64,6 +133,7 @@ public class HttpInput extends ServletInputStream implements Runnable
private long _contentArrived;
private long _contentConsumed;
private long _blockUntil;
private Interceptor _interceptor;
public HttpInput(HttpChannelState state)
{
@ -79,6 +149,9 @@ public class HttpInput extends ServletInputStream implements Runnable
{
synchronized (_inputQ)
{
if (_content!=null)
_content.failed(null);
_content = null;
Content item = _inputQ.poll();
while (item != null)
{
@ -91,9 +164,42 @@ public class HttpInput extends ServletInputStream implements Runnable
_contentConsumed = 0;
_firstByteTimeStamp = -1;
_blockUntil = 0;
if (_interceptor instanceof Destroyable)
((Destroyable)_interceptor).destroy();
_interceptor = null;
}
}
/**
* @return The current Interceptor, or null if none set
*/
public Interceptor getInterceptor()
{
return _interceptor;
}
/**
* Set the interceptor.
* @param interceptor The interceptor to use.
*/
public void setInterceptor(Interceptor interceptor)
{
_interceptor = interceptor;
}
/**
* Set the {@link Interceptor}, using a {@link ChainedInterceptor} if
* an {@link Interceptor} is already set.
* @param interceptor the next {@link Interceptor} in a chain
*/
public void addInterceptor(Interceptor interceptor)
{
if (_interceptor == null)
_interceptor = interceptor;
else
_interceptor = new ChainedInterceptor(_interceptor,interceptor);
}
@Override
public int available()
{
@ -101,8 +207,9 @@ public class HttpInput extends ServletInputStream implements Runnable
boolean woken = false;
synchronized (_inputQ)
{
Content content = _inputQ.peek();
if (content == null)
if (_content == null)
_content = _inputQ.poll();
if (_content == null)
{
try
{
@ -112,11 +219,12 @@ public class HttpInput extends ServletInputStream implements Runnable
{
woken = failed(e);
}
content = _inputQ.peek();
if (_content == null)
_content = _inputQ.poll();
}
if (content != null)
available = remaining(content);
if (_content != null)
available = _content.remaining();
}
if (woken)
@ -139,10 +247,10 @@ public class HttpInput extends ServletInputStream implements Runnable
@Override
public int read() throws IOException
{
int read = read(_oneByteBuffer, 0, 1);
int read = read(_oneByteBuffer,0,1);
if (read == 0)
throw new IllegalStateException("unready read=0");
return read < 0 ? -1 : _oneByteBuffer[0] & 0xFF;
return read < 0?-1:_oneByteBuffer[0] & 0xFF;
}
@Override
@ -168,7 +276,7 @@ public class HttpInput extends ServletInputStream implements Runnable
{
long minimum_data = minRequestDataRate * TimeUnit.NANOSECONDS.toMillis(period) / TimeUnit.SECONDS.toMillis(1);
if (_contentArrived < minimum_data)
throw new BadMessageException(HttpStatus.REQUEST_TIMEOUT_408, String.format("Request data rate < %d B/s", minRequestDataRate));
throw new BadMessageException(HttpStatus.REQUEST_TIMEOUT_408,String.format("Request data rate < %d B/s",minRequestDataRate));
}
}
@ -177,11 +285,12 @@ public class HttpInput extends ServletInputStream implements Runnable
Content item = nextContent();
if (item != null)
{
int l = get(item, b, off, len);
int l = get(item,b,off,len);
if (LOG.isDebugEnabled())
LOG.debug("{} read {} from {}", this, l, item);
LOG.debug("{} read {} from {}",this,l,item);
consumeNonContent();
// Consume any following poison pills
pollReadableContent();
return l;
}
@ -193,191 +302,207 @@ public class HttpInput extends ServletInputStream implements Runnable
}
/**
* Called when derived implementations should attempt to
* produce more Content and add it via {@link #addContent(Content)}.
* For protocols that are constantly producing (eg HTTP2) this can
* be left as a noop;
* Called when derived implementations should attempt to produce more Content and add it via {@link #addContent(Content)}. For protocols that are constantly
* producing (eg HTTP2) this can be left as a noop;
*
* @throws IOException if unable to produce content
* @throws IOException
* if unable to produce content
*/
protected void produceContent() throws IOException
{
}
/**
* Get the next content from the inputQ, calling {@link #produceContent()}
* if need be. EOF is processed and state changed.
* Get the next content from the inputQ, calling {@link #produceContent()} if need be. EOF is processed and state changed.
*
* @return the content or null if none available.
* @throws IOException if retrieving the content fails
* @throws IOException
* if retrieving the content fails
*/
protected Content nextContent() throws IOException
{
Content content = pollContent();
Content content = pollNonEmptyContent();
if (content == null && !isFinished())
{
produceContent();
content = pollContent();
content = pollNonEmptyContent();
}
return content;
}
/**
* Poll the inputQ for Content.
* Consumed buffers and {@link PoisonPillContent}s are removed and
* EOF state updated if need be.
* Poll the inputQ for Content. Consumed buffers and {@link SentinelContent}s are removed and EOF state updated if need be.
*
* @return Content or null
*/
protected Content pollContent()
protected Content pollNonEmptyContent()
{
// Items are removed only when they are fully consumed.
Content content = _inputQ.peek();
// Skip consumed items at the head of the queue.
while (content != null && remaining(content) == 0)
{
_inputQ.poll();
content.succeeded();
if (LOG.isDebugEnabled())
LOG.debug("{} consumed {}", this, content);
if (content == EOF_CONTENT)
while (true)
{
// Get the next content (or EOF)
Content content = pollReadableContent();
// If it is EOF, consume it here
if (content instanceof SentinelContent)
{
if (_listener == null)
_state = EOF;
else
if (content == EARLY_EOF_CONTENT)
_state = EARLY_EOF;
else if (content instanceof EofContent)
{
_state = AEOF;
boolean woken = _channelState.onReadReady(); // force callback?
if (woken)
wake();
if (_listener == null)
_state = EOF;
else
{
_state = AEOF;
boolean woken = _channelState.onReadReady(); // force callback?
if (woken)
wake();
}
}
// Consume the EOF content, either if it was original content
// or if it was produced by interception
content.succeeded();
if (_content==content)
_content = null;
else if (_intercepted==content)
_intercepted = null;
continue;
}
else if (content == EARLY_EOF_CONTENT)
_state = EARLY_EOF;
content = _inputQ.peek();
return content;
}
return content;
}
/**
* Poll the inputQ for Content or EOF. Consumed buffers and non EOF {@link SentinelContent}s are removed. EOF state is not updated.
* Interception is done within this method.
* @return Content with remaining, a {@link SentinelContent}, or null
*/
protected void consumeNonContent()
protected Content pollReadableContent()
{
// Items are removed only when they are fully consumed.
Content content = _inputQ.peek();
// Skip consumed items at the head of the queue.
while (content != null && remaining(content) == 0)
// If we have a chunk produced by interception
if (_intercepted!=null)
{
// Defer EOF until read
if (content instanceof EofContent)
break;
// Consume all other empty content
_inputQ.poll();
content.succeeded();
if (LOG.isDebugEnabled())
LOG.debug("{} consumed {}", this, content);
content = _inputQ.peek();
// Use it if it has any remaining content
if (_intercepted.hasContent())
return _intercepted;
// succeed the chunk
_intercepted.succeeded();
_intercepted=null;
}
// If we don't have a Content under consideration, get
// the next one off the input Q.
if (_content == null)
_content = _inputQ.poll();
// While we have content to consider.
while (_content!=null)
{
// Are we intercepting?
if (_interceptor!=null)
{
// Intercept the current content (may be called several
// times for the same content
_intercepted = _interceptor.readFrom(_content);
// If interception produced new content
if (_intercepted!=null && _intercepted!=_content)
{
// if it is not empty use it
if (_intercepted.hasContent())
return _intercepted;
_intercepted.succeeded();
}
// intercepted content consumed
_intercepted=null;
// fall through so that the unintercepted _content is
// considered for any remaining content, for EOF and to
// succeed it if it is entirely consumed.
}
// If the content has content or is an EOF marker, use it
if (_content.hasContent() || _content instanceof SentinelContent)
return _content;
// The content is consumed, so get the next one. Note that EOF
// content is never consumed here, but in #pollContent
_content.succeeded();
_content = _inputQ.poll();
}
return null;
}
/**
* Get the next readable from the inputQ, calling {@link #produceContent()}
* if need be. EOF is NOT processed and state is not changed.
* Get the next readable from the inputQ, calling {@link #produceContent()} if need be. EOF is NOT processed and state is not changed.
*
* @return the content or EOF or null if none available.
* @throws IOException if retrieving the content fails
* @throws IOException
* if retrieving the content fails
*/
protected Content nextReadable() throws IOException
{
Content content = pollReadable();
Content content = pollReadableContent();
if (content == null && !isFinished())
{
produceContent();
content = pollReadable();
content = pollReadableContent();
}
return content;
}
/**
* Poll the inputQ for Content or EOF.
* Consumed buffers and non EOF {@link PoisonPillContent}s are removed.
* EOF state is not updated.
*
* @return Content, EOF or null
*/
protected Content pollReadable()
{
// Items are removed only when they are fully consumed.
Content content = _inputQ.peek();
// Skip consumed items at the head of the queue except EOF
while (content != null)
{
if (content == EOF_CONTENT || content == EARLY_EOF_CONTENT || remaining(content) > 0)
return content;
_inputQ.poll();
content.succeeded();
if (LOG.isDebugEnabled())
LOG.debug("{} consumed {}", this, content);
content = _inputQ.peek();
}
return null;
}
/**
* @param item the content
* @return how many bytes remain in the given content
*/
protected int remaining(Content item)
{
return item.remaining();
}
/**
* Copies the given content into the given byte buffer.
*
* @param content the content to copy from
* @param buffer the buffer to copy into
* @param offset the buffer offset to start copying from
* @param length the space available in the buffer
* @param content
* the content to copy from
* @param buffer
* the buffer to copy into
* @param offset
* the buffer offset to start copying from
* @param length
* the space available in the buffer
* @return the number of bytes actually copied
*/
protected int get(Content content, byte[] buffer, int offset, int length)
{
int l = Math.min(content.remaining(), length);
content.getContent().get(buffer, offset, l);
int l = content.get(buffer,offset,length);
_contentConsumed += l;
return l;
}
/**
* Consumes the given content.
* Calls the content succeeded if all content consumed.
* Consumes the given content. Calls the content succeeded if all content consumed.
*
* @param content the content to consume
* @param length the number of bytes to consume
* @param content
* the content to consume
* @param length
* the number of bytes to consume
*/
protected void skip(Content content, int length)
{
int l = Math.min(content.remaining(), length);
ByteBuffer buffer = content.getContent();
buffer.position(buffer.position() + l);
int l = content.skip(length);
_contentConsumed += l;
if (l > 0 && !content.hasContent())
pollContent(); // hungry succeed
if (l > 0 && content.isEmpty())
pollNonEmptyContent(); // hungry succeed
}
/**
* Blocks until some content or some end-of-file event arrives.
*
* @throws IOException if the wait is interrupted
* @throws IOException
* if the wait is interrupted
*/
protected void blockForContent() throws IOException
{
@ -392,7 +517,7 @@ public class HttpInput extends ServletInputStream implements Runnable
}
if (LOG.isDebugEnabled())
LOG.debug("{} blocking for content timeout={}", this, timeout);
LOG.debug("{} blocking for content timeout={}",this,timeout);
if (timeout > 0)
_inputQ.wait(timeout);
else
@ -402,7 +527,7 @@ public class HttpInput extends ServletInputStream implements Runnable
// TODO: so spurious wakeups are not handled correctly.
if (_blockUntil != 0 && TimeUnit.NANOSECONDS.toMillis(_blockUntil - System.nanoTime()) <= 0)
throw new TimeoutException(String.format("Blocking timeout %d ms", getBlockingTimeout()));
throw new TimeoutException(String.format("Blocking timeout %d ms",getBlockingTimeout()));
}
catch (Throwable e)
{
@ -412,11 +537,12 @@ public class HttpInput extends ServletInputStream implements Runnable
/**
* Adds some content to the start of this input stream.
* <p>Typically used to push back content that has
* been read, perhaps mutated. The bytes prepended are
* deducted for the contentConsumed total</p>
* <p>
* Typically used to push back content that has been read, perhaps mutated. The bytes prepended are deducted for the contentConsumed total
* </p>
*
* @param item the content to add
* @param item
* the content to add
* @return true if content channel woken for read
*/
public boolean prependContent(Content item)
@ -424,44 +550,54 @@ public class HttpInput extends ServletInputStream implements Runnable
boolean woken = false;
synchronized (_inputQ)
{
_inputQ.push(item);
if (_content != null)
_inputQ.push(_content);
_content = item;
_contentConsumed -= item.remaining();
if (LOG.isDebugEnabled())
LOG.debug("{} prependContent {}", this, item);
LOG.debug("{} prependContent {}",this,item);
if (_listener == null)
_inputQ.notify();
else
woken = _channelState.onReadPossible();
}
return woken;
}
/**
* Adds some content to this input stream.
*
* @param item the content to add
* @param content
* the content to add
* @return true if content channel woken for read
*/
public boolean addContent(Content item)
public boolean addContent(Content content)
{
boolean woken = false;
synchronized (_inputQ)
{
if (_firstByteTimeStamp == -1)
_firstByteTimeStamp = System.nanoTime();
_contentArrived += item.remaining();
_inputQ.offer(item);
if (LOG.isDebugEnabled())
LOG.debug("{} addContent {}", this, item);
if (_listener == null)
_inputQ.notify();
_contentArrived += content.remaining();
if (_content==null && _inputQ.isEmpty())
_content=content;
else
woken = _channelState.onReadPossible();
}
_inputQ.offer(content);
if (LOG.isDebugEnabled())
LOG.debug("{} addContent {}",this,content);
if (pollReadableContent()!=null)
{
if (_listener == null)
_inputQ.notify();
else
woken = _channelState.onReadPossible();
}
}
return woken;
}
@ -469,7 +605,7 @@ public class HttpInput extends ServletInputStream implements Runnable
{
synchronized (_inputQ)
{
return _inputQ.size() > 0;
return _content!=null || _inputQ.size() > 0;
}
}
@ -490,11 +626,9 @@ public class HttpInput extends ServletInputStream implements Runnable
}
/**
* This method should be called to signal that an EOF has been
* detected before all the expected content arrived.
* This method should be called to signal that an EOF has been detected before all the expected content arrived.
* <p>
* Typically this will result in an EOFException being thrown
* from a subsequent read rather than a -1 return.
* Typically this will result in an EOFException being thrown from a subsequent read rather than a -1 return.
*
* @return true if content channel woken for read
*/
@ -504,8 +638,7 @@ public class HttpInput extends ServletInputStream implements Runnable
}
/**
* This method should be called to signal that all the expected
* content arrived.
* This method should be called to signal that all the expected content arrived.
*
* @return true if content channel woken for read
*/
@ -526,7 +659,7 @@ public class HttpInput extends ServletInputStream implements Runnable
if (item == null)
break; // Let's not bother blocking
skip(item, remaining(item));
skip(item,item.remaining());
}
return isFinished() && !isError();
}
@ -641,11 +774,8 @@ public class HttpInput extends ServletInputStream implements Runnable
}
/*
* <p>
* While this class is-a Runnable, it should never be dispatched in it's own thread. It is a
* runnable only so that the calling thread can use {@link ContextHandler#handle(Runnable)}
* to setup classloaders etc.
* </p>
* <p> While this class is-a Runnable, it should never be dispatched in it's own thread. It is a runnable only so that the calling thread can use {@link
* ContextHandler#handle(Runnable)} to setup classloaders etc. </p>
*/
@Override
public void run()
@ -666,7 +796,7 @@ public class HttpInput extends ServletInputStream implements Runnable
}
listener = _listener;
error = _state instanceof ErrorState ? ((ErrorState)_state).getError() : null;
error = _state instanceof ErrorState?((ErrorState)_state).getError():null;
}
try
@ -721,19 +851,24 @@ public class HttpInput extends ServletInputStream implements Runnable
content = _inputQ.peekFirst();
}
return String.format("%s@%x[c=%d,q=%d,[0]=%s,s=%s]",
getClass().getSimpleName(),
hashCode(),
consumed,
q,
content,
state);
getClass().getSimpleName(),
hashCode(),
consumed,
q,
content,
state);
}
public static class PoisonPillContent extends Content
/**
* A Sentinel Content, which has zero length content but
* indicates some other event in the input stream (eg EOF)
*
*/
public static class SentinelContent extends Content
{
private final String _name;
public PoisonPillContent(String name)
public SentinelContent(String name)
{
super(BufferUtil.EMPTY_BUFFER);
_name = name;
@ -746,7 +881,7 @@ public class HttpInput extends ServletInputStream implements Runnable
}
}
public static class EofContent extends PoisonPillContent
public static class EofContent extends SentinelContent
{
EofContent(String name)
{
@ -756,22 +891,36 @@ public class HttpInput extends ServletInputStream implements Runnable
public static class Content implements Callback
{
private final ByteBuffer _content;
protected final ByteBuffer _content;
public Content(ByteBuffer content)
{
_content = content;
}
public ByteBuffer getByteBuffer()
{
return _content;
}
@Override
public InvocationType getInvocationType()
{
return InvocationType.NON_BLOCKING;
}
public ByteBuffer getContent()
public int get(byte[] buffer, int offset, int length)
{
return _content;
length = Math.min(_content.remaining(),length);
_content.get(buffer,offset,length);
return length;
}
public int skip(int length)
{
length = Math.min(_content.remaining(),length);
_content.position(_content.position() + length);
return length;
}
public boolean hasContent()
@ -783,15 +932,19 @@ public class HttpInput extends ServletInputStream implements Runnable
{
return _content.remaining();
}
public boolean isEmpty()
{
return !_content.hasRemaining();
}
@Override
public String toString()
{
return String.format("Content@%x{%s}", hashCode(), BufferUtil.toDetailString(_content));
return String.format("Content@%x{%s}",hashCode(),BufferUtil.toDetailString(_content));
}
}
protected static abstract class State
{
public boolean blockForContent(HttpInput in) throws IOException

View File

@ -175,9 +175,9 @@ public class HttpOutput extends ServletOutputStream implements Runnable
return _interceptor;
}
public void setInterceptor(Interceptor filter)
public void setInterceptor(Interceptor interceptor)
{
_interceptor = filter;
_interceptor = interceptor;
}
public boolean isWritten()

View File

@ -133,7 +133,7 @@ public class BufferedResponseHandler extends HandlerWrapper
}
// If not a supported method - no Vary because no matter what client, this URI is always excluded
if (!_methods.matches(baseRequest.getMethod()))
if (!_methods.test(baseRequest.getMethod()))
{
LOG.debug("{} excluded by method {}",this,request);
_handler.handle(target,baseRequest, request, response);
@ -173,7 +173,7 @@ public class BufferedResponseHandler extends HandlerWrapper
/* ------------------------------------------------------------ */
protected boolean isMimeTypeBufferable(String mimetype)
{
return _mimeTypes.matches(mimetype);
return _mimeTypes.test(mimetype);
}
/* ------------------------------------------------------------ */
@ -182,7 +182,7 @@ public class BufferedResponseHandler extends HandlerWrapper
if (requestURI == null)
return true;
return _paths.matches(requestURI);
return _paths.test(requestURI);
}
/* ------------------------------------------------------------ */

View File

@ -65,6 +65,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
private int _compressionLevel=Deflater.DEFAULT_COMPRESSION;
private boolean _checkGzExists = true;
private boolean _syncFlush = false;
private int _inflateBufferSize = -1;
// non-static, as other GzipHandler instances may have different configurations
private final ThreadLocal<Deflater> _deflater = new ThreadLocal<>();
@ -77,6 +78,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
private HttpField _vary;
/* ------------------------------------------------------------ */
/**
* Instantiates a new gzip handler.
@ -398,6 +400,24 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
return _vary;
}
/* ------------------------------------------------------------ */
/**
* @return size in bytes of the buffer to inflate compressed request, or 0 for no inflation.
*/
public int getInflateBufferSize()
{
return _inflateBufferSize;
}
/* ------------------------------------------------------------ */
/**
* @param size size in bytes of the buffer to inflate compressed request, or 0 for no inflation.
*/
public void setInflateBufferSize(int size)
{
_inflateBufferSize = size;
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.server.handler.HandlerWrapper#handle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
@ -409,6 +429,19 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
String path = context==null?baseRequest.getRequestURI():URIUtil.addPaths(baseRequest.getServletPath(),baseRequest.getPathInfo());
LOG.debug("{} handle {} in {}",this,baseRequest,context);
// Handle request inflation
if (_inflateBufferSize>0)
{
HttpField ce = baseRequest.getHttpFields().getField(HttpHeader.CONTENT_ENCODING);
if (ce!=null && "gzip".equalsIgnoreCase(ce.getValue()))
{
// TODO should check ce.contains and then remove just the gzip encoding
baseRequest.getHttpFields().remove(HttpHeader.CONTENT_ENCODING);
baseRequest.getHttpFields().add(new HttpField("X-Content-Encoding",ce.getValue()));
baseRequest.getHttpInput().addInterceptor(new GzipHttpInputInterceptor(baseRequest.getHttpChannel().getByteBufferPool(),_inflateBufferSize));
}
}
HttpOutput out = baseRequest.getResponse().getHttpOutput();
// Are we already being gzipped?
HttpOutput.Interceptor interceptor = out.getInterceptor();
@ -424,7 +457,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
}
// If not a supported method - no Vary because no matter what client, this URI is always excluded
if (!_methods.matches(baseRequest.getMethod()))
if (!_methods.test(baseRequest.getMethod()))
{
LOG.debug("{} excluded by method {}",this,request);
_handler.handle(target,baseRequest, request, response);
@ -516,14 +549,14 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
if (ua == null)
return false;
return _agentPatterns.matches(ua);
return _agentPatterns.test(ua);
}
/* ------------------------------------------------------------ */
@Override
public boolean isMimeTypeGzipable(String mimetype)
{
return _mimeTypes.matches(mimetype);
return _mimeTypes.test(mimetype);
}
/* ------------------------------------------------------------ */
@ -539,7 +572,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
if (requestURI == null)
return true;
return _paths.matches(requestURI);
return _paths.test(requestURI);
}
/* ------------------------------------------------------------ */

View File

@ -0,0 +1,88 @@
//
// ========================================================================
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.server.handler.gzip;
import java.nio.ByteBuffer;
import org.eclipse.jetty.http.GZIPContentDecoder;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.server.HttpInput;
import org.eclipse.jetty.server.HttpInput.Content;
import org.eclipse.jetty.util.component.Destroyable;
/**
* A HttpInput Interceptor that inflates GZIP encoded request content.
*/
public class GzipHttpInputInterceptor implements HttpInput.Interceptor, Destroyable
{
private final Decoder _decoder;
private ByteBuffer _chunk;
public GzipHttpInputInterceptor(ByteBufferPool pool, int bufferSize)
{
_decoder = new Decoder(pool, bufferSize);
}
@Override
public Content readFrom(Content content)
{
_decoder.decodeChunks(content.getByteBuffer());
final ByteBuffer chunk = _chunk;
if (chunk == null)
return null;
return new Content(chunk)
{
@Override
public void succeeded()
{
_decoder.release(chunk);
}
};
}
@Override
public void destroy()
{
_decoder.destroy();
}
private class Decoder extends GZIPContentDecoder
{
private Decoder(ByteBufferPool pool, int bufferSize)
{
super(pool, bufferSize);
}
@Override
protected boolean decodedChunk(final ByteBuffer chunk)
{
_chunk = chunk;
return true;
}
@Override
public void decodeChunks(ByteBuffer compressed)
{
_chunk = null;
super.decodeChunks(compressed);
}
}
}

View File

@ -336,9 +336,9 @@ public class DefaultSessionIdManager extends AbstractLifeCycle implements Sessio
{
String inst = System.getenv("JETTY_WORKER_INSTANCE");
_workerName = "node"+ (inst==null?"0":inst);
LOG.warn("No workerName configured for DefaultSessionIdManager, using {}",_workerName);
}
LOG.info("DefaultSessionIdManager workerName={}",_workerName);
_workerAttr=(_workerName!=null && _workerName.startsWith("$"))?_workerName.substring(1):null;
if (_houseKeeper == null)

View File

@ -354,6 +354,7 @@ public class AsyncRequestReadTest
for (int i=read;i-->0;)
{
int c=in.read();
// System.err.println("in="+c);
if (c<0)
break;
out.write(c);

View File

@ -0,0 +1,265 @@
//
// ========================================================================
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.server.ssl;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
import org.eclipse.jetty.util.thread.Scheduler;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
public class SslContextFactoryReloadTest
{
public static final String KEYSTORE_1 = "src/test/resources/reload_keystore_1.jks";
public static final String KEYSTORE_2 = "src/test/resources/reload_keystore_2.jks";
private Server server;
private SslContextFactory sslContextFactory;
private ServerConnector connector;
private void start(Handler handler) throws Exception
{
server = new Server();
sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath(KEYSTORE_1);
sslContextFactory.setKeyStorePassword("storepwd");
sslContextFactory.setKeyStoreType("JKS");
sslContextFactory.setKeyStoreProvider(null);
HttpConfiguration httpsConfig = new HttpConfiguration();
httpsConfig.addCustomizer(new SecureRequestCustomizer());
connector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
new HttpConnectionFactory(httpsConfig));
server.addConnector(connector);
server.setHandler(handler);
server.start();
}
@After
public void dispose() throws Exception
{
if (server != null)
server.stop();
}
@Test
public void testReload() throws Exception
{
start(new EchoHandler());
SSLContext ctx = SSLContext.getInstance("TLSv1.2");
ctx.init(null, SslContextFactory.TRUST_ALL_CERTS, null);
SSLSocketFactory socketFactory = ctx.getSocketFactory();
try (SSLSocket client1 = (SSLSocket)socketFactory.createSocket("localhost", connector.getLocalPort()))
{
String serverDN1 = client1.getSession().getPeerPrincipal().getName();
Assert.assertThat(serverDN1, Matchers.startsWith("CN=localhost1"));
String request = "" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n";
OutputStream output1 = client1.getOutputStream();
output1.write(request.getBytes(StandardCharsets.UTF_8));
output1.flush();
HttpTester.Response response1 = HttpTester.parseResponse(HttpTester.from(client1.getInputStream()));
Assert.assertNotNull(response1);
Assert.assertThat(response1.getStatus(), Matchers.equalTo(HttpStatus.OK_200));
// Reconfigure SslContextFactory.
sslContextFactory.reload(sslContextFactory ->
{
sslContextFactory.setKeyStorePath(KEYSTORE_2);
sslContextFactory.setKeyStorePassword("storepwd");
});
// New connection should use the new keystore.
try (SSLSocket client2 = (SSLSocket)socketFactory.createSocket("localhost", connector.getLocalPort()))
{
String serverDN2 = client2.getSession().getPeerPrincipal().getName();
Assert.assertThat(serverDN2, Matchers.startsWith("CN=localhost2"));
OutputStream output2 = client1.getOutputStream();
output2.write(request.getBytes(StandardCharsets.UTF_8));
output2.flush();
HttpTester.Response response2 = HttpTester.parseResponse(HttpTester.from(client1.getInputStream()));
Assert.assertNotNull(response2);
Assert.assertThat(response2.getStatus(), Matchers.equalTo(HttpStatus.OK_200));
}
// Must still be possible to make requests with the first connection.
output1.write(request.getBytes(StandardCharsets.UTF_8));
output1.flush();
response1 = HttpTester.parseResponse(HttpTester.from(client1.getInputStream()));
Assert.assertNotNull(response1);
Assert.assertThat(response1.getStatus(), Matchers.equalTo(HttpStatus.OK_200));
}
}
@Test
public void testReloadWhileServing() throws Exception
{
start(new EchoHandler());
Scheduler scheduler = new ScheduledExecutorScheduler();
scheduler.start();
try
{
SSLContext ctx = SSLContext.getInstance("TLSv1.2");
ctx.init(null, SslContextFactory.TRUST_ALL_CERTS, null);
SSLSocketFactory socketFactory = ctx.getSocketFactory();
// Perform 4 reloads while connections are being served.
AtomicInteger reloads = new AtomicInteger(4);
long reloadPeriod = 500;
AtomicBoolean running = new AtomicBoolean(true);
scheduler.schedule(new Runnable()
{
@Override
public void run()
{
if (reloads.decrementAndGet() == 0)
{
running.set(false);
}
else
{
try
{
sslContextFactory.reload(sslContextFactory ->
{
if (sslContextFactory.getKeyStorePath().endsWith(KEYSTORE_1))
sslContextFactory.setKeyStorePath(KEYSTORE_2);
else
sslContextFactory.setKeyStorePath(KEYSTORE_1);
});
scheduler.schedule(this, reloadPeriod, TimeUnit.MILLISECONDS);
}
catch (Exception x)
{
running.set(false);
reloads.set(-1);
}
}
}
}, reloadPeriod, TimeUnit.MILLISECONDS);
byte[] content = new byte[16 * 1024];
while (running.get())
{
try (SSLSocket client = (SSLSocket)socketFactory.createSocket("localhost", connector.getLocalPort()))
{
// We need to invalidate the session every time we open a new SSLSocket.
// This is because when the client uses session resumption, it caches
// the server certificates and then checks that it is the same during
// a new TLS handshake. If the SslContextFactory is reloaded during the
// TLS handshake, the client will see the new certificate and blow up.
// Note that browsers can handle this case better: they will just not
// use session resumption and fallback to the normal TLS handshake.
client.getSession().invalidate();
String request1 = "" +
"POST / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Content-Length: " + content.length + "\r\n" +
"\r\n";
OutputStream outputStream = client.getOutputStream();
outputStream.write(request1.getBytes(StandardCharsets.UTF_8));
outputStream.write(content);
outputStream.flush();
InputStream inputStream = client.getInputStream();
HttpTester.Response response1 = HttpTester.parseResponse(HttpTester.from(inputStream));
Assert.assertNotNull(response1);
Assert.assertThat(response1.getStatus(), Matchers.equalTo(HttpStatus.OK_200));
String request2 = "" +
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Connection: close\r\n" +
"\r\n";
outputStream.write(request2.getBytes(StandardCharsets.UTF_8));
outputStream.flush();
HttpTester.Response response2 = HttpTester.parseResponse(HttpTester.from(inputStream));
Assert.assertNotNull(response2);
Assert.assertThat(response2.getStatus(), Matchers.equalTo(HttpStatus.OK_200));
}
}
Assert.assertEquals(0, reloads.get());
}
finally
{
scheduler.stop();
}
}
private static class EchoHandler extends AbstractHandler
{
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
if (HttpMethod.POST.is(request.getMethod()))
IO.copy(request.getInputStream(), response.getOutputStream());
else
response.setContentLength(0);
}
}
}

Binary file not shown.

Binary file not shown.

View File

@ -33,8 +33,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
@ -45,6 +47,7 @@ import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.IO;
import org.hamcrest.Matchers;
import org.junit.After;
@ -86,6 +89,7 @@ public class GzipHandlerTest
GzipHandler gzipHandler = new GzipHandler();
gzipHandler.setExcludedAgentPatterns();
gzipHandler.setMinGzipSize(16);
gzipHandler.setInflateBufferSize(4096);
ServletContextHandler context = new ServletContextHandler(gzipHandler,"/ctx");
ServletHandler servlets = context.getServletHandler();
@ -97,6 +101,7 @@ public class GzipHandlerTest
servlets.addServletWithMapping(TestServlet.class,"/content");
servlets.addServletWithMapping(ForwardServlet.class,"/forward");
servlets.addServletWithMapping(IncludeServlet.class,"/include");
servlets.addServletWithMapping(EchoServlet.class,"/echo/*");
_server.start();
}
@ -147,6 +152,21 @@ public class GzipHandlerTest
}
}
}
public static class EchoServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType(req.getContentType());
IO.copy(req.getInputStream(),response.getOutputStream());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException
{
doGet(req,response);
}
}
public static class ForwardServlet extends HttpServlet
{
@ -392,4 +412,68 @@ public class GzipHandlerTest
assertThat("Included Paths.size", includedPaths.length, is(2));
assertThat("Included Paths", Arrays.asList(includedPaths), contains("/foo","^/bar.*$"));
}
@Test
public void testGzipRequest() throws Exception
{
String data = "Hello Nice World! ";
for (int i = 0; i < 10; ++i)
data += data;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes = baos.toByteArray();
// generated and parsed test
HttpTester.Request request = HttpTester.newRequest();
HttpTester.Response response;
request.setMethod("POST");
request.setURI("/ctx/echo");
request.setVersion("HTTP/1.0");
request.setHeader("Host","tester");
request.setHeader("Content-Type","text/plain");
request.setHeader("Content-Encoding","gzip");
request.setContent(bytes);
response = HttpTester.parseResponse(_connector.getResponse(request.generate()));
assertThat(response.getStatus(),is(200));
assertThat(response.getContent(),is(data));
}
@Test
public void testGzipBomb() throws Exception
{
byte[] data = new byte[512*1024];
Arrays.fill(data,(byte)'X');
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data);
output.close();
byte[] bytes = baos.toByteArray();
// generated and parsed test
HttpTester.Request request = HttpTester.newRequest();
HttpTester.Response response;
request.setMethod("POST");
request.setURI("/ctx/echo");
request.setVersion("HTTP/1.0");
request.setHeader("Host","tester");
request.setHeader("Content-Type","text/plain");
request.setHeader("Content-Encoding","gzip");
request.setContent(bytes);
response = HttpTester.parseResponse(_connector.getResponse(request.generate()));
// TODO need to test back pressure works
assertThat(response.getStatus(),is(200));
assertThat(response.getContentBytes().length,is(512*1024));
}
}

View File

@ -50,11 +50,10 @@ public class BaseBuilder
*
* @param module
* the module to add
* @return true if module was added, false if module was not added
* (because that module already exists)
* @return The ini file if module was added, null if module was not added.
* @throws IOException if unable to add the module
*/
public boolean addModule(Module module) throws IOException;
public String addModule(Module module) throws IOException;
}
private static final String EXITING_LICENSE_NOT_ACKNOWLEDGED = "Exiting: license not acknowledged!";
@ -181,7 +180,6 @@ public class BaseBuilder
if (!newly_added.isEmpty())
{
if (Files.exists(startini) && Files.exists(startd))
StartLog.warn("Use both %s and %s is deprecated",getBaseHome().toShortForm(startd),getBaseHome().toShortForm(startini));
@ -189,6 +187,7 @@ public class BaseBuilder
builder.set(useStartD?new StartDirBuilder(this):new StartIniBuilder(this));
newly_added.stream().map(n->modules.get(n)).forEach(module ->
{
String ini=null;
try
{
if (module.isSkipFilesValidation())
@ -197,8 +196,13 @@ public class BaseBuilder
}
else
{
if (builder.get().addModule(module))
modified.set(true);
// if (explictly added and ini file modified)
if (startArgs.getStartModules().contains(module.getName()))
{
ini=builder.get().addModule(module);
if (ini!=null)
modified.set(true);
}
for (String file : module.getFiles())
files.add(new FileArg(module,startArgs.getProperties().expand(file)));
}
@ -207,6 +211,26 @@ public class BaseBuilder
{
throw new RuntimeException(e);
}
if (module.isDynamic())
{
for (String s:module.getEnableSources())
StartLog.info("%-15s %s",module.getName(),s);
}
else if (module.isTransitive())
{
if (module.hasIniTemplate())
StartLog.info("%-15s transitively enabled, ini template available with --add-to-start=%s",
module.getName(),
module.getName());
else
StartLog.info("%-15s transitively enabled",module.getName());
}
else
StartLog.info("%-15s initialized in %s",
module.getName(),
ini);
});
}

View File

@ -243,16 +243,19 @@ public class Main
public void listModules(StartArgs args)
{
List<String> tags = args.getListModules();
StartLog.endStartLog();
System.out.println();
System.out.println("Jetty All Available Modules:");
System.out.println("----------------------------");
args.getAllModules().dump();
System.out.println("Available Modules:");
System.out.println("==================");
System.out.println("tags: "+tags);
args.getAllModules().dump(tags);
// Dump Enabled Modules
System.out.println();
System.out.println("Jetty Selected Module Ordering:");
System.out.println("-------------------------------");
System.out.println("Enabled Modules:");
System.out.println("================");
Modules modules = args.getAllModules();
modules.dumpEnabled();
}
@ -381,7 +384,7 @@ public class Main
}
// Show modules
if (args.isListModules())
if (args.getListModules()!=null)
{
listModules(args);
}

View File

@ -55,7 +55,7 @@ import java.util.stream.Collectors;
* A module may be enabled, either directly by name or transiently via a dependency
* from another module by name or provided capability.
*/
public class Module
public class Module implements Comparable<Module>
{
private static final String VERSION_UNSPECIFIED = "9.2";
private static Pattern MOD_NAME = Pattern.compile("^(.*)\\.mod",Pattern.CASE_INSENSITIVE);
@ -96,6 +96,9 @@ public class Module
/** List of provides for this Module */
private final Set<String> _provides=new HashSet<>();
/** List of tags for this Module */
private final List<String> _tags=new ArrayList<>();
/** Boolean true if directly enabled, false if all selections are transitive */
private boolean _notTransitive;
@ -328,6 +331,10 @@ public class Module
case "FILES":
_files.add(line);
break;
case "TAG":
case "TAGS":
_tags.add(line);
break;
case "DEFAULTS": // old name introduced in 9.2.x
case "INI": // new name for 9.3+
_defaultConfig.add(line);
@ -446,6 +453,16 @@ public class Module
return _description;
}
public List<String> getTags()
{
return _tags;
}
public String getPrimaryTag()
{
return _tags.isEmpty()?"*":_tags.get(0);
}
public boolean isEnabled()
{
return !_enables.isEmpty();
@ -504,4 +521,13 @@ public class Module
out.println();
out.flush();
}
@Override
public int compareTo(Module m)
{
int by_tag = getPrimaryTag().compareTo(m.getPrimaryTag());
if (by_tag!=0)
return by_tag;
return getName().compareTo(m.getName());
}
}

View File

@ -21,7 +21,6 @@ package org.eclipse.jetty.start;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@ -30,6 +29,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -57,59 +57,92 @@ public class Modules implements Iterable<Module>
}
}
public void dump()
public void dump(List<String> tags)
{
List<String> ordered = _modules.stream().map(m->{return m.getName();}).collect(Collectors.toList());
Collections.sort(ordered);
ordered.stream().map(n->{return get(n);}).forEach(module->
{
String status = "[ ]";
if (module.isTransitive())
Set<String> exclude = tags.stream().filter(t->t.startsWith("-")).map(t->t.substring(1)).collect(Collectors.toSet());
Set<String> include = tags.stream().filter(t->!t.startsWith("-")).collect(Collectors.toSet());
boolean all = include.contains("*") || include.isEmpty();
AtomicReference<String> tag = new AtomicReference<>();
_modules.stream()
.filter(m->
{
status = "[t]";
}
else if (module.isEnabled())
boolean included = all || m.getTags().stream().anyMatch(t->include.contains(t));
boolean excluded = m.getTags().stream().anyMatch(t->exclude.contains(t));
return included && !excluded;
})
.sorted()
.forEach(module->
{
status = "[x]";
}
System.out.printf("%n %s Module: %s%n",status,module.getName());
if (module.getProvides().size()>1)
{
System.out.printf(" Provides: %s%n",module.getProvides());
}
for (String description : module.getDescription())
{
System.out.printf(" : %s%n",description);
}
for (String parent : module.getDepends())
{
System.out.printf(" Depend: %s%n",parent);
}
for (String optional : module.getOptional())
{
System.out.printf(" Optional: %s%n",optional);
}
for (String lib : module.getLibs())
{
System.out.printf(" LIB: %s%n",lib);
}
for (String xml : module.getXmls())
{
System.out.printf(" XML: %s%n",xml);
}
for (String jvm : module.getJvmArgs())
{
System.out.printf(" JVM: %s%n",jvm);
}
if (module.isEnabled())
{
for (String selection : module.getEnableSources())
if (!module.getPrimaryTag().equals(tag.get()))
{
System.out.printf(" Enabled: %s%n",selection);
tag.set(module.getPrimaryTag());
System.out.printf("%nModules for tag '%s':%n",module.getPrimaryTag());
System.out.print("-------------------");
for (int i=module.getPrimaryTag().length();i-->0;)
System.out.print("-");
System.out.println();
}
}
});
String label;
Set<String> provides = module.getProvides();
provides.remove(module.getName());
System.out.printf("%n Module: %s %s%n",module.getName(),provides.size()>0?provides:"");
for (String description : module.getDescription())
{
System.out.printf(" : %s%n",description);
}
if (!module.getTags().isEmpty())
{
label=" Tags: %s";
for (String t : module.getTags())
{
System.out.printf(label,t);
label=", %s";
}
System.out.println();
}
if (!module.getDepends().isEmpty())
{
label=" Depend: %s";
for (String parent : module.getDepends())
{
System.out.printf(label,parent);
label=", %s";
}
System.out.println();
}
if (!module.getOptional().isEmpty())
{
label=" Optional: %s";
for (String parent : module.getOptional())
{
System.out.printf(label,parent);
label=", %s";
}
System.out.println();
}
for (String lib : module.getLibs())
{
System.out.printf(" LIB: %s%n",lib);
}
for (String xml : module.getXmls())
{
System.out.printf(" XML: %s%n",xml);
}
for (String jvm : module.getJvmArgs())
{
System.out.printf(" JVM: %s%n",jvm);
}
if (module.isEnabled())
{
for (String selection : module.getEnableSources())
{
System.out.printf(" Enabled: %s%n",selection);
}
}
});
}
public void dumpEnabled()
@ -125,6 +158,8 @@ public class Modules implements Iterable<Module>
index="";
name="";
}
if (module.isTransitive() && module.hasIniTemplate())
System.out.printf(" init template available with --add-to-start=%s%n",module.getName());
}
}
@ -279,9 +314,6 @@ public class Modules implements Iterable<Module>
m.expandProperties(_args.getProperties());
}
}
else if (module.isTransitive() && module.hasIniTemplate())
newlyEnabled.add(module.getName());
// Process module dependencies (always processed as may be dynamic)
for(String dependsOn:module.getDepends())
@ -318,7 +350,7 @@ public class Modules implements Iterable<Module>
// Is there an obvious default?
Optional<Module> dftProvider = providers.stream().filter(m->m.getName().equals(dependsOn)).findFirst();
if (dftProvider.isPresent())
enable(newlyEnabled,dftProvider.get(),"default provider of "+dependsOn+" for "+module.getName(),true);
enable(newlyEnabled,dftProvider.get(),"transitive provider of "+dependsOn+" for "+module.getName(),true);
else if (StartLog.isDebugEnabled())
StartLog.debug("Module %s requires %s from one of %s",module,dependsOn,providers);
}

View File

@ -170,7 +170,7 @@ public class StartArgs
private boolean help = false;
private boolean stopCommand = false;
private boolean listModules = false;
private List<String> listModules = null;
private boolean listClasspath = false;
private boolean listConfig = false;
private boolean version = false;
@ -364,7 +364,7 @@ public class StartArgs
}
else
{
System.out.printf(" %s = %s%n",key,properties.expand(prop.value));
System.out.printf(" %s = %s%n",key,prop.value);
if (StartLog.isDebugEnabled())
{
System.out.printf(" origin: %s%n",prop.origin);
@ -372,7 +372,7 @@ public class StartArgs
{
prop = prop.overrides;
System.out.printf(" (overrides)%n");
System.out.printf(" %s = %s%n",key,properties.expand(prop.value));
System.out.printf(" %s = %s%n",key,prop.value);
System.out.printf(" origin: %s%n",prop.origin);
}
}
@ -398,7 +398,7 @@ public class StartArgs
for (String key : sortedKeys)
{
String value = System.getProperty(key);
System.out.printf(" %s = %s%n",key,properties.expand(value));
System.out.printf(" %s = %s%n",key,value);
}
}
@ -750,7 +750,7 @@ public class StartArgs
return listConfig;
}
public boolean isListModules()
public List<String> getListModules()
{
return listModules;
}
@ -873,7 +873,7 @@ public class StartArgs
if (arg.equals("--create-files"))
{
run = false;
download = true;
download = true;boolean
licenseCheckRequired = true;
return;
}
@ -938,10 +938,25 @@ public class StartArgs
return;
}
// Module Management
if ("--list-all-modules".equals(arg))
{
listModules = Collections.singletonList("*");
run = false;
return;
}
// Module Management
if ("--list-modules".equals(arg))
{
listModules = true;
listModules = Collections.singletonList("-internal");
run = false;
return;
}
if (arg.startsWith("--list-modules="))
{
listModules = Props.getValues(arg);
run = false;
return;
}
@ -1035,13 +1050,33 @@ public class StartArgs
}
// Is this a raw property declaration?
int idx = arg.indexOf('=');
if (idx >= 0)
int equals = arg.indexOf('=');
if (equals >= 0)
{
String key = arg.substring(0,idx);
String value = arg.substring(idx + 1);
String key = arg.substring(0,equals);
String value = arg.substring(equals + 1);
if (replaceProps)
if (key.endsWith("+"))
{
key = key.substring(0,key.length()-1);
String orig = getProperties().getString(key);
if (orig != null && !orig.isEmpty())
{
value=orig+value;
source=propertySource.get(key)+","+source;
}
}
else if (key.endsWith(","))
{
key = key.substring(0,key.length()-1);
String orig = getProperties().getString(key);
if (orig != null && !orig.isEmpty())
{
value=value.isEmpty()?orig:(orig+","+value);
source=propertySource.get(key)+","+source;
}
}
else if (replaceProps)
{
if (propertySource.containsKey(key))
{
@ -1050,21 +1085,10 @@ public class StartArgs
propertySource.put(key,source);
}
if ("OPTION".equals(key) || "OPTIONS".equals(key))
{
StringBuilder warn = new StringBuilder();
warn.append("The behavior of the argument ");
warn.append(arg).append(" (seen in ").append(source);
warn.append(") has changed, and is now considered a normal property. ");
warn.append(key).append(" no longer controls what libraries are on your classpath,");
warn.append(" use --module instead. See --help for details.");
StartLog.warn(warn.toString());
}
setProperty(key,value,source,replaceProps);
return;
}
// Is this an xml file?
if (FS.isXml(arg))
{
@ -1169,7 +1193,9 @@ public class StartArgs
return;
}
if (replaceProp || (!properties.containsKey(key)))
if (value==null || value.isEmpty())
properties.remove(key,value,source);
else if (replaceProp || (!properties.containsKey(key)))
{
properties.setProperty(key,value,source);
if(key.equals("java.version"))

View File

@ -50,7 +50,7 @@ public class StartDirBuilder implements BaseBuilder.Config
}
@Override
public boolean addModule(Module module) throws IOException
public String addModule(Module module) throws IOException
{
if (module.isDynamic())
{
@ -59,28 +59,20 @@ public class StartDirBuilder implements BaseBuilder.Config
// warn
StartLog.warn("%-15s not adding [ini-template] from dynamic module",module.getName());
}
return false;
}
String mode = "";
if (module.isTransitive())
{
mode = "(transitively) ";
return null;
}
if (module.hasIniTemplate() || !module.isTransitive())
{
// Create start.d/{name}.ini
Path ini = startDir.resolve(module.getName() + ".ini");
StartLog.info("%-15s initialised %sin %s",module.getName(),mode,baseHome.toShortForm(ini));
try (BufferedWriter writer = Files.newBufferedWriter(ini,StandardCharsets.UTF_8,StandardOpenOption.CREATE,StandardOpenOption.TRUNCATE_EXISTING))
{
module.writeIniSection(writer);
}
return true;
return baseHome.toShortForm(ini);
}
return false;
return null;
}
}

View File

@ -21,7 +21,6 @@ package org.eclipse.jetty.start.builders;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@ -86,13 +85,13 @@ public class StartIniBuilder implements BaseBuilder.Config
}
@Override
public boolean addModule(Module module) throws IOException
public String addModule(Module module) throws IOException
{
if (modulesPresent.contains(module.getName()))
{
StartLog.info("%-15s already initialised in %s",module.getName(),baseHome.toShortForm(startIni));
// skip, already present
return false;
return null;
}
if (module.isDynamic())
@ -102,27 +101,19 @@ public class StartIniBuilder implements BaseBuilder.Config
// warn
StartLog.warn("%-15s not adding [ini-template] from dynamic module",module.getName());
}
return false;
}
String mode = "";
if (module.isTransitive())
{
mode = "(transitively) ";
return null;
}
if (module.hasIniTemplate() || !module.isTransitive())
{
StartLog.info("%-15s initialised %sin %s",module.getName(),mode,baseHome.toShortForm(startIni));
// Append to start.ini
try (BufferedWriter writer = Files.newBufferedWriter(startIni,StandardCharsets.UTF_8,StandardOpenOption.APPEND,StandardOpenOption.CREATE))
{
module.writeIniSection(writer);
}
return true;
return baseHome.toShortForm(startIni);
}
return false;
return null;
}
}

View File

@ -59,7 +59,7 @@ Debug and Start Logging:
Module Management:
------------------
--list-modules List all modules defined by the system.
--list-modules List non verbose modules defined by the system.
Looking for module files in ${jetty.base}/modules/*.mod and
then ${jetty.home}/modules/*.mod
Will also list enabled state based on information
@ -67,6 +67,13 @@ Module Management:
o The command line
o The ${jetty.base}/start.ini
o The ${jetty.base}/start.d/*.ini files
--list-modules=<tag>(,<tag>)*
List modules by tag. Use '*' for all tags. Prefix a tag
with '-' to exclude the tag.
--list-all-modules
List all modules.
--module=<modulename>(,<modulename>)*
Temporarily enable a module from the command line.
@ -140,6 +147,15 @@ Startup / Shutdown Command Line:
Properties:
name=value
Set a property that can be expanded in XML files with the <Property> element.
name+=value
Add to an existing property.
name,=value
Add to an existing property as a comma separated list.
STOP.HOST=[string]
The host to use to stop the running Jetty server (defaults to 127.0.0.1)
Required along with STOP.PORT if you want to use the --stop option above.

View File

@ -12,3 +12,5 @@ PROP|main.prop=value0
PROP|port=9090
PROP|other=value
PROP|jetty.http.port=9090
PROP|add=beginningmiddleend
PROP|list=one,two,three

View File

@ -1,2 +1,8 @@
other=value
port=9090
add+=beginning
add+=middle
add+=end
list,=one
list,=two
list,=three

View File

@ -14,7 +14,7 @@ LIB|${jetty.home}/lib/extra/extra1.jar
# The Properties we expect (order is irrelevant)
PROP|extra.prop=value0
PROP|main.prop=valueT
PROP|main.prop=value0
PROP|optional.prop=value0
# Files / Directories to create

View File

@ -14,12 +14,11 @@ LIB|${jetty.home}/lib/extra/extra1.jar
# The Properties we expect (order is irrelevant)
PROP|extra.prop=value0
PROP|main.prop=valueT
PROP|main.prop=value0
PROP|optional.prop=value0
# Files / Directories to create
EXISTS|maindir/
EXISTS|start.d/main.ini
EXISTS|start.d/extra.ini
EXISTS|start.d/optional.ini

View File

@ -14,12 +14,11 @@ LIB|${jetty.home}/lib/extra/extra1.jar
# The Properties we expect (order is irrelevant)
PROP|extra.prop=value0
PROP|main.prop=valueT
PROP|main.prop=value0
PROP|optional.prop=value0
# Files / Directories to create
EXISTS|maindir/
EXISTS|start.d/
EXISTS|start.d/main.ini
EXISTS|start.d/extra.ini
EXISTS|start.d/optional.ini

View File

@ -4,5 +4,8 @@ etc/t.xml
[optional]
main
[ini]
transient.option=transient
[ini-template]
transient.option=transient

View File

@ -4,6 +4,9 @@ by the Unix Domain Socket connector, for use when behind a proxy operating
in HTTP mode that adds forwarded-for style HTTP headers. Typically this
is an alternate to the Proxy Protocol used mostly for TCP mode.
[Tags]
connector
[depend]
unixsocket-http

View File

@ -4,6 +4,10 @@ It should be used when a proxy is forwarding either HTTP or decrypted
HTTPS traffic to the connector and may be used with the
unix-socket-http2c modules to upgrade to HTTP/2.
[Tags]
connector
http
[depend]
unixsocket

View File

@ -3,6 +3,10 @@ Adds a HTTP2C connetion factory to the Unix Domain Socket Connector
It can be used when either the proxy forwards direct
HTTP/2C (unecrypted) or decrypted HTTP/2 traffic.
[Tags]
connector
http2
[depend]
unixsocket-http

View File

@ -8,6 +8,9 @@ SSL properties may be interpreted by the unixsocket-secure
module to indicate secure HTTPS traffic. Typically this
is an alternate to the forwarded module.
[Tags]
connector
[depend]
unixsocket

View File

@ -5,6 +5,9 @@ This looks for a secure scheme transported either by the
unixsocket-forwarded, unixsocket-proxy-protocol or in a
HTTP2 request.
[Tags]
connector
[depend]
unixsocket-http

View File

@ -7,6 +7,9 @@ needless fragmentation and have better dispatch behaviours.
When enabled with corresponding support modules, the connector can
accept HTTP, HTTPS or HTTP2C traffic.
[Tags]
connector
[depend]
server

View File

@ -2,6 +2,11 @@
Provides a Java Commons Logging implementation.
To receive jetty logs the jetty-slf4j and slf4j-jcl must also be enabled.
[tags]
logging
jcl
internal
[depends]
[provides]

View File

@ -1,6 +1,11 @@
[description]
Provides a Java Commons Logging implementation that logs to the SLF4J API.
Requires another module that provides and SLF4J implementation.
Provides a Java Commons Logging (JCL) to SLF4J logging bridge.
[tags]
logging
jcl
slf4j
internal
[depends]
slf4j-api

View File

@ -1,9 +0,0 @@
[description]
Provides a Jetty Logging implementation that logs to the Java Util Logging API.
Requires another module that provides a Java Util Logging implementation.
[provide]
logging
[exec]
-Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.JavaUtilLog

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