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