diff --git a/apps/jetty/java/src/org/mortbay/util/FileResource.java b/apps/jetty/java/src/org/mortbay/util/FileResource.java new file mode 100644 index 0000000000000000000000000000000000000000..2738d679b8a0f1b67d5440789261b078924e878f --- /dev/null +++ b/apps/jetty/java/src/org/mortbay/util/FileResource.java @@ -0,0 +1,350 @@ +// ======================================================================== +// $Id: FileResource.java,v 1.31 2006/01/04 13:55:31 gregwilkins Exp $ +// Copyright 1996-2004 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ======================================================================== +package org.mortbay.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.security.Permission; + +import org.apache.commons.logging.Log; +import org.mortbay.log.LogFactory; + + +/* ------------------------------------------------------------ */ +/** File Resource. + * + * Handle resources of implied or explicit file type. + * This class can check for aliasing in the filesystem (eg case + * insensitivity). By default this is turned on if the platform does + * not have the "/" path separator, or it can be controlled with the + * "org.mortbay.util.FileResource.checkAliases" system parameter. + * + * If alias checking is turned on, then aliased resources are + * treated as if they do not exist, nor can they be created. + * + * @version $Revision: 1.31 $ + * @author Greg Wilkins (gregw) + */ +public class FileResource extends URLResource +{ + private static Log log = LogFactory.getLog(Credential.class); + private static boolean __checkAliases; + static + { + __checkAliases= + "true".equalsIgnoreCase + (System.getProperty("org.mortbay.util.FileResource.checkAliases","true")); + + if (__checkAliases) + log.info("Checking Resource aliases"); + } + + /* ------------------------------------------------------------ */ + private File _file; + private transient URL _alias=null; + private transient boolean _aliasChecked=false; + + /* ------------------------------------------------------------------------------- */ + /** setCheckAliases. + * @param checkAliases True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found. + */ + public static void setCheckAliases(boolean checkAliases) + { + __checkAliases=checkAliases; + } + + /* ------------------------------------------------------------------------------- */ + /** getCheckAliases. + * @return True of resource aliases are to be checked for (eg case insensitivity or 8.3 short names) and treated as not found. + */ + public static boolean getCheckAliases() + { + return __checkAliases; + } + + /* -------------------------------------------------------- */ + FileResource(URL url) + throws IOException, URISyntaxException + { + super(url,null); + + try + { + // Try standard API to convert URL to file. + _file =new File(new URI(url.toString())); + } + catch (Exception e) + { + LogSupport.ignore(log,e); + try + { + // Assume that File.toURL produced unencoded chars. So try + // encoding them. + String urls= + "file:"+org.mortbay.util.URI.encodePath(url.toString().substring(5)); + _file =new File(new URI(urls)); + } + catch (Exception e2) + { + LogSupport.ignore(log,e2); + + // Still can't get the file. Doh! try good old hack! + checkConnection(); + Permission perm = _connection.getPermission(); + _file = new File(perm==null?url.getFile():perm.getName()); + } + } + + if (_file.isDirectory() && !_urlString.endsWith("/")) + _urlString=_urlString+"/"; + } + + /* -------------------------------------------------------- */ + FileResource(URL url, URLConnection connection, File file) + { + super(url,connection); + _file=file; + if (_file.isDirectory() && !_urlString.endsWith("/")) + _urlString=_urlString+"/"; + } + + /* -------------------------------------------------------- */ + public Resource addPath(String path) + throws IOException,MalformedURLException + { + FileResource r=null; + + if (!isDirectory()) + { + r=(FileResource)super.addPath(path); + } + else + { + path = org.mortbay.util.URI.canonicalPath(path); + + // treat all paths being added as relative + String rel=path; + if (path.startsWith("/")) + rel = path.substring(1); + + File newFile = new File(_file,rel.replace('/', File.separatorChar)); + r=new FileResource(newFile.toURI().toURL(),null,newFile); + } + + String encoded=org.mortbay.util.URI.encodePath(path); + int expected=r._urlString.length()-encoded.length(); + int index = r._urlString.lastIndexOf(encoded, expected); + + if (expected!=index && ((expected-1)!=index || path.endsWith("/") || !r.isDirectory())) + { + r._alias=r._url; + r._aliasChecked=true; + } + return r; + } + + + /* ------------------------------------------------------------ */ + public URL getAlias() + { + if (__checkAliases && !_aliasChecked) + { + try + { + String abs=_file.getAbsolutePath(); + String can=_file.getCanonicalPath(); + + if (abs.length()!=can.length() || !abs.equals(can)) + _alias=new File(can).toURI().toURL(); + + _aliasChecked=true; + + if (_alias!=null && log.isDebugEnabled()) + { + log.debug("ALIAS abs="+abs); + log.debug("ALIAS can="+can); + } + } + catch(Exception e) + { + log.warn(LogSupport.EXCEPTION,e); + return getURL(); + } + } + return _alias; + } + + /* -------------------------------------------------------- */ + /** + * Returns true if the resource exists. + */ + public boolean exists() + { + return _file.exists(); + } + + /* -------------------------------------------------------- */ + /** + * Returns the last modified time + */ + public long lastModified() + { + return _file.lastModified(); + } + + /* -------------------------------------------------------- */ + /** + * Returns true if the respresenetd resource is a container/directory. + */ + public boolean isDirectory() + { + return _file.isDirectory(); + } + + /* --------------------------------------------------------- */ + /** + * Return the length of the resource + */ + public long length() + { + return _file.length(); + } + + + /* --------------------------------------------------------- */ + /** + * Returns the name of the resource + */ + public String getName() + { + return _file.getAbsolutePath(); + } + + /* ------------------------------------------------------------ */ + /** + * Returns an File representing the given resource or NULL if this + * is not possible. + */ + public File getFile() + { + return _file; + } + + /* --------------------------------------------------------- */ + /** + * Returns an input stream to the resource + */ + public InputStream getInputStream() throws IOException + { + return new FileInputStream(_file); + } + + /* --------------------------------------------------------- */ + /** + * Returns an output stream to the resource + */ + public OutputStream getOutputStream() + throws java.io.IOException, SecurityException + { + return new FileOutputStream(_file); + } + + /* --------------------------------------------------------- */ + /** + * Deletes the given resource + */ + public boolean delete() + throws SecurityException + { + return _file.delete(); + } + + /* --------------------------------------------------------- */ + /** + * Rename the given resource + */ + public boolean renameTo( Resource dest) + throws SecurityException + { + if( dest instanceof FileResource) + return _file.renameTo( ((FileResource)dest)._file); + else + return false; + } + + /* --------------------------------------------------------- */ + /** + * Returns a list of resources contained in the given resource + */ + public String[] list() + { + String[] list =_file.list(); + if (list==null) + return null; + for (int i=list.length;i-->0;) + { + if (new File(_file,list[i]).isDirectory() && + !list[i].endsWith("/")) + list[i]+="/"; + } + return list; + } + + /* ------------------------------------------------------------ */ + /** Encode according to this resource type. + * File URIs are encoded. + * @param uri URI to encode. + * @return The uri unchanged. + */ + public String encode(String uri) + { + return uri; + } + + /* ------------------------------------------------------------ */ + /** + * @param o + * @return + */ + public boolean equals( Object o) + { + if (this == o) + return true; + + if (null == o || ! (o instanceof FileResource)) + return false; + + FileResource f=(FileResource)o; + return f._file == _file || (null != _file && _file.equals(f._file)); + } + + /* ------------------------------------------------------------ */ + /** + * @return the hashcode. + */ + public int hashCode() + { + return null == _file ? super.hashCode() : _file.hashCode(); + } +} diff --git a/apps/jetty/java/src/org/mortbay/util/URI.java b/apps/jetty/java/src/org/mortbay/util/URI.java index 073951a57cce54141e092f392db4f690aa952d24..d5543832b77d67ff3e8c73a351e05b6f061e656f 100644 --- a/apps/jetty/java/src/org/mortbay/util/URI.java +++ b/apps/jetty/java/src/org/mortbay/util/URI.java @@ -53,6 +53,9 @@ public class URI private String _query; private UrlEncoded _parameters; private boolean _dirty; + private static String unreserved = "/0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.~"; + private static String reserved = "!*'();:@&=+$,?%#[]"; + private static String hexchars = "0123456789ABCDEF"; /* ------------------------------------------------------------ */ /** Copy Constructor . @@ -237,6 +240,7 @@ public class URI else _parameters.clear(); _parameters.decode(_query,__CHARSET); + } else _query=null; @@ -566,52 +570,48 @@ public class URI */ public static StringBuffer encodePath(StringBuffer buf, String path) { - if (buf==null) - { - loop: - for (int i=0;i<path.length();i++) - { - char c=path.charAt(i); - switch(c) - { - case '%': - case '?': - case ';': - case '#': - case ' ': - buf=new StringBuffer(path.length()<<1); - break loop; + // Convert path to native first. + byte[] b = null; + /* + try { + b = path.getBytes(__CHARSET); + } catch(UnsupportedEncodingException ex) { + return null; // Shouldn't be possible. + } + */ + b = path.getBytes(); + StringBuffer x = new StringBuffer(b.length); + for(int i=0; i<b.length; i++) { + x.append((char)(b[i]&0xff)); + } + String _path = new String(x); + if(buf == null) { + loop: + for(int i = 0; i < _path.length(); i++) { + char c = _path.charAt(i); + String cs = "" + c; + if(reserved.contains(cs) || !unreserved.contains(cs)) { + buf = new StringBuffer(_path.length() << 1); + break loop; } } - if (buf==null) + if(buf == null) { return null; + } } - - synchronized(buf) - { - for (int i=0;i<path.length();i++) - { - char c=path.charAt(i); - switch(c) - { - case '%': - buf.append("%25"); - continue; - case '?': - buf.append("%3F"); - continue; - case ';': - buf.append("%3B"); - continue; - case '#': - buf.append("%23"); - continue; - case ' ': - buf.append("%20"); - continue; - default: - buf.append(c); - continue; + synchronized(buf) { + for(int i = 0; i < _path.length(); i++) { + char c = _path.charAt(i); + String cs = "" + c; + if(reserved.contains(cs) || !unreserved.contains(cs)) { + if((c & 0xff) == c) { + buf.append(gethex(c & 0xff)); + } else { + buf.append(gethex((c >> 8) & 0xff)); + buf.append(gethex(c & 0xff)); + } + } else { + buf.append(c); } } } @@ -619,6 +619,14 @@ public class URI return buf; } + /** + * + * @param decimal value not greater than 255. + * @return a percent sign followed by two hexadecimal digits. + */ + private static String gethex(int decimal) { + return new String("%" + hexchars.charAt(decimal >> 4) + hexchars.charAt(decimal & 0xF)); + } /* ------------------------------------------------------------ */ /** Encode a URI path. * @param path The path the encode @@ -708,6 +716,7 @@ public class URI if (noDecode) return path; + /* try { return new String(bytes,0,n,__CHARSET); @@ -717,6 +726,10 @@ public class URI log.warn(LogSupport.EXCEPTION,e); return new String(bytes,0,n); } + */ + + return new String(bytes,0,n); + } /* ------------------------------------------------------------ */