lookupstate.java

来自「很棒的web服务器源代码」· Java 代码 · 共 392 行

JAVA
392
字号
// LookupState.java// $Id: LookupState.java,v 1.16 2004/02/02 11:58:55 ylafon Exp $// (c) COPYRIGHT MIT and INRIA, 1996.// Please first read the full copyright statement in file COPYRIGHT.htmlpackage org.w3c.tools.resources ;import java.util.Vector ;/** * This object keeps the state info around while looking up an entity. */public class LookupState {    private int     index ;    private String  components[] ;    private String  componentstype[];    private RequestInterface request ;    private boolean is_directory = false ;    private boolean is_internal  = false ;    private String  uri = null ;    private String query = null;    private String fragment = null;    private String type = null; // rfc1630 type as defined in ftp    /**     * Unescape a escaped string     * @param s The string to be unescaped     * @return the unescaped string.     */    public static String unescape (String s) {	int l  = s.length() ;	boolean work = false;	// this one is to avoid allocating a string and a char array	// the cost is 3n tests, need to check that in the long run	for (int i=0; i< l; i++) {	    char c = s.charAt(i);	    if ((c == '%') || (c == '+')) {		work = true;		break;	    }	}	if (work) {	    char cbuf[] = new char[l];	    int pos = 0;	    int ch = -1 ;	    for (int i = 0 ; i < l ; i++) {		switch (ch = s.charAt(i)) {		case '%':		    ch = s.charAt (++i);		    int hb = (Character.isDigit ((char) ch) 			      ? ch - '0'			      : 10+Character.toLowerCase((char)ch) - 'a')& 0xF;		    ch = s.charAt (++i);		    int lb = (Character.isDigit ((char) ch)			      ? ch - '0'			      : 10+Character.toLowerCase((char)ch) - 'a')& 0xF;		    // remove if equal to 0 FIXME for utf8		    if (((hb << 4) | lb) > 0) {			cbuf[pos++] = (char) ((hb << 4) | lb);		    }		    break ;		case '+':		    cbuf[pos++] = ' ';		    break ;		default:		    cbuf[pos++] = (char)ch;		}	    }	    return new String(cbuf, 0, pos);	}	return s;    }    /**     * Parse the given URI into an array of hierarchical components.     * The optional query string and an optional fragment are recorded into     * the request as new fields.     * <p>The query string and the fragment are recorded into the request     * as the <strong>query</strong> and <strong>frag</strong> attributes.     * @exception ProtocolException if unable to parse     */    protected void parseURI ()	throws ProtocolException    {	int    urilen = uri.length() ;	int    start  = 0 ;	int    slash  = -1 ;	int    t      = -1;	Vector comps  = new Vector(8) ;	int    q      = uri.indexOf ('?', start);	int    f      = uri.indexOf ('#', start);	int    stop   = -1;		if ((q >= 0) && (f >= 0)) {	    stop = Math.min(q, f);	} else if (q >= 0) {	    stop = q;	} else if (f >= 0) {	    stop = f;	} else {	    stop = urilen;	}	if ( stop < 0 )	    stop = urilen;	this.uri = uri ;    loop:	while ( true ) {	    slash = uri.indexOf ('/', start) ;	    if ((slash >= stop) || (slash < 0)) {		break loop;	    } else if ( slash == start ) {		start = slash + 1;		continue loop;	    } else if ( slash > 0 ) {		String part = unescape(uri.substring (start, slash)) ;		// detect / and		t = part.indexOf(';');		if (t == -1) {		    if (part.indexOf('/') != -1) {			// FIXME currently using unescaped string			String spa = uri.substring (start, slash);			comps.addElement (spa) ;		    } else {			comps.addElement (part) ;		    }		} else {		    int sl = part.indexOf('/');		    if (sl >= 0) {			if (t < sl) {			    comps.addElement (part) ;			} else {			    // FIXME currently using unescaped string			    comps.addElement ((uri.substring (start, slash))) ;			}		    }	        } 		start = slash + 1;		continue loop;	    }	}	// Deal with any ? or # fragments:	if ((q >= 0) || (f >= 0)) {	    if ((q >= 0) && (f > q)) {		// ?q#f		if (q+1 < f)		    this.query = uri.substring(q+1, f);		if (f+1 < urilen)		    this.fragment = uri.substring(f+1, urilen);	    } else if ((f >= 0) && (q > f)) {		// #f?q		if (f+1 < q)		    this.fragment = uri.substring(f+1, q);		if (q+1 < urilen)		    this.query = uri.substring(q+1, urilen);	    } else if ( f >= 0 ) {		// #f		if (f+1 < urilen)		    this.fragment = uri.substring(f+1, urilen);	    } else if ( q >= 0 ) {	        // ?q	        if (q+1 < urilen)		    this.query = uri.substring(q+1, urilen);	    }	}	// Update query states:	if ( request != null ) {	    if ( query != null )		request.setState("query", query);	    if ( fragment != null )		request.setState("frag", fragment);	}	// Keep track of last frament, and wrap up the result:	if (start < stop) {	    comps.addElement(unescape(uri.substring(start, stop)));	}	if (--stop >= 0 )	    is_directory = (uri.charAt(stop) == '/');	components = new String[comps.size()] ;	componentstype = new String[comps.size()] ;	comps.copyInto (components) ;	// now cut possible comments inside the URL, per rfc 1630	for (int i=0; i< components.length; i++) {	    t = components[i].indexOf(';');	    if (t >= 0) {		componentstype[i] = components[i].substring(t+1);		components[i] = components[i].substring(0,t);	    }	    if (components[i].indexOf('/') >= 0) {		throw new ProtocolException("encoded % in URI are forbidden"+					    " on this server");	    }	}	index = 0 ;    }    /**     * Get the fragment part of the URL, if any.     * The fragment is anything beyond the # character in a URL.     * @return A String instance, or <strong>null</strong>.     */    public String getFragment() {	return fragment;    }    /**     * Get the query part of the URL, if any.     * The query is anything beyond a ? character in a URL.     * @return A String instance, or <strong>null</strong>.     */    public String getQuery() {	return query;    }    /**     * Get the type part of the URL, if any.     * The type is anything beyond a ; character in a URL.     * @return A String instance, or <strong>null</strong>.     */    public String getType() {	return componentstype[index];    }    /**     * Is the requested URI a directory URI ?     * @return A boolean <strong>true</strong> if the requested URI ends with     * a slash, <strong>false</strong> otherwise.     */    public boolean isDirectory() {	return is_directory ;    }    /**     * Get this lookpu state full URI.     */    public String getURI() {	return uri ;    }    /**     * Get next part of the URL to be look for.     * @return A String giving the next component.     */    public final String getNextComponent() {	if (request != null) {	    request.setState("type", componentstype[index]); 	}	return components[index++] ;    }    /**     * Get the next component, without consuming it.     * @return A String giving the next component, or <strong>null</strong>     *    if none is available.     */    public final String peekNextComponent() {	if ( index  < components.length )	    return components[index] ;	return null ;    }    /**     * Get the remaining path.     * @param consume If <strong>true</strong>, consume the components,      * otherwise, just peek them.     * @return A String giving the remaining URL.     */    public final String getRemainingPath(boolean consume) {	StringBuffer sb = new StringBuffer() ;	for (int i = index ; i < components.length ; i++) {	    sb.append("/"+components[i]);	}	if ( consume )	    index = components.length;	return sb.toString() ;    }    /**     * Get the remaiing path, without consuming it.     * @return The remaining path.     */    public final String getRemainingPath() {	return getRemainingPath(false);    }    /**     * Does this look up state has more components to be looked for.     * @return <strong>true</strong> if more components are to be looked for.     */    public boolean hasMoreComponents() {	return index < components.length ;    }    /**     * How much components have not yet been looked up in this state.     */    public int countRemainingComponents() {	return components.length - index ;    }    /**     * Get this lookup state request.     * @return An instance of RequestInterface, or <strong>null</strong>      * if this is an internal request.     */    public final RequestInterface getRequest () {	return request ;    }    /**     * Is this lookup state object associated with a request ?     * @return A boolean <strong>true</strong> if a request is associated.     */    public boolean hasRequest() {	return (request != null) ;    }    /**     * Mark this lookup state as being done internally.     * This allows lookup methods to be more kind (for example, not throwing     * redirections error, etc).     */    public void markInternal() {	is_internal = true ;    }    /**     * Is this lookup state internal to the server.     * Internal lookup state may not have an associated request.     * @return A boolean <strong>true</strong> if this is an internal request.     */    public boolean isInternal() {	return is_internal ;    }    /**     * Create a lookup state to handle the given request on behalf of client.     * @param client The client that issued the request.     * @param request The request whose URI is to bee looked up.     * @exception ProtocolException if an error relative to the protocol occurs     */    public LookupState (RequestInterface request)      throws ProtocolException    {	this.request     = request ;	this.uri         = request.getURLPath();	this.is_internal = request.isInternal();	if ( uri == null ) {	    ReplyInterface reply = request.makeBadRequestReply() ;	    reply.setContent ("Invalid URI (unparsable)") ;	    throw new ProtocolException (reply) ;	}	parseURI () ;    }    /**     * Construct a lookup state to be resolved internnaly by the server.     * This method allows for internal lookup of object, even if there is no     * real client making the request.     * @param uri The URI to be looked up.     * @exception ProtocolException if an error relative to the protocol occurs     */    public LookupState(String uri) 	throws ProtocolException    {	this.request     = null ;	this.is_internal = true ;	this.uri         = uri ;	parseURI() ;    }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?