org.eclipse.jetty.http.HttpURI Maven / Gradle / Ivy
The newest version!
//
// ========================================================================
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.http;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.nio.charset.Charset;
import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.UrlEncoded;
import org.eclipse.jetty.util.Utf8StringBuilder;
/* ------------------------------------------------------------ */
/** Http URI.
* Parse a HTTP URI from a string or byte array. Given a URI
* http://user@host:port/path/info;param?query#fragment
* this class will split it into the following undecoded optional elements:
* - {@link #getScheme()} - http:
* - {@link #getAuthority()} - //name@host:port
* - {@link #getHost()} - host
* - {@link #getPort()} - port
* - {@link #getPath()} - /path/info
* - {@link #getParam()} - param
* - {@link #getQuery()} - query
* - {@link #getFragment()} - fragment
*
*
*/
public class HttpURI
{
private static final byte[] __empty={};
private final static int
START=0,
AUTH_OR_PATH=1,
SCHEME_OR_PATH=2,
AUTH=4,
IPV6=5,
PORT=6,
PATH=7,
PARAM=8,
QUERY=9,
ASTERISK=10;
final Charset _charset;
boolean _partial=false;
byte[] _raw=__empty;
String _rawString;
int _scheme;
int _authority;
int _host;
int _port;
int _portValue;
int _path;
int _param;
int _query;
int _fragment;
int _end;
boolean _encoded=false;
public HttpURI()
{
_charset = URIUtil.__CHARSET;
}
public HttpURI(Charset charset)
{
_charset = charset;
}
/* ------------------------------------------------------------ */
/**
* @param parsePartialAuth If True, parse auth without prior scheme, else treat all URIs starting with / as paths
*/
public HttpURI(boolean parsePartialAuth)
{
_partial=parsePartialAuth;
_charset = URIUtil.__CHARSET;
}
public HttpURI(String raw)
{
_rawString=raw;
byte[] b;
try
{
b = raw.getBytes(StringUtil.__UTF8);
}
catch (UnsupportedEncodingException e)
{
throw new RuntimeException(e.getMessage());
}
parse(b,0,b.length);
_charset = URIUtil.__CHARSET;
}
public HttpURI(byte[] raw,int offset, int length)
{
parse2(raw,offset,length);
_charset = URIUtil.__CHARSET;
}
public HttpURI(URI uri)
{
parse(uri.toASCIIString());
_charset = URIUtil.__CHARSET;
}
public void parse(String raw)
{
byte[] b = StringUtil.getBytes(raw);
parse2(b,0,b.length);
_rawString=raw;
}
public void parseConnect(String raw)
{
byte[] b = StringUtil.getBytes(raw);
parseConnect(b,0,b.length);
_rawString=raw;
}
public void parse(byte[] raw,int offset, int length)
{
_rawString=null;
parse2(raw,offset,length);
}
public void parseConnect(byte[] raw,int offset, int length)
{
_rawString=null;
_encoded=false;
_raw=raw;
int i=offset;
int e=offset+length;
int state=AUTH;
_end=offset+length;
_scheme=offset;
_authority=offset;
_host=offset;
_port=_end;
_portValue=-1;
_path=_end;
_param=_end;
_query=_end;
_fragment=_end;
loop: while (i6 && c=='t')
{
if (_raw[offset+3]==':')
{
s=offset+3;
i=offset+4;
c=':';
}
else if (_raw[offset+4]==':')
{
s=offset+4;
i=offset+5;
c=':';
}
else if (_raw[offset+5]==':')
{
s=offset+5;
i=offset+6;
c=':';
}
}
switch (c)
{
case ':':
{
m = i++;
_authority = m;
_path = m;
c = (char)(0xff & _raw[i]);
if (c == '/')
state = AUTH_OR_PATH;
else
{
_host = m;
_port = m;
state = PATH;
}
break;
}
case '/':
{
state = PATH;
break;
}
case ';':
{
_param = s;
state = PARAM;
break;
}
case '?':
{
_param = s;
_query = s;
state = QUERY;
break;
}
case '#':
{
_param = s;
_query = s;
_fragment = s;
break;
}
}
continue;
}
case AUTH:
{
switch (c)
{
case '/':
{
m = s;
_path = m;
_port = _path;
state = PATH;
break;
}
case '@':
{
_host = i;
break;
}
case ':':
{
_port = s;
state = PORT;
break;
}
case '[':
{
state = IPV6;
break;
}
}
continue;
}
case IPV6:
{
switch (c)
{
case '/':
{
throw new IllegalArgumentException("No closing ']' for " + new String(_raw,offset,length,_charset));
}
case ']':
{
state = AUTH;
break;
}
}
continue;
}
case PORT:
{
if (c=='/')
{
m=s;
_path=m;
if (_port<=_authority)
_port=_path;
state=PATH;
}
continue;
}
case PATH:
{
switch (c)
{
case ';':
{
_param = s;
state = PARAM;
break;
}
case '?':
{
_param = s;
_query = s;
state = QUERY;
break;
}
case '#':
{
_param = s;
_query = s;
_fragment = s;
break state;
}
case '%':
{
_encoded=true;
}
}
continue;
}
case PARAM:
{
switch (c)
{
case '?':
{
_query = s;
state = QUERY;
break;
}
case '#':
{
_query = s;
_fragment = s;
break state;
}
}
continue;
}
case QUERY:
{
if (c=='#')
{
_fragment=s;
break state;
}
continue;
}
case ASTERISK:
{
throw new IllegalArgumentException("only '*'");
}
}
}
if (_port<_path)
_portValue=TypeUtil.parseInt(_raw, _port+1, _path-_port-1,10);
}
public String getScheme()
{
if (_scheme==_authority)
return null;
int l=_authority-_scheme;
if (l==5 &&
_raw[_scheme]=='h' &&
_raw[_scheme+1]=='t' &&
_raw[_scheme+2]=='t' &&
_raw[_scheme+3]=='p' )
return HttpScheme.HTTP.asString();
if (l==6 &&
_raw[_scheme]=='h' &&
_raw[_scheme+1]=='t' &&
_raw[_scheme+2]=='t' &&
_raw[_scheme+3]=='p' &&
_raw[_scheme+4]=='s' )
return HttpScheme.HTTPS.asString();
return new String(_raw,_scheme,_authority-_scheme-1,_charset);
}
public String getAuthority()
{
if (_authority==_path)
return null;
return new String(_raw,_authority,_path-_authority,_charset);
}
public String getHost()
{
if (_host==_port)
return null;
return new String(_raw,_host,_port-_host,_charset);
}
public int getPort()
{
return _portValue;
}
public String getPath()
{
if (_path==_param)
return null;
return new String(_raw,_path,_param-_path,_charset);
}
public String getDecodedPath()
{
if (_path==_param)
return null;
int length = _param-_path;
byte[] bytes=null;
int n=0;
for (int i=_path;i<_param;i++)
{
byte b = _raw[i];
if (b=='%')
{
if ((i+2)>=_param)
throw new IllegalArgumentException("Bad % encoding: "+this);
b=(byte)(0xff&TypeUtil.parseInt(_raw,i+1,2,16));
i+=2;
}
else if (bytes==null)
{
n++;
continue;
}
if (bytes==null)
{
bytes=new byte[length];
System.arraycopy(_raw,_path,bytes,0,n);
}
bytes[n++]=b;
}
if (bytes==null)
return new String(_raw,_path,length,_charset);
return new String(bytes,0,n,_charset);
}
public String getDecodedPath(String encoding)
{
if (_path==_param)
return null;
int length = _param-_path;
byte[] bytes=null;
int n=0;
for (int i=_path;i<_param;i++)
{
byte b = _raw[i];
if (b=='%')
{
if ((i+2)>=_param)
throw new IllegalArgumentException("Bad % encoding: "+this);
b=(byte)(0xff&TypeUtil.parseInt(_raw,i+1,2,16));
i+=2;
}
else if (bytes==null)
{
n++;
continue;
}
if (bytes==null)
{
bytes=new byte[length];
System.arraycopy(_raw,_path,bytes,0,n);
}
bytes[n++]=b;
}
if (bytes==null)
return StringUtil.toString(_raw,_path,_param-_path,encoding);
return StringUtil.toString(bytes,0,n,encoding);
}
public String getPathAndParam()
{
if (_path==_query)
return null;
return new String(_raw,_path,_query-_path,_charset);
}
public String getCompletePath()
{
if (_path==_end)
return null;
return new String(_raw,_path,_end-_path,_charset);
}
public String getParam()
{
if (_param==_query)
return null;
return new String(_raw,_param+1,_query-_param-1,_charset);
}
public String getQuery()
{
if (_query==_fragment)
return null;
return new String(_raw,_query+1,_fragment-_query-1,_charset);
}
public String getQuery(String encoding)
{
if (_query==_fragment)
return null;
return StringUtil.toString(_raw,_query+1,_fragment-_query-1,encoding);
}
public boolean hasQuery()
{
return (_fragment>_query);
}
public String getFragment()
{
if (_fragment==_end)
return null;
return new String(_raw,_fragment+1,_end-_fragment-1,_charset);
}
public void decodeQueryTo(MultiMap parameters)
{
if (_query==_fragment)
return;
if (_charset==StringUtil.__UTF8_CHARSET)
UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters);
else
UrlEncoded.decodeTo(StringUtil.toString(_raw,_query+1,_fragment-_query-1,_charset.toString()),parameters,_charset.toString());
}
public void decodeQueryTo(MultiMap parameters, String encoding) throws UnsupportedEncodingException
{
if (_query==_fragment)
return;
if (encoding==null || StringUtil.isUTF8(encoding))
UrlEncoded.decodeUtf8To(_raw,_query+1,_fragment-_query-1,parameters);
else
UrlEncoded.decodeTo(StringUtil.toString(_raw,_query+1,_fragment-_query-1,encoding),parameters,encoding);
}
public void clear()
{
_scheme=_authority=_host=_port=_path=_param=_query=_fragment=_end=0;
_raw=__empty;
_rawString="";
_encoded=false;
}
@Override
public String toString()
{
if (_rawString==null)
_rawString=new String(_raw,_scheme,_end-_scheme,_charset);
return _rawString;
}
public void writeTo(Utf8StringBuilder buf)
{
buf.append(_raw,_scheme,_end-_scheme);
}
}