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