Merge branch 'jetty-8' into release-8
This commit is contained in:
commit
e97838e9d4
|
@ -22,7 +22,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
|
||||
import org.eclipse.jetty.annotations.AnnotationParser.Value;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.webapp.DiscoveredAnnotation;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
|
@ -34,13 +34,32 @@ import org.eclipse.jetty.webapp.WebAppContext;
|
|||
public abstract class AbstractDiscoverableAnnotationHandler implements DiscoverableAnnotationHandler
|
||||
{
|
||||
protected WebAppContext _context;
|
||||
protected List<DiscoveredAnnotation> _annotations = new ArrayList<DiscoveredAnnotation>();
|
||||
protected List<DiscoveredAnnotation> _annotations;
|
||||
protected Resource _resource;
|
||||
|
||||
public AbstractDiscoverableAnnotationHandler(WebAppContext context)
|
||||
{
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public AbstractDiscoverableAnnotationHandler(WebAppContext context, List<DiscoveredAnnotation> list)
|
||||
{
|
||||
_context = context;
|
||||
if (list == null)
|
||||
_annotations = new ArrayList<DiscoveredAnnotation>();
|
||||
else
|
||||
_annotations = list;
|
||||
}
|
||||
|
||||
public Resource getResource()
|
||||
{
|
||||
return _resource;
|
||||
}
|
||||
|
||||
public void setResource(Resource resource)
|
||||
{
|
||||
_resource = resource;
|
||||
}
|
||||
|
||||
public List<DiscoveredAnnotation> getAnnotationList ()
|
||||
{
|
||||
|
|
|
@ -33,6 +33,7 @@ import javax.servlet.annotation.HandlesTypes;
|
|||
|
||||
import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
|
||||
import org.eclipse.jetty.plus.annotation.ContainerInitializer;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
@ -55,12 +56,22 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
private static final Logger LOG = Log.getLogger(AnnotationConfiguration.class);
|
||||
public static final String CLASS_INHERITANCE_MAP = "org.eclipse.jetty.classInheritanceMap";
|
||||
public static final String CONTAINER_INITIALIZERS = "org.eclipse.jetty.containerInitializers";
|
||||
|
||||
|
||||
protected List<DiscoverableAnnotationHandler> _discoverableAnnotationHandlers = new ArrayList<DiscoverableAnnotationHandler>();
|
||||
protected ClassInheritanceHandler _classInheritanceHandler;
|
||||
protected List<ContainerInitializerAnnotationHandler> _containerInitializerAnnotationHandlers = new ArrayList<ContainerInitializerAnnotationHandler>();
|
||||
|
||||
|
||||
public void preConfigure(final WebAppContext context) throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.webapp.AbstractConfiguration#configure(org.eclipse.jetty.webapp.WebAppContext)
|
||||
*/
|
||||
@Override
|
||||
public void configure(WebAppContext context) throws Exception
|
||||
{
|
||||
|
@ -75,10 +86,9 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
//If metadata isn't complete, if this is a servlet 3 webapp or isConfigDiscovered is true, we need to search for annotations
|
||||
if (context.getServletContext().getEffectiveMajorVersion() >= 3 || context.isConfigurationDiscovered())
|
||||
{
|
||||
parser = createAnnotationParser();
|
||||
parser.registerAnnotationHandler("javax.servlet.annotation.WebServlet", new WebServletAnnotationHandler(context));
|
||||
parser.registerAnnotationHandler("javax.servlet.annotation.WebFilter", new WebFilterAnnotationHandler(context));
|
||||
parser.registerAnnotationHandler("javax.servlet.annotation.WebListener", new WebListenerAnnotationHandler(context));
|
||||
_discoverableAnnotationHandlers.add(new WebServletAnnotationHandler(context));
|
||||
_discoverableAnnotationHandlers.add(new WebFilterAnnotationHandler(context));
|
||||
_discoverableAnnotationHandlers.add(new WebListenerAnnotationHandler(context));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -88,11 +98,11 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
|
||||
//Regardless of metadata, if there are any ServletContainerInitializers with @HandlesTypes, then we need to scan all the
|
||||
//classes so we can call their onStartup() methods correctly
|
||||
List<ServletContainerInitializer> nonExcludedInitializers = getNonExcludedInitializers(context);
|
||||
parser = registerServletContainerInitializerAnnotationHandlers(context, parser, nonExcludedInitializers);
|
||||
createServletContainerInitializerAnnotationHandlers(context, getNonExcludedInitializers(context));
|
||||
|
||||
if (parser != null)
|
||||
if (!_discoverableAnnotationHandlers.isEmpty() || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty())
|
||||
{
|
||||
parser = createAnnotationParser();
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Scanning all classses for annotations: webxmlVersion="+context.getServletContext().getEffectiveMajorVersion()+" configurationDiscovered="+context.isConfigurationDiscovered());
|
||||
parseContainerPath(context, parser);
|
||||
//email from Rajiv Mordani jsrs 315 7 April 2010
|
||||
|
@ -102,11 +112,39 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
// WEB-INF/classes + order of the elements.
|
||||
parseWebInfClasses(context, parser);
|
||||
parseWebInfLib (context, parser);
|
||||
|
||||
for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
|
||||
context.getMetaData().addDiscoveredAnnotations(((AbstractDiscoverableAnnotationHandler)h).getAnnotationList());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.webapp.AbstractConfiguration#postConfigure(org.eclipse.jetty.webapp.WebAppContext)
|
||||
*/
|
||||
@Override
|
||||
public void postConfigure(WebAppContext context) throws Exception
|
||||
{
|
||||
MultiMap map = (MultiMap)context.getAttribute(CLASS_INHERITANCE_MAP);
|
||||
if (map != null)
|
||||
map.clear();
|
||||
|
||||
context.removeAttribute(CLASS_INHERITANCE_MAP);
|
||||
|
||||
List<ContainerInitializer> initializers = (List<ContainerInitializer>)context.getAttribute(CONTAINER_INITIALIZERS);
|
||||
if (initializers != null)
|
||||
initializers.clear();
|
||||
if (_discoverableAnnotationHandlers != null)
|
||||
_discoverableAnnotationHandlers.clear();
|
||||
|
||||
_classInheritanceHandler = null;
|
||||
if (_containerInitializerAnnotationHandlers != null)
|
||||
_containerInitializerAnnotationHandlers.clear();
|
||||
|
||||
super.postConfigure(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a new AnnotationParser. This method can be overridden to use a different impleemntation of
|
||||
* the AnnotationParser. Note that this is considered internal API.
|
||||
|
@ -116,6 +154,9 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
return new AnnotationParser();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.webapp.AbstractConfiguration#cloneConfigure(org.eclipse.jetty.webapp.WebAppContext, org.eclipse.jetty.webapp.WebAppContext)
|
||||
*/
|
||||
@Override
|
||||
public void cloneConfigure(WebAppContext template, WebAppContext context) throws Exception
|
||||
{
|
||||
|
@ -123,32 +164,21 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public AnnotationParser registerServletContainerInitializerAnnotationHandlers (WebAppContext context, AnnotationParser parser, List<ServletContainerInitializer> scis)
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @param scis
|
||||
* @throws Exception
|
||||
*/
|
||||
public void createServletContainerInitializerAnnotationHandlers (WebAppContext context, List<ServletContainerInitializer> scis)
|
||||
throws Exception
|
||||
{
|
||||
|
||||
//TODO verify my interpretation of the spec. That is, that metadata-complete has nothing
|
||||
//to do with finding the ServletContainerInitializers, classes designated to be of interest to them,
|
||||
//or even calling them on startup.
|
||||
|
||||
//Get all ServletContainerInitializers, and check them for HandlesTypes annotations.
|
||||
//For each class in the HandlesTypes value, if it IS an annotation, register a handler
|
||||
//that will record the classes that have that annotation.
|
||||
//If it is NOT an annotation, then we will interrogate the type hierarchy discovered during
|
||||
//parsing later on to find the applicable classes.
|
||||
{
|
||||
|
||||
if (scis == null || scis.isEmpty())
|
||||
return parser; // nothing to do
|
||||
|
||||
ServletContainerInitializerListener listener = new ServletContainerInitializerListener();
|
||||
listener.setWebAppContext(context);
|
||||
context.addEventListener(listener);
|
||||
|
||||
//may need to add a listener
|
||||
return; // nothing to do
|
||||
|
||||
ArrayList<ContainerInitializer> initializers = new ArrayList<ContainerInitializer>();
|
||||
|
||||
List<ContainerInitializer> initializers = new ArrayList<ContainerInitializer>();
|
||||
context.setAttribute(CONTAINER_INITIALIZERS, initializers);
|
||||
|
||||
for (ServletContainerInitializer service : scis)
|
||||
|
@ -164,18 +194,14 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
if (classes != null)
|
||||
{
|
||||
initializer.setInterestedTypes(classes);
|
||||
|
||||
//We need to create a parser if we haven't already
|
||||
if (parser == null)
|
||||
parser = createAnnotationParser();
|
||||
|
||||
|
||||
//If we haven't already done so, we need to register a handler that will
|
||||
//process the whole class hierarchy
|
||||
//process the whole class hierarchy to satisfy the ServletContainerInitializer
|
||||
if (context.getAttribute(CLASS_INHERITANCE_MAP) == null)
|
||||
{
|
||||
ClassInheritanceHandler classHandler = new ClassInheritanceHandler();
|
||||
context.setAttribute(CLASS_INHERITANCE_MAP, classHandler.getMap());
|
||||
parser.registerClassHandler(classHandler);
|
||||
MultiMap map = new MultiMap();
|
||||
context.setAttribute(CLASS_INHERITANCE_MAP, map);
|
||||
_classInheritanceHandler = new ClassInheritanceHandler(map);
|
||||
}
|
||||
|
||||
for (Class c: classes)
|
||||
|
@ -186,7 +212,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
{
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Registering annotation handler for "+c.getName());
|
||||
|
||||
parser.registerAnnotationHandler(c.getName(), new ContainerInitializerAnnotationHandler(initializer, c));
|
||||
_containerInitializerAnnotationHandlers.add(new ContainerInitializerAnnotationHandler(initializer, c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -197,15 +223,15 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
if (LOG.isDebugEnabled()) LOG.debug("No annotation on initializer "+service.getClass());
|
||||
}
|
||||
|
||||
//return the parser in case we lazily created it
|
||||
return parser;
|
||||
|
||||
//add a listener which will call the servletcontainerinitializers when appropriate
|
||||
ServletContainerInitializerListener listener = new ServletContainerInitializerListener();
|
||||
listener.setWebAppContext(context);
|
||||
context.addEventListener(listener);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check to see if the ServletContainerIntializer loaded via the ServiceLoader came
|
||||
* from a jar that is excluded by the fragment ordering. See ServletSpec 3.0 p.85.
|
||||
|
@ -248,7 +274,12 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
|
||||
|
||||
|
||||
public List<ServletContainerInitializer> getNonExcludedInitializers (WebAppContext context)
|
||||
/**
|
||||
* @param context
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public List<ServletContainerInitializer> getNonExcludedInitializers (WebAppContext context)
|
||||
throws Exception
|
||||
{
|
||||
List<ServletContainerInitializer> nonExcludedInitializers = new ArrayList<ServletContainerInitializer>();
|
||||
|
@ -270,14 +301,29 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* Scan jars on container path.
|
||||
*
|
||||
* @param context
|
||||
* @param parser
|
||||
* @throws Exception
|
||||
*/
|
||||
public void parseContainerPath (final WebAppContext context, final AnnotationParser parser)
|
||||
throws Exception
|
||||
{
|
||||
//if no pattern for the container path is defined, then by default scan NOTHING
|
||||
LOG.debug("Scanning container jars");
|
||||
|
||||
//clear any previously discovered annotations
|
||||
clearAnnotationList(parser.getAnnotationHandlers());
|
||||
//always parse for discoverable annotations as well as class hierarchy and servletcontainerinitializer related annotations
|
||||
parser.clearHandlers();
|
||||
for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
|
||||
{
|
||||
if (h instanceof AbstractDiscoverableAnnotationHandler)
|
||||
((AbstractDiscoverableAnnotationHandler)h).setResource(null); //
|
||||
}
|
||||
parser.registerHandlers(_discoverableAnnotationHandlers);
|
||||
parser.registerHandler(_classInheritanceHandler);
|
||||
parser.registerHandlers(_containerInitializerAnnotationHandlers);
|
||||
|
||||
//Convert from Resource to URI
|
||||
ArrayList<URI> containerUris = new ArrayList<URI>();
|
||||
|
@ -304,16 +350,19 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
return true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//gather together all annotations discovered
|
||||
List<DiscoveredAnnotation> annotations = new ArrayList<DiscoveredAnnotation>();
|
||||
gatherAnnotations(annotations, parser.getAnnotationHandlers());
|
||||
|
||||
context.getMetaData().addDiscoveredAnnotations(annotations);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scan jars in WEB-INF/lib
|
||||
*
|
||||
* @param context
|
||||
* @param parser
|
||||
* @throws Exception
|
||||
*/
|
||||
public void parseWebInfLib (final WebAppContext context, final AnnotationParser parser)
|
||||
throws Exception
|
||||
{
|
||||
|
@ -332,17 +381,34 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
|
||||
for (Resource r : jars)
|
||||
{
|
||||
//clear any previously discovered annotations from handlers
|
||||
clearAnnotationList(parser.getAnnotationHandlers());
|
||||
|
||||
|
||||
//for each jar, we decide which set of annotations we need to parse for
|
||||
parser.clearHandlers();
|
||||
URI uri = r.getURI();
|
||||
FragmentDescriptor f = getFragmentFromJar(r, frags);
|
||||
|
||||
//if a jar has no web-fragment.xml we scan it (because it is not exluded by the ordering)
|
||||
//if its from a fragment jar that is metadata complete, we should skip scanning for @webservlet etc
|
||||
// but yet we still need to do the scanning for the classes on behalf of the servletcontainerinitializers
|
||||
//if a jar has no web-fragment.xml we scan it (because it is not excluded by the ordering)
|
||||
//or if it has a fragment we scan it if it is not metadata complete
|
||||
if (f == null || !isMetaDataComplete(f))
|
||||
if (f == null || !isMetaDataComplete(f) || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty())
|
||||
{
|
||||
//register the classinheritance handler if there is one
|
||||
parser.registerHandler(_classInheritanceHandler);
|
||||
|
||||
//register the handlers for the @HandlesTypes values that are themselves annotations if there are any
|
||||
parser.registerHandlers(_containerInitializerAnnotationHandlers);
|
||||
|
||||
//only register the discoverable annotation handlers if this fragment is not metadata complete, or has no fragment descriptor
|
||||
if (f == null || !isMetaDataComplete(f))
|
||||
{
|
||||
for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
|
||||
{
|
||||
if (h instanceof AbstractDiscoverableAnnotationHandler)
|
||||
((AbstractDiscoverableAnnotationHandler)h).setResource(r);
|
||||
}
|
||||
parser.registerHandlers(_discoverableAnnotationHandlers);
|
||||
}
|
||||
|
||||
parser.parse(uri,
|
||||
new ClassNameResolver()
|
||||
{
|
||||
|
@ -360,14 +426,18 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
return false;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
List<DiscoveredAnnotation> annotations = new ArrayList<DiscoveredAnnotation>();
|
||||
gatherAnnotations(annotations, parser.getAnnotationHandlers());
|
||||
context.getMetaData().addDiscoveredAnnotations(r, annotations);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan classes in WEB-INF/classes
|
||||
*
|
||||
* @param context
|
||||
* @param parser
|
||||
* @throws Exception
|
||||
*/
|
||||
public void parseWebInfClasses (final WebAppContext context, final AnnotationParser parser)
|
||||
throws Exception
|
||||
{
|
||||
|
@ -377,7 +447,16 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
Resource classesDir = context.getWebInf().addPath("classes/");
|
||||
if (classesDir.exists())
|
||||
{
|
||||
clearAnnotationList(parser.getAnnotationHandlers());
|
||||
parser.clearHandlers();
|
||||
for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
|
||||
{
|
||||
if (h instanceof AbstractDiscoverableAnnotationHandler)
|
||||
((AbstractDiscoverableAnnotationHandler)h).setResource(null); //
|
||||
}
|
||||
parser.registerHandlers(_discoverableAnnotationHandlers);
|
||||
parser.registerHandler(_classInheritanceHandler);
|
||||
parser.registerHandlers(_containerInitializerAnnotationHandlers);
|
||||
|
||||
parser.parse(classesDir,
|
||||
new ClassNameResolver()
|
||||
{
|
||||
|
@ -396,17 +475,20 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
//TODO - where to set the annotations discovered from WEB-INF/classes?
|
||||
List<DiscoveredAnnotation> annotations = new ArrayList<DiscoveredAnnotation>();
|
||||
gatherAnnotations(annotations, parser.getAnnotationHandlers());
|
||||
context.getMetaData().addDiscoveredAnnotations (annotations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the web-fragment.xml from a jar
|
||||
*
|
||||
* @param jar
|
||||
* @param frags
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public FragmentDescriptor getFragmentFromJar (Resource jar, List<FragmentDescriptor> frags)
|
||||
throws Exception
|
||||
{
|
||||
|
@ -428,25 +510,4 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
{
|
||||
return (d!=null && d.getMetaDataComplete() == MetaDataComplete.True);
|
||||
}
|
||||
|
||||
protected void clearAnnotationList (List<DiscoverableAnnotationHandler> handlers)
|
||||
{
|
||||
if (handlers == null)
|
||||
return;
|
||||
|
||||
for (DiscoverableAnnotationHandler h:handlers)
|
||||
{
|
||||
if (h instanceof AbstractDiscoverableAnnotationHandler)
|
||||
((AbstractDiscoverableAnnotationHandler)h).resetList();
|
||||
}
|
||||
}
|
||||
|
||||
protected void gatherAnnotations (List<DiscoveredAnnotation> annotations, List<DiscoverableAnnotationHandler> handlers)
|
||||
{
|
||||
for (DiscoverableAnnotationHandler h:handlers)
|
||||
{
|
||||
if (h instanceof AbstractDiscoverableAnnotationHandler)
|
||||
annotations.addAll(((AbstractDiscoverableAnnotationHandler)h).getAnnotationList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import java.util.Collection;
|
|||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.jar.JarEntry;
|
||||
|
||||
|
@ -53,11 +54,8 @@ public class AnnotationParser
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(AnnotationParser.class);
|
||||
|
||||
protected List<String> _parsedClassNames = new ArrayList<String>();
|
||||
protected Map<String, List<DiscoverableAnnotationHandler>> _annotationHandlers = new HashMap<String, List<DiscoverableAnnotationHandler>>();
|
||||
protected List<ClassHandler> _classHandlers = new ArrayList<ClassHandler>();
|
||||
protected List<MethodHandler> _methodHandlers = new ArrayList<MethodHandler>();
|
||||
protected List<FieldHandler> _fieldHandlers = new ArrayList<FieldHandler>();
|
||||
protected List<String> _parsedClassNames = new ArrayList<String>();
|
||||
protected List<Handler> _handlers = new ArrayList<Handler>();
|
||||
|
||||
public static String normalize (String name)
|
||||
{
|
||||
|
@ -168,37 +166,122 @@ public class AnnotationParser
|
|||
|
||||
|
||||
|
||||
public interface DiscoverableAnnotationHandler
|
||||
/**
|
||||
* Handler
|
||||
*
|
||||
* Signature for all handlers that respond to parsing class files.
|
||||
*/
|
||||
public interface Handler
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* DiscoverableAnnotationHandler
|
||||
*
|
||||
* Processes an annotation when it is discovered on a class.
|
||||
*/
|
||||
public interface DiscoverableAnnotationHandler extends Handler
|
||||
{
|
||||
/**
|
||||
* Process an annotation that was discovered on a class
|
||||
* @param className
|
||||
* @param version
|
||||
* @param access
|
||||
* @param signature
|
||||
* @param superName
|
||||
* @param interfaces
|
||||
* @param annotation
|
||||
* @param values
|
||||
*/
|
||||
public void handleClass (String className, int version, int access,
|
||||
String signature, String superName, String[] interfaces,
|
||||
String annotation, List<Value>values);
|
||||
|
||||
/**
|
||||
* Process an annotation that was discovered on a method
|
||||
* @param className
|
||||
* @param methodName
|
||||
* @param access
|
||||
* @param desc
|
||||
* @param signature
|
||||
* @param exceptions
|
||||
* @param annotation
|
||||
* @param values
|
||||
*/
|
||||
public void handleMethod (String className, String methodName, int access,
|
||||
String desc, String signature,String[] exceptions,
|
||||
String annotation, List<Value>values);
|
||||
|
||||
|
||||
/**
|
||||
* Process an annotation that was discovered on a field
|
||||
* @param className
|
||||
* @param fieldName
|
||||
* @param access
|
||||
* @param fieldType
|
||||
* @param signature
|
||||
* @param value
|
||||
* @param annotation
|
||||
* @param values
|
||||
*/
|
||||
public void handleField (String className, String fieldName, int access,
|
||||
String fieldType, String signature, Object value,
|
||||
String annotation, List<Value>values);
|
||||
|
||||
|
||||
/**
|
||||
* Get the name of the annotation processed by this handler. Can be null
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getAnnotationName();
|
||||
}
|
||||
|
||||
|
||||
public interface ClassHandler
|
||||
|
||||
/**
|
||||
* ClassHandler
|
||||
*
|
||||
* Responds to finding a Class
|
||||
*/
|
||||
public interface ClassHandler extends Handler
|
||||
{
|
||||
public void handle (String className, int version, int access, String signature, String superName, String[] interfaces);
|
||||
}
|
||||
|
||||
public interface MethodHandler
|
||||
|
||||
|
||||
/**
|
||||
* MethodHandler
|
||||
*
|
||||
* Responds to finding a Method
|
||||
*/
|
||||
public interface MethodHandler extends Handler
|
||||
{
|
||||
public void handle (String className, String methodName, int access, String desc, String signature,String[] exceptions);
|
||||
}
|
||||
|
||||
public interface FieldHandler
|
||||
|
||||
/**
|
||||
* FieldHandler
|
||||
*
|
||||
* Responds to finding a Field
|
||||
*/
|
||||
public interface FieldHandler extends Handler
|
||||
{
|
||||
public void handle (String className, String fieldName, int access, String fieldType, String signature, Object value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* MyAnnotationVisitor
|
||||
*
|
||||
* ASM Visitor for Annotations
|
||||
*/
|
||||
public class MyAnnotationVisitor implements AnnotationVisitor
|
||||
{
|
||||
List<Value> _annotationValues;
|
||||
|
@ -307,10 +390,13 @@ public class AnnotationParser
|
|||
for (String s : interfaces)
|
||||
normalizedInterfaces[i++] = normalize(s);
|
||||
}
|
||||
|
||||
for (ClassHandler h : AnnotationParser.this._classHandlers)
|
||||
|
||||
for (Handler h : AnnotationParser.this._handlers)
|
||||
{
|
||||
h.handle(_className, _version, _access, _signature, normalize(_superName), normalizedInterfaces);
|
||||
if (h instanceof ClassHandler)
|
||||
{
|
||||
((ClassHandler)h).handle(_className, _version, _access, _signature, normalize(_superName), normalizedInterfaces);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -323,12 +409,13 @@ public class AnnotationParser
|
|||
super.visitEnd();
|
||||
|
||||
//call all AnnotationHandlers with classname, annotation name + values
|
||||
List<DiscoverableAnnotationHandler> handlers = AnnotationParser.this._annotationHandlers.get(_annotationName);
|
||||
if (handlers != null)
|
||||
for (Handler h : AnnotationParser.this._handlers)
|
||||
{
|
||||
for (DiscoverableAnnotationHandler h:handlers)
|
||||
if (h instanceof DiscoverableAnnotationHandler)
|
||||
{
|
||||
h.handleClass(_className, _version, _access, _signature, _superName, _interfaces, _annotationName, _annotationValues);
|
||||
DiscoverableAnnotationHandler dah = (DiscoverableAnnotationHandler)h;
|
||||
if (_annotationName.equalsIgnoreCase(dah.getAnnotationName()))
|
||||
dah.handleClass(_className, _version, _access, _signature, _superName, _interfaces, _annotationName, _annotationValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -354,12 +441,13 @@ public class AnnotationParser
|
|||
{
|
||||
super.visitEnd();
|
||||
//call all AnnotationHandlers with classname, method, annotation name + values
|
||||
List<DiscoverableAnnotationHandler> handlers = AnnotationParser.this._annotationHandlers.get(_annotationName);
|
||||
if (handlers != null)
|
||||
for (Handler h : AnnotationParser.this._handlers)
|
||||
{
|
||||
for (DiscoverableAnnotationHandler h:handlers)
|
||||
if (h instanceof DiscoverableAnnotationHandler)
|
||||
{
|
||||
h.handleMethod(_className, name, access, methodDesc, signature, exceptions, _annotationName, _annotationValues);
|
||||
DiscoverableAnnotationHandler dah = (DiscoverableAnnotationHandler)h;
|
||||
if (_annotationName.equalsIgnoreCase(dah.getAnnotationName()))
|
||||
dah.handleMethod(_className, name, access, methodDesc, signature, exceptions, _annotationName, _annotationValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -386,12 +474,13 @@ public class AnnotationParser
|
|||
public void visitEnd()
|
||||
{
|
||||
super.visitEnd();
|
||||
List<DiscoverableAnnotationHandler> handlers = AnnotationParser.this._annotationHandlers.get(_annotationName);
|
||||
if (handlers != null)
|
||||
for (Handler h : AnnotationParser.this._handlers)
|
||||
{
|
||||
for (DiscoverableAnnotationHandler h:handlers)
|
||||
if (h instanceof DiscoverableAnnotationHandler)
|
||||
{
|
||||
h.handleField(_className, fieldName, access, fieldType, signature, value, _annotationName, _annotationValues);
|
||||
DiscoverableAnnotationHandler dah = (DiscoverableAnnotationHandler)h;
|
||||
if (_annotationName.equalsIgnoreCase(dah.getAnnotationName()))
|
||||
dah.handleField(_className, fieldName, access, fieldType, signature, value, _annotationName, _annotationValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -407,46 +496,130 @@ public class AnnotationParser
|
|||
* Register a handler that will be called back when the named annotation is
|
||||
* encountered on a class.
|
||||
*
|
||||
* @deprecated see registerHandler(Handler)
|
||||
* @param annotationName
|
||||
* @param handler
|
||||
*/
|
||||
public void registerAnnotationHandler (String annotationName, DiscoverableAnnotationHandler handler)
|
||||
{
|
||||
List<DiscoverableAnnotationHandler> handlers = _annotationHandlers.get(annotationName);
|
||||
if (handlers == null)
|
||||
{
|
||||
handlers = new ArrayList<DiscoverableAnnotationHandler>();
|
||||
_annotationHandlers.put(annotationName, handlers);
|
||||
}
|
||||
handlers.add(handler);
|
||||
_handlers.add(handler);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param annotationName
|
||||
* @return
|
||||
*/
|
||||
public List<DiscoverableAnnotationHandler> getAnnotationHandlers(String annotationName)
|
||||
{
|
||||
List<DiscoverableAnnotationHandler> handlers = _annotationHandlers.get(annotationName);
|
||||
if (handlers == null)
|
||||
return Collections.emptyList();
|
||||
return new ArrayList<DiscoverableAnnotationHandler>();
|
||||
List<DiscoverableAnnotationHandler> handlers = new ArrayList<DiscoverableAnnotationHandler>();
|
||||
for (Handler h:_handlers)
|
||||
{
|
||||
if (h instanceof DiscoverableAnnotationHandler)
|
||||
{
|
||||
DiscoverableAnnotationHandler dah = (DiscoverableAnnotationHandler)h;
|
||||
if (annotationName.equals(dah.getAnnotationName()))
|
||||
handlers.add(dah);
|
||||
}
|
||||
}
|
||||
|
||||
return handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @return
|
||||
*/
|
||||
public List<DiscoverableAnnotationHandler> getAnnotationHandlers()
|
||||
{
|
||||
List<DiscoverableAnnotationHandler> allHandlers = new ArrayList<DiscoverableAnnotationHandler>();
|
||||
for (List<DiscoverableAnnotationHandler> list:_annotationHandlers.values())
|
||||
allHandlers.addAll(list);
|
||||
return allHandlers;
|
||||
List<DiscoverableAnnotationHandler> allAnnotationHandlers = new ArrayList<DiscoverableAnnotationHandler>();
|
||||
for (Handler h:_handlers)
|
||||
{
|
||||
if (h instanceof DiscoverableAnnotationHandler)
|
||||
allAnnotationHandlers.add((DiscoverableAnnotationHandler)h);
|
||||
}
|
||||
return allAnnotationHandlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated see registerHandler(Handler)
|
||||
* @param handler
|
||||
*/
|
||||
public void registerClassHandler (ClassHandler handler)
|
||||
{
|
||||
_classHandlers.add(handler);
|
||||
_handlers.add(handler);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add a particular handler
|
||||
*
|
||||
* @param h
|
||||
*/
|
||||
public void registerHandler(Handler h)
|
||||
{
|
||||
if (h == null)
|
||||
return;
|
||||
|
||||
_handlers.add(h);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a list of handlers
|
||||
*
|
||||
* @param handlers
|
||||
*/
|
||||
public void registerHandlers(List<? extends Handler> handlers)
|
||||
{
|
||||
if (handlers == null)
|
||||
return;
|
||||
_handlers.addAll(handlers);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a particular handler
|
||||
*
|
||||
* @param h
|
||||
* @return
|
||||
*/
|
||||
public boolean deregisterHandler(Handler h)
|
||||
{
|
||||
return _handlers.remove(h);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove all registered handlers
|
||||
*/
|
||||
public void clearHandlers()
|
||||
{
|
||||
_handlers.clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* True if the class has already been processed, false otherwise
|
||||
* @param className
|
||||
* @return
|
||||
*/
|
||||
public boolean isParsed (String className)
|
||||
{
|
||||
return _parsedClassNames.contains(className);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Parse a given class
|
||||
*
|
||||
* @param className
|
||||
* @param resolver
|
||||
* @throws Exception
|
||||
*/
|
||||
public void parse (String className, ClassNameResolver resolver)
|
||||
throws Exception
|
||||
{
|
||||
|
@ -468,6 +641,16 @@ public class AnnotationParser
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Parse the given class, optionally walking its inheritance hierarchy
|
||||
*
|
||||
* @param clazz
|
||||
* @param resolver
|
||||
* @param visitSuperClasses
|
||||
* @throws Exception
|
||||
*/
|
||||
public void parse (Class clazz, ClassNameResolver resolver, boolean visitSuperClasses)
|
||||
throws Exception
|
||||
{
|
||||
|
@ -494,6 +677,15 @@ public class AnnotationParser
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Parse the given classes
|
||||
*
|
||||
* @param classNames
|
||||
* @param resolver
|
||||
* @throws Exception
|
||||
*/
|
||||
public void parse (String[] classNames, ClassNameResolver resolver)
|
||||
throws Exception
|
||||
{
|
||||
|
@ -503,6 +695,14 @@ public class AnnotationParser
|
|||
parse(Arrays.asList(classNames), resolver);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse the given classes
|
||||
*
|
||||
* @param classNames
|
||||
* @param resolver
|
||||
* @throws Exception
|
||||
*/
|
||||
public void parse (List<String> classNames, ClassNameResolver resolver)
|
||||
throws Exception
|
||||
{
|
||||
|
@ -521,6 +721,14 @@ public class AnnotationParser
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse all classes in a directory
|
||||
*
|
||||
* @param dir
|
||||
* @param resolver
|
||||
* @throws Exception
|
||||
*/
|
||||
public void parse (Resource dir, ClassNameResolver resolver)
|
||||
throws Exception
|
||||
{
|
||||
|
@ -556,8 +764,9 @@ public class AnnotationParser
|
|||
|
||||
|
||||
/**
|
||||
* Find annotations on classes in the supplied classloader.
|
||||
* Parse classes in the supplied classloader.
|
||||
* Only class files in jar files will be scanned.
|
||||
*
|
||||
* @param loader
|
||||
* @param visitParents
|
||||
* @param nullInclusive
|
||||
|
@ -580,7 +789,7 @@ public class AnnotationParser
|
|||
try
|
||||
{
|
||||
String name = entry.getName();
|
||||
if (name.toLowerCase().endsWith(".class"))
|
||||
if (name.toLowerCase(Locale.ENGLISH).endsWith(".class"))
|
||||
{
|
||||
String shortName = name.replace('/', '.').substring(0,name.length()-6);
|
||||
if ((resolver == null)
|
||||
|
@ -606,7 +815,8 @@ public class AnnotationParser
|
|||
|
||||
|
||||
/**
|
||||
* Find annotations in classes in the supplied url of jar files.
|
||||
* Parse classes in the supplied url of jar files.
|
||||
*
|
||||
* @param uris
|
||||
* @param resolver
|
||||
* @throws Exception
|
||||
|
@ -624,7 +834,7 @@ public class AnnotationParser
|
|||
try
|
||||
{
|
||||
String name = entry.getName();
|
||||
if (name.toLowerCase().endsWith(".class"))
|
||||
if (name.toLowerCase(Locale.ENGLISH).endsWith(".class"))
|
||||
{
|
||||
String shortName = name.replace('/', '.').substring(0,name.length()-6);
|
||||
|
||||
|
@ -648,6 +858,12 @@ public class AnnotationParser
|
|||
scanner.scan(null, uris, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a particular resource
|
||||
* @param uri
|
||||
* @param resolver
|
||||
* @throws Exception
|
||||
*/
|
||||
public void parse (URI uri, final ClassNameResolver resolver)
|
||||
throws Exception
|
||||
{
|
||||
|
@ -657,6 +873,14 @@ public class AnnotationParser
|
|||
parse(uris, resolver);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Use ASM on a class
|
||||
*
|
||||
* @param is
|
||||
* @throws IOException
|
||||
*/
|
||||
protected void scanClass (InputStream is)
|
||||
throws IOException
|
||||
{
|
||||
|
|
|
@ -35,10 +35,16 @@ public class ClassInheritanceHandler implements ClassHandler
|
|||
private static final Logger LOG = Log.getLogger(ClassInheritanceHandler.class);
|
||||
|
||||
|
||||
MultiMap _inheritanceMap = new MultiMap();
|
||||
MultiMap _inheritanceMap;
|
||||
|
||||
public ClassInheritanceHandler()
|
||||
{
|
||||
_inheritanceMap = new MultiMap();
|
||||
}
|
||||
|
||||
public ClassInheritanceHandler(MultiMap map)
|
||||
{
|
||||
_inheritanceMap = map;
|
||||
}
|
||||
|
||||
public void handle(String className, int version, int access, String signature, String superName, String[] interfaces)
|
||||
|
|
|
@ -69,4 +69,15 @@ public class ContainerInitializerAnnotationHandler implements DiscoverableAnnota
|
|||
_initializer.addAnnotatedTypeName(className);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAnnotationName()
|
||||
{
|
||||
return _annotation.getName();
|
||||
}
|
||||
|
||||
public ContainerInitializer getContainerInitializer()
|
||||
{
|
||||
return _initializer;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.annotations;
|
|||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.naming.InitialContext;
|
||||
|
@ -262,7 +263,7 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH
|
|||
|
||||
//default name is the javabean property name
|
||||
String name = method.getName().substring(3);
|
||||
name = name.substring(0,1).toLowerCase()+name.substring(1);
|
||||
name = name.substring(0,1).toLowerCase(Locale.ENGLISH)+name.substring(1);
|
||||
name = clazz.getCanonicalName()+"/"+name;
|
||||
|
||||
name = (resource.name()!=null && !resource.name().trim().equals("")? resource.name(): name);
|
||||
|
|
|
@ -28,6 +28,8 @@ import javax.servlet.ServletContextListener;
|
|||
import org.eclipse.jetty.annotations.AnnotationConfiguration;
|
||||
import org.eclipse.jetty.plus.annotation.ContainerInitializer;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
/**
|
||||
|
@ -37,7 +39,8 @@ import org.eclipse.jetty.webapp.WebAppContext;
|
|||
*/
|
||||
public class ServletContainerInitializerListener implements ServletContextListener
|
||||
{
|
||||
WebAppContext _context = null;
|
||||
private static final Logger LOG = Log.getLogger(ServletContainerInitializerListener.class);
|
||||
protected WebAppContext _context = null;
|
||||
|
||||
|
||||
public void setWebAppContext (WebAppContext context)
|
||||
|
@ -105,16 +108,11 @@ public class ServletContainerInitializerListener implements ServletContextListen
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//OK, how do I throw an exception such that it really stops the startup sequence?
|
||||
e.printStackTrace();
|
||||
LOG.warn(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
//Email from Jan Luehe 18 August: after all ServletContainerInitializers have been
|
||||
//called, need to check to see if there are any ServletRegistrations remaining
|
||||
//that are "preliminary" and fail the deployment if so. Implemented in ServletHolder.doStart().
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -138,8 +136,7 @@ public class ServletContainerInitializerListener implements ServletContextListen
|
|||
*/
|
||||
public void contextDestroyed(ServletContextEvent sce)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.annotations;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.ServletSecurityElement;
|
||||
import javax.servlet.annotation.HttpConstraint;
|
||||
import javax.servlet.annotation.HttpMethodConstraint;
|
||||
import javax.servlet.annotation.ServletSecurity;
|
||||
|
@ -30,12 +31,13 @@ import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
|
|||
import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler;
|
||||
import org.eclipse.jetty.security.ConstraintAware;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.servlet.ServletMapping;
|
||||
import org.eclipse.jetty.util.LazyList;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.webapp.Origin;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
/**
|
||||
|
@ -82,7 +84,7 @@ public class ServletSecurityAnnotationHandler extends AbstractIntrospectableAnno
|
|||
if (servletSecurity == null)
|
||||
return;
|
||||
|
||||
//If there are already constraints defined (ie from web.xml or programmatically(?)) that match any
|
||||
//If there are already constraints defined (ie from web.xml) that match any
|
||||
//of the url patterns defined for this servlet, then skip the security annotation.
|
||||
|
||||
List<ServletMapping> servletMappings = getServletMappings(clazz.getCanonicalName());
|
||||
|
@ -97,19 +99,15 @@ public class ServletSecurityAnnotationHandler extends AbstractIntrospectableAnno
|
|||
//Make a fresh list
|
||||
constraintMappings = new ArrayList<ConstraintMapping>();
|
||||
|
||||
//Get the values that form the constraints that will apply unless there are HttpMethodConstraints to augment them
|
||||
HttpConstraint defaults = servletSecurity.value();
|
||||
|
||||
//Make a Constraint for the <auth-constraint> and <user-data-constraint> specified by the HttpConstraint
|
||||
Constraint defaultConstraint = makeConstraint (clazz,
|
||||
defaults.rolesAllowed(),
|
||||
defaults.value(),
|
||||
defaults.transportGuarantee());
|
||||
|
||||
constraintMappings.addAll(makeMethodMappings(clazz,
|
||||
defaultConstraint,
|
||||
servletMappings,
|
||||
servletSecurity.httpMethodConstraints()));
|
||||
ServletSecurityElement securityElement = new ServletSecurityElement(servletSecurity);
|
||||
for (ServletMapping sm : servletMappings)
|
||||
{
|
||||
for (String url : sm.getPathSpecs())
|
||||
{
|
||||
_context.getMetaData().setOrigin("constraint.url."+url, Origin.Annotation);
|
||||
constraintMappings.addAll(ConstraintSecurityHandler.createConstraintsWithMappingsForPath(clazz.getName(), url, securityElement));
|
||||
}
|
||||
}
|
||||
|
||||
//set up the security constraints produced by the annotation
|
||||
ConstraintAware securityHandler = (ConstraintAware)_context.getSecurityHandler();
|
||||
|
@ -131,111 +129,10 @@ public class ServletSecurityAnnotationHandler extends AbstractIntrospectableAnno
|
|||
*/
|
||||
protected Constraint makeConstraint (Class servlet, String[] rolesAllowed, EmptyRoleSemantic permitOrDeny, TransportGuarantee transport)
|
||||
{
|
||||
Constraint constraint = new Constraint();
|
||||
if (rolesAllowed == null || rolesAllowed.length==0)
|
||||
{
|
||||
if (permitOrDeny.equals(EmptyRoleSemantic.DENY))
|
||||
{
|
||||
//Equivalent to <auth-constraint> with no roles
|
||||
constraint.setName(servlet.getName()+"-Deny");
|
||||
constraint.setAuthenticate(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Equivalent to no <auth-constraint>
|
||||
constraint.setAuthenticate(false);
|
||||
constraint.setName(servlet.getName()+"-Permit");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Equivalent to <auth-constraint> with list of <security-role-name>s
|
||||
constraint.setAuthenticate(true);
|
||||
constraint.setRoles(rolesAllowed);
|
||||
constraint.setName(servlet.getName()+"-RolesAllowed");
|
||||
}
|
||||
|
||||
//Equivalent to //<user-data-constraint><transport-guarantee>CONFIDENTIAL</transport-guarantee></user-data-constraint>
|
||||
constraint.setDataConstraint((transport.equals(TransportGuarantee.CONFIDENTIAL)?Constraint.DC_CONFIDENTIAL:Constraint.DC_NONE));
|
||||
return constraint;
|
||||
return ConstraintSecurityHandler.createConstraint(servlet.getName(), rolesAllowed, permitOrDeny, transport);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make a ConstraintMapping which captures the <http-method> or <http-method-omission> elements for a particular url pattern,
|
||||
* and relates it to a Constraint object (<auth-constraint> and <user-data-constraint>).
|
||||
* @param constraint
|
||||
* @param url
|
||||
* @param method
|
||||
* @param omissions
|
||||
* @return
|
||||
*/
|
||||
protected ConstraintMapping makeConstraintMapping (Constraint constraint, String url, String method, String[] omissions)
|
||||
{
|
||||
ConstraintMapping mapping = new ConstraintMapping();
|
||||
mapping.setConstraint(constraint);
|
||||
mapping.setPathSpec(url);
|
||||
if (method != null)
|
||||
mapping.setMethod(method);
|
||||
if (omissions != null)
|
||||
mapping.setMethodOmissions(omissions);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the Jetty Constraints and ConstraintMapping objects that correspond to the HttpMethodConstraint
|
||||
* annotations for each url pattern for the servlet.
|
||||
* @param servlet
|
||||
* @param defaultConstraint
|
||||
* @param servletMappings
|
||||
* @param annotations
|
||||
* @return
|
||||
*/
|
||||
protected List<ConstraintMapping> makeMethodMappings (Class servlet, Constraint defaultConstraint, List<ServletMapping> servletMappings, HttpMethodConstraint[] annotations)
|
||||
{
|
||||
List<ConstraintMapping> mappings = new ArrayList<ConstraintMapping>();
|
||||
|
||||
//for each url-pattern existing for the servlet make a ConstraintMapping for the HttpConstraint, and ConstraintMappings for
|
||||
//each HttpMethodConstraint
|
||||
for (ServletMapping sm : servletMappings)
|
||||
{
|
||||
for (String url : sm.getPathSpecs())
|
||||
{
|
||||
//Make a ConstraintMapping that matches the defaultConstraint
|
||||
ConstraintMapping defaultMapping = makeConstraintMapping(defaultConstraint, url, null, null);
|
||||
|
||||
//If there are HttpMethodConstraint annotations, make a Constraint and a ConstraintMapping for it
|
||||
if (annotations != null && annotations.length>0)
|
||||
{
|
||||
List<String> omissions = new ArrayList<String>();
|
||||
|
||||
//for each HttpMethodConstraint annotation, make a new Constraint and ConstraintMappings for this url
|
||||
for (int i=0; i < annotations.length;i++)
|
||||
{
|
||||
//Make a Constraint that captures the <auth-constraint> and <user-data-constraint> elements
|
||||
Constraint methodConstraint = makeConstraint(servlet,
|
||||
annotations[i].rolesAllowed(),
|
||||
annotations[i].emptyRoleSemantic(),
|
||||
annotations[i].transportGuarantee());
|
||||
|
||||
//Make ConstraintMapping that captures the <http-method> elements
|
||||
ConstraintMapping methodConstraintMapping = makeConstraintMapping (methodConstraint,
|
||||
url,annotations[i].value(),
|
||||
null);
|
||||
mappings.add(methodConstraintMapping);
|
||||
omissions.add(annotations[i].value());
|
||||
}
|
||||
defaultMapping.setMethodOmissions(omissions.toArray(new String[0]));
|
||||
}
|
||||
|
||||
//add the constraint mapping containing the http-method-omissions, if there are any
|
||||
mappings.add(defaultMapping);
|
||||
}
|
||||
}
|
||||
return mappings;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the ServletMappings for the servlet's class.
|
||||
|
@ -284,6 +181,7 @@ public class ServletSecurityAnnotationHandler extends AbstractIntrospectableAnno
|
|||
{
|
||||
for (int j=0; j < pathSpecs.length; j++)
|
||||
{
|
||||
//TODO decide if we need to check the origin
|
||||
if (pathSpecs[j].equals(constraintMappings.get(i).getPathSpec()))
|
||||
{
|
||||
exists = true;
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.eclipse.jetty.servlet.FilterMapping;
|
|||
import org.eclipse.jetty.servlet.Holder;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.webapp.DiscoveredAnnotation;
|
||||
import org.eclipse.jetty.webapp.MetaData;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
@ -53,6 +54,11 @@ public class WebFilterAnnotation extends DiscoveredAnnotation
|
|||
{
|
||||
super(context, className);
|
||||
}
|
||||
|
||||
public WebFilterAnnotation(WebAppContext context, String className, Resource resource)
|
||||
{
|
||||
super(context, className, resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.annotations.ClassAnnotation#apply()
|
||||
|
|
|
@ -40,11 +40,16 @@ public class WebFilterAnnotationHandler extends AbstractDiscoverableAnnotationHa
|
|||
{
|
||||
super(context);
|
||||
}
|
||||
|
||||
|
||||
public WebFilterAnnotationHandler (WebAppContext context, List<DiscoveredAnnotation> list)
|
||||
{
|
||||
super(context, list);
|
||||
}
|
||||
|
||||
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
|
||||
List<Value> values)
|
||||
{
|
||||
WebFilterAnnotation wfAnnotation = new WebFilterAnnotation(_context, className);
|
||||
WebFilterAnnotation wfAnnotation = new WebFilterAnnotation(_context, className, _resource);
|
||||
addAnnotation(wfAnnotation);
|
||||
}
|
||||
|
||||
|
@ -60,4 +65,10 @@ public class WebFilterAnnotationHandler extends AbstractDiscoverableAnnotationHa
|
|||
LOG.warn ("@WebFilter not applicable for methods: "+className+"."+methodName+" "+signature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAnnotationName()
|
||||
{
|
||||
return "javax.servlet.annotation.WebFilter";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import javax.servlet.http.HttpSessionListener;
|
|||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.webapp.DiscoveredAnnotation;
|
||||
import org.eclipse.jetty.webapp.MetaData;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
@ -49,6 +50,11 @@ public class WebListenerAnnotation extends DiscoveredAnnotation
|
|||
{
|
||||
super(context, className);
|
||||
}
|
||||
|
||||
public WebListenerAnnotation(WebAppContext context, String className, Resource resource)
|
||||
{
|
||||
super(context, className, resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.annotations.ClassAnnotation#apply()
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.List;
|
|||
import org.eclipse.jetty.annotations.AnnotationParser.Value;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.webapp.DiscoveredAnnotation;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
public class WebListenerAnnotationHandler extends AbstractDiscoverableAnnotationHandler
|
||||
|
@ -34,13 +35,18 @@ public class WebListenerAnnotationHandler extends AbstractDiscoverableAnnotation
|
|||
super(context);
|
||||
}
|
||||
|
||||
public WebListenerAnnotationHandler (WebAppContext context, List<DiscoveredAnnotation> list)
|
||||
{
|
||||
super(context, list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler#handleClass(java.lang.String, int, int, java.lang.String, java.lang.String, java.lang.String[], java.lang.String, java.util.List)
|
||||
*/
|
||||
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
|
||||
List<Value> values)
|
||||
{
|
||||
WebListenerAnnotation wlAnnotation = new WebListenerAnnotation(_context, className);
|
||||
WebListenerAnnotation wlAnnotation = new WebListenerAnnotation(_context, className, _resource);
|
||||
addAnnotation(wlAnnotation);
|
||||
}
|
||||
|
||||
|
@ -56,4 +62,10 @@ public class WebListenerAnnotationHandler extends AbstractDiscoverableAnnotation
|
|||
LOG.warn ("@WebListener is not applicable to methods: "+className+"."+methodName+" "+signature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAnnotationName()
|
||||
{
|
||||
return "javax.servlet.annotation.WebListener";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.eclipse.jetty.servlet.ServletMapping;
|
|||
import org.eclipse.jetty.util.LazyList;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.webapp.DiscoveredAnnotation;
|
||||
import org.eclipse.jetty.webapp.MetaData;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
@ -48,7 +49,13 @@ public class WebServletAnnotation extends DiscoveredAnnotation
|
|||
{
|
||||
super(context, className);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public WebServletAnnotation (WebAppContext context, String className, Resource resource)
|
||||
{
|
||||
super(context, className, resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.annotations.ClassAnnotation#apply()
|
||||
*/
|
||||
|
|
|
@ -42,6 +42,11 @@ public class WebServletAnnotationHandler extends AbstractDiscoverableAnnotationH
|
|||
super(context);
|
||||
}
|
||||
|
||||
public WebServletAnnotationHandler (WebAppContext context, List<DiscoveredAnnotation> list)
|
||||
{
|
||||
super(context, list);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle discovering a WebServlet annotation.
|
||||
|
@ -55,7 +60,7 @@ public class WebServletAnnotationHandler extends AbstractDiscoverableAnnotationH
|
|||
if (!"javax.servlet.annotation.WebServlet".equals(annotationName))
|
||||
return;
|
||||
|
||||
WebServletAnnotation annotation = new WebServletAnnotation (_context, className);
|
||||
WebServletAnnotation annotation = new WebServletAnnotation (_context, className, _resource);
|
||||
addAnnotation(annotation);
|
||||
}
|
||||
|
||||
|
@ -69,5 +74,12 @@ public class WebServletAnnotationHandler extends AbstractDiscoverableAnnotationH
|
|||
List<Value> values)
|
||||
{
|
||||
LOG.warn ("@WebServlet annotation not supported for methods");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getAnnotationName()
|
||||
{
|
||||
return "javax.servlet.annotation.WebServlet";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,6 +66,12 @@ public class TestAnnotationInheritance
|
|||
{
|
||||
annotatedMethods.add(className+"."+methodName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAnnotationName()
|
||||
{
|
||||
return "org.eclipse.jetty.annotations.Sample";
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -85,7 +91,7 @@ public class TestAnnotationInheritance
|
|||
|
||||
SampleHandler handler = new SampleHandler();
|
||||
AnnotationParser parser = new AnnotationParser();
|
||||
parser.registerAnnotationHandler("org.eclipse.jetty.annotations.Sample", handler);
|
||||
parser.registerHandler(handler);
|
||||
parser.parse(classNames, new ClassNameResolver ()
|
||||
{
|
||||
public boolean isExcluded(String name)
|
||||
|
|
|
@ -41,6 +41,9 @@ public class TestAnnotationParser
|
|||
{
|
||||
private List<String> methods = Arrays.asList("a", "b", "c", "d", "l");
|
||||
|
||||
|
||||
|
||||
|
||||
public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation,
|
||||
List<Value> values)
|
||||
{
|
||||
|
@ -81,9 +84,15 @@ public class TestAnnotationParser
|
|||
assertTrue(methods.contains(methodName));
|
||||
assertEquals("org.eclipse.jetty.annotations.Sample", annotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAnnotationName()
|
||||
{
|
||||
return "org.eclipse.jetty.annotations.Sample";
|
||||
}
|
||||
}
|
||||
|
||||
parser.registerAnnotationHandler("org.eclipse.jetty.annotations.Sample", new SampleAnnotationHandler());
|
||||
parser.registerHandler(new SampleAnnotationHandler());
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
parser.parse(classNames, new ClassNameResolver ()
|
||||
|
@ -140,9 +149,17 @@ public class TestAnnotationParser
|
|||
System.err.println(anv.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAnnotationName()
|
||||
{
|
||||
return "org.eclipse.jetty.annotations.Multi";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
parser.registerAnnotationHandler("org.eclipse.jetty.annotations.Multi", new MultiAnnotationHandler());
|
||||
parser.registerHandler(new MultiAnnotationHandler());
|
||||
parser.parse(classNames, null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@ package org.eclipse.jetty.client;
|
|||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.jetty.client.helperClasses.ServerAndClientCreator;
|
||||
import org.eclipse.jetty.client.helperClasses.SslServerAndClientCreator;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
|
@ -51,7 +53,7 @@ public class SslHttpExchangeTest extends HttpExchangeTest
|
|||
{
|
||||
// Use Junit 4.x to flag test as ignored if encountering IBM JVM
|
||||
// Will show up in various junit reports as an ignored test as well.
|
||||
Assume.assumeThat(System.getProperty("java.vendor").toLowerCase(),not(containsString("ibm")));
|
||||
Assume.assumeThat(System.getProperty("java.vendor").toLowerCase(Locale.ENGLISH),not(containsString("ibm")));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.io.OutputStream;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -126,7 +127,7 @@ public class SslSecurityListenerTest
|
|||
public void testSslGet() throws Exception
|
||||
{
|
||||
// TODO Resolve problems on IBM JVM https://bugs.eclipse.org/bugs/show_bug.cgi?id=304532
|
||||
if (System.getProperty("java.vendor").toLowerCase().indexOf("ibm")>=0)
|
||||
if (System.getProperty("java.vendor").toLowerCase(Locale.ENGLISH).indexOf("ibm")>=0)
|
||||
{
|
||||
LOG.warn("Skipped SSL testSslGet on IBM JVM");
|
||||
return;
|
||||
|
|
|
@ -214,6 +214,7 @@ public class WebSocketUpgradeTest
|
|||
return _websocket;
|
||||
}
|
||||
};
|
||||
_handler.getWebSocketFactory().setMinVersion(-1);
|
||||
|
||||
_server.setHandler(_handler);
|
||||
_server.start();
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.eclipse.jetty.deploy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.jetty.deploy.providers.ScanningAppProvider;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
|
@ -223,7 +224,7 @@ public class WebAppDeployer extends AbstractLifeCycle
|
|||
|
||||
Resource app=r.addPath(r.encode(context));
|
||||
|
||||
if (context.toLowerCase().endsWith(".war")||context.toLowerCase().endsWith(".jar"))
|
||||
if (context.toLowerCase(Locale.ENGLISH).endsWith(".war")||context.toLowerCase(Locale.ENGLISH).endsWith(".jar"))
|
||||
{
|
||||
context=context.substring(0,context.length()-4);
|
||||
Resource unpacked=r.addPath(context);
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.deploy.providers;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.ConfigurationManager;
|
||||
|
@ -45,7 +46,7 @@ public class ContextProvider extends ScanningAppProvider
|
|||
{
|
||||
if (!dir.exists())
|
||||
return false;
|
||||
String lowername = name.toLowerCase();
|
||||
String lowername = name.toLowerCase(Locale.ENGLISH);
|
||||
if (lowername.startsWith("."))
|
||||
return false;
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.io.File;
|
|||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.util.FileID;
|
||||
|
@ -59,7 +60,7 @@ public class WebAppProvider extends ScanningAppProvider
|
|||
{
|
||||
return false;
|
||||
}
|
||||
String lowername = name.toLowerCase();
|
||||
String lowername = name.toLowerCase(Locale.ENGLISH);
|
||||
|
||||
File file = new File(dir,name);
|
||||
// is it not a directory and not a war ?
|
||||
|
@ -279,9 +280,9 @@ public class WebAppProvider extends ScanningAppProvider
|
|||
{
|
||||
context = URIUtil.SLASH;
|
||||
}
|
||||
else if (context.toLowerCase().startsWith("root-"))
|
||||
else if (context.toLowerCase(Locale.ENGLISH).startsWith("root-"))
|
||||
{
|
||||
int dash=context.toLowerCase().indexOf('-');
|
||||
int dash=context.toLowerCase(Locale.ENGLISH).indexOf('-');
|
||||
String virtual = context.substring(dash+1);
|
||||
wah.setVirtualHosts(new String[]{virtual});
|
||||
context = URIUtil.SLASH;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.eclipse.jetty.deploy.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Simple, yet surprisingly common utility methods for identifying various file types commonly seen and worked with in a
|
||||
|
@ -38,7 +39,7 @@ public class FileID
|
|||
{
|
||||
if (path.isFile())
|
||||
{
|
||||
String name = path.getName().toLowerCase();
|
||||
String name = path.getName().toLowerCase(Locale.ENGLISH);
|
||||
return (name.endsWith(".war") || name.endsWith(".jar"));
|
||||
}
|
||||
|
||||
|
@ -62,7 +63,7 @@ public class FileID
|
|||
return false;
|
||||
}
|
||||
|
||||
String name = path.getName().toLowerCase();
|
||||
String name = path.getName().toLowerCase(Locale.ENGLISH);
|
||||
return (name.endsWith(".war") || name.endsWith(".jar"));
|
||||
}
|
||||
|
||||
|
@ -73,7 +74,7 @@ public class FileID
|
|||
return false;
|
||||
}
|
||||
|
||||
String name = path.getName().toLowerCase();
|
||||
String name = path.getName().toLowerCase(Locale.ENGLISH);
|
||||
return name.endsWith(".xml");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -976,6 +976,9 @@ public class HttpFields
|
|||
QuotedStringTokenizer.quoteIfNeeded(buf, name, delim);
|
||||
buf.append('=');
|
||||
String start=buf.toString();
|
||||
boolean hasDomain = false;
|
||||
boolean hasPath = false;
|
||||
|
||||
if (value != null && value.length() > 0)
|
||||
QuotedStringTokenizer.quoteIfNeeded(buf, value, delim);
|
||||
|
||||
|
@ -987,6 +990,7 @@ public class HttpFields
|
|||
|
||||
if (path != null && path.length() > 0)
|
||||
{
|
||||
hasPath = true;
|
||||
buf.append(";Path=");
|
||||
if (path.trim().startsWith("\""))
|
||||
buf.append(path);
|
||||
|
@ -995,8 +999,9 @@ public class HttpFields
|
|||
}
|
||||
if (domain != null && domain.length() > 0)
|
||||
{
|
||||
hasDomain = true;
|
||||
buf.append(";Domain=");
|
||||
QuotedStringTokenizer.quoteIfNeeded(buf,domain.toLowerCase(),delim);
|
||||
QuotedStringTokenizer.quoteIfNeeded(buf,domain.toLowerCase(Locale.ENGLISH),delim);
|
||||
}
|
||||
|
||||
if (maxAge >= 0)
|
||||
|
@ -1027,14 +1032,20 @@ public class HttpFields
|
|||
Field last=null;
|
||||
while (field!=null)
|
||||
{
|
||||
if (field._value!=null && field._value.toString().startsWith(start))
|
||||
String val = (field._value == null ? null : field._value.toString());
|
||||
if (val!=null && val.startsWith(start))
|
||||
{
|
||||
_fields.remove(field);
|
||||
if (last==null)
|
||||
_names.put(HttpHeaders.SET_COOKIE_BUFFER,field._next);
|
||||
else
|
||||
last._next=field._next;
|
||||
break;
|
||||
//existing cookie has same name, does it also match domain and path?
|
||||
if (((!hasDomain && !val.contains("Domain")) || (hasDomain && val.contains("Domain="+domain))) &&
|
||||
((!hasPath && !val.contains("Path")) || (hasPath && val.contains("Path="+path))))
|
||||
{
|
||||
_fields.remove(field);
|
||||
if (last==null)
|
||||
_names.put(HttpHeaders.SET_COOKIE_BUFFER,field._next);
|
||||
else
|
||||
last._next=field._next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
last=field;
|
||||
field=field._next;
|
||||
|
|
|
@ -94,7 +94,15 @@ public class HttpURI
|
|||
public HttpURI(String raw)
|
||||
{
|
||||
_rawString=raw;
|
||||
byte[] b = raw.getBytes();
|
||||
byte[] b;
|
||||
try
|
||||
{
|
||||
b = raw.getBytes(StringUtil.__UTF8);
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
parse(b,0,b.length);
|
||||
}
|
||||
|
||||
|
@ -700,7 +708,7 @@ public class HttpURI
|
|||
if (encoding==null || StringUtil.isUTF8(encoding))
|
||||
UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters);
|
||||
else
|
||||
UrlEncoded.decodeTo(toUtf8String(_query+1,_fragment-_query-1),parameters,encoding);
|
||||
UrlEncoded.decodeTo(StringUtil.toString(_raw,_query+1,_fragment-_query-1,encoding),parameters,encoding);
|
||||
}
|
||||
|
||||
public void clear()
|
||||
|
|
|
@ -171,6 +171,7 @@ xhtml = application/xhtml+xml
|
|||
xls = application/vnd.ms-excel
|
||||
xml = application/xml
|
||||
xpm = image/x-xpixmap
|
||||
xsd = application/xml
|
||||
xsl = application/xml
|
||||
xslt = application/xslt+xml
|
||||
xul = application/vnd.mozilla.xul+xml
|
||||
|
|
|
@ -25,6 +25,7 @@ import static org.junit.Assert.assertTrue;
|
|||
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
|
@ -312,8 +313,8 @@ public class HttpFieldsTest
|
|||
s=enum2set(fields.getFieldNames());
|
||||
assertEquals(3,s.size());
|
||||
assertTrue(s.contains("message-id"));
|
||||
assertEquals("value",fields.getStringField("message-id").toLowerCase());
|
||||
assertEquals("value",fields.getStringField("Message-ID").toLowerCase());
|
||||
assertEquals("value",fields.getStringField("message-id").toLowerCase(Locale.ENGLISH));
|
||||
assertEquals("value",fields.getStringField("Message-ID").toLowerCase(Locale.ENGLISH));
|
||||
|
||||
fields.clear();
|
||||
|
||||
|
@ -323,8 +324,8 @@ public class HttpFieldsTest
|
|||
s=enum2set(fields.getFieldNames());
|
||||
assertEquals(3,s.size());
|
||||
assertTrue(s.contains("message-id"));
|
||||
assertEquals("value",fields.getStringField("Message-ID").toLowerCase());
|
||||
assertEquals("value",fields.getStringField("message-id").toLowerCase());
|
||||
assertEquals("value",fields.getStringField("Message-ID").toLowerCase(Locale.ENGLISH));
|
||||
assertEquals("value",fields.getStringField("message-id").toLowerCase(Locale.ENGLISH));
|
||||
|
||||
fields.clear();
|
||||
|
||||
|
@ -334,8 +335,8 @@ public class HttpFieldsTest
|
|||
s=enum2set(fields.getFieldNames());
|
||||
assertEquals(3,s.size());
|
||||
assertTrue(s.contains("message-id"));
|
||||
assertEquals("value",fields.getStringField("message-id").toLowerCase());
|
||||
assertEquals("value",fields.getStringField("Message-ID").toLowerCase());
|
||||
assertEquals("value",fields.getStringField("message-id").toLowerCase(Locale.ENGLISH));
|
||||
assertEquals("value",fields.getStringField("Message-ID").toLowerCase(Locale.ENGLISH));
|
||||
|
||||
fields.clear();
|
||||
|
||||
|
@ -345,8 +346,8 @@ public class HttpFieldsTest
|
|||
s=enum2set(fields.getFieldNames());
|
||||
assertEquals(3,s.size());
|
||||
assertTrue(s.contains("message-id"));
|
||||
assertEquals("value",fields.getStringField("Message-ID").toLowerCase());
|
||||
assertEquals("value",fields.getStringField("message-id").toLowerCase());
|
||||
assertEquals("value",fields.getStringField("Message-ID").toLowerCase(Locale.ENGLISH));
|
||||
assertEquals("value",fields.getStringField("message-id").toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -364,7 +365,8 @@ public class HttpFieldsTest
|
|||
assertEquals("minimal=value",fields.getStringField("Set-Cookie"));
|
||||
|
||||
fields.clear();
|
||||
fields.addSetCookie("everything","wrong","wrong","wrong",0,"to be replaced",true,true,0);
|
||||
//test cookies with same name, domain and path, only 1 allowed
|
||||
fields.addSetCookie("everything","wrong","domain","path",0,"to be replaced",true,true,0);
|
||||
fields.addSetCookie("everything","value","domain","path",0,"comment",true,true,0);
|
||||
assertEquals("everything=value;Comment=comment;Path=path;Domain=domain;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Secure;HttpOnly",fields.getStringField("Set-Cookie"));
|
||||
Enumeration<String> e =fields.getValues("Set-Cookie");
|
||||
|
@ -372,6 +374,61 @@ public class HttpFieldsTest
|
|||
assertEquals("everything=value;Comment=comment;Path=path;Domain=domain;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Secure;HttpOnly",e.nextElement());
|
||||
assertFalse(e.hasMoreElements());
|
||||
assertEquals("Thu, 01 Jan 1970 00:00:00 GMT",fields.getStringField("Expires"));
|
||||
assertFalse(e.hasMoreElements());
|
||||
|
||||
//test cookies with same name, different domain
|
||||
fields.clear();
|
||||
fields.addSetCookie("everything","other","domain1","path",0,"blah",true,true,0);
|
||||
fields.addSetCookie("everything","value","domain2","path",0,"comment",true,true,0);
|
||||
e =fields.getValues("Set-Cookie");
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals("everything=other;Comment=blah;Path=path;Domain=domain1;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Secure;HttpOnly",e.nextElement());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals("everything=value;Comment=comment;Path=path;Domain=domain2;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Secure;HttpOnly",e.nextElement());
|
||||
assertFalse(e.hasMoreElements());
|
||||
|
||||
//test cookies with same name, same path, one with domain, one without
|
||||
fields.clear();
|
||||
fields.addSetCookie("everything","other","domain1","path",0,"blah",true,true,0);
|
||||
fields.addSetCookie("everything","value","","path",0,"comment",true,true,0);
|
||||
e =fields.getValues("Set-Cookie");
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals("everything=other;Comment=blah;Path=path;Domain=domain1;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Secure;HttpOnly",e.nextElement());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals("everything=value;Comment=comment;Path=path;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Secure;HttpOnly",e.nextElement());
|
||||
assertFalse(e.hasMoreElements());
|
||||
|
||||
|
||||
//test cookies with same name, different path
|
||||
fields.clear();
|
||||
fields.addSetCookie("everything","other","domain1","path1",0,"blah",true,true,0);
|
||||
fields.addSetCookie("everything","value","domain1","path2",0,"comment",true,true,0);
|
||||
e =fields.getValues("Set-Cookie");
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals("everything=other;Comment=blah;Path=path1;Domain=domain1;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Secure;HttpOnly",e.nextElement());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals("everything=value;Comment=comment;Path=path2;Domain=domain1;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Secure;HttpOnly",e.nextElement());
|
||||
assertFalse(e.hasMoreElements());
|
||||
|
||||
//test cookies with same name, same domain, one with path, one without
|
||||
fields.clear();
|
||||
fields.addSetCookie("everything","other","domain1","path1",0,"blah",true,true,0);
|
||||
fields.addSetCookie("everything","value","domain1","",0,"comment",true,true,0);
|
||||
e =fields.getValues("Set-Cookie");
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals("everything=other;Comment=blah;Path=path1;Domain=domain1;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Secure;HttpOnly",e.nextElement());
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals("everything=value;Comment=comment;Domain=domain1;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Secure;HttpOnly",e.nextElement());
|
||||
assertFalse(e.hasMoreElements());
|
||||
|
||||
//test cookies same name only, no path, no domain
|
||||
fields.clear();
|
||||
fields.addSetCookie("everything","other","","",0,"blah",true,true,0);
|
||||
fields.addSetCookie("everything","value","","",0,"comment",true,true,0);
|
||||
e =fields.getValues("Set-Cookie");
|
||||
assertTrue(e.hasMoreElements());
|
||||
assertEquals("everything=value;Comment=comment;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Secure;HttpOnly",e.nextElement());
|
||||
assertFalse(e.hasMoreElements());
|
||||
|
||||
fields.clear();
|
||||
fields.addSetCookie("ev erything","va lue","do main","pa th",1,"co mment",true,true,2);
|
||||
|
@ -402,7 +459,7 @@ public class HttpFieldsTest
|
|||
{
|
||||
Set<String> s=new HashSet<String>();
|
||||
while(e.hasMoreElements())
|
||||
s.add(e.nextElement().toLowerCase());
|
||||
s.add(e.nextElement().toLowerCase(Locale.ENGLISH));
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.io;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -644,6 +645,23 @@ public abstract class AbstractBuffer implements Buffer
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String toString(Charset charset)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] bytes=array();
|
||||
if (bytes!=null)
|
||||
return new String(bytes,getIndex(),length(),charset);
|
||||
return new String(asArray(), 0, length(),charset);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
return new String(asArray(), 0, length());
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String toDebugString()
|
||||
{
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.io;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -365,7 +366,10 @@ public interface Buffer extends Cloneable
|
|||
/* ------------------------------------------------------------ */
|
||||
String toString(String charset);
|
||||
|
||||
/*
|
||||
/* ------------------------------------------------------------ */
|
||||
String toString(Charset charset);
|
||||
|
||||
/*
|
||||
* Buffers implementing this interface should be compared with case insensitive equals
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -354,6 +354,6 @@ public class BufferUtil
|
|||
{
|
||||
if (buffer instanceof CachedBuffer)
|
||||
return buffer.toString();
|
||||
return buffer.toString(StringUtil.__ISO_8859_1);
|
||||
return buffer.toString(StringUtil.__ISO_8859_1_CHARSET);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.nio.channels.ClosedChannelException;
|
|||
import java.nio.channels.SelectableChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
|
@ -42,7 +43,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
{
|
||||
public static final Logger LOG=Log.getLogger("org.eclipse.jetty.io.nio");
|
||||
|
||||
private final boolean WORK_AROUND_JVM_BUG_6346658 = System.getProperty("os.name").toLowerCase().contains("win");
|
||||
private final boolean WORK_AROUND_JVM_BUG_6346658 = System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("win");
|
||||
private final SelectorManager.SelectSet _selectSet;
|
||||
private final SelectorManager _manager;
|
||||
private SelectionKey _key;
|
||||
|
|
|
@ -31,21 +31,30 @@ import javax.security.auth.message.config.ServerAuthConfig;
|
|||
import javax.security.auth.message.config.ServerAuthContext;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.eclipse.jetty.security.Authenticator;
|
||||
import org.eclipse.jetty.security.IdentityService;
|
||||
import org.eclipse.jetty.security.ServerAuthException;
|
||||
import org.eclipse.jetty.security.UserAuthentication;
|
||||
import org.eclipse.jetty.security.authentication.DeferredAuthentication;
|
||||
import org.eclipse.jetty.security.authentication.LoginAuthenticator;
|
||||
import org.eclipse.jetty.security.authentication.SessionAuthentication;
|
||||
import org.eclipse.jetty.security.jaspi.modules.BaseAuthModule;
|
||||
import org.eclipse.jetty.server.Authentication;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
import org.eclipse.jetty.server.Authentication.User;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
|
||||
*/
|
||||
public class JaspiAuthenticator implements Authenticator
|
||||
public class JaspiAuthenticator extends LoginAuthenticator
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(JaspiAuthenticator.class.getName());
|
||||
|
||||
private final ServerAuthConfig _authConfig;
|
||||
|
||||
private final Map _authProperties;
|
||||
|
@ -58,7 +67,7 @@ public class JaspiAuthenticator implements Authenticator
|
|||
|
||||
private final IdentityService _identityService;
|
||||
|
||||
private final DeferredAuthentication _deferred;
|
||||
|
||||
|
||||
public JaspiAuthenticator(ServerAuthConfig authConfig, Map authProperties, ServletCallbackHandler callbackHandler, Subject serviceSubject,
|
||||
boolean allowLazyAuthentication, IdentityService identityService)
|
||||
|
@ -72,11 +81,11 @@ public class JaspiAuthenticator implements Authenticator
|
|||
this._serviceSubject = serviceSubject;
|
||||
this._allowLazyAuthentication = allowLazyAuthentication;
|
||||
this._identityService = identityService;
|
||||
this._deferred = new DeferredAuthentication(this);
|
||||
}
|
||||
|
||||
public void setConfiguration(AuthConfiguration configuration)
|
||||
{
|
||||
super.setConfiguration(configuration);
|
||||
}
|
||||
|
||||
public String getAuthMethod()
|
||||
|
@ -93,7 +102,7 @@ public class JaspiAuthenticator implements Authenticator
|
|||
|
||||
//if its not mandatory to authenticate, and the authenticator returned UNAUTHENTICATED, we treat it as authentication deferred
|
||||
if (_allowLazyAuthentication && !info.isAuthMandatory() && a == Authentication.UNAUTHENTICATED)
|
||||
a =_deferred;
|
||||
a = new DeferredAuthentication(this);
|
||||
return a;
|
||||
}
|
||||
|
||||
|
@ -106,6 +115,28 @@ public class JaspiAuthenticator implements Authenticator
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.security.authentication.LoginAuthenticator#login(java.lang.String, java.lang.Object, javax.servlet.ServletRequest)
|
||||
*/
|
||||
@Override
|
||||
public UserIdentity login(String username, Object password, ServletRequest request)
|
||||
{
|
||||
UserIdentity user = _loginService.login(username, password);
|
||||
if (user != null)
|
||||
{
|
||||
renewSession((HttpServletRequest)request, null);
|
||||
HttpSession session = ((HttpServletRequest)request).getSession(true);
|
||||
if (session != null)
|
||||
{
|
||||
SessionAuthentication sessionAuth = new SessionAuthentication(getAuthMethod(), user, password);
|
||||
session.setAttribute(SessionAuthentication.__J_AUTHENTICATED, sessionAuth);
|
||||
}
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Authentication validateRequest(JaspiMessageInfo messageInfo) throws ServerAuthException
|
||||
{
|
||||
try
|
||||
|
@ -150,6 +181,12 @@ public class JaspiAuthenticator implements Authenticator
|
|||
String[] groups = groupPrincipalCallback == null ? null : groupPrincipalCallback.getGroups();
|
||||
userIdentity = _identityService.newUserIdentity(clientSubject, principal, groups);
|
||||
}
|
||||
|
||||
HttpSession session = ((HttpServletRequest)messageInfo.getRequestMessage()).getSession(false);
|
||||
Authentication cached = (session == null?null:(SessionAuthentication)session.getAttribute(SessionAuthentication.__J_AUTHENTICATED));
|
||||
if (cached != null)
|
||||
return cached;
|
||||
|
||||
return new UserAuthentication(getAuthMethod(), userIdentity);
|
||||
}
|
||||
if (authStatus == AuthStatus.SEND_SUCCESS)
|
||||
|
|
|
@ -43,7 +43,10 @@ import org.eclipse.jetty.util.security.Password;
|
|||
import org.eclipse.jetty.security.CrossContextPsuedoSession;
|
||||
import org.eclipse.jetty.security.authentication.DeferredAuthentication;
|
||||
import org.eclipse.jetty.security.authentication.LoginCallbackImpl;
|
||||
import org.eclipse.jetty.security.authentication.SessionAuthentication;
|
||||
import org.eclipse.jetty.security.jaspi.callback.CredentialValidationCallback;
|
||||
import org.eclipse.jetty.server.Authentication;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -214,21 +217,22 @@ public class FormAuthModule extends BaseAuthModule
|
|||
|
||||
|
||||
// Check if the session is already authenticated.
|
||||
FormCredential form_cred = (FormCredential) session.getAttribute(__J_AUTHENTICATED);
|
||||
if (form_cred != null)
|
||||
SessionAuthentication sessionAuth = (SessionAuthentication)session.getAttribute(SessionAuthentication.__J_AUTHENTICATED);
|
||||
if (sessionAuth != null)
|
||||
{
|
||||
//TODO: ideally we would like the form auth module to be able to invoke the
|
||||
//loginservice.validate() method to check the previously authed user, but it is not visible
|
||||
//to FormAuthModule
|
||||
if (form_cred._subject == null)
|
||||
if (sessionAuth.getUserIdentity().getSubject() == null)
|
||||
return AuthStatus.SEND_FAILURE;
|
||||
Set<Object> credentials = form_cred._subject.getPrivateCredentials();
|
||||
|
||||
Set<Object> credentials = sessionAuth.getUserIdentity().getSubject().getPrivateCredentials();
|
||||
if (credentials == null || credentials.isEmpty())
|
||||
return AuthStatus.SEND_FAILURE; //if no private credentials, assume it cannot be authenticated
|
||||
|
||||
clientSubject.getPrivateCredentials().addAll(credentials);
|
||||
clientSubject.getPrivateCredentials().add(sessionAuth.getUserIdentity());
|
||||
|
||||
//boolean success = tryLogin(messageInfo, clientSubject, response, session, form_cred._jUserName, new Password(new String(form_cred._jPassword)));
|
||||
return AuthStatus.SUCCESS;
|
||||
}
|
||||
else if (ssoSource != null)
|
||||
|
@ -300,8 +304,14 @@ public class FormAuthModule extends BaseAuthModule
|
|||
if (!loginCallbacks.isEmpty())
|
||||
{
|
||||
LoginCallbackImpl loginCallback = loginCallbacks.iterator().next();
|
||||
FormCredential form_cred = new FormCredential(username, pwdChars, loginCallback.getUserPrincipal(), loginCallback.getSubject());
|
||||
session.setAttribute(__J_AUTHENTICATED, form_cred);
|
||||
Set<UserIdentity> userIdentities = clientSubject.getPrivateCredentials(UserIdentity.class);
|
||||
if (!userIdentities.isEmpty())
|
||||
{
|
||||
UserIdentity userIdentity = userIdentities.iterator().next();
|
||||
|
||||
SessionAuthentication sessionAuth = new SessionAuthentication(Constraint.__FORM_AUTH, userIdentity, password);
|
||||
session.setAttribute(SessionAuthentication.__J_AUTHENTICATED, sessionAuth);
|
||||
}
|
||||
}
|
||||
|
||||
// Sign-on to SSO mechanism
|
||||
|
@ -320,61 +330,4 @@ public class FormAuthModule extends BaseAuthModule
|
|||
return pathInContext != null && (pathInContext.equals(_formErrorPath) || pathInContext.equals(_formLoginPath));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* FORM Authentication credential holder.
|
||||
*/
|
||||
private static class FormCredential implements Serializable, HttpSessionBindingListener
|
||||
{
|
||||
String _jUserName;
|
||||
|
||||
char[] _jPassword;
|
||||
|
||||
transient Principal _userPrincipal;
|
||||
|
||||
transient Subject _subject;
|
||||
|
||||
private FormCredential(String _jUserName, char[] _jPassword, Principal _userPrincipal, Subject subject)
|
||||
{
|
||||
this._jUserName = _jUserName;
|
||||
this._jPassword = _jPassword;
|
||||
this._userPrincipal = _userPrincipal;
|
||||
this._subject = subject;
|
||||
}
|
||||
|
||||
public void valueBound(HttpSessionBindingEvent event)
|
||||
{
|
||||
}
|
||||
|
||||
public void valueUnbound(HttpSessionBindingEvent event)
|
||||
{
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Logout " + _jUserName);
|
||||
|
||||
// TODO jaspi call cleanSubject()
|
||||
// if (_realm instanceof SSORealm)
|
||||
// ((SSORealm) _realm).clearSingleSignOn(_jUserName);
|
||||
//
|
||||
// if (_realm != null && _userPrincipal != null)
|
||||
// _realm.logout(_userPrincipal);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return _jUserName.hashCode() + _jPassword.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (!(o instanceof FormCredential)) return false;
|
||||
FormCredential fc = (FormCredential) o;
|
||||
return _jUserName.equals(fc._jUserName) && Arrays.equals(_jPassword, fc._jPassword);
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "Cred[" + _jUserName + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.util.HashMap;
|
|||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
|
@ -251,7 +252,7 @@ public class MBeanContainer extends AbstractLifeCycle implements Container.Liste
|
|||
//no override mbean object name, so make a generic one
|
||||
if (oname == null)
|
||||
{
|
||||
String type = obj.getClass().getName().toLowerCase();
|
||||
String type = obj.getClass().getName().toLowerCase(Locale.ENGLISH);
|
||||
int dot = type.lastIndexOf('.');
|
||||
if (dot >= 0)
|
||||
type = type.substring(dot + 1);
|
||||
|
|
|
@ -564,7 +564,7 @@ public class ObjectMBean implements DynamicMBean
|
|||
}
|
||||
|
||||
|
||||
String uName = name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
String uName = name.substring(0, 1).toUpperCase(Locale.ENGLISH) + name.substring(1);
|
||||
Class oClass = onMBean ? this.getClass() : _managed.getClass();
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
|
|
|
@ -99,74 +99,41 @@ public class ContextFactory implements ObjectFactory
|
|||
return ctx;
|
||||
}
|
||||
|
||||
// Next, see if we are in a webapp context, if we are, use
|
||||
// the classloader of the webapp to find the right jndi comp context
|
||||
ClassLoader loader = null;
|
||||
if (ContextHandler.getCurrentContext() != null)
|
||||
|
||||
loader = Thread.currentThread().getContextClassLoader();
|
||||
if (__log.isDebugEnabled() && loader != null) __log.debug("Using thread context classloader");
|
||||
|
||||
if (loader == null && ContextHandler.getCurrentContext() != null)
|
||||
{
|
||||
loader = ContextHandler.getCurrentContext().getContextHandler().getClassLoader();
|
||||
if (__log.isDebugEnabled() && loader != null) __log.debug("Using classloader of current org.eclipse.jetty.server.handler.ContextHandler");
|
||||
}
|
||||
|
||||
|
||||
if (loader != null)
|
||||
{
|
||||
if (__log.isDebugEnabled()) __log.debug("Using classloader of current org.eclipse.jetty.server.handler.ContextHandler");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Not already in a webapp context, in that case, we try the
|
||||
//curren't thread's classloader instead
|
||||
loader = Thread.currentThread().getContextClassLoader();
|
||||
if (__log.isDebugEnabled()) __log.debug("Using thread context classloader");
|
||||
}
|
||||
|
||||
|
||||
//Get the context matching the classloader
|
||||
ctx = (Context)__contextMap.get(loader);
|
||||
|
||||
|
||||
//The map does not contain an entry for this classloader
|
||||
if (ctx == null)
|
||||
{
|
||||
//Check if a parent classloader has created the context
|
||||
ctx = getParentClassLoaderContext(loader);
|
||||
//Didn't find a context to match, make one
|
||||
Reference ref = (Reference)obj;
|
||||
StringRefAddr parserAddr = (StringRefAddr)ref.get("parser");
|
||||
String parserClassName = (parserAddr==null?null:(String)parserAddr.getContent());
|
||||
NameParser parser = (NameParser)(parserClassName==null?null:loader.loadClass(parserClassName).newInstance());
|
||||
|
||||
//Didn't find a context to match any of the ancestors
|
||||
//of the classloader, so make a context
|
||||
if (ctx == null)
|
||||
{
|
||||
Reference ref = (Reference)obj;
|
||||
StringRefAddr parserAddr = (StringRefAddr)ref.get("parser");
|
||||
String parserClassName = (parserAddr==null?null:(String)parserAddr.getContent());
|
||||
NameParser parser = (NameParser)(parserClassName==null?null:loader.loadClass(parserClassName).newInstance());
|
||||
|
||||
ctx = new NamingContext (env,
|
||||
name.get(0),
|
||||
(NamingContext)nameCtx,
|
||||
parser);
|
||||
if(__log.isDebugEnabled())__log.debug("No entry for classloader: "+loader);
|
||||
__contextMap.put (loader, ctx);
|
||||
}
|
||||
ctx = new NamingContext (env,
|
||||
name.get(0),
|
||||
(NamingContext)nameCtx,
|
||||
parser);
|
||||
if(__log.isDebugEnabled())__log.debug("Made context "+name.get(0)+" for classloader: "+loader);
|
||||
__contextMap.put (loader, ctx);
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep trying ancestors of the given classloader to find one to which
|
||||
* the context is bound.
|
||||
* @param loader
|
||||
* @return the context from the parent class loader
|
||||
*/
|
||||
public Context getParentClassLoaderContext (ClassLoader loader)
|
||||
{
|
||||
Context ctx = null;
|
||||
ClassLoader cl = loader;
|
||||
for (cl = cl.getParent(); (cl != null) && (ctx == null); cl = cl.getParent())
|
||||
{
|
||||
ctx = (Context)__contextMap.get(cl);
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -37,6 +37,7 @@ import javax.naming.Reference;
|
|||
import javax.naming.StringRefAddr;
|
||||
import javax.naming.spi.ObjectFactory;
|
||||
|
||||
import org.eclipse.jetty.jndi.ContextFactory;
|
||||
import org.eclipse.jetty.jndi.NamingContext;
|
||||
import org.eclipse.jetty.jndi.NamingUtil;
|
||||
import org.eclipse.jetty.jndi.local.localContextRoot;
|
||||
|
@ -47,7 +48,8 @@ import org.junit.Test;
|
|||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -74,14 +76,16 @@ public class TestJNDI
|
|||
@Test
|
||||
public void testIt() throws Exception
|
||||
{
|
||||
//set up some classloaders
|
||||
Thread currentThread = Thread.currentThread();
|
||||
ClassLoader currentLoader = currentThread.getContextClassLoader();
|
||||
ClassLoader childLoader1 = new URLClassLoader(new URL[0], currentLoader);
|
||||
ClassLoader childLoader2 = new URLClassLoader(new URL[0], currentLoader);
|
||||
|
||||
try
|
||||
{
|
||||
//set up some classloaders
|
||||
Thread currentThread = Thread.currentThread();
|
||||
ClassLoader currentLoader = currentThread.getContextClassLoader();
|
||||
ClassLoader childLoader1 = new URLClassLoader(new URL[0], currentLoader);
|
||||
ClassLoader childLoader2 = new URLClassLoader(new URL[0], currentLoader);
|
||||
|
||||
//Uncomment to aid with debug
|
||||
/*
|
||||
javaRootURLContext.getRoot().addListener(new NamingContext.Listener()
|
||||
{
|
||||
|
@ -119,7 +123,19 @@ public class TestJNDI
|
|||
InitialContext initCtxA = new InitialContext();
|
||||
initCtxA.bind ("blah", "123");
|
||||
assertEquals ("123", initCtxA.lookup("blah"));
|
||||
|
||||
|
||||
initCtxA.destroySubcontext("blah");
|
||||
try
|
||||
{
|
||||
initCtxA.lookup("blah");
|
||||
fail("context blah was not destroyed");
|
||||
}
|
||||
catch (NameNotFoundException e)
|
||||
{
|
||||
//expected
|
||||
}
|
||||
|
||||
|
||||
InitialContext initCtx = new InitialContext();
|
||||
Context sub0 = (Context)initCtx.lookup("java:");
|
||||
|
||||
|
@ -219,6 +235,7 @@ public class TestJNDI
|
|||
try
|
||||
{
|
||||
initCtx.lookup("java:comp/env/rubbish");
|
||||
fail("env should not exist for this classloader");
|
||||
}
|
||||
catch (NameNotFoundException e)
|
||||
{
|
||||
|
@ -287,18 +304,77 @@ public class TestJNDI
|
|||
{
|
||||
//expected failure to modify immutable context
|
||||
}
|
||||
|
||||
System.err.println("java:"+javaRootURLContext.getRoot().dump());
|
||||
System.err.println("local:"+localContextRoot.getRoot().dump());
|
||||
|
||||
//test what happens when you close an initial context that was used
|
||||
initCtx.close();
|
||||
}
|
||||
finally
|
||||
{
|
||||
//make some effort to clean up
|
||||
InitialContext ic = new InitialContext();
|
||||
Context java = (Context)ic.lookup("java:");
|
||||
java.destroySubcontext("zero");
|
||||
java.destroySubcontext("fee");
|
||||
currentThread.setContextClassLoader(childLoader1);
|
||||
Context comp = (Context)ic.lookup("java:comp");
|
||||
comp.destroySubcontext("env");
|
||||
comp.unbind("crud");
|
||||
comp.unbind("crud2");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testParent()
|
||||
throws Exception
|
||||
{
|
||||
//set up some classloaders
|
||||
Thread currentThread = Thread.currentThread();
|
||||
ClassLoader parentLoader = currentThread.getContextClassLoader();
|
||||
ClassLoader childLoader1 = new URLClassLoader(new URL[0], parentLoader);
|
||||
|
||||
try
|
||||
{
|
||||
//Test creating a comp for the parent loader does not leak to child
|
||||
InitialContext initCtx = new InitialContext();
|
||||
Context comp = (Context)initCtx.lookup("java:comp");
|
||||
assertNotNull(comp);
|
||||
|
||||
Context env = (Context)comp.createSubcontext("env");
|
||||
assertNotNull(env);
|
||||
|
||||
env.bind("foo", "aaabbbcccddd");
|
||||
assertEquals("aaabbbcccddd", (String)initCtx.lookup("java:comp/env/foo"));
|
||||
|
||||
//Change to child loader
|
||||
currentThread.setContextClassLoader(childLoader1);
|
||||
comp = (Context)initCtx.lookup("java:comp");
|
||||
|
||||
Context childEnv = (Context)comp.createSubcontext("env");
|
||||
assertNotSame(env, childEnv);
|
||||
|
||||
childEnv.bind("foo", "eeefffggghhh");
|
||||
assertEquals("eeefffggghhh", (String)initCtx.lookup("java:comp/env/foo"));
|
||||
|
||||
//Change back to parent
|
||||
currentThread.setContextClassLoader(parentLoader);
|
||||
assertEquals("aaabbbcccddd", (String)initCtx.lookup("java:comp/env/foo"));
|
||||
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
//make some effort to clean up
|
||||
InitialContext ic = new InitialContext();
|
||||
currentThread.setContextClassLoader(parentLoader);
|
||||
Context comp = (Context)ic.lookup("java:comp");
|
||||
comp.destroySubcontext("env");
|
||||
|
||||
currentThread.setContextClassLoader(childLoader1);
|
||||
comp = (Context)ic.lookup("java:comp");
|
||||
comp.destroySubcontext("env");
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -216,7 +216,7 @@ public class MongoSessionIdManager extends AbstractSessionIdManager
|
|||
BasicDBObject invalidQuery = new BasicDBObject();
|
||||
|
||||
invalidQuery.put(MongoSessionManager.__ACCESSED, new BasicDBObject("$lt",System.currentTimeMillis() - _purgeInvalidAge));
|
||||
invalidQuery.put(MongoSessionManager.__VALID, __valid_false);
|
||||
invalidQuery.put(MongoSessionManager.__VALID, false);
|
||||
|
||||
DBCursor oldSessions = _sessions.find(invalidQuery, new BasicDBObject(MongoSessionManager.__ID, 1));
|
||||
|
||||
|
@ -234,9 +234,9 @@ public class MongoSessionIdManager extends AbstractSessionIdManager
|
|||
BasicDBObject validQuery = new BasicDBObject();
|
||||
|
||||
validQuery.put(MongoSessionManager.__ACCESSED,new BasicDBObject("$lt",System.currentTimeMillis() - _purgeValidAge));
|
||||
validQuery.put(MongoSessionManager.__VALID, __valid_false);
|
||||
validQuery.put(MongoSessionManager.__VALID, true);
|
||||
|
||||
oldSessions = _sessions.find(invalidQuery,new BasicDBObject(MongoSessionManager.__ID,1));
|
||||
oldSessions = _sessions.find(validQuery,new BasicDBObject(MongoSessionManager.__ID,1));
|
||||
|
||||
for (DBObject session : oldSessions)
|
||||
{
|
||||
|
@ -410,7 +410,8 @@ public class MongoSessionIdManager extends AbstractSessionIdManager
|
|||
purge();
|
||||
}
|
||||
};
|
||||
_purgeTimer.schedule(_purgeTask,_purgeDelay);
|
||||
|
||||
_purgeTimer.schedule(_purgeTask,0,_purgeDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@ package org.eclipse.jetty.osgi.annotations;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.annotations.AbstractDiscoverableAnnotationHandler;
|
||||
import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
|
||||
import org.eclipse.jetty.annotations.ClassNameResolver;
|
||||
import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
|
||||
import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
|
||||
|
@ -151,20 +153,25 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot
|
|||
protected void parseBundle(WebAppContext context, AnnotationParser parser,
|
||||
Bundle webbundle, Bundle bundle) throws Exception
|
||||
{
|
||||
|
||||
Resource bundleRes = parser.getResource(bundle);
|
||||
|
||||
parser.clearHandlers();
|
||||
for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
|
||||
{
|
||||
if (h instanceof AbstractDiscoverableAnnotationHandler)
|
||||
{
|
||||
if (webbundle == bundle)
|
||||
((AbstractDiscoverableAnnotationHandler)h).setResource(null);
|
||||
else
|
||||
((AbstractDiscoverableAnnotationHandler)h).setResource(bundleRes);
|
||||
}
|
||||
}
|
||||
parser.registerHandlers(_discoverableAnnotationHandlers);
|
||||
parser.registerHandler(_classInheritanceHandler);
|
||||
parser.registerHandlers(_containerInitializerAnnotationHandlers);
|
||||
|
||||
parser.parse(bundle,createClassNameResolver(context));
|
||||
List<DiscoveredAnnotation> annotations = new ArrayList<DiscoveredAnnotation>();
|
||||
gatherAnnotations(annotations, parser.getAnnotationHandlers());
|
||||
if (webbundle == bundle)
|
||||
{
|
||||
//just like the super with its question about annotations in WEB-INF/classes:
|
||||
//"TODO - where to set the annotations discovered from WEB-INF/classes?"
|
||||
context.getMetaData().addDiscoveredAnnotations(annotations);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.getMetaData().addDiscoveredAnnotations(bundleRes, annotations);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -109,7 +110,7 @@ public class LibExtClassLoaderHelper
|
|||
for (File f : jettyResources.listFiles())
|
||||
{
|
||||
jettyResFiles.put(f.getName(), f);
|
||||
if (f.getName().toLowerCase().startsWith("readme"))
|
||||
if (f.getName().toLowerCase(Locale.ENGLISH).startsWith("readme"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import java.util.Enumeration;
|
|||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
@ -389,7 +390,7 @@ public class OverlayedAppProvider extends AbstractLifeCycle implements AppProvid
|
|||
List<URL> libs = new ArrayList<URL>();
|
||||
for (String jar :instance_lib.list())
|
||||
{
|
||||
if (!jar.toLowerCase().endsWith(".jar"))
|
||||
if (!jar.toLowerCase(Locale.ENGLISH).endsWith(".jar"))
|
||||
continue;
|
||||
libs.add(instance_lib.addPath(jar).getURL());
|
||||
}
|
||||
|
@ -610,7 +611,7 @@ public class OverlayedAppProvider extends AbstractLifeCycle implements AppProvid
|
|||
{
|
||||
for (String jar :lib.list())
|
||||
{
|
||||
if (!jar.toLowerCase().endsWith(".jar"))
|
||||
if (!jar.toLowerCase(Locale.ENGLISH).endsWith(".jar"))
|
||||
continue;
|
||||
libs.add(lib.addPath(jar).getURL());
|
||||
}
|
||||
|
@ -832,12 +833,12 @@ public class OverlayedAppProvider extends AbstractLifeCycle implements AppProvid
|
|||
File origin = new File(new URI(_scanDir.toURI()+ruri));
|
||||
String name=origin.getName();
|
||||
|
||||
Monitor monitor = Monitor.valueOf(origin.getParentFile().getName().toUpperCase());
|
||||
Monitor monitor = Monitor.valueOf(origin.getParentFile().getName().toUpperCase(Locale.ENGLISH));
|
||||
|
||||
String ext=".war";
|
||||
|
||||
// check directory vs archive
|
||||
if (origin.isDirectory() || !origin.exists() && !ruri.toLowerCase().endsWith(ext))
|
||||
if (origin.isDirectory() || !origin.exists() && !ruri.toLowerCase(Locale.ENGLISH).endsWith(ext))
|
||||
{
|
||||
// directories have priority over archives
|
||||
directory=origin;
|
||||
|
@ -846,7 +847,7 @@ public class OverlayedAppProvider extends AbstractLifeCycle implements AppProvid
|
|||
else
|
||||
{
|
||||
// check extension name
|
||||
if (!ruri.toLowerCase().endsWith(ext))
|
||||
if (!ruri.toLowerCase(Locale.ENGLISH).endsWith(ext))
|
||||
continue;
|
||||
|
||||
name=name.substring(0,name.length()-4);
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.plus.annotation;
|
|||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NamingException;
|
||||
|
@ -141,7 +142,7 @@ public class Injection
|
|||
_resourceClass = resourceType;
|
||||
|
||||
//first look for a javabeans style setter matching the targetName
|
||||
String setter = "set"+target.substring(0,1).toUpperCase()+target.substring(1);
|
||||
String setter = "set"+target.substring(0,1).toUpperCase(Locale.ENGLISH)+target.substring(1);
|
||||
try
|
||||
{
|
||||
LOG.debug("Looking for method for setter: "+setter+" with arg "+_resourceClass);
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.io.IOException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
|
@ -653,12 +654,12 @@ public class LdapLoginModule extends AbstractLoginModule
|
|||
|
||||
public static String convertCredentialJettyToLdap(String encryptedPassword)
|
||||
{
|
||||
if ("MD5:".startsWith(encryptedPassword.toUpperCase()))
|
||||
if ("MD5:".startsWith(encryptedPassword.toUpperCase(Locale.ENGLISH)))
|
||||
{
|
||||
return "{MD5}" + encryptedPassword.substring("MD5:".length(), encryptedPassword.length());
|
||||
}
|
||||
|
||||
if ("CRYPT:".startsWith(encryptedPassword.toUpperCase()))
|
||||
if ("CRYPT:".startsWith(encryptedPassword.toUpperCase(Locale.ENGLISH)))
|
||||
{
|
||||
return "{CRYPT}" + encryptedPassword.substring("CRYPT:".length(), encryptedPassword.length());
|
||||
}
|
||||
|
@ -673,12 +674,12 @@ public class LdapLoginModule extends AbstractLoginModule
|
|||
return encryptedPassword;
|
||||
}
|
||||
|
||||
if ("{MD5}".startsWith(encryptedPassword.toUpperCase()))
|
||||
if ("{MD5}".startsWith(encryptedPassword.toUpperCase(Locale.ENGLISH)))
|
||||
{
|
||||
return "MD5:" + encryptedPassword.substring("{MD5}".length(), encryptedPassword.length());
|
||||
}
|
||||
|
||||
if ("{CRYPT}".startsWith(encryptedPassword.toUpperCase()))
|
||||
if ("{CRYPT}".startsWith(encryptedPassword.toUpperCase(Locale.ENGLISH)))
|
||||
{
|
||||
return "CRYPT:" + encryptedPassword.substring("{CRYPT}".length(), encryptedPassword.length());
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.sql.ResultSet;
|
|||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NameNotFoundException;
|
||||
|
@ -414,7 +415,7 @@ public class DataSourceLoginService extends MappedLoginService
|
|||
DatabaseMetaData metaData = connection.getMetaData();
|
||||
|
||||
//check if tables exist
|
||||
String tableName = (metaData.storesLowerCaseIdentifiers()? _userTableName.toLowerCase(): (metaData.storesUpperCaseIdentifiers()?_userTableName.toUpperCase(): _userTableName));
|
||||
String tableName = (metaData.storesLowerCaseIdentifiers()? _userTableName.toLowerCase(Locale.ENGLISH): (metaData.storesUpperCaseIdentifiers()?_userTableName.toUpperCase(Locale.ENGLISH): _userTableName));
|
||||
ResultSet result = metaData.getTables(null, null, tableName, null);
|
||||
if (!result.next())
|
||||
{
|
||||
|
@ -432,7 +433,7 @@ public class DataSourceLoginService extends MappedLoginService
|
|||
|
||||
result.close();
|
||||
|
||||
tableName = (metaData.storesLowerCaseIdentifiers()? _roleTableName.toLowerCase(): (metaData.storesUpperCaseIdentifiers()?_roleTableName.toUpperCase(): _roleTableName));
|
||||
tableName = (metaData.storesLowerCaseIdentifiers()? _roleTableName.toLowerCase(Locale.ENGLISH): (metaData.storesUpperCaseIdentifiers()?_roleTableName.toUpperCase(Locale.ENGLISH): _roleTableName));
|
||||
result = metaData.getTables(null, null, tableName, null);
|
||||
if (!result.next())
|
||||
{
|
||||
|
@ -449,7 +450,7 @@ public class DataSourceLoginService extends MappedLoginService
|
|||
|
||||
result.close();
|
||||
|
||||
tableName = (metaData.storesLowerCaseIdentifiers()? _userRoleTableName.toLowerCase(): (metaData.storesUpperCaseIdentifiers()?_userRoleTableName.toUpperCase(): _userRoleTableName));
|
||||
tableName = (metaData.storesLowerCaseIdentifiers()? _userRoleTableName.toLowerCase(Locale.ENGLISH): (metaData.storesUpperCaseIdentifiers()?_userRoleTableName.toUpperCase(Locale.ENGLISH): _userRoleTableName));
|
||||
result = metaData.getTables(null, null, tableName, null);
|
||||
if (!result.next())
|
||||
{
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.io.OutputStream;
|
|||
import java.net.MalformedURLException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
@ -229,7 +230,7 @@ public class ProxyRule extends PatternRule
|
|||
@Override
|
||||
protected void onResponseHeader(Buffer name, Buffer value) throws IOException
|
||||
{
|
||||
String s = name.toString().toLowerCase();
|
||||
String s = name.toString().toLowerCase(Locale.ENGLISH);
|
||||
if (!_DontProxyHeaders.contains(s) || (HttpHeaders.CONNECTION_BUFFER.equals(name) && HttpHeaderValues.CLOSE_BUFFER.equals(value)))
|
||||
{
|
||||
if (debug != 0)
|
||||
|
@ -348,7 +349,7 @@ public class ProxyRule extends PatternRule
|
|||
String connectionHdr = request.getHeader("Connection");
|
||||
if (connectionHdr != null)
|
||||
{
|
||||
connectionHdr = connectionHdr.toLowerCase();
|
||||
connectionHdr = connectionHdr.toLowerCase(Locale.ENGLISH);
|
||||
if (connectionHdr.indexOf("keep-alive") < 0 && connectionHdr.indexOf("close") < 0)
|
||||
{
|
||||
connectionHdr = null;
|
||||
|
@ -370,7 +371,7 @@ public class ProxyRule extends PatternRule
|
|||
{
|
||||
// TODO could be better than this!
|
||||
String hdr = (String)enm.nextElement();
|
||||
String lhdr = hdr.toLowerCase();
|
||||
String lhdr = hdr.toLowerCase(Locale.ENGLISH);
|
||||
|
||||
if (_DontProxyHeaders.contains(lhdr))
|
||||
continue;
|
||||
|
|
|
@ -77,6 +77,20 @@ public class RewriteHandlerTest extends AbstractRuleTestCase
|
|||
@Test
|
||||
public void test() throws Exception
|
||||
{
|
||||
_response.setStatus(200);
|
||||
_request.setHandled(false);
|
||||
_handler.setOriginalPathAttribute("/before");
|
||||
_handler.setRewriteRequestURI(true);
|
||||
_handler.setRewritePathInfo(true);
|
||||
_request.setRequestURI("/xxx/bar");
|
||||
_request.setPathInfo("/xxx/bar");
|
||||
_handler.handle("/xxx/bar",_request,_request, _response);
|
||||
assertEquals(201,_response.getStatus());
|
||||
assertEquals("/bar/zzz",_request.getAttribute("target"));
|
||||
assertEquals("/bar/zzz",_request.getAttribute("URI"));
|
||||
assertEquals("/bar/zzz",_request.getAttribute("info"));
|
||||
assertEquals(null,_request.getAttribute("before"));
|
||||
|
||||
_response.setStatus(200);
|
||||
_request.setHandled(false);
|
||||
_handler.setOriginalPathAttribute("/before");
|
||||
|
|
|
@ -19,16 +19,24 @@
|
|||
package org.eclipse.jetty.security;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
import javax.servlet.HttpConstraintElement;
|
||||
import javax.servlet.HttpMethodConstraintElement;
|
||||
import javax.servlet.ServletSecurityElement;
|
||||
import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
|
||||
import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
|
||||
|
||||
import org.eclipse.jetty.http.PathMap;
|
||||
import org.eclipse.jetty.server.AbstractHttpConnection;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
|
@ -42,17 +50,225 @@ import org.eclipse.jetty.util.security.Constraint;
|
|||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Handler to enforce SecurityConstraints. This implementation is servlet spec
|
||||
* 2.4 compliant and precomputes the constraint combinations for runtime
|
||||
* 3.0 compliant and precomputes the constraint combinations for runtime
|
||||
* efficiency.
|
||||
*
|
||||
*/
|
||||
public class ConstraintSecurityHandler extends SecurityHandler implements ConstraintAware
|
||||
{
|
||||
private static final String OMISSION_SUFFIX = ".omission";
|
||||
|
||||
private final List<ConstraintMapping> _constraintMappings= new CopyOnWriteArrayList<ConstraintMapping>();
|
||||
private final Set<String> _roles = new CopyOnWriteArraySet<String>();
|
||||
private final PathMap _constraintMap = new PathMap();
|
||||
private boolean _strict = true;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public static Constraint createConstraint()
|
||||
{
|
||||
return new Constraint();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param constraint
|
||||
* @return
|
||||
*/
|
||||
public static Constraint createConstraint(Constraint constraint)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (Constraint)constraint.clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e)
|
||||
{
|
||||
throw new IllegalStateException (e);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Create a security constraint
|
||||
*
|
||||
* @param name
|
||||
* @param authenticate
|
||||
* @param roles
|
||||
* @param dataConstraint
|
||||
* @return
|
||||
*/
|
||||
public static Constraint createConstraint (String name, boolean authenticate, String[] roles, int dataConstraint)
|
||||
{
|
||||
Constraint constraint = createConstraint();
|
||||
if (name != null)
|
||||
constraint.setName(name);
|
||||
constraint.setAuthenticate(authenticate);
|
||||
constraint.setRoles(roles);
|
||||
constraint.setDataConstraint(dataConstraint);
|
||||
return constraint;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param name
|
||||
* @param element
|
||||
* @return
|
||||
*/
|
||||
public static Constraint createConstraint (String name, HttpConstraintElement element)
|
||||
{
|
||||
return createConstraint(name, element.getRolesAllowed(), element.getEmptyRoleSemantic(), element.getTransportGuarantee());
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param name
|
||||
* @param rolesAllowed
|
||||
* @param permitOrDeny
|
||||
* @param transport
|
||||
* @return
|
||||
*/
|
||||
public static Constraint createConstraint (String name, String[] rolesAllowed, EmptyRoleSemantic permitOrDeny, TransportGuarantee transport)
|
||||
{
|
||||
Constraint constraint = createConstraint();
|
||||
|
||||
if (rolesAllowed == null || rolesAllowed.length==0)
|
||||
{
|
||||
if (permitOrDeny.equals(EmptyRoleSemantic.DENY))
|
||||
{
|
||||
//Equivalent to <auth-constraint> with no roles
|
||||
constraint.setName(name+"-Deny");
|
||||
constraint.setAuthenticate(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Equivalent to no <auth-constraint>
|
||||
constraint.setName(name+"-Permit");
|
||||
constraint.setAuthenticate(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Equivalent to <auth-constraint> with list of <security-role-name>s
|
||||
constraint.setAuthenticate(true);
|
||||
constraint.setRoles(rolesAllowed);
|
||||
constraint.setName(name+"-RolesAllowed");
|
||||
}
|
||||
|
||||
//Equivalent to //<user-data-constraint><transport-guarantee>CONFIDENTIAL</transport-guarantee></user-data-constraint>
|
||||
constraint.setDataConstraint((transport.equals(TransportGuarantee.CONFIDENTIAL)?Constraint.DC_CONFIDENTIAL:Constraint.DC_NONE));
|
||||
return constraint;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param pathSpec
|
||||
* @param constraintMappings
|
||||
* @return
|
||||
*/
|
||||
public static List<ConstraintMapping> getConstraintMappingsForPath(String pathSpec, List<ConstraintMapping> constraintMappings)
|
||||
{
|
||||
if (pathSpec == null || "".equals(pathSpec.trim()) || constraintMappings == null || constraintMappings.size() == 0)
|
||||
return Collections.emptyList();
|
||||
|
||||
List<ConstraintMapping> mappings = new ArrayList<ConstraintMapping>();
|
||||
for (ConstraintMapping mapping:constraintMappings)
|
||||
{
|
||||
if (pathSpec.equals(mapping.getPathSpec()))
|
||||
{
|
||||
mappings.add(mapping);
|
||||
}
|
||||
}
|
||||
return mappings;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Take out of the constraint mappings those that match the
|
||||
* given path.
|
||||
*
|
||||
* @param pathSpec
|
||||
* @param constraintMappings a new list minus the matching constraints
|
||||
* @return
|
||||
*/
|
||||
public static List<ConstraintMapping> removeConstraintMappingsForPath(String pathSpec, List<ConstraintMapping> constraintMappings)
|
||||
{
|
||||
if (pathSpec == null || "".equals(pathSpec.trim()) || constraintMappings == null || constraintMappings.size() == 0)
|
||||
return Collections.emptyList();
|
||||
|
||||
List<ConstraintMapping> mappings = new ArrayList<ConstraintMapping>();
|
||||
for (ConstraintMapping mapping:constraintMappings)
|
||||
{
|
||||
//Remove the matching mappings by only copying in non-matching mappings
|
||||
if (!pathSpec.equals(mapping.getPathSpec()))
|
||||
{
|
||||
mappings.add(mapping);
|
||||
}
|
||||
}
|
||||
return mappings;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Generate Constraints and ContraintMappings for the given url pattern and ServletSecurityElement
|
||||
*
|
||||
* @param name
|
||||
* @param pathSpec
|
||||
* @param securityElement
|
||||
* @return
|
||||
*/
|
||||
public static List<ConstraintMapping> createConstraintsWithMappingsForPath (String name, String pathSpec, ServletSecurityElement securityElement)
|
||||
{
|
||||
List<ConstraintMapping> mappings = new ArrayList<ConstraintMapping>();
|
||||
|
||||
//Create a constraint that will describe the default case (ie if not overridden by specific HttpMethodConstraints)
|
||||
Constraint constraint = ConstraintSecurityHandler.createConstraint(name, securityElement);
|
||||
|
||||
//Create a mapping for the pathSpec for the default case
|
||||
ConstraintMapping defaultMapping = new ConstraintMapping();
|
||||
defaultMapping.setPathSpec(pathSpec);
|
||||
defaultMapping.setConstraint(constraint);
|
||||
mappings.add(defaultMapping);
|
||||
|
||||
|
||||
//See Spec 13.4.1.2 p127
|
||||
List<String> methodOmissions = new ArrayList<String>();
|
||||
|
||||
//make constraint mappings for this url for each of the HttpMethodConstraintElements
|
||||
Collection<HttpMethodConstraintElement> methodConstraints = securityElement.getHttpMethodConstraints();
|
||||
if (methodConstraints != null)
|
||||
{
|
||||
for (HttpMethodConstraintElement methodConstraint:methodConstraints)
|
||||
{
|
||||
//Make a Constraint that captures the <auth-constraint> and <user-data-constraint> elements supplied for the HttpMethodConstraintElement
|
||||
Constraint mconstraint = ConstraintSecurityHandler.createConstraint(name, methodConstraint);
|
||||
ConstraintMapping mapping = new ConstraintMapping();
|
||||
mapping.setConstraint(mconstraint);
|
||||
mapping.setPathSpec(pathSpec);
|
||||
if (methodConstraint.getMethodName() != null)
|
||||
{
|
||||
mapping.setMethod(methodConstraint.getMethodName());
|
||||
//See spec 13.4.1.2 p127 - add an omission for every method name to the default constraint
|
||||
methodOmissions.add(methodConstraint.getMethodName());
|
||||
}
|
||||
mappings.add(mapping);
|
||||
}
|
||||
}
|
||||
//See spec 13.4.1.2 p127 - add an omission for every method name to the default constraint
|
||||
if (methodOmissions.size() > 0)
|
||||
defaultMapping.setMethodOmissions(methodOmissions.toArray(new String[methodOmissions.size()]));
|
||||
|
||||
return mappings;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the strict mode.
|
||||
* @return true if the security handler is running in strict mode.
|
||||
|
@ -136,8 +352,6 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
*/
|
||||
public void setConstraintMappings(List<ConstraintMapping> constraintMappings, Set<String> roles)
|
||||
{
|
||||
if (isStarted())
|
||||
throw new IllegalStateException("Started");
|
||||
_constraintMappings.clear();
|
||||
_constraintMappings.addAll(constraintMappings);
|
||||
|
||||
|
@ -156,6 +370,14 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
}
|
||||
}
|
||||
setRoles(roles);
|
||||
|
||||
if (isStarted())
|
||||
{
|
||||
for (ConstraintMapping mapping : _constraintMappings)
|
||||
{
|
||||
processConstraintMapping(mapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -168,9 +390,6 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
*/
|
||||
public void setRoles(Set<String> roles)
|
||||
{
|
||||
if (isStarted())
|
||||
throw new IllegalStateException("Started");
|
||||
|
||||
_roles.clear();
|
||||
_roles.addAll(roles);
|
||||
}
|
||||
|
@ -232,7 +451,9 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
}
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
|
@ -241,7 +462,15 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
_roles.clear();
|
||||
super.doStop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Create and combine the constraint with the existing processed
|
||||
* constraints.
|
||||
*
|
||||
* @param mapping
|
||||
*/
|
||||
protected void processConstraintMapping(ConstraintMapping mapping)
|
||||
{
|
||||
Map<String, RoleInfo> mappings = (Map<String, RoleInfo>)_constraintMap.get(mapping.getPathSpec());
|
||||
|
@ -253,8 +482,15 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
RoleInfo allMethodsRoleInfo = mappings.get(null);
|
||||
if (allMethodsRoleInfo != null && allMethodsRoleInfo.isForbidden())
|
||||
return;
|
||||
|
||||
if (mapping.getMethodOmissions() != null && mapping.getMethodOmissions().length > 0)
|
||||
{
|
||||
|
||||
processConstraintMappingWithMethodOmissions(mapping, mappings);
|
||||
return;
|
||||
}
|
||||
|
||||
String httpMethod = mapping.getMethod();
|
||||
String httpMethod = mapping.getMethod();
|
||||
RoleInfo roleInfo = mappings.get(httpMethod);
|
||||
if (roleInfo == null)
|
||||
{
|
||||
|
@ -268,10 +504,10 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
if (roleInfo.isForbidden())
|
||||
return;
|
||||
|
||||
Constraint constraint = mapping.getConstraint();
|
||||
boolean forbidden = constraint.isForbidden();
|
||||
roleInfo.setForbidden(forbidden);
|
||||
if (forbidden)
|
||||
//add in info from the constraint
|
||||
configureRoleInfo(roleInfo, mapping);
|
||||
|
||||
if (roleInfo.isForbidden())
|
||||
{
|
||||
if (httpMethod == null)
|
||||
{
|
||||
|
@ -281,36 +517,7 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
}
|
||||
else
|
||||
{
|
||||
UserDataConstraint userDataConstraint = UserDataConstraint.get(constraint.getDataConstraint());
|
||||
roleInfo.setUserDataConstraint(userDataConstraint);
|
||||
|
||||
boolean checked = constraint.getAuthenticate();
|
||||
roleInfo.setChecked(checked);
|
||||
if (roleInfo.isChecked())
|
||||
{
|
||||
if (constraint.isAnyRole())
|
||||
{
|
||||
if (_strict)
|
||||
{
|
||||
// * means "all defined roles"
|
||||
for (String role : _roles)
|
||||
roleInfo.addRole(role);
|
||||
}
|
||||
else
|
||||
// * means any role
|
||||
roleInfo.setAnyRole(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
String[] newRoles = constraint.getRoles();
|
||||
for (String role : newRoles)
|
||||
{
|
||||
if (_strict &&!_roles.contains(role))
|
||||
throw new IllegalArgumentException("Attempt to use undeclared role: " + role + ", known roles: " + _roles);
|
||||
roleInfo.addRole(role);
|
||||
}
|
||||
}
|
||||
}
|
||||
//combine with any entry that covers all methods
|
||||
if (httpMethod == null)
|
||||
{
|
||||
for (Map.Entry<String, RoleInfo> entry : mappings.entrySet())
|
||||
|
@ -325,6 +532,105 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constraints that name method omissions are dealt with differently.
|
||||
* We create an entry in the mappings with key "method.omission". This entry
|
||||
* is only ever combined with other omissions for the same method to produce a
|
||||
* consolidated RoleInfo. Then, when we wish to find the relevant constraints for
|
||||
* a given Request (in prepareConstraintInfo()), we consult 3 types of entries in
|
||||
* the mappings: an entry that names the method of the Request specifically, an
|
||||
* entry that names constraints that apply to all methods, entries of the form
|
||||
* method.omission, where the method of the Request is not named in the omission.
|
||||
* @param mapping
|
||||
* @param mappings
|
||||
*/
|
||||
protected void processConstraintMappingWithMethodOmissions (ConstraintMapping mapping, Map<String, RoleInfo> mappings)
|
||||
{
|
||||
String[] omissions = mapping.getMethodOmissions();
|
||||
|
||||
for (String omission:omissions)
|
||||
{
|
||||
//for each method omission, see if there is already a RoleInfo for it in mappings
|
||||
RoleInfo ri = mappings.get(omission+OMISSION_SUFFIX);
|
||||
if (ri == null)
|
||||
{
|
||||
//if not, make one
|
||||
ri = new RoleInfo();
|
||||
mappings.put(omission+OMISSION_SUFFIX, ri);
|
||||
}
|
||||
|
||||
//initialize RoleInfo or combine from ConstraintMapping
|
||||
configureRoleInfo(ri, mapping);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Initialize or update the RoleInfo from the constraint
|
||||
* @param ri
|
||||
* @param mapping
|
||||
*/
|
||||
protected void configureRoleInfo (RoleInfo ri, ConstraintMapping mapping)
|
||||
{
|
||||
Constraint constraint = mapping.getConstraint();
|
||||
boolean forbidden = constraint.isForbidden();
|
||||
ri.setForbidden(forbidden);
|
||||
|
||||
//set up the data constraint (NOTE: must be done after setForbidden, as it nulls out the data constraint
|
||||
//which we need in order to do combining of omissions in prepareConstraintInfo
|
||||
UserDataConstraint userDataConstraint = UserDataConstraint.get(mapping.getConstraint().getDataConstraint());
|
||||
ri.setUserDataConstraint(userDataConstraint);
|
||||
|
||||
|
||||
//if forbidden, no point setting up roles
|
||||
if (!ri.isForbidden())
|
||||
{
|
||||
//add in the roles
|
||||
boolean checked = mapping.getConstraint().getAuthenticate();
|
||||
ri.setChecked(checked);
|
||||
if (ri.isChecked())
|
||||
{
|
||||
if (mapping.getConstraint().isAnyRole())
|
||||
{
|
||||
if (_strict)
|
||||
{
|
||||
// * means "all defined roles"
|
||||
for (String role : _roles)
|
||||
ri.addRole(role);
|
||||
}
|
||||
else
|
||||
// * means any role
|
||||
ri.setAnyRole(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
String[] newRoles = mapping.getConstraint().getRoles();
|
||||
for (String role : newRoles)
|
||||
{
|
||||
if (_strict &&!_roles.contains(role))
|
||||
throw new IllegalArgumentException("Attempt to use undeclared role: " + role + ", known roles: " + _roles);
|
||||
ri.addRole(role);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Find constraints that apply to the given path.
|
||||
* In order to do this, we consult 3 different types of information stored in the mappings for each path - each mapping
|
||||
* represents a merged set of user data constraints, roles etc -:
|
||||
* <ol>
|
||||
* <li>A mapping of an exact method name </li>
|
||||
* <li>A mapping will null key that matches every method name</li>
|
||||
* <li>Mappings with keys of the form "method.omission" that indicates it will match every method name EXCEPT that given</li>
|
||||
* </ol>
|
||||
*
|
||||
* @see org.eclipse.jetty.security.SecurityHandler#prepareConstraintInfo(java.lang.String, org.eclipse.jetty.server.Request)
|
||||
*/
|
||||
protected Object prepareConstraintInfo(String pathInContext, Request request)
|
||||
{
|
||||
Map<String, RoleInfo> mappings = (Map<String, RoleInfo>)_constraintMap.match(pathInContext);
|
||||
|
@ -334,13 +640,46 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
String httpMethod = request.getMethod();
|
||||
RoleInfo roleInfo = mappings.get(httpMethod);
|
||||
if (roleInfo == null)
|
||||
roleInfo = mappings.get(null);
|
||||
{
|
||||
//No specific http-method names matched
|
||||
List<RoleInfo> applicableConstraints = new ArrayList<RoleInfo>();
|
||||
|
||||
//Get info for constraint that matches all methods if it exists
|
||||
RoleInfo all = mappings.get(null);
|
||||
if (all != null)
|
||||
applicableConstraints.add(all);
|
||||
|
||||
|
||||
//Get info for constraints that name method omissions where target method name is not omitted
|
||||
//(ie matches because target method is not omitted, hence considered covered by the constraint)
|
||||
for (Entry<String, RoleInfo> entry: mappings.entrySet())
|
||||
{
|
||||
if (entry.getKey() != null && entry.getKey().contains(OMISSION_SUFFIX) && !(httpMethod+OMISSION_SUFFIX).equals(entry.getKey()))
|
||||
applicableConstraints.add(entry.getValue());
|
||||
}
|
||||
|
||||
if (applicableConstraints.size() == 1)
|
||||
roleInfo = applicableConstraints.get(0);
|
||||
else
|
||||
{
|
||||
roleInfo = new RoleInfo();
|
||||
roleInfo.setUserDataConstraint(UserDataConstraint.None);
|
||||
|
||||
for (RoleInfo r:applicableConstraints)
|
||||
roleInfo.combine(r);
|
||||
}
|
||||
|
||||
}
|
||||
return roleInfo;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.security.SecurityHandler#checkUserDataPermissions(java.lang.String, org.eclipse.jetty.server.Request, org.eclipse.jetty.server.Response, java.lang.Object)
|
||||
*/
|
||||
protected boolean checkUserDataPermissions(String pathInContext, Request request, Response response, Object constraintInfo) throws IOException
|
||||
{
|
||||
if (constraintInfo == null)
|
||||
|
@ -404,7 +743,11 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.security.SecurityHandler#isAuthMandatory(org.eclipse.jetty.server.Request, org.eclipse.jetty.server.Response, java.lang.Object)
|
||||
*/
|
||||
protected boolean isAuthMandatory(Request baseRequest, Response base_response, Object constraintInfo)
|
||||
{
|
||||
if (constraintInfo == null)
|
||||
|
@ -413,7 +756,12 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
}
|
||||
return ((RoleInfo)constraintInfo).isChecked();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.security.SecurityHandler#checkWebResourcePermissions(java.lang.String, org.eclipse.jetty.server.Request, org.eclipse.jetty.server.Response, java.lang.Object, org.eclipse.jetty.server.UserIdentity)
|
||||
*/
|
||||
@Override
|
||||
protected boolean checkWebResourcePermissions(String pathInContext, Request request, Response response, Object constraintInfo, UserIdentity userIdentity)
|
||||
throws IOException
|
||||
|
@ -454,4 +802,5 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
getBeans(),
|
||||
TypeUtil.asList(getHandlers()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -335,18 +335,22 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
|
|||
|
||||
if (_identityService==null)
|
||||
{
|
||||
|
||||
if (_loginService!=null)
|
||||
_identityService=_loginService.getIdentityService();
|
||||
|
||||
System.err.println("Null identity service, trying login service: "+_identityService);
|
||||
if (_identityService==null)
|
||||
_identityService=findIdentityService();
|
||||
|
||||
System.err.println("Finding identity service: "+_identityService);
|
||||
if (_identityService==null && _realmName!=null)
|
||||
_identityService=new DefaultIdentityService();
|
||||
}
|
||||
|
||||
if (_loginService!=null)
|
||||
{
|
||||
System.err.println("LoginService="+_loginService + " identityService="+_identityService);
|
||||
if (_loginService.getIdentityService()==null)
|
||||
_loginService.setIdentityService(_identityService);
|
||||
else if (_loginService.getIdentityService()!=_identityService)
|
||||
|
@ -525,8 +529,6 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
|
|||
else if (authentication instanceof Authentication.Deferred)
|
||||
{
|
||||
DeferredAuthentication deferred= (DeferredAuthentication)authentication;
|
||||
deferred.setIdentityService(_identityService);
|
||||
deferred.setLoginService(_loginService);
|
||||
baseRequest.setAuthentication(authentication);
|
||||
|
||||
try
|
||||
|
@ -536,7 +538,6 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
|
|||
finally
|
||||
{
|
||||
previousIdentity = deferred.getPreviousAssociation();
|
||||
deferred.setIdentityService(null);
|
||||
}
|
||||
|
||||
if (authenticator!=null)
|
||||
|
|
|
@ -54,6 +54,8 @@ public class BasicAuthenticator extends LoginAuthenticator
|
|||
return Constraint.__BASIC_AUTH;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.security.Authenticator#validateRequest(javax.servlet.ServletRequest, javax.servlet.ServletResponse, boolean)
|
||||
|
@ -67,8 +69,8 @@ public class BasicAuthenticator extends LoginAuthenticator
|
|||
try
|
||||
{
|
||||
if (!mandatory)
|
||||
return _deferred;
|
||||
|
||||
return new DeferredAuthentication(this);
|
||||
|
||||
if (credentials != null)
|
||||
{
|
||||
int space=credentials.indexOf(' ');
|
||||
|
@ -85,10 +87,9 @@ public class BasicAuthenticator extends LoginAuthenticator
|
|||
String username = credentials.substring(0,i);
|
||||
String password = credentials.substring(i+1);
|
||||
|
||||
UserIdentity user = _loginService.login(username,password);
|
||||
UserIdentity user = login (username, password, request);
|
||||
if (user!=null)
|
||||
{
|
||||
renewSession(request,response);
|
||||
return new UserAuthentication(getAuthMethod(),user);
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +97,7 @@ public class BasicAuthenticator extends LoginAuthenticator
|
|||
}
|
||||
}
|
||||
|
||||
if (_deferred.isDeferred(response))
|
||||
if (DeferredAuthentication.isDeferred(response))
|
||||
return Authentication.UNAUTHENTICATED;
|
||||
|
||||
response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "basic realm=\"" + _loginService.getName() + '"');
|
||||
|
|
|
@ -81,6 +81,8 @@ public class ClientCertAuthenticator extends LoginAuthenticator
|
|||
return Constraint.__CERT_AUTH;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return Authentication for request
|
||||
* @throws ServerAuthException
|
||||
|
@ -88,8 +90,8 @@ public class ClientCertAuthenticator extends LoginAuthenticator
|
|||
public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
|
||||
{
|
||||
if (!mandatory)
|
||||
return _deferred;
|
||||
|
||||
return new DeferredAuthentication(this);
|
||||
|
||||
HttpServletRequest request = (HttpServletRequest)req;
|
||||
HttpServletResponse response = (HttpServletResponse)res;
|
||||
X509Certificate[] certs = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
|
||||
|
@ -121,16 +123,15 @@ public class ClientCertAuthenticator extends LoginAuthenticator
|
|||
|
||||
final char[] credential = B64Code.encode(cert.getSignature());
|
||||
|
||||
UserIdentity user = _loginService.login(username,credential);
|
||||
UserIdentity user = login(username, credential, req);
|
||||
if (user!=null)
|
||||
{
|
||||
renewSession(request,response);
|
||||
return new UserAuthentication(getAuthMethod(),user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!_deferred.isDeferred(response))
|
||||
|
||||
if (!DeferredAuthentication.isDeferred(response))
|
||||
{
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN);
|
||||
return Authentication.SEND_FAILURE;
|
||||
|
|
|
@ -29,6 +29,7 @@ import javax.servlet.ServletOutputStream;
|
|||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.security.Authenticator;
|
||||
|
@ -45,22 +46,9 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
public class DeferredAuthentication implements Authentication.Deferred
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(DeferredAuthentication.class);
|
||||
|
||||
protected final Authenticator _authenticator;
|
||||
|
||||
private LoginService _loginService;
|
||||
private IdentityService _identityService;
|
||||
protected final LoginAuthenticator _authenticator;
|
||||
private Object _previousAssociation;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public DeferredAuthentication(Authenticator authenticator)
|
||||
{
|
||||
if (authenticator == null)
|
||||
throw new NullPointerException("No Authenticator");
|
||||
this._authenticator = authenticator;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public DeferredAuthentication(LoginAuthenticator authenticator)
|
||||
{
|
||||
|
@ -68,36 +56,6 @@ public class DeferredAuthentication implements Authentication.Deferred
|
|||
throw new NullPointerException("No Authenticator");
|
||||
this._authenticator = authenticator;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the identityService.
|
||||
* @return the identityService
|
||||
*/
|
||||
public IdentityService getIdentityService()
|
||||
{
|
||||
return _identityService;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the identityService.
|
||||
* @param identityService the identityService to set
|
||||
*/
|
||||
public void setIdentityService(IdentityService identityService)
|
||||
{
|
||||
_identityService = identityService;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public LoginService getLoginService()
|
||||
{
|
||||
return _loginService;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setLoginService(LoginService loginService)
|
||||
{
|
||||
_loginService = loginService;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -111,8 +69,12 @@ public class DeferredAuthentication implements Authentication.Deferred
|
|||
|
||||
if (authentication!=null && (authentication instanceof Authentication.User) && !(authentication instanceof Authentication.ResponseSent))
|
||||
{
|
||||
if (_identityService!=null)
|
||||
_previousAssociation=_identityService.associate(((Authentication.User)authentication).getUserIdentity());
|
||||
LoginService login_service= _authenticator.getLoginService();
|
||||
IdentityService identity_service=login_service.getIdentityService();
|
||||
|
||||
if (identity_service!=null)
|
||||
_previousAssociation=identity_service.associate(((Authentication.User)authentication).getUserIdentity());
|
||||
|
||||
return authentication;
|
||||
}
|
||||
}
|
||||
|
@ -120,6 +82,7 @@ public class DeferredAuthentication implements Authentication.Deferred
|
|||
{
|
||||
LOG.debug(e);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -131,9 +94,12 @@ public class DeferredAuthentication implements Authentication.Deferred
|
|||
{
|
||||
try
|
||||
{
|
||||
LoginService login_service= _authenticator.getLoginService();
|
||||
IdentityService identity_service=login_service.getIdentityService();
|
||||
|
||||
Authentication authentication = _authenticator.validateRequest(request,response,true);
|
||||
if (authentication instanceof Authentication.User && _identityService!=null)
|
||||
_previousAssociation=_identityService.associate(((Authentication.User)authentication).getUserIdentity());
|
||||
if (authentication instanceof Authentication.User && identity_service!=null)
|
||||
_previousAssociation=identity_service.associate(((Authentication.User)authentication).getUserIdentity());
|
||||
return authentication;
|
||||
}
|
||||
catch (ServerAuthException e)
|
||||
|
@ -147,18 +113,16 @@ public class DeferredAuthentication implements Authentication.Deferred
|
|||
/**
|
||||
* @see org.eclipse.jetty.server.Authentication.Deferred#login(java.lang.String, java.lang.String)
|
||||
*/
|
||||
public Authentication login(String username, String password)
|
||||
public Authentication login(String username, Object password, ServletRequest request)
|
||||
{
|
||||
if (_loginService!=null)
|
||||
UserIdentity identity = _authenticator.login(username, password, request);
|
||||
if (identity != null)
|
||||
{
|
||||
UserIdentity user = _loginService.login(username,password);
|
||||
if (user!=null)
|
||||
{
|
||||
UserAuthentication authentication = new UserAuthentication("API",user);
|
||||
if (_identityService!=null)
|
||||
_previousAssociation=_identityService.associate(user);
|
||||
return authentication;
|
||||
}
|
||||
IdentityService identity_service = _authenticator.getLoginService().getIdentityService();
|
||||
UserAuthentication authentication = new UserAuthentication("API",identity);
|
||||
if (identity_service != null)
|
||||
_previousAssociation=identity_service.associate(identity);
|
||||
return authentication;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -116,13 +116,15 @@ public class DigestAuthenticator extends LoginAuthenticator
|
|||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
|
||||
{
|
||||
if (!mandatory)
|
||||
return _deferred;
|
||||
|
||||
return new DeferredAuthentication(this);
|
||||
|
||||
HttpServletRequest request = (HttpServletRequest)req;
|
||||
HttpServletResponse response = (HttpServletResponse)res;
|
||||
String credentials = request.getHeader(HttpHeaders.AUTHORIZATION);
|
||||
|
@ -185,10 +187,10 @@ public class DigestAuthenticator extends LoginAuthenticator
|
|||
|
||||
if (n > 0)
|
||||
{
|
||||
UserIdentity user = _loginService.login(digest.username,digest);
|
||||
//UserIdentity user = _loginService.login(digest.username,digest);
|
||||
UserIdentity user = login(digest.username, digest, req);
|
||||
if (user!=null)
|
||||
{
|
||||
renewSession(request,response);
|
||||
return new UserAuthentication(getAuthMethod(),user);
|
||||
}
|
||||
}
|
||||
|
@ -197,7 +199,7 @@ public class DigestAuthenticator extends LoginAuthenticator
|
|||
|
||||
}
|
||||
|
||||
if (!_deferred.isDeferred(response))
|
||||
if (!DeferredAuthentication.isDeferred(response))
|
||||
{
|
||||
String domain = request.getContextPath();
|
||||
if (domain == null)
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.security.authentication;
|
|||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletException;
|
||||
|
@ -179,6 +180,22 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
_formErrorPath = _formErrorPath.substring(0, _formErrorPath.indexOf('?'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public UserIdentity login(String username, Object password, ServletRequest request)
|
||||
{
|
||||
|
||||
UserIdentity user = super.login(username,password,request);
|
||||
if (user!=null)
|
||||
{
|
||||
HttpSession session = ((HttpServletRequest)request).getSession(true);
|
||||
Authentication cached=new SessionAuthentication(getAuthMethod(),user,password);
|
||||
session.setAttribute(SessionAuthentication.__J_AUTHENTICATED, cached);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Authentication validateRequest(ServletRequest req, ServletResponse res, boolean mandatory) throws ServerAuthException
|
||||
|
@ -191,11 +208,11 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
|
||||
mandatory|=isJSecurityCheck(uri);
|
||||
if (!mandatory)
|
||||
return _deferred;
|
||||
|
||||
return new DeferredAuthentication(this);
|
||||
|
||||
if (isLoginOrErrorPage(URIUtil.addPaths(request.getServletPath(),request.getPathInfo())) &&!DeferredAuthentication.isDeferred(response))
|
||||
return _deferred;
|
||||
|
||||
return new DeferredAuthentication(this);
|
||||
|
||||
HttpSession session = request.getSession(true);
|
||||
|
||||
try
|
||||
|
@ -206,11 +223,10 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
final String username = request.getParameter(__J_USERNAME);
|
||||
final String password = request.getParameter(__J_PASSWORD);
|
||||
|
||||
UserIdentity user = _loginService.login(username,password);
|
||||
UserIdentity user = login(username, password, request);
|
||||
session = request.getSession(true);
|
||||
if (user!=null)
|
||||
{
|
||||
session=renewSession(request,response);
|
||||
|
||||
{
|
||||
// Redirect to original request
|
||||
String nuri;
|
||||
synchronized(session)
|
||||
|
@ -223,9 +239,6 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
if (nuri.length() == 0)
|
||||
nuri = URIUtil.SLASH;
|
||||
}
|
||||
|
||||
Authentication cached=new SessionAuthentication(getAuthMethod(),user,password);
|
||||
session.setAttribute(SessionAuthentication.__J_AUTHENTICATED, cached);
|
||||
}
|
||||
response.setContentLength(0);
|
||||
response.sendRedirect(response.encodeRedirectURL(nuri));
|
||||
|
@ -300,9 +313,12 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
}
|
||||
|
||||
// if we can't send challenge
|
||||
if (_deferred.isDeferred(response))
|
||||
return Authentication.UNAUTHENTICATED;
|
||||
|
||||
if (DeferredAuthentication.isDeferred(response))
|
||||
{
|
||||
LOG.debug("auth deferred {}",session.getId());
|
||||
return Authentication.UNAUTHENTICATED;
|
||||
}
|
||||
|
||||
// remember the current URI
|
||||
synchronized (session)
|
||||
{
|
||||
|
@ -387,7 +403,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
@Override
|
||||
public long getDateHeader(String name)
|
||||
{
|
||||
if (name.toLowerCase().startsWith("if-"))
|
||||
if (name.toLowerCase(Locale.ENGLISH).startsWith("if-"))
|
||||
return -1;
|
||||
return super.getDateHeader(name);
|
||||
}
|
||||
|
@ -395,7 +411,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
@Override
|
||||
public String getHeader(String name)
|
||||
{
|
||||
if (name.toLowerCase().startsWith("if-"))
|
||||
if (name.toLowerCase(Locale.ENGLISH).startsWith("if-"))
|
||||
return null;
|
||||
return super.getHeader(name);
|
||||
}
|
||||
|
@ -409,7 +425,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
@Override
|
||||
public Enumeration getHeaders(String name)
|
||||
{
|
||||
if (name.toLowerCase().startsWith("if-"))
|
||||
if (name.toLowerCase(Locale.ENGLISH).startsWith("if-"))
|
||||
return Collections.enumeration(Collections.EMPTY_LIST);
|
||||
return super.getHeaders(name);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.eclipse.jetty.security.authentication;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
@ -25,11 +26,12 @@ import javax.servlet.http.HttpSession;
|
|||
import org.eclipse.jetty.security.Authenticator;
|
||||
import org.eclipse.jetty.security.IdentityService;
|
||||
import org.eclipse.jetty.security.LoginService;
|
||||
import org.eclipse.jetty.server.Authentication;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
import org.eclipse.jetty.server.session.AbstractSessionManager;
|
||||
|
||||
public abstract class LoginAuthenticator implements Authenticator
|
||||
{
|
||||
protected final DeferredAuthentication _deferred=new DeferredAuthentication(this);
|
||||
protected LoginService _loginService;
|
||||
protected IdentityService _identityService;
|
||||
private boolean _renewSession;
|
||||
|
@ -38,6 +40,20 @@ public abstract class LoginAuthenticator implements Authenticator
|
|||
{
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public UserIdentity login(String username, Object password, ServletRequest request)
|
||||
{
|
||||
UserIdentity user = _loginService.login(username,password);
|
||||
if (user!=null)
|
||||
{
|
||||
renewSession((HttpServletRequest)request, null);
|
||||
return user;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void setConfiguration(AuthConfiguration configuration)
|
||||
{
|
||||
_loginService=configuration.getLoginService();
|
||||
|
|
|
@ -98,8 +98,8 @@ public class SessionAuthentication implements Authentication.User, Serializable,
|
|||
{
|
||||
if (_session!=null && _session.getAttribute(__J_AUTHENTICATED)!=null)
|
||||
_session.removeAttribute(__J_AUTHENTICATED);
|
||||
else
|
||||
doLogout();
|
||||
|
||||
doLogout();
|
||||
}
|
||||
|
||||
private void doLogout()
|
||||
|
|
|
@ -60,6 +60,8 @@ public class SpnegoAuthenticator extends LoginAuthenticator
|
|||
return _authMethod;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Authentication validateRequest(ServletRequest request, ServletResponse response, boolean mandatory) throws ServerAuthException
|
||||
{
|
||||
HttpServletRequest req = (HttpServletRequest)request;
|
||||
|
@ -69,7 +71,7 @@ public class SpnegoAuthenticator extends LoginAuthenticator
|
|||
|
||||
if (!mandatory)
|
||||
{
|
||||
return _deferred;
|
||||
return new DeferredAuthentication(this);
|
||||
}
|
||||
|
||||
// check to see if we have authorization headers required to continue
|
||||
|
@ -77,7 +79,7 @@ public class SpnegoAuthenticator extends LoginAuthenticator
|
|||
{
|
||||
try
|
||||
{
|
||||
if (_deferred.isDeferred(res))
|
||||
if (DeferredAuthentication.isDeferred(res))
|
||||
{
|
||||
return Authentication.UNAUTHENTICATED;
|
||||
}
|
||||
|
@ -96,7 +98,7 @@ public class SpnegoAuthenticator extends LoginAuthenticator
|
|||
{
|
||||
String spnegoToken = header.substring(10);
|
||||
|
||||
UserIdentity user = _loginService.login(null,spnegoToken);
|
||||
UserIdentity user = login(null,spnegoToken, request);
|
||||
|
||||
if ( user != null )
|
||||
{
|
||||
|
|
|
@ -22,9 +22,11 @@ import static org.junit.Assert.assertFalse;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -76,6 +78,8 @@ public class ConstraintTest
|
|||
_loginService.putUser("user",new Password("password"));
|
||||
_loginService.putUser("user2",new Password("password"), new String[] {"user"});
|
||||
_loginService.putUser("admin",new Password("password"), new String[] {"user","administrator"});
|
||||
_loginService.putUser("user3", new Password("password"), new String[] {"foo"});
|
||||
|
||||
|
||||
_context.setContextPath("/ctx");
|
||||
_server.setHandler(_context);
|
||||
|
@ -189,17 +193,59 @@ public class ConstraintTest
|
|||
@Test
|
||||
public void testBasic() throws Exception
|
||||
{
|
||||
|
||||
List<ConstraintMapping> list = new ArrayList<ConstraintMapping>(_security.getConstraintMappings());
|
||||
|
||||
Constraint constraint6 = new Constraint();
|
||||
constraint6.setAuthenticate(true);
|
||||
constraint6.setName("omit POST and GET");
|
||||
constraint6.setRoles(new String[]{"user"});
|
||||
ConstraintMapping mapping6 = new ConstraintMapping();
|
||||
mapping6.setPathSpec("/omit/*");
|
||||
mapping6.setConstraint(constraint6);
|
||||
mapping6.setMethodOmissions(new String[]{"GET", "HEAD"}); //requests for every method except GET and HEAD must be in role "user"
|
||||
list.add(mapping6);
|
||||
|
||||
Constraint constraint7 = new Constraint();
|
||||
constraint7.setAuthenticate(true);
|
||||
constraint7.setName("non-omitted GET");
|
||||
constraint7.setRoles(new String[]{"administrator"});
|
||||
ConstraintMapping mapping7 = new ConstraintMapping();
|
||||
mapping7.setPathSpec("/omit/*");
|
||||
mapping7.setConstraint(constraint7);
|
||||
mapping7.setMethod("GET"); //requests for GET must be in role "admin"
|
||||
list.add(mapping7);
|
||||
|
||||
Constraint constraint8 = new Constraint();
|
||||
constraint8.setAuthenticate(true);
|
||||
constraint8.setName("non specific");
|
||||
constraint8.setRoles(new String[]{"foo"});
|
||||
ConstraintMapping mapping8 = new ConstraintMapping();
|
||||
mapping8.setPathSpec("/omit/*");
|
||||
mapping8.setConstraint(constraint8);//requests for all methods must be in role "foo"
|
||||
list.add(mapping8);
|
||||
|
||||
Set<String> knownRoles=new HashSet<String>();
|
||||
knownRoles.add("user");
|
||||
knownRoles.add("administrator");
|
||||
knownRoles.add("foo");
|
||||
|
||||
_security.setConstraintMappings(list, knownRoles);
|
||||
|
||||
|
||||
_security.setAuthenticator(new BasicAuthenticator());
|
||||
_security.setStrict(false);
|
||||
_server.start();
|
||||
|
||||
String response;
|
||||
/*
|
||||
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
*/
|
||||
|
||||
response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
/*
|
||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
assertTrue(response.indexOf("WWW-Authenticate: basic realm=\"TestRealm\"") > 0);
|
||||
|
@ -214,8 +260,8 @@ public class ConstraintTest
|
|||
"Authorization: Basic " + B64Code.encode("user:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
|
||||
*/
|
||||
/*
|
||||
// test admin
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
|
@ -241,7 +287,33 @@ public class ConstraintTest
|
|||
|
||||
response = _connector.getResponses("GET /ctx/admin/relax/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
//check GET is in role administrator
|
||||
response = _connector.getResponses("GET /ctx/omit/x HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("admin:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
//check POST is in role user
|
||||
response = _connector.getResponses("POST /ctx/omit/x HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user2:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
//check POST can be in role foo too
|
||||
response = _connector.getResponses("POST /ctx/omit/x HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user3:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
//check HEAD cannot be in role user
|
||||
response = _connector.getResponses("HEAD /ctx/omit/x HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("user2:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testFormDispatch() throws Exception
|
||||
|
@ -847,7 +919,7 @@ public class ConstraintTest
|
|||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
if (request.getAuthType()==null || "user".equals(request.getRemoteUser()) || request.isUserInRole("user"))
|
||||
if (request.getAuthType()==null || "user".equals(request.getRemoteUser()) || request.isUserInRole("user") || request.isUserInRole("foo"))
|
||||
{
|
||||
response.setStatus(200);
|
||||
response.setContentType("text/plain; charset=UTF-8");
|
||||
|
|
|
@ -0,0 +1,311 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.security;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.session.SessionHandler;
|
||||
import org.eclipse.jetty.util.B64Code;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
import org.eclipse.jetty.util.security.Password;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version $Revision: 1441 $ $Date: 2010-04-02 12:28:17 +0200 (Fri, 02 Apr 2010) $
|
||||
*/
|
||||
public class SpecExampleConstraintTest
|
||||
{
|
||||
private static final String TEST_REALM = "TestRealm";
|
||||
private static Server _server;
|
||||
private static LocalConnector _connector;
|
||||
private static SessionHandler _session;
|
||||
private ConstraintSecurityHandler _security;
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer()
|
||||
{
|
||||
_server = new Server();
|
||||
_connector = new LocalConnector();
|
||||
_server.setConnectors(new Connector[]{_connector});
|
||||
|
||||
ContextHandler _context = new ContextHandler();
|
||||
_session = new SessionHandler();
|
||||
|
||||
HashLoginService _loginService = new HashLoginService(TEST_REALM);
|
||||
_loginService.putUser("fred",new Password("password"));
|
||||
_loginService.putUser("harry",new Password("password"), new String[] {"HOMEOWNER"});
|
||||
_loginService.putUser("chris",new Password("password"), new String[] {"CONTRACTOR"});
|
||||
_loginService.putUser("steven", new Password("password"), new String[] {"SALESCLERK"});
|
||||
|
||||
|
||||
_context.setContextPath("/ctx");
|
||||
_server.setHandler(_context);
|
||||
_context.setHandler(_session);
|
||||
|
||||
_server.addBean(_loginService);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setupSecurity()
|
||||
{
|
||||
_security = new ConstraintSecurityHandler();
|
||||
_session.setHandler(_security);
|
||||
RequestHandler _handler = new RequestHandler();
|
||||
_security.setHandler(_handler);
|
||||
|
||||
|
||||
/*
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>precluded methods</web-resource-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
<url-pattern>/acme/wholesale/*</url-pattern>
|
||||
<url-pattern>/acme/retail/*</url-pattern>
|
||||
<http-method-exception>GET</http-method-exception>
|
||||
<http-method-exception>POST</http-method-exception>
|
||||
</web-resource-collection>
|
||||
<auth-constraint/>
|
||||
</security-constraint>
|
||||
*/
|
||||
|
||||
Constraint constraint0 = new Constraint();
|
||||
constraint0.setAuthenticate(true);
|
||||
constraint0.setName("precluded methods");
|
||||
ConstraintMapping mapping0 = new ConstraintMapping();
|
||||
mapping0.setPathSpec("/*");
|
||||
mapping0.setConstraint(constraint0);
|
||||
mapping0.setMethodOmissions(new String[]{"GET", "POST"});
|
||||
|
||||
ConstraintMapping mapping1 = new ConstraintMapping();
|
||||
mapping1.setPathSpec("/acme/wholesale/*");
|
||||
mapping1.setConstraint(constraint0);
|
||||
mapping1.setMethodOmissions(new String[]{"GET", "POST"});
|
||||
|
||||
ConstraintMapping mapping2 = new ConstraintMapping();
|
||||
mapping2.setPathSpec("/acme/retail/*");
|
||||
mapping2.setConstraint(constraint0);
|
||||
mapping2.setMethodOmissions(new String[]{"GET", "POST"});
|
||||
|
||||
/*
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>wholesale</web-resource-name>
|
||||
<url-pattern>/acme/wholesale/*</url-pattern>
|
||||
<http-method>GET</http-method>
|
||||
<http-method>PUT</http-method>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>SALESCLERK</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
*/
|
||||
Constraint constraint1 = new Constraint();
|
||||
constraint1.setAuthenticate(true);
|
||||
constraint1.setName("wholesale");
|
||||
constraint1.setRoles(new String[]{"SALESCLERK"});
|
||||
ConstraintMapping mapping3 = new ConstraintMapping();
|
||||
mapping3.setPathSpec("/acme/wholesale/*");
|
||||
mapping3.setConstraint(constraint1);
|
||||
mapping3.setMethod("GET");
|
||||
ConstraintMapping mapping4 = new ConstraintMapping();
|
||||
mapping4.setPathSpec("/acme/wholesale/*");
|
||||
mapping4.setConstraint(constraint1);
|
||||
mapping4.setMethod("PUT");
|
||||
|
||||
/*
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>wholesale 2</web-resource-name>
|
||||
<url-pattern>/acme/wholesale/*</url-pattern>
|
||||
<http-method>GET</http-method>
|
||||
<http-method>POST</http-method>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>CONTRACTOR</role-name>
|
||||
</auth-constraint>
|
||||
<user-data-constraint>
|
||||
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
|
||||
</user-data-constraint>
|
||||
</security-constraint>
|
||||
*/
|
||||
Constraint constraint2 = new Constraint();
|
||||
constraint2.setAuthenticate(true);
|
||||
constraint2.setName("wholesale 2");
|
||||
constraint2.setRoles(new String[]{"CONTRACTOR"});
|
||||
constraint2.setDataConstraint(Constraint.DC_CONFIDENTIAL);
|
||||
ConstraintMapping mapping5 = new ConstraintMapping();
|
||||
mapping5.setPathSpec("/acme/wholesale/*");
|
||||
mapping5.setMethod("GET");
|
||||
mapping5.setConstraint(constraint2);
|
||||
ConstraintMapping mapping6 = new ConstraintMapping();
|
||||
mapping6.setPathSpec("/acme/wholesale/*");
|
||||
mapping6.setMethod("POST");
|
||||
mapping6.setConstraint(constraint2);
|
||||
|
||||
/*
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>retail</web-resource-name>
|
||||
<url-pattern>/acme/retail/*</url-pattern>
|
||||
<http-method>GET</http-method>
|
||||
<http-method>POST</http-method>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>CONTRACTOR</role-name>
|
||||
<role-name>HOMEOWNER</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
*/
|
||||
Constraint constraint4 = new Constraint();
|
||||
constraint4.setName("retail");
|
||||
constraint4.setAuthenticate(true);
|
||||
constraint4.setRoles(new String[]{"CONTRACTOR", "HOMEOWNER"});
|
||||
ConstraintMapping mapping7 = new ConstraintMapping();
|
||||
mapping7.setPathSpec("/acme/retail/*");
|
||||
mapping7.setMethod("GET");
|
||||
mapping7.setConstraint(constraint4);
|
||||
ConstraintMapping mapping8 = new ConstraintMapping();
|
||||
mapping8.setPathSpec("/acme/retail/*");
|
||||
mapping8.setMethod("POST");
|
||||
mapping8.setConstraint(constraint4);
|
||||
|
||||
|
||||
|
||||
|
||||
Set<String> knownRoles=new HashSet<String>();
|
||||
knownRoles.add("CONTRACTOR");
|
||||
knownRoles.add("HOMEOWNER");
|
||||
knownRoles.add("SALESCLERK");
|
||||
|
||||
_security.setConstraintMappings(Arrays.asList(new ConstraintMapping[]
|
||||
{
|
||||
mapping0, mapping1, mapping2, mapping3, mapping4, mapping5, mapping6, mapping7, mapping8
|
||||
}), knownRoles);
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopServer() throws Exception
|
||||
{
|
||||
if (_server.isRunning())
|
||||
{
|
||||
_server.stop();
|
||||
_server.join();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testBasic() throws Exception
|
||||
{
|
||||
|
||||
_security.setAuthenticator(new BasicAuthenticator());
|
||||
_security.setStrict(false);
|
||||
_server.start();
|
||||
|
||||
String response;
|
||||
/*
|
||||
/star all methods except GET/POST forbidden
|
||||
/acme/wholesale/star all methods except GET/POST forbidden
|
||||
/acme/retail/star all methods except GET/POST forbidden
|
||||
/acme/wholesale/star GET must be in role CONTRACTOR or SALESCLERK
|
||||
/acme/wholesale/star POST must be in role CONTRACTOR and confidential transport
|
||||
/acme/retail/star GET must be in role CONTRACTOR or HOMEOWNER
|
||||
/acme/retail/star POST must be in role CONTRACTOR or HOMEOWNER
|
||||
*/
|
||||
|
||||
//a user in role HOMEOWNER is forbidden HEAD request
|
||||
response = _connector.getResponses("HEAD /ctx/index.html HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
response = _connector.getResponses("HEAD /ctx/index.html HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("harry:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
response = _connector.getResponses("HEAD /ctx/acme/wholesale/index.html HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("harry:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
response = _connector.getResponses("HEAD /ctx/acme/retail/index.html HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("harry:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||
|
||||
//a user in role CONTRACTOR can do a GET
|
||||
response = _connector.getResponses("GET /ctx/acme/wholesale/index.html HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("chris:password") + "\r\n" +
|
||||
"\r\n");
|
||||
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
//a user in role CONTRACTOR can only do a post if confidential
|
||||
response = _connector.getResponses("POST /ctx/acme/wholesale/index.html HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("chris:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 403 !Confidential"));
|
||||
|
||||
|
||||
//a user in role HOMEOWNER can do a GET
|
||||
response = _connector.getResponses("GET /ctx/acme/retail/index.html HTTP/1.0\r\n" +
|
||||
"Authorization: Basic " + B64Code.encode("harry:password") + "\r\n" +
|
||||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
}
|
||||
|
||||
|
||||
private class RequestHandler extends AbstractHandler
|
||||
{
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response ) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
|
||||
response.setStatus(200);
|
||||
response.setContentType("text/plain; charset=UTF-8");
|
||||
response.getWriter().println("URI="+request.getRequestURI());
|
||||
String user = request.getRemoteUser();
|
||||
response.getWriter().println("user="+user);
|
||||
if (request.getParameter("test_parameter")!=null)
|
||||
response.getWriter().println(request.getParameter("test_parameter"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -85,7 +85,7 @@ public interface Authentication
|
|||
* @param password
|
||||
* @return The new Authentication state
|
||||
*/
|
||||
Authentication login(String username,String password);
|
||||
Authentication login(String username,Object password,ServletRequest request);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
//
|
||||
|
||||
package org.eclipse.jetty.server;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
import org.eclipse.jetty.util.LazyList;
|
||||
|
@ -286,7 +288,7 @@ public class CookieCutter
|
|||
{
|
||||
if (name.startsWith("$"))
|
||||
{
|
||||
String lowercaseName = name.toLowerCase();
|
||||
String lowercaseName = name.toLowerCase(Locale.ENGLISH);
|
||||
if ("$path".equals(lowercaseName))
|
||||
{
|
||||
if (cookie!=null)
|
||||
|
|
|
@ -50,6 +50,8 @@ import javax.servlet.ServletInputStream;
|
|||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletRequestAttributeEvent;
|
||||
import javax.servlet.ServletRequestAttributeListener;
|
||||
import javax.servlet.ServletRequestEvent;
|
||||
import javax.servlet.ServletRequestListener;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -80,6 +82,7 @@ import org.eclipse.jetty.server.handler.ContextHandler.Context;
|
|||
import org.eclipse.jetty.util.Attributes;
|
||||
import org.eclipse.jetty.util.AttributesMap;
|
||||
import org.eclipse.jetty.util.LazyList;
|
||||
import org.eclipse.jetty.util.MultiException;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.eclipse.jetty.util.MultiPartInputStream;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
@ -123,12 +126,50 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
public class Request implements HttpServletRequest
|
||||
{
|
||||
public static final String __MULTIPART_CONFIG_ELEMENT = "org.eclipse.multipartConfig";
|
||||
public static final String __MULTIPART_INPUT_STREAM = "org.eclipse.multiPartInputStream";
|
||||
public static final String __MULTIPART_CONTEXT = "org.eclipse.multiPartContext";
|
||||
private static final Logger LOG = Log.getLogger(Request.class);
|
||||
|
||||
private static final String __ASYNC_FWD = "org.eclipse.asyncfwd";
|
||||
private static final Collection __defaultLocale = Collections.singleton(Locale.getDefault());
|
||||
private static final int __NONE = 0, _STREAM = 1, __READER = 2;
|
||||
|
||||
public static class MultiPartCleanerListener implements ServletRequestListener
|
||||
{
|
||||
|
||||
@Override
|
||||
public void requestDestroyed(ServletRequestEvent sre)
|
||||
{
|
||||
//Clean up any tmp files created by MultiPartInputStream
|
||||
MultiPartInputStream mpis = (MultiPartInputStream)sre.getServletRequest().getAttribute(__MULTIPART_INPUT_STREAM);
|
||||
if (mpis != null)
|
||||
{
|
||||
ContextHandler.Context context = (ContextHandler.Context)sre.getServletRequest().getAttribute(__MULTIPART_CONTEXT);
|
||||
|
||||
//Only do the cleanup if we are exiting from the context in which a servlet parsed the multipart files
|
||||
if (context == sre.getServletContext())
|
||||
{
|
||||
try
|
||||
{
|
||||
mpis.deleteParts();
|
||||
}
|
||||
catch (MultiException e)
|
||||
{
|
||||
sre.getServletContext().log("Errors deleting multipart tmp files", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestInitialized(ServletRequestEvent sre)
|
||||
{
|
||||
//nothing to do, multipart config set up by ServletHolder.handle()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static Request getRequest(HttpServletRequest request)
|
||||
{
|
||||
|
@ -1271,6 +1312,7 @@ public class Request implements HttpServletRequest
|
|||
UserIdentity user = ((Authentication.User)_authentication).getUserIdentity();
|
||||
return user.getUserPrincipal();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1762,6 +1804,7 @@ public class Request implements HttpServletRequest
|
|||
public void setQueryString(String queryString)
|
||||
{
|
||||
_queryString = queryString;
|
||||
_queryEncoding = null; //assume utf-8
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -1938,7 +1981,7 @@ public class Request implements HttpServletRequest
|
|||
{
|
||||
if (_authentication instanceof Authentication.Deferred)
|
||||
{
|
||||
setAuthentication(((Authentication.Deferred)_authentication).authenticate(this,response));
|
||||
setAuthentication(((Authentication.Deferred)_authentication).authenticate(this,response));
|
||||
return !(_authentication instanceof Authentication.ResponseSent);
|
||||
}
|
||||
response.sendError(HttpStatus.UNAUTHORIZED_401);
|
||||
|
@ -1953,9 +1996,16 @@ public class Request implements HttpServletRequest
|
|||
|
||||
if (_multiPartInputStream == null)
|
||||
{
|
||||
MultipartConfigElement config = (MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT);
|
||||
|
||||
if (config == null)
|
||||
throw new IllegalStateException("No multipart config for servlet");
|
||||
|
||||
_multiPartInputStream = new MultiPartInputStream(getInputStream(),
|
||||
getContentType(),(MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT),
|
||||
getContentType(),config,
|
||||
(_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null));
|
||||
setAttribute(__MULTIPART_INPUT_STREAM, _multiPartInputStream);
|
||||
setAttribute(__MULTIPART_CONTEXT, _context);
|
||||
Collection<Part> parts = _multiPartInputStream.getParts(); //causes parsing
|
||||
for (Part p:parts)
|
||||
{
|
||||
|
@ -1984,9 +2034,17 @@ public class Request implements HttpServletRequest
|
|||
|
||||
if (_multiPartInputStream == null)
|
||||
{
|
||||
MultipartConfigElement config = (MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT);
|
||||
|
||||
if (config == null)
|
||||
throw new IllegalStateException("No multipart config for servlet");
|
||||
|
||||
_multiPartInputStream = new MultiPartInputStream(getInputStream(),
|
||||
getContentType(),(MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT),
|
||||
getContentType(), config,
|
||||
(_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null));
|
||||
|
||||
setAttribute(__MULTIPART_INPUT_STREAM, _multiPartInputStream);
|
||||
setAttribute(__MULTIPART_CONTEXT, _context);
|
||||
Collection<Part> parts = _multiPartInputStream.getParts(); //causes parsing
|
||||
for (Part p:parts)
|
||||
{
|
||||
|
@ -2012,7 +2070,7 @@ public class Request implements HttpServletRequest
|
|||
{
|
||||
if (_authentication instanceof Authentication.Deferred)
|
||||
{
|
||||
_authentication=((Authentication.Deferred)_authentication).login(username,password);
|
||||
_authentication=((Authentication.Deferred)_authentication).login(username,password,this);
|
||||
if (_authentication == null)
|
||||
throw new ServletException();
|
||||
}
|
||||
|
@ -2042,7 +2100,7 @@ public class Request implements HttpServletRequest
|
|||
{
|
||||
// extract parameters from dispatch query
|
||||
MultiMap<String> parameters = new MultiMap<String>();
|
||||
UrlEncoded.decodeTo(query,parameters,getCharacterEncoding());
|
||||
UrlEncoded.decodeTo(query,parameters, StringUtil.__UTF8); //have to assume UTF-8 because we can't know otherwise
|
||||
|
||||
boolean merge_old_query = false;
|
||||
|
||||
|
@ -2077,10 +2135,11 @@ public class Request implements HttpServletRequest
|
|||
{
|
||||
StringBuilder overridden_query_string = new StringBuilder();
|
||||
MultiMap<String> overridden_old_query = new MultiMap<String>();
|
||||
UrlEncoded.decodeTo(_queryString,overridden_old_query,getCharacterEncoding());
|
||||
|
||||
UrlEncoded.decodeTo(_queryString,overridden_old_query,getQueryEncoding());//decode using any queryencoding set for the request
|
||||
|
||||
|
||||
MultiMap<String> overridden_new_query = new MultiMap<String>();
|
||||
UrlEncoded.decodeTo(query,overridden_new_query,getCharacterEncoding());
|
||||
UrlEncoded.decodeTo(query,overridden_new_query,StringUtil.__UTF8); //have to assume utf8 as we cannot know otherwise
|
||||
|
||||
Iterator<Entry<String, Object>> iter = overridden_old_query.entrySet().iterator();
|
||||
while (iter.hasNext())
|
||||
|
|
|
@ -388,7 +388,7 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
baseRequest.setRequestURI(null);
|
||||
baseRequest.setPathInfo(baseRequest.getRequestURI());
|
||||
if (uri.getQuery()!=null)
|
||||
baseRequest.mergeQueryString(uri.getQuery());
|
||||
baseRequest.mergeQueryString(uri.getQuery()); //we have to assume dispatch path and query are UTF8
|
||||
}
|
||||
|
||||
final String target=baseRequest.getPathInfo();
|
||||
|
|
|
@ -50,7 +50,7 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
<pre>
|
||||
public static void attemptShutdown(int port, String shutdownCookie) {
|
||||
try {
|
||||
URL url = new URL("http://localhost:" + port + "/shutdown?cookie=" + shutdownCookie);
|
||||
URL url = new URL("http://localhost:" + port + "/shutdown?token=" + shutdownCookie);
|
||||
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
|
||||
connection.setRequestMethod("POST");
|
||||
connection.getResponseCode();
|
||||
|
|
|
@ -65,8 +65,7 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
private boolean _newSession;
|
||||
private int _requests;
|
||||
|
||||
// TODO remove this.
|
||||
protected final Map<String,Object> _jdbcAttributes=_attributes;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
protected AbstractSession(AbstractSessionManager abstractSessionManager, HttpServletRequest request)
|
||||
|
@ -255,6 +254,18 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
|
|||
return (String[])_attributes.keySet().toArray(a);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected Map<String,Object> getAttributeMap ()
|
||||
{
|
||||
return _attributes;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void addAttributes(Map<String,Object> map)
|
||||
{
|
||||
_attributes.putAll(map);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected boolean access(long time)
|
||||
|
|
|
@ -483,32 +483,40 @@ public class HashSessionManager extends AbstractSessionManager
|
|||
protected synchronized HashedSession restoreSession(String idInCuster)
|
||||
{
|
||||
File file = new File(_storeDir,idInCuster);
|
||||
FileInputStream in = null;
|
||||
Exception error = null;
|
||||
try
|
||||
{
|
||||
if (file.exists())
|
||||
{
|
||||
FileInputStream in = new FileInputStream(file);
|
||||
in = new FileInputStream(file);
|
||||
HashedSession session = restoreSession(in, null);
|
||||
in.close();
|
||||
addSession(session, false);
|
||||
session.didActivate();
|
||||
file.delete();
|
||||
return session;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
if (isDeleteUnrestorableSessions())
|
||||
error = e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (in != null)
|
||||
try {in.close();} catch (Exception x) {__log.ignore(x);}
|
||||
|
||||
if (error != null)
|
||||
{
|
||||
if (file.exists())
|
||||
if (isDeleteUnrestorableSessions() && file.exists())
|
||||
{
|
||||
file.delete();
|
||||
__log.warn("Deleting file for unrestorable session "+idInCuster, e);
|
||||
__log.warn("Deleting file for unrestorable session "+idInCuster, error);
|
||||
}
|
||||
else
|
||||
__log.warn("Problem restoring session "+idInCuster, error);
|
||||
}
|
||||
else
|
||||
__log.warn("Problem restoring session "+idInCuster, e);
|
||||
file.delete(); //delete successfully restored file
|
||||
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -30,8 +30,11 @@ import java.sql.ResultSet;
|
|||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Random;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
@ -81,7 +84,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
protected String _createSessionIdTable;
|
||||
protected String _createSessionTable;
|
||||
|
||||
protected String _selectExpiredSessions;
|
||||
protected String _selectBoundedExpiredSessions;
|
||||
protected String _deleteOldExpiredSessions;
|
||||
|
||||
protected String _insertId;
|
||||
|
@ -96,6 +99,8 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
|
||||
protected DatabaseAdaptor _dbAdaptor;
|
||||
|
||||
private String _selectExpiredSessions;
|
||||
|
||||
|
||||
/**
|
||||
* DatabaseAdaptor
|
||||
|
@ -114,16 +119,16 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
String _dbName;
|
||||
boolean _isLower;
|
||||
boolean _isUpper;
|
||||
|
||||
|
||||
|
||||
|
||||
public DatabaseAdaptor (DatabaseMetaData dbMeta)
|
||||
throws SQLException
|
||||
{
|
||||
_dbName = dbMeta.getDatabaseProductName().toLowerCase();
|
||||
_dbName = dbMeta.getDatabaseProductName().toLowerCase(Locale.ENGLISH);
|
||||
LOG.debug ("Using database {}",_dbName);
|
||||
_isLower = dbMeta.storesLowerCaseIdentifiers();
|
||||
_isUpper = dbMeta.storesUpperCaseIdentifiers();
|
||||
_isUpper = dbMeta.storesUpperCaseIdentifiers();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -136,9 +141,9 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
public String convertIdentifier (String identifier)
|
||||
{
|
||||
if (_isLower)
|
||||
return identifier.toLowerCase();
|
||||
return identifier.toLowerCase(Locale.ENGLISH);
|
||||
if (_isUpper)
|
||||
return identifier.toUpperCase();
|
||||
return identifier.toUpperCase(Locale.ENGLISH);
|
||||
|
||||
return identifier;
|
||||
}
|
||||
|
@ -455,6 +460,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
inUse = _sessionIds.contains(clusterId);
|
||||
}
|
||||
|
||||
|
||||
if (inUse)
|
||||
return true; //optimisation - if this session is one we've been managing, we can check locally
|
||||
|
||||
|
@ -514,7 +520,8 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
try
|
||||
{
|
||||
initializeDatabase();
|
||||
prepareTables();
|
||||
prepareTables();
|
||||
cleanExpiredSessions();
|
||||
super.doStart();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Scavenging interval = "+getScavengeInterval()+" sec");
|
||||
|
@ -542,6 +549,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
_timer.cancel();
|
||||
_timer=null;
|
||||
}
|
||||
_sessionIds.clear();
|
||||
super.doStop();
|
||||
}
|
||||
|
||||
|
@ -559,31 +567,9 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
else
|
||||
return DriverManager.getConnection(_connectionUrl);
|
||||
}
|
||||
|
||||
|
||||
private void initializeDatabase ()
|
||||
throws Exception
|
||||
{
|
||||
if (_datasource != null)
|
||||
return; //already set up
|
||||
|
||||
if (_jndiName!=null)
|
||||
{
|
||||
InitialContext ic = new InitialContext();
|
||||
_datasource = (DataSource)ic.lookup(_jndiName);
|
||||
}
|
||||
else if ( _driver != null && _connectionUrl != null )
|
||||
{
|
||||
DriverManager.registerDriver(_driver);
|
||||
}
|
||||
else if (_driverClassName != null && _connectionUrl != null)
|
||||
{
|
||||
Class.forName(_driverClassName);
|
||||
}
|
||||
else
|
||||
throw new IllegalStateException("No database configured for sessions");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
@ -594,7 +580,8 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
throws SQLException
|
||||
{
|
||||
_createSessionIdTable = "create table "+_sessionIdTable+" (id varchar(120), primary key(id))";
|
||||
_selectExpiredSessions = "select * from "+_sessionTable+" where expiryTime >= ? and expiryTime <= ?";
|
||||
_selectBoundedExpiredSessions = "select * from "+_sessionTable+" where expiryTime >= ? and expiryTime <= ?";
|
||||
_selectExpiredSessions = "select * from "+_sessionTable+" where expiryTime >0 and expiryTime <= ?";
|
||||
_deleteOldExpiredSessions = "delete from "+_sessionTable+" where expiryTime >0 and expiryTime <= ?";
|
||||
|
||||
_insertId = "insert into "+_sessionIdTable+" (id) values (?)";
|
||||
|
@ -794,7 +781,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
connection = getConnection();
|
||||
connection.setAutoCommit(true);
|
||||
//"select sessionId from JettySessions where expiryTime > (lastScavengeTime - scanInterval) and expiryTime < lastScavengeTime";
|
||||
PreparedStatement statement = connection.prepareStatement(_selectExpiredSessions);
|
||||
PreparedStatement statement = connection.prepareStatement(_selectBoundedExpiredSessions);
|
||||
long lowerBound = (_lastScavengeTime - _scavengeIntervalMs);
|
||||
long upperBound = _lastScavengeTime;
|
||||
if (LOG.isDebugEnabled())
|
||||
|
@ -833,7 +820,8 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
if (LOG.isDebugEnabled()) LOG.debug("Deleting old expired sessions expired before "+upperBound);
|
||||
statement = connection.prepareStatement(_deleteOldExpiredSessions);
|
||||
statement.setLong(1, upperBound);
|
||||
statement.executeUpdate();
|
||||
int rows = statement.executeUpdate();
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Deleted "+rows+" rows");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -861,4 +849,121 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rid of sessions and sessionids from sessions that have already expired
|
||||
* @throws Exception
|
||||
*/
|
||||
private void cleanExpiredSessions ()
|
||||
throws Exception
|
||||
{
|
||||
Connection connection = null;
|
||||
List<String> expiredSessionIds = new ArrayList<String>();
|
||||
try
|
||||
{
|
||||
connection = getConnection();
|
||||
connection.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
|
||||
connection.setAutoCommit(false);
|
||||
|
||||
PreparedStatement statement = connection.prepareStatement(_selectExpiredSessions);
|
||||
long now = System.currentTimeMillis();
|
||||
if (LOG.isDebugEnabled()) LOG.debug ("Searching for sessions expired before {}", now);
|
||||
|
||||
statement.setLong(1, now);
|
||||
ResultSet result = statement.executeQuery();
|
||||
while (result.next())
|
||||
{
|
||||
String sessionId = result.getString("sessionId");
|
||||
expiredSessionIds.add(sessionId);
|
||||
if (LOG.isDebugEnabled()) LOG.debug ("Found expired sessionId={}", sessionId);
|
||||
}
|
||||
|
||||
Statement sessionsTableStatement = null;
|
||||
Statement sessionIdsTableStatement = null;
|
||||
|
||||
if (!expiredSessionIds.isEmpty())
|
||||
{
|
||||
sessionsTableStatement = connection.createStatement();
|
||||
sessionsTableStatement.executeUpdate(createCleanExpiredSessionsSql("delete from "+_sessionTable+" where sessionId in ", expiredSessionIds));
|
||||
sessionIdsTableStatement = connection.createStatement();
|
||||
sessionIdsTableStatement.executeUpdate(createCleanExpiredSessionsSql("delete from "+_sessionIdTable+" where id in ", expiredSessionIds));
|
||||
}
|
||||
connection.commit();
|
||||
|
||||
synchronized (_sessionIds)
|
||||
{
|
||||
_sessionIds.removeAll(expiredSessionIds); //in case they were in our local cache of session ids
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (connection != null)
|
||||
connection.rollback();
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if (connection != null)
|
||||
connection.close();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sql
|
||||
* @param connection
|
||||
* @param expiredSessionIds
|
||||
* @throws Exception
|
||||
*/
|
||||
private String createCleanExpiredSessionsSql (String sql,Collection<String> expiredSessionIds)
|
||||
throws Exception
|
||||
{
|
||||
StringBuffer buff = new StringBuffer();
|
||||
buff.append(sql);
|
||||
buff.append("(");
|
||||
Iterator<String> itor = expiredSessionIds.iterator();
|
||||
while (itor.hasNext())
|
||||
{
|
||||
buff.append("'"+(itor.next())+"'");
|
||||
if (itor.hasNext())
|
||||
buff.append(",");
|
||||
}
|
||||
buff.append(")");
|
||||
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Cleaning expired sessions with: {}", buff);
|
||||
return buff.toString();
|
||||
}
|
||||
|
||||
private void initializeDatabase ()
|
||||
throws Exception
|
||||
{
|
||||
if (_datasource != null)
|
||||
return; //already set up
|
||||
|
||||
if (_jndiName!=null)
|
||||
{
|
||||
InitialContext ic = new InitialContext();
|
||||
_datasource = (DataSource)ic.lookup(_jndiName);
|
||||
}
|
||||
else if ( _driver != null && _connectionUrl != null )
|
||||
{
|
||||
DriverManager.registerDriver(_driver);
|
||||
}
|
||||
else if (_driverClassName != null && _connectionUrl != null)
|
||||
{
|
||||
Class.forName(_driverClassName);
|
||||
}
|
||||
else
|
||||
throw new IllegalStateException("No database configured for sessions");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -267,7 +267,8 @@ public class JDBCSessionManager extends AbstractSessionManager
|
|||
private static final long serialVersionUID = 5208464051134226143L;
|
||||
private final SessionData _data;
|
||||
private boolean _dirty=false;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Session from a request.
|
||||
*
|
||||
|
@ -276,7 +277,7 @@ public class JDBCSessionManager extends AbstractSessionManager
|
|||
protected Session (HttpServletRequest request)
|
||||
{
|
||||
super(JDBCSessionManager.this,request);
|
||||
_data = new SessionData(getClusterId(),_jdbcAttributes);
|
||||
_data = new SessionData(getClusterId(),getAttributeMap());
|
||||
if (_dftMaxIdleSecs>0)
|
||||
_data.setMaxIdleMs(_dftMaxIdleSecs*1000L);
|
||||
_data.setCanonicalContext(canonicalize(_context.getContextPath()));
|
||||
|
@ -286,18 +287,18 @@ public class JDBCSessionManager extends AbstractSessionManager
|
|||
}
|
||||
|
||||
/**
|
||||
* Session restored in database.
|
||||
* @param data
|
||||
*/
|
||||
protected Session (long accessed, SessionData data)
|
||||
{
|
||||
super(JDBCSessionManager.this,data.getCreated(), accessed, data.getId());
|
||||
_data=data;
|
||||
if (_dftMaxIdleSecs>0)
|
||||
_data.setMaxIdleMs(_dftMaxIdleSecs*1000L);
|
||||
_jdbcAttributes.putAll(_data.getAttributeMap());
|
||||
_data.setAttributeMap(_jdbcAttributes);
|
||||
}
|
||||
* Session restored in database.
|
||||
* @param data
|
||||
*/
|
||||
protected Session (long accessed, SessionData data)
|
||||
{
|
||||
super(JDBCSessionManager.this,data.getCreated(), accessed, data.getId());
|
||||
_data=data;
|
||||
if (_dftMaxIdleSecs>0)
|
||||
_data.setMaxIdleMs(_dftMaxIdleSecs*1000L);
|
||||
addAttributes(_data.getAttributeMap());
|
||||
_data.setAttributeMap(getAttributeMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute (String name, Object value)
|
||||
|
@ -541,7 +542,7 @@ public class JDBCSessionManager extends AbstractSessionManager
|
|||
//if the session has no expiry, or it is not already expired
|
||||
if (data._expiryTime <= 0 || data._expiryTime > now)
|
||||
{
|
||||
LOG.debug("getSession("+idInCluster+"): lastNode="+data.getLastNode()+" thisNode="+getSessionIdManager().getWorkerName());
|
||||
if (LOG.isDebugEnabled()) LOG.debug("getSession("+idInCluster+"): lastNode="+data.getLastNode()+" thisNode="+getSessionIdManager().getWorkerName());
|
||||
data.setLastNode(getSessionIdManager().getWorkerName());
|
||||
//session last used on a different node, or we don't have it in memory
|
||||
session = new Session(now,data);
|
||||
|
@ -552,18 +553,21 @@ public class JDBCSessionManager extends AbstractSessionManager
|
|||
updateSessionNode(data);
|
||||
}
|
||||
else
|
||||
if (LOG.isDebugEnabled()) LOG.debug("getSession("+idInCluster+"): Session has expired");
|
||||
{
|
||||
LOG.debug("getSession ({}): Session has expired", idInCluster);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
if (LOG.isDebugEnabled()) LOG.debug("getSession("+idInCluster+"): Session not stale "+session._data);
|
||||
LOG.debug("getSession({}): Session not stale {}", idInCluster,session._data);
|
||||
//session in db shares same id, but is not for this context
|
||||
}
|
||||
else
|
||||
{
|
||||
//No session in db with matching id and context path.
|
||||
session=null;
|
||||
if (LOG.isDebugEnabled()) LOG.debug("getSession("+idInCluster+"): No session in database matching id="+idInCluster);
|
||||
LOG.debug("getSession({}): No session in database matching id={}",idInCluster,idInCluster);
|
||||
}
|
||||
|
||||
return session;
|
||||
|
@ -607,6 +611,7 @@ public class JDBCSessionManager extends AbstractSessionManager
|
|||
_jdbcSessionIdMgr = (JDBCSessionIdManager)_sessionIdManager;
|
||||
|
||||
_sessions = new ConcurrentHashMap<String, AbstractSession>();
|
||||
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.eclipse.jetty.server;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
@ -26,12 +27,16 @@ import static org.junit.Assert.fail;
|
|||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eclipse.jetty.http.EncodedHttpURI;
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
public class HttpURITest
|
||||
|
@ -205,6 +210,106 @@ public class HttpURITest
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNoPercentEncodingOfQueryUsingNonUTF8() throws Exception
|
||||
{
|
||||
|
||||
byte[] utf8_bytes = "/%D0%A1%D1%82%D1%80%D0%BE%D0%BD%D0%B3-%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80/%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3?".getBytes("UTF-8");
|
||||
byte[] cp1251_bytes = TypeUtil.fromHexString("e2fbe1f0e0edee3dd2e5ecefe5f0e0f2f3f0e0");
|
||||
String expectedCP1251String = new String(cp1251_bytes, "cp1251");
|
||||
String expectedCP1251Key = new String(cp1251_bytes, 0, 7, "cp1251");
|
||||
String expectedCP1251Value = new String(cp1251_bytes, 8, cp1251_bytes.length-8, "cp1251");
|
||||
|
||||
//paste both byte arrays together to form the uri
|
||||
byte[] allbytes = new byte[utf8_bytes.length+cp1251_bytes.length];
|
||||
int i=0;
|
||||
for (;i<utf8_bytes.length;i++) {
|
||||
allbytes[i] = utf8_bytes[i];
|
||||
}
|
||||
for (int j=0; j< cp1251_bytes.length;j++)
|
||||
allbytes[i+j] = cp1251_bytes[j];
|
||||
|
||||
//Test using a HttpUri that expects a particular charset encoding. See URIUtil.__CHARSET
|
||||
EncodedHttpURI uri = new EncodedHttpURI("cp1251");
|
||||
uri.parse(allbytes, 0, allbytes.length);
|
||||
assertEquals(expectedCP1251String, uri.getQuery("cp1251"));
|
||||
|
||||
//Test params decoded correctly
|
||||
MultiMap params = new MultiMap();
|
||||
uri.decodeQueryTo(params);
|
||||
String val = params.getString(expectedCP1251Key);
|
||||
assertNotNull(val);
|
||||
assertEquals(expectedCP1251Value, val);
|
||||
|
||||
//Test using HttpURI where you pass in the charset encoding.
|
||||
HttpURI httpuri = new HttpURI();
|
||||
httpuri.parse(allbytes,0,allbytes.length);
|
||||
assertNotNull(httpuri.getQuery("UTF-8")); //still get back a query string, just incorrectly encoded
|
||||
assertEquals(expectedCP1251String, httpuri.getQuery("cp1251"));
|
||||
|
||||
//Test params decoded correctly
|
||||
params.clear();
|
||||
httpuri.decodeQueryTo(params, "cp1251");
|
||||
val = params.getString(expectedCP1251Key);
|
||||
assertNotNull(val);
|
||||
assertEquals(expectedCP1251Value, val);
|
||||
|
||||
//test able to set the query encoding and call getQueryString multiple times
|
||||
Request request = new Request();
|
||||
request.setUri(httpuri);
|
||||
request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "ISO-8859-1");
|
||||
assertNotNull (request.getQueryString()); //will be incorrect encoding but not null
|
||||
request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "cp1251");
|
||||
assertEquals(expectedCP1251String, request.getQueryString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPercentEncodingOfQueryStringUsingNonUTF8() throws UnsupportedEncodingException
|
||||
{
|
||||
|
||||
byte[] utf8_bytes = "/%D0%A1%D1%82%D1%80%D0%BE%D0%BD%D0%B3-%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80/%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3?".getBytes("UTF-8");
|
||||
byte[] cp1251_bytes = "%e2%fb%e1%f0%e0%ed%ee=%d2%e5%ec%ef%e5%f0%e0%f2%f3%f0%e0".getBytes("cp1251");
|
||||
|
||||
byte[] key_bytes = TypeUtil.fromHexString("e2fbe1f0e0edee");
|
||||
byte[] val_bytes = TypeUtil.fromHexString("d2e5ecefe5f0e0f2f3f0e0");
|
||||
String expectedCP1251String = new String(cp1251_bytes, "cp1251");
|
||||
String expectedCP1251Key = new String(key_bytes, "cp1251");
|
||||
String expectedCP1251Value = new String(val_bytes, "cp1251");
|
||||
|
||||
byte[] allbytes = new byte[utf8_bytes.length+cp1251_bytes.length];
|
||||
|
||||
//stick both arrays together to form uri
|
||||
int i=0;
|
||||
for (;i<utf8_bytes.length;i++) {
|
||||
allbytes[i] = utf8_bytes[i];
|
||||
}
|
||||
for (int j=0; j< cp1251_bytes.length;j++)
|
||||
allbytes[i+j] = cp1251_bytes[j];
|
||||
|
||||
|
||||
HttpURI httpuri = new HttpURI();
|
||||
httpuri.parse(allbytes,0,allbytes.length);
|
||||
assertNotNull(httpuri.getQuery("UTF-8")); //will be incorrectly encoded, but no errors
|
||||
assertEquals(expectedCP1251String, httpuri.getQuery("cp1251"));
|
||||
|
||||
//test params decoded correctly
|
||||
MultiMap params = new MultiMap();
|
||||
httpuri.decodeQueryTo(params, "cp1251");
|
||||
String val = params.getString(expectedCP1251Key);
|
||||
assertNotNull(val);
|
||||
assertEquals(expectedCP1251Value, val);
|
||||
|
||||
//test able to set the query encoding and call getQueryString multiple times
|
||||
Request request = new Request();
|
||||
request.setUri(httpuri);
|
||||
request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "ISO-8859-1");
|
||||
assertNotNull (request.getQueryString()); //will be incorrect encoding but not null
|
||||
request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "cp1251");
|
||||
assertEquals(expectedCP1251String, request.getQueryString());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnicodeErrors() throws UnsupportedEncodingException
|
||||
|
|
|
@ -37,7 +37,9 @@ import java.util.Enumeration;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.MultipartConfigElement;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequestEvent;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
@ -49,6 +51,7 @@ import org.eclipse.jetty.http.MimeTypes;
|
|||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.MultiPartInputStream;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.junit.After;
|
||||
|
@ -131,7 +134,7 @@ public class RequestTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testMultiPart() throws Exception
|
||||
public void testMultiPartNoConfig() throws Exception
|
||||
{
|
||||
_handler._checker = new RequestTester()
|
||||
{
|
||||
|
@ -140,14 +143,16 @@ public class RequestTest
|
|||
try
|
||||
{
|
||||
Part foo = request.getPart("stuff");
|
||||
assertNotNull(foo);
|
||||
String value = request.getParameter("stuff");
|
||||
byte[] expected = "000000000000000000000000000000000000000000000000000".getBytes("ISO-8859-1");
|
||||
return value.equals(new String(expected, "ISO-8859-1"));
|
||||
return false;
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
//expected exception because no multipart config is set up
|
||||
assertTrue(e.getMessage().startsWith("No multipart config"));
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -174,6 +179,66 @@ public class RequestTest
|
|||
String responses=_connector.getResponses(request);
|
||||
assertTrue(responses.startsWith("HTTP/1.1 200"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMultiPart() throws Exception
|
||||
{
|
||||
final File tmpDir = new File (System.getProperty("java.io.tmpdir"));
|
||||
final File testTmpDir = new File (tmpDir, "reqtest");
|
||||
testTmpDir.deleteOnExit();
|
||||
assertTrue(testTmpDir.mkdirs());
|
||||
assertTrue(testTmpDir.list().length == 0);
|
||||
|
||||
ContextHandler contextHandler = new ContextHandler();
|
||||
contextHandler.setContextPath("/foo");
|
||||
contextHandler.setResourceBase(".");
|
||||
contextHandler.setHandler(new MultiPartRequestHandler(testTmpDir));
|
||||
contextHandler.addEventListener(new Request.MultiPartCleanerListener()
|
||||
{
|
||||
|
||||
@Override
|
||||
public void requestDestroyed(ServletRequestEvent sre)
|
||||
{
|
||||
MultiPartInputStream m = (MultiPartInputStream)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM);
|
||||
ContextHandler.Context c = (ContextHandler.Context)sre.getServletRequest().getAttribute(Request.__MULTIPART_CONTEXT);
|
||||
assertNotNull (m);
|
||||
assertNotNull (c);
|
||||
assertTrue(c == sre.getServletContext());
|
||||
assertTrue(!m.getParsedParts().isEmpty());
|
||||
assertTrue(testTmpDir.list().length == 2);
|
||||
super.requestDestroyed(sre);
|
||||
String[] files = testTmpDir.list();
|
||||
assertTrue(files.length == 0);
|
||||
}
|
||||
|
||||
});
|
||||
_server.stop();
|
||||
_server.setHandler(contextHandler);
|
||||
_server.start();
|
||||
|
||||
String multipart = "--AaB03x\r\n"+
|
||||
"content-disposition: form-data; name=\"field1\"\r\n"+
|
||||
"\r\n"+
|
||||
"Joe Blow\r\n"+
|
||||
"--AaB03x\r\n"+
|
||||
"content-disposition: form-data; name=\"stuff\"; filename=\"foo.upload\"\r\n"+
|
||||
"Content-Type: text/plain;charset=ISO-8859-1\r\n"+
|
||||
"\r\n"+
|
||||
"000000000000000000000000000000000000000000000000000\r\n"+
|
||||
"--AaB03x--\r\n";
|
||||
|
||||
String request="GET /foo/x.html HTTP/1.1\r\n"+
|
||||
"Host: whatever\r\n"+
|
||||
"Content-Type: multipart/form-data; boundary=\"AaB03x\"\r\n"+
|
||||
"Content-Length: "+multipart.getBytes().length+"\r\n"+
|
||||
"\r\n"+
|
||||
multipart;
|
||||
|
||||
String responses=_connector.getResponses(request);
|
||||
System.err.println(responses);
|
||||
assertTrue(responses.startsWith("HTTP/1.1 200"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadUtf8ParamExtraction() throws Exception
|
||||
|
@ -912,4 +977,43 @@ public class RequestTest
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
private class MultiPartRequestHandler extends AbstractHandler
|
||||
{
|
||||
File tmpDir;
|
||||
|
||||
public MultiPartRequestHandler(File tmpDir)
|
||||
{
|
||||
this.tmpDir = tmpDir;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
((Request)request).setHandled(true);
|
||||
try
|
||||
{
|
||||
|
||||
MultipartConfigElement mpce = new MultipartConfigElement(tmpDir.getAbsolutePath(),-1, -1, 2);
|
||||
request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, mpce);
|
||||
|
||||
Part foo = request.getPart("stuff");
|
||||
assertNotNull(foo);
|
||||
assertTrue(foo.getSize() > 0);
|
||||
|
||||
response.setStatus(200);
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
//expected exception because no multipart config is set up
|
||||
assertTrue(e.getMessage().startsWith("No multipart config"));
|
||||
response.setStatus(200);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
response.sendError(500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.Socket;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.session.SessionHandler;
|
||||
|
@ -54,7 +55,7 @@ public class SelectChannelTimeoutTest extends ConnectorTimeoutTest
|
|||
|
||||
_handler.setSuspendFor(100);
|
||||
_handler.setResumeAfter(25);
|
||||
assertTrue(process(null).toUpperCase().contains("RESUMED"));
|
||||
assertTrue(process(null).toUpperCase(Locale.ENGLISH).contains("RESUMED"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -68,7 +69,7 @@ public class SelectChannelTimeoutTest extends ConnectorTimeoutTest
|
|||
_server.start();
|
||||
|
||||
_handler.setSuspendFor(50);
|
||||
assertTrue(process(null).toUpperCase().contains("TIMEOUT"));
|
||||
assertTrue(process(null).toUpperCase(Locale.ENGLISH).contains("TIMEOUT"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -83,7 +84,7 @@ public class SelectChannelTimeoutTest extends ConnectorTimeoutTest
|
|||
|
||||
_handler.setSuspendFor(100);
|
||||
_handler.setCompleteAfter(25);
|
||||
assertTrue(process(null).toUpperCase().contains("COMPLETED"));
|
||||
assertTrue(process(null).toUpperCase(Locale.ENGLISH).contains("COMPLETED"));
|
||||
}
|
||||
|
||||
private synchronized String process(String content) throws UnsupportedEncodingException, IOException, InterruptedException
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.io.IOException;
|
|||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -104,7 +105,7 @@ public abstract class AbstractConnectHandlerTest
|
|||
assertTrue(header.lookingAt());
|
||||
String headerName = header.group(1);
|
||||
String headerValue = header.group(2);
|
||||
headers.put(headerName.toLowerCase(), headerValue.toLowerCase());
|
||||
headers.put(headerName.toLowerCase(Locale.ENGLISH), headerValue.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
StringBuilder body;
|
||||
|
|
|
@ -30,6 +30,7 @@ import java.net.Socket;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -152,7 +153,7 @@ public class IPAccessHandlerTest
|
|||
assertTrue(header.lookingAt());
|
||||
String headerName = header.group(1);
|
||||
String headerValue = header.group(2);
|
||||
headers.put(headerName.toLowerCase(), headerValue.toLowerCase());
|
||||
headers.put(headerName.toLowerCase(Locale.ENGLISH), headerValue.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
StringBuilder body = new StringBuilder();
|
||||
|
|
|
@ -50,6 +50,7 @@ public class ErrorPageErrorHandler extends ErrorHandler
|
|||
private static final Logger LOG = Log.getLogger(ErrorPageErrorHandler.class);
|
||||
|
||||
public final static String ERROR_PAGE="org.eclipse.jetty.server.error_page";
|
||||
public final static String GLOBAL_ERROR_PAGE = "org.eclipse.jetty.server.error_page.global";
|
||||
|
||||
protected ServletContext _servletContext;
|
||||
private final Map<String,String> _errorPages= new HashMap<String,String>(); // code or exception to URL
|
||||
|
@ -120,6 +121,12 @@ public class ErrorPageErrorHandler extends ErrorHandler
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
//try new servlet 3.0 global error page
|
||||
if (error_page == null)
|
||||
{
|
||||
error_page = _errorPages.get(GLOBAL_ERROR_PAGE);
|
||||
}
|
||||
|
||||
if (error_page!=null)
|
||||
{
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.servlet;
|
|||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
@ -91,7 +92,7 @@ public class Invoker extends HttpServlet
|
|||
{
|
||||
String param=(String)e.nextElement();
|
||||
String value=getInitParameter(param);
|
||||
String lvalue=value.toLowerCase();
|
||||
String lvalue=value.toLowerCase(Locale.ENGLISH);
|
||||
if ("nonContextServlets".equals(param))
|
||||
{
|
||||
_nonContextServlets=value.length()>0 && lvalue.startsWith("t");
|
||||
|
|
|
@ -48,6 +48,7 @@ import javax.servlet.descriptor.JspPropertyGroupDescriptor;
|
|||
import javax.servlet.descriptor.TaglibDescriptor;
|
||||
|
||||
import org.eclipse.jetty.security.ConstraintAware;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.security.SecurityHandler;
|
||||
import org.eclipse.jetty.server.Dispatcher;
|
||||
|
@ -59,6 +60,7 @@ import org.eclipse.jetty.server.handler.HandlerCollection;
|
|||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||
import org.eclipse.jetty.server.session.SessionHandler;
|
||||
import org.eclipse.jetty.util.LazyList;
|
||||
import org.eclipse.jetty.util.security.Constraint;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -377,10 +379,21 @@ public class ServletContextHandler extends ContextHandler
|
|||
* @param registration ServletRegistration.Dynamic instance that setServletSecurity was called on
|
||||
* @param servletSecurityElement new security info
|
||||
* @return the set of exact URL mappings currently associated with the registration that are also present in the web.xml
|
||||
* security constratins and thus will be unaffected by this call.
|
||||
* security constraints and thus will be unaffected by this call.
|
||||
*/
|
||||
public Set<String> setServletSecurity(ServletRegistration.Dynamic registration, ServletSecurityElement servletSecurityElement)
|
||||
{
|
||||
//Default implementation is to just accept them all. If using a webapp, then this behaviour is overridden in WebAppContext.setServletSecurity
|
||||
Collection<String> pathSpecs = registration.getMappings();
|
||||
if (pathSpecs != null)
|
||||
{
|
||||
for (String pathSpec:pathSpecs)
|
||||
{
|
||||
List<ConstraintMapping> mappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath(registration.getName(), pathSpec, servletSecurityElement);
|
||||
for (ConstraintMapping m:mappings)
|
||||
((ConstraintAware)getSecurityHandler()).addConstraintMapping(m);
|
||||
}
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
|
|
|
@ -514,6 +514,8 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
|
|||
initJspServlet();
|
||||
}
|
||||
|
||||
initMultiPart();
|
||||
|
||||
_servlet.init(_config);
|
||||
}
|
||||
catch (UnavailableException e)
|
||||
|
@ -570,6 +572,25 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Register a ServletRequestListener that will ensure tmp multipart
|
||||
* files are deleted when the request goes out of scope.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected void initMultiPart () throws Exception
|
||||
{
|
||||
//if this servlet can handle multipart requests, ensure tmp files will be
|
||||
//cleaned up correctly
|
||||
if (((Registration)getRegistration()).getMultipartConfig() != null)
|
||||
{
|
||||
//Register a listener to delete tmp files that are created as a result of this
|
||||
//servlet calling Request.getPart() or Request.getParts()
|
||||
ContextHandler ch = ((ContextHandler.Context)getServletHandler().getServletContext()).getContextHandler();
|
||||
ch.addEventListener(new Request.MultiPartCleanerListener());
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
|
|
@ -56,6 +56,7 @@ import org.eclipse.jetty.server.handler.ContextHandler;
|
|||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.ResourceHandler;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -114,6 +115,23 @@ public class DispatcherTest
|
|||
assertEquals(expected, responses);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test public void testForwardNonUTF8() throws Exception
|
||||
{
|
||||
_contextHandler.addServlet(ForwardNonUTF8Servlet.class, "/ForwardServlet/*");
|
||||
_contextHandler.addServlet(AssertNonUTF8ForwardServlet.class, "/AssertForwardServlet/*");
|
||||
|
||||
String expected=
|
||||
"HTTP/1.1 200 OK\r\n"+
|
||||
"Content-Type: text/html\r\n"+
|
||||
"Content-Length: 0\r\n"+
|
||||
"\r\n";
|
||||
String responses = _connector.getResponses("GET /context/ForwardServlet?do=assertforward&foreign=%d2%e5%ec%ef%e5%f0%e0%f2%f3%f0%e0&test=1 HTTP/1.1\n" + "Host: localhost\n\n");
|
||||
|
||||
assertEquals(expected, responses);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForwardWithParam() throws Exception
|
||||
{
|
||||
|
@ -306,6 +324,7 @@ public class DispatcherTest
|
|||
dispatcher = getServletContext().getRequestDispatcher("/IncludeServlet/includepath?do=assertforwardinclude");
|
||||
else if(request.getParameter("do").equals("assertincludeforward"))
|
||||
dispatcher = getServletContext().getRequestDispatcher("/AssertIncludeForwardServlet/assertpath?do=end");
|
||||
|
||||
else if(request.getParameter("do").equals("assertforward"))
|
||||
dispatcher = getServletContext().getRequestDispatcher("/AssertForwardServlet?do=end&do=the");
|
||||
else if(request.getParameter("do").equals("ctx.echo"))
|
||||
|
@ -316,6 +335,18 @@ public class DispatcherTest
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ForwardNonUTF8Servlet extends HttpServlet implements Servlet
|
||||
{
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
RequestDispatcher dispatcher = null;
|
||||
request.setAttribute("org.eclipse.jetty.server.Request.queryEncoding", "cp1251");
|
||||
dispatcher = getServletContext().getRequestDispatcher("/AssertForwardServlet?do=end&else=%D0%B2%D1%8B%D0%B1%D1%80%D0%B0%D0%BD%D0%BE%3D%D0%A2%D0%B5%D0%BC%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D1%83%D1%80%D0%B0");
|
||||
dispatcher.forward(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Forward filter works with roger, echo and reverse echo servlets to test various
|
||||
* forwarding bits using filters.
|
||||
|
@ -534,6 +565,45 @@ public class DispatcherTest
|
|||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class AssertNonUTF8ForwardServlet extends HttpServlet implements Servlet
|
||||
{
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
byte[] cp1251_bytes = TypeUtil.fromHexString("d2e5ecefe5f0e0f2f3f0e0");
|
||||
String expectedCP1251String = new String(cp1251_bytes, "cp1251");
|
||||
|
||||
assertEquals( "/context/ForwardServlet", request.getAttribute(Dispatcher.FORWARD_REQUEST_URI));
|
||||
assertEquals( "/context", request.getAttribute(Dispatcher.FORWARD_CONTEXT_PATH) );
|
||||
assertEquals( "/ForwardServlet", request.getAttribute(Dispatcher.FORWARD_SERVLET_PATH));
|
||||
assertEquals( null, request.getAttribute(Dispatcher.FORWARD_PATH_INFO));
|
||||
assertEquals( "do=assertforward&foreign=%d2%e5%ec%ef%e5%f0%e0%f2%f3%f0%e0&test=1", request.getAttribute(Dispatcher.FORWARD_QUERY_STRING) );
|
||||
|
||||
List<String> expectedAttributeNames = Arrays.asList(Dispatcher.FORWARD_REQUEST_URI, Dispatcher.FORWARD_CONTEXT_PATH,
|
||||
Dispatcher.FORWARD_SERVLET_PATH, Dispatcher.FORWARD_QUERY_STRING);
|
||||
List<String> requestAttributeNames = Collections.list(request.getAttributeNames());
|
||||
assertTrue(requestAttributeNames.containsAll(expectedAttributeNames));
|
||||
|
||||
assertEquals(null, request.getPathInfo());
|
||||
assertEquals(null, request.getPathTranslated());
|
||||
assertTrue(request.getQueryString().startsWith("do=end&else=%D0%B2%D1%8B%D0%B1%D1%80%D0%B0%D0%BD%D0%BE%3D%D0%A2%D0%B5%D0%BC%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D1%83%D1%80%D0%B0&test=1&foreign="));
|
||||
|
||||
String[] vals = request.getParameterValues("foreign");
|
||||
assertTrue(vals!=null);
|
||||
assertEquals(1, vals.length);
|
||||
assertEquals(expectedCP1251String, vals[0]);
|
||||
|
||||
assertEquals("/context/AssertForwardServlet", request.getRequestURI());
|
||||
assertEquals("/context", request.getContextPath());
|
||||
assertEquals("/AssertForwardServlet", request.getServletPath());
|
||||
|
||||
response.setContentType("text/html");
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class AssertIncludeServlet extends HttpServlet implements Servlet
|
||||
{
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.io.InputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
@ -139,7 +140,7 @@ public class CGI extends HttpServlet
|
|||
if (!_env.envMap.containsKey("SystemRoot"))
|
||||
{
|
||||
String os = System.getProperty("os.name");
|
||||
if (os != null && os.toLowerCase().indexOf("windows") != -1)
|
||||
if (os != null && os.toLowerCase(Locale.ENGLISH).indexOf("windows") != -1)
|
||||
{
|
||||
_env.set("SystemRoot","C:\\WINDOWS");
|
||||
}
|
||||
|
@ -256,7 +257,7 @@ public class CGI extends HttpServlet
|
|||
{
|
||||
String name = (String)enm.nextElement();
|
||||
String value = req.getHeader(name);
|
||||
env.set("HTTP_" + name.toUpperCase().replace('-','_'),value);
|
||||
env.set("HTTP_" + name.toUpperCase(Locale.ENGLISH).replace('-','_'),value);
|
||||
}
|
||||
|
||||
// these extra ones were from printenv on www.dev.nomura.co.uk
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.servlets;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -278,7 +279,7 @@ public class GzipFilter extends UserAgentFilter
|
|||
{
|
||||
for (int i=0; i< encodings.length; i++)
|
||||
{
|
||||
if (encodings[i].toLowerCase().contains(GZIP))
|
||||
if (encodings[i].toLowerCase(Locale.ENGLISH).contains(GZIP))
|
||||
{
|
||||
if (isEncodingAcceptable(encodings[i]))
|
||||
{
|
||||
|
@ -287,7 +288,7 @@ public class GzipFilter extends UserAgentFilter
|
|||
}
|
||||
}
|
||||
|
||||
if (encodings[i].toLowerCase().contains(DEFLATE))
|
||||
if (encodings[i].toLowerCase(Locale.ENGLISH).contains(DEFLATE))
|
||||
{
|
||||
if (isEncodingAcceptable(encodings[i]))
|
||||
{
|
||||
|
|
|
@ -34,6 +34,7 @@ import java.util.Enumeration;
|
|||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
@ -84,7 +85,7 @@ import org.eclipse.jetty.util.TypeUtil;
|
|||
public class MultiPartFilter implements Filter
|
||||
{
|
||||
public final static String CONTENT_TYPE_SUFFIX=".org.eclipse.jetty.servlet.contentType";
|
||||
private final static String FILES ="org.eclipse.jetty.servlet.MultiPartFilter.files";
|
||||
private final static String MULTIPART = "org.eclipse.jetty.servlet.MultiPartFile.multiPartInputStream";
|
||||
private File tempdir;
|
||||
private boolean _deleteFiles;
|
||||
private ServletContext _context;
|
||||
|
@ -149,7 +150,8 @@ public class MultiPartFilter implements Filter
|
|||
|
||||
MultipartConfigElement config = new MultipartConfigElement(tempdir.getCanonicalPath(), _maxFileSize, _maxRequestSize, _fileOutputBuffer);
|
||||
MultiPartInputStream mpis = new MultiPartInputStream(in, content_type, config, tempdir);
|
||||
|
||||
mpis.setDeleteOnExit(_deleteFiles);
|
||||
request.setAttribute(MULTIPART, mpis);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -170,18 +172,6 @@ public class MultiPartFilter implements Filter
|
|||
if (mp.getContentType() != null)
|
||||
params.add(mp.getName()+CONTENT_TYPE_SUFFIX, mp.getContentType());
|
||||
}
|
||||
if (_deleteFiles)
|
||||
{
|
||||
mp.getFile().deleteOnExit();
|
||||
|
||||
ArrayList files = (ArrayList)request.getAttribute(FILES);
|
||||
if (files==null)
|
||||
{
|
||||
files=new ArrayList();
|
||||
request.setAttribute(FILES,files);
|
||||
}
|
||||
files.add(mp.getFile());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -202,26 +192,27 @@ public class MultiPartFilter implements Filter
|
|||
deleteFiles(request);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void deleteFiles(ServletRequest request)
|
||||
{
|
||||
ArrayList files = (ArrayList)request.getAttribute(FILES);
|
||||
if (files!=null)
|
||||
if (!_deleteFiles)
|
||||
return;
|
||||
|
||||
MultiPartInputStream mpis = (MultiPartInputStream)request.getAttribute(MULTIPART);
|
||||
if (mpis != null)
|
||||
{
|
||||
Iterator iter = files.iterator();
|
||||
while (iter.hasNext())
|
||||
try
|
||||
{
|
||||
File file=(File)iter.next();
|
||||
try
|
||||
{
|
||||
file.delete();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
_context.log("failed to delete "+file,e);
|
||||
}
|
||||
mpis.deleteParts();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_context.log("Error deleting multipart tmp files", e);
|
||||
}
|
||||
}
|
||||
request.removeAttribute(MULTIPART);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -30,6 +30,7 @@ import java.util.Collections;
|
|||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
|
@ -489,7 +490,7 @@ public class ProxyServlet implements Servlet
|
|||
protected void onResponseHeader(Buffer name, Buffer value) throws IOException
|
||||
{
|
||||
String nameString = name.toString();
|
||||
String s = nameString.toLowerCase();
|
||||
String s = nameString.toLowerCase(Locale.ENGLISH);
|
||||
if (!_DontProxyHeaders.contains(s) || (HttpHeaders.CONNECTION_BUFFER.equals(name) && HttpHeaderValues.CLOSE_BUFFER.equals(value)))
|
||||
{
|
||||
if (debug != 0)
|
||||
|
@ -560,7 +561,7 @@ public class ProxyServlet implements Servlet
|
|||
String connectionHdr = request.getHeader("Connection");
|
||||
if (connectionHdr != null)
|
||||
{
|
||||
connectionHdr = connectionHdr.toLowerCase();
|
||||
connectionHdr = connectionHdr.toLowerCase(Locale.ENGLISH);
|
||||
if (connectionHdr.indexOf("keep-alive") < 0 && connectionHdr.indexOf("close") < 0)
|
||||
connectionHdr = null;
|
||||
}
|
||||
|
@ -578,7 +579,7 @@ public class ProxyServlet implements Servlet
|
|||
{
|
||||
// TODO could be better than this!
|
||||
String hdr = (String)enm.nextElement();
|
||||
String lhdr = hdr.toLowerCase();
|
||||
String lhdr = hdr.toLowerCase(Locale.ENGLISH);
|
||||
|
||||
if (_DontProxyHeaders.contains(lhdr))
|
||||
continue;
|
||||
|
|
|
@ -121,7 +121,7 @@ public class MultipartFilterTest
|
|||
|
||||
response.parse(tester.getResponses(request.generate()));
|
||||
assertTrue(response.getMethod()==null);
|
||||
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
|
||||
assertEquals(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,response.getStatus());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ import java.util.EnumSet;
|
|||
import javax.servlet.DispatcherType;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
@ -63,7 +64,7 @@ public class PutFilterTest
|
|||
FilterHolder holder = tester.addFilter(PutFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST));
|
||||
holder.setInitParameter("delAllowed","true");
|
||||
// Bloody Windows does not allow file renaming
|
||||
if (!System.getProperty("os.name").toLowerCase().contains("windows"))
|
||||
if (!System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("windows"))
|
||||
holder.setInitParameter("putAtomic","true");
|
||||
tester.start();
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.Collections;
|
|||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -93,7 +94,7 @@ public class Headers implements Iterable<Headers.Header>
|
|||
*/
|
||||
public Header get(String name)
|
||||
{
|
||||
return headers.get(name.trim().toLowerCase());
|
||||
return headers.get(name.trim().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,7 +107,7 @@ public class Headers implements Iterable<Headers.Header>
|
|||
{
|
||||
name = name.trim();
|
||||
Header header = new Header(name, value.trim());
|
||||
headers.put(name.toLowerCase(), header);
|
||||
headers.put(name.toLowerCase(Locale.ENGLISH), header);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -117,7 +118,7 @@ public class Headers implements Iterable<Headers.Header>
|
|||
public void put(Header header)
|
||||
{
|
||||
if (header != null)
|
||||
headers.put(header.name().toLowerCase(), header);
|
||||
headers.put(header.name().toLowerCase(Locale.ENGLISH), header);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,16 +131,16 @@ public class Headers implements Iterable<Headers.Header>
|
|||
public void add(String name, String value)
|
||||
{
|
||||
name = name.trim();
|
||||
Header header = headers.get(name.toLowerCase());
|
||||
Header header = headers.get(name.toLowerCase(Locale.ENGLISH));
|
||||
if (header == null)
|
||||
{
|
||||
header = new Header(name, value.trim());
|
||||
headers.put(name.toLowerCase(), header);
|
||||
headers.put(name.toLowerCase(Locale.ENGLISH), header);
|
||||
}
|
||||
else
|
||||
{
|
||||
header = new Header(header.name(), header.value() + "," + value.trim());
|
||||
headers.put(name.toLowerCase(), header);
|
||||
headers.put(name.toLowerCase(Locale.ENGLISH), header);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,7 +153,7 @@ public class Headers implements Iterable<Headers.Header>
|
|||
public Header remove(String name)
|
||||
{
|
||||
name = name.trim();
|
||||
return headers.remove(name.toLowerCase());
|
||||
return headers.remove(name.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -229,7 +230,7 @@ public class Headers implements Iterable<Headers.Header>
|
|||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
int result = name.toLowerCase().hashCode();
|
||||
int result = name.toLowerCase(Locale.ENGLISH).hashCode();
|
||||
result = 31 * result + Arrays.hashCode(values);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.spdy.generator;
|
|||
import java.io.ByteArrayOutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.jetty.spdy.CompressionDictionary;
|
||||
import org.eclipse.jetty.spdy.CompressionFactory;
|
||||
|
@ -45,7 +46,7 @@ public class HeadersBlockGenerator
|
|||
writeCount(version, buffer, headers.size());
|
||||
for (Headers.Header header : headers)
|
||||
{
|
||||
String name = header.name().toLowerCase();
|
||||
String name = header.name().toLowerCase(Locale.ENGLISH);
|
||||
byte[] nameBytes = name.getBytes(iso1);
|
||||
writeNameLength(version, buffer, nameBytes.length);
|
||||
buffer.write(nameBytes, 0, nameBytes.length);
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
@ -205,7 +206,7 @@ public class ReferrerPushStrategy implements PushStrategy
|
|||
if (header == null)
|
||||
return true;
|
||||
|
||||
String contentType = header.value().toLowerCase();
|
||||
String contentType = header.value().toLowerCase(Locale.ENGLISH);
|
||||
for (String pushContentType : pushContentTypes)
|
||||
if (contentType.startsWith(pushContentType))
|
||||
return true;
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.io.IOException;
|
|||
import java.io.InterruptedIOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Locale;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
@ -664,7 +665,7 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
|
|||
for (int i = 0; i < fields.size(); ++i)
|
||||
{
|
||||
HttpFields.Field field = fields.getField(i);
|
||||
String name = field.getName().toLowerCase();
|
||||
String name = field.getName().toLowerCase(Locale.ENGLISH);
|
||||
String value = field.getValue();
|
||||
headers.put(name, value);
|
||||
logger.debug("HTTP < {}: {}", name, value);
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.spdy.proxy;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -95,7 +96,7 @@ public class ProxyHTTPSPDYAsyncConnection extends AsyncHttpConnection
|
|||
@Override
|
||||
protected void parsedHeader(Buffer name, Buffer value) throws IOException
|
||||
{
|
||||
String headerName = name.toString("UTF-8").toLowerCase();
|
||||
String headerName = name.toString("UTF-8").toLowerCase(Locale.ENGLISH);
|
||||
String headerValue = value.toString("UTF-8");
|
||||
switch (headerName)
|
||||
{
|
||||
|
|
|
@ -38,6 +38,7 @@ import java.util.Enumeration;
|
|||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
@ -269,7 +270,7 @@ public class Config
|
|||
}
|
||||
else
|
||||
{
|
||||
String name = entry.getName().toLowerCase();
|
||||
String name = entry.getName().toLowerCase(Locale.ENGLISH);
|
||||
if (name.endsWith(".jar") || name.endsWith(".zip"))
|
||||
{
|
||||
String jar = entry.getCanonicalPath();
|
||||
|
@ -796,7 +797,7 @@ public class Config
|
|||
}
|
||||
|
||||
// Add XML configuration
|
||||
if (subject.toLowerCase().endsWith(".xml"))
|
||||
if (subject.toLowerCase(Locale.ENGLISH).endsWith(".xml"))
|
||||
{
|
||||
// Config file
|
||||
File f = new File(fixPath(file));
|
||||
|
@ -807,7 +808,7 @@ public class Config
|
|||
}
|
||||
|
||||
// Set the main class to execute (overrides any previously set)
|
||||
if (subject.toLowerCase().endsWith(".class"))
|
||||
if (subject.toLowerCase(Locale.ENGLISH).endsWith(".class"))
|
||||
{
|
||||
// Class
|
||||
String cn = expand(subject.substring(0,subject.length() - 6));
|
||||
|
@ -820,7 +821,7 @@ public class Config
|
|||
}
|
||||
|
||||
// Add raw classpath entry
|
||||
if (subject.toLowerCase().endsWith(".path"))
|
||||
if (subject.toLowerCase(Locale.ENGLISH).endsWith(".path"))
|
||||
{
|
||||
// classpath (jetty.class.path?) to add to runtime classpath
|
||||
String cn = expand(subject.substring(0,subject.length() - 5));
|
||||
|
|
|
@ -30,6 +30,7 @@ import java.io.FilenameFilter;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.LineNumberReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
@ -37,6 +38,7 @@ import java.lang.reflect.Method;
|
|||
import java.net.ConnectException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -44,6 +46,7 @@ import java.util.Collections;
|
|||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -152,7 +155,7 @@ public class Main
|
|||
{
|
||||
public boolean accept(File dir, String name)
|
||||
{
|
||||
return name.toLowerCase().endsWith(".ini");
|
||||
return name.toLowerCase(Locale.ENGLISH).endsWith(".ini");
|
||||
}
|
||||
});
|
||||
Arrays.sort(inis);
|
||||
|
@ -184,6 +187,15 @@ public class Main
|
|||
stop(port,key);
|
||||
return null;
|
||||
}
|
||||
|
||||
if ("--stop-wait".equals(arg))
|
||||
{
|
||||
int port = Integer.parseInt(Config.getProperty("STOP.PORT","-1"));
|
||||
String key = Config.getProperty("STOP.KEY",null);
|
||||
int timeout = Integer.parseInt(Config.getProperty("STOP.WAIT", "0"));
|
||||
stop(port,key, true, timeout);
|
||||
return null;
|
||||
}
|
||||
|
||||
if ("--version".equals(arg) || "-v".equals(arg) || "--info".equals(arg))
|
||||
{
|
||||
|
@ -288,7 +300,7 @@ public class Main
|
|||
{
|
||||
String opts[] = assign[1].split(",");
|
||||
for (String opt : opts)
|
||||
_config.addActiveOption(opt);
|
||||
_config.addActiveOption(opt.trim());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -374,7 +386,7 @@ public class Main
|
|||
return false;
|
||||
}
|
||||
|
||||
String name = path.getName().toLowerCase();
|
||||
String name = path.getName().toLowerCase(Locale.ENGLISH);
|
||||
return (name.startsWith("jetty") && name.endsWith(".xml"));
|
||||
}
|
||||
});
|
||||
|
@ -648,7 +660,7 @@ public class Main
|
|||
|
||||
private String resolveXmlConfig(String xmlFilename) throws FileNotFoundException
|
||||
{
|
||||
if (!xmlFilename.toLowerCase().endsWith(".xml"))
|
||||
if (!xmlFilename.toLowerCase(Locale.ENGLISH).endsWith(".xml"))
|
||||
{
|
||||
// Nothing to resolve.
|
||||
return xmlFilename;
|
||||
|
@ -862,7 +874,7 @@ public class Main
|
|||
|
||||
if (element.isFile())
|
||||
{
|
||||
String name = element.getName().toLowerCase();
|
||||
String name = element.getName().toLowerCase(Locale.ENGLISH);
|
||||
if (name.endsWith(".jar"))
|
||||
{
|
||||
return JarVersion.getVersion(element);
|
||||
|
@ -1002,6 +1014,12 @@ public class Main
|
|||
* Stop a running jetty instance.
|
||||
*/
|
||||
public void stop(int port, String key)
|
||||
{
|
||||
stop (port,key,false, 0);
|
||||
}
|
||||
|
||||
|
||||
public void stop (int port, String key, boolean wait, int timeout)
|
||||
{
|
||||
int _port = port;
|
||||
String _key = key;
|
||||
|
@ -1020,17 +1038,33 @@ public class Main
|
|||
}
|
||||
|
||||
Socket s = new Socket(InetAddress.getByName("127.0.0.1"),_port);
|
||||
if (wait && timeout > 0)
|
||||
s.setSoTimeout(timeout*1000);
|
||||
try
|
||||
{
|
||||
OutputStream out = s.getOutputStream();
|
||||
out.write((_key + "\r\nstop\r\n").getBytes());
|
||||
out.flush();
|
||||
|
||||
if (wait)
|
||||
{
|
||||
System.err.println("Waiting"+(timeout > 0 ? (" "+timeout+"sec") : "")+" for jetty to stop");
|
||||
LineNumberReader lin = new LineNumberReader(new InputStreamReader(s.getInputStream()));
|
||||
String response=lin.readLine();
|
||||
if ("Stopped".equals(response))
|
||||
System.err.println("Stopped");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
s.close();
|
||||
}
|
||||
}
|
||||
catch (SocketTimeoutException e)
|
||||
{
|
||||
System.err.println("Timed out waiting for stop confirmation");
|
||||
System.exit(ERR_UNKNOWN);
|
||||
}
|
||||
catch (ConnectException e)
|
||||
{
|
||||
usageExit(e,ERR_NOT_STOPPED);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
//
|
||||
|
||||
package org.eclipse.jetty.start;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.LineNumberReader;
|
||||
import java.net.InetAddress;
|
||||
|
@ -113,21 +114,23 @@ public class Monitor extends Thread
|
|||
Config.debug("command=" + cmd);
|
||||
if ("stop".equals(cmd))
|
||||
{
|
||||
try {socket.close();}catch(Exception e){e.printStackTrace();}
|
||||
try {_socket.close();}catch(Exception e){e.printStackTrace();}
|
||||
if (_process!=null)
|
||||
{
|
||||
//if we have a child process, wait for it to finish before we stop
|
||||
try
|
||||
{
|
||||
_process.destroy();
|
||||
_process.waitFor();
|
||||
_process.destroy();
|
||||
_process.waitFor();
|
||||
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
System.err.println("Interrupted waiting for child to terminate");
|
||||
}
|
||||
}
|
||||
socket.getOutputStream().write("Stopped\r\n".getBytes());
|
||||
try {socket.close();}catch(Exception e){e.printStackTrace();}
|
||||
try {_socket.close();}catch(Exception e){e.printStackTrace();}
|
||||
System.exit(0);
|
||||
}
|
||||
else if ("status".equals(cmd))
|
||||
|
|
|
@ -24,7 +24,10 @@ Command Line Options:
|
|||
contains -X or -D arguments, but creates an extra
|
||||
JVM instance.
|
||||
|
||||
--stop Stop the running Jetty instance.
|
||||
--stop Send a stop signal to the running Jetty instance.
|
||||
|
||||
--stop-wait Send a stop signal to the running Jetty instance, waiting for
|
||||
confirmation that it is stopping.
|
||||
|
||||
--daemon Start in daemon mode with stderr and stdout
|
||||
redirected to ${jetty.log}/start.log
|
||||
|
@ -92,6 +95,11 @@ Properties:
|
|||
STOP.KEY=[alphanumeric]
|
||||
The passphrase defined to stop the server.
|
||||
Requried along with STOP.PORT if you want to use the --stop option above.
|
||||
|
||||
STOP.WAIT=[number]
|
||||
The time (in seconds) to wait for confirmation that the running Jetty server
|
||||
has stopped. If not specified, the stopper will wait indefinitely. Use in
|
||||
conjunction with the --stop-wait option.
|
||||
|
||||
DEBUG=true
|
||||
Enable debug on the start mechanism and sets the
|
||||
|
|
|
@ -34,8 +34,10 @@ import java.io.InputStreamReader;
|
|||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
|
@ -59,7 +61,7 @@ public class MultiPartInputStream
|
|||
protected MultiMap<String> _parts;
|
||||
protected File _tmpDir;
|
||||
protected File _contextTmpDir;
|
||||
|
||||
protected boolean _deleteOnExit;
|
||||
|
||||
|
||||
|
||||
|
@ -73,6 +75,7 @@ public class MultiPartInputStream
|
|||
protected String _contentType;
|
||||
protected MultiMap<String> _headers;
|
||||
protected long _size = 0;
|
||||
protected boolean _temporary = true;
|
||||
|
||||
public MultiPart (String name, String filename)
|
||||
throws IOException
|
||||
|
@ -141,6 +144,8 @@ public class MultiPartInputStream
|
|||
throws IOException
|
||||
{
|
||||
_file = File.createTempFile("MultiPart", "", MultiPartInputStream.this._tmpDir);
|
||||
if (_deleteOnExit)
|
||||
_file.deleteOnExit();
|
||||
FileOutputStream fos = new FileOutputStream(_file);
|
||||
BufferedOutputStream bos = new BufferedOutputStream(fos);
|
||||
|
||||
|
@ -177,7 +182,7 @@ public class MultiPartInputStream
|
|||
{
|
||||
if (name == null)
|
||||
return null;
|
||||
return (String)_headers.getValue(name.toLowerCase(), 0);
|
||||
return (String)_headers.getValue(name.toLowerCase(Locale.ENGLISH), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -203,11 +208,12 @@ public class MultiPartInputStream
|
|||
{
|
||||
if (_file != null)
|
||||
{
|
||||
//written to a file, whether temporary or not
|
||||
return new BufferedInputStream (new FileInputStream(_file));
|
||||
}
|
||||
else
|
||||
{
|
||||
//part content is in a ByteArrayOutputStream
|
||||
//part content is in memory
|
||||
return new ByteArrayInputStream(_bout.getBuf(),0,_bout.size());
|
||||
}
|
||||
}
|
||||
|
@ -232,7 +238,7 @@ public class MultiPartInputStream
|
|||
*/
|
||||
public long getSize()
|
||||
{
|
||||
return _size;
|
||||
return _size;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -242,8 +248,11 @@ public class MultiPartInputStream
|
|||
{
|
||||
if (_file == null)
|
||||
{
|
||||
_temporary = false;
|
||||
|
||||
//part data is only in the ByteArrayOutputStream and never been written to disk
|
||||
_file = new File (_tmpDir, fileName);
|
||||
|
||||
BufferedOutputStream bos = null;
|
||||
try
|
||||
{
|
||||
|
@ -261,6 +270,8 @@ public class MultiPartInputStream
|
|||
else
|
||||
{
|
||||
//the part data is already written to a temporary file, just rename it
|
||||
_temporary = false;
|
||||
|
||||
File f = new File(_tmpDir, fileName);
|
||||
if (_file.renameTo(f))
|
||||
_file = f;
|
||||
|
@ -268,14 +279,27 @@ public class MultiPartInputStream
|
|||
}
|
||||
|
||||
/**
|
||||
* Remove the file, whether or not Part.write() was called on it
|
||||
* (ie no longer temporary)
|
||||
* @see javax.servlet.http.Part#delete()
|
||||
*/
|
||||
public void delete() throws IOException
|
||||
{
|
||||
if (_file != null)
|
||||
if (_file != null && _file.exists())
|
||||
_file.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Only remove tmp files.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void cleanUp() throws IOException
|
||||
{
|
||||
if (_temporary && _file != null && _file.exists())
|
||||
_file.delete();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the file, if any, the data has been written to.
|
||||
|
@ -314,12 +338,65 @@ public class MultiPartInputStream
|
|||
_contextTmpDir = contextTmpDir;
|
||||
if (_contextTmpDir == null)
|
||||
_contextTmpDir = new File (System.getProperty("java.io.tmpdir"));
|
||||
|
||||
if (_config == null)
|
||||
_config = new MultipartConfigElement(_contextTmpDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the already parsed parts.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Collection<Part> getParsedParts()
|
||||
{
|
||||
if (_parts == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
Collection<Object> values = _parts.values();
|
||||
List<Part> parts = new ArrayList<Part>();
|
||||
for (Object o: values)
|
||||
{
|
||||
List<Part> asList = LazyList.getList(o, false);
|
||||
parts.addAll(asList);
|
||||
}
|
||||
return parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete any tmp storage for parts, and clear out the parts list.
|
||||
*
|
||||
* @throws MultiException
|
||||
*/
|
||||
public void deleteParts ()
|
||||
throws MultiException
|
||||
{
|
||||
Collection<Part> parts = getParsedParts();
|
||||
MultiException err = new MultiException();
|
||||
for (Part p:parts)
|
||||
{
|
||||
try
|
||||
{
|
||||
((MultiPartInputStream.MultiPart)p).cleanUp();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
err.add(e);
|
||||
}
|
||||
}
|
||||
_parts.clear();
|
||||
|
||||
err.ifExceptionThrowMulti();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse, if necessary, the multipart data and return the list of Parts.
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
public Collection<Part> getParts()
|
||||
throws IOException, ServletException
|
||||
{
|
||||
|
@ -335,6 +412,14 @@ public class MultiPartInputStream
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the named Part.
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
public Part getPart(String name)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
|
@ -343,6 +428,12 @@ public class MultiPartInputStream
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse, if necessary, the multipart stream.
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
protected void parse ()
|
||||
throws IOException, ServletException
|
||||
{
|
||||
|
@ -415,7 +506,7 @@ public class MultiPartInputStream
|
|||
int c=line.indexOf(':',0);
|
||||
if(c>0)
|
||||
{
|
||||
String key=line.substring(0,c).trim().toLowerCase();
|
||||
String key=line.substring(0,c).trim().toLowerCase(Locale.ENGLISH);
|
||||
String value=line.substring(c+1,line.length()).trim();
|
||||
headers.put(key, value);
|
||||
if (key.equalsIgnoreCase("content-disposition"))
|
||||
|
@ -441,7 +532,7 @@ public class MultiPartInputStream
|
|||
while(tok.hasMoreTokens())
|
||||
{
|
||||
String t=tok.nextToken().trim();
|
||||
String tl=t.toLowerCase();
|
||||
String tl=t.toLowerCase(Locale.ENGLISH);
|
||||
if(t.startsWith("form-data"))
|
||||
form_data=true;
|
||||
else if(tl.startsWith("name="))
|
||||
|
@ -589,9 +680,22 @@ public class MultiPartInputStream
|
|||
part.close();
|
||||
}
|
||||
}
|
||||
if (!lastPart)
|
||||
throw new IOException("Incomplete parts");
|
||||
}
|
||||
|
||||
|
||||
public void setDeleteOnExit(boolean deleteOnExit)
|
||||
{
|
||||
_deleteOnExit = deleteOnExit;
|
||||
}
|
||||
|
||||
|
||||
public boolean isDeleteOnExit()
|
||||
{
|
||||
return _deleteOnExit;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private String value(String nameEqualsValue, boolean splitAfterSpace)
|
||||
{
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.text.SimpleDateFormat;
|
|||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
@ -221,7 +222,7 @@ public class RolloverFileOutputStream extends FilterOutputStream
|
|||
|
||||
// Is this a rollover file?
|
||||
String filename=file.getName();
|
||||
int i=filename.toLowerCase().indexOf(YYYY_MM_DD);
|
||||
int i=filename.toLowerCase(Locale.ENGLISH).indexOf(YYYY_MM_DD);
|
||||
if (i>=0)
|
||||
{
|
||||
file=new File(dir,
|
||||
|
@ -258,7 +259,7 @@ public class RolloverFileOutputStream extends FilterOutputStream
|
|||
File file= new File(_filename);
|
||||
File dir = new File(file.getParent());
|
||||
String fn=file.getName();
|
||||
int s=fn.toLowerCase().indexOf(YYYY_MM_DD);
|
||||
int s=fn.toLowerCase(Locale.ENGLISH).indexOf(YYYY_MM_DD);
|
||||
if (s<0)
|
||||
return;
|
||||
String prefix=fn.substring(0,s);
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.lang.reflect.Method;
|
|||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -89,9 +90,9 @@ public class JSONObjectConvertor implements JSON.Convertor
|
|||
{
|
||||
String name=m.getName();
|
||||
if (name.startsWith("is"))
|
||||
name=name.substring(2,3).toLowerCase()+name.substring(3);
|
||||
name=name.substring(2,3).toLowerCase(Locale.ENGLISH)+name.substring(3);
|
||||
else if (name.startsWith("get"))
|
||||
name=name.substring(3,4).toLowerCase()+name.substring(4);
|
||||
name=name.substring(3,4).toLowerCase(Locale.ENGLISH)+name.substring(4);
|
||||
else
|
||||
continue;
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.Arrays;
|
|||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -122,9 +123,9 @@ public class JSONPojoConvertor implements JSON.Convertor
|
|||
if(m.getReturnType()!=null)
|
||||
{
|
||||
if (name.startsWith("is") && name.length()>2)
|
||||
name=name.substring(2,3).toLowerCase()+name.substring(3);
|
||||
name=name.substring(2,3).toLowerCase(Locale.ENGLISH)+name.substring(3);
|
||||
else if (name.startsWith("get") && name.length()>3)
|
||||
name=name.substring(3,4).toLowerCase()+name.substring(4);
|
||||
name=name.substring(3,4).toLowerCase(Locale.ENGLISH)+name.substring(4);
|
||||
else
|
||||
break;
|
||||
if(includeField(name, m))
|
||||
|
@ -134,7 +135,7 @@ public class JSONPojoConvertor implements JSON.Convertor
|
|||
case 1:
|
||||
if (name.startsWith("set") && name.length()>3)
|
||||
{
|
||||
name=name.substring(3,4).toLowerCase()+name.substring(4);
|
||||
name=name.substring(3,4).toLowerCase(Locale.ENGLISH)+name.substring(4);
|
||||
if(includeField(name, m))
|
||||
addSetter(name, m);
|
||||
}
|
||||
|
|
|
@ -31,12 +31,11 @@ import org.eclipse.jetty.util.DateCache;
|
|||
* the eclipse jetty root level logger level to that specified level. (Default level is INFO)
|
||||
* <p>
|
||||
* If the system property "org.eclipse.jetty.util.log.SOURCE" is set, then the source method/file of a log is logged.
|
||||
* For named debuggers, the system property name+".SOURCE" is checked. If it is not not set, then
|
||||
* "org.eclipse.jetty.util.log.SOURCE" is used as the default.
|
||||
* For named debuggers, the system property name+".SOURCE" is checked, eg "org.eclipse.jetty.util.log.stderr.SOURCE".
|
||||
* If it is not not set, then "org.eclipse.jetty.util.log.SOURCE" is used as the default.
|
||||
* <p>
|
||||
* If the system property "org.eclipse.jetty.util.log.LONG" is set, then the full, unabbreviated name of the logger is
|
||||
* used for logging. For named debuggers, the system property name+".LONG" is checked. If it is not not set, then
|
||||
* "org.eclipse.jetty.util.log.LONG" is used as the default.
|
||||
* If the system property "org.eclipse.jetty.util.log.stderr.LONG" is set, then the full, unabbreviated name of the logger is
|
||||
* used for logging.
|
||||
*/
|
||||
public class StdErrLog extends AbstractLogger
|
||||
{
|
||||
|
|
|
@ -27,6 +27,7 @@ import static org.junit.Assert.assertThat;
|
|||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
|
@ -50,8 +51,42 @@ public class MultiPartInputStreamTest extends TestCase
|
|||
protected String _contentType = "multipart/form-data, boundary=AaB03x";
|
||||
protected String _multi = createMultipartRequestString(FILENAME);
|
||||
protected String _dirname = System.getProperty("java.io.tmpdir")+File.separator+"myfiles-"+System.currentTimeMillis();
|
||||
protected File _tmpDir = new File(_dirname);
|
||||
|
||||
public MultiPartInputStreamTest ()
|
||||
{
|
||||
_tmpDir.deleteOnExit();
|
||||
}
|
||||
|
||||
public void testBadMultiPartRequest()
|
||||
throws Exception
|
||||
{
|
||||
String boundary = "X0Y0";
|
||||
String str = "--" + boundary + "\r\n"+
|
||||
"Content-Disposition: form-data; name=\"fileup\"; filename=\"test.upload\"\r\n"+
|
||||
"Content-Type: application/octet-stream\r\n\r\n"+
|
||||
"How now brown cow."+
|
||||
"\r\n--" + boundary + "-\r\n\r\n";
|
||||
|
||||
MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
|
||||
MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(str.getBytes()),
|
||||
"multipart/form-data, boundary="+boundary,
|
||||
config,
|
||||
_tmpDir);
|
||||
mpis.setDeleteOnExit(true);
|
||||
try
|
||||
{
|
||||
mpis.getParts();
|
||||
fail ("Multipart incomplete");
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
assertTrue(e.getMessage().startsWith("Incomplete"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void testNonMultiPartRequest()
|
||||
throws Exception
|
||||
{
|
||||
|
@ -59,7 +94,8 @@ public class MultiPartInputStreamTest extends TestCase
|
|||
MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(_multi.getBytes()),
|
||||
"Content-type: text/plain",
|
||||
config,
|
||||
new File(_dirname));
|
||||
_tmpDir);
|
||||
mpis.setDeleteOnExit(true);
|
||||
assertTrue(mpis.getParts().isEmpty());
|
||||
}
|
||||
|
||||
|
@ -70,7 +106,8 @@ public class MultiPartInputStreamTest extends TestCase
|
|||
MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(_multi.getBytes()),
|
||||
_contentType,
|
||||
config,
|
||||
new File(_dirname));
|
||||
_tmpDir);
|
||||
mpis.setDeleteOnExit(true);
|
||||
Collection<Part> parts = mpis.getParts();
|
||||
assertFalse(parts.isEmpty());
|
||||
}
|
||||
|
@ -82,11 +119,12 @@ public class MultiPartInputStreamTest extends TestCase
|
|||
MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(_multi.getBytes()),
|
||||
_contentType,
|
||||
config,
|
||||
new File(_dirname));
|
||||
|
||||
_tmpDir);
|
||||
mpis.setDeleteOnExit(true);
|
||||
Collection<Part> parts = null;
|
||||
try
|
||||
{
|
||||
mpis.getParts();
|
||||
parts = mpis.getParts();
|
||||
fail("Request should have exceeded maxRequestSize");
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
|
@ -102,11 +140,12 @@ public class MultiPartInputStreamTest extends TestCase
|
|||
MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(_multi.getBytes()),
|
||||
_contentType,
|
||||
config,
|
||||
new File(_dirname));
|
||||
|
||||
_tmpDir);
|
||||
mpis.setDeleteOnExit(true);
|
||||
Collection<Part> parts = null;
|
||||
try
|
||||
{
|
||||
mpis.getParts();
|
||||
parts = mpis.getParts();
|
||||
fail("stuff.txt should have been larger than maxFileSize");
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
|
@ -115,6 +154,48 @@ public class MultiPartInputStreamTest extends TestCase
|
|||
}
|
||||
}
|
||||
|
||||
public void testPartFileNotDeleted () throws Exception
|
||||
{
|
||||
MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
|
||||
MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(createMultipartRequestString("tptfd").getBytes()),
|
||||
_contentType,
|
||||
config,
|
||||
_tmpDir);
|
||||
mpis.setDeleteOnExit(true);
|
||||
Collection<Part> parts = mpis.getParts();
|
||||
|
||||
MultiPart part = (MultiPart)mpis.getPart("stuff");
|
||||
File stuff = ((MultiPartInputStream.MultiPart)part).getFile();
|
||||
assertThat(stuff,notNullValue()); // longer than 100 bytes, should already be a tmp file
|
||||
part.write("tptfd.txt");
|
||||
File tptfd = new File (_dirname+File.separator+"tptfd.txt");
|
||||
assertThat(tptfd.exists(), is(true));
|
||||
assertThat(stuff.exists(), is(false)); //got renamed
|
||||
part.cleanUp();
|
||||
assertThat(tptfd.exists(), is(true)); //explicitly written file did not get removed after cleanup
|
||||
tptfd.deleteOnExit(); //clean up test
|
||||
}
|
||||
|
||||
|
||||
public void testPartTmpFileDeletion () throws Exception
|
||||
{
|
||||
MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
|
||||
MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(createMultipartRequestString("tptfd").getBytes()),
|
||||
_contentType,
|
||||
config,
|
||||
_tmpDir);
|
||||
mpis.setDeleteOnExit(true);
|
||||
Collection<Part> parts = mpis.getParts();
|
||||
|
||||
MultiPart part = (MultiPart)mpis.getPart("stuff");
|
||||
File stuff = ((MultiPartInputStream.MultiPart)part).getFile();
|
||||
assertThat(stuff,notNullValue()); // longer than 100 bytes, should already be a tmp file
|
||||
assertThat (stuff.exists(), is(true));
|
||||
part.cleanUp();
|
||||
assertThat(stuff.exists(), is(false)); //tmp file was removed after cleanup
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void testMulti ()
|
||||
throws Exception
|
||||
|
@ -133,11 +214,11 @@ public class MultiPartInputStreamTest extends TestCase
|
|||
MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(createMultipartRequestString(filename).getBytes()),
|
||||
_contentType,
|
||||
config,
|
||||
new File(_dirname));
|
||||
|
||||
_tmpDir);
|
||||
mpis.setDeleteOnExit(true);
|
||||
Collection<Part> parts = mpis.getParts();
|
||||
assertThat(parts.size(), is(2));
|
||||
Part field1 = mpis.getPart("field1");
|
||||
Part field1 = mpis.getPart("field1"); //field 1 too small to go into tmp file, should be in internal buffer
|
||||
assertThat(field1,notNullValue());
|
||||
assertThat(field1.getName(),is("field1"));
|
||||
InputStream is = field1.getInputStream();
|
||||
|
@ -146,17 +227,18 @@ public class MultiPartInputStreamTest extends TestCase
|
|||
assertEquals("Joe Blow", new String(os.toByteArray()));
|
||||
assertEquals(8, field1.getSize());
|
||||
|
||||
assertNotNull(((MultiPartInputStream.MultiPart)field1).getBytes()); //in internal buffer
|
||||
assertNotNull(((MultiPartInputStream.MultiPart)field1).getBytes());//in internal buffer
|
||||
field1.write("field1.txt");
|
||||
assertNull(((MultiPartInputStream.MultiPart)field1).getBytes()); //no longer in internal buffer
|
||||
assertNull(((MultiPartInputStream.MultiPart)field1).getBytes());//no longer in internal buffer
|
||||
File f = new File (_dirname+File.separator+"field1.txt");
|
||||
assertTrue(f.exists());
|
||||
field1.write("another_field1.txt");
|
||||
field1.write("another_field1.txt"); //write after having already written
|
||||
File f2 = new File(_dirname+File.separator+"another_field1.txt");
|
||||
assertTrue(f2.exists());
|
||||
assertFalse(f.exists()); //should have been renamed
|
||||
field1.delete(); //file should be deleted
|
||||
assertFalse(f2.exists());
|
||||
assertFalse(f.exists()); //original file was renamed
|
||||
assertFalse(f2.exists()); //2nd written file was explicitly deleted
|
||||
|
||||
MultiPart stuff = (MultiPart)mpis.getPart("stuff");
|
||||
assertThat(stuff.getContentDispositionFilename(), is(filename));
|
||||
|
@ -166,14 +248,24 @@ public class MultiPartInputStreamTest extends TestCase
|
|||
assertThat(stuff.getHeader("content-disposition"),is("form-data; name=\"stuff\"; filename=\"" + filename + "\""));
|
||||
assertThat(stuff.getHeaderNames().size(),is(2));
|
||||
assertThat(stuff.getSize(),is(51L));
|
||||
f = ((MultiPartInputStream.MultiPart)stuff).getFile();
|
||||
assertThat(f,notNullValue()); // longer than 100 bytes, should already be a file
|
||||
assertThat(((MultiPartInputStream.MultiPart)stuff).getBytes(),nullValue()); //not in internal buffer any more
|
||||
assertThat(f.exists(),is(true));
|
||||
assertThat(f.getName(),is(not("stuff with space.txt")));
|
||||
File tmpfile = ((MultiPartInputStream.MultiPart)stuff).getFile();
|
||||
assertThat(tmpfile,notNullValue()); // longer than 100 bytes, should already be a tmp file
|
||||
assertThat(((MultiPartInputStream.MultiPart)stuff).getBytes(),nullValue()); //not in an internal buffer
|
||||
assertThat(tmpfile.exists(),is(true));
|
||||
assertThat(tmpfile.getName(),is(not("stuff with space.txt")));
|
||||
stuff.write(filename);
|
||||
f = new File(_dirname+File.separator+filename);
|
||||
assertThat(f.exists(),is(true));
|
||||
assertThat(tmpfile.exists(), is(false));
|
||||
try
|
||||
{
|
||||
stuff.getInputStream();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
fail("Part.getInputStream() after file rename operation");
|
||||
}
|
||||
f.deleteOnExit(); //clean up after test
|
||||
}
|
||||
|
||||
public void testMultiSameNames ()
|
||||
|
@ -188,15 +280,15 @@ public class MultiPartInputStreamTest extends TestCase
|
|||
"content-disposition: form-data; name=\"stuff\"; filename=\"stuff2.txt\"\r\n"+
|
||||
"Content-Type: text/plain\r\n"+
|
||||
"\r\n"+
|
||||
"000000000000000000000000000000000000000000000000000\r\n"+
|
||||
"110000000000000000000000000000000000000000000000000\r\n"+
|
||||
"--AaB03x--\r\n";
|
||||
|
||||
MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
|
||||
MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(sameNames.getBytes()),
|
||||
_contentType,
|
||||
config,
|
||||
new File(_dirname));
|
||||
|
||||
_tmpDir);
|
||||
mpis.setDeleteOnExit(true);
|
||||
Collection<Part> parts = mpis.getParts();
|
||||
assertEquals(2, parts.size());
|
||||
for (Part p:parts)
|
||||
|
@ -210,6 +302,18 @@ public class MultiPartInputStreamTest extends TestCase
|
|||
|
||||
private String createMultipartRequestString(String filename)
|
||||
{
|
||||
int length = filename.length();
|
||||
String name = filename;
|
||||
if (length > 10)
|
||||
name = filename.substring(0,10);
|
||||
StringBuffer filler = new StringBuffer();
|
||||
int i = name.length();
|
||||
while (i < 51)
|
||||
{
|
||||
filler.append("0");
|
||||
i++;
|
||||
}
|
||||
|
||||
return "--AaB03x\r\n"+
|
||||
"content-disposition: form-data; name=\"field1\"\r\n"+
|
||||
"\r\n"+
|
||||
|
@ -217,8 +321,8 @@ public class MultiPartInputStreamTest extends TestCase
|
|||
"--AaB03x\r\n"+
|
||||
"content-disposition: form-data; name=\"stuff\"; filename=\"" + filename + "\"\r\n"+
|
||||
"Content-Type: text/plain\r\n"+
|
||||
"\r\n"+
|
||||
"000000000000000000000000000000000000000000000000000\r\n"+
|
||||
"\r\n"+name+
|
||||
filler.toString()+"\r\n" +
|
||||
"--AaB03x--\r\n";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.webapp;
|
|||
import org.eclipse.jetty.util.Loader;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
||||
/**
|
||||
* DiscoveredAnnotation
|
||||
|
@ -36,16 +37,28 @@ public abstract class DiscoveredAnnotation
|
|||
protected WebAppContext _context;
|
||||
protected String _className;
|
||||
protected Class<?> _clazz;
|
||||
protected Resource _resource; //resource it was discovered on, can be null (eg from WEB-INF/classes)
|
||||
|
||||
public abstract void apply();
|
||||
|
||||
public DiscoveredAnnotation (WebAppContext context, String className)
|
||||
{
|
||||
_context = context;
|
||||
_className = className;
|
||||
this(context,className, null);
|
||||
}
|
||||
|
||||
|
||||
public DiscoveredAnnotation(WebAppContext context, String className, Resource resource)
|
||||
{
|
||||
_context = context;
|
||||
_className = className;
|
||||
_resource = resource;
|
||||
}
|
||||
|
||||
public Resource getResource ()
|
||||
{
|
||||
return _resource;
|
||||
}
|
||||
|
||||
public Class<?> getTargetClass()
|
||||
{
|
||||
if (_clazz != null)
|
||||
|
|
|
@ -136,7 +136,7 @@ public class FragmentDescriptor extends WebDescriptor
|
|||
node = (XmlParser.Node) o;
|
||||
if (node.getTag().equalsIgnoreCase("others"))
|
||||
{
|
||||
if (_otherType != OtherType.After)
|
||||
if (_otherType != OtherType.None)
|
||||
throw new IllegalStateException("Duplicate <other> clause detected in "+_xml.getURI());
|
||||
|
||||
_otherType = OtherType.After;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue