873 lines · 29.6 KB · Java
RawDownload
/* * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.applet; import java.lang.NullPointerException;import java.net.URL;import java.net.URLClassLoader;import java.net.SocketPermission;import java.net.URLConnection;import java.net.MalformedURLException;import java.net.InetAddress;import java.net.UnknownHostException;import java.io.File;import java.io.FilePermission;import java.io.IOException;import java.io.BufferedInputStream;import java.io.InputStream;import java.util.Enumeration;import java.util.HashMap;import java.util.NoSuchElementException;import java.security.AccessController;import java.security.AccessControlContext;import java.security.PrivilegedAction;import java.security.PrivilegedExceptionAction;import java.security.PrivilegedActionException;import java.security.CodeSource;import java.security.Permission;import java.security.PermissionCollection;import sun.awt.AppContext;import sun.awt.SunToolkit;import sun.misc.IOUtils;import sun.net.www.ParseUtil;import sun.security.util.SecurityConstants; /** * This class defines the class loader for loading applet classes and * resources. It extends URLClassLoader to search the applet code base * for the class or resource after checking any loaded JAR files. */public class AppletClassLoader extends URLClassLoader {    private URL base;   /* applet code base URL */    private CodeSource codesource; /* codesource for the base URL */    private AccessControlContext acc;    private boolean exceptionStatus = false;     private final Object threadGroupSynchronizer = new Object();    private final Object grabReleaseSynchronizer = new Object();     private boolean codebaseLookup = true;    private volatile boolean allowRecursiveDirectoryRead = true;     /*     * Creates a new AppletClassLoader for the specified base URL.     */    protected AppletClassLoader(URL base) {        super(new URL[0]);        this.base = base;        this.codesource =            new CodeSource(base, (java.security.cert.Certificate[]) null);        acc = AccessController.getContext();    }     public void disableRecursiveDirectoryRead() {        allowRecursiveDirectoryRead = false;    }      /**     * Set the codebase lookup flag.     */    void setCodebaseLookup(boolean codebaseLookup)  {        this.codebaseLookup = codebaseLookup;    }     /*     * Returns the applet code base URL.     */    URL getBaseURL() {        return base;    }     /*     * Returns the URLs used for loading classes and resources.     */    public URL[] getURLs() {        URL[] jars = super.getURLs();        URL[] urls = new URL[jars.length + 1];        System.arraycopy(jars, 0, urls, 0, jars.length);        urls[urls.length - 1] = base;        return urls;    }     /*     * Adds the specified JAR file to the search path of loaded JAR files.     * Changed modifier to protected in order to be able to overwrite addJar()     * in PluginClassLoader.java     */    protected void addJar(String name) throws IOException {        URL url;        try {            url = new URL(base, name);        } catch (MalformedURLException e) {            throw new IllegalArgumentException("name");        }        addURL(url);        // DEBUG        //URL[] urls = getURLs();        //for (int i = 0; i < urls.length; i++) {        //    System.out.println("url[" + i + "] = " + urls[i]);        //}    }     /*     * Override loadClass so that class loading errors can be caught in     * order to print better error messages.     */    public synchronized Class loadClass(String name, boolean resolve)        throws ClassNotFoundException    {        // First check if we have permission to access the package. This        // should go away once we've added support for exported packages.        int i = name.lastIndexOf('.');        if (i != -1) {            SecurityManager sm = System.getSecurityManager();            if (sm != null)                sm.checkPackageAccess(name.substring(0, i));        }        try {            return super.loadClass(name, resolve);        } catch (ClassNotFoundException e) {            //printError(name, e.getException());            throw e;        } catch (RuntimeException e) {            //printError(name, e);            throw e;        } catch (Error e) {            //printError(name, e);            throw e;        }    }     /*     * Finds the applet class with the specified name. First searches     * loaded JAR files then the applet code base for the class.     */    protected Class findClass(String name) throws ClassNotFoundException {         int index = name.indexOf(";");        String cookie = "";        if(index != -1) {                cookie = name.substring(index, name.length());                name = name.substring(0, index);        }         // check loaded JAR files        try {            return super.findClass(name);        } catch (ClassNotFoundException e) {        }         // Otherwise, try loading the class from the code base URL         // 4668479: Option to turn off codebase lookup in AppletClassLoader        // during resource requests. [stanley.ho]        if (codebaseLookup == false)            throw new ClassNotFoundException(name); //      final String path = name.replace('.', '/').concat(".class").concat(cookie);        String encodedName = ParseUtil.encodePath(name.replace('.', '/'), false);        final String path = (new StringBuffer(encodedName)).append(".class").append(cookie).toString();        try {            byte[] b = (byte[]) AccessController.doPrivileged(                               new PrivilegedExceptionAction() {                public Object run() throws IOException {                   try {                        URL finalURL = new URL(base, path);                         // Make sure the codebase won't be modified                        if (base.getProtocol().equals(finalURL.getProtocol()) &&                            base.getHost().equals(finalURL.getHost()) &&                            base.getPort() == finalURL.getPort()) {                            return getBytes(finalURL);                        }                        else {                            return null;                        }                    } catch (Exception e) {                        return null;                    }                }            }, acc);             if (b != null) {                return defineClass(name, b, 0, b.length, codesource);            } else {                throw new ClassNotFoundException(name);            }        } catch (PrivilegedActionException e) {            throw new ClassNotFoundException(name, e.getException());        }    }     /**     * Returns the permissions for the given codesource object.     * The implementation of this method first calls super.getPermissions,     * to get the permissions     * granted by the super class, and then adds additional permissions     * based on the URL of the codesource.     * <p>     * If the protocol is "file"     * and the path specifies a file, permission is granted to read all files     * and (recursively) all files and subdirectories contained in     * that directory. This is so applets with a codebase of     * file:/blah/some.jar can read in file:/blah/, which is needed to     * be backward compatible. We also add permission to connect back to     * the "localhost".     *     * @param codesource the codesource     * @return the permissions granted to the codesource     */    protected PermissionCollection getPermissions(CodeSource codesource)    {        final PermissionCollection perms = super.getPermissions(codesource);         URL url = codesource.getLocation();         String path = null;        Permission p;         try {            p = url.openConnection().getPermission();        } catch (java.io.IOException ioe) {            p = null;        }         if (p instanceof FilePermission) {            path = p.getName();        } else if ((p == null) && (url.getProtocol().equals("file"))) {            path = url.getFile().replace('/', File.separatorChar);            path = ParseUtil.decode(path);        }         if (path != null) {            final String rawPath = path;            if (!path.endsWith(File.separator)) {                int endIndex = path.lastIndexOf(File.separatorChar);                if (endIndex != -1) {                        path = path.substring(0, endIndex + 1) + "-";                        perms.add(new FilePermission(path,                            SecurityConstants.FILE_READ_ACTION));                }            }            final File f = new File(rawPath);            final boolean isDirectory = f.isDirectory();            // grant codebase recursive read permission            // this should only be granted to non-UNC file URL codebase and            // the codesource path must either be a directory, or a file            // that ends with .jar or .zip            if (allowRecursiveDirectoryRead && (isDirectory ||                    rawPath.toLowerCase().endsWith(".jar") ||                    rawPath.toLowerCase().endsWith(".zip"))) {             Permission bperm;                try {                    bperm = base.openConnection().getPermission();                } catch (java.io.IOException ioe) {                    bperm = null;                }                if (bperm instanceof FilePermission) {                    String bpath = bperm.getName();                    if (bpath.endsWith(File.separator)) {                        bpath += "-";                    }                    perms.add(new FilePermission(bpath,                        SecurityConstants.FILE_READ_ACTION));                } else if ((bperm == null) && (base.getProtocol().equals("file"))) {                    String bpath = base.getFile().replace('/', File.separatorChar);                    bpath = ParseUtil.decode(bpath);                    if (bpath.endsWith(File.separator)) {                        bpath += "-";                    }                    perms.add(new FilePermission(bpath, SecurityConstants.FILE_READ_ACTION));                }             }        }        return perms;    }     /*     * Returns the contents of the specified URL as an array of bytes.     */    private static byte[] getBytes(URL url) throws IOException {        URLConnection uc = url.openConnection();        if (uc instanceof java.net.HttpURLConnection) {            java.net.HttpURLConnection huc = (java.net.HttpURLConnection) uc;            int code = huc.getResponseCode();            if (code >= java.net.HttpURLConnection.HTTP_BAD_REQUEST) {                throw new IOException("open HTTP connection failed.");            }        }        int len = uc.getContentLength();         // Fixed #4507227: Slow performance to load        // class and resources. [stanleyh]        //        // Use buffered input stream [stanleyh]        InputStream in = new BufferedInputStream(uc.getInputStream());         byte[] b;        try {            b = IOUtils.readFully(in, len, true);        } finally {            in.close();        }        return b;    }     // Object for synchronization around getResourceAsStream()    private Object syncResourceAsStream = new Object();    private Object syncResourceAsStreamFromJar = new Object();     // Flag to indicate getResourceAsStream() is in call    private boolean resourceAsStreamInCall = false;    private boolean resourceAsStreamFromJarInCall = false;     /**     * Returns an input stream for reading the specified resource.     *     * The search order is described in the documentation for {@link     * #getResource(String)}.<p>     *     * @param  name the resource name     * @return an input stream for reading the resource, or <code>null</code>     *         if the resource could not be found     * @since  JDK1.1     */    public InputStream getResourceAsStream(String name)    {         if (name == null) {            throw new NullPointerException("name");        }         try        {            InputStream is = null;             // Fixed #4507227: Slow performance to load            // class and resources. [stanleyh]            //            // The following is used to avoid calling            // AppletClassLoader.findResource() in            // super.getResourceAsStream(). Otherwise,            // unnecessary connection will be made.            //            synchronized(syncResourceAsStream)            {                resourceAsStreamInCall = true;                 // Call super class                is = super.getResourceAsStream(name);                 resourceAsStreamInCall = false;            }             // 4668479: Option to turn off codebase lookup in AppletClassLoader            // during resource requests. [stanley.ho]            if (codebaseLookup == true && is == null)            {                // If resource cannot be obtained,                // try to download it from codebase                URL url = new URL(base, ParseUtil.encodePath(name, false));                is = url.openStream();            }             return is;        }        catch (Exception e)        {            return null;        }    }      /**     * Returns an input stream for reading the specified resource from the     * the loaded jar files.     *     * The search order is described in the documentation for {@link     * #getResource(String)}.<p>     *     * @param  name the resource name     * @return an input stream for reading the resource, or <code>null</code>     *         if the resource could not be found     * @since  JDK1.1     */    public InputStream getResourceAsStreamFromJar(String name) {         if (name == null) {            throw new NullPointerException("name");        }         try {            InputStream is = null;            synchronized(syncResourceAsStreamFromJar) {                resourceAsStreamFromJarInCall = true;                // Call super class                is = super.getResourceAsStream(name);                resourceAsStreamFromJarInCall = false;            }             return is;        } catch (Exception e) {            return null;        }    }      /*     * Finds the applet resource with the specified name. First checks     * loaded JAR files then the applet code base for the resource.     */    public URL findResource(String name) {        // check loaded JAR files        URL url = super.findResource(name);         // 6215746:  Disable META-INF/* lookup from codebase in        // applet/plugin classloader. [stanley.ho]        if (name.startsWith("META-INF/"))            return url;         // 4668479: Option to turn off codebase lookup in AppletClassLoader        // during resource requests. [stanley.ho]        if (codebaseLookup == false)            return url;         if (url == null)        {            //#4805170, if it is a call from Applet.getImage()            //we should check for the image only in the archives            boolean insideGetResourceAsStreamFromJar = false;                synchronized(syncResourceAsStreamFromJar) {                insideGetResourceAsStreamFromJar = resourceAsStreamFromJarInCall;            }             if (insideGetResourceAsStreamFromJar) {                return null;            }             // Fixed #4507227: Slow performance to load            // class and resources. [stanleyh]            //            // Check if getResourceAsStream is called.            //            boolean insideGetResourceAsStream = false;             synchronized(syncResourceAsStream)            {                insideGetResourceAsStream = resourceAsStreamInCall;            }             // If getResourceAsStream is called, don't            // trigger the following code. Otherwise,            // unnecessary connection will be made.            //            if (insideGetResourceAsStream == false)            {                // otherwise, try the code base                try {                    url = new URL(base, ParseUtil.encodePath(name, false));                    // check if resource exists                    if(!resourceExists(url))                        url = null;                } catch (Exception e) {                    // all exceptions, including security exceptions, are caught                    url = null;

Lines 1–500 of 873.