merge of 'daa35ac8b482063c4db4b6205ca5dacc045080a4'
and 'e19c106344aa97ad1765e79df75f96182f89d102'
This commit is contained in:
352
apps/jetty/java/src/org/mortbay/util/FileResource.java
Normal file
352
apps/jetty/java/src/org/mortbay/util/FileResource.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
@ -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("</A> ");
|
||||
buf.append("</TD><TD ALIGN=right>");
|
||||
buf.append(item.length());
|
||||
buf.append(" bytes </TD><TD>");
|
||||
|
995
apps/jetty/java/src/org/mortbay/util/URI.java
Normal file
995
apps/jetty/java/src/org/mortbay/util/URI.java
Normal file
@ -0,0 +1,995 @@
|
||||
// ========================================================================
|
||||
// $Id: URI.java,v 1.40 2009/05/16 02:02:00 gregwilkins Exp $
|
||||
// Copyright 199-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.UnsupportedEncodingException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.mortbay.log.LogFactory;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** URI Holder.
|
||||
* This class assists with the decoding and encoding or HTTP URI's.
|
||||
* It differs from the java.net.URL class as it does not provide
|
||||
* communications ability, but it does assist with query string
|
||||
* formatting.
|
||||
* <P>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<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) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
* @param buf StringBuffer to encode path into (or null)
|
||||
* @param encode String of characters to encode. % is always encoded.
|
||||
* @return The StringBuffer or null if no substitutions required.
|
||||
*/
|
||||
public static StringBuffer encodeString(StringBuffer buf,
|
||||
String path,
|
||||
String encode)
|
||||
{
|
||||
if (buf==null)
|
||||
{
|
||||
loop:
|
||||
for (int i=0;i<path.length();i++)
|
||||
{
|
||||
char c=path.charAt(i);
|
||||
if (c=='%' || encode.indexOf(c)>=0)
|
||||
{
|
||||
buf=new StringBuffer(path.length()<<1);
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
if (buf==null)
|
||||
return null;
|
||||
}
|
||||
|
||||
synchronized(buf)
|
||||
{
|
||||
for (int i=0;i<path.length();i++)
|
||||
{
|
||||
char c=path.charAt(i);
|
||||
if (c=='%' || encode.indexOf(c)>=0)
|
||||
{
|
||||
buf.append('%');
|
||||
StringUtil.append(buf,(byte)(0xff&c),16);
|
||||
}
|
||||
else
|
||||
buf.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* Decode a URI path.
|
||||
* @param path The path the encode
|
||||
* @param buf StringBuffer to encode path into
|
||||
*/
|
||||
public static String decodePath(String path)
|
||||
{
|
||||
int len=path.length();
|
||||
byte[] bytes=null;
|
||||
int n=0;
|
||||
boolean noDecode=true;
|
||||
|
||||
for (int i=0;i<len;i++)
|
||||
{
|
||||
char c = path.charAt(i);
|
||||
|
||||
byte b = (byte)(0xff & c);
|
||||
|
||||
if (c=='%' && (i+2)<len)
|
||||
{
|
||||
noDecode=false;
|
||||
b=(byte)(0xff&TypeUtil.parseInt(path,i+1,2,16));
|
||||
i+=2;
|
||||
}
|
||||
else if (bytes==null)
|
||||
{
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bytes==null)
|
||||
{
|
||||
noDecode=false;
|
||||
bytes=new byte[len];
|
||||
for (int j=0;j<n;j++)
|
||||
bytes[j]=(byte)(0xff & path.charAt(j));
|
||||
}
|
||||
|
||||
bytes[n++]=b;
|
||||
}
|
||||
|
||||
if (noDecode)
|
||||
return path;
|
||||
|
||||
/*
|
||||
try
|
||||
{
|
||||
return new String(bytes,0,n,__CHARSET);
|
||||
}
|
||||
catch(UnsupportedEncodingException e)
|
||||
{
|
||||
log.warn(LogSupport.EXCEPTION,e);
|
||||
return new String(bytes,0,n);
|
||||
}
|
||||
*/
|
||||
|
||||
return new String(bytes,0,n);
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Clone URI.
|
||||
* @return cloned URI
|
||||
*/
|
||||
public Object clone()
|
||||
throws CloneNotSupportedException
|
||||
{
|
||||
URI u = (URI)super.clone();
|
||||
if (_parameters!=null)
|
||||
u._parameters=(UrlEncoded)_parameters.clone();
|
||||
_dirty=false;
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Add two URI path segments.
|
||||
* Handles null and empty paths, path and query params (eg ?a=b or
|
||||
* ;JSESSIONID=xxx) and avoids duplicate '/'
|
||||
* @param p1 URI path segment
|
||||
* @param p2 URI path segment
|
||||
* @return Legally combined path segments.
|
||||
*/
|
||||
public static String addPaths(String p1, String p2)
|
||||
{
|
||||
if (p1==null || p1.length()==0)
|
||||
{
|
||||
if (p2==null || p2.length()==0)
|
||||
return p1;
|
||||
return p2;
|
||||
}
|
||||
if (p2==null || p2.length()==0)
|
||||
return p1;
|
||||
|
||||
int split=p1.indexOf(';');
|
||||
if (split<0)
|
||||
split=p1.indexOf('?');
|
||||
if (split==0)
|
||||
return p2+p1;
|
||||
if (split<0)
|
||||
split=p1.length();
|
||||
|
||||
StringBuffer buf = new StringBuffer(p1.length()+p2.length()+2);
|
||||
buf.append(p1);
|
||||
|
||||
if (buf.charAt(split-1)=='/')
|
||||
{
|
||||
if (p2.startsWith("/"))
|
||||
{
|
||||
buf.deleteCharAt(split-1);
|
||||
buf.insert(split-1,p2);
|
||||
}
|
||||
else
|
||||
buf.insert(split,p2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p2.startsWith("/"))
|
||||
buf.insert(split,p2);
|
||||
else
|
||||
{
|
||||
buf.insert(split,'/');
|
||||
buf.insert(split+1,p2);
|
||||
}
|
||||
}
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Return the parent Path.
|
||||
* Treat a URI like a directory path and return the parent directory.
|
||||
*/
|
||||
public static String parentPath(String p)
|
||||
{
|
||||
if (p==null || "/".equals(p))
|
||||
return null;
|
||||
int slash=p.lastIndexOf('/',p.length()-2);
|
||||
if (slash>=0)
|
||||
return p.substring(0,slash+1);
|
||||
return null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Strip parameters from a path.
|
||||
* Return path upto any semicolon parameters.
|
||||
*/
|
||||
public static String stripPath(String path)
|
||||
{
|
||||
if (path==null)
|
||||
return null;
|
||||
int semi=path.indexOf(';');
|
||||
if (semi<0)
|
||||
return path;
|
||||
return path.substring(0,semi);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Convert a path to a cananonical form.
|
||||
* All instances of "." and ".." are factored out. Null is returned
|
||||
* if the path tries to .. above it's root.
|
||||
* @param path
|
||||
* @return path or null.
|
||||
*/
|
||||
public static String canonicalPath(String path)
|
||||
{
|
||||
if (path==null || path.length()==0)
|
||||
return path;
|
||||
|
||||
int end=path.length();
|
||||
int start = path.lastIndexOf('/', end);
|
||||
|
||||
search:
|
||||
while (end>0)
|
||||
{
|
||||
switch(end-start)
|
||||
{
|
||||
case 2: // possible single dot
|
||||
if (path.charAt(start+1)!='.')
|
||||
break;
|
||||
break search;
|
||||
case 3: // possible double dot
|
||||
if (path.charAt(start+1)!='.' || path.charAt(start+2)!='.')
|
||||
break;
|
||||
break search;
|
||||
}
|
||||
|
||||
end=start;
|
||||
start=path.lastIndexOf('/',end-1);
|
||||
}
|
||||
|
||||
// If we have checked the entire string
|
||||
if (start>=end)
|
||||
return path;
|
||||
|
||||
StringBuffer buf = new StringBuffer(path);
|
||||
int delStart=-1;
|
||||
int delEnd=-1;
|
||||
int skip=0;
|
||||
|
||||
while (end>0)
|
||||
{
|
||||
switch(end-start)
|
||||
{
|
||||
case 2: // possible single dot
|
||||
if (buf.charAt(start+1)!='.')
|
||||
{
|
||||
if (skip>0 && --skip==0)
|
||||
{
|
||||
delStart=start>=0?start:0;
|
||||
if(delStart>0 && delEnd==buf.length() && buf.charAt(delEnd-1)=='.')
|
||||
delStart++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(start<0 && buf.length()>2 && buf.charAt(1)=='/' && buf.charAt(2)=='/')
|
||||
break;
|
||||
|
||||
if(delEnd<0)
|
||||
delEnd=end;
|
||||
delStart=start;
|
||||
if (delStart<0 || delStart==0&&buf.charAt(delStart)=='/')
|
||||
{
|
||||
delStart++;
|
||||
if (delEnd<buf.length() && buf.charAt(delEnd)=='/')
|
||||
delEnd++;
|
||||
break;
|
||||
}
|
||||
if (end==buf.length())
|
||||
delStart++;
|
||||
|
||||
end=start--;
|
||||
while (start>=0 && buf.charAt(start)!='/')
|
||||
start--;
|
||||
continue;
|
||||
|
||||
case 3: // possible double dot
|
||||
if (buf.charAt(start+1)!='.' || buf.charAt(start+2)!='.')
|
||||
{
|
||||
if (skip>0 && --skip==0)
|
||||
{ delStart=start>=0?start:0;
|
||||
if(delStart>0 && delEnd==buf.length() && buf.charAt(delEnd-1)=='.')
|
||||
delStart++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
delStart=start;
|
||||
if (delEnd<0)
|
||||
delEnd=end;
|
||||
|
||||
skip++;
|
||||
end=start--;
|
||||
while (start>=0 && buf.charAt(start)!='/')
|
||||
start--;
|
||||
continue;
|
||||
|
||||
default:
|
||||
if (skip>0 && --skip==0)
|
||||
{
|
||||
delStart=start>=0?start:0;
|
||||
if(delEnd==buf.length() && buf.charAt(delEnd-1)=='.')
|
||||
delStart++;
|
||||
}
|
||||
}
|
||||
|
||||
// Do the delete
|
||||
if (skip<=0 && delStart>=0 && delStart>=0)
|
||||
{
|
||||
buf.delete(delStart,delEnd);
|
||||
delStart=delEnd=-1;
|
||||
if (skip>0)
|
||||
delEnd=end;
|
||||
}
|
||||
|
||||
end=start--;
|
||||
while (start>=0 && buf.charAt(start)!='/')
|
||||
start--;
|
||||
}
|
||||
|
||||
// Too many ..
|
||||
if (skip>0)
|
||||
return null;
|
||||
|
||||
// Do the delete
|
||||
if (delEnd>=0)
|
||||
buf.delete(delStart,delEnd);
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param uri URI
|
||||
* @return True if the uri has a scheme
|
||||
*/
|
||||
public static boolean hasScheme(String uri)
|
||||
{
|
||||
for (int i=0;i<uri.length();i++)
|
||||
{
|
||||
char c=uri.charAt(i);
|
||||
if (c==':')
|
||||
return true;
|
||||
if (!(c>='a'&&c<='z' ||
|
||||
c>='A'&&c<='Z' ||
|
||||
(i>0 &&(c>='0'&&c<='9' ||
|
||||
c=='.' ||
|
||||
c=='+' ||
|
||||
c=='-'))
|
||||
))
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user