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