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

This commit is contained in:
Greg Wilkins 2019-04-29 13:21:59 +02:00
commit f28bfa9377
8 changed files with 137 additions and 36 deletions

View File

@ -1,5 +1,10 @@
jetty-10.0.0-SNAPSHOT
jetty-9.4.17.v20190418 - 18 April 2019
+ 3464 Split SslContextFactory into Client and Server
+ 3549 Directory Listing on Windows reveals Resource Base path
+ 3555 DefaultHandler Reveals Base Resource Path of each Context
jetty-9.4.16.v20190411 - 11 April 2019
+ 1861 Limit total bytes pooled by ByteBufferPools
+ 3133 Logging of `key.readyOps()` can throw unchecked `CancelledKeyException`

View File

@ -162,6 +162,10 @@ You can do so directly to the API via a context XML file such as the following:
If none of the alternatives already described meet your needs, you can always provide a custom classloader for your webapp.
We recommend, but do not require, that your custom loader subclasses link:{JDURL}/org/eclipse/jetty/webapp/WebAppClassLoader.html[WebAppClassLoader].
If you do not subclass WebAppClassLoader, we recommend that you implement the link:{JDURL}/org/eclipse/jetty/util/ClassVisibilityChecker.html[ClassVisibilityChecker] interface.
Without this interface, session persistence will be slower.
You configure the classloader for the webapp like so:
[source, java, subs="{sub-order}"]

View File

@ -22,6 +22,7 @@
<artifactId>hazelcast</artifactId>
<version>${hazelcast.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>

View File

@ -28,6 +28,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
import org.eclipse.jetty.util.ClassVisibilityChecker;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -78,22 +79,47 @@ public class SessionData implements Serializable
out.writeObject(entries);
for (Entry<String,Object> entry: data._attributes.entrySet())
{
out.writeUTF(entry.getKey());
ClassLoader loader = entry.getValue().getClass().getClassLoader();
boolean isServerLoader = false;
if (loader == Thread.currentThread().getContextClassLoader()) //is it the webapp classloader?
isServerLoader = false;
else if (loader == Thread.currentThread().getContextClassLoader().getParent() || loader == SessionData.class.getClassLoader() || loader == null) // is it the container loader?
isServerLoader = true;
else
throw new IOException ("Unknown loader"); // we don't know what loader to use
out.writeUTF(entry.getKey());
out.writeBoolean(isServerLoader);
Class<?> clazz = entry.getValue().getClass();
ClassLoader loader = clazz.getClassLoader();
ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
boolean isContextLoader;
if (loader == contextLoader) //is it the context classloader?
isContextLoader = true;
else if (contextLoader == null) //not context classloader
isContextLoader = false;
else if (contextLoader instanceof ClassVisibilityChecker)
{
//Clazz not loaded by context classloader, but ask if loadable by context classloader,
//because preferable to use context classloader if possible (eg for deep structures).
ClassVisibilityChecker checker = (ClassVisibilityChecker)(contextLoader);
isContextLoader = (checker.isSystemClass(clazz) && !(checker.isServerClass(clazz)));
}
else
{
//Class wasn't loaded by context classloader, but try loading from context loader,
//because preferable to use context classloader if possible (eg for deep structures).
try
{
Class<?> result = contextLoader.loadClass(clazz.getName());
isContextLoader = (result == clazz); //only if TTCL loaded this instance of the class
}
catch (Throwable e)
{
isContextLoader = false; //TCCL can't see the class
}
}
if (LOG.isDebugEnabled())
LOG.debug("Attribute {} class={} isServerLoader={}", entry.getKey(),clazz.getName(),(!isContextLoader));
out.writeBoolean(!isContextLoader);
out.writeObject(entry.getValue());
}
}
/**
* De-serialize the attribute map of a session.
*
@ -118,12 +144,15 @@ public class SessionData implements Serializable
data._attributes = new ConcurrentHashMap<>();
int entries = ((Integer)o).intValue();
ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
ClassLoader serverLoader = SessionData.class.getClassLoader();
for (int i=0; i < entries; i++)
{
String name = in.readUTF(); //attribute name
boolean isServerClassLoader = in.readBoolean(); //use server or webapp classloader to load
Object value = ((ClassLoadingObjectInputStream)in).readObject(isServerClassLoader?SessionData.class.getClassLoader():Thread.currentThread().getContextClassLoader());
if (LOG.isDebugEnabled())
LOG.debug("Deserialize {} isServerLoader={} serverLoader={} tccl={}", name, isServerClassLoader,serverLoader, contextLoader);
Object value = ((ClassLoadingObjectInputStream)in).readObject(isServerClassLoader?serverLoader:contextLoader);
data._attributes.put(name, value);
}
}

View File

@ -0,0 +1,51 @@
//
// ========================================================================
// Copyright (c) 1995-2019 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.util;
/**
* ClassVisibilityChecker
*
* Interface to be implemented by classes capable of checking class visibility
* for a context.
*
*/
public interface ClassVisibilityChecker
{
/* ------------------------------------------------------------ */
/** Is the class a System Class.
* A System class is a class that is visible to a webapplication,
* but that cannot be overridden by the contents of WEB-INF/lib or
* WEB-INF/classes
* @param clazz The fully qualified name of the class.
* @return True if the class is a system class.
*/
boolean isSystemClass(Class<?> clazz);
/* ------------------------------------------------------------ */
/** Is the class a Server Class.
* A Server class is a class that is part of the implementation of
* the server and is NIT visible to a webapplication. The web
* application may provide it's own implementation of the class,
* to be loaded from WEB-INF/lib or WEB-INF/classes
* @param clazz The fully qualified name of the class.
* @return True if the class is a server class.
*/
boolean isServerClass(Class<?> clazz);
}

View File

@ -39,6 +39,7 @@ import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.jetty.util.ClassVisibilityChecker;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
@ -65,7 +66,7 @@ import org.eclipse.jetty.util.resource.ResourceCollection;
* context classloader will be used. If that is null then the
* classloader that loaded this class is used as the parent.
*/
public class WebAppClassLoader extends URLClassLoader
public class WebAppClassLoader extends URLClassLoader implements ClassVisibilityChecker
{
static
{
@ -85,7 +86,7 @@ public class WebAppClassLoader extends URLClassLoader
/* ------------------------------------------------------------ */
/** The Context in which the classloader operates.
*/
public interface Context
public interface Context extends ClassVisibilityChecker
{
/* ------------------------------------------------------------ */
/** Convert a URL or path to a Resource.
@ -103,26 +104,6 @@ public class WebAppClassLoader extends URLClassLoader
*/
PermissionCollection getPermissions();
/* ------------------------------------------------------------ */
/** Is the class a System Class.
* A System class is a class that is visible to a webapplication,
* but that cannot be overridden by the contents of WEB-INF/lib or
* WEB-INF/classes
* @param clazz The fully qualified name of the class.
* @return True if the class is a system class.
*/
boolean isSystemClass(Class<?> clazz);
/* ------------------------------------------------------------ */
/** Is the class a Server Class.
* A Server class is a class that is part of the implementation of
* the server and is NIT visible to a webapplication. The web
* application may provide it's own implementation of the class,
* to be loaded from WEB-INF/lib or WEB-INF/classes
* @param clazz The fully qualified name of the class.
* @return True if the class is a server class.
*/
boolean isServerClass(Class<?> clazz);
/* ------------------------------------------------------------ */
/**
@ -722,5 +703,17 @@ public class WebAppClassLoader extends URLClassLoader
{
return "WebAppClassLoader=" + _name+"@"+Long.toHexString(hashCode());
}
@Override
public boolean isSystemClass(Class<?> clazz)
{
return _context.isSystemClass(clazz);
}
@Override
public boolean isServerClass(Class<?> clazz)
{
return _context.isServerClass(clazz);
}
}

View File

@ -518,6 +518,8 @@
</dependency>
</dependencies>
<configuration>
<source>11</source>
<target>11</target>
<charset>UTF-8</charset>
<docencoding>UTF-8</docencoding>
<encoding>UTF-8</encoding>

View File

@ -31,10 +31,12 @@ import static org.junit.jupiter.api.Assertions.fail;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@ -238,6 +240,11 @@ public abstract class AbstractSessionDataStoreTest
File factoryClass = new File (proxyabledir, "ProxyableFactory.class");
IO.copy(is, new FileOutputStream(factoryClass));
is.close();
is = Thread.currentThread().getContextClassLoader().getResourceAsStream("Foo.clazz");
File fooClass = new File (proxyabledir, "Foo.class");
IO.copy(is, new FileOutputStream(fooClass));
is.close();
URL[] proxyabledirUrls = new URL[]{proxyabledir.toURI().toURL()};
_contextClassLoader = new URLClassLoader(proxyabledirUrls, Thread.currentThread().getContextClassLoader());
@ -272,6 +279,15 @@ public abstract class AbstractSessionDataStoreTest
//Make an attribute that uses the proxy only known to the webapp classloader
data.setAttribute("a", proxy);
//Now make an attribute that uses a system class to store a webapp classes
//see issue #3597
Class fooclazz = Class.forName("Foo", true, _contextClassLoader);
Constructor constructor = fooclazz.getConstructor(null);
Object foo = constructor.newInstance(null);
ArrayList list = new ArrayList();
list.add(foo);
data.setAttribute("foo", list);
}
finally
{