Tomcat provided static content

I am doing a service that, among others, has the function "photo albums", which serves users for photos. The user must "allow" to see the photo from the album. Therefore, sending a direct link to another person should not allow you to view the photo.

Photos are stored in a folder out of context.

What I need to do is perform some checks when the user requests a photo, and then, if the checks are in order, they serve the file. I want to avoid creating a wheel and just let tomcat serve the image, as is usually done for static files. Can you give some advice on this?

+6
java-ee security tomcat servlets
source share
1 answer

Ok guys.

After difficulties with this question, I think I finally figured out what to do to solve this problem. First of all, it seems that the question actually decomposes into two independent tasks. One of them is providing access to some resources, and the second is loading resources from a folder out of context.

The first task is trivial and can be solved by writing a simple filter placed in "/".

The second task is much less trivial, but, fortunately, can also be solved. Tomcat uses the javax.naming.directory.DirContext implementation to download all the resources of this web application, including class files. It also allows you to provide a custom implementation of this interface and configure it in the context.xml file. The default implementation is org.apache.naming.resources.FileDirContext. Details here: http://tomcat.apache.org/tomcat-6.0-doc/config/resources.html

I created my own implementation of DirContext by simply extending FileDirContext. Fortunately, there was one method that had to be rewritten in order to β€œplug in” file detection. This method is called file ().

I post my test code here. It is far from ideal and does not take into account angular cases, such as renaming files, but I do not think that they are necessary for a normal server run.

The main idea of ​​this code is to check if the path begins with the prefix "virtual directory" and if it is to search for the file elsewhere in the file system (I know that there is a duplicate of the code, but I hope that you " It is not so lazy to delete if you ever want to use it :-). SetVirtualName and setVirtualBase are called automatically to enter configuration parameters.

/** * TODO: add javadocs * * @author Juriy Bura */ public class VirtualFolderDirContext extends FileDirContext { private String virtualName; private String realName; private File virtualBase; private String absoluteVirtualBase; public VirtualFolderDirContext() { super(); } public VirtualFolderDirContext(Hashtable env) { super(env); } public void setVirtualName(String path) { virtualName = path; } public void setVirtualBase(String base) { this.realName = base; virtualBase = new File(realName); try { virtualBase = virtualBase.getCanonicalFile(); } catch (IOException e) { // Ignore } this.absoluteVirtualBase = virtualBase.getAbsolutePath(); } protected File file(String name) { File file = null; boolean virtualFile = name.startsWith(virtualName + "/"); if (virtualFile) { file = new File(virtualBase, name.substring(virtualName.length())); } else { file = new File(base, name); } if (file.exists() && file.canRead()) { if (allowLinking) return file; // Check that this file belongs to our root path String canPath = null; try { canPath = file.getCanonicalPath(); } catch (IOException e) { } if (canPath == null) return null; // Check to see if going outside of the web application root if (!canPath.startsWith(absoluteBase) && !canPath.startsWith(absoluteVirtualBase)) { return null; } // Case sensitivity check if (caseSensitive) { String fileAbsPath = file.getAbsolutePath(); if (fileAbsPath.endsWith(".")) fileAbsPath = fileAbsPath + "/"; String absPath = normalize(fileAbsPath); if (canPath != null) canPath = normalize(canPath); if (virtualFile) { if ((absoluteVirtualBase.length() < absPath.length()) && (absoluteVirtualBase.length() < canPath.length())) { absPath = absPath.substring(absoluteVirtualBase.length() + 1); if ((canPath == null) || (absPath == null)) return null; if (absPath.equals("")) absPath = "/"; canPath = canPath.substring(absoluteVirtualBase.length() + 1); if (canPath.equals("")) canPath = "/"; if (!canPath.equals(absPath)) return null; } } else { if ((absoluteBase.length() < absPath.length()) && (absoluteBase.length() < canPath.length())) { absPath = absPath.substring(absoluteBase.length() + 1); if ((canPath == null) || (absPath == null)) return null; if (absPath.equals("")) absPath = "/"; canPath = canPath.substring(absoluteBase.length() + 1); if (canPath.equals("")) canPath = "/"; if (!canPath.equals(absPath)) return null; } } } } else { return null; } return file; } } 

Once you have this class, you must compile it and put this jar in the Tomcat lib folder. For obvious reasons, it cannot be combined with a war file. In your .xml context, you should add configuration lines like these:

 <?xml version="1.0" encoding="UTF-8"?> <Context antiResourceLocking="true" antiJARLocking="true"> <Resources className="com.juriy.tomcat.virtualdir.VirtualFolderDirContext" virtualName="/upload" virtualBase="c:/temp/up"> </Resources> ... ... 

Now when the user requests / upload /, he will be allowed c: \ temp. Using this technology, you can implement resource loading from almost anywhere: http, a shared folder, a database, and even a version control system. So it's pretty cool.

PS I killed all day so that it all worked together, so feel free to give me your vote if you like the answer :-))

Greetings

Juriy

+8
source share

All Articles