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