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 sun.misc; 27 28 import java.util.*; 29 import java.util.jar.JarFile; 30 import sun.misc.JarIndex; 31 import sun.misc.InvalidJarIndexException; 32 import sun.net.www.ParseUtil; 33 import java.util.zip.ZipEntry; 34 import java.util.jar.JarEntry; 35 import java.util.jar.Manifest; 36 import java.util.jar.Attributes; 37 import java.util.jar.Attributes.Name; 38 import java.net.JarURLConnection; 39 import java.net.MalformedURLException; 40 import java.net.URL; 41 import java.net.URLConnection; 42 import java.net.HttpURLConnection; 43 import java.net.URLStreamHandler; 44 import java.net.URLStreamHandlerFactory; 45 import java.io.*; 46 import java.security.AccessController; 47 import java.security.AccessControlException; 48 import java.security.CodeSigner; 49 import java.security.Permission; 50 import java.security.PrivilegedAction; 51 import java.security.PrivilegedExceptionAction; 52 import java.security.cert.Certificate; 53 import sun.misc.FileURLMapper; 54 import sun.net.util.URLUtil; 55 56 /** 57 * This class is used to maintain a search path of URLs for loading classes 58 * and resources from both JAR files and directories. 59 * 60 * @author David Connelly 61 */ 62 public class URLClassPath { 63 final static String USER_AGENT_JAVA_VERSION = "UA-Java-Version"; 64 final static String JAVA_VERSION; 65 private static final boolean DEBUG; 66 private static final boolean DISABLE_JAR_CHECKING; 67 68 static { 69 JAVA_VERSION = java.security.AccessController.doPrivileged( 70 new sun.security.action.GetPropertyAction("java.version")); 71 DEBUG = (java.security.AccessController.doPrivileged( 72 new sun.security.action.GetPropertyAction("sun.misc.URLClassPath.debug")) != null); 73 String p = java.security.AccessController.doPrivileged( 74 new sun.security.action.GetPropertyAction("sun.misc.URLClassPath.disableJarChecking")); 75 DISABLE_JAR_CHECKING = p != null ? p.equals("true") || p.equals("") : false; 76 } 77 78 /* The original search path of URLs. */ 79 private ArrayList<URL> path = new ArrayList<URL>(); 80 81 /* The stack of unopened URLs */ 82 Stack<URL> urls = new Stack<URL>(); 83 84 /* The resulting search path of Loaders */ 85 ArrayList<Loader> loaders = new ArrayList<Loader>(); 86 87 /* Map of each URL opened to its corresponding Loader */ 88 HashMap<String, Loader> lmap = new HashMap<String, Loader>(); 346 } 347 return loaders.get(index); 348 } 349 350 /* 351 * Returns the Loader for the specified base URL. 352 */ 353 private Loader getLoader(final URL url) throws IOException { 354 try { 355 return java.security.AccessController.doPrivileged( 356 new java.security.PrivilegedExceptionAction<Loader>() { 357 public Loader run() throws IOException { 358 String file = url.getFile(); 359 if (file != null && file.endsWith("/")) { 360 if ("file".equals(url.getProtocol())) { 361 return new FileLoader(url); 362 } else { 363 return new Loader(url); 364 } 365 } else { 366 return new JarLoader(url, jarHandler, lmap); 367 } 368 } 369 }); 370 } catch (java.security.PrivilegedActionException pae) { 371 throw (IOException)pae.getException(); 372 } 373 } 374 375 /* 376 * Pushes the specified URLs onto the list of unopened URLs. 377 */ 378 private void push(URL[] us) { 379 synchronized (urls) { 380 for (int i = us.length - 1; i >= 0; --i) { 381 urls.push(us[i]); 382 } 383 } 384 } 385 963 964 // If the count is unchanged, we are done. 965 } while(count < jarFilesList.size()); 966 return null; 967 } 968 969 970 /* 971 * Returns the JAR file local class path, or null if none. 972 */ 973 URL[] getClassPath() throws IOException { 974 if (index != null) { 975 return null; 976 } 977 978 if (metaIndex != null) { 979 return null; 980 } 981 982 ensureOpen(); 983 parseExtensionsDependencies(); 984 985 if (SharedSecrets.javaUtilJarAccess().jarFileHasClassPathAttribute(jar)) { // Only get manifest when necessary 986 Manifest man = jar.getManifest(); 987 if (man != null) { 988 Attributes attr = man.getMainAttributes(); 989 if (attr != null) { 990 String value = attr.getValue(Name.CLASS_PATH); 991 if (value != null) { 992 return parseClassPath(csu, value); 993 } 994 } 995 } 996 } 997 return null; 998 } 999 1000 /* 1001 * parse the standard extension dependencies 1002 */ 1003 private void parseExtensionsDependencies() throws IOException { 1004 ExtensionDependency.checkExtensionsDependencies(jar); 1005 } 1006 1007 /* 1008 * Parses value of the Class-Path manifest attribute and returns 1009 * an array of URLs relative to the specified base URL. 1010 */ 1011 private URL[] parseClassPath(URL base, String value) 1012 throws MalformedURLException 1013 { 1014 StringTokenizer st = new StringTokenizer(value); 1015 URL[] urls = new URL[st.countTokens()]; 1016 int i = 0; 1017 while (st.hasMoreTokens()) { 1018 String path = st.nextToken(); 1019 urls[i] = new URL(base, path); 1020 i++; 1021 } 1022 return urls; 1023 } 1024 } 1025 1026 /* 1027 * Inner class used to represent a loader of classes and resources 1078 file = new File(dir, name.replace('/', File.separatorChar)); 1079 } 1080 1081 if (file.exists()) { 1082 return new Resource() { 1083 public String getName() { return name; }; 1084 public URL getURL() { return url; }; 1085 public URL getCodeSourceURL() { return getBaseURL(); }; 1086 public InputStream getInputStream() throws IOException 1087 { return new FileInputStream(file); }; 1088 public int getContentLength() throws IOException 1089 { return (int)file.length(); }; 1090 }; 1091 } 1092 } catch (Exception e) { 1093 return null; 1094 } 1095 return null; 1096 } 1097 } 1098 } | 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 sun.misc; 27 28 import java.util.*; 29 import java.util.concurrent.atomic.AtomicInteger; 30 import java.util.jar.JarFile; 31 import sun.net.www.ParseUtil; 32 import java.util.zip.ZipEntry; 33 import java.util.jar.JarEntry; 34 import java.util.jar.Manifest; 35 import java.util.jar.Attributes; 36 import java.util.jar.Attributes.Name; 37 import java.net.JarURLConnection; 38 import java.net.MalformedURLException; 39 import java.net.URL; 40 import java.net.URLConnection; 41 import java.net.HttpURLConnection; 42 import java.net.URLStreamHandler; 43 import java.net.URLStreamHandlerFactory; 44 import java.io.*; 45 import java.security.AccessController; 46 import java.security.AccessControlException; 47 import java.security.CodeSigner; 48 import java.security.Permission; 49 import java.security.PrivilegedExceptionAction; 50 import java.security.cert.Certificate; 51 52 import jdk.internal.jimage.ImageLocation; 53 import jdk.internal.jimage.ImageReader; 54 55 import sun.net.util.URLUtil; 56 import sun.net.www.protocol.jrt.JavaRuntimeURLConnection; 57 58 /** 59 * This class is used to maintain a search path of URLs for loading classes 60 * and resources from both JAR files and directories. 61 * 62 * @author David Connelly 63 */ 64 public class URLClassPath { 65 private static final String USER_AGENT_JAVA_VERSION = "UA-Java-Version"; 66 private static final String JAVA_HOME; 67 private static final String JAVA_VERSION; 68 private static final boolean DEBUG; 69 private static final boolean DISABLE_JAR_CHECKING; 70 71 static { 72 JAVA_HOME = java.security.AccessController.doPrivileged( 73 new sun.security.action.GetPropertyAction("java.home")); 74 JAVA_VERSION = java.security.AccessController.doPrivileged( 75 new sun.security.action.GetPropertyAction("java.version")); 76 DEBUG = (java.security.AccessController.doPrivileged( 77 new sun.security.action.GetPropertyAction("sun.misc.URLClassPath.debug")) != null); 78 String p = java.security.AccessController.doPrivileged( 79 new sun.security.action.GetPropertyAction("sun.misc.URLClassPath.disableJarChecking")); 80 DISABLE_JAR_CHECKING = p != null ? p.equals("true") || p.equals("") : false; 81 } 82 83 /* The original search path of URLs. */ 84 private ArrayList<URL> path = new ArrayList<URL>(); 85 86 /* The stack of unopened URLs */ 87 Stack<URL> urls = new Stack<URL>(); 88 89 /* The resulting search path of Loaders */ 90 ArrayList<Loader> loaders = new ArrayList<Loader>(); 91 92 /* Map of each URL opened to its corresponding Loader */ 93 HashMap<String, Loader> lmap = new HashMap<String, Loader>(); 351 } 352 return loaders.get(index); 353 } 354 355 /* 356 * Returns the Loader for the specified base URL. 357 */ 358 private Loader getLoader(final URL url) throws IOException { 359 try { 360 return java.security.AccessController.doPrivileged( 361 new java.security.PrivilegedExceptionAction<Loader>() { 362 public Loader run() throws IOException { 363 String file = url.getFile(); 364 if (file != null && file.endsWith("/")) { 365 if ("file".equals(url.getProtocol())) { 366 return new FileLoader(url); 367 } else { 368 return new Loader(url); 369 } 370 } else { 371 if (file != null && "file".equals(url.getProtocol())) { 372 if (file.endsWith(".jimage")) 373 return new JImageLoader(url); 374 } 375 return new JarLoader(url, jarHandler, lmap); 376 } 377 } 378 }); 379 } catch (java.security.PrivilegedActionException pae) { 380 throw (IOException)pae.getException(); 381 } 382 } 383 384 /* 385 * Pushes the specified URLs onto the list of unopened URLs. 386 */ 387 private void push(URL[] us) { 388 synchronized (urls) { 389 for (int i = us.length - 1; i >= 0; --i) { 390 urls.push(us[i]); 391 } 392 } 393 } 394 972 973 // If the count is unchanged, we are done. 974 } while(count < jarFilesList.size()); 975 return null; 976 } 977 978 979 /* 980 * Returns the JAR file local class path, or null if none. 981 */ 982 URL[] getClassPath() throws IOException { 983 if (index != null) { 984 return null; 985 } 986 987 if (metaIndex != null) { 988 return null; 989 } 990 991 ensureOpen(); 992 993 if (SharedSecrets.javaUtilJarAccess().jarFileHasClassPathAttribute(jar)) { // Only get manifest when necessary 994 Manifest man = jar.getManifest(); 995 if (man != null) { 996 Attributes attr = man.getMainAttributes(); 997 if (attr != null) { 998 String value = attr.getValue(Name.CLASS_PATH); 999 if (value != null) { 1000 return parseClassPath(csu, value); 1001 } 1002 } 1003 } 1004 } 1005 return null; 1006 } 1007 1008 /* 1009 * Parses value of the Class-Path manifest attribute and returns 1010 * an array of URLs relative to the specified base URL. 1011 */ 1012 private URL[] parseClassPath(URL base, String value) 1013 throws MalformedURLException 1014 { 1015 StringTokenizer st = new StringTokenizer(value); 1016 URL[] urls = new URL[st.countTokens()]; 1017 int i = 0; 1018 while (st.hasMoreTokens()) { 1019 String path = st.nextToken(); 1020 urls[i] = new URL(base, path); 1021 i++; 1022 } 1023 return urls; 1024 } 1025 } 1026 1027 /* 1028 * Inner class used to represent a loader of classes and resources 1079 file = new File(dir, name.replace('/', File.separatorChar)); 1080 } 1081 1082 if (file.exists()) { 1083 return new Resource() { 1084 public String getName() { return name; }; 1085 public URL getURL() { return url; }; 1086 public URL getCodeSourceURL() { return getBaseURL(); }; 1087 public InputStream getInputStream() throws IOException 1088 { return new FileInputStream(file); }; 1089 public int getContentLength() throws IOException 1090 { return (int)file.length(); }; 1091 }; 1092 } 1093 } catch (Exception e) { 1094 return null; 1095 } 1096 return null; 1097 } 1098 } 1099 1100 /** 1101 * A Loader of classes and resources from a jimage file located in the 1102 * runtime image. 1103 */ 1104 private static class JImageLoader 1105 extends Loader implements JavaRuntimeURLConnection.ResourceFinder 1106 { 1107 private static final AtomicInteger NEXT_INDEX = new AtomicInteger(); 1108 1109 private final ImageReader jimage; 1110 private final int index; 1111 1112 JImageLoader(URL url) throws IOException { 1113 super(url); 1114 1115 // get path to image file and check that it's in the runtime 1116 String urlPath = url.getFile().replace('/', File.separatorChar); 1117 1118 File filePath = new File(ParseUtil.decode(urlPath)); 1119 File home = new File(JAVA_HOME); 1120 File parent = filePath.getParentFile(); 1121 while (parent != null) { 1122 if (parent.equals(home)) 1123 break; 1124 parent = parent.getParentFile(); 1125 } 1126 if (parent == null) 1127 throw new IOException(filePath + " not in runtime image"); 1128 1129 this.jimage = ImageReader.open(filePath.toString()); 1130 this.index = NEXT_INDEX.getAndIncrement(); 1131 1132 // register with the jimage protocol handler 1133 JavaRuntimeURLConnection.register(this); 1134 } 1135 1136 /** 1137 * Maps the given resource name to a module. 1138 */ 1139 private String nameToModule(String name) { 1140 int pos = name.lastIndexOf('/'); 1141 if (pos > 0) { 1142 String pkg = name.substring(0, pos); 1143 String module = jimage.getModule(pkg); 1144 if (module != null) 1145 return module; 1146 } 1147 // cannot map to module 1148 return "UNNAMED" + index; 1149 } 1150 1151 /** 1152 * Constructs a URL for the resource name. 1153 */ 1154 private URL toURL(String name) { 1155 String module = nameToModule(name); 1156 String encodedName = ParseUtil.encodePath(name, false); 1157 try { 1158 return new URL("jrt:/" + module + "/" + encodedName); 1159 } catch (MalformedURLException e) { 1160 throw new InternalError(e); 1161 } 1162 } 1163 1164 @Override 1165 URL findResource(String name, boolean check) { 1166 ImageLocation location = jimage.findLocation(name); 1167 if (location == null) 1168 return null; 1169 URL url = toURL(name); 1170 if (check) { 1171 try { 1172 URLClassPath.check(url); 1173 } catch (IOException | SecurityException e) { 1174 return null; 1175 } 1176 } 1177 return url; 1178 } 1179 1180 @Override 1181 Resource getResource(String name, boolean check) { 1182 ImageLocation location = jimage.findLocation(name); 1183 if (location == null) 1184 return null; 1185 URL url = toURL(name); 1186 if (check) { 1187 try { 1188 URLClassPath.check(url); 1189 } catch (IOException | SecurityException e) { 1190 return null; 1191 } 1192 } 1193 return new Resource() { 1194 @Override 1195 public String getName() { return name; } 1196 @Override 1197 public URL getURL() { return url; } 1198 @Override 1199 public URL getCodeSourceURL() { 1200 try { 1201 return new URL("jrt:/" + nameToModule(name)); 1202 } catch (MalformedURLException e) { 1203 throw new InternalError(e); 1204 } 1205 } 1206 @Override 1207 public InputStream getInputStream() throws IOException { 1208 byte[] resource = jimage.getResource(location); 1209 return new ByteArrayInputStream(resource); 1210 } 1211 public int getContentLength() { 1212 long size = location.getUncompressedSize(); 1213 return (size > Integer.MAX_VALUE) ? -1 : (int)size; 1214 } 1215 }; 1216 } 1217 1218 @Override 1219 public void close() { 1220 throw new UnsupportedOperationException(); 1221 } 1222 1223 @Override 1224 public Resource find(String module, String name) throws IOException { 1225 String m = nameToModule(name); 1226 if (!m.equals(module)) 1227 return null; 1228 // URLConnection will do the permission check 1229 return getResource(name, false); 1230 } 1231 } 1232 } |