< prev index next >

src/java.base/share/classes/jdk/internal/loader/URLClassPath.java

Print this page
imported patch classloader-cleanup


 309             System.err.println("URLClassPath.getResource(\"" + name + "\")");
 310         }
 311 
 312         Loader loader;
 313         for (int i = 0; (loader = getLoader(i)) != null; i++) {
 314             Resource res = loader.getResource(name, check);
 315             if (res != null) {
 316                 return res;
 317             }
 318         }
 319         return null;
 320     }
 321 
 322     /**
 323      * Finds all resources on the URL search path with the given name.
 324      * Returns an enumeration of the URL objects.
 325      *
 326      * @param name the resource name
 327      * @return an Enumeration of all the urls having the specified name
 328      */
 329     public Enumeration<URL> findResources(final String name,
 330                                      final boolean check) {
 331         return new Enumeration<>() {
 332             private int index = 0;
 333             private URL url = null;
 334 
 335             private boolean next() {
 336                 if (url != null) {
 337                     return true;
 338                 } else {
 339                     Loader loader;
 340                     while ((loader = getLoader(index++)) != null) {
 341                         url = loader.findResource(name, check);
 342                         if (url != null) {
 343                             return true;
 344                         }
 345                     }
 346                     return false;
 347                 }
 348             }
 349 
 350             public boolean hasMoreElements() {


 356                     throw new NoSuchElementException();
 357                 }
 358                 URL u = url;
 359                 url = null;
 360                 return u;
 361             }
 362         };
 363     }
 364 
 365     public Resource getResource(String name) {
 366         return getResource(name, true);
 367     }
 368 
 369     /**
 370      * Finds all resources on the URL search path with the given name.
 371      * Returns an enumeration of the Resource objects.
 372      *
 373      * @param name the resource name
 374      * @return an Enumeration of all the resources having the specified name
 375      */
 376     public Enumeration<Resource> getResources(final String name,
 377                                     final boolean check) {
 378         return new Enumeration<>() {
 379             private int index = 0;
 380             private Resource res = null;
 381 
 382             private boolean next() {
 383                 if (res != null) {
 384                     return true;
 385                 } else {
 386                     Loader loader;
 387                     while ((loader = getLoader(index++)) != null) {
 388                         res = loader.getResource(name, check);
 389                         if (res != null) {
 390                             return true;
 391                         }
 392                     }
 393                     return false;
 394                 }
 395             }
 396 
 397             public boolean hasMoreElements() {
 398                 return next();
 399             }
 400 
 401             public Resource nextElement() {
 402                 if (!next()) {
 403                     throw new NoSuchElementException();
 404                 }
 405                 Resource r = res;
 406                 res = null;
 407                 return r;
 408             }
 409         };
 410     }
 411 
 412     public Enumeration<Resource> getResources(final String name) {
 413         return getResources(name, true);
 414     }
 415 
 416     /*
 417      * Returns the Loader at the specified position in the URL search
 418      * path. The URLs are opened and expanded as needed. Returns null
 419      * if the specified index is out of range.
 420      */
 421     private synchronized Loader getLoader(int index) {
 422         if (closed) {
 423             return null;
 424         }
 425         // Expand URL search path until the request can be satisfied
 426         // or unopenedUrls is exhausted.
 427         while (loaders.size() < index + 1) {
 428             final URL url;
 429             synchronized (unopenedUrls) {
 430                 url = unopenedUrls.pollFirst();
 431                 if (url == null)
 432                     return null;


 520 
 521     /*
 522      * Checks whether the resource URL should be returned.
 523      * Returns null on security check failure.
 524      * Called by java.net.URLClassLoader.
 525      */
 526     public static URL checkURL(URL url) {
 527         if (url != null) {
 528             try {
 529                 check(url);
 530             } catch (Exception e) {
 531                 return null;
 532             }
 533         }
 534         return url;
 535     }
 536 
 537     /*
 538      * Checks whether the resource URL should be returned.
 539      * Throws exception on failure.
 540      * Called internally within this file.
 541      */
 542     public static void check(URL url) throws IOException {
 543         SecurityManager security = System.getSecurityManager();
 544         if (security != null) {
 545             URLConnection urlConnection = url.openConnection();
 546             Permission perm = urlConnection.getPermission();
 547             if (perm != null) {
 548                 try {
 549                     security.checkPermission(perm);
 550                 } catch (SecurityException se) {
 551                     // fallback to checkRead/checkConnect for pre 1.2
 552                     // security managers
 553                     if ((perm instanceof java.io.FilePermission) &&
 554                         perm.getActions().indexOf("read") != -1) {
 555                         security.checkRead(perm.getName());
 556                     } else if ((perm instanceof
 557                         java.net.SocketPermission) &&
 558                         perm.getActions().indexOf("connect") != -1) {
 559                         URL locUrl = url;
 560                         if (urlConnection instanceof JarURLConnection) {
 561                             locUrl = ((JarURLConnection)urlConnection).getJarFileURL();
 562                         }
 563                         security.checkConnect(locUrl.getHost(),
 564                                               locUrl.getPort());
 565                     } else {
 566                         throw se;
 567                     }
 568                 }
 569             }
 570         }
 571     }
 572 
 573     /**
 574      * Nested class used to represent a loader of resources and classes
 575      * from a base URL.
 576      */
 577     private static class Loader implements Closeable {
 578         private final URL base;
 579         private JarFile jarfile; // if this points to a jar file
 580 
 581         /*
 582          * Creates a new Loader for the specified URL.
 583          */
 584         Loader(URL url) {
 585             base = url;
 586         }
 587 
 588         /*
 589          * Returns the base URL for this Loader.
 590          */
 591         URL getBaseURL() {
 592             return base;
 593         }
 594 
 595         URL findResource(final String name, boolean check) {


 653                 return null;
 654             }
 655             return new Resource() {
 656                 public String getName() { return name; }
 657                 public URL getURL() { return url; }
 658                 public URL getCodeSourceURL() { return base; }
 659                 public InputStream getInputStream() throws IOException {
 660                     return uc.getInputStream();
 661                 }
 662                 public int getContentLength() throws IOException {
 663                     return uc.getContentLength();
 664                 }
 665             };
 666         }
 667 
 668         /*
 669          * Returns the Resource for the specified name, or null if not
 670          * found or the caller does not have the permission to get the
 671          * resource.
 672          */
 673         Resource getResource(final String name) {
 674             return getResource(name, true);
 675         }
 676 
 677         /*
 678          * Closes this loader and release all resources.
 679          * Method overridden in sub-classes.
 680          */
 681         @Override
 682         public void close() throws IOException {
 683             if (jarfile != null) {
 684                 jarfile.close();
 685             }
 686         }
 687 
 688         /*
 689          * Returns the local class path for this loader, or null if none.
 690          */
 691         URL[] getClassPath() throws IOException {
 692             return null;
 693         }
 694     }
 695 
 696     /*
 697      * Nested class used to represent a Loader of resources from a JAR URL.
 698      */
 699     static class JarLoader extends Loader {
 700         private JarFile jar;
 701         private final URL csu;
 702         private JarIndex index;
 703         private URLStreamHandler handler;
 704         private final HashMap<String, Loader> lmap;
 705         private final AccessControlContext acc;
 706         private boolean closed = false;
 707         private static final JavaUtilZipFileAccess zipAccess =
 708                 SharedSecrets.getJavaUtilZipFileAccess();
 709 
 710         /*
 711          * Creates a new JarLoader for the specified URL referring to
 712          * a JAR file.
 713          */
 714         JarLoader(URL url, URLStreamHandler jarHandler,
 715                   HashMap<String, Loader> loaderMap,
 716                   AccessControlContext acc)
 717             throws IOException
 718         {
 719             super(new URL("jar", "", -1, url + "!/", jarHandler));
 720             csu = url;
 721             handler = jarHandler;
 722             lmap = loaderMap;
 723             this.acc = acc;
 724 
 725             ensureOpen();
 726         }
 727 
 728         @Override
 729         public void close () throws IOException {
 730             // closing is synchronized at higher level
 731             if (!closed) {
 732                 closed = true;
 733                 // in case not already open.
 734                 ensureOpen();
 735                 jar.close();
 736             }
 737         }
 738 
 739         JarFile getJarFile () {
 740             return jar;
 741         }
 742 
 743         private boolean isOptimizable(URL url) {
 744             return "file".equals(url.getProtocol());
 745         }
 746 
 747         private void ensureOpen() throws IOException {
 748             if (jar == null) {
 749                 try {
 750                     AccessController.doPrivileged(
 751                         new PrivilegedExceptionAction<>() {
 752                             public Void run() throws IOException {
 753                                 if (DEBUG) {
 754                                     System.err.println("Opening " + csu);
 755                                     Thread.dumpStack();
 756                                 }
 757 
 758                                 jar = getJarFile(csu);
 759                                 index = JarIndex.getJarIndex(jar);


 769                                             URL jarURL = new URL(csu, jarfiles[i]);
 770                                             // If a non-null loader already exists, leave it alone.
 771                                             String urlNoFragString = URLUtil.urlNoFragString(jarURL);
 772                                             if (!lmap.containsKey(urlNoFragString)) {
 773                                                 lmap.put(urlNoFragString, null);
 774                                             }
 775                                         } catch (MalformedURLException e) {
 776                                             continue;
 777                                         }
 778                                     }
 779                                 }
 780                                 return null;
 781                             }
 782                         }, acc);
 783                 } catch (PrivilegedActionException pae) {
 784                     throw (IOException)pae.getException();
 785                 }
 786             }
 787         }
 788 
 789         /* Throws if the given jar file is does not start with the correct LOC */
 790         static JarFile checkJar(JarFile jar) throws IOException {
 791             if (System.getSecurityManager() != null && !DISABLE_JAR_CHECKING
 792                 && !zipAccess.startsWithLocHeader(jar)) {
 793                 IOException x = new IOException("Invalid Jar file");
 794                 try {
 795                     jar.close();
 796                 } catch (IOException ex) {
 797                     x.addSuppressed(ex);
 798                 }
 799                 throw x;
 800             }
 801 
 802             return jar;
 803         }
 804 
 805         private JarFile getJarFile(URL url) throws IOException {
 806             // Optimize case where url refers to a local jar file
 807             if (isOptimizable(url)) {
 808                 FileURLMapper p = new FileURLMapper(url);
 809                 if (!p.exists()) {


 815             URLConnection uc = (new URL(getBaseURL(), "#runtime")).openConnection();
 816             uc.setRequestProperty(USER_AGENT_JAVA_VERSION, JAVA_VERSION);
 817             JarFile jarFile = ((JarURLConnection)uc).getJarFile();
 818             return checkJar(jarFile);
 819         }
 820 
 821         /*
 822          * Returns the index of this JarLoader if it exists.
 823          */
 824         JarIndex getIndex() {
 825             try {
 826                 ensureOpen();
 827             } catch (IOException e) {
 828                 throw new InternalError(e);
 829             }
 830             return index;
 831         }
 832 
 833         /*
 834          * Creates the resource and if the check flag is set to true, checks if
 835          * is its okay to return the resource.
 836          */
 837         Resource checkResource(final String name, boolean check,
 838             final JarEntry entry) {
 839 
 840             final URL url;
 841             try {
 842                 String nm;
 843                 if (jar.isMultiRelease()) {
 844                     nm = entry.getRealName();
 845                 } else {
 846                     nm = name;
 847                 }
 848                 url = new URL(getBaseURL(), ParseUtil.encodePath(nm, false));
 849                 if (check) {
 850                     URLClassPath.check(url);
 851                 }
 852             } catch (MalformedURLException e) {
 853                 return null;
 854                 // throw new IllegalArgumentException("name");
 855             } catch (IOException e) {


 888             if ((pos = name.lastIndexOf('/')) != -1) {
 889                 packageName = name.substring(0, pos);
 890             }
 891 
 892             String entryName;
 893             ZipEntry entry;
 894             Enumeration<JarEntry> enum_ = jar.entries();
 895             while (enum_.hasMoreElements()) {
 896                 entry = enum_.nextElement();
 897                 entryName = entry.getName();
 898                 if ((pos = entryName.lastIndexOf('/')) != -1)
 899                     entryName = entryName.substring(0, pos);
 900                 if (entryName.equals(packageName)) {
 901                     return true;
 902                 }
 903             }
 904             return false;
 905         }
 906 
 907         /*
 908          * Returns the URL for a resource with the specified name
 909          */
 910         @Override
 911         URL findResource(final String name, boolean check) {
 912             Resource rsc = getResource(name, check);
 913             if (rsc != null) {
 914                 return rsc.getURL();
 915             }
 916             return null;
 917         }
 918 
 919         /*
 920          * Returns the JAR Resource for the specified name.
 921          */
 922         @Override
 923         Resource getResource(final String name, boolean check) {
 924             try {
 925                 ensureOpen();
 926             } catch (IOException e) {
 927                 throw new InternalError(e);
 928             }


1019                         /* Verify that at least one other resource with the
1020                          * same package name as the lookedup resource is
1021                          * present in the new jar
1022                          */
1023                         if (!newLoader.validIndex(name)) {
1024                             /* the mapping is wrong */
1025                             throw new InvalidJarIndexError("Invalid index");
1026                         }
1027                     }
1028 
1029                     /* If newLoader is the current loader or if it is a
1030                      * loader that has already been searched or if the new
1031                      * loader does not have an index then skip it
1032                      * and move on to the next loader.
1033                      */
1034                     if (visitedURL || newLoader == this ||
1035                             newLoader.getIndex() == null) {
1036                         continue;
1037                     }
1038 
1039                     /* Process the index of the new loader
1040                      */
1041                     if ((res = newLoader.getResource(name, check, visited))
1042                             != null) {
1043                         return res;
1044                     }
1045                 }
1046                 // Get the list of jar files again as the list could have grown
1047                 // due to merging of index files.
1048                 jarFilesList = index.get(name);
1049 
1050             // If the count is unchanged, we are done.
1051             } while (count < jarFilesList.size());
1052             return null;
1053         }
1054 
1055 
1056         /*
1057          * Returns the JAR file local class path, or null if none.
1058          */
1059         @Override
1060         URL[] getClassPath() throws IOException {


1091             URL[] urls = new URL[st.countTokens()];
1092             int i = 0;
1093             while (st.hasMoreTokens()) {
1094                 String path = st.nextToken();
1095                 URL url = DISABLE_CP_URL_CHECK ? new URL(base, path) : safeResolve(base, path);
1096                 if (url != null) {
1097                     urls[i] = url;
1098                     i++;
1099                 }
1100             }
1101             if (i == 0) {
1102                 urls = null;
1103             } else if (i != urls.length) {
1104                 // Truncate nulls from end of array
1105                 urls = Arrays.copyOf(urls, i);
1106             }
1107             return urls;
1108         }
1109 
1110         /*
1111          * Return a URL for the given path resolved against the base URL, or
1112          * null if the resulting URL is invalid.
1113          */
1114         static URL safeResolve(URL base, String path) {
1115             String child = path.replace(File.separatorChar, '/');
1116             try {
1117                 if (!URI.create(child).isAbsolute()) {
1118                     URL url = new URL(base, child);
1119                     if (base.getProtocol().equalsIgnoreCase("file")) {
1120                         return url;
1121                     } else {
1122                         String bp = base.getPath();
1123                         String urlp = url.getPath();
1124                         int pos = bp.lastIndexOf('/');
1125                         if (pos == -1) {
1126                             pos = bp.length() - 1;
1127                         }
1128                         if (urlp.regionMatches(0, bp, 0, pos + 1)
1129                             && urlp.indexOf("..", pos) == -1) {
1130                             return url;
1131                         }
1132                     }
1133                 }
1134             } catch (MalformedURLException | IllegalArgumentException e) {}
1135             if (DEBUG_CP_URL_CHECK) {
1136                 System.err.println("Class-Path entry: \"" + path + "\" ignored in JAR file " + base);
1137             }
1138             return null;
1139         }
1140     }
1141 
1142     /*
1143      * Nested class used to represent a loader of classes and resources
1144      * from a file URL that refers to a directory.
1145      */
1146     private static class FileLoader extends Loader {
1147         /* Canonicalized File */
1148         private File dir;
1149 
1150         FileLoader(URL url) throws IOException {
1151             super(url);
1152             if (!"file".equals(url.getProtocol())) {
1153                 throw new IllegalArgumentException("url");
1154             }
1155             String path = url.getFile().replace('/', File.separatorChar);
1156             path = ParseUtil.decode(path);
1157             dir = (new File(path)).getCanonicalFile();
1158         }
1159 
1160         /*
1161          * Returns the URL for a resource with the specified name
1162          */
1163         @Override
1164         URL findResource(final String name, boolean check) {
1165             Resource rsc = getResource(name, check);
1166             if (rsc != null) {
1167                 return rsc.getURL();
1168             }
1169             return null;
1170         }
1171 
1172         @Override
1173         Resource getResource(final String name, boolean check) {
1174             final URL url;
1175             try {
1176                 URL normalizedBase = new URL(getBaseURL(), ".");
1177                 url = new URL(getBaseURL(), ParseUtil.encodePath(name, false));

1178 
1179                 if (url.getFile().startsWith(normalizedBase.getFile()) == false) {
1180                     // requested resource had ../..'s in path
1181                     return null;
1182                 }
1183 
1184                 if (check)
1185                     URLClassPath.check(url);
1186 
1187                 final File file;
1188                 if (name.indexOf("..") != -1) {
1189                     file = (new File(dir, name.replace('/', File.separatorChar)))
1190                           .getCanonicalFile();
1191                     if ( !((file.getPath()).startsWith(dir.getPath())) ) {
1192                         /* outside of base dir */
1193                         return null;
1194                     }
1195                 } else {
1196                     file = new File(dir, name.replace('/', File.separatorChar));
1197                 }
1198 
1199                 if (file.exists()) {
1200                     return new Resource() {
1201                         public String getName() { return name; };
1202                         public URL getURL() { return url; };
1203                         public URL getCodeSourceURL() { return getBaseURL(); };
1204                         public InputStream getInputStream() throws IOException
1205                             { return new FileInputStream(file); };
1206                         public int getContentLength() throws IOException
1207                             { return (int)file.length(); };
1208                     };
1209                 }
1210             } catch (Exception e) {
1211                 return null;


 309             System.err.println("URLClassPath.getResource(\"" + name + "\")");
 310         }
 311 
 312         Loader loader;
 313         for (int i = 0; (loader = getLoader(i)) != null; i++) {
 314             Resource res = loader.getResource(name, check);
 315             if (res != null) {
 316                 return res;
 317             }
 318         }
 319         return null;
 320     }
 321 
 322     /**
 323      * Finds all resources on the URL search path with the given name.
 324      * Returns an enumeration of the URL objects.
 325      *
 326      * @param name the resource name
 327      * @return an Enumeration of all the urls having the specified name
 328      */
 329     public Enumeration<URL> findResources(String name, boolean check) {

 330         return new Enumeration<>() {
 331             private int index = 0;
 332             private URL url = null;
 333 
 334             private boolean next() {
 335                 if (url != null) {
 336                     return true;
 337                 } else {
 338                     Loader loader;
 339                     while ((loader = getLoader(index++)) != null) {
 340                         url = loader.findResource(name, check);
 341                         if (url != null) {
 342                             return true;
 343                         }
 344                     }
 345                     return false;
 346                 }
 347             }
 348 
 349             public boolean hasMoreElements() {


 355                     throw new NoSuchElementException();
 356                 }
 357                 URL u = url;
 358                 url = null;
 359                 return u;
 360             }
 361         };
 362     }
 363 
 364     public Resource getResource(String name) {
 365         return getResource(name, true);
 366     }
 367 
 368     /**
 369      * Finds all resources on the URL search path with the given name.
 370      * Returns an enumeration of the Resource objects.
 371      *
 372      * @param name the resource name
 373      * @return an Enumeration of all the resources having the specified name
 374      */
 375     public Enumeration<Resource> getResources(String name, boolean check) {

 376         return new Enumeration<>() {
 377             private int index = 0;
 378             private Resource res = null;
 379 
 380             private boolean next() {
 381                 if (res != null) {
 382                     return true;
 383                 } else {
 384                     Loader loader;
 385                     while ((loader = getLoader(index++)) != null) {
 386                         res = loader.getResource(name, check);
 387                         if (res != null) {
 388                             return true;
 389                         }
 390                     }
 391                     return false;
 392                 }
 393             }
 394 
 395             public boolean hasMoreElements() {
 396                 return next();
 397             }
 398 
 399             public Resource nextElement() {
 400                 if (!next()) {
 401                     throw new NoSuchElementException();
 402                 }
 403                 Resource r = res;
 404                 res = null;
 405                 return r;
 406             }
 407         };
 408     }
 409 
 410     public Enumeration<Resource> getResources(String name) {
 411         return getResources(name, true);
 412     }
 413 
 414     /*
 415      * Returns the Loader at the specified position in the URL search
 416      * path. The URLs are opened and expanded as needed. Returns null
 417      * if the specified index is out of range.
 418      */
 419     private synchronized Loader getLoader(int index) {
 420         if (closed) {
 421             return null;
 422         }
 423         // Expand URL search path until the request can be satisfied
 424         // or unopenedUrls is exhausted.
 425         while (loaders.size() < index + 1) {
 426             final URL url;
 427             synchronized (unopenedUrls) {
 428                 url = unopenedUrls.pollFirst();
 429                 if (url == null)
 430                     return null;


 518 
 519     /*
 520      * Checks whether the resource URL should be returned.
 521      * Returns null on security check failure.
 522      * Called by java.net.URLClassLoader.
 523      */
 524     public static URL checkURL(URL url) {
 525         if (url != null) {
 526             try {
 527                 check(url);
 528             } catch (Exception e) {
 529                 return null;
 530             }
 531         }
 532         return url;
 533     }
 534 
 535     /*
 536      * Checks whether the resource URL should be returned.
 537      * Throws exception on failure.

 538      */
 539     private static void check(URL url) throws IOException {
 540         SecurityManager security = System.getSecurityManager();
 541         if (security != null) {
 542             URLConnection urlConnection = url.openConnection();
 543             Permission perm = urlConnection.getPermission();
 544             if (perm != null) {
 545                 try {
 546                     security.checkPermission(perm);
 547                 } catch (SecurityException se) {
 548                     // fallback to checkRead/checkConnect for pre 1.2
 549                     // security managers
 550                     if ((perm instanceof java.io.FilePermission) &&
 551                         perm.getActions().indexOf("read") != -1) {
 552                         security.checkRead(perm.getName());
 553                     } else if ((perm instanceof
 554                         java.net.SocketPermission) &&
 555                         perm.getActions().indexOf("connect") != -1) {
 556                         URL locUrl = url;
 557                         if (urlConnection instanceof JarURLConnection) {
 558                             locUrl = ((JarURLConnection)urlConnection).getJarFileURL();
 559                         }
 560                         security.checkConnect(locUrl.getHost(),
 561                                               locUrl.getPort());
 562                     } else {
 563                         throw se;
 564                     }
 565                 }
 566             }
 567         }
 568     }
 569 
 570     /**
 571      * A loader of resources and classes from a base URL.

 572      */
 573     private static class Loader implements Closeable {
 574         private final URL base;
 575         private JarFile jarfile; // if this points to a jar file
 576 
 577         /*
 578          * Creates a new Loader for the specified URL.
 579          */
 580         Loader(URL url) {
 581             base = url;
 582         }
 583 
 584         /*
 585          * Returns the base URL for this Loader.
 586          */
 587         URL getBaseURL() {
 588             return base;
 589         }
 590 
 591         URL findResource(final String name, boolean check) {


 649                 return null;
 650             }
 651             return new Resource() {
 652                 public String getName() { return name; }
 653                 public URL getURL() { return url; }
 654                 public URL getCodeSourceURL() { return base; }
 655                 public InputStream getInputStream() throws IOException {
 656                     return uc.getInputStream();
 657                 }
 658                 public int getContentLength() throws IOException {
 659                     return uc.getContentLength();
 660                 }
 661             };
 662         }
 663 
 664         /*
 665          * Returns the Resource for the specified name, or null if not
 666          * found or the caller does not have the permission to get the
 667          * resource.
 668          */
 669         Resource getResource(String name) {
 670             return getResource(name, true);
 671         }
 672 
 673         /*
 674          * Closes this loader and release all resources.
 675          * Method overridden in sub-classes.
 676          */
 677         @Override
 678         public void close() throws IOException {
 679             if (jarfile != null) {
 680                 jarfile.close();
 681             }
 682         }
 683 
 684         /*
 685          * Returns the local class path for this loader, or null if none.
 686          */
 687         URL[] getClassPath() throws IOException {
 688             return null;
 689         }
 690     }
 691 
 692     /*
 693      * A Loader of resources from a JAR URL.
 694      */
 695     static class JarLoader extends Loader {
 696         private JarFile jar;
 697         private final URL csu;
 698         private JarIndex index;
 699         private URLStreamHandler handler;
 700         private final HashMap<String, Loader> lmap;
 701         private final AccessControlContext acc;
 702         private boolean closed = false;
 703         private static final JavaUtilZipFileAccess zipAccess =
 704                 SharedSecrets.getJavaUtilZipFileAccess();
 705 
 706         /*
 707          * Creates a new JarLoader for the specified URL referring to
 708          * a JAR file.
 709          */
 710         JarLoader(URL url, URLStreamHandler jarHandler,
 711                   HashMap<String, Loader> loaderMap,
 712                   AccessControlContext acc)
 713             throws IOException
 714         {
 715             super(new URL("jar", "", -1, url + "!/", jarHandler));
 716             csu = url;
 717             handler = jarHandler;
 718             lmap = loaderMap;
 719             this.acc = acc;
 720 
 721             ensureOpen();
 722         }
 723 
 724         @Override
 725         public void close() throws IOException {
 726             // closing is synchronized at higher level
 727             if (!closed) {
 728                 closed = true;
 729                 // in case not already open.
 730                 ensureOpen();
 731                 jar.close();
 732             }
 733         }
 734 
 735         JarFile getJarFile() {
 736             return jar;
 737         }
 738 
 739         private boolean isOptimizable(URL url) {
 740             return "file".equals(url.getProtocol());
 741         }
 742 
 743         private void ensureOpen() throws IOException {
 744             if (jar == null) {
 745                 try {
 746                     AccessController.doPrivileged(
 747                         new PrivilegedExceptionAction<>() {
 748                             public Void run() throws IOException {
 749                                 if (DEBUG) {
 750                                     System.err.println("Opening " + csu);
 751                                     Thread.dumpStack();
 752                                 }
 753 
 754                                 jar = getJarFile(csu);
 755                                 index = JarIndex.getJarIndex(jar);


 765                                             URL jarURL = new URL(csu, jarfiles[i]);
 766                                             // If a non-null loader already exists, leave it alone.
 767                                             String urlNoFragString = URLUtil.urlNoFragString(jarURL);
 768                                             if (!lmap.containsKey(urlNoFragString)) {
 769                                                 lmap.put(urlNoFragString, null);
 770                                             }
 771                                         } catch (MalformedURLException e) {
 772                                             continue;
 773                                         }
 774                                     }
 775                                 }
 776                                 return null;
 777                             }
 778                         }, acc);
 779                 } catch (PrivilegedActionException pae) {
 780                     throw (IOException)pae.getException();
 781                 }
 782             }
 783         }
 784 
 785         /* Throws if the given jar file does not start with the correct LOC */
 786         static JarFile checkJar(JarFile jar) throws IOException {
 787             if (System.getSecurityManager() != null && !DISABLE_JAR_CHECKING
 788                 && !zipAccess.startsWithLocHeader(jar)) {
 789                 IOException x = new IOException("Invalid Jar file");
 790                 try {
 791                     jar.close();
 792                 } catch (IOException ex) {
 793                     x.addSuppressed(ex);
 794                 }
 795                 throw x;
 796             }
 797 
 798             return jar;
 799         }
 800 
 801         private JarFile getJarFile(URL url) throws IOException {
 802             // Optimize case where url refers to a local jar file
 803             if (isOptimizable(url)) {
 804                 FileURLMapper p = new FileURLMapper(url);
 805                 if (!p.exists()) {


 811             URLConnection uc = (new URL(getBaseURL(), "#runtime")).openConnection();
 812             uc.setRequestProperty(USER_AGENT_JAVA_VERSION, JAVA_VERSION);
 813             JarFile jarFile = ((JarURLConnection)uc).getJarFile();
 814             return checkJar(jarFile);
 815         }
 816 
 817         /*
 818          * Returns the index of this JarLoader if it exists.
 819          */
 820         JarIndex getIndex() {
 821             try {
 822                 ensureOpen();
 823             } catch (IOException e) {
 824                 throw new InternalError(e);
 825             }
 826             return index;
 827         }
 828 
 829         /*
 830          * Creates the resource and if the check flag is set to true, checks if
 831          * is it's okay to return the resource.
 832          */
 833         Resource checkResource(final String name, boolean check,
 834             final JarEntry entry) {
 835 
 836             final URL url;
 837             try {
 838                 String nm;
 839                 if (jar.isMultiRelease()) {
 840                     nm = entry.getRealName();
 841                 } else {
 842                     nm = name;
 843                 }
 844                 url = new URL(getBaseURL(), ParseUtil.encodePath(nm, false));
 845                 if (check) {
 846                     URLClassPath.check(url);
 847                 }
 848             } catch (MalformedURLException e) {
 849                 return null;
 850                 // throw new IllegalArgumentException("name");
 851             } catch (IOException e) {


 884             if ((pos = name.lastIndexOf('/')) != -1) {
 885                 packageName = name.substring(0, pos);
 886             }
 887 
 888             String entryName;
 889             ZipEntry entry;
 890             Enumeration<JarEntry> enum_ = jar.entries();
 891             while (enum_.hasMoreElements()) {
 892                 entry = enum_.nextElement();
 893                 entryName = entry.getName();
 894                 if ((pos = entryName.lastIndexOf('/')) != -1)
 895                     entryName = entryName.substring(0, pos);
 896                 if (entryName.equals(packageName)) {
 897                     return true;
 898                 }
 899             }
 900             return false;
 901         }
 902 
 903         /*
 904          * Returns the URL for a resource with the specified name.
 905          */
 906         @Override
 907         URL findResource(final String name, boolean check) {
 908             Resource rsc = getResource(name, check);
 909             if (rsc != null) {
 910                 return rsc.getURL();
 911             }
 912             return null;
 913         }
 914 
 915         /*
 916          * Returns the JAR Resource for the specified name.
 917          */
 918         @Override
 919         Resource getResource(final String name, boolean check) {
 920             try {
 921                 ensureOpen();
 922             } catch (IOException e) {
 923                 throw new InternalError(e);
 924             }


1015                         /* Verify that at least one other resource with the
1016                          * same package name as the lookedup resource is
1017                          * present in the new jar
1018                          */
1019                         if (!newLoader.validIndex(name)) {
1020                             /* the mapping is wrong */
1021                             throw new InvalidJarIndexError("Invalid index");
1022                         }
1023                     }
1024 
1025                     /* If newLoader is the current loader or if it is a
1026                      * loader that has already been searched or if the new
1027                      * loader does not have an index then skip it
1028                      * and move on to the next loader.
1029                      */
1030                     if (visitedURL || newLoader == this ||
1031                             newLoader.getIndex() == null) {
1032                         continue;
1033                     }
1034 
1035                     // Process the index of the new loader

1036                     if ((res = newLoader.getResource(name, check, visited))
1037                             != null) {
1038                         return res;
1039                     }
1040                 }
1041                 // Get the list of jar files again as the list could have grown
1042                 // due to merging of index files.
1043                 jarFilesList = index.get(name);
1044 
1045             // If the count is unchanged, we are done.
1046             } while (count < jarFilesList.size());
1047             return null;
1048         }
1049 
1050 
1051         /*
1052          * Returns the JAR file local class path, or null if none.
1053          */
1054         @Override
1055         URL[] getClassPath() throws IOException {


1086             URL[] urls = new URL[st.countTokens()];
1087             int i = 0;
1088             while (st.hasMoreTokens()) {
1089                 String path = st.nextToken();
1090                 URL url = DISABLE_CP_URL_CHECK ? new URL(base, path) : safeResolve(base, path);
1091                 if (url != null) {
1092                     urls[i] = url;
1093                     i++;
1094                 }
1095             }
1096             if (i == 0) {
1097                 urls = null;
1098             } else if (i != urls.length) {
1099                 // Truncate nulls from end of array
1100                 urls = Arrays.copyOf(urls, i);
1101             }
1102             return urls;
1103         }
1104 
1105         /*
1106          * Returns a URL for the given path resolved against the base URL, or
1107          * null if the resulting URL is invalid.
1108          */
1109         static URL safeResolve(URL base, String path) {
1110             String child = path.replace(File.separatorChar, '/');
1111             try {
1112                 if (!URI.create(child).isAbsolute()) {
1113                     URL url = new URL(base, child);
1114                     if (base.getProtocol().equalsIgnoreCase("file")) {
1115                         return url;
1116                     } else {
1117                         String bp = base.getPath();
1118                         String urlp = url.getPath();
1119                         int pos = bp.lastIndexOf('/');
1120                         if (pos == -1) {
1121                             pos = bp.length() - 1;
1122                         }
1123                         if (urlp.regionMatches(0, bp, 0, pos + 1)
1124                             && urlp.indexOf("..", pos) == -1) {
1125                             return url;
1126                         }
1127                     }
1128                 }
1129             } catch (MalformedURLException | IllegalArgumentException e) {}
1130             if (DEBUG_CP_URL_CHECK) {
1131                 System.err.println("Class-Path entry: \"" + path + "\" ignored in JAR file " + base);
1132             }
1133             return null;
1134         }
1135     }
1136 
1137     /*
1138      * A loader of classes and resources from a file URL that refers to a directory.

1139      */
1140     private static class FileLoader extends Loader {
1141         /* Canonicalized File */
1142         private File dir;
1143 
1144         FileLoader(URL url) throws IOException {
1145             super(url);
1146             if (!"file".equals(url.getProtocol())) {
1147                 throw new IllegalArgumentException("url");
1148             }
1149             String path = url.getFile().replace('/', File.separatorChar);
1150             path = ParseUtil.decode(path);
1151             dir = (new File(path)).getCanonicalFile();
1152         }
1153 
1154         /*
1155          * Returns the URL for a resource with the specified name.
1156          */
1157         @Override
1158         URL findResource(String name, boolean check) {
1159             Resource rsc = getResource(name, check);
1160             if (rsc != null) {
1161                 return rsc.getURL();
1162             }
1163             return null;
1164         }
1165 
1166         @Override
1167         Resource getResource(String name, boolean check) {

1168             try {
1169                 URL normalizedBase = new URL(getBaseURL(), ".");
1170                 final URL url = new URL(
1171                         getBaseURL(), ParseUtil.encodePath(name, false));
1172 
1173                 if (!url.getFile().startsWith(normalizedBase.getFile())) {
1174                     // requested resource had ../..'s in path
1175                     return null;
1176                 }
1177 
1178                 if (check)
1179                     URLClassPath.check(url);
1180 
1181                 final File file;
1182                 if (name.indexOf("..") != -1) {
1183                     file = (new File(dir, name.replace('/', File.separatorChar)))
1184                           .getCanonicalFile();
1185                     if (!file.getPath().startsWith(dir.getPath())) {
1186                         /* outside of base dir */
1187                         return null;
1188                     }
1189                 } else {
1190                     file = new File(dir, name.replace('/', File.separatorChar));
1191                 }
1192 
1193                 if (file.exists()) {
1194                     return new Resource() {
1195                         public String getName() { return name; };
1196                         public URL getURL() { return url; };
1197                         public URL getCodeSourceURL() { return getBaseURL(); };
1198                         public InputStream getInputStream() throws IOException
1199                             { return new FileInputStream(file); };
1200                         public int getContentLength() throws IOException
1201                             { return (int)file.length(); };
1202                     };
1203                 }
1204             } catch (Exception e) {
1205                 return null;
< prev index next >