Skip to content

Commit

Permalink
fix: Don't serve directories as static files (#12514)
Browse files Browse the repository at this point in the history
Modified and simplified from #12325 to work with Java 6.
  • Loading branch information
TatuLund authored Feb 8, 2022
1 parent 85bbd90 commit 2790b45
Show file tree
Hide file tree
Showing 3 changed files with 654 additions and 1 deletion.
118 changes: 117 additions & 1 deletion server/src/main/java/com/vaadin/server/VaadinServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.io.Serializable;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
Expand All @@ -44,6 +45,9 @@
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
Expand Down Expand Up @@ -1141,7 +1145,8 @@ private ScssCacheEntry compileScssOnTheFly(String filename,

/**
* Check whether a URL obtained from a classloader refers to a valid static
* resource in the directory VAADIN.
* resource in the directory VAADIN. Directories do not count as valid
* resources.
*
* Warning: Overriding of this method is not recommended, but is possible to
* support non-default classloaders or servers that may produce URLs
Expand All @@ -1161,6 +1166,9 @@ private ScssCacheEntry compileScssOnTheFly(String filename,
@Deprecated
protected boolean isAllowedVAADINResourceUrl(HttpServletRequest request,
URL resourceUrl) {
if (resourceUrl == null || resourceIsDirectory(resourceUrl)) {
return false;
}
String resourcePath = resourceUrl.getPath();
if ("jar".equals(resourceUrl.getProtocol())) {
// This branch is used for accessing resources directly from the
Expand Down Expand Up @@ -1201,6 +1209,114 @@ protected boolean isAllowedVAADINResourceUrl(HttpServletRequest request,
}
}

private boolean resourceIsDirectory(URL resource) {
if (resource.getPath().endsWith("/")) {
return true;
}
URI resourceURI = null;
boolean isDirectory = false;
try {
resourceURI = resource.toURI();
} catch (URISyntaxException e) {
getLogger().log(Level.FINE,
"Syntax error in uri from getStaticResource", e);
// Return false as we couldn't determine if the resource is a
// directory.
return false;
}

if ("jar".equals(resource.getProtocol())) {
// Get the file path in jar

String[] parts = resource.getPath().split("!");
String pathInJar = null;
String pathOfWar = null;
String pathOfJar = null;
if (parts.length == 2) {
pathInJar = parts[1].substring(1);
pathOfJar = parts[0].substring(8);

} else if (resource.getPath().startsWith("file:")) {
pathInJar = parts[2].substring(1);
pathOfJar = parts[1].substring(1);
pathOfWar = parts[0].substring(6);
} else {
pathInJar = parts[2].substring(1);
pathOfJar = parts[1].substring(1);
pathOfWar = parts[0].substring(10);
}
try {
// Jars and wars are zip files, hence we use ZipFile to parse
// them. Java 6 does not have virtual filesystems.
ZipEntry entry = null;
if (pathOfWar == null) {
entry = getJarEntry(pathOfJar, pathInJar);
} else {
entry = getWarEntry(pathOfWar, pathOfJar, pathInJar);
}
if (entry != null) {
isDirectory = entry.isDirectory();
}
return isDirectory;
} catch (IOException e) {
// Return false as we couldn't determine if the resource is a
// directory.
return false;
}
}
// If not a jar check if a file path directory.
File file = new File(resourceURI);
return "file".equals(resource.getProtocol()) && file.isDirectory();
}

// Find entry pathInJar within nested jar pathOfJar within war pathOfWar.
private ZipEntry getWarEntry(String pathOfWar, String pathOfJar,
String pathInJar) throws IOException {
ZipFile war = null;
ZipInputStream stream = null;
try {
// Use ZipInputStream for nested jar files
war = new ZipFile(pathOfWar);
ZipEntry jarEntry = war.getEntry(pathOfJar);
InputStream in = war.getInputStream(jarEntry);
stream = new ZipInputStream(in);
return findEntry(stream, pathInJar);
} finally {
if (stream != null) {
stream.close();
}
if (war != null) {
war.close();
}
}
}

// Find entry pathInJar within jar pathOfJar.
private ZipEntry getJarEntry(String pathOfJar, String pathInJar)
throws IOException {
ZipFile jar = null;
try {
jar = new ZipFile(pathOfJar);
return jar.getEntry(pathInJar);
} finally {
if (jar != null) {
jar.close();
}
}
}

// Traverse zip's header table for entries and return entry matching name.
private ZipEntry findEntry(ZipInputStream in, String name)
throws IOException {
ZipEntry entry = null;
while ((entry = in.getNextEntry()) != null) {
if (entry.getName().equals(name)) {
return entry;
}
}
return null;
}

/**
* Checks if the browser has an up to date cached version of requested
* resource. Currently the check is performed using the "If-Modified-Since"
Expand Down
Loading

0 comments on commit 2790b45

Please sign in to comment.