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 path = name.replace('.', '/').concat("/"); 574 String specTitle = null, specVersion = null, specVendor = null; 575 String implTitle = null, implVersion = null, implVendor = null; 576 String sealed = null; 577 URL sealBase = null; 578 579 Attributes attr = man.getAttributes(path); 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 private boolean isSealed(String name, Manifest man) { 625 String path = name.replace('.', '/').concat("/"); 626 Attributes attr = man.getAttributes(path); 627 String sealed = null; 628 if (attr != null) { 629 sealed = attr.getValue(Name.SEALED); 630 } 631 if (sealed == null) { 632 if ((attr = man.getMainAttributes()) != null) { 633 sealed = attr.getValue(Name.SEALED); 634 } 635 } 636 return "true".equalsIgnoreCase(sealed); 637 } 638 639 /** 640 * Finds the resource with the specified name on the URL search path. 641 * 642 * @param name the name of the resource 643 * @return a {@code URL} for the resource, or {@code null} 644 * if the resource could not be found, or if the loader is closed. 645 */ 646 public URL findResource(final String name) { 647 /* 648 * The same restriction to finding classes applies to resources 649 */ 650 URL url = AccessController.doPrivileged( 651 new PrivilegedAction<>() { 652 public URL run() { 653 return ucp.findResource(name, true); 654 } 655 }, acc); 656 657 return url != null ? URLClassPath.checkURL(url) : null; 658 } 659 660 /** 661 * Returns an Enumeration of URLs representing all of the resources 662 * on the URL search path having the specified name. 663 * 664 * @param name the resource name 665 * @exception IOException if an I/O exception occurs 666 * @return An {@code Enumeration} of {@code URL}s. 667 * If the loader is closed, the Enumeration contains no elements. 668 */ 669 public Enumeration<URL> findResources(final String name) 670 throws IOException 671 { 672 final Enumeration<URL> e = ucp.findResources(name, true); 673 674 return new Enumeration<>() { 675 private URL url = null; 676 677 private boolean next() { 678 if (url != null) { 679 return true; 680 } 681 do { 682 URL u = AccessController.doPrivileged( 683 new PrivilegedAction<>() { 684 public URL run() { 685 if (!e.hasMoreElements()) 686 return null; 687 return e.nextElement(); 688 } 689 }, acc); 690 if (u == null) 691 break; 692 url = URLClassPath.checkURL(u); 693 } while (url == null); 694 return url != null; 695 } 696 697 public URL nextElement() { 698 if (!next()) { 699 throw new NoSuchElementException(); 700 } 701 URL u = url; 702 url = null; 703 return u; 704 } 705 706 public boolean hasMoreElements() { 707 return next(); 708 } 709 }; 710 } 711 712 /** 713 * Returns the permissions for the given codesource object. 714 * The implementation of this method first calls super.getPermissions 715 * and then adds permissions based on the URL of the codesource. 716 * <p> 717 * If the protocol of this URL is "jar", then the permission granted 718 * is based on the permission that is required by the URL of the Jar 719 * file. 720 * <p> 721 * If the protocol is "file" and there is an authority component, then 722 * permission to connect to and accept connections from that authority 723 * may be granted. If the protocol is "file" 724 * and the path specifies a file, then permission to read that 725 * file is granted. If protocol is "file" and the path is 726 * a directory, permission is granted to read all files 727 * and (recursively) all files and subdirectories contained in 728 * that directory. 729 * <p> 730 * If the protocol is not "file", then permission 731 * to connect to and accept connections from the URL's host is granted. 732 * @param codesource the codesource 733 * @exception NullPointerException if {@code codesource} is {@code null}. 734 * @return the permissions granted to the codesource 735 */ 736 protected PermissionCollection getPermissions(CodeSource codesource) 737 { 738 PermissionCollection perms = super.getPermissions(codesource); 739 740 URL url = codesource.getLocation(); 741 742 Permission p; 743 URLConnection urlConnection; 744 745 try { 746 urlConnection = url.openConnection(); 747 p = urlConnection.getPermission(); 748 } catch (java.io.IOException ioe) { 749 p = null; 750 urlConnection = null; 751 } 752 753 if (p instanceof FilePermission) { 754 // if the permission has a separator char on the end, 755 // it means the codebase is a directory, and we need 756 // to add an additional permission to read recursively 757 String path = p.getName(); 758 if (path.endsWith(File.separator)) { 759 path += "-"; 760 p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION); 761 } 762 } else if ((p == null) && (url.getProtocol().equals("file"))) { 763 String path = url.getFile().replace('/', File.separatorChar); 764 path = ParseUtil.decode(path); 765 if (path.endsWith(File.separator)) 766 path += "-"; 767 p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION); 768 } else { 769 /** 770 * Not loading from a 'file:' URL so we want to give the class 771 * permission to connect to and accept from the remote host 772 * after we've made sure the host is the correct one and is valid. 773 */ 774 URL locUrl = url; 775 if (urlConnection instanceof JarURLConnection) { 776 locUrl = ((JarURLConnection)urlConnection).getJarFileURL(); 777 } 778 String host = locUrl.getHost(); 779 if (host != null && (host.length() > 0)) 780 p = new SocketPermission(host, 781 SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION); 782 } 783 784 // make sure the person that created this class loader 785 // would have this permission 786 787 if (p != null) { 788 final SecurityManager sm = System.getSecurityManager(); 789 if (sm != null) { 790 final Permission fp = p; 791 AccessController.doPrivileged(new PrivilegedAction<>() { 792 public Void run() throws SecurityException { 793 sm.checkPermission(fp); 794 return null; 795 } 796 }, acc); 797 } 798 perms.add(p); 799 } 800 return perms; 801 } 802 803 /** 804 * Creates a new instance of URLClassLoader for the specified 805 * URLs and parent class loader. If a security manager is 806 * installed, the {@code loadClass} method of the URLClassLoader 807 * returned by this method will invoke the 808 * {@code SecurityManager.checkPackageAccess} method before 809 * loading the class. 810 * 811 * @param urls the URLs to search for classes and resources 812 * @param parent the parent class loader for delegation 813 * @exception NullPointerException if {@code urls} or any of its 814 * elements is {@code null}. 815 * @return the resulting class loader 816 */ 817 public static URLClassLoader newInstance(final URL[] urls, 818 final ClassLoader parent) { 819 // Save the caller's context 820 final AccessControlContext acc = AccessController.getContext(); 821 // Need a privileged block to create the class loader 822 URLClassLoader ucl = AccessController.doPrivileged( 823 new PrivilegedAction<>() { 824 public URLClassLoader run() { 825 return new FactoryURLClassLoader(null, urls, parent, acc); 826 } 827 }); 828 return ucl; 829 } 830 831 /** 832 * Creates a new instance of URLClassLoader for the specified 833 * URLs and default parent class loader. If a security manager is 834 * installed, the {@code loadClass} method of the URLClassLoader 835 * returned by this method will invoke the 836 * {@code SecurityManager.checkPackageAccess} before 837 * loading the class. 838 * 839 * @param urls the URLs to search for classes and resources 840 * @exception NullPointerException if {@code urls} or any of its 841 * elements is {@code null}. 842 * @return the resulting class loader 843 */ 844 public static URLClassLoader newInstance(final URL[] urls) { 845 // Save the caller's context 846 final AccessControlContext acc = AccessController.getContext(); 847 // Need a privileged block to create the class loader 848 URLClassLoader ucl = AccessController.doPrivileged( 849 new PrivilegedAction<>() { 850 public URLClassLoader run() { 851 return new FactoryURLClassLoader(urls, acc); 852 } 853 }); 854 return ucl; 855 } 856 857 static { 858 SharedSecrets.setJavaNetURLClassLoaderAccess( 859 new JavaNetURLClassLoaderAccess() { 860 @Override 861 public AccessControlContext getAccessControlContext(URLClassLoader u) { 862 return u.acc; 863 } 864 } 865 ); 866 ClassLoader.registerAsParallelCapable(); 867 } 868 } 869 870 final class FactoryURLClassLoader extends URLClassLoader { 871 872 static { 873 ClassLoader.registerAsParallelCapable(); 874 } 875 876 FactoryURLClassLoader(String name, URL[] urls, ClassLoader parent, 877 AccessControlContext acc) { 878 super(name, urls, parent, acc); 879 } 880 881 FactoryURLClassLoader(URL[] urls, AccessControlContext acc) { 882 super(urls, acc); 883 } 884 885 public final Class<?> loadClass(String name, boolean resolve) 886 throws ClassNotFoundException 887 { 888 // First check if we have permission to access the package. This 889 // should go away once we've added support for exported packages. 890 SecurityManager sm = System.getSecurityManager(); 891 if (sm != null) { 892 int i = name.lastIndexOf('.'); 893 if (i != -1) { 894 sm.checkPackageAccess(name.substring(0, i)); 895 } 896 } 897 return super.loadClass(name, resolve); 898 } 899 }