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.length() > 0)) 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 }