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