1 /*
   2  * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.net;
  27 
  28 import java.io.Closeable;
  29 import java.io.File;
  30 import java.io.FilePermission;
  31 import java.io.IOException;
  32 import java.io.InputStream;
  33 import java.security.AccessControlContext;
  34 import java.security.AccessController;
  35 import java.security.CodeSigner;
  36 import java.security.CodeSource;
  37 import java.security.Permission;
  38 import java.security.PermissionCollection;
  39 import java.security.PrivilegedAction;
  40 import java.security.PrivilegedExceptionAction;
  41 import java.security.SecureClassLoader;
  42 import java.util.Enumeration;
  43 import java.util.List;
  44 import java.util.NoSuchElementException;
  45 import java.util.Set;
  46 import java.util.WeakHashMap;
  47 import java.util.jar.Attributes;
  48 import java.util.jar.Attributes.Name;
  49 import java.util.jar.JarFile;
  50 import java.util.jar.Manifest;
  51 
  52 import jdk.internal.loader.Resource;
  53 import jdk.internal.loader.URLClassPath;
  54 import jdk.internal.misc.JavaNetURLClassLoaderAccess;
  55 import jdk.internal.misc.SharedSecrets;
  56 import jdk.internal.perf.PerfCounter;
  57 import sun.net.www.ParseUtil;
  58 import sun.security.util.SecurityConstants;
  59 
  60 /**
  61  * This class loader is used to load classes and resources from a search
  62  * path of URLs referring to both JAR files and directories. Any {@code jar:}
  63  * scheme URL (see {@link java.net.JarURLConnection}) is assumed to refer to a
  64  * JAR file.  Any {@code file:} scheme URL that ends with a '/' is assumed to
  65  * refer to a directory. Otherwise, the URL is assumed to refer to a JAR file
  66  * which will be opened as needed.
  67  * <p>
  68  * The AccessControlContext of the thread that created the instance of
  69  * URLClassLoader will be used when subsequently loading classes and
  70  * resources.
  71  * <p>
  72  * The classes that are loaded are by default granted permission only to
  73  * access the URLs specified when the URLClassLoader was created.
  74  *
  75  * @author  David Connelly
  76  * @since   1.2
  77  */
  78 public class URLClassLoader extends SecureClassLoader implements Closeable {
  79     /* The search path for classes and resources */
  80     private final URLClassPath ucp;
  81 
  82     /* The context to be used when loading classes and resources */
  83     private final AccessControlContext acc;
  84 
  85     /**
  86      * Constructs a new URLClassLoader for the given URLs. The URLs will be
  87      * searched in the order specified for classes and resources after first
  88      * searching in the specified parent class loader.  Any {@code jar:}
  89      * scheme URL is assumed to refer to a JAR file.  Any {@code file:} scheme
  90      * URL that ends with a '/' is assumed to refer to a directory.  Otherwise,
  91      * the URL is assumed to refer to a JAR file which will be downloaded and
  92      * opened as needed.
  93      *
  94      * <p>If there is a security manager, this method first
  95      * calls the security manager's {@code checkCreateClassLoader} method
  96      * to ensure creation of a class loader is allowed.
  97      *
  98      * @param urls the URLs from which to load classes and resources
  99      * @param parent the parent class loader for delegation
 100      * @exception  SecurityException  if a security manager exists and its
 101      *             {@code checkCreateClassLoader} method doesn't allow
 102      *             creation of a class loader.
 103      * @exception  NullPointerException if {@code urls} is {@code null}.
 104      * @see SecurityManager#checkCreateClassLoader
 105      */
 106     public URLClassLoader(URL[] urls, ClassLoader parent) {
 107         super(parent);
 108         // this is to make the stack depth consistent with 1.1
 109         SecurityManager security = System.getSecurityManager();
 110         if (security != null) {
 111             security.checkCreateClassLoader();
 112         }
 113         this.ucp = new URLClassPath(urls);
 114         this.acc = AccessController.getContext();
 115     }
 116 
 117     URLClassLoader(String name, URL[] urls, ClassLoader parent,
 118                    AccessControlContext acc) {
 119         super(name, parent);
 120         // this is to make the stack depth consistent with 1.1
 121         SecurityManager security = System.getSecurityManager();
 122         if (security != null) {
 123             security.checkCreateClassLoader();
 124         }
 125         this.ucp = new URLClassPath(urls);
 126         this.acc = acc;
 127     }
 128 
 129     /**
 130      * Constructs a new URLClassLoader for the specified URLs using the
 131      * default delegation parent {@code ClassLoader}. The URLs will
 132      * be searched in the order specified for classes and resources after
 133      * first searching in the parent class loader. Any URL that ends with
 134      * a '/' is assumed to refer to a directory. Otherwise, the URL is
 135      * assumed to refer to a JAR file which will be downloaded and opened
 136      * as needed.
 137      *
 138      * <p>If there is a security manager, this method first
 139      * calls the security manager's {@code checkCreateClassLoader} method
 140      * to ensure creation of a class loader is allowed.
 141      *
 142      * @param urls the URLs from which to load classes and resources
 143      *
 144      * @exception  SecurityException  if a security manager exists and its
 145      *             {@code checkCreateClassLoader} method doesn't allow
 146      *             creation of a class loader.
 147      * @exception  NullPointerException if {@code urls} is {@code null}.
 148      * @see SecurityManager#checkCreateClassLoader
 149      */
 150     public URLClassLoader(URL[] urls) {
 151         super();
 152         // this is to make the stack depth consistent with 1.1
 153         SecurityManager security = System.getSecurityManager();
 154         if (security != null) {
 155             security.checkCreateClassLoader();
 156         }
 157         this.ucp = new URLClassPath(urls);
 158         this.acc = AccessController.getContext();
 159     }
 160 
 161     URLClassLoader(URL[] urls, AccessControlContext acc) {
 162         super();
 163         // this is to make the stack depth consistent with 1.1
 164         SecurityManager security = System.getSecurityManager();
 165         if (security != null) {
 166             security.checkCreateClassLoader();
 167         }
 168         this.ucp = new URLClassPath(urls);
 169         this.acc = acc;
 170     }
 171 
 172     /**
 173      * Constructs a new URLClassLoader for the specified URLs, parent
 174      * class loader, and URLStreamHandlerFactory. The parent argument
 175      * will be used as the parent class loader for delegation. The
 176      * factory argument will be used as the stream handler factory to
 177      * obtain protocol handlers when creating new jar URLs.
 178      *
 179      * <p>If there is a security manager, this method first
 180      * calls the security manager's {@code checkCreateClassLoader} method
 181      * to ensure creation of a class loader is allowed.
 182      *
 183      * @param urls the URLs from which to load classes and resources
 184      * @param parent the parent class loader for delegation
 185      * @param factory the URLStreamHandlerFactory to use when creating URLs
 186      *
 187      * @exception  SecurityException  if a security manager exists and its
 188      *             {@code checkCreateClassLoader} method doesn't allow
 189      *             creation of a class loader.
 190      * @exception  NullPointerException if {@code urls} is {@code null}.
 191      * @see SecurityManager#checkCreateClassLoader
 192      */
 193     public URLClassLoader(URL[] urls, ClassLoader parent,
 194                           URLStreamHandlerFactory factory) {
 195         super(parent);
 196         // this is to make the stack depth consistent with 1.1
 197         SecurityManager security = System.getSecurityManager();
 198         if (security != null) {
 199             security.checkCreateClassLoader();
 200         }
 201         this.ucp = new URLClassPath(urls, factory);
 202         this.acc = AccessController.getContext();
 203     }
 204 
 205 
 206     /**
 207      * Constructs a new named {@code URLClassLoader} for the specified URLs.
 208      * The URLs will be searched in the order specified for classes
 209      * and resources after first searching in the specified parent class loader.
 210      * Any URL that ends with a '/' is assumed to refer to a directory.
 211      * Otherwise, the URL is assumed to refer to a JAR file which will be
 212      * downloaded and opened as needed.
 213      *
 214      * @param  name class loader name; or {@code null} if not named
 215      * @param  urls the URLs from which to load classes and resources
 216      * @param  parent the parent class loader for delegation
 217      *
 218      * @throws IllegalArgumentException if the given name is empty.
 219      * @throws NullPointerException if {@code urls} is {@code null}.
 220      *
 221      * @throws SecurityException if a security manager exists and its
 222      *         {@link SecurityManager#checkCreateClassLoader()} method doesn't
 223      *         allow creation of a class loader.
 224      *
 225      * @since 9
 226      */
 227     public URLClassLoader(String name,
 228                           URL[] urls,
 229                           ClassLoader parent) {
 230         super(name, parent);
 231         // this is to make the stack depth consistent with 1.1
 232         SecurityManager security = System.getSecurityManager();
 233         if (security != null) {
 234             security.checkCreateClassLoader();
 235         }
 236         this.ucp = new URLClassPath(urls);
 237         this.acc = AccessController.getContext();
 238     }
 239 
 240     /**
 241      * Constructs a new named {@code URLClassLoader} for the specified URLs,
 242      * parent class loader, and URLStreamHandlerFactory.
 243      * The parent argument will be used as the parent class loader for delegation.
 244      * The factory argument will be used as the stream handler factory to
 245      * obtain protocol handlers when creating new jar URLs.
 246      *
 247      * @param  name class loader name; or {@code null} if not named
 248      * @param  urls the URLs from which to load classes and resources
 249      * @param  parent the parent class loader for delegation
 250      * @param  factory the URLStreamHandlerFactory to use when creating URLs
 251      *
 252      * @throws IllegalArgumentException if the given name is empty.
 253      * @throws NullPointerException if {@code urls} is {@code null}.
 254      *
 255      * @throws SecurityException if a security manager exists and its
 256      *         {@code checkCreateClassLoader} method doesn't allow
 257      *         creation of a class loader.
 258      *
 259      * @since 9
 260      */
 261     public URLClassLoader(String name, URL[] urls, ClassLoader parent,
 262                           URLStreamHandlerFactory factory) {
 263         super(name, parent);
 264         // this is to make the stack depth consistent with 1.1
 265         SecurityManager security = System.getSecurityManager();
 266         if (security != null) {
 267             security.checkCreateClassLoader();
 268         }
 269         this.ucp = new URLClassPath(urls, factory);
 270         this.acc = AccessController.getContext();
 271     }
 272 
 273     /* A map (used as a set) to keep track of closeable local resources
 274      * (either JarFiles or FileInputStreams). We don't care about
 275      * Http resources since they don't need to be closed.
 276      *
 277      * If the resource is coming from a jar file
 278      * we keep a (weak) reference to the JarFile object which can
 279      * be closed if URLClassLoader.close() called. Due to jar file
 280      * caching there will typically be only one JarFile object
 281      * per underlying jar file.
 282      *
 283      * For file resources, which is probably a less common situation
 284      * we have to keep a weak reference to each stream.
 285      */
 286 
 287     private WeakHashMap<Closeable,Void>
 288         closeables = new WeakHashMap<>();
 289 
 290     /**
 291      * Returns an input stream for reading the specified resource.
 292      * If this loader is closed, then any resources opened by this method
 293      * will be closed.
 294      *
 295      * <p> The search order is described in the documentation for {@link
 296      * #getResource(String)}.  </p>
 297      *
 298      * @param  name
 299      *         The resource name
 300      *
 301      * @return  An input stream for reading the resource, or {@code null}
 302      *          if the resource could not be found
 303      *
 304      * @since  1.7
 305      */
 306     public InputStream getResourceAsStream(String name) {
 307         URL url = getResource(name);
 308         try {
 309             if (url == null) {
 310                 return null;
 311             }
 312             URLConnection urlc = url.openConnection();
 313             InputStream is = urlc.getInputStream();
 314             if (urlc instanceof JarURLConnection) {
 315                 JarURLConnection juc = (JarURLConnection)urlc;
 316                 JarFile jar = juc.getJarFile();
 317                 synchronized (closeables) {
 318                     if (!closeables.containsKey(jar)) {
 319                         closeables.put(jar, null);
 320                     }
 321                 }
 322             } else if (urlc instanceof sun.net.www.protocol.file.FileURLConnection) {
 323                 synchronized (closeables) {
 324                     closeables.put(is, null);
 325                 }
 326             }
 327             return is;
 328         } catch (IOException e) {
 329             return null;
 330         }
 331     }
 332 
 333    /**
 334     * Closes this URLClassLoader, so that it can no longer be used to load
 335     * new classes or resources that are defined by this loader.
 336     * Classes and resources defined by any of this loader's parents in the
 337     * delegation hierarchy are still accessible. Also, any classes or resources
 338     * that are already loaded, are still accessible.
 339     * <p>
 340     * In the case of jar: and file: URLs, it also closes any files
 341     * that were opened by it. If another thread is loading a
 342     * class when the {@code close} method is invoked, then the result of
 343     * that load is undefined.
 344     * <p>
 345     * The method makes a best effort attempt to close all opened files,
 346     * by catching {@link IOException}s internally. Unchecked exceptions
 347     * and errors are not caught. Calling close on an already closed
 348     * loader has no effect.
 349     *
 350     * @exception IOException if closing any file opened by this class loader
 351     * resulted in an IOException. Any such exceptions are caught internally.
 352     * If only one is caught, then it is re-thrown. If more than one exception
 353     * is caught, then the second and following exceptions are added
 354     * as suppressed exceptions of the first one caught, which is then re-thrown.
 355     *
 356     * @exception SecurityException if a security manager is set, and it denies
 357     *   {@link RuntimePermission}{@code ("closeClassLoader")}
 358     *
 359     * @since 1.7
 360     */
 361     public void close() throws IOException {
 362         SecurityManager security = System.getSecurityManager();
 363         if (security != null) {
 364             security.checkPermission(new RuntimePermission("closeClassLoader"));
 365         }
 366         List<IOException> errors = ucp.closeLoaders();
 367 
 368         // now close any remaining streams.
 369 
 370         synchronized (closeables) {
 371             Set<Closeable> keys = closeables.keySet();
 372             for (Closeable c : keys) {
 373                 try {
 374                     c.close();
 375                 } catch (IOException ioex) {
 376                     errors.add(ioex);
 377                 }
 378             }
 379             closeables.clear();
 380         }
 381 
 382         if (errors.isEmpty()) {
 383             return;
 384         }
 385 
 386         IOException firstex = errors.remove(0);
 387 
 388         // Suppress any remaining exceptions
 389 
 390         for (IOException error: errors) {
 391             firstex.addSuppressed(error);
 392         }
 393         throw firstex;
 394     }
 395 
 396     /**
 397      * Appends the specified URL to the list of URLs to search for
 398      * classes and resources.
 399      * <p>
 400      * If the URL specified is {@code null} or is already in the
 401      * list of URLs, or if this loader is closed, then invoking this
 402      * method has no effect.
 403      *
 404      * @param url the URL to be added to the search path of URLs
 405      */
 406     protected void addURL(URL url) {
 407         ucp.addURL(url);
 408     }
 409 
 410     /**
 411      * Returns the search path of URLs for loading classes and resources.
 412      * This includes the original list of URLs specified to the constructor,
 413      * along with any URLs subsequently appended by the addURL() method.
 414      * @return the search path of URLs for loading classes and resources.
 415      */
 416     public URL[] getURLs() {
 417         return ucp.getURLs();
 418     }
 419 
 420     /**
 421      * Finds and loads the class with the specified name from the URL search
 422      * path. Any URLs referring to JAR files are loaded and opened as needed
 423      * until the class is found.
 424      *
 425      * @param name the name of the class
 426      * @return the resulting class
 427      * @exception ClassNotFoundException if the class could not be found,
 428      *            or if the loader is closed.
 429      * @exception NullPointerException if {@code name} is {@code null}.
 430      */
 431     protected Class<?> findClass(final String name)
 432         throws ClassNotFoundException
 433     {
 434         final Class<?> result;
 435         try {
 436             result = AccessController.doPrivileged(
 437                 new PrivilegedExceptionAction<>() {
 438                     public Class<?> run() throws ClassNotFoundException {
 439                         String path = name.replace('.', '/').concat(".class");
 440                         Resource res = ucp.getResource(path, false);
 441                         if (res != null) {
 442                             try {
 443                                 return defineClass(name, res);
 444                             } catch (IOException e) {
 445                                 throw new ClassNotFoundException(name, e);
 446                             }
 447                         } else {
 448                             return null;
 449                         }
 450                     }
 451                 }, acc);
 452         } catch (java.security.PrivilegedActionException pae) {
 453             throw (ClassNotFoundException) pae.getException();
 454         }
 455         if (result == null) {
 456             throw new ClassNotFoundException(name);
 457         }
 458         return result;
 459     }
 460 
 461     /*
 462      * Retrieve the package using the specified package name.
 463      * If non-null, verify the package using the specified code
 464      * source and manifest.
 465      */
 466     private Package getAndVerifyPackage(String pkgname,
 467                                         Manifest man, URL url) {
 468         Package pkg = getDefinedPackage(pkgname);
 469         if (pkg != null) {
 470             // Package found, so check package sealing.
 471             if (pkg.isSealed()) {
 472                 // Verify that code source URL is the same.
 473                 if (!pkg.isSealed(url)) {
 474                     throw new SecurityException(
 475                         "sealing violation: package " + pkgname + " is sealed");
 476                 }
 477             } else {
 478                 // Make sure we are not attempting to seal the package
 479                 // at this code source URL.
 480                 if ((man != null) && isSealed(pkgname, man)) {
 481                     throw new SecurityException(
 482                         "sealing violation: can't seal package " + pkgname +
 483                         ": already loaded");
 484                 }
 485             }
 486         }
 487         return pkg;
 488     }
 489 
 490     /*
 491      * Defines a Class using the class bytes obtained from the specified
 492      * Resource. The resulting Class must be resolved before it can be
 493      * used.
 494      */
 495     private Class<?> defineClass(String name, Resource res) throws IOException {
 496         long t0 = System.nanoTime();
 497         int i = name.lastIndexOf('.');
 498         URL url = res.getCodeSourceURL();
 499         if (i != -1) {
 500             String pkgname = name.substring(0, i);
 501             // Check if package already loaded.
 502             Manifest man = res.getManifest();
 503             if (getAndVerifyPackage(pkgname, man, url) == null) {
 504                 try {
 505                     if (man != null) {
 506                         definePackage(pkgname, man, url);
 507                     } else {
 508                         definePackage(pkgname, null, null, null, null, null, null, null);
 509                     }
 510                 } catch (IllegalArgumentException iae) {
 511                     // parallel-capable class loaders: re-verify in case of a
 512                     // race condition
 513                     if (getAndVerifyPackage(pkgname, man, url) == null) {
 514                         // Should never happen
 515                         throw new AssertionError("Cannot find package " +
 516                                                  pkgname);
 517                     }
 518                 }
 519             }
 520         }
 521         // Now read the class bytes and define the class
 522         java.nio.ByteBuffer bb = res.getByteBuffer();
 523         if (bb != null) {
 524             // Use (direct) ByteBuffer:
 525             CodeSigner[] signers = res.getCodeSigners();
 526             CodeSource cs = new CodeSource(url, signers);
 527             PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
 528             return defineClass(name, bb, cs);
 529         } else {
 530             byte[] b = res.getBytes();
 531             // must read certificates AFTER reading bytes.
 532             CodeSigner[] signers = res.getCodeSigners();
 533             CodeSource cs = new CodeSource(url, signers);
 534             PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
 535             return defineClass(name, b, 0, b.length, cs);
 536         }
 537     }
 538 
 539     /**
 540      * Defines a new package by name in this {@code URLClassLoader}.
 541      * The attributes contained in the specified {@code Manifest}
 542      * will be used to obtain package version and sealing information.
 543      * For sealed packages, the additional URL specifies the code source URL
 544      * from which the package was loaded.
 545      *
 546      * @param name  the package name
 547      * @param man   the {@code Manifest} containing package version and sealing
 548      *              information
 549      * @param url   the code source url for the package, or null if none
 550      * @throws      IllegalArgumentException if the package name is
 551      *              already defined by this class loader
 552      * @return      the newly defined {@code Package} object
 553      */
 554     protected Package definePackage(String name, Manifest man, URL url) {
 555         String path = name.replace('.', '/').concat("/");
 556         String specTitle = null, specVersion = null, specVendor = null;
 557         String implTitle = null, implVersion = null, implVendor = null;
 558         String sealed = null;
 559         URL sealBase = null;
 560 
 561         Attributes attr = man.getAttributes(path);
 562         if (attr != null) {
 563             specTitle   = attr.getValue(Name.SPECIFICATION_TITLE);
 564             specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
 565             specVendor  = attr.getValue(Name.SPECIFICATION_VENDOR);
 566             implTitle   = attr.getValue(Name.IMPLEMENTATION_TITLE);
 567             implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
 568             implVendor  = attr.getValue(Name.IMPLEMENTATION_VENDOR);
 569             sealed      = attr.getValue(Name.SEALED);
 570         }
 571         attr = man.getMainAttributes();
 572         if (attr != null) {
 573             if (specTitle == null) {
 574                 specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
 575             }
 576             if (specVersion == null) {
 577                 specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
 578             }
 579             if (specVendor == null) {
 580                 specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
 581             }
 582             if (implTitle == null) {
 583                 implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
 584             }
 585             if (implVersion == null) {
 586                 implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
 587             }
 588             if (implVendor == null) {
 589                 implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
 590             }
 591             if (sealed == null) {
 592                 sealed = attr.getValue(Name.SEALED);
 593             }
 594         }
 595         if ("true".equalsIgnoreCase(sealed)) {
 596             sealBase = url;
 597         }
 598         return definePackage(name, specTitle, specVersion, specVendor,
 599                              implTitle, implVersion, implVendor, sealBase);
 600     }
 601 
 602     /*
 603      * Returns true if the specified package name is sealed according to the
 604      * given manifest.
 605      */
 606     private boolean isSealed(String name, Manifest man) {
 607         String path = name.replace('.', '/').concat("/");
 608         Attributes attr = man.getAttributes(path);
 609         String sealed = null;
 610         if (attr != null) {
 611             sealed = attr.getValue(Name.SEALED);
 612         }
 613         if (sealed == null) {
 614             if ((attr = man.getMainAttributes()) != null) {
 615                 sealed = attr.getValue(Name.SEALED);
 616             }
 617         }
 618         return "true".equalsIgnoreCase(sealed);
 619     }
 620 
 621     /**
 622      * Finds the resource with the specified name on the URL search path.
 623      *
 624      * @param name the name of the resource
 625      * @return a {@code URL} for the resource, or {@code null}
 626      * if the resource could not be found, or if the loader is closed.
 627      */
 628     public URL findResource(final String name) {
 629         /*
 630          * The same restriction to finding classes applies to resources
 631          */
 632         URL url = AccessController.doPrivileged(
 633             new PrivilegedAction<>() {
 634                 public URL run() {
 635                     return ucp.findResource(name, true);
 636                 }
 637             }, acc);
 638 
 639         return url != null ? URLClassPath.checkURL(url) : null;
 640     }
 641 
 642     /**
 643      * Returns an Enumeration of URLs representing all of the resources
 644      * on the URL search path having the specified name.
 645      *
 646      * @param name the resource name
 647      * @exception IOException if an I/O exception occurs
 648      * @return an {@code Enumeration} of {@code URL}s
 649      *         If the loader is closed, the Enumeration will be empty.
 650      */
 651     public Enumeration<URL> findResources(final String name)
 652         throws IOException
 653     {
 654         final Enumeration<URL> e = ucp.findResources(name, true);
 655 
 656         return new Enumeration<>() {
 657             private URL url = null;
 658 
 659             private boolean next() {
 660                 if (url != null) {
 661                     return true;
 662                 }
 663                 do {
 664                     URL u = AccessController.doPrivileged(
 665                         new PrivilegedAction<>() {
 666                             public URL run() {
 667                                 if (!e.hasMoreElements())
 668                                     return null;
 669                                 return e.nextElement();
 670                             }
 671                         }, acc);
 672                     if (u == null)
 673                         break;
 674                     url = URLClassPath.checkURL(u);
 675                 } while (url == null);
 676                 return url != null;
 677             }
 678 
 679             public URL nextElement() {
 680                 if (!next()) {
 681                     throw new NoSuchElementException();
 682                 }
 683                 URL u = url;
 684                 url = null;
 685                 return u;
 686             }
 687 
 688             public boolean hasMoreElements() {
 689                 return next();
 690             }
 691         };
 692     }
 693 
 694     /**
 695      * Returns the permissions for the given codesource object.
 696      * The implementation of this method first calls super.getPermissions
 697      * and then adds permissions based on the URL of the codesource.
 698      * <p>
 699      * If the protocol of this URL is "jar", then the permission granted
 700      * is based on the permission that is required by the URL of the Jar
 701      * file.
 702      * <p>
 703      * If the protocol is "file" and there is an authority component, then
 704      * permission to connect to and accept connections from that authority
 705      * may be granted. If the protocol is "file"
 706      * and the path specifies a file, then permission to read that
 707      * file is granted. If protocol is "file" and the path is
 708      * a directory, permission is granted to read all files
 709      * and (recursively) all files and subdirectories contained in
 710      * that directory.
 711      * <p>
 712      * If the protocol is not "file", then permission
 713      * to connect to and accept connections from the URL's host is granted.
 714      * @param codesource the codesource
 715      * @exception NullPointerException if {@code codesource} is {@code null}.
 716      * @return the permissions granted to the codesource
 717      */
 718     protected PermissionCollection getPermissions(CodeSource codesource)
 719     {
 720         PermissionCollection perms = super.getPermissions(codesource);
 721 
 722         URL url = codesource.getLocation();
 723 
 724         Permission p;
 725         URLConnection urlConnection;
 726 
 727         try {
 728             urlConnection = url.openConnection();
 729             p = urlConnection.getPermission();
 730         } catch (java.io.IOException ioe) {
 731             p = null;
 732             urlConnection = null;
 733         }
 734 
 735         if (p instanceof FilePermission) {
 736             // if the permission has a separator char on the end,
 737             // it means the codebase is a directory, and we need
 738             // to add an additional permission to read recursively
 739             String path = p.getName();
 740             if (path.endsWith(File.separator)) {
 741                 path += "-";
 742                 p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
 743             }
 744         } else if ((p == null) && (url.getProtocol().equals("file"))) {
 745             String path = url.getFile().replace('/', File.separatorChar);
 746             path = ParseUtil.decode(path);
 747             if (path.endsWith(File.separator))
 748                 path += "-";
 749             p =  new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
 750         } else {
 751             /**
 752              * Not loading from a 'file:' URL so we want to give the class
 753              * permission to connect to and accept from the remote host
 754              * after we've made sure the host is the correct one and is valid.
 755              */
 756             URL locUrl = url;
 757             if (urlConnection instanceof JarURLConnection) {
 758                 locUrl = ((JarURLConnection)urlConnection).getJarFileURL();
 759             }
 760             String host = locUrl.getHost();
 761             if (host != null && (host.length() > 0))
 762                 p = new SocketPermission(host,
 763                                          SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION);
 764         }
 765 
 766         // make sure the person that created this class loader
 767         // would have this permission
 768 
 769         if (p != null) {
 770             final SecurityManager sm = System.getSecurityManager();
 771             if (sm != null) {
 772                 final Permission fp = p;
 773                 AccessController.doPrivileged(new PrivilegedAction<>() {
 774                     public Void run() throws SecurityException {
 775                         sm.checkPermission(fp);
 776                         return null;
 777                     }
 778                 }, acc);
 779             }
 780             perms.add(p);
 781         }
 782         return perms;
 783     }
 784 
 785     /**
 786      * Creates a new instance of URLClassLoader for the specified
 787      * URLs and parent class loader. If a security manager is
 788      * installed, the {@code loadClass} method of the URLClassLoader
 789      * returned by this method will invoke the
 790      * {@code SecurityManager.checkPackageAccess} method before
 791      * loading the class.
 792      *
 793      * @param urls the URLs to search for classes and resources
 794      * @param parent the parent class loader for delegation
 795      * @exception  NullPointerException if {@code urls} is {@code null}.
 796      * @return the resulting class loader
 797      */
 798     public static URLClassLoader newInstance(final URL[] urls,
 799                                              final ClassLoader parent) {
 800         // Save the caller's context
 801         final AccessControlContext acc = AccessController.getContext();
 802         // Need a privileged block to create the class loader
 803         URLClassLoader ucl = AccessController.doPrivileged(
 804             new PrivilegedAction<>() {
 805                 public URLClassLoader run() {
 806                     return new FactoryURLClassLoader(null, urls, parent, acc);
 807                 }
 808             });
 809         return ucl;
 810     }
 811 
 812     /**
 813      * Creates a new instance of URLClassLoader for the specified
 814      * URLs and default parent class loader. If a security manager is
 815      * installed, the {@code loadClass} method of the URLClassLoader
 816      * returned by this method will invoke the
 817      * {@code SecurityManager.checkPackageAccess} before
 818      * loading the class.
 819      *
 820      * @param urls the URLs to search for classes and resources
 821      * @exception  NullPointerException if {@code urls} is {@code null}.
 822      * @return the resulting class loader
 823      */
 824     public static URLClassLoader newInstance(final URL[] urls) {
 825         // Save the caller's context
 826         final AccessControlContext acc = AccessController.getContext();
 827         // Need a privileged block to create the class loader
 828         URLClassLoader ucl = AccessController.doPrivileged(
 829             new PrivilegedAction<>() {
 830                 public URLClassLoader run() {
 831                     return new FactoryURLClassLoader(urls, acc);
 832                 }
 833             });
 834         return ucl;
 835     }
 836 
 837     static {
 838         SharedSecrets.setJavaNetURLClassLoaderAccess(
 839             new JavaNetURLClassLoaderAccess() {
 840                 @Override
 841                 public AccessControlContext getAccessControlContext(URLClassLoader u) {
 842                     return u.acc;
 843                 }
 844             }
 845         );
 846         ClassLoader.registerAsParallelCapable();
 847     }
 848 }
 849 
 850 final class FactoryURLClassLoader extends URLClassLoader {
 851 
 852     static {
 853         ClassLoader.registerAsParallelCapable();
 854     }
 855 
 856     FactoryURLClassLoader(String name, URL[] urls, ClassLoader parent,
 857                           AccessControlContext acc) {
 858         super(name, urls, parent, acc);
 859     }
 860 
 861     FactoryURLClassLoader(URL[] urls, AccessControlContext acc) {
 862         super(urls, acc);
 863     }
 864 
 865     public final Class<?> loadClass(String name, boolean resolve)
 866         throws ClassNotFoundException
 867     {
 868         // First check if we have permission to access the package. This
 869         // should go away once we've added support for exported packages.
 870         SecurityManager sm = System.getSecurityManager();
 871         if (sm != null) {
 872             int i = name.lastIndexOf('.');
 873             if (i != -1) {
 874                 sm.checkPackageAccess(name.substring(0, i));
 875             }
 876         }
 877         return super.loadClass(name, resolve);
 878     }
 879 }