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