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