Allow serving static files in subdirectories

Change-Id: I82447dd9ce47ffc44727d9f886a45a9fa1a2463e
Signed-Off-By: James Y Knight <jyknight@google.com>
(cherry picked from commit b8ddd05fbf)
This commit is contained in:
James Y Knight
2011-05-17 11:45:37 -04:00
committed by Shawn O. Pearce
parent 183d0f865a
commit 7bb1f97b98

View File

@@ -89,34 +89,53 @@ public class StaticServlet extends HttpServlet {
} }
private final File staticBase; private final File staticBase;
private final String staticBasePath;
@Inject @Inject
StaticServlet(final SitePaths site) { StaticServlet(final SitePaths site) {
staticBase = site.static_dir; File f;
try {
f = site.static_dir.getCanonicalFile();
} catch (IOException e) {
f = site.static_dir.getAbsoluteFile();
}
staticBase = f;
staticBasePath = staticBase.getPath() + File.separator;
} }
private File local(final HttpServletRequest req) { private File local(final HttpServletRequest req) {
final String name = req.getPathInfo(); final String name = req.getPathInfo();
if (name.length() < 2 || !name.startsWith("/")) { if (name.length() < 2 || !name.startsWith("/") || isUnreasonableName(name)) {
// Too short to be a valid file name, or doesn't start with // Too short to be a valid file name, or doesn't start with
// the path info separator like we expected. // the path info separator like we expected.
// //
return null; return null;
} }
if (name.indexOf('/', 1) > 0 || name.indexOf('\\', 1) > 0) { final File p = new File(staticBase, name.substring(1));
// Contains a path separator. Don't serve it as the client
// might be trying something evil like "/../../etc/passwd". // Ensure that the requested file is *actually* within the static dir base.
// This static servlet is just meant to facilitate simple try {
// assets like banner images. if (!p.getCanonicalFile().getPath().startsWith(staticBasePath))
// return null;
} catch (IOException e) {
return null; return null;
} }
final File p = new File(staticBase, name.substring(1));
return p.isFile() ? p : null; return p.isFile() ? p : null;
} }
private static boolean isUnreasonableName(String name) {
if (name.charAt(name.length() -1) == '/') return true; // no suffix
if (name.indexOf('\\') >= 0) return true; // no windows/dos stlye paths
if (name.startsWith("../")) return true; // no "../etc/passwd"
if (name.contains("/../")) return true; // no "foo/../etc/passwd"
if (name.contains("/./")) return true; // "foo/./foo" is insane to ask
if (name.contains("//")) return true; // windows UNC path can be "//..."
return false; // is a reasonable name
}
@Override @Override
protected long getLastModified(final HttpServletRequest req) { protected long getLastModified(final HttpServletRequest req) {
final File p = local(req); final File p = local(req);