Skip to content

Commit 2790b45

Browse files
authored
fix: Don't serve directories as static files (#12514)
Modified and simplified from #12325 to work with Java 6.
1 parent 85bbd90 commit 2790b45

File tree

3 files changed

+654
-1
lines changed

3 files changed

+654
-1
lines changed

server/src/main/java/com/vaadin/server/VaadinServlet.java

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.io.Serializable;
2929
import java.lang.reflect.Method;
3030
import java.net.MalformedURLException;
31+
import java.net.URI;
3132
import java.net.URISyntaxException;
3233
import java.net.URL;
3334
import java.net.URLConnection;
@@ -44,6 +45,9 @@
4445
import java.util.Properties;
4546
import java.util.logging.Level;
4647
import java.util.logging.Logger;
48+
import java.util.zip.ZipEntry;
49+
import java.util.zip.ZipFile;
50+
import java.util.zip.ZipInputStream;
4751

4852
import javax.servlet.ServletContext;
4953
import javax.servlet.ServletException;
@@ -1141,7 +1145,8 @@ private ScssCacheEntry compileScssOnTheFly(String filename,
11411145

11421146
/**
11431147
* Check whether a URL obtained from a classloader refers to a valid static
1144-
* resource in the directory VAADIN.
1148+
* resource in the directory VAADIN. Directories do not count as valid
1149+
* resources.
11451150
*
11461151
* Warning: Overriding of this method is not recommended, but is possible to
11471152
* support non-default classloaders or servers that may produce URLs
@@ -1161,6 +1166,9 @@ private ScssCacheEntry compileScssOnTheFly(String filename,
11611166
@Deprecated
11621167
protected boolean isAllowedVAADINResourceUrl(HttpServletRequest request,
11631168
URL resourceUrl) {
1169+
if (resourceUrl == null || resourceIsDirectory(resourceUrl)) {
1170+
return false;
1171+
}
11641172
String resourcePath = resourceUrl.getPath();
11651173
if ("jar".equals(resourceUrl.getProtocol())) {
11661174
// This branch is used for accessing resources directly from the
@@ -1201,6 +1209,114 @@ protected boolean isAllowedVAADINResourceUrl(HttpServletRequest request,
12011209
}
12021210
}
12031211

1212+
private boolean resourceIsDirectory(URL resource) {
1213+
if (resource.getPath().endsWith("/")) {
1214+
return true;
1215+
}
1216+
URI resourceURI = null;
1217+
boolean isDirectory = false;
1218+
try {
1219+
resourceURI = resource.toURI();
1220+
} catch (URISyntaxException e) {
1221+
getLogger().log(Level.FINE,
1222+
"Syntax error in uri from getStaticResource", e);
1223+
// Return false as we couldn't determine if the resource is a
1224+
// directory.
1225+
return false;
1226+
}
1227+
1228+
if ("jar".equals(resource.getProtocol())) {
1229+
// Get the file path in jar
1230+
1231+
String[] parts = resource.getPath().split("!");
1232+
String pathInJar = null;
1233+
String pathOfWar = null;
1234+
String pathOfJar = null;
1235+
if (parts.length == 2) {
1236+
pathInJar = parts[1].substring(1);
1237+
pathOfJar = parts[0].substring(8);
1238+
1239+
} else if (resource.getPath().startsWith("file:")) {
1240+
pathInJar = parts[2].substring(1);
1241+
pathOfJar = parts[1].substring(1);
1242+
pathOfWar = parts[0].substring(6);
1243+
} else {
1244+
pathInJar = parts[2].substring(1);
1245+
pathOfJar = parts[1].substring(1);
1246+
pathOfWar = parts[0].substring(10);
1247+
}
1248+
try {
1249+
// Jars and wars are zip files, hence we use ZipFile to parse
1250+
// them. Java 6 does not have virtual filesystems.
1251+
ZipEntry entry = null;
1252+
if (pathOfWar == null) {
1253+
entry = getJarEntry(pathOfJar, pathInJar);
1254+
} else {
1255+
entry = getWarEntry(pathOfWar, pathOfJar, pathInJar);
1256+
}
1257+
if (entry != null) {
1258+
isDirectory = entry.isDirectory();
1259+
}
1260+
return isDirectory;
1261+
} catch (IOException e) {
1262+
// Return false as we couldn't determine if the resource is a
1263+
// directory.
1264+
return false;
1265+
}
1266+
}
1267+
// If not a jar check if a file path directory.
1268+
File file = new File(resourceURI);
1269+
return "file".equals(resource.getProtocol()) && file.isDirectory();
1270+
}
1271+
1272+
// Find entry pathInJar within nested jar pathOfJar within war pathOfWar.
1273+
private ZipEntry getWarEntry(String pathOfWar, String pathOfJar,
1274+
String pathInJar) throws IOException {
1275+
ZipFile war = null;
1276+
ZipInputStream stream = null;
1277+
try {
1278+
// Use ZipInputStream for nested jar files
1279+
war = new ZipFile(pathOfWar);
1280+
ZipEntry jarEntry = war.getEntry(pathOfJar);
1281+
InputStream in = war.getInputStream(jarEntry);
1282+
stream = new ZipInputStream(in);
1283+
return findEntry(stream, pathInJar);
1284+
} finally {
1285+
if (stream != null) {
1286+
stream.close();
1287+
}
1288+
if (war != null) {
1289+
war.close();
1290+
}
1291+
}
1292+
}
1293+
1294+
// Find entry pathInJar within jar pathOfJar.
1295+
private ZipEntry getJarEntry(String pathOfJar, String pathInJar)
1296+
throws IOException {
1297+
ZipFile jar = null;
1298+
try {
1299+
jar = new ZipFile(pathOfJar);
1300+
return jar.getEntry(pathInJar);
1301+
} finally {
1302+
if (jar != null) {
1303+
jar.close();
1304+
}
1305+
}
1306+
}
1307+
1308+
// Traverse zip's header table for entries and return entry matching name.
1309+
private ZipEntry findEntry(ZipInputStream in, String name)
1310+
throws IOException {
1311+
ZipEntry entry = null;
1312+
while ((entry = in.getNextEntry()) != null) {
1313+
if (entry.getName().equals(name)) {
1314+
return entry;
1315+
}
1316+
}
1317+
return null;
1318+
}
1319+
12041320
/**
12051321
* Checks if the browser has an up to date cached version of requested
12061322
* resource. Currently the check is performed using the "If-Modified-Since"

0 commit comments

Comments
 (0)