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