diff options
Diffstat (limited to 'libjava/java/net/URLClassLoader.java')
-rw-r--r-- | libjava/java/net/URLClassLoader.java | 226 |
1 files changed, 213 insertions, 13 deletions
diff --git a/libjava/java/net/URLClassLoader.java b/libjava/java/net/URLClassLoader.java index eeec8821316..5e059cf9cb6 100644 --- a/libjava/java/net/URLClassLoader.java +++ b/libjava/java/net/URLClassLoader.java @@ -1,4 +1,4 @@ -/* Copyright (C) 1999, 2000 Free Software Foundation +/* Copyright (C) 1999, 2000, 2002 Free Software Foundation This file is part of libgcj. @@ -12,8 +12,15 @@ import java.io.*; import java.util.jar.*; import java.util.Enumeration; import java.util.Vector; - -public class URLClassLoader extends ClassLoader +import java.security.CodeSource; +import java.security.SecureClassLoader; +import java.security.PermissionCollection; +import java.security.cert.Certificate; + +/** + * @since 1.2 + */ +public class URLClassLoader extends SecureClassLoader { // The URLStreamHandlerFactory URLStreamHandlerFactory factory = null; @@ -33,11 +40,23 @@ public class URLClassLoader extends ClassLoader return null; } + /** + * Createa a new URL class loader object + * + * @exception SecurityException If a security manager exists and its + * checkCreateClassLoader method doesn't allow creation of a class loader + */ public URLClassLoader (URL[] urls) { this (urls, null, null); } - + + /** + * Createa a new URL class loader object + * + * @exception SecurityException If a security manager exists and its + * checkCreateClassLoader method doesn't allow creation of a class loader + */ public URLClassLoader (URL[] urls, ClassLoader parent) { this (urls, parent, null); @@ -93,11 +112,21 @@ public class URLClassLoader extends ClassLoader info.addElement (conn); } + /** + * Createa a new URL class loader object + * + * @exception SecurityException If a security manager exists and its + * checkCreateClassLoader method doesn't allow creation of a class loader + */ public URLClassLoader (URL[] urls, ClassLoader parent, URLStreamHandlerFactory fac) { super (parent); + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkCreateClassLoader(); + factory = fac; if (urls == null || urls.length == 0) @@ -112,7 +141,7 @@ public class URLClassLoader extends ClassLoader for (int i = 0; i < urls.length; i++) { - // Convert a Jar File URL into a Jar URL is possible. + // Convert a Jar File URL into a Jar URL if possible. URL u = jarFileize(urls[i]); path.addElement (u); @@ -143,7 +172,13 @@ public class URLClassLoader extends ClassLoader path.copyInto (urls); return urls; } - + + /** + * Returns an Enumeration of URLs representing all of the resources on the + * URL search path having the specified name + * + * @exception IOException If an error occurs + */ public Enumeration findResources (String name) { Vector results = new Vector (); @@ -158,7 +193,8 @@ public class URLClassLoader extends ClassLoader if (conn != null) { if (conn.getJarFile().getJarEntry (name) != null) - results.addElement (new URL(u, name, getHandler0 (u.getProtocol()))); + results.addElement (new URL(u, name, + getHandler0 (u.getProtocol()))); } else { @@ -216,7 +252,12 @@ public class URLClassLoader extends ClassLoader return null; } - // and finally, we can implement our class loader functionality. + /** + * Finds and loads the class with the specified name from the + * URL search path + * + * @exception ClassNotFoundException If the class could not be found + */ protected Class findClass (String name) throws ClassNotFoundException { @@ -225,12 +266,12 @@ public class URLClassLoader extends ClassLoader try { - URL u = getResource (name.replace ('.', '/') + ".class"); + URL url = getResource (name.replace ('.', '/') + ".class"); - if (u == null) + if (url == null) throw new ClassNotFoundException (name); - URLConnection connection = u.openConnection (); + URLConnection connection = url.openConnection (); InputStream is = connection.getInputStream (); int len = connection.getContentLength (); @@ -247,12 +288,171 @@ public class URLClassLoader extends ClassLoader off += c; } - return defineClass (name, data, 0, len); + // Now construct the CodeSource (if loaded from a jar file) + CodeSource source = null; + if (url.getProtocol().equals("jar")) + { + Certificate[] certificates = + ((JarURLConnection) connection).getCertificates(); + String u = url.toExternalForm (); + u = u.substring (4); //skip "jar:" + int i = u.indexOf ('!'); + if (i >= 0) + u = u.substring (0, i); + url = new URL(u); + + source = new CodeSource(url, certificates); + } + else if (url.getProtocol().equals("file")) + { + try + { + String u = url.toExternalForm(); + // Skip "file:" and then get canonical directory name. + File f = new File(u.substring(5)); + f = f.getCanonicalFile(); + url = new URL("file", "", f.getParent()); + source = new CodeSource (url, null); + } + catch (IOException ignore) + { + } + } + + return defineClass (name, data, 0, len, source); } catch (java.io.IOException x) { throw new ClassNotFoundException(name); } } -} + /** + * Defines a Package based on the given name and the supplied manifest + * information. The manifest indicates the tile, version and + * vendor information of the specification and implementation and wheter the + * package is sealed. If the Manifest indicates that the package is sealed + * then the Package will be sealed with respect to the supplied URL. + * + * @exception IllegalArgumentException If this package name already exists + * in this class loader + * @param name The name of the package + * @param manifest The manifest describing the specification, + * implementation and sealing details of the package + * @param url the code source url to seal the package + * @return the defined Package + */ + protected Package definePackage(String name, Manifest manifest, URL url) + throws IllegalArgumentException + { + Attributes attr = manifest.getMainAttributes(); + String specTitle = + attr.getValue(Attributes.Name.SPECIFICATION_TITLE); + String specVersion = + attr.getValue(Attributes.Name.SPECIFICATION_VERSION); + String specVendor = + attr.getValue(Attributes.Name.SPECIFICATION_VENDOR); + String implTitle = + attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE); + String implVersion = + attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION); + String implVendor = + attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); + + // Look if the Manifest indicates that this package is sealed + // XXX - most likely not completely correct! + // Shouldn't we also check the sealed attribute of the complete jar? + // http://java.sun.com/products/jdk/1.3/docs/guide/extensions/spec.html#bundled + // But how do we get that jar manifest here? + String sealed = attr.getValue(Attributes.Name.SEALED); + if ("false".equals(sealed)) + { + // Make sure that the URL is null so the package is not + // sealed. + url = null; + } + + return definePackage(name, specTitle, specVersion, specVendor, + implTitle, implVersion, implVendor, url); + } + + /** + * Returns the permissions needed to access a particular code source. + * These permissions includes those returned by + * <CODE>SecureClassLoader.getPermissions</CODE> and the actual permissions + * to access the objects referenced by the URL of the code source. + * The extra permissions added depend on the protocol and file portion of + * the URL in the code source. If the URL has the "file" protocol ends with + * a / character then it must be a directory and a file Permission to read + * everthing in that directory and all subdirectories is added. If the URL + * had the "file" protocol and doesn't end with a / character then it must + * be a normal file and a file permission to read that file is added. If the + * URL has any other protocol then a socket permission to connect and accept + * connections from the host portion of the URL is added. + * @param source The codesource that needs the permissions to be accessed + * @return the collection of permissions needed to access the code resource + * @see SecureClassLoader.getPermissions() + */ + protected PermissionCollection getPermissions(CodeSource source) + { + // XXX - This implementation does exactly as the Javadoc describes. + // But maybe we should/could use URLConnection.getPermissions()? + + // First get the permissions that would normally be granted + PermissionCollection permissions = super.getPermissions(source); + + // Now add the any extra permissions depending on the URL location + URL url = source.getLocation(); + String protocol = url.getProtocol(); + if (protocol.equals("file")) + { + String file = url.getFile(); + // If the file end in / it must be an directory + if (file.endsWith("/")) + { + // Grant permission to read everything in that directory and + // all subdirectories + permissions.add(new FilePermission(file + "-", "read")); + } + else + { + // It is a 'normal' file + // Grant permission to access that file + permissions.add(new FilePermission(file, "read")); + } + } + else + { + // Grant permission to connect to and accept connections from host + String host = url.getHost(); + permissions.add(new SocketPermission(host, "connect,accept")); + } + + return permissions; + } + + /** + * Creates a new instance of a URLClassLoader that gets classes from the + * supplied URLs. This class loader will have as parent the standard + * system class loader. + * @param urls the initial URLs used to resolve classes and resources + */ + public static URLClassLoader newInstance(URL[] urls) throws + SecurityException + { + return new URLClassLoader(urls); + } + + /** + * Creates a new instance of a URLClassLoader that gets classes from the + * supplied URLs and with the supplied loader as parent class loader. + * @param urls the initial URLs used to resolve classes and resources + * @param parent the parent class loader + */ + public static URLClassLoader newInstance(URL[] urls, + ClassLoader parent) + throws SecurityException + { + return new URLClassLoader(urls, parent); + } +} |