1 /*
2 * Copyright (c) 1997, 2018, 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
1075 return parseClassPath(csu, value);
1076 }
1077 }
1078 }
1079 }
1080 return null;
1081 }
1082
1083 /*
1084 * Parses value of the Class-Path manifest attribute and returns
1085 * an array of URLs relative to the specified base URL.
1086 */
1087 private static URL[] parseClassPath(URL base, String value)
1088 throws MalformedURLException
1089 {
1090 StringTokenizer st = new StringTokenizer(value);
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 }
|
1 /*
2 * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
1075 return parseClassPath(csu, value);
1076 }
1077 }
1078 }
1079 }
1080 return null;
1081 }
1082
1083 /*
1084 * Parses value of the Class-Path manifest attribute and returns
1085 * an array of URLs relative to the specified base URL.
1086 */
1087 private static URL[] parseClassPath(URL base, String value)
1088 throws MalformedURLException
1089 {
1090 StringTokenizer st = new StringTokenizer(value);
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) : tryResolve(base, path);
1096 if (url != null) {
1097 urls[i] = url;
1098 i++;
1099 } else {
1100 if (DEBUG_CP_URL_CHECK) {
1101 System.err.println("Class-Path entry: \"" + path
1102 + "\" ignored in JAR file " + base);
1103 }
1104 }
1105 }
1106 if (i == 0) {
1107 urls = null;
1108 } else if (i != urls.length) {
1109 // Truncate nulls from end of array
1110 urls = Arrays.copyOf(urls, i);
1111 }
1112 return urls;
1113 }
1114
1115
1116 static URL tryResolve(URL base, String input) throws MalformedURLException {
1117 if ("file".equalsIgnoreCase(base.getProtocol())) {
1118 return tryResolveFile(base, input);
1119 } else {
1120 return tryResolveNonFile(base, input);
1121 }
1122 }
1123
1124 /**
1125 * Attempt to return a file URL by resolving input against a base file
1126 * URL. The input is an absolute or relative file URL that encodes a
1127 * file path.
1128 *
1129 * @apiNote Nonsensical input such as a Windows file path with a drive
1130 * letter cannot be disambiguated from an absolute URL so will be rejected
1131 * (by returning null) by this method.
1132 *
1133 * @return the resolved URL or null if the input is an absolute URL with
1134 * a scheme other than file (ignoring case)
1135 * @throws MalformedURLException
1136 */
1137 static URL tryResolveFile(URL base, String input) throws MalformedURLException {
1138 int index = input.indexOf(':');
1139 boolean isFile;
1140 if (index >= 0) {
1141 String scheme = input.substring(0, index);
1142 isFile = "file".equalsIgnoreCase(scheme);
1143 } else {
1144 isFile = true;
1145 }
1146 return (isFile) ? new URL(base, input) : null;
1147 }
1148
1149 /**
1150 * Attempt to return a URL by resolving input against a base URL. Returns
1151 * null if the resolved URL is not contained by the base URL.
1152 *
1153 * @return the resolved URL or null
1154 * @throws MalformedURLException
1155 */
1156 static URL tryResolveNonFile(URL base, String input) throws MalformedURLException {
1157 String child = input.replace(File.separatorChar, '/');
1158 if (isRelative(child)) {
1159 URL url = new URL(base, child);
1160 String bp = base.getPath();
1161 String urlp = url.getPath();
1162 int pos = bp.lastIndexOf('/');
1163 if (pos == -1) {
1164 pos = bp.length() - 1;
1165 }
1166 if (urlp.regionMatches(0, bp, 0, pos + 1)
1167 && urlp.indexOf("..", pos) == -1) {
1168 return url;
1169 }
1170 }
1171 return null;
1172 }
1173
1174 /**
1175 * Returns true if the given input is a relative URI.
1176 */
1177 static boolean isRelative(String child) {
1178 try {
1179 return !URI.create(child).isAbsolute();
1180 } catch (IllegalArgumentException e) {
1181 return false;
1182 }
1183 }
1184 }
1185
1186 /*
1187 * Nested class used to represent a loader of classes and resources
1188 * from a file URL that refers to a directory.
1189 */
1190 private static class FileLoader extends Loader {
1191 /* Canonicalized File */
1192 private File dir;
1193
1194 FileLoader(URL url) throws IOException {
1195 super(url);
1196 if (!"file".equals(url.getProtocol())) {
1197 throw new IllegalArgumentException("url");
1198 }
1199 String path = url.getFile().replace('/', File.separatorChar);
1200 path = ParseUtil.decode(path);
1201 dir = (new File(path)).getCanonicalFile();
1202 }
|