Merge branch 'jetty-7' into release-7

This commit is contained in:
Jesse McConnell 2012-11-05 11:43:27 -06:00
commit 073ab7af20
97 changed files with 2069 additions and 369 deletions

View File

@ -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;
@ -426,7 +427,7 @@ public class AnnotationParser
List<DiscoverableAnnotationHandler> handlers = _annotationHandlers.get(annotationName);
if (handlers == null)
return Collections.emptyList();
return new ArrayList<DiscoverableAnnotationHandler>();
return new ArrayList<DiscoverableAnnotationHandler>(handlers);
}
public List<DiscoverableAnnotationHandler> getAnnotationHandlers()
@ -580,7 +581,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)
@ -624,7 +625,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);

View File

@ -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);

View File

@ -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")));
}
/* ------------------------------------------------------------ */

View File

@ -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;

View File

@ -214,6 +214,7 @@ public class WebSocketUpgradeTest
return _websocket;
}
};
_handler.getWebSocketFactory().setMinVersion(-1);
_server.setHandler(_handler);
_server.start();

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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");
}
}

View File

@ -934,6 +934,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);
@ -945,6 +948,7 @@ public class HttpFields
if (path != null && path.length() > 0)
{
hasPath = true;
buf.append(";Path=");
if (path.trim().startsWith("\""))
buf.append(path);
@ -953,8 +957,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)
@ -985,14 +990,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;

View File

@ -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()

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -37,6 +37,7 @@ 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.server.Authentication;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.server.Authentication.User;
@ -44,7 +45,7 @@ import org.eclipse.jetty.server.Authentication.User;
/**
* @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 final ServerAuthConfig _authConfig;
@ -58,7 +59,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 +73,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 +94,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;
}

View File

@ -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);

View File

@ -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())

View File

@ -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;
}
/**

View File

@ -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");
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);

View File

@ -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());
}

View File

@ -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())
{

View File

@ -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;

View File

@ -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");

View File

@ -525,8 +525,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 +534,6 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
finally
{
previousIdentity = deferred.getPreviousAssociation();
deferred.setIdentityService(null);
}
if (authenticator!=null)

View File

@ -67,8 +67,8 @@ public class BasicAuthenticator extends LoginAuthenticator
try
{
if (!mandatory)
return _deferred;
return new DeferredAuthentication(this);
if (credentials != null)
{
int space=credentials.indexOf(' ');
@ -96,7 +96,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() + '"');

View File

@ -88,8 +88,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");
@ -129,8 +129,8 @@ public class ClientCertAuthenticator extends LoginAuthenticator
}
}
}
if (!_deferred.isDeferred(response))
if (!DeferredAuthentication.isDeferred(response))
{
response.sendError(HttpServletResponse.SC_FORBIDDEN);
return Authentication.SEND_FAILURE;

View File

@ -43,22 +43,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)
{
@ -66,36 +53,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;
}
/* ------------------------------------------------------------ */
/**
@ -109,8 +66,11 @@ 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;
}
}
@ -129,9 +89,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,14 +110,17 @@ public class DeferredAuthentication implements Authentication.Deferred
*/
public Authentication login(String username, String password)
{
if (_loginService!=null)
LoginService login_service= _authenticator.getLoginService();
IdentityService identity_service=login_service.getIdentityService();
if (login_service!=null)
{
UserIdentity user = _loginService.login(username,password);
UserIdentity user = login_service.login(username,password);
if (user!=null)
{
UserAuthentication authentication = new UserAuthentication("API",user);
if (_identityService!=null)
_previousAssociation=_identityService.associate(user);
if (identity_service!=null)
_previousAssociation=identity_service.associate(user);
return authentication;
}
}

View File

@ -121,8 +121,8 @@ public class DigestAuthenticator 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;
String credentials = request.getHeader(HttpHeaders.AUTHORIZATION);
@ -197,7 +197,7 @@ public class DigestAuthenticator extends LoginAuthenticator
}
if (!_deferred.isDeferred(response))
if (!DeferredAuthentication.isDeferred(response))
{
String domain = request.getContextPath();
if (domain == null)

View File

@ -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;
@ -191,11 +192,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
@ -300,9 +301,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 +391,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 +399,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 +413,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);
}

View File

@ -29,7 +29,6 @@ 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;

View File

@ -69,7 +69,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 +77,7 @@ public class SpnegoAuthenticator extends LoginAuthenticator
{
try
{
if (_deferred.isDeferred(res))
if (DeferredAuthentication.isDeferred(res))
{
return Authentication.UNAUTHENTICATED;
}

View File

@ -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)

View File

@ -1739,6 +1739,7 @@ public class Request implements HttpServletRequest
public void setQueryString(String queryString)
{
_queryString = queryString;
_queryEncoding = null; //assume utf-8
}
/* ------------------------------------------------------------ */
@ -1922,7 +1923,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;
@ -1957,10 +1958,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())

View File

@ -386,7 +386,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();

View File

@ -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();

View File

@ -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)

View File

@ -482,32 +482,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;

View File

@ -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");
}
}

View File

@ -265,7 +265,8 @@ public class JDBCSessionManager extends AbstractSessionManager
private static final long serialVersionUID = 5208464051134226143L;
private final SessionData _data;
private boolean _dirty=false;
/**
* Session from a request.
*
@ -274,7 +275,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()));
@ -284,18 +285,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)
@ -539,7 +540,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);
@ -550,18 +551,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;
@ -605,6 +609,7 @@ public class JDBCSessionManager extends AbstractSessionManager
_jdbcSessionIdMgr = (JDBCSessionIdManager)_sessionIdManager;
_sessions = new ConcurrentHashMap<String, AbstractSession>();
super.doStart();
}

View File

@ -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

View File

@ -24,6 +24,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

View File

@ -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;

View File

@ -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();

View File

@ -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)
{

View File

@ -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");

View File

@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.Filter;
@ -53,6 +54,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;
@ -111,6 +113,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
{
@ -303,6 +322,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"))
@ -313,6 +333,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.
@ -531,6 +563,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
{

View File

@ -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

View File

@ -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]))
{

View File

@ -36,6 +36,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;
@ -172,7 +173,7 @@ public class MultiPartFilter implements Filter
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();
if(key.equals("content-disposition"))
content_disposition=value;

View File

@ -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)

View File

@ -28,6 +28,7 @@ import java.net.Socket;
import java.net.URL;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import javax.servlet.http.HttpServletResponse;
@ -61,7 +62,7 @@ public class PutFilterTest
FilterHolder holder = tester.addFilter(PutFilter.class,"/*",0);
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();
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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)
{

View File

@ -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));

View File

@ -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);

View File

@ -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))

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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))

View File

@ -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
{

View File

@ -23,6 +23,7 @@ import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Locale;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.regex.Pattern;
@ -144,7 +145,7 @@ public abstract class JarScanner extends org.eclipse.jetty.util.PatternMatcher
throws Exception
{
LOG.debug("Search of {}",uri);
if (uri.toString().toLowerCase().endsWith(".jar"))
if (uri.toString().toLowerCase(Locale.ENGLISH).endsWith(".jar"))
{
InputStream in = Resource.newResource(uri).getInputStream();

View File

@ -22,6 +22,7 @@ package org.eclipse.jetty.webapp;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.jar.JarEntry;
import org.eclipse.jetty.util.log.Log;
@ -125,7 +126,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
}
else
{
String lcname = name.toLowerCase();
String lcname = name.toLowerCase(Locale.ENGLISH);
if (lcname.endsWith(".tld"))
{
addResource(context,METAINF_TLDS,Resource.newResource("jar:"+jarUri+"!/"+name));

View File

@ -27,6 +27,7 @@ import java.util.EnumSet;
import java.util.EventListener;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.servlet.ServletException;
@ -320,7 +321,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
XmlParser.Node startup = node.get("load-on-startup");
if (startup != null)
{
String s = startup.toString(false, true).toLowerCase();
String s = startup.toString(false, true).toLowerCase(Locale.ENGLISH);
int order = 0;
if (s.startsWith("t"))
{
@ -679,16 +680,18 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
String error = node.getString("error-code", false, true);
int code=0;
if (error == null || error.length() == 0)
{
error = node.getString("exception-type", false, true);
if (error == null || error.length() == 0)
error = ErrorPageErrorHandler.GLOBAL_ERROR_PAGE;
}
else
code=Integer.valueOf(error);
String location = node.getString("location", false, true);
ErrorPageErrorHandler handler = (ErrorPageErrorHandler)context.getErrorHandler();
Origin o = context.getMetaData().getOrigin("error."+error);
switch (o)
{
case NotSet:
@ -708,11 +711,16 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
//an error page setup was set in web.xml, only allow other web xml descriptors to override it
if (!(descriptor instanceof FragmentDescriptor))
{
if (code>0)
handler.addErrorPage(code,location);
if (descriptor instanceof OverrideDescriptor || descriptor instanceof DefaultsDescriptor)
{
if (code>0)
handler.addErrorPage(code,location);
else
handler.addErrorPage(error,location);
context.getMetaData().setOrigin("error."+error, descriptor);
}
else
handler.addErrorPage(error,location);
context.getMetaData().setOrigin("error."+error, descriptor);
throw new IllegalStateException("Duplicate global error-page "+location);
}
break;
}
@ -909,7 +917,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
if (data != null)
{
data = data.get("transport-guarantee");
String guarantee = data.toString(false, true).toUpperCase();
String guarantee = data.toString(false, true).toUpperCase(Locale.ENGLISH);
if (guarantee == null || guarantee.length() == 0 || "NONE".equals(guarantee))
scBase.setDataConstraint(Constraint.DC_NONE);
else if ("INTEGRAL".equals(guarantee))

View File

@ -28,6 +28,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;
@ -217,7 +218,7 @@ public class TagLibConfiguration extends AbstractConfiguration
while(iter.hasNext())
{
String location = iter.next();
if (location!=null && location.toLowerCase().endsWith(".tld"))
if (location!=null && location.toLowerCase(Locale.ENGLISH).endsWith(".tld"))
{
if (!location.startsWith("/"))
location="/WEB-INF/"+location;
@ -234,7 +235,7 @@ public class TagLibConfiguration extends AbstractConfiguration
String[] contents = web_inf.list();
for (int i=0;contents!=null && i<contents.length;i++)
{
if (contents[i]!=null && contents[i].toLowerCase().endsWith(".tld"))
if (contents[i]!=null && contents[i].toLowerCase(Locale.ENGLISH).endsWith(".tld"))
{
Resource l=web_inf.addPath(contents[i]);
tlds.add(l);
@ -249,7 +250,7 @@ public class TagLibConfiguration extends AbstractConfiguration
String[] contents = web_inf_tlds.list();
for (int i=0;contents!=null && i<contents.length;i++)
{
if (contents[i]!=null && contents[i].toLowerCase().endsWith(".tld"))
if (contents[i]!=null && contents[i].toLowerCase(Locale.ENGLISH).endsWith(".tld"))
{
Resource l=web_inf_tlds.addPath(contents[i]);
tlds.add(l);

View File

@ -29,6 +29,7 @@ import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.StringTokenizer;
@ -271,7 +272,7 @@ public class WebAppClassLoader extends URLClassLoader
try
{
Resource fn=lib.addPath(files[f]);
String fnlc=fn.getName().toLowerCase();
String fnlc=fn.getName().toLowerCase(Locale.ENGLISH);
// don't check if this is a directory, see Bug 353165
if (isFileSupported(fnlc))
{

View File

@ -26,6 +26,7 @@ import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.regex.Pattern;
import org.eclipse.jetty.server.Connector;
@ -442,7 +443,7 @@ public class WebInfConfiguration extends AbstractConfiguration
{
// look for a sibling like "foo/" to a "foo.war"
File warfile=Resource.newResource(war).getFile();
if (warfile!=null && warfile.getName().toLowerCase().endsWith(".war"))
if (warfile!=null && warfile.getName().toLowerCase(Locale.ENGLISH).endsWith(".war"))
{
File sibling = new File(warfile.getParent(),warfile.getName().substring(0,warfile.getName().length()-4));
if (sibling.exists() && sibling.isDirectory() && sibling.canWrite())
@ -709,7 +710,7 @@ public class WebInfConfiguration extends AbstractConfiguration
try
{
Resource file = web_inf_lib.addPath(files[f]);
String fnlc = file.getName().toLowerCase();
String fnlc = file.getName().toLowerCase(Locale.ENGLISH);
int dot = fnlc.lastIndexOf('.');
String extension = (dot < 0 ? null : fnlc.substring(dot));
if (extension != null && (extension.equals(".jar") || extension.equals(".zip")))

View File

@ -28,6 +28,7 @@ import java.util.Map;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.ConcurrentLinkedQueue;
import javax.net.ssl.SSLEngine;
import org.eclipse.jetty.http.HttpFields;
@ -389,7 +390,7 @@ public class WebSocketClientFactory extends AggregateLifeCycle
_accept = value.toString();
}
@Override
@Override // TODO simone says shouldn't be needed
public void startRequest(Buffer method, Buffer url, Buffer version) throws IOException
{
if (_error == null)
@ -397,7 +398,7 @@ public class WebSocketClientFactory extends AggregateLifeCycle
_endp.close();
}
@Override
@Override // TODO simone says shouldn't be needed
public void content(Buffer ref) throws IOException
{
if (_error == null)
@ -515,6 +516,7 @@ public class WebSocketClientFactory extends AggregateLifeCycle
private WebSocketConnection newWebSocketConnection() throws IOException
{
__log.debug("newWebSocketConnection()");
return new WebSocketClientConnection(
_future._client.getFactory(),
_future.getWebSocket(),

View File

@ -123,6 +123,8 @@ public class WebSocketConnectionD00 extends AbstractConnection implements WebSoc
_endp.close();
break;
}
else if (filled==0)
return this;
}
if (_websocket instanceof OnFrame)

View File

@ -323,13 +323,13 @@ public class WebSocketConnectionRFC6455 extends AbstractConnection implements We
try
{
if (tell_app)
_webSocket.onClose(code,message);
if (!closed_out)
closeOut(code,message);
}
finally
{
if (!closed_out)
closeOut(code,message);
if (tell_app)
_webSocket.onClose(code,message);
}
}
@ -353,7 +353,7 @@ public class WebSocketConnectionRFC6455 extends AbstractConnection implements We
}
try
{
{
if (tell_app)
_webSocket.onClose(code,message);
}

View File

@ -81,16 +81,37 @@ public class WebSocketFactory extends AbstractLifeCycle
private int _maxIdleTime = 300000;
private int _maxTextMessageSize = 16 * 1024;
private int _maxBinaryMessageSize = -1;
private int _minVersion;
public WebSocketFactory(Acceptor acceptor)
{
this(acceptor, 64 * 1024);
this(acceptor, 64 * 1024, WebSocketConnectionRFC6455.VERSION);
}
public WebSocketFactory(Acceptor acceptor, int bufferSize)
{
this(acceptor, bufferSize, WebSocketConnectionRFC6455.VERSION);
}
public WebSocketFactory(Acceptor acceptor, int bufferSize, int minVersion)
{
_buffers = new WebSocketBuffers(bufferSize);
_acceptor = acceptor;
_minVersion=WebSocketConnectionRFC6455.VERSION;
}
public int getMinVersion()
{
return _minVersion;
}
/* ------------------------------------------------------------ */
/**
* @param minVersion The minimum support version (default RCF6455.VERSION == 13 )
*/
public void setMinVersion(int minVersion)
{
_minVersion = minVersion;
}
/**
@ -227,6 +248,8 @@ public class WebSocketFactory extends AbstractLifeCycle
}
final WebSocketServletConnection connection;
if (draft<_minVersion)
draft=Integer.MAX_VALUE;
switch (draft)
{
case -1: // unspecified draft/version
@ -263,7 +286,15 @@ public class WebSocketFactory extends AbstractLifeCycle
LOG.warn("Unsupported Websocket version: " + draft);
// Per RFC 6455 - 4.4 - Supporting Multiple Versions of WebSocket Protocol
// Using the examples as outlined
response.setHeader("Sec-WebSocket-Version", "13, 8, 6, 0");
String versions="13";
if (_minVersion<=8)
versions+=", 8";
if (_minVersion<=6)
versions+=", 6";
if (_minVersion<=0)
versions+=", 0";
response.setHeader("Sec-WebSocket-Version", versions);
throw new HttpException(400, "Unsupported websocket version specification: " + draft);
}
}

View File

@ -45,6 +45,9 @@ import org.eclipse.jetty.util.log.Logger;
* <p/>
* The initParameter "maxBinaryMessagesSize" can be used to set the size in bytes
* that a websocket may be accept before closing.
* <p/>
* The initParameter "minVersion" can be used to set the minimum protocol version
* accepted. Default is the RFC6455 version (13)
*/
@SuppressWarnings("serial")
public abstract class WebSocketServlet extends HttpServlet implements WebSocketFactory.Acceptor
@ -76,6 +79,10 @@ public abstract class WebSocketServlet extends HttpServlet implements WebSocketF
max = getInitParameter("maxBinaryMessageSize");
if (max != null)
_webSocketFactory.setMaxBinaryMessageSize(Integer.parseInt(max));
String min = getInitParameter("minVersion");
if (min != null)
_webSocketFactory.setMinVersion(Integer.parseInt(min));
}
catch (ServletException x)
{

View File

@ -62,7 +62,9 @@ public class SafariWebsocketDraft0Test
// Serve capture servlet
servlet = new WebSocketCaptureServlet();
context.addServlet(new ServletHolder(servlet),"/");
ServletHolder holder = new ServletHolder(servlet);
holder.setInitParameter("minVersion","-1");
context.addServlet(holder,"/");
// Start Server
server.start();

View File

@ -0,0 +1,122 @@
//
// ========================================================================
// 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.websocket;
import java.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.websocket.dummy.DummyServer;
import org.eclipse.jetty.websocket.dummy.DummyServer.ServerConnection;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
public class TomcatServerQuirksTest
{
/**
* Test for when encountering a "Transfer-Encoding: chunked" on a Upgrade Response header.
* <ul>
* <li><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=393075">Eclipse Jetty Bug #393075</a></li>
* <li><a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=54067">Apache Tomcat Bug #54067</a></li>
* </ul>
* @throws IOException
*/
@Test
@Ignore("Bug with Transfer-Encoding")
public void testTomcat7_0_32_WithTransferEncoding() throws Exception {
DummyServer server = new DummyServer();
int bufferSize = 512;
QueuedThreadPool threadPool = new QueuedThreadPool();
WebSocketClientFactory factory = new WebSocketClientFactory(threadPool, new ZeroMaskGen(), bufferSize);
try {
server.start();
// Setup Client Factory
threadPool.start();
factory.start();
// Create Client
WebSocketClient client = new WebSocketClient(factory);
// Create End User WebSocket Class
final CountDownLatch openLatch = new CountDownLatch(1);
final CountDownLatch dataLatch = new CountDownLatch(1);
WebSocket.OnTextMessage websocket = new WebSocket.OnTextMessage()
{
public void onOpen(Connection connection)
{
openLatch.countDown();
}
public void onMessage(String data)
{
// System.out.println("data = " + data);
dataLatch.countDown();
}
public void onClose(int closeCode, String message)
{
}
};
// Open connection
URI wsURI = server.getWsUri();
client.open(wsURI, websocket);
// Accept incoming connection
ServerConnection socket = server.accept();
socket.setSoTimeout(2000); // timeout
// Issue upgrade
Map<String,String> extraResponseHeaders = new HashMap<String, String>();
extraResponseHeaders.put("Transfer-Encoding", "chunked"); // !! The problem !!
socket.upgrade(extraResponseHeaders);
// Wait for proper upgrade
Assert.assertTrue("Timed out waiting for Client side WebSocket open event", openLatch.await(1, TimeUnit.SECONDS));
// Have server write frame.
int length = bufferSize / 2;
ByteBuffer serverFrame = ByteBuffer.allocate(bufferSize);
serverFrame.put((byte)(0x80 | 0x01)); // FIN + TEXT
serverFrame.put((byte)0x7E); // No MASK and 2 bytes length
serverFrame.put((byte)(length >> 8)); // first length byte
serverFrame.put((byte)(length & 0xFF)); // second length byte
for (int i = 0; i < length; ++i)
serverFrame.put((byte)'x');
serverFrame.flip();
byte buf[] = serverFrame.array();
socket.write(buf,0,buf.length);
socket.flush();
Assert.assertTrue(dataLatch.await(1000, TimeUnit.SECONDS));
} finally {
factory.stop();
threadPool.stop();
server.stop();
}
}
}

View File

@ -18,6 +18,8 @@
package org.eclipse.jetty.websocket;
import static org.hamcrest.Matchers.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
@ -47,9 +49,6 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
public class WebSocketClientTest
{
private WebSocketClientFactory _factory = new WebSocketClientFactory();
@ -103,6 +102,7 @@ public class WebSocketClientTest
{
}
};
client.open(new URI("ws://127.0.0.1:" + _serverPort + "/"), websocket);
Socket socket = _server.accept();

View File

@ -72,6 +72,7 @@ public class WebSocketLoadD08Test
return new EchoWebSocket();
}
};
wsHandler.getWebSocketFactory().setMinVersion(8);
wsHandler.setHandler(new DefaultHandler());
_server.setHandler(wsHandler);
@ -196,7 +197,7 @@ public class WebSocketLoadD08Test
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"+
"Sec-WebSocket-Origin: http://example.com\r\n"+
"Sec-WebSocket-Protocol: onConnect\r\n" +
"Sec-WebSocket-Version: 7\r\n"+
"Sec-WebSocket-Version: 8\r\n"+
"\r\n");
output.flush();

View File

@ -194,7 +194,7 @@ public class WebSocketLoadRFC6455Test
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"+
"Sec-WebSocket-Origin: http://example.com\r\n"+
"Sec-WebSocket-Protocol: onConnect\r\n" +
"Sec-WebSocket-Version: 7\r\n"+
"Sec-WebSocket-Version: 13\r\n"+
"\r\n");
output.flush();

View File

@ -80,6 +80,7 @@ public class WebSocketMessageD00Test
return __serverWebSocket;
}
};
wsHandler.getWebSocketFactory().setMinVersion(-1);
wsHandler.setHandler(new DefaultHandler());
__server.setHandler(wsHandler);
__server.start();

View File

@ -66,6 +66,7 @@ public class WebSocketMessageD06Test
return _serverWebSocket;
}
};
wsHandler.getWebSocketFactory().setMinVersion(6);
wsHandler.getWebSocketFactory().setBufferSize(8192);
wsHandler.getWebSocketFactory().setMaxIdleTime(1000);
wsHandler.setHandler(new DefaultHandler());

View File

@ -77,6 +77,7 @@ public class WebSocketMessageD08Test
return __serverWebSocket;
}
};
wsHandler.getWebSocketFactory().setMinVersion(8);
wsHandler.getWebSocketFactory().setBufferSize(8192);
wsHandler.getWebSocketFactory().setMaxIdleTime(1000);
wsHandler.setHandler(new DefaultHandler());

View File

@ -1337,7 +1337,7 @@ public class WebSocketMessageRFC6455Test
output.flush();
// Make sure the read times out if there are problems with the implementation
socket.setSoTimeout(1000);
socket.setSoTimeout(10000);
InputStream input = socket.getInputStream();
@ -1347,7 +1347,7 @@ public class WebSocketMessageRFC6455Test
skipTo("\r\n\r\n",input);
assertTrue(__serverWebSocket.awaitConnected(1000));
assertTrue(__serverWebSocket.awaitConnected(10000));
assertNotNull(__serverWebSocket.connection);
assertEquals(0x81,input.read());
@ -1355,7 +1355,7 @@ public class WebSocketMessageRFC6455Test
lookFor("sent on connect",input);
socket.close();
assertTrue(__serverWebSocket.awaitDisconnected(500));
assertTrue(__serverWebSocket.awaitDisconnected(10000));
try
{

View File

@ -80,6 +80,8 @@ public class WebSocketServletRFCTest
try
{
conn.sendMessage(data);
conn.close(1000, data);
}
catch (IOException e)
{
@ -178,7 +180,7 @@ public class WebSocketServletRFCTest
// System.out.println("RESPONSE: " + respHeader);
Assert.assertThat("Response Code",respHeader,startsWith("HTTP/1.1 400 Unsupported websocket version specification"));
Assert.assertThat("Response Header Versions",respHeader,containsString("Sec-WebSocket-Version: 13, 8, 6, 0\r\n"));
Assert.assertThat("Response Header Versions",respHeader,containsString("Sec-WebSocket-Version: 13\r\n"));
}
finally
{
@ -240,4 +242,44 @@ public class WebSocketServletRFCTest
sender.close();
}
}
/**
* Test the requirement of responding with server terminated close code 1011 when there is an unhandled (internal
* server error) being produced by the extended WebSocketServlet.
*/
@Test
public void testResponseOfHttpKeyword() throws Exception
{
WebSocketClientFactory clientFactory = new WebSocketClientFactory();
clientFactory.start();
WebSocketClient wsc = clientFactory.newWebSocketClient();
MessageSender sender = new MessageSender();
wsc.open(serverUri,sender);
String message = "GET";
try
{
sender.awaitConnect();
// echo back a http keyword
sender.sendMessage(message);
// Give servlet 500 millisecond to process messages
TimeUnit.MILLISECONDS.sleep(500);
sender.awaitMessage();
Assert.assertEquals("Message should match",message, sender.getMessage());
Assert.assertThat("WebSocket should be closed",sender.isConnected(),is(false));
Assert.assertThat("WebSocket close clode",sender.getCloseCode(),is(1000));
Assert.assertEquals("WebSocket close message",message, sender.getCloseMessage());
}
finally
{
sender.close();
}
}
}

View File

@ -0,0 +1,308 @@
//
// ========================================================================
// 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.websocket.dummy;
import static org.hamcrest.Matchers.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.WebSocketConnectionRFC6455;
import org.junit.Assert;
/**
* Simple ServerSocket server used to test oddball server scenarios encountered in the real world.
*/
public class DummyServer
{
public static class ServerConnection
{
private static final Logger LOG = Log.getLogger(ServerConnection.class);
private final Socket socket;
private InputStream in;
private OutputStream out;
public ServerConnection(Socket socket)
{
this.socket = socket;
}
public int read(ByteBuffer buf) throws IOException
{
int len = 0;
while ((in.available() > 0) && (buf.remaining() > 0))
{
buf.put((byte)in.read());
len++;
}
return len;
}
public void disconnect()
{
LOG.debug("disconnect");
IO.close(in);
IO.close(out);
if (socket != null)
{
try
{
socket.close();
}
catch (IOException ignore)
{
/* ignore */
}
}
}
public InputStream getInputStream() throws IOException
{
if (in == null)
{
in = socket.getInputStream();
}
return in;
}
public OutputStream getOutputStream() throws IOException
{
if (out == null)
{
out = socket.getOutputStream();
}
return out;
}
public void flush() throws IOException
{
LOG.debug("flush()");
getOutputStream().flush();
}
public String readRequest() throws IOException
{
LOG.debug("Reading client request");
StringBuilder request = new StringBuilder();
BufferedReader in = new BufferedReader(new InputStreamReader(getInputStream()));
for (String line = in.readLine(); line != null; line = in.readLine())
{
if (line.length() == 0)
{
break;
}
request.append(line).append("\r\n");
LOG.debug("read line: {}",line);
}
LOG.debug("Client Request:{}{}","\n",request);
return request.toString();
}
public void respond(String rawstr) throws IOException
{
LOG.debug("respond(){}{}","\n",rawstr);
getOutputStream().write(rawstr.getBytes());
flush();
}
public void setSoTimeout(int ms) throws SocketException
{
socket.setSoTimeout(ms);
}
public void upgrade(Map<String, String> extraResponseHeaders) throws IOException
{
@SuppressWarnings("unused")
Pattern patExts = Pattern.compile("^Sec-WebSocket-Extensions: (.*)$",Pattern.CASE_INSENSITIVE);
Pattern patKey = Pattern.compile("^Sec-WebSocket-Key: (.*)$",Pattern.CASE_INSENSITIVE);
LOG.debug("(Upgrade) Reading HTTP Request");
Matcher mat;
String key = "not sent";
BufferedReader in = new BufferedReader(new InputStreamReader(getInputStream()));
for (String line = in.readLine(); line != null; line = in.readLine())
{
if (line.length() == 0)
{
break;
}
// TODO: Check for extensions
// mat = patExts.matcher(line);
// if (mat.matches())
// Check for Key
mat = patKey.matcher(line);
if (mat.matches())
{
key = mat.group(1);
}
}
LOG.debug("(Upgrade) Writing HTTP Response");
// TODO: handle extensions?
// Setup Response
StringBuilder resp = new StringBuilder();
resp.append("HTTP/1.1 101 Upgrade\r\n");
resp.append("Upgrade: websocket\r\n");
resp.append("Connection: upgrade\r\n");
resp.append("Sec-WebSocket-Accept: ");
resp.append(WebSocketConnectionRFC6455.hashKey(key)).append("\r\n");
// extra response headers.
if (extraResponseHeaders != null)
{
for (Map.Entry<String,String> header : extraResponseHeaders.entrySet())
{
resp.append(header.getKey());
resp.append(": ");
resp.append(header.getValue());
resp.append("\r\n");
}
}
resp.append("\r\n");
// Write Response
getOutputStream().write(resp.toString().getBytes());
flush();
}
public void write(byte[] bytes) throws IOException
{
LOG.debug("Writing {} bytes", bytes.length);
getOutputStream().write(bytes);
}
public void write(byte[] buf, int offset, int length) throws IOException
{
LOG.debug("Writing bytes[{}], offset={}, length={}", buf.length, offset, length);
getOutputStream().write(buf,offset,length);
}
public void write(int b) throws IOException
{
LOG.debug("Writing int={}", b);
getOutputStream().write(b);
}
}
private static final Logger LOG = Log.getLogger(DummyServer.class);
private ServerSocket serverSocket;
private URI wsUri;
public ServerConnection accept() throws IOException
{
LOG.debug(".accept()");
assertIsStarted();
Socket socket = serverSocket.accept();
return new ServerConnection(socket);
}
private void assertIsStarted()
{
Assert.assertThat("ServerSocket",serverSocket,notNullValue());
Assert.assertThat("ServerSocket.isBound",serverSocket.isBound(),is(true));
Assert.assertThat("ServerSocket.isClosed",serverSocket.isClosed(),is(false));
Assert.assertThat("WsUri",wsUri,notNullValue());
}
public URI getWsUri()
{
return wsUri;
}
public void respondToClient(Socket connection, String serverResponse) throws IOException
{
InputStream in = null;
InputStreamReader isr = null;
BufferedReader buf = null;
OutputStream out = null;
try
{
in = connection.getInputStream();
isr = new InputStreamReader(in);
buf = new BufferedReader(isr);
String line;
while ((line = buf.readLine()) != null)
{
// System.err.println(line);
if (line.length() == 0)
{
// Got the "\r\n" line.
break;
}
}
// System.out.println("[Server-Out] " + serverResponse);
out = connection.getOutputStream();
out.write(serverResponse.getBytes());
out.flush();
}
finally
{
IO.close(buf);
IO.close(isr);
IO.close(in);
IO.close(out);
}
}
public void start() throws IOException
{
serverSocket = new ServerSocket();
InetAddress addr = InetAddress.getByName("localhost");
InetSocketAddress endpoint = new InetSocketAddress(addr,0);
serverSocket.bind(endpoint);
int port = serverSocket.getLocalPort();
String uri = String.format("ws://%s:%d/",addr.getHostAddress(),port);
wsUri = URI.create(uri);
LOG.debug("Server Started on {} -> {}",endpoint,wsUri);
}
public void stop()
{
LOG.debug("Stopping Server");
try
{
serverSocket.close();
}
catch (IOException ignore)
{
/* ignore */
}
}
}

View File

@ -24,13 +24,17 @@ import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.websocket.WebSocket;
public class MessageSender implements WebSocket
public class MessageSender implements WebSocket, WebSocket.OnTextMessage
{
private Connection conn;
private CountDownLatch connectLatch = new CountDownLatch(1);
private CountDownLatch messageLatch = new CountDownLatch(1);
private int closeCode = -1;
private String closeMessage = null;
private String message = null;
public void onOpen(Connection connection)
{
this.conn = connection;
@ -43,6 +47,12 @@ public class MessageSender implements WebSocket
this.closeCode = closeCode;
this.closeMessage = message;
}
public void onMessage(String data)
{
message = data;
}
public boolean isConnected()
{
@ -62,6 +72,11 @@ public class MessageSender implements WebSocket
{
return closeMessage;
}
public String getMessage()
{
return message;
}
public void sendMessage(String format, Object... args) throws IOException
{
@ -72,6 +87,11 @@ public class MessageSender implements WebSocket
{
connectLatch.await(1,TimeUnit.SECONDS);
}
public void awaitMessage() throws InterruptedException
{
messageLatch.await(1,TimeUnit.SECONDS);
}
public void close()
{

View File

@ -0,0 +1,4 @@
# Setup default logging implementation for during testing
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
org.eclipse.jetty.LEVEL=INFO
org.eclipse.jetty.websocket.LEVEL=DEBUG

View File

@ -39,6 +39,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.Queue;
@ -424,7 +425,7 @@ public class XmlConfiguration
private void set(Object obj, XmlParser.Node node) throws Exception
{
String attr = node.getAttribute("name");
String name = "set" + attr.substring(0,1).toUpperCase() + attr.substring(1);
String name = "set" + attr.substring(0,1).toUpperCase(Locale.ENGLISH) + attr.substring(1);
Object value = value(obj,node);
Object[] arg =
{ value };
@ -663,7 +664,7 @@ public class XmlConfiguration
try
{
// try calling a getXxx method.
Method method = oClass.getMethod("get" + name.substring(0,1).toUpperCase() + name.substring(1),(java.lang.Class[])null);
Method method = oClass.getMethod("get" + name.substring(0,1).toUpperCase(Locale.ENGLISH) + name.substring(1),(java.lang.Class[])null);
obj = method.invoke(obj,(java.lang.Object[])null);
configure(obj,node,0);
}
@ -1232,7 +1233,7 @@ public class XmlConfiguration
Object[] obj = new Object[args.length];
for (int i = 0; i < args.length; i++)
{
if (args[i].toLowerCase().endsWith(".properties"))
if (args[i].toLowerCase(Locale.ENGLISH).endsWith(".properties"))
{
properties.load(Resource.newResource(args[i]).getInputStream());
}

View File

@ -127,7 +127,7 @@ public class Dump extends HttpServlet
final boolean flush= request.getParameter("flush")!=null?Boolean.parseBoolean(request.getParameter("flush")):false;
if(request.getPathInfo()!=null && request.getPathInfo().toLowerCase().indexOf("script")!=-1)
if(request.getPathInfo()!=null && request.getPathInfo().toLowerCase(Locale.ENGLISH).indexOf("script")!=-1)
{
response.sendRedirect(response.encodeRedirectURL(getServletContext().getContextPath() + "/dump/info"));
return;

View File

@ -0,0 +1,54 @@
//
// ========================================================================
// 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.server.session;
import org.junit.Test;
/**
* SessionExpiryTest
*
*
*
*/
public class SessionExpiryTest extends AbstractSessionExpiryTest
{
/**
* @see org.eclipse.jetty.server.session.AbstractSessionExpiryTest#createServer(int, int, int)
*/
@Override
public AbstractTestServer createServer(int port, int max, int scavenge)
{
return new JdbcTestServer(port,max,scavenge);
}
@Test
public void testSessionExpiry() throws Exception
{
super.testSessionExpiry();
}
@Test
public void testSessionNotExpired() throws Exception
{
super.testSessionNotExpired();
}
}

View File

@ -0,0 +1,190 @@
//
// ========================================================================
// 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.nosql.mongodb;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotNull;
import java.io.IOException;
import java.net.UnknownHostException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.http.HttpMethods;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.junit.Test;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
/**
* PurgeInvalidSessionTest
*
*
*
*/
public class PurgeInvalidSessionTest
{
public MongoTestServer createServer(int port, int max, int scavenge)
{
MongoTestServer server = new MongoTestServer(port,max,scavenge);
return server;
}
@Test
public void testPurgeInvalidSession() throws Exception
{
String contextPath = "";
String servletMapping = "/server";
long purgeDelay = 1000; //1 sec
long purgeInvalidAge = 1000; //1 sec
long purgeValidAge = 1000;
//ensure scavenging is turned off so the purger gets a chance to find the session
MongoTestServer server = createServer(0, 1, 0);
ServletContextHandler context = server.addContext(contextPath);
context.addServlet(TestServlet.class, servletMapping);
MongoSessionManager sessionManager = (MongoSessionManager)context.getSessionHandler().getSessionManager();
MongoSessionIdManager idManager = (MongoSessionIdManager)server.getServer().getSessionIdManager();
idManager.setPurge(true);
idManager.setPurgeDelay(purgeDelay);
idManager.setPurgeInvalidAge(purgeInvalidAge); //purge invalid sessions older than
idManager.setPurgeValidAge(purgeValidAge); //purge valid sessions older than
server.start();
int port=server.getPort();
try
{
HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SOCKET);
client.start();
try
{
//Create a session
ContentExchange exchange = new ContentExchange(true);
exchange.setMethod(HttpMethods.GET);
exchange.setURL("http://localhost:" + port + contextPath + servletMapping + "?action=create");
client.send(exchange);
exchange.waitForDone();
assertEquals(HttpServletResponse.SC_OK,exchange.getResponseStatus());
String sessionCookie = exchange.getResponseFields().getStringField("Set-Cookie");
assertTrue(sessionCookie != null);
// Mangle the cookie, replacing Path with $Path, etc.
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
//make a request to invalidate the session
exchange = new ContentExchange(true);
exchange.setMethod(HttpMethods.GET);
exchange.setURL("http://localhost:" + port + contextPath + servletMapping + "?action=invalidate");
exchange.getRequestFields().add("Cookie", sessionCookie);
client.send(exchange);
exchange.waitForDone();
assertEquals(HttpServletResponse.SC_OK,exchange.getResponseStatus());
Thread.currentThread().sleep(3*purgeDelay); //sleep long enough for purger to have run
//make a request using previous session to test if its still there
exchange = new ContentExchange(true);
exchange.setMethod(HttpMethods.GET);
exchange.setURL("http://localhost:" + port + contextPath + servletMapping + "?action=test");
exchange.getRequestFields().add("Cookie", sessionCookie);
client.send(exchange);
exchange.waitForDone();
assertEquals(HttpServletResponse.SC_OK,exchange.getResponseStatus());
}
finally
{
client.stop();
}
}
finally
{
server.stop();
}
}
public static class TestServlet extends HttpServlet
{
DBCollection _sessions;
public TestServlet() throws UnknownHostException, MongoException
{
super();
_sessions = new Mongo().getDB("HttpSessions").getCollection("sessions");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String action = request.getParameter("action");
if ("create".equals(action))
{
HttpSession session = request.getSession(true);
assertTrue(session.isNew());
}
else if ("invalidate".equals(action))
{
HttpSession existingSession = request.getSession(false);
assertNotNull(existingSession);
existingSession.invalidate();
String id = request.getRequestedSessionId();
assertNotNull(id);
id = id.substring(0, id.indexOf("."));
//still in db, just marked as invalid
DBObject dbSession = _sessions.findOne(new BasicDBObject("id", id));
assertTrue(dbSession != null);
}
else if ("test".equals(action))
{
String id = request.getRequestedSessionId();
assertNotNull(id);
id = id.substring(0, id.indexOf("."));
HttpSession existingSession = request.getSession(false);
assertTrue(existingSession == null);
//not in db any more
DBObject dbSession = _sessions.findOne(new BasicDBObject("id", id));
assertTrue(dbSession == null);
}
}
}
}

View File

@ -0,0 +1,171 @@
//
// ========================================================================
// 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.nosql.mongodb;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotNull;
import java.io.IOException;
import java.net.UnknownHostException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.http.HttpMethods;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.junit.Test;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
/**
* PurgeValidSessionTest
*
*
*
*/
public class PurgeValidSessionTest
{
public MongoTestServer createServer(int port, int max, int scavenge)
{
MongoTestServer server = new MongoTestServer(port,max,scavenge);
return server;
}
@Test
public void testPurgeValidSession() throws Exception
{
String contextPath = "";
String servletMapping = "/server";
long purgeDelay = 1000; //1 sec
long purgeValidAge = 1000;
//ensure scavenging is turned off so the purger gets a chance to find the session
MongoTestServer server = createServer(0, 1, 0);
ServletContextHandler context = server.addContext(contextPath);
context.addServlet(TestServlet.class, servletMapping);
MongoSessionManager sessionManager = (MongoSessionManager)context.getSessionHandler().getSessionManager();
MongoSessionIdManager idManager = (MongoSessionIdManager)server.getServer().getSessionIdManager();
idManager.setPurge(true);
idManager.setPurgeDelay(purgeDelay);
idManager.setPurgeValidAge(purgeValidAge); //purge valid sessions older than
server.start();
int port=server.getPort();
try
{
HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SOCKET);
client.start();
try
{
//Create a session
ContentExchange exchange = new ContentExchange(true);
exchange.setMethod(HttpMethods.GET);
exchange.setURL("http://localhost:" + port + contextPath + servletMapping + "?action=create");
client.send(exchange);
exchange.waitForDone();
assertEquals(HttpServletResponse.SC_OK,exchange.getResponseStatus());
String sessionCookie = exchange.getResponseFields().getStringField("Set-Cookie");
assertTrue(sessionCookie != null);
// Mangle the cookie, replacing Path with $Path, etc.
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
Thread.currentThread().sleep(3*purgeDelay); //sleep long enough for purger to have run
//make a request using previous session to test if its still there
exchange = new ContentExchange(true);
exchange.setMethod(HttpMethods.GET);
exchange.setURL("http://localhost:" + port + contextPath + servletMapping + "?action=test");
exchange.getRequestFields().add("Cookie", sessionCookie);
client.send(exchange);
exchange.waitForDone();
assertEquals(HttpServletResponse.SC_OK,exchange.getResponseStatus());
}
finally
{
client.stop();
}
}
finally
{
server.stop();
}
}
public static class TestServlet extends HttpServlet
{
DBCollection _sessions;
public TestServlet() throws UnknownHostException, MongoException
{
super();
_sessions = new Mongo().getDB("HttpSessions").getCollection("sessions");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String action = request.getParameter("action");
if ("create".equals(action))
{
HttpSession session = request.getSession(true);
assertTrue(session.isNew());
}
else if ("test".equals(action))
{
String id = request.getRequestedSessionId();
assertNotNull(id);
id = id.substring(0, id.indexOf("."));
HttpSession existingSession = request.getSession(false);
assertTrue(existingSession == null);
//not in db any more
DBObject dbSession = _sessions.findOne(new BasicDBObject("id", id));
assertTrue(dbSession == null);
}
}
}
}

View File

@ -27,10 +27,14 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.http.HttpMethods;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@ -51,7 +55,12 @@ public abstract class AbstractLastAccessTimeTest
int maxInactivePeriod = 8;
int scavengePeriod = 2;
AbstractTestServer server1 = createServer(0, maxInactivePeriod, scavengePeriod);
server1.addContext(contextPath).addServlet(TestServlet.class, servletMapping);
TestServlet servlet1 = new TestServlet();
ServletHolder holder1 = new ServletHolder(servlet1);
ServletContextHandler context = server1.addContext(contextPath);
TestSessionListener listener1 = new TestSessionListener();
context.addEventListener(listener1);
context.addServlet(holder1, servletMapping);
server1.start();
int port1=server1.getPort();
try
@ -108,17 +117,9 @@ public abstract class AbstractLastAccessTimeTest
// Let's wait for the scavenger to run, waiting 2.5 times the scavenger period
Thread.sleep(scavengePeriod * 2500L);
// Access again server1, and ensure that we can still access the session
exchange1 = new ContentExchange(true);
exchange1.setMethod(HttpMethods.GET);
exchange1.setURL("http://localhost:" + port1 + contextPath + servletMapping);
exchange1.getRequestFields().add("Cookie", sessionCookie);
client.send(exchange1);
exchange1.waitForDone();
assertEquals(HttpServletResponse.SC_OK, exchange1.getResponseStatus());
//test that the session was kept alive by server 2 and still contains what server1 put in it
assertEquals("test", exchange1.getResponseContent());
//check that the session was not scavenged over on server1 by ensuring that the SessionListener destroy method wasn't called
assertTrue (listener1.destroyed == false);
}
finally
{
@ -136,6 +137,25 @@ public abstract class AbstractLastAccessTimeTest
}
}
public static class TestSessionListener implements HttpSessionListener
{
public boolean destroyed = false;
public boolean created = false;
public void sessionDestroyed(HttpSessionEvent se)
{
destroyed = true;
}
public void sessionCreated(HttpSessionEvent se)
{
created = true;
}
}
public static class TestServlet extends HttpServlet
{
@Override

View File

@ -0,0 +1,211 @@
//
// ========================================================================
// 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.server.session;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.http.HttpMethods;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.SessionManager;
import org.eclipse.jetty.server.session.AbstractTestServer;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* AbstractSessionExpiryTest
*
*
*
*/
public abstract class AbstractSessionExpiryTest
{
public abstract AbstractTestServer createServer(int port, int max, int scavenge);
public void pause(int scavengePeriod)
{
try
{
Thread.sleep(scavengePeriod * 2500L);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
@Test
public void testSessionNotExpired() throws Exception
{
String contextPath = "";
String servletMapping = "/server";
int inactivePeriod = 10;
int scavengePeriod = 10;
AbstractTestServer server1 = createServer(0, inactivePeriod, scavengePeriod);
TestServlet servlet = new TestServlet();
ServletHolder holder = new ServletHolder(servlet);
server1.addContext(contextPath).addServlet(holder, servletMapping);
server1.start();
int port1 = server1.getPort();
try
{
HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SOCKET);
client.start();
String url = "http://localhost:" + port1 + contextPath + servletMapping;
//make a request to set up a session on the server
ContentExchange exchange1 = new ContentExchange(true);
exchange1.setMethod(HttpMethods.GET);
exchange1.setURL(url + "?action=init");
client.send(exchange1);
exchange1.waitForDone();
assertEquals(HttpServletResponse.SC_OK,exchange1.getResponseStatus());
String sessionCookie = exchange1.getResponseFields().getStringField("Set-Cookie");
assertTrue(sessionCookie != null);
// Mangle the cookie, replacing Path with $Path, etc.
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
//now stop the server
server1.stop();
//start the server again, before the session times out
server1.start();
port1 = server1.getPort();
url = "http://localhost:" + port1 + contextPath + servletMapping;
//make another request, the session should not have expired
ContentExchange exchange2 = new ContentExchange(true);
exchange2.setMethod(HttpMethods.GET);
exchange2.setURL(url + "?action=notexpired");
exchange2.getRequestFields().add("Cookie", sessionCookie);
client.send(exchange2);
exchange2.waitForDone();
assertEquals(HttpServletResponse.SC_OK,exchange2.getResponseStatus());
}
finally
{
server1.stop();
}
}
@Test
public void testSessionExpiry() throws Exception
{
String contextPath = "";
String servletMapping = "/server";
int inactivePeriod = 2;
int scavengePeriod = 10;
AbstractTestServer server1 = createServer(0, inactivePeriod, scavengePeriod);
TestServlet servlet = new TestServlet();
ServletHolder holder = new ServletHolder(servlet);
server1.addContext(contextPath).addServlet(holder, servletMapping);
server1.start();
int port1 = server1.getPort();
try
{
HttpClient client = new HttpClient();
client.setConnectorType(HttpClient.CONNECTOR_SOCKET);
client.start();
String url = "http://localhost:" + port1 + contextPath + servletMapping;
//make a request to set up a session on the server
ContentExchange exchange1 = new ContentExchange(true);
exchange1.setMethod(HttpMethods.GET);
exchange1.setURL(url + "?action=init");
client.send(exchange1);
exchange1.waitForDone();
assertEquals(HttpServletResponse.SC_OK,exchange1.getResponseStatus());
String sessionCookie = exchange1.getResponseFields().getStringField("Set-Cookie");
assertTrue(sessionCookie != null);
// Mangle the cookie, replacing Path with $Path, etc.
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
//now stop the server
server1.stop();
//and wait until the expiry time has passed
pause(inactivePeriod);
//restart the server
server1.start();
port1 = server1.getPort();
url = "http://localhost:" + port1 + contextPath + servletMapping;
//make another request, the session should have expired
ContentExchange exchange2 = new ContentExchange(true);
exchange2.setMethod(HttpMethods.GET);
exchange2.setURL(url + "?action=test");
exchange2.getRequestFields().add("Cookie", sessionCookie);
client.send(exchange2);
exchange2.waitForDone();
assertEquals(HttpServletResponse.SC_OK,exchange2.getResponseStatus());
}
finally
{
server1.stop();
}
}
public static class TestServlet extends HttpServlet
{
public String originalId = null;
public String testId = null;
public String checkId = null;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException
{
String action = request.getParameter("action");
if ("init".equals(action))
{
HttpSession session = request.getSession(true);
session.setAttribute("test", "test");
originalId = session.getId();
}
else if ("test".equals(action))
{
HttpSession session = request.getSession(true);
assertTrue(session != null);
assertTrue(!originalId.equals(session.getId()));
}
else if ("notexpired".equals(action))
{
HttpSession session = request.getSession(false);
assertTrue(session != null);
assertTrue(originalId.equals(session.getId()));
}
}
}
}