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 000000000..8788f14fd --- /dev/null +++ b/apps/jetty/java/src/org/mortbay/util/FileResource.java @@ -0,0 +1,352 @@ +// ======================================================================== +// $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) { + if (!_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(); + } + } + } else return null; + 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/Resource.java b/apps/jetty/java/src/org/mortbay/util/Resource.java index 4180b8b01..ed992cfd5 100644 --- a/apps/jetty/java/src/org/mortbay/util/Resource.java +++ b/apps/jetty/java/src/org/mortbay/util/Resource.java @@ -392,7 +392,7 @@ public abstract class Resource implements Serializable buf.append(path); buf.append("\">"); buf.append(StringUtil.replace(StringUtil.replace(ls[i],"<","<"),">",">")); - buf.append(" "); + buf.append(" "); buf.append("
ISO_8859_1 encoding is used by default for % encoded characters. This
+ * may be overridden with the org.mortbay.util.URI.charset system property.
+ * @see UrlEncoded
+ * @version $Id: URI.java,v 1.40 2009/05/16 02:02:00 gregwilkins Exp $
+ * @author Greg Wilkins (gregw)
+ */
+public class URI
+ implements Cloneable
+{
+ private static Log log = LogFactory.getLog(URI.class);
+
+ public static final String __CHARSET=System.getProperty("org.mortbay.util.URI.charset",StringUtil.__UTF_8);
+ public static final boolean __CHARSET_IS_DEFAULT=__CHARSET.equals(StringUtil.__UTF_8);
+
+ /* ------------------------------------------------------------ */
+ private String _uri;
+ private String _scheme;
+ private String _host;
+ private int _port;
+ private String _path;
+ private String _encodedPath;
+ 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 .
+ * @param uri
+ */
+ public URI(URI uri)
+ throws IllegalArgumentException
+ {
+ _uri=uri.toString();
+ _scheme=uri._scheme;
+ _host=uri._host;
+ _port=uri._port;
+ _path=uri._path;
+ _encodedPath=uri._encodedPath;
+ _query=uri._query;
+ if (uri._parameters!=null)
+ _parameters=(UrlEncoded)uri._parameters.clone();
+ _dirty=false;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Construct from a String.
+ * The string must contain a URI path, but optionaly may contain a
+ * scheme, host, port and query string.
+ *
+ * @param uri [scheme://host[:port]]/path[?query]
+ */
+ public URI(String uri)
+ throws IllegalArgumentException
+ {
+ setURI(uri);
+ }
+
+ /* ------------------------------------------------------------ */
+ public void setURI(String uri)
+ throws IllegalArgumentException
+ {
+ try
+ {
+ _uri=uri;
+ _scheme=null;
+ _host=null;
+ _port=0;
+ _path=null;
+ _encodedPath=null;
+ _query=null;
+ if (_parameters!=null)
+ _parameters.clear();
+
+ // Scan _uri for host, port, path & query
+ int maxi=uri.length()-1;
+ int mark=0;
+ int state=0;
+ int i=0;
+
+ if (maxi==0 || uri.charAt(0)=='/' && uri.charAt(1)!='/')
+ {
+ state=3;
+ _scheme=null;
+ _host=null;
+ _port=0;
+ }
+ else
+ {
+ for (i=0;state<3 && i<=maxi;i++)
+ {
+ char c=uri.charAt(i);
+ switch(state)
+ {
+ case 0: // looking for scheme or path
+ if (c==':' &&
+ uri.charAt(i+1)=='/' &&
+ uri.charAt(i+2)=='/')
+ {
+ // found end of scheme & start of host
+ _scheme=uri.substring(mark,i);
+ i+=2;
+ mark=i+1;
+ state=1;
+ }
+ else if (i==0 && c=='/')
+ {
+ // Found path
+ state=3;
+ }
+ else if (i==0 && c=='*')
+ {
+ state=5;
+ _path="*";
+ _encodedPath="*";
+ }
+ continue;
+
+ case 1: // Get host & look for port or path
+ if (c==':')
+ {
+ // found port
+ _host=uri.substring(mark,i);
+ mark=i+1;
+ state=2;
+ }
+ else if (c=='/')
+ {
+ // found path
+ _host=uri.substring(mark,i);
+ mark=i;
+ state=3;
+ }
+ continue;
+
+ case 2: // Get port & look for path
+ if (c=='/')
+ {
+ _port=TypeUtil.parseInt(uri,mark,i-mark,10);
+ mark=i;
+ state=3;
+ }
+ continue;
+ }
+ }
+ }
+
+ // State 3 - Get path & look for query
+ _query=null;
+ for (i++;i<=maxi;i++)
+ {
+ char c=uri.charAt(i);
+ if (c=='?')
+ {
+ // Found query
+ _encodedPath=uri.substring(mark,i);
+ _path=decodePath(_encodedPath);
+
+ mark=i+1;
+ state=4;
+ break;
+ }
+ }
+
+ // complete last state
+ switch(state)
+ {
+ case 0:
+ _dirty=false;
+ _encodedPath=_uri;
+ _path=decodePath(_encodedPath);
+ break;
+
+ case 1:
+ _dirty=true;
+ _encodedPath="/";
+ _path=_encodedPath;
+ _host=uri.substring(mark);
+ break;
+
+ case 2:
+ _dirty=true;
+ _encodedPath="/";
+ _path=_encodedPath;
+ _port=TypeUtil.parseInt(uri,mark,-1,10);
+ break;
+ case 3:
+ _dirty=(mark==maxi);
+ _encodedPath=uri.substring(mark);
+ _path=decodePath(_encodedPath);
+ break;
+
+ case 4:
+ _dirty=false;
+ if (mark<=maxi)
+ _query=uri.substring(mark);
+ break;
+
+ case 5:
+ _dirty=false;
+ }
+
+ if (_query!=null && _query.length()>0)
+ {
+ if (_parameters==null)
+ _parameters= new UrlEncoded();
+ else
+ _parameters.clear();
+ _parameters.decode(_query,__CHARSET);
+
+ }
+ else
+ _query=null;
+ }
+ catch (Exception e)
+ {
+ LogSupport.ignore(log,e);
+ throw new IllegalArgumentException("Malformed URI '"+uri+
+ "' : "+e.toString());
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Is the URI an absolute URL?
+ * @return True if the URI has a scheme or host
+ */
+ public boolean isAbsolute()
+ {
+ return _scheme!=null || _host!=null;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get the uri scheme.
+ * @return the URI scheme
+ */
+ public String getScheme()
+ {
+ return _scheme;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set the uri scheme.
+ * @param scheme the uri scheme
+ */
+ public void setScheme(String scheme)
+ {
+ _scheme=scheme;
+ _dirty=true;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get the uri host.
+ * @return the URI host
+ */
+ public String getHost()
+ {
+ return _host;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set the uri host.
+ * @param host the uri host
+ */
+ public void setHost(String host)
+ {
+ _host=host;
+ _dirty=true;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get the uri port.
+ * @return the URI port
+ */
+ public int getPort()
+ {
+ return _port;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set the uri port.
+ * A port of 0 implies use the default port.
+ * @param port the uri port
+ */
+ public void setPort(int port)
+ {
+ _port=port;
+ _dirty=true;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get the uri path.
+ * @return the URI path
+ */
+ public String getPath()
+ {
+ return _path;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get the encoded uri path.
+ * @return the URI path
+ */
+ public String getEncodedPath()
+ {
+ return _encodedPath;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set the uri path.
+ * @param path the URI path
+ */
+ public void setPath(String path)
+ {
+ _path=path;
+ _encodedPath=encodePath(_path);
+ _dirty=true;
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /** Get the uri query String.
+ * @return the URI query string
+ */
+ public String getQuery()
+ {
+ if (_dirty && _parameters!=null)
+ {
+ _query = _parameters.encode(__CHARSET);
+ if (_query!=null && _query.length()==0)
+ _query=null;
+ }
+ return _query;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Set the uri query String.
+ * @param query the URI query string
+ */
+ public void setQuery(String query)
+ {
+ _query=query;
+
+ if (_parameters!=null)
+ _parameters.clear();
+ else if (query!=null)
+ _parameters=new UrlEncoded();
+
+ if (query!=null)
+ _parameters.decode(query,__CHARSET);
+
+ cleanURI();
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get the uri query _parameters names.
+ * @return Unmodifiable set of URI query _parameters names
+ */
+ public Set getParameterNames()
+ {
+ if (_parameters==null)
+ return Collections.EMPTY_SET;
+ return _parameters.keySet();
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get the uri query _parameters.
+ * @return the URI query _parameters
+ */
+ public MultiMap getParameters()
+ {
+ if (_parameters==null)
+ _parameters=new UrlEncoded();
+ _dirty=true;
+ return _parameters;
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get the uri query _parameters.
+ * @return the URI query _parameters in an unmodifiable map.
+ */
+ public Map getUnmodifiableParameters()
+ {
+ if (_parameters==null)
+ return Collections.EMPTY_MAP;
+ return Collections.unmodifiableMap(_parameters);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Add the uri query _parameters to a MultiMap
+ */
+ public void putParametersTo(MultiMap map)
+ {
+ if (_parameters!=null && _parameters.size()>0)
+ map.putAll(_parameters);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Clear the URI _parameters.
+ */
+ public void clearParameters()
+ {
+ if (_parameters!=null)
+ {
+ _dirty=true;
+ _parameters.clear();
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Add encoded _parameters.
+ * @param encoded A HTTP encoded string of _parameters: e.g.. "a=1&b=2"
+ */
+ public void put(String encoded)
+ {
+ UrlEncoded params = new UrlEncoded(encoded);
+ put(params);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Add name value pair to the uri query _parameters.
+ * @param name name of value
+ * @param value The value, which may be a multi valued list or
+ * String array.
+ */
+ public Object put(Object name, Object value)
+ {
+ return getParameters().put(name,value);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Add dictionary to the uri query _parameters.
+ */
+ public void put(Map values)
+ {
+ getParameters().putAll(values);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get named value
+ */
+ public String get(String name)
+ {
+ if (_parameters==null)
+ return null;
+ return (String)_parameters.get(name);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Get named multiple values.
+ * @param name The parameter name
+ * @return Umodifiable list of values or null
+ */
+ public List getValues(String name)
+ {
+ if (_parameters==null)
+ return null;
+ return _parameters.getValues(name);
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Remove named value
+ */
+ public void remove(String name)
+ {
+ if (_parameters!=null)
+ {
+ _dirty=
+ _parameters.remove(name)!=null;
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /** @return the URI string encoded.
+ */
+ public String toString()
+ {
+ if (_dirty)
+ {
+ getQuery();
+ cleanURI();
+ }
+ return _uri;
+ }
+
+ /* ------------------------------------------------------------ */
+ private void cleanURI()
+ {
+ StringBuffer buf = new StringBuffer(_uri.length()*2);
+ synchronized(buf)
+ {
+ if (_scheme!=null)
+ {
+ buf.append(_scheme);
+ buf.append("://");
+ buf.append(_host);
+ if (_port>0)
+ {
+ buf.append(':');
+ buf.append(_port);
+ }
+ }
+
+ buf.append(_encodedPath);
+
+ if (_query!=null && _query.length()>0)
+ {
+ buf.append('?');
+ buf.append(_query);
+ }
+ _uri=buf.toString();
+ _dirty=false;
+ }
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /** Encode a URI path.
+ * This is the same encoding offered by URLEncoder, except that
+ * the '/' character is not encoded.
+ * @param path The path the encode
+ * @return The encoded path
+ */
+ public static String encodePath(String path)
+ {
+ if (path==null || path.length()==0)
+ return path;
+
+ StringBuffer buf = encodePath(null,path);
+ return buf==null?path:buf.toString();
+ }
+
+ /* ------------------------------------------------------------ */
+ /** Encode a URI path.
+ * @param path The path the encode
+ * @param buf StringBuffer to encode path into (or null)
+ * @return The StringBuffer or null if no substitutions required.
+ */
+ public static StringBuffer encodePath(StringBuffer buf, String path)
+ {
+ // 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