All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.lightbody.bmp.proxy.jetty.util.URI Maven / Gradle / Ivy

The newest version!
// ========================================================================
// $Id: URI.java,v 1.39 2006/01/04 13:55:31 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 net.lightbody.bmp.proxy.jetty.util;

import net.lightbody.bmp.proxy.jetty.log.LogFactory;
import org.apache.commons.logging.Log;

import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

/* ------------------------------------------------------------ */
/** 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.
 * 

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.39 2006/01/04 13:55:31 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("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; /* ------------------------------------------------------------ */ /** 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) { if (buf==null) { loop: for (int i=0;i=0) { buf=new StringBuffer(path.length()<<1); break loop; } } if (buf==null) return null; } synchronized(buf) { for (int i=0;i=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=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 queryIdx=path.indexOf('?'); int start = path.lastIndexOf('/', (queryIdx > 0 ? queryIdx : 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=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='a'&&c<='z' || c>='A'&&c<='Z' || (i>0 &&(c>='0'&&c<='9' || c=='.' || c=='+' || c=='-')) )) break; } return false; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy