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 */
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
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 */
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
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 }
462 } else {
463 return null;
464 }
465 }
466 }, acc);
467 } catch (java.security.PrivilegedActionException pae) {
468 throw (ClassNotFoundException) pae.getException();
469 }
470 if (result == null) {
471 throw new ClassNotFoundException(name);
472 }
473 return result;
474 }
475
476 /*
477 * Retrieve the package using the specified package name.
478 * If non-null, verify the package using the specified code
479 * source and manifest.
480 */
481 private Package getAndVerifyPackage(String pkgname,
482 Manifest man, URL url) {
483 Package pkg = getDefinedPackage(pkgname);
484 if (pkg != null) {
485 // Package found, so check package sealing.
486 if (pkg.isSealed()) {
487 // Verify that code source URL is the same.
488 if (!pkg.isSealed(url)) {
489 throw new SecurityException(
490 "sealing violation: package " + pkgname + " is sealed");
491 }
492 } else {
493 // Make sure we are not attempting to seal the package
494 // at this code source URL.
495 if ((man != null) && isSealed(pkgname, man)) {
496 throw new SecurityException(
497 "sealing violation: can't seal package " + pkgname +
498 ": already loaded");
499 }
500 }
501 }
502 return pkg;
503 }
504
505 /*
506 * Defines a Class using the class bytes obtained from the specified
507 * Resource. The resulting Class must be resolved before it can be
508 * used.
509 */
510 private Class<?> defineClass(String name, Resource res) throws IOException {
511 long t0 = System.nanoTime();
512 int i = name.lastIndexOf('.');
513 URL url = res.getCodeSourceURL();
514 if (i != -1) {
515 String pkgname = name.substring(0, i);
516 // Check if package already loaded.
517 Manifest man = res.getManifest();
518 if (getAndVerifyPackage(pkgname, man, url) == null) {
519 try {
520 if (man != null) {
521 definePackage(pkgname, man, url);
522 } else {
523 definePackage(pkgname, null, null, null, null, null, null, null);
524 }
525 } catch (IllegalArgumentException iae) {
526 // parallel-capable class loaders: re-verify in case of a
527 // race condition
528 if (getAndVerifyPackage(pkgname, man, url) == null) {
529 // Should never happen
530 throw new AssertionError("Cannot find package " +
531 pkgname);
532 }
533 }
534 }
535 }
536 // Now read the class bytes and define the class
537 java.nio.ByteBuffer bb = res.getByteBuffer();
538 if (bb != null) {
539 // Use (direct) ByteBuffer:
540 CodeSigner[] signers = res.getCodeSigners();
541 CodeSource cs = new CodeSource(url, signers);
542 PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
543 return defineClass(name, bb, cs);
544 } else {
545 byte[] b = res.getBytes();
546 // must read certificates AFTER reading bytes.
547 CodeSigner[] signers = res.getCodeSigners();
548 CodeSource cs = new CodeSource(url, signers);
549 PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
550 return defineClass(name, b, 0, b.length, cs);
551 }
552 }
553
554 /**
555 * Defines a new package by name in this {@code URLClassLoader}.
556 * The attributes contained in the specified {@code Manifest}
557 * will be used to obtain package version and sealing information.
558 * For sealed packages, the additional URL specifies the code source URL
559 * from which the package was loaded.
560 *
561 * @param name the package name
562 * @param man the {@code Manifest} containing package version and sealing
563 * information
564 * @param url the code source url for the package, or null if none
565 * @throws IllegalArgumentException if the package name is
566 * already defined by this class loader
567 * @return the newly defined {@code Package} object
568 *
569 * @revised 9
570 * @spec JPMS
571 */
572 protected Package definePackage(String name, Manifest man, URL url) {
573 String specTitle = null, specVersion = null, specVendor = null;
574 String implTitle = null, implVersion = null, implVendor = null;
575 String sealed = null;
576 URL sealBase = null;
577
578 Attributes attr = SharedSecrets.javaUtilJarAccess()
579 .getTrustedAttributes(man, name.replace('.', '/').concat("/"));
580 if (attr != null) {
581 specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
582 specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
583 specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
584 implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
585 implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
586 implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
587 sealed = attr.getValue(Name.SEALED);
588 }
589 attr = man.getMainAttributes();
590 if (attr != null) {
591 if (specTitle == null) {
592 specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
593 }
594 if (specVersion == null) {
595 specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
596 }
597 if (specVendor == null) {
598 specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
599 }
600 if (implTitle == null) {
601 implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
602 }
603 if (implVersion == null) {
604 implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
605 }
606 if (implVendor == null) {
607 implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
608 }
609 if (sealed == null) {
610 sealed = attr.getValue(Name.SEALED);
611 }
612 }
613 if ("true".equalsIgnoreCase(sealed)) {
614 sealBase = url;
615 }
616 return definePackage(name, specTitle, specVersion, specVendor,
617 implTitle, implVersion, implVendor, sealBase);
618 }
619
620 /*
621 * Returns true if the specified package name is sealed according to the
622 * given manifest.
623 *
624 * @throws SecurityException if the package name is untrusted in the manifest
625 */
626 private boolean isSealed(String name, Manifest man) {
627 Attributes attr = SharedSecrets.javaUtilJarAccess()
628 .getTrustedAttributes(man, name.replace('.', '/').concat("/"));
629 String sealed = null;
630 if (attr != null) {
631 sealed = attr.getValue(Name.SEALED);
632 }
633 if (sealed == null) {
634 if ((attr = man.getMainAttributes()) != null) {
635 sealed = attr.getValue(Name.SEALED);
636 }
637 }
638 return "true".equalsIgnoreCase(sealed);
639 }
640
641 /**
642 * Finds the resource with the specified name on the URL search path.
643 *
644 * @param name the name of the resource
645 * @return a {@code URL} for the resource, or {@code null}
646 * if the resource could not be found, or if the loader is closed.
647 */
648 public URL findResource(final String name) {
649 /*
650 * The same restriction to finding classes applies to resources
651 */
652 URL url = AccessController.doPrivileged(
653 new PrivilegedAction<>() {
654 public URL run() {
655 return ucp.findResource(name, true);
656 }
657 }, acc);
658
659 return url != null ? URLClassPath.checkURL(url) : null;
660 }
661
662 /**
663 * Returns an Enumeration of URLs representing all of the resources
664 * on the URL search path having the specified name.
665 *
666 * @param name the resource name
667 * @exception IOException if an I/O exception occurs
668 * @return An {@code Enumeration} of {@code URL}s.
669 * If the loader is closed, the Enumeration contains no elements.
670 */
671 public Enumeration<URL> findResources(final String name)
672 throws IOException
673 {
674 final Enumeration<URL> e = ucp.findResources(name, true);
675
676 return new Enumeration<>() {
677 private URL url = null;
678
679 private boolean next() {
680 if (url != null) {
681 return true;
682 }
683 do {
684 URL u = AccessController.doPrivileged(
685 new PrivilegedAction<>() {
686 public URL run() {
687 if (!e.hasMoreElements())
688 return null;
689 return e.nextElement();
690 }
691 }, acc);
692 if (u == null)
693 break;
694 url = URLClassPath.checkURL(u);
695 } while (url == null);
696 return url != null;
697 }
698
699 public URL nextElement() {
700 if (!next()) {
701 throw new NoSuchElementException();
702 }
703 URL u = url;
704 url = null;
705 return u;
706 }
707
708 public boolean hasMoreElements() {
709 return next();
710 }
711 };
712 }
713
714 /**
715 * Returns the permissions for the given codesource object.
716 * The implementation of this method first calls super.getPermissions
717 * and then adds permissions based on the URL of the codesource.
718 * <p>
719 * If the protocol of this URL is "jar", then the permission granted
720 * is based on the permission that is required by the URL of the Jar
721 * file.
722 * <p>
723 * If the protocol is "file" and there is an authority component, then
724 * permission to connect to and accept connections from that authority
725 * may be granted. If the protocol is "file"
726 * and the path specifies a file, then permission to read that
727 * file is granted. If protocol is "file" and the path is
728 * a directory, permission is granted to read all files
729 * and (recursively) all files and subdirectories contained in
730 * that directory.
731 * <p>
732 * If the protocol is not "file", then permission
733 * to connect to and accept connections from the URL's host is granted.
734 * @param codesource the codesource
735 * @exception NullPointerException if {@code codesource} is {@code null}.
736 * @return the permissions granted to the codesource
737 */
738 protected PermissionCollection getPermissions(CodeSource codesource)
739 {
740 PermissionCollection perms = super.getPermissions(codesource);
741
742 URL url = codesource.getLocation();
743
744 Permission p;
745 URLConnection urlConnection;
746
747 try {
748 urlConnection = url.openConnection();
749 p = urlConnection.getPermission();
750 } catch (java.io.IOException ioe) {
751 p = null;
752 urlConnection = null;
753 }
754
755 if (p instanceof FilePermission) {
756 // if the permission has a separator char on the end,
757 // it means the codebase is a directory, and we need
758 // to add an additional permission to read recursively
759 String path = p.getName();
760 if (path.endsWith(File.separator)) {
761 path += "-";
762 p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
763 }
764 } else if ((p == null) && (url.getProtocol().equals("file"))) {
765 String path = url.getFile().replace('/', File.separatorChar);
766 path = ParseUtil.decode(path);
767 if (path.endsWith(File.separator))
768 path += "-";
769 p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
770 } else {
771 /**
772 * Not loading from a 'file:' URL so we want to give the class
773 * permission to connect to and accept from the remote host
774 * after we've made sure the host is the correct one and is valid.
775 */
776 URL locUrl = url;
777 if (urlConnection instanceof JarURLConnection) {
778 locUrl = ((JarURLConnection)urlConnection).getJarFileURL();
779 }
780 String host = locUrl.getHost();
781 if (host != null && !host.isEmpty())
782 p = new SocketPermission(host,
783 SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION);
784 }
785
786 // make sure the person that created this class loader
787 // would have this permission
788
789 if (p != null) {
790 final SecurityManager sm = System.getSecurityManager();
791 if (sm != null) {
792 final Permission fp = p;
793 AccessController.doPrivileged(new PrivilegedAction<>() {
794 public Void run() throws SecurityException {
795 sm.checkPermission(fp);
796 return null;
797 }
798 }, acc);
799 }
800 perms.add(p);
801 }
802 return perms;
803 }
804
805 /**
806 * Creates a new instance of URLClassLoader for the specified
807 * URLs and parent class loader. If a security manager is
808 * installed, the {@code loadClass} method of the URLClassLoader
809 * returned by this method will invoke the
810 * {@code SecurityManager.checkPackageAccess} method before
811 * loading the class.
812 *
813 * @param urls the URLs to search for classes and resources
814 * @param parent the parent class loader for delegation
815 * @exception NullPointerException if {@code urls} or any of its
816 * elements is {@code null}.
817 * @return the resulting class loader
818 */
819 public static URLClassLoader newInstance(final URL[] urls,
820 final ClassLoader parent) {
821 // Save the caller's context
822 final AccessControlContext acc = AccessController.getContext();
823 // Need a privileged block to create the class loader
824 URLClassLoader ucl = AccessController.doPrivileged(
825 new PrivilegedAction<>() {
826 public URLClassLoader run() {
827 return new FactoryURLClassLoader(null, urls, parent, acc);
828 }
829 });
830 return ucl;
831 }
832
833 /**
834 * Creates a new instance of URLClassLoader for the specified
835 * URLs and default parent class loader. If a security manager is
836 * installed, the {@code loadClass} method of the URLClassLoader
837 * returned by this method will invoke the
838 * {@code SecurityManager.checkPackageAccess} before
839 * loading the class.
840 *
841 * @param urls the URLs to search for classes and resources
842 * @exception NullPointerException if {@code urls} or any of its
843 * elements is {@code null}.
844 * @return the resulting class loader
845 */
846 public static URLClassLoader newInstance(final URL[] urls) {
847 // Save the caller's context
848 final AccessControlContext acc = AccessController.getContext();
849 // Need a privileged block to create the class loader
850 URLClassLoader ucl = AccessController.doPrivileged(
851 new PrivilegedAction<>() {
852 public URLClassLoader run() {
853 return new FactoryURLClassLoader(urls, acc);
854 }
855 });
856 return ucl;
857 }
858
859 static {
860 SharedSecrets.setJavaNetURLClassLoaderAccess(
861 new JavaNetURLClassLoaderAccess() {
862 @Override
863 public AccessControlContext getAccessControlContext(URLClassLoader u) {
864 return u.acc;
865 }
866 }
867 );
868 ClassLoader.registerAsParallelCapable();
869 }
870 }
871
872 final class FactoryURLClassLoader extends URLClassLoader {
873
874 static {
875 ClassLoader.registerAsParallelCapable();
876 }
877
878 FactoryURLClassLoader(String name, URL[] urls, ClassLoader parent,
879 AccessControlContext acc) {
880 super(name, urls, parent, acc);
881 }
882
883 FactoryURLClassLoader(URL[] urls, AccessControlContext acc) {
884 super(urls, acc);
885 }
886
887 public final Class<?> loadClass(String name, boolean resolve)
888 throws ClassNotFoundException
889 {
890 // First check if we have permission to access the package. This
891 // should go away once we've added support for exported packages.
892 SecurityManager sm = System.getSecurityManager();
893 if (sm != null) {
894 int i = name.lastIndexOf('.');
895 if (i != -1) {
896 sm.checkPackageAccess(name.substring(0, i));
897 }
898 }
899 return super.loadClass(name, resolve);
900 }
901 }
902