Allow for Aliases at the resource level.
authorfunkman <funkman@13f79535-47bb-0310-9956-ffa450edef68>
Thu, 13 Sep 2007 15:19:59 +0000 (15:19 +0000)
committerfunkman <funkman@13f79535-47bb-0310-9956-ffa450edef68>
Thu, 13 Sep 2007 15:19:59 +0000 (15:19 +0000)
This is to prevent situations of relying on symlinks, or Filters
while still make outside directories appear as part of the webapp.
(A common feature request seen on the user list)

Example usage:
<Context ... >
  <Resources className="org.apache.naming.resources.FileDirContext"
               aliases="/doh/=C:/tmp/woohoo/,
                        /mmmmmm/=C:/opt/data/doughnuts/" />
</Context>

If the feature is NOT used - there is no additional overhead.

git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk@575332 13f79535-47bb-0310-9956-ffa450edef68

java/org/apache/naming/resources/FileDirContext.java
webapps/docs/changelog.xml

index ddb40fe..033364c 100644 (file)
@@ -108,6 +108,17 @@ public class FileDirContext extends BaseDirContext {
     protected boolean allowLinking = false;
 
 
+    /**
+     * Aliases
+     */
+    protected String aliases;
+
+
+    /**
+     * Aliases in decoded form.
+     */
+    protected Alias[] pathAliases;
+
     // ------------------------------------------------------------- Properties
 
 
@@ -123,22 +134,22 @@ public class FileDirContext extends BaseDirContext {
      */
     public void setDocBase(String docBase) {
 
-    // Validate the format of the proposed document root
-    if (docBase == null)
-        throw new IllegalArgumentException
-        (sm.getString("resources.null"));
+        // Validate the format of the proposed document root
+        if (docBase == null)
+            throw new IllegalArgumentException
+            (sm.getString("resources.null"));
 
-    // Calculate a File object referencing this document base directory
-    base = new File(docBase);
+        // Calculate a File object referencing this document base directory
+        base = new File(docBase);
         try {
             base = base.getCanonicalFile();
         } catch (IOException e) {
             // Ignore
         }
 
-    // Validate that the document base is an existing directory
-    if (!base.exists() || !base.isDirectory() || !base.canRead())
-        throw new IllegalArgumentException
+        // Validate that the document base is an existing directory
+        if (!base.exists() || !base.isDirectory() || !base.canRead())
+            throw new IllegalArgumentException
         (sm.getString("fileResources.base", docBase));
         this.absoluteBase = base.getAbsolutePath();
         super.setDocBase(docBase);
@@ -177,18 +188,69 @@ public class FileDirContext extends BaseDirContext {
         return allowLinking;
     }
 
-
-    // --------------------------------------------------------- Public Methods
+    /**
+     * Get the alias string in use.
+     */
+    public String getAliases(String aliases) {
+        return aliases;
+    }
 
 
     /**
-     * Release any resources allocated for this directory context.
+     * Set files system aliases. Aliases are of the form
+     * <pre>prefix=path,prefix2=path2</pre>
+     * For example: 
+     * <pre>
+     *   /images/=/tmp/images/,
+     *   /pdf/=/usr/local/data/pdfs/
+     * </pre>
      */
-    public void release() {
-        super.release();
+    public void setAliases(String aliases) {
+        this.aliases = aliases;
+
+        pathAliases = null;
+        if (this.aliases!=null) {
+            this.aliases = this.aliases.trim();
+        }
+        if (this.aliases==null||this.aliases.length()==0) {
+            this.aliases=null;
+            return;
+        }
+
+        String[] split1 = this.aliases.split(",");
+        ArrayList aliasList = new ArrayList();
+        for (int i=0; split1!=null && i<split1.length; i++) {
+            String[] kvp = split1[i].split("=");
+            if (kvp!=null&&kvp.length==2) {
+                kvp[0] = kvp[0].trim();
+                kvp[1] = kvp[1].trim();
+
+                if (kvp[0].length()>0 && kvp[1].length()>0) {
+                    Alias alias = new Alias();
+                    alias.prefix=kvp[0];
+                    alias.basePath= new File(kvp[1]);
+                    alias.absPath=alias.basePath.getAbsolutePath();
+                    aliasList.add(alias);
+                }
+            }
+        }
+
+        if (aliasList.size()>0) {
+            pathAliases = new Alias[aliasList.size()];
+            for (int i=0; i<aliasList.size(); i++) {
+                pathAliases[i] = (Alias)aliasList.get(i);
+            }
+        } else {
+            this.aliases=null;
+        }
     }
 
 
+    // --------------------------------------------------------- Public Methods
+
+
+
+
     // -------------------------------------------------------- Context Methods
 
 
@@ -273,7 +335,20 @@ public class FileDirContext extends BaseDirContext {
             throw new NamingException
                 (sm.getString("resources.notFound", oldName));
 
-        File newFile = new File(base, newName);
+        File baseDir = base;
+        String absoluteBaseDir = absoluteBase;
+
+        if (pathAliases!=null) {
+            for (int i=0; i<pathAliases.length; i++) {
+                if (newName.startsWith(pathAliases[i].prefix)) {
+                    baseDir = pathAliases[i].basePath;
+                    newName = newName.substring(pathAliases[i].prefix.length());
+                    break;
+                }
+            }
+        }
+
+        File newFile = new File(baseDir, newName);
 
         file.renameTo(newFile);
 
@@ -495,8 +570,19 @@ public class FileDirContext extends BaseDirContext {
         throws NamingException {
 
         // Note: No custom attributes allowed
+        File baseDir = base;
+
+        if (pathAliases!=null) {
+            for (int i=0; i<pathAliases.length; i++) {
+                if (name.startsWith(pathAliases[i].prefix)) {
+                    baseDir = pathAliases[i].basePath;
+                    name = name.substring(pathAliases[i].prefix.length());
+                    break;
+                }
+            }
+        }
 
-        File file = new File(base, name);
+        File file = new File(baseDir, name);
         if (file.exists())
             throw new NameAlreadyBoundException
                 (sm.getString("resources.alreadyBound", name));
@@ -530,7 +616,19 @@ public class FileDirContext extends BaseDirContext {
         // Note: No custom attributes allowed
         // Check obj type
 
-        File file = new File(base, name);
+        File baseDir = base;
+
+        if (pathAliases!=null) {
+            for (int i=0; i<pathAliases.length; i++) {
+                if (name.startsWith(pathAliases[i].prefix)) {
+                    baseDir = pathAliases[i].basePath;
+                    name = name.substring(pathAliases[i].prefix.length());
+                    break;
+                }
+            }
+        }
+
+        File file = new File(baseDir, name);
 
         InputStream is = null;
         if (obj instanceof Resource) {
@@ -601,7 +699,19 @@ public class FileDirContext extends BaseDirContext {
     public DirContext createSubcontext(String name, Attributes attrs)
         throws NamingException {
 
-        File file = new File(base, name);
+        File baseDir = base;
+
+        if (pathAliases!=null) {
+            for (int i=0; i<pathAliases.length; i++) {
+                if (name.startsWith(pathAliases[i].prefix)) {
+                    baseDir = pathAliases[i].basePath;
+                    name = name.substring(pathAliases[i].prefix.length());
+                    break;
+                }
+            }
+        }
+
+        File file = new File(baseDir, name);
         if (file.exists())
             throw new NameAlreadyBoundException
                 (sm.getString("resources.alreadyBound", name));
@@ -765,46 +875,46 @@ public class FileDirContext extends BaseDirContext {
      */
     protected String normalize(String path) {
 
-    String normalized = path;
-
-    // Normalize the slashes and add leading slash if necessary
-    if (File.separatorChar == '\\' && normalized.indexOf('\\') >= 0)
-        normalized = normalized.replace('\\', '/');
-    if (!normalized.startsWith("/"))
-        normalized = "/" + normalized;
-
-    // Resolve occurrences of "//" in the normalized path
-    while (true) {
-        int index = normalized.indexOf("//");
-        if (index < 0)
-        break;
-        normalized = normalized.substring(0, index) +
-        normalized.substring(index + 1);
-    }
+        String normalized = path;
+
+        // Normalize the slashes and add leading slash if necessary
+        if (File.separatorChar == '\\' && normalized.indexOf('\\') >= 0)
+            normalized = normalized.replace('\\', '/');
+        if (!normalized.startsWith("/"))
+            normalized = "/" + normalized;
+
+        // Resolve occurrences of "//" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("//");
+            if (index < 0)
+            break;
+            normalized = normalized.substring(0, index) +
+            normalized.substring(index + 1);
+        }
 
-    // Resolve occurrences of "/./" in the normalized path
-    while (true) {
-        int index = normalized.indexOf("/./");
-        if (index < 0)
-        break;
-        normalized = normalized.substring(0, index) +
-        normalized.substring(index + 2);
-    }
+        // Resolve occurrences of "/./" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("/./");
+            if (index < 0)
+            break;
+            normalized = normalized.substring(0, index) +
+            normalized.substring(index + 2);
+        }
 
-    // Resolve occurrences of "/../" in the normalized path
-    while (true) {
-        int index = normalized.indexOf("/../");
-        if (index < 0)
-        break;
-        if (index == 0)
-        return (null);  // Trying to go outside our context
-        int index2 = normalized.lastIndexOf('/', index - 1);
-        normalized = normalized.substring(0, index2) +
-        normalized.substring(index + 3);
-    }
+        // Resolve occurrences of "/../" in the normalized path
+        while (true) {
+            int index = normalized.indexOf("/../");
+            if (index < 0)
+            break;
+            if (index == 0)
+            return (null);  // Trying to go outside our context
+            int index2 = normalized.lastIndexOf('/', index - 1);
+            normalized = normalized.substring(0, index2) +
+            normalized.substring(index + 3);
+        }
 
-    // Return the normalized path that we have completed
-    return (normalized);
+        // Return the normalized path that we have completed
+        return (normalized);
 
     }
 
@@ -818,12 +928,27 @@ public class FileDirContext extends BaseDirContext {
      */
     protected File file(String name) {
 
-        File file = new File(base, name);
+        File baseDir = base;
+        String absoluteBaseDir = absoluteBase;
+
+        if (pathAliases!=null) {
+            for (int i=0; i<pathAliases.length; i++) {
+                if (name.startsWith(pathAliases[i].prefix)) {
+                    baseDir = pathAliases[i].basePath;
+                    absoluteBaseDir = pathAliases[i].absPath;
+                    name = name.substring(pathAliases[i].prefix.length());
+                    break;
+                }
+            }
+        }
+
+        File file = new File(baseDir, name);
+
         if (file.exists() && file.canRead()) {
 
-               if (allowLinking)
-                       return file;
-               
+            if (allowLinking)
+                return file;
+
             // Check that this file belongs to our root path
             String canPath = null;
             try {
@@ -834,7 +959,7 @@ public class FileDirContext extends BaseDirContext {
                 return null;
 
             // Check to see if going outside of the web application root
-            if (!canPath.startsWith(absoluteBase)) {
+            if (!canPath.startsWith(absoluteBaseDir)) {
                 return null;
             }
 
@@ -846,14 +971,14 @@ public class FileDirContext extends BaseDirContext {
                 String absPath = normalize(fileAbsPath);
                 if (canPath != null)
                     canPath = normalize(canPath);
-                if ((absoluteBase.length() < absPath.length())
-                    && (absoluteBase.length() < canPath.length())) {
-                    absPath = absPath.substring(absoluteBase.length() + 1);
+                if ((absoluteBaseDir.length() < absPath.length())
+                    && (absoluteBaseDir.length() < canPath.length())) {
+                    absPath = absPath.substring(absoluteBaseDir.length() + 1);
                     if ((canPath == null) || (absPath == null))
                         return null;
                     if (absPath.equals(""))
                         absPath = "/";
-                    canPath = canPath.substring(absoluteBase.length() + 1);
+                    canPath = canPath.substring(absoluteBaseDir.length() + 1);
                     if (canPath.equals(""))
                         canPath = "/";
                     if (!canPath.equals(absPath))
@@ -1105,10 +1230,10 @@ public class FileDirContext extends BaseDirContext {
             return super.getResourceType();
         }
 
-        
+
         /**
          * Get canonical path.
-         * 
+         *
          * @return String the file's canonical path
          */
         public String getCanonicalPath() {
@@ -1121,10 +1246,15 @@ public class FileDirContext extends BaseDirContext {
             }
             return canonicalPath;
         }
-        
+
 
     }
 
+    protected class Alias {
+        String prefix;
+        File basePath;
+        String absPath;
+    }
 
 }
 
index 3791116..8a85677 100644 (file)
@@ -73,6 +73,9 @@
         In the APR connector, start accepting connections after fully starting
         the connector, to prevent possible exceptions due to non initialized fields. (remm)
       </fix>
+      <add>
+         Allow for aliases in FileDirContext. (funkman)
+      </add>
     </changelog>
   </subsection>
   <subsection name="Jasper">