You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by cr...@locus.apache.org on 2000/04/15 07:39:19 UTC

cvs commit: jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/util CookieUtil.java

craigmcc    00/04/14 22:39:19

  Modified:    proposals/catalina STATUS.html
               proposals/catalina/src/share/org/apache/tomcat/connector/http
                        Constants.java HttpConnector.java
                        HttpProcessor.java HttpRequestImpl.java
                        LocalStrings.properties
  Added:       proposals/catalina/src/share/org/apache/tomcat/util
                        CookieUtil.java
  Log:
  Flesh out a basic Connector implementation that is reasonably HTTP/1.0
  compliant.  This is primarily intended for testing and development until
  a complete HTTP/1.1 implementation is available.
  
  Revision  Changes    Path
  1.2       +2 -2      jakarta-tomcat/proposals/catalina/STATUS.html
  
  Index: STATUS.html
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/proposals/catalina/STATUS.html,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- STATUS.html	2000/04/13 23:09:18	1.1
  +++ STATUS.html	2000/04/15 05:39:13	1.2
  @@ -115,7 +115,7 @@
       <td align="center">High</td>
       <td>Design and implement a high-performance Connector implementation
           that fully supports HTTP/1.1 for use in stand-alone applications.
  -        [org.apache.tomcat.connector.http</td>
  +        [org.apache.tomcat.connector.http11]</td>
       <td>---</td>
     </tr>
     <tr>
  @@ -427,7 +427,7 @@
   
   <br>
   <div align="center"><hr width="75%"><font size="2">
  -$Id: STATUS.html,v 1.1 2000/04/13 23:09:18 craigmcc Exp $
  +$Id: STATUS.html,v 1.2 2000/04/15 05:39:13 craigmcc Exp $
   </font></div>
   
   </body>
  
  
  
  1.2       +4 -2      jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/connector/http/Constants.java
  
  Index: Constants.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/connector/http/Constants.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Constants.java	2000/02/20 02:57:10	1.1
  +++ Constants.java	2000/04/15 05:39:14	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/connector/http/Constants.java,v 1.1 2000/02/20 02:57:10 craigmcc Exp $
  - * $Revision: 1.1 $
  - * $Date: 2000/02/20 02:57:10 $
  + * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/connector/http/Constants.java,v 1.2 2000/04/15 05:39:14 craigmcc Exp $
  + * $Revision: 1.2 $
  + * $Date: 2000/04/15 05:39:14 $
    *
    * ====================================================================
    *
  @@ -72,5 +72,7 @@
   public final class Constants {
   
       public static final String Package = "org.apache.tomcat.connector.http";
  +    public static final String ServerInfo =
  +	"Catalina/0.1";
   
   }
  
  
  
  1.5       +53 -23    jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/connector/http/HttpConnector.java
  
  Index: HttpConnector.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/connector/http/HttpConnector.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- HttpConnector.java	2000/04/14 19:41:51	1.4
  +++ HttpConnector.java	2000/04/15 05:39:15	1.5
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/connector/http/HttpConnector.java,v 1.4 2000/04/14 19:41:51 craigmcc Exp $
  - * $Revision: 1.4 $
  - * $Date: 2000/04/14 19:41:51 $
  + * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/connector/http/HttpConnector.java,v 1.5 2000/04/15 05:39:15 craigmcc Exp $
  + * $Revision: 1.5 $
  + * $Date: 2000/04/15 05:39:15 $
    *
    * ====================================================================
    *
  @@ -336,12 +336,25 @@
   
   
       /**
  +     * Recycle the specified Processor.
  +     *
  +     * @param processor The processor to be recycled
  +     */
  +    void recycle(HttpProcessor processor) {
  +
  +	processors.push(processor);
  +
  +    }
  +
  +
  +    /**
        * Recycle the specified Request.
        *
        * @param request The request to be recycled
        */
       void recycle(HttpRequest request) {
   
  +	request.recycle();
   	requests.push(request);
   
       }
  @@ -354,6 +367,7 @@
        */
       void recycle(HttpResponse response) {
   
  +	response.recycle();
   	responses.push(response);
   
       }
  @@ -382,20 +396,46 @@
   
   
       /**
  +     * Log a message on the Logger associated with our Container (if any)
  +     *
  +     * @param message Message to be logged
  +     */
  +    private void log(String message) {
  +
  +	Logger logger = container.getLogger();
  +	if (logger != null)
  +	    logger.log(threadName + " " + message);
  +
  +    }
  +
  +
  +    /**
  +     * Log a message on the Logger associated with our Container (if any)
  +     *
  +     * @param message Message to be logged
  +     * @param throwable Associated exception
  +     */
  +    private void log(String message, Throwable throwable) {
  +
  +	Logger logger = container.getLogger();
  +	if (logger != null)
  +	    logger.log(threadName + " " + message, throwable);
  +
  +    }
  +
  +
  +    /**
        * Instantiate and return a new processor suitable for receiving
        * and processing HTTP requests.
        */
       private HttpProcessor newProcessor() {
   
  -	curProcessors++;
  -	HttpProcessor processor = new HttpProcessor(this);
  +	HttpProcessor processor = new HttpProcessor(this, curProcessors++);
   	if (processor instanceof Lifecycle) {
   	    try {
   		((Lifecycle) processor).start();
   	    } catch (LifecycleException e) {
  -		Logger logger = container.getLogger();
  -		if (logger != null)
  -		    logger.log(threadName + ".newProcessor", e);
  +		log("newProcessor: ", e);
   	    }
   	}
   	return (processor);
  @@ -419,11 +459,8 @@
   	    try {
   		socket = serverSocket.accept();
   	    } catch (IOException e) {
  -		if (!stopped) {
  -		    Logger logger = container.getLogger();
  -		    if (logger != null)
  -			logger.log(threadName + ".accept", e);
  -		}
  +		if (!stopped)
  +		    log("accept: ", e);
   		break;
   	    }
   
  @@ -431,10 +468,7 @@
   	    HttpProcessor processor = createProcessor();
   	    if (processor == null) {
   		try {
  -		    Logger logger = container.getLogger();
  -		    if (logger != null)
  -			logger.log(threadName +
  -				   "select:  No processor available");
  +		    log("select: No processor available");
   		    socket.close();
   		} catch (IOException e) {
   		    ;
  @@ -458,9 +492,7 @@
   	if (threadName == null)
   	    setThreadName("HttpConnector[" + port + "]");
   
  -	Logger logger = container.getLogger();
  -	if (logger != null)
  -	    logger.log(threadName + ":  Starting");
  +	log("Starting");
   
   	thread = new Thread(this, threadName);
   	thread.setDaemon(true);
  @@ -474,9 +506,7 @@
        */
       private void threadStop() {
   
  -	Logger logger = container.getLogger();
  -	if (logger != null)
  -	    logger.log(threadName + ":  Stopping");
  +	log("Stopping");
   
   	stopped = true;
   	try {
  
  
  
  1.3       +463 -12   jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/connector/http/HttpProcessor.java
  
  Index: HttpProcessor.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/connector/http/HttpProcessor.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- HttpProcessor.java	2000/04/10 20:01:36	1.2
  +++ HttpProcessor.java	2000/04/15 05:39:15	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/connector/http/HttpProcessor.java,v 1.2 2000/04/10 20:01:36 craigmcc Exp $
  - * $Revision: 1.2 $
  - * $Date: 2000/04/10 20:01:36 $
  + * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/connector/http/HttpProcessor.java,v 1.3 2000/04/15 05:39:15 craigmcc Exp $
  + * $Revision: 1.3 $
  + * $Date: 2000/04/15 05:39:15 $
    *
    * ====================================================================
    *
  @@ -65,16 +65,26 @@
   package org.apache.tomcat.connector.http;
   
   
  +import java.io.InputStream;
   import java.io.IOException;
  +import java.io.OutputStream;
  +import java.net.InetAddress;
   import java.net.Socket;
  +import java.util.NoSuchElementException;
  +import java.util.StringTokenizer;
  +import javax.servlet.ServletException;
  +import javax.servlet.http.Cookie;
  +import javax.servlet.http.HttpServletResponse;
   import org.apache.tomcat.Connector;
   import org.apache.tomcat.Container;
  +import org.apache.tomcat.HttpRequest;
  +import org.apache.tomcat.HttpResponse;
   import org.apache.tomcat.Lifecycle;
   import org.apache.tomcat.LifecycleEvent;
   import org.apache.tomcat.LifecycleException;
   import org.apache.tomcat.LifecycleListener;
  -import org.apache.tomcat.Request;
  -import org.apache.tomcat.Response;
  +import org.apache.tomcat.Logger;
  +import org.apache.tomcat.util.CookieUtil;
   import org.apache.tomcat.util.LifecycleSupport;
   import org.apache.tomcat.util.StringManager;
   
  @@ -87,11 +97,11 @@
    * the request.  When the processor is completed, it will recycle itself.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.2 $ $Date: 2000/04/10 20:01:36 $
  + * @version $Revision: 1.3 $ $Date: 2000/04/15 05:39:15 $
    */
   
   final class HttpProcessor
  -    implements Lifecycle {
  +    implements Lifecycle, Runnable {
   
   
       // ----------------------------------------------------------- Constructors
  @@ -101,12 +111,15 @@
        * Construct a new HttpProcessor associated with the specified connector.
        *
        * @param connector HttpConnector that owns this processor
  +     * @param id Identifier of this HttpProcessor (unique per connector)
        */
  -    public HttpProcessor(HttpConnector connector) {
  +    public HttpProcessor(HttpConnector connector, int id) {
   
   	super();
   	this.connector = connector;
  -
  +	this.id = id;
  +	request = (HttpRequest) connector.newRequest();
  +	response = (HttpResponse) connector.newResponse();
       }
   
   
  @@ -120,23 +133,101 @@
   
   
       /**
  +     * The identifier of this processor, unique per connector.
  +     */
  +    private int id = 0;
  +
  +
  +    /**
  +     * The input stream associated with this request.
  +     */
  +    private InputStream input = null;
  +
  +
  +    /**
        * The lifecycle event support for this component.
        */
       private LifecycleSupport lifecycle = new LifecycleSupport(this);
   
   
  +    /**
  +     * The output stream associated with this request.
  +     */
  +    private OutputStream output = null;
  +
  +
  +    /**
  +     * The HTTP request object we will pass to our associated container.
  +     */
  +    private HttpRequest request = null;
  +
  +
  +    /**
  +     * The HTTP response object we will pass to our associated container.
  +     */
  +    private HttpResponse response = null;
  +
  +
  +    /**
  +     * The string manager for this package.
  +     */
  +    protected StringManager sm =
  +	StringManager.getManager(Constants.Package);
  +
  +
  +    /**
  +     * The socket we are currently processing a request for.  If this is
  +     * <code>null</code>, this processor is available.
  +     */
  +    private Socket socket = null;
  +
  +
  +    /**
  +     * Has this component been started yet?
  +     */
  +    private boolean started = false;
  +
  +
  +    /**
  +     * The shutdown signal to our background thread
  +     */
  +    private boolean stopped = false;
  +
  +
  +    /**
  +     * The background thread.
  +     */
  +    private Thread thread = null;
  +
  +
  +    /**
  +     * The name to register for the background thread.
  +     */
  +    private String threadName = null;
  +
  +
  +    /**
  +     * The thread synchronization object.
  +     */
  +    private String threadSync = "";
  +
  +
       // -------------------------------------------------------- Package Methods
   
   
       /**
        * Process an incoming TCP/IP connection on the specified socket.  Any
        * exception that occurs during processing must be logged and swallowed.
  +     * <b>NOTE</b>:  This method is called from our Connector's thread.  We
  +     * must assign it to our own thread so that multiple simultaneous
  +     * requests can be handled.
        *
        * @param socket TCP socket to process
        */
       void process(Socket socket) {
   
  -	;	// FIXME: process()
  +	this.socket = socket;
  +	notify();
   
       }
   
  @@ -144,6 +235,356 @@
       // -------------------------------------------------------- Private Methods
   
   
  +    /**
  +     * Log a message on the Logger associated with our Container (if any)
  +     *
  +     * @param message Message to be logged
  +     */
  +    private void log(String message) {
  +
  +	Logger logger = connector.getContainer().getLogger();
  +	if (logger != null)
  +	    logger.log(threadName + " " + message);
  +
  +    }
  +
  +
  +    /**
  +     * Log a message on the Logger associated with our Container (if any)
  +     *
  +     * @param message Message to be logged
  +     * @param throwable Associated exception
  +     */
  +    private void log(String message, Throwable throwable) {
  +
  +	Logger logger = connector.getContainer().getLogger();
  +	if (logger != null)
  +	    logger.log(threadName + " " + message, throwable);
  +
  +    }
  +
  +
  +    /**
  +     * Parse and record the connection parameters related to this request.
  +     *
  +     * @exception IOException if an input/output error occurs
  +     * @exception ServletException if a parsing error occurs
  +     */
  +    private void parseConnection() throws IOException, ServletException {
  +
  +	((HttpRequestImpl) request).setInet(socket.getInetAddress());
  +	request.setServerPort(connector.getPort());
  +
  +    }
  +
  +
  +    /**
  +     * Parse the incoming HTTP request headers, and set the appropriate
  +     * request headers.
  +     *
  +     * @exception IOException if an input/output error occurs
  +     * @exception ServletException if a parsing error occurs
  +     */
  +    private void parseHeaders() throws IOException, ServletException {
  +
  +	while (true) {
  +
  +	    // Read the next header line
  +	    String line = read();
  +	    if ((line == null) || (line.length() < 1))
  +		break;
  +
  +	    // Parse the header name and value
  +	    int colon = line.indexOf(":");
  +	    if (colon < 0)
  +		throw new ServletException
  +		    (sm.getString("httpProcessor.parseHeaders.colon"));
  +	    String name = line.substring(0, colon).trim();
  +	    String match = name.toLowerCase();
  +	    String value = line.substring(colon + 1).trim();
  +
  +	    // Set the corresponding request headers
  +	    if (match.equals("authorization")) {
  +		;	// FIXME -- do not want to include with regular headers
  +	    } else if (match.equals("cookie")) {
  +		Cookie cookies[] = CookieUtil.parseCookieHeader(value);
  +		for (int i = 0; i < cookies.length; i++)
  +		    request.addCookie(cookies[i]);
  +	    } else if (match.equals("content-length")) {
  +		int n = -1;
  +		try {
  +		    n = Integer.parseInt(value);
  +		} catch (Exception e) {
  +		    throw new ServletException
  +			(sm.getString("httpProcessor.parseHeaders.contentLength"));
  +		}
  +		request.setContentLength(n);
  +	    } else if (match.equals("content-type")) {
  +		request.setContentType(value);	// FIXME -- encoding?
  +	    } else if (match.equals("host")) {
  +		int n = value.indexOf(":");
  +		if (n < 0)
  +		    request.setServerName(value);
  +		else {
  +		    request.setServerName(value.substring(0, n).trim());
  +		    int port = 80;
  +		    try {
  +			port = Integer.parseInt(value.substring(n+1).trim());
  +		    } catch (Exception e) {
  +			throw new ServletException
  +			    (sm.getString("httpProcessor.parseHeaders.portNumber"));
  +		    }
  +		    request.setServerPort(port);
  +		}
  +	    } else {
  +		request.addHeader(name, value);
  +	    }
  +	}
  +
  +    }
  +
  +
  +    /**
  +     * Parse the incoming HTTP request and set the corresponding HTTP request
  +     * properties.
  +     *
  +     * @exception IOException if an input/output error occurs
  +     * @exception ServletException if a parsing error occurs
  +     */
  +    private void parseRequest() throws IOException, ServletException {
  +
  +	// Parse the incoming request line
  +	String line = read();
  +	StringTokenizer st = new StringTokenizer(line);
  +
  +	String method = null;
  +	try {
  +	    method = st.nextToken();
  +	} catch (NoSuchElementException e) {
  +	    method = null;
  +	}
  +
  +	String uri = null;
  +	try {
  +	    uri = st.nextToken();
  +	    ;	// FIXME - URL decode the URI?
  +	} catch (NoSuchElementException e) {
  +	    uri = null;
  +	}
  +
  +	String protocol = null;
  +	try {
  +	    protocol = st.nextToken();
  +	} catch (NoSuchElementException e) {
  +	    protocol = "HTTP/0.9";
  +	}
  +
  +	// Validate the incoming request line
  +	if (method == null) {
  +	    throw new ServletException
  +		(sm.getString("httpProcessor.parseRequest.method"));
  +	} else if (uri == null) {
  +	    throw new ServletException
  +		(sm.getString("httpProcessor.parseRequest.uri"));
  +	}
  +
  +	// Set the corresponding request properties
  +	((HttpRequest) request).setMethod(method);
  +	request.setProtocol(protocol);
  +	((HttpRequest) request).setRequestURI(uri);
  +	request.setScheme("http");
  +
  +    }
  +
  +
  +    /**
  +     * Process an incoming HTTP request on the Socket that has been assigned
  +     * to this Processor.  Any exceptions that occur during processing must be
  +     * swallowed and dealt with.
  +     */
  +    private void process() {
  +
  +	boolean ok = true;
  +
  +	// Construct and initialize the objects we will need
  +	try {
  +	    input = socket.getInputStream();
  +	    request.setStream(input);
  +	    request.setResponse(response);
  +	    output = socket.getOutputStream();
  +	    response.setStream(output);
  +	    response.setRequest(request);
  +	    ((HttpServletResponse) response.getResponse()).setHeader
  +		("Server", Constants.ServerInfo);
  +	} catch (Exception e) {
  +	    log("process.create", e);
  +	    ok = false;
  +	}
  +
  +	// Parse the incoming request
  +	try {
  +	    if (ok) {
  +		parseConnection();
  +		parseRequest();
  +		if (!request.getRequest().getProtocol().startsWith("HTTP/0"))
  +		    parseHeaders();
  +	    }
  +	} catch (Exception e) {
  +	    try {
  +		log("process.parse", e);
  +		((HttpServletResponse) response.getResponse()).sendError
  +		    (HttpServletResponse.SC_BAD_REQUEST);
  +	    } catch (Exception f) {
  +		;
  +	    }
  +	}
  +
  +	// Ask our Container to process this request
  +	try {
  +	    if (ok) {
  +		connector.getContainer().invoke(request, response);
  +	    }
  +	} catch (ServletException e) {
  +	    log("process.invoke", e);
  +	    try {
  +		((HttpServletResponse) response.getResponse()).sendError
  +		    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
  +	    } catch (Exception f) {
  +		;
  +	    }
  +	    ok = false;
  +	} catch (Throwable e) {
  +	    log("process.invoke", e);
  +	    try {
  +		((HttpServletResponse) response.getResponse()).sendError
  +		    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
  +	    } catch (Exception f) {
  +		;
  +	    }
  +	    ok = false;
  +	}
  +
  +	// Finish up the handling of the request
  +	try {
  +	    if (output != null)
  +		output.flush();
  +	} catch (IOException e) {
  +	    ;
  +	}
  +	try {
  +	    socket.close();
  +	} catch (IOException e) {
  +	    ;
  +	}
  +	socket = null;
  +
  +    }
  +
  +
  +    /**
  +     * Read a line from the specified input stream, and strip off the
  +     * trailing carriage return and newline (if any).  Return the remaining
  +     * characters that were read as a String.
  +     *
  +     * @returns The lline that was read, or <code>null</code> if end-of-file
  +     *  was encountered
  +     *
  +     * @exception IOException if an input/output error occurs
  +     */
  +    private String read() throws IOException {
  +
  +	StringBuffer sb = new StringBuffer();
  +	while (true) {
  +	    int ch = input.read();
  +	    if (ch < 0) {
  +		if (sb.length() == 0) {
  +		    return (null);
  +		} else {
  +		    break;
  +		}
  +	    } else if (ch == '\r') {
  +		continue;
  +	    } else if (ch == '\n') {
  +		break;
  +	    }
  +	    sb.append((char) ch);
  +	}
  +	return (sb.toString());
  +
  +    }
  +
  +
  +    // ---------------------------------------------- Background Thread Methods
  +
  +
  +    /**
  +     * The background thread that listens for incoming TCP/IP connections and
  +     * hands them off to an appropriate processor.
  +     */
  +    public void run() {
  +
  +	while (!stopped) {
  +
  +	    // Wait for the next socket to be assigned
  +	    try {
  +		wait();
  +	    } catch (InterruptedException e) {
  +		;
  +	    }
  +	    if (socket == null)
  +		continue;
  +
  +	    // Process the request from this socket
  +	    process();
  +
  +	    // Finish up this request
  +	    request.recycle();
  +	    response.recycle();
  +	    connector.recycle(this);
  +
  +	}
  +
  +	threadSync.notifyAll();
  +
  +    }
  +
  +
  +    /**
  +     * Start the background processing thread.
  +     */
  +    private void threadStart() {
  +
  +	if (threadName == null)
  +	    threadName = connector.getThreadName() + "[" + id + "]";
  +
  +	log("Starting");
  +
  +	thread = new Thread(this, threadName);
  +	thread.setDaemon(true);
  +	thread.start();
  +
  +    }
  +
  +
  +    /**
  +     * Stop the background processing thread.
  +     */
  +    private void threadStop() {
  +
  +	log("Stopping");
  +
  +	stopped = true;
  +	process(null);
  +	try {
  +	    threadSync.wait(5000);
  +	} catch (InterruptedException e) {
  +	    ;
  +	}
  +	thread = null;
  +
  +    }
  +
  +
       // ------------------------------------------------------ Lifecycle Methods
   
   
  @@ -178,9 +619,14 @@
        */
       public void start() throws LifecycleException {
   
  +	if (started)
  +	    throw new LifecycleException
  +		(sm.getString("httpProcessor.start"));
  +	started = true;
   	lifecycle.fireLifecycleEvent(START_EVENT, null);
  -	;	// FIXME: start()
   
  +	threadStart();
  +
       }
   
   
  @@ -191,8 +637,13 @@
        */
       public void stop() throws LifecycleException {
   
  +	if (!started)
  +	    throw new LifecycleException
  +		(sm.getString("httpProcessor.stop"));
  +	started = false;
   	lifecycle.fireLifecycleEvent(STOP_EVENT, null);
  -	;	// FIXME: stop()
  +
  +	threadStop();
   
       }
   
  
  
  
  1.2       +57 -3     jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/connector/http/HttpRequestImpl.java
  
  Index: HttpRequestImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/connector/http/HttpRequestImpl.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- HttpRequestImpl.java	2000/04/14 18:55:28	1.1
  +++ HttpRequestImpl.java	2000/04/15 05:39:16	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/connector/http/HttpRequestImpl.java,v 1.1 2000/04/14 18:55:28 craigmcc Exp $
  - * $Revision: 1.1 $
  - * $Date: 2000/04/14 18:55:28 $
  + * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/connector/http/HttpRequestImpl.java,v 1.2 2000/04/15 05:39:16 craigmcc Exp $
  + * $Revision: 1.2 $
  + * $Date: 2000/04/15 05:39:16 $
    *
    * ====================================================================
    *
  @@ -65,6 +65,7 @@
   package org.apache.tomcat.connector.http;
   
   
  +import java.net.InetAddress;
   import org.apache.tomcat.connector.HttpRequestBase;
   
   
  @@ -72,7 +73,7 @@
    * Implementation of <b>HttpRequest</b> specific to the HTTP connector.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.1 $ $Date: 2000/04/14 18:55:28 $
  + * @version $Revision: 1.2 $ $Date: 2000/04/15 05:39:16 $
    */
   
   final class HttpRequestImpl
  @@ -83,6 +84,12 @@
   
   
       /**
  +     * The InetAddress of the remote client of ths request.
  +     */
  +    protected InetAddress inet = null;
  +
  +
  +    /**
        * Descriptive information about this Request implementation.
        */
       protected static final String info =
  @@ -93,6 +100,30 @@
   
   
       /**
  +     * [Package Private] Return the InetAddress of the remote client of
  +     * this request.
  +     */
  +    InetAddress getInet() {
  +
  +	return (inet);
  +
  +    }
  +
  +
  +    /**
  +     * [Package Private] Set the InetAddress of the remote client of
  +     * this request.
  +     *
  +     * @param inet The new InetAddress
  +     */
  +    void setInet(InetAddress inet) {
  +
  +	this.inet = inet;
  +
  +    }
  +
  +
  +    /**
        * Return descriptive information about this Request implementation and
        * the corresponding version number, in the format
        * <code>&lt;description&gt;/&lt;version&gt;</code>.
  @@ -108,12 +139,35 @@
   
   
       /**
  +     * Return the Internet Protocol (IP) address of the client that sent
  +     * this request.
  +     */
  +    public String getRemoteAddr() {
  +
  +	return (inet.getHostAddress());
  +
  +    }
  +
  +
  +    /**
  +     * Return the fully qualified name of the client that sent this request,
  +     * or the IP address of the client if the name cannot be determined.
  +     */
  +    public String getRemoteHost() {
  +
  +	return (inet.getHostName());
  +
  +    }
  +
  +
  +    /**
        * Release all object references, and initialize instance variables, in
        * preparation for reuse of this object.
        */
       public void recycle() {
   
   	super.recycle();
  +	inet = null;
   	((HttpConnector) connector).recycle(this);
   
       }
  
  
  
  1.2       +7 -0      jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/connector/http/LocalStrings.properties
  
  Index: LocalStrings.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/connector/http/LocalStrings.properties,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- LocalStrings.properties	2000/02/20 02:57:10	1.1
  +++ LocalStrings.properties	2000/04/15 05:39:16	1.2
  @@ -1,2 +1,9 @@
   httpConnector.alreadyStarted=HTTP connector has already been started
   httpConnector.notStarted=HTTP connector has not yet been started
  +httpProcessor.parseHeaders.contentLength=Invalid 'Content-Length' header
  +httpProcessor.parseHeaders.colon=Invalid HTTP header format
  +httpProcessor.parseHeaders.portNumber=Invalid TCP/IP port number in 'Host' header
  +httpProcessor.parseRequest.method=Missing HTTP request method
  +httpProcessor.parseRequest.uri=Missing HTTP request URI
  +httpProcessor.start=HTTP processor has already been started
  +httpProcessor.stop=HTTP processor has already been stopped
  
  
  
  1.1                  jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/util/CookieUtil.java
  
  Index: CookieUtil.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/util/CookieUtil.java,v 1.1 2000/04/15 05:39:18 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/04/15 05:39:18 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  
  package org.apache.tomcat.util;
  
  
  import java.util.StringTokenizer;
  import java.util.Vector;
  import javax.servlet.http.Cookie;
  
  
  /**
   * General purpose Cookie parsing and encoding utility methods.
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/04/15 05:39:18 $
   */
  
  public final class CookieUtil {
  
  
      /**
       * Parse a cookie header into an array of cookies according to RFC 2109.
       *
       * @param header Value of an HTTP "Cookie" header
       */
      public static Cookie[] parseCookieHeader(String header) {
  
  	if ((header == null) || (header.length() < 1))
  	    return (new Cookie[0]);
  
  	Vector cookieJar = new Vector();
  	StringTokenizer tokens = new StringTokenizer(header, ";");
  	while (tokens.hasMoreTokens()) {
  	    try {
  		String token = tokens.nextToken();
  		int equals = token.indexOf("=");
  		if (equals > 0) {
  		    String name = URLDecode(token.substring(0, equals).trim());
  		    String value = URLDecode(token.substring(equals+1).trim());
  		    cookieJar.addElement(new Cookie(name, value));
  		}
  	    } catch (Throwable e) {
  		;
  	    }
  	}
  
  	Cookie[] cookies = new Cookie[cookieJar.size()];
  	cookieJar.copyInto(cookies);
  	return (cookies);
  
      }
  
  
      /**
       * Decode and return the specified URL-encoded String.
       *
       * @param str The url-encoded string
       *
       * @exception IllegalArgumentException if a '%' character is not followed
       * by a valid 2-digit hexadecimal number
       */
      public static String URLDecode(String str)
  	throws IllegalArgumentException {
  
  	if (str == null)
  	    return (null);
  
  	StringBuffer dec = new StringBuffer();
  	int pos = 0;
  	int len = str.length();
  	dec.ensureCapacity(str.length());
  
  	while (pos < len) {
  	    int lookahead;	// Look-ahead position
  
  	    // Look ahead to the next URLencoded metacharacter, if any
  	    for (lookahead = pos; lookahead < len; lookahead++) {
  		char ch = str.charAt(lookahead);
  		if ((ch == '+') || (ch == '%'))
  		    break;
  	    }
  
  	    // If there were non-metacharacters, copy them as a block
  	    if (lookahead > pos) {
  		dec.append(str.substring(pos, lookahead));
  		pos = lookahead;
  	    }
  
  	    // Shortcut out if we are at the end of the string
  	    if (pos >= len)
  		break;
  
  	    // Process the next metacharacter
  	    char meta = str.charAt(pos);
  	    if (meta == '+') {
  		dec.append(' ');
  		pos++;
  	    } else if (meta == '%') {
  		try {
  		    dec.append((char) Integer.parseInt
  			       (str.substring(pos+1, pos+3), 16));
  		} catch (NumberFormatException e) {
  		    throw new IllegalArgumentException
  			("Invalid hexadecimal '" + str.substring(pos+1, pos+3)
  			 + " in URLencoded string");
  		} catch (StringIndexOutOfBoundsException e) {
  		    throw new IllegalArgumentException
  			("Invalid unescaped '%' in URLcoded string");
  		}
  		pos += 3;
  	    }
  	}
  	return (dec.toString());
  
      }
  
  }