Хорошо, ребята.
После борьбы трудно с этим вопросом, я думаю, что я наконец-то узнал, что нужно сделать, чтобы решить эту проблему. Прежде всего, похоже, что вопрос на самом деле разбивается на две независимые задачи. Один из них - защита доступа к некоторым ресурсам, а второй - подача ресурсов из папки вне контекста.
Первая задача тривиальна, и ее можно решить, написав простой фильтр, привязанный к "/".
Вторая задача гораздо менее тривиальна, но, к счастью, также может быть решена. Tomcat использует реализацию javax.naming.directory.DirContext для загрузки всех ресурсов данного веб-приложения, включая файлы классов. Это также позволяет вам предоставить пользовательскую реализацию этого интерфейса и настроить его в файле context.xml. Реализация по умолчанию - org.apache.naming.resources.FileDirContext. Подробности здесь: http://tomcat.apache.org/tomcat-6.0-doc/config/resources.html
Я создал собственную реализацию DirContext, просто расширив FileDirContext. К счастью, был один метод, который нужно было перезаписать, чтобы «подключить» обнаружение файлов. Метод называется file ().
Я публикую здесь свой тестовый код. Он далек от совершенства и не учитывает такие крайние случаи, как переименование файлов, но я не думаю, что они необходимы при нормальной работе сервера.
Основная идея этого кода состоит в том, чтобы проверить, начинается ли путь с префикса «виртуального каталога», и если это так - искать файл в другом месте файловой системы (я знаю, что там есть некоторый дублирующий код, но я надеюсь, что вы не лень его удалить, если вы когда-нибудь захотите его использовать :-). setVirtualName и setVirtualBase вызываются автоматически для ввода параметров конфигурации.
/**
* 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;
}
}
После того, как у вас есть этот класс, вы должны поставить его в JAR-папку Tomcat. По понятным причинам он не может сочетаться с военным файлом. В вашем context.xml вы должны добавить строки конфигурации, подобные этим:
<?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>
...
...
Теперь каждый раз, когда пользователь запрашивает / upload /, он будет преобразован в c: \ temp. С помощью этой техники вы можете осуществлять загрузку ресурсов практически из любого места: http, общая папка, база данных, даже система контроля версий. Так что это довольно круто.
P.S. Я убил целый день, чтобы все это работало вместе, так что не стесняйтесь отдать мне свой голос, если вам нравится ответ: -))
Приветствия
Juriy