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/08/23 03:07:18 UTC

cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/util RequestUtil.java

craigmcc    00/08/22 18:07:17

  Modified:    catalina/src/share/org/apache/catalina Wrapper.java
               catalina/src/share/org/apache/catalina/connector
                        HttpRequestBase.java
               catalina/src/share/org/apache/catalina/core
                        ApplicationDispatcher.java
                        ApplicationFilterConfig.java
                        LocalStrings.properties StandardWrapper.java
                        StandardWrapperValve.java
               catalina/src/share/org/apache/catalina/util RequestUtil.java
  Added:       catalina/src/share/org/apache/catalina/core
                        ApplicationHttpRequest.java
                        ApplicationHttpResponse.java
                        ApplicationRequest.java ApplicationResponse.java
  Log:
  Implement substantial changes to ApplicationDispatcher (the request
  dispatcher implementation class for Catalina) to support the new 2.3
  ability for servlets to wrap the request and response objects that they
  pass to forward() or include().  Previously, servlets were required to use
  the original request and response objects.  This is the largest single
  impact change required by Servlet 2.3.
  
  Be sure you pick up the updates to the "jakarta-servletapi" module, which
  fixes a problem with getSession() returning null on all session related
  events.
  
  As of now, Tomcat 4.0 passes all but one of the Watchdog servlet tests
  (the one that checks for version 2.2 :-), and all but one of the JSP tests
  (positiveInclude.jsp, which needs further investigation).
  
  Revision  Changes    Path
  1.2       +15 -4     jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/Wrapper.java
  
  Index: Wrapper.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/Wrapper.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Wrapper.java	2000/08/11 05:24:12	1.1
  +++ Wrapper.java	2000/08/23 01:07:07	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/Wrapper.java,v 1.1 2000/08/11 05:24:12 craigmcc Exp $
  - * $Revision: 1.1 $
  - * $Date: 2000/08/11 05:24:12 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/Wrapper.java,v 1.2 2000/08/23 01:07:07 craigmcc Exp $
  + * $Revision: 1.2 $
  + * $Date: 2000/08/23 01:07:07 $
    *
    * ====================================================================
    *
  @@ -67,6 +67,7 @@
   
   import javax.servlet.Servlet;
   import javax.servlet.ServletException;
  +import javax.servlet.UnavailableException;
   
   
   /**
  @@ -89,7 +90,7 @@
    * <code>IllegalArgumentException</code>.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.1 $ $Date: 2000/08/11 05:24:12 $
  + * @version $Revision: 1.2 $ $Date: 2000/08/23 01:07:07 $
    */
   
   public interface Wrapper extends Container {
  @@ -295,6 +296,16 @@
        * @param name Security role used within this servlet to be removed
        */
       public void removeSecurityReference(String name);
  +
  +
  +    /**
  +     * Process an UnavailableException, marking this servlet as unavailable
  +     * for the specified amount of time.
  +     *
  +     * @param unavailable The exception that occurred, or <code>null</code>
  +     *  to mark this servlet as permanently unavailable
  +     */
  +    public void unavailable(UnavailableException unavailable);
   
   
       /**
  
  
  
  1.5       +9 -69     jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/HttpRequestBase.java
  
  Index: HttpRequestBase.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/HttpRequestBase.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- HttpRequestBase.java	2000/08/17 23:19:58	1.4
  +++ HttpRequestBase.java	2000/08/23 01:07:08	1.5
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/HttpRequestBase.java,v 1.4 2000/08/17 23:19:58 craigmcc Exp $
  - * $Revision: 1.4 $
  - * $Date: 2000/08/17 23:19:58 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/HttpRequestBase.java,v 1.5 2000/08/23 01:07:08 craigmcc Exp $
  + * $Revision: 1.5 $
  + * $Date: 2000/08/23 01:07:08 $
    *
    * ====================================================================
    *
  @@ -86,6 +86,7 @@
   import org.apache.catalina.Realm;
   import org.apache.catalina.Session;
   import org.apache.catalina.util.Enumerator;
  +import org.apache.catalina.util.RequestUtil;
   import org.apache.catalina.util.StringParser;
   
   
  @@ -96,7 +97,7 @@
    * be implemented.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.4 $ $Date: 2000/08/17 23:19:58 $
  + * @version $Revision: 1.5 $ $Date: 2000/08/23 01:07:08 $
    */
   
   public class HttpRequestBase
  @@ -529,7 +530,7 @@
   	String queryString = getQueryString();
   	if ((queryString != null) && (queryString.length() > 0)) {
   	    try {
  -	        parseParameters(results, queryString);
  +	        RequestUtil.parseParameters(results, queryString);
   	    } catch (Throwable t) {
   	        ;
   	    }
  @@ -546,9 +547,10 @@
   		String data = null;
   		String encoding = getCharacterEncoding();
   		if (encoding == null)
  -		    parseParameters(results, new String(buf));
  +		    RequestUtil.parseParameters(results, new String(buf));
   		else
  -		    parseParameters(results, new String(buf, encoding));
  +		    RequestUtil.parseParameters(results,
  +						new String(buf, encoding));
   	    } catch (Throwable t) {
   	        ;
   	    }
  @@ -556,68 +558,6 @@
   
   	// Store the final results
   	parameters = results;
  -
  -    }
  -
  -
  -    /**
  -     * Append request parameters from the specified String to the specified
  -     * Map.  It is presumed that the specified Map is not accessed from any
  -     * other thread, so no synchronization is performed.
  -     *
  -     * @param map Map that accumulates the resulting parameters
  -     * @param data Input string containing request parameters
  -     *
  -     * @exception IllegalArgumentException if the data is malformed
  -     */
  -    private void parseParameters(Map map, String data) {
  -
  -        if ((data == null) || (data.length() < 1))
  -	    return;
  -
  -	// Initialize the variables we will require
  -	StringParser parser = new StringParser(data);
  -	boolean first = true;
  -	int nameStart = 0;
  -	int nameEnd = 0;
  -	int valueStart = 0;
  -	int valueEnd = 0;
  -	String name = null;
  -	String value = null;
  -	String oldValues[] = null;
  -	String newValues[] = null;
  -
  -	// Loop through the "name=value" entries in the input data
  -	while (true) {
  -
  -	    // Extract the name and value components
  -	    if (first)
  -	        first = false;
  -	    else
  -	        parser.advance();
  -	    nameStart = parser.getIndex();
  -	    nameEnd = parser.findChar('=');
  -	    parser.advance();
  -	    valueStart = parser.getIndex();
  -	    valueEnd = parser.findChar('&');
  -	    name = parser.extract(nameStart, nameEnd);
  -	    value = parser.extract(valueStart, valueEnd);
  -
  -	    // A zero-length name or value means we are done
  -	    if ((name.length() < 1) || (value.length() < 1))
  -	        break;
  -
  -	    // Create or update the array of values for this name
  -	    oldValues = (String[]) map.get(name);
  -	    if (oldValues == null)
  -	        oldValues = new String[0];
  -	    newValues = new String[oldValues.length + 1];
  -	    System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
  -	    newValues[oldValues.length] = value;
  -	    map.put(name, newValues);
  -
  -	}
  -
   
       }
   
  
  
  
  1.2       +274 -173  jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ApplicationDispatcher.java
  
  Index: ApplicationDispatcher.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ApplicationDispatcher.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ApplicationDispatcher.java	2000/08/11 23:40:44	1.1
  +++ ApplicationDispatcher.java	2000/08/23 01:07:10	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ApplicationDispatcher.java,v 1.1 2000/08/11 23:40:44 craigmcc Exp $
  - * $Revision: 1.1 $
  - * $Date: 2000/08/11 23:40:44 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ApplicationDispatcher.java,v 1.2 2000/08/23 01:07:10 craigmcc Exp $
  + * $Revision: 1.2 $
  + * $Date: 2000/08/23 01:07:10 $
    *
    * ====================================================================
    *
  @@ -68,19 +68,17 @@
   import java.io.IOException;
   import java.io.PrintWriter;
   import javax.servlet.RequestDispatcher;
  -import javax.servlet.ServletContext;
  +import javax.servlet.Servlet;
   import javax.servlet.ServletException;
   import javax.servlet.ServletOutputStream;
   import javax.servlet.ServletRequest;
   import javax.servlet.ServletResponse;
  +import javax.servlet.UnavailableException;
  +import javax.servlet.http.HttpServlet;
   import javax.servlet.http.HttpServletRequest;
   import javax.servlet.http.HttpServletResponse;
   import org.apache.catalina.Context;
  -import org.apache.catalina.HttpRequest;
  -import org.apache.catalina.HttpResponse;
   import org.apache.catalina.Logger;
  -import org.apache.catalina.Request;
  -import org.apache.catalina.Response;
   import org.apache.catalina.Wrapper;
   import org.apache.catalina.util.StringManager;
   
  @@ -89,10 +87,14 @@
    * Standard implementation of <code>RequestDispatcher</code> that allows a
    * request to be forwarded to a different resource to create the ultimate
    * response, or to include the output of another resource in the response
  - * from this resource.
  + * from this resource.  This implementation allows application level servlets
  + * to wrap the request and/or response objects that are passed on to the
  + * called resource, as long as the wrapping classes extend
  + * <code>javax.servlet.ServletRequestWrapper</code> and
  + * <code>javax.servlet.ServletResponseWrapper</code>.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.1 $ $Date: 2000/08/11 23:40:44 $
  + * @version $Revision: 1.2 $ $Date: 2000/08/23 01:07:10 $
    */
   
   final class ApplicationDispatcher
  @@ -109,16 +111,20 @@
        * was acquired by name, rather than by path.
        *
        * @param wrapper The Wrapper associated with the resource that will
  -     *  be forwarded to or included
  -     * @param servletPath The revised servlet path to this resource
  +     *  be forwarded to or included (required)
  +     * @param servletPath The revised servlet path to this resource (if any)
        * @param pathInfo The revised extra path information to this resource
  +     *  (if any)
        * @param queryString Query string parameters included with this request
  +     *  (if any)
        */
  -    public ApplicationDispatcher(Wrapper wrapper,
  -    			         String servletPath, String pathInfo,
  -    			         String queryString) {
  +    public ApplicationDispatcher
  +	(Wrapper wrapper, String servletPath,
  +	 String pathInfo, String queryString) {
   
   	super();
  +
  +	// Save all of our configuration parameters
   	this.wrapper = wrapper;
   	this.context = (Context) wrapper.getParent();
   	this.servletPath = servletPath;
  @@ -194,119 +200,115 @@
       public void forward(ServletRequest request, ServletResponse response)
           throws IOException, ServletException {
   
  -	// Reset any output that has already been buffered
  +	// Reset any output that has been buffered, but keep headers/cookies
   	if (response.isCommitted())
   	    throw new IllegalStateException
  -	      (sm.getString("applicationDispatcher.forward.ise"));
  -	((Response) response).resetBuffer();
  +		(sm.getString("applicationDispatcher.forward.ise"));
  +	;	// FIXME - No API call to reset just the buffer
   
  -	// Cast the servlet request and response to our internal objects
  -	Request srequest = (Request) request;
  -	Response sresponse = (Response) response;
  -	HttpRequest hrequest = null;
  -	if (request instanceof HttpRequest)
  -	    hrequest = (HttpRequest) request;
  -	HttpResponse hresponse = null;
  -	if (response instanceof HttpResponse)
  -	    hresponse = (HttpResponse) response;
  +	// Identify the HTTP-specific request and response objects (if any)
  +	HttpServletRequest hrequest = null;
  +	if (request instanceof HttpServletRequest)
  +	    hrequest = (HttpServletRequest) request;
  +	HttpServletResponse hresponse = null;
  +	if (response instanceof HttpServletResponse)
  +	    hresponse = (HttpServletResponse) response;
   
  -	// Handle a non-HTTP forward by passing on the existing request and response
  +	// Handle a non-HTTP forward by passing the existing request/response
   	if ((hrequest == null) || (hresponse == null)) {
  +
   	    if (debug >= 1)
   		log(" Non-HTTP Forward");
  +
   	    try {
  -		wrapper.invoke(srequest, sresponse);
  +		invoke(request, response);
   	    } catch (IOException e) {
   		throw e;
   	    } catch (ServletException e) {
   		throw e;
   	    } catch (Throwable t) {
   		throw new ServletException
  -		  (sm.getString("applicationDispatcher.forward.throw"), t);
  +		    (sm.getString("applicationDispatcher.forward.throw"), t);
   	    }
  +
   	}
  +
  +	// Handle an HTTP named dispatcher forward
  +	else if ((servletPath == null) && (pathInfo == null)) {
   
  -	// Handle an HTTP named dispatcher forward (no wrapping is required)
  -        else if ((servletPath == null) && (pathInfo == null)) {
   	    if (debug >= 1)
   		log(" Named Dispatcher Forward");
  -	    try {
  -		wrapper.invoke(hrequest, hresponse);
  -	    } catch (IOException e) {
  -		throw e;
  -	    } catch (ServletException e) {
  -		throw e;
  -	    } catch (Throwable t) {
  -		throw new ServletException
  -		  (sm.getString("applicationDispatcher.forward.throw"), t);
  -	    }
  -	}
   
  -	// Handle an HTTP path-based forward with no new query parameters
  -	else if (queryString == null) {
  -	    if (debug >= 1)
  -		log(" Non-Wrapped Path Forward");
  -	    StringBuffer sb = new StringBuffer();
  -	    if (context.getPath() != null)
  -	        sb.append(context.getPath());
  -	    if (servletPath != null)
  -	        sb.append(servletPath);
  -	    if (pathInfo != null)
  -	        sb.append(pathInfo);
  -	    String requestURI = sb.toString();
  -	    hrequest.setRequestURI(requestURI);
  -	    hrequest.setServletPath(servletPath);
  -	    hrequest.setPathInfo(pathInfo);
  -	    // Keep original query string
  -	    if (debug >= 1)
  -		log(" requestURI=" + requestURI);
   	    try {
  -		wrapper.invoke(hrequest, hresponse);
  +		invoke(request, response);
   	    } catch (IOException e) {
   		throw e;
   	    } catch (ServletException e) {
   		throw e;
   	    } catch (Throwable t) {
   		throw new ServletException
  -		  (sm.getString("applicationDispatcher.forward.throw"), t);
  +		    (sm.getString("applicationDispatcher.forward.throw"), t);
   	    }
  -	}
   
  +	}
   
  -	// Handle an HTTP path-based dispatcher include with request wrapping
  +	// Handle an HTTP path-based forward
   	else {
  +
   	    if (debug >= 1)
  -		log(" Wrapped Path Forward");
  -	    WrappedRequest wrequest = new WrappedRequest(hrequest, queryString);
  +		log(" Path Based Forward");
  +
  +	    ApplicationHttpRequest wrequest =
  +		new ApplicationHttpRequest((HttpServletRequest) request);
   	    StringBuffer sb = new StringBuffer();
  -	    if (context.getPath() != null)
  -	        sb.append(context.getPath());
  +	    String contextPath = context.getPath();
  +	    if (contextPath != null)
  +		sb.append(contextPath);
   	    if (servletPath != null)
  -	        sb.append(servletPath);
  +		sb.append(servletPath);
   	    if (pathInfo != null)
  -	        sb.append(pathInfo);
  -	    String requestURI = sb.toString();
  -	    if (debug >= 1)
  -		log(" requestURI=" + requestURI);
  -	    wrequest.setRequestURI(requestURI);
  +		sb.append(pathInfo);
  +	    wrequest.setContextPath(contextPath);
  +	    wrequest.setRequestURI(sb.toString());
   	    wrequest.setServletPath(servletPath);
   	    wrequest.setPathInfo(pathInfo);
  -	    wrequest.setQueryString(queryString);
  +	    if (queryString != null) {
  +		wrequest.setQueryString(queryString);
  +		wrequest.mergeParameters(queryString);
  +	    }
  +
   	    try {
  -		wrapper.invoke(wrequest, hresponse);
  +		invoke(wrequest, response);
   	    } catch (IOException e) {
   		throw e;
   	    } catch (ServletException e) {
   		throw e;
   	    } catch (Throwable t) {
   		throw new ServletException
  -		  (sm.getString("applicationDispatcher.forward.throw"), t);
  +		    (sm.getString("applicationDispatcher.forward.throw"), t);
   	    }
  +
   	}
   
   	// Commit and close the response before we return
  -	sresponse.finishResponse();
  -
  +	response.flushBuffer();
  +	try {
  +	    PrintWriter writer = response.getWriter();
  +	    writer.flush();
  +	    writer.close();
  +	} catch (IllegalStateException e) {
  +	    try {
  +		ServletOutputStream stream = response.getOutputStream();
  +		stream.flush();
  +		stream.close();
  +	    } catch (IllegalStateException f) {
  +		;
  +	    } catch (IOException f) {
  +		;
  +	    }
  +	} catch (IOException e) {
  +	    ;
  +	}
   
       }
   
  @@ -323,122 +325,225 @@
       public void include(ServletRequest request, ServletResponse response)
           throws IOException, ServletException {
   
  -	// Flush the response to avoid allowing the included resource
  -	// to set headers
  -	//	response.flushBuffer();
  -
  -	// Cast the servlet request and response to our internal objects
  -	Request srequest = (Request) request;
  -	Response sresponse = (Response) response;
  -	HttpRequest hrequest = null;
  -	if (request instanceof HttpRequest)
  -	    hrequest = (HttpRequest) request;
  -	HttpResponse hresponse = null;
  -	if (response instanceof HttpResponse)
  -	    hresponse = (HttpResponse) response;
  -	boolean oldIncluded = sresponse.getIncluded();
  +	// Create a wrapped response to use for this request
  +	ServletResponse wresponse = null;
  +	if (response instanceof HttpServletResponse) {
  +	    response =
  +		new ApplicationHttpResponse((HttpServletResponse) response,
  +					    true);
  +	} else {
  +	    response = new ApplicationResponse(response, true);
  +	}
   
  -	// Handle a non-HTTP include by passing on the existing request and response
  -	if ((hrequest == null) || (hresponse == null)) {
  +	// Handle a non-HTTP include
  +	if (!(request instanceof HttpServletRequest) ||
  +	    !(response instanceof HttpServletResponse)) {
  +
   	    if (debug >= 1)
   		log(" Non-HTTP Include");
  +
   	    try {
  -		wrapper.invoke(srequest, sresponse);
  -		sresponse.setIncluded(oldIncluded);
  +		invoke(request, wresponse);
   	    } catch (IOException e) {
  -		sresponse.setIncluded(oldIncluded);
   		throw e;
   	    } catch (ServletException e) {
  -		sresponse.setIncluded(oldIncluded);
   		throw e;
   	    } catch (Throwable t) {
  -		sresponse.setIncluded(oldIncluded);
   		throw new ServletException
  -		  (sm.getString("applicationDispatcher.include.throw"), t);
  +		    (sm.getString("applicationDispatcher.include.throw"), t);
   	    }
  -	    return;
  +
   	}
   
  -	// Handle an HTTP named dispatcher include (no wrapping is required)
  -	if ((servletPath == null) && (pathInfo == null)) {
  +	// Handle an HTTP named dispatcher include
  +	else if ((servletPath == null) && (pathInfo == null)) {
  +
   	    if (debug >= 1)
   		log(" Named Dispatcher Include");
  +
   	    try {
  -		wrapper.invoke(hrequest, hresponse);
  -		sresponse.setIncluded(oldIncluded);
  +		invoke(request, wresponse);
   	    } catch (IOException e) {
  -		sresponse.setIncluded(oldIncluded);
   		throw e;
   	    } catch (ServletException e) {
  -		sresponse.setIncluded(oldIncluded);
   		throw e;
   	    } catch (Throwable t) {
  -		sresponse.setIncluded(oldIncluded);
   		throw new ServletException
  -		  (sm.getString("applicationDispatcher.include.throw"), t);
  +		    (sm.getString("applicationDispatcher.include.throw"), t);
   	    }
  -	    return;
  -	}
   
  -	// Handle an HTTP path-based dispatcher include (with request wrapping)
  -	if (debug >= 1)
  -	    log(" Wrapped Path Include");
  -	WrappedRequest wrequest = new WrappedRequest(hrequest, queryString);
  -	String contextPath = context.getPath();
  -	StringBuffer sb = new StringBuffer();
  -	if (contextPath != null)
  -	    sb.append(contextPath);
  -	if (servletPath != null)
  -	    sb.append(servletPath);
  -	if (pathInfo != null)
  -	    sb.append(pathInfo);
  -	ServletRequest sr = wrequest.getRequest();
  -	if (sb.length() > 0) {
  -	    if (debug >= 1)
  -		log("  requestURI=" + sb.toString());
  -	    sr.setAttribute("javax.servlet.include.request_uri",
  -			    sb.toString());
   	}
  -	if (contextPath != null) {
  -	    if (debug >= 1)
  -		log("  contextPath=" + contextPath);
  -	    sr.setAttribute("javax.servlet.include.context_path", contextPath);
  -	}
  -	if (servletPath != null) {
  +
  +	// Handle an HTTP path based include
  +	else {
  +
   	    if (debug >= 1)
  -		log("  servletPath=" + servletPath);
  -	    sr.setAttribute("javax.servlet.include.servlet_path", servletPath);
  +		log(" Path Based Include");
  +
  +	    ApplicationHttpRequest wrequest =
  +		new ApplicationHttpRequest((HttpServletRequest) request);
  +	    StringBuffer sb = new StringBuffer();
  +	    String contextPath = context.getPath();
  +	    if (contextPath != null)
  +		sb.append(contextPath);
  +	    if (servletPath != null)
  +		sb.append(servletPath);
  +	    if (pathInfo != null)
  +		sb.append(pathInfo);
  +	    if (sb.length() > 0)
  +		wrequest.setAttribute("javax.servlet.include.request_uri",
  +				      sb.toString());
  +	    if (contextPath != null)
  +		wrequest.setAttribute("javax.servlet.include.context_path",
  +				      contextPath);
  +	    if (servletPath != null)
  +		wrequest.setAttribute("javax.servlet.include.servlet_path",
  +				      servletPath);
  +	    if (pathInfo != null)
  +		wrequest.setAttribute("javax.servlet.include.path_info",
  +				      pathInfo);
  +	    if (queryString != null) {
  +		wrequest.setAttribute("javax.servlet.include.query_string",
  +				      queryString);
  +		wrequest.mergeParameters(queryString);
  +	    }
  +
  +	    try {
  +		invoke(wrequest, wresponse);
  +	    } catch (IOException e) {
  +		throw e;
  +	    } catch (ServletException e) {
  +		throw e;
  +	    } catch (Throwable t) {
  +		throw new ServletException
  +		    (sm.getString("applicationDispatcher.include.throw"), t);
  +	    }
  +
   	}
  -	if (pathInfo != null) {
  -	    if (debug >= 1)
  -		log("  pathInfo=" + pathInfo);
  -	    sr.setAttribute("javax.servlet.include.path_info", pathInfo);
  +
  +    }
  +
  +
  +    // -------------------------------------------------------- Private Methods
  +
  +
  +    /**
  +     * Ask the resource represented by this RequestDispatcher to process
  +     * the associated request, and create (or append to) the associated
  +     * response.
  +     * <p>
  +     * <strong>IMPLEMENTATION NOTE</strong>: This implementation assumes
  +     * that no filters are applied to a forwarded or included resource,
  +     * because they were already done for the original request.
  +     *
  +     * @param request The servlet request we are processing
  +     * @param response The servlet response we are creating
  +     *
  +     * @exception IOException if an input/output error occurs
  +     * @exception ServletException if a servlet error occurs
  +     */
  +    private void invoke(ServletRequest request, ServletResponse response)
  +	throws IOException, ServletException {
  +
  +	// Initialize local variables we may need
  +	HttpServletRequest hrequest = null;
  +	if (request instanceof HttpServletRequest)
  +	    hrequest = (HttpServletRequest) request;
  +	HttpServletResponse hresponse = null;
  +	if (response instanceof HttpServletResponse)
  +	    hresponse = (HttpServletResponse) response;
  +	Servlet servlet = null;
  +	Throwable throwable = null;
  +	boolean unavailable = false;
  +
  +	// Check for the servlet being marked unavailable
  +	if (wrapper.isUnavailable()) {
  +	    log(sm.getString("applicationDispatcher.isUnavailable",
  +			     wrapper.getName()));
  +	    if (hresponse == null) {
  +		;	// NOTE - Not much we can do generically
  +	    } else {
  +		long available = wrapper.getAvailable();
  +		if ((available > 0L) && (available < Long.MAX_VALUE))
  +		    hresponse.setDateHeader("Retry-After", available);
  +		hresponse.sendError
  +		    (HttpServletResponse.SC_SERVICE_UNAVAILABLE,
  +		     sm.getString("applicationDispatcher.isUnavailable",
  +				  wrapper.getName()));
  +	    }
  +	    unavailable = true;
   	}
  -	if (queryString != null) {
  -	    if (debug >= 1)
  -		log("  queryString=" + queryString);
  -	    sr.setAttribute("javax.servlet.include.query_string", queryString);
  +
  +	// Allocate a servlet instance to process this request
  +	try {
  +	    if (!unavailable) {
  +		servlet = wrapper.allocate();
  +	    }
  +	} catch (ServletException e) {
  +	    log(sm.getString("applicationDispatcher.allocateException",
  +			     wrapper.getName()), e);
  +	    throwable = e;
  +	    // exception(request, response, e);
  +	    servlet = null;
  +	} catch (Throwable e) {
  +	    log(sm.getString("applicationDispatcher.allocateException",
  +			     wrapper.getName()), e);
  +	    throwable = e;
  +	    // exception(request, response, e);
  +	    servlet = null;
   	}
   
  +	// Call the service() method for the allocated servlet instance
   	try {
  -	    wrapper.invoke(wrequest, hresponse);
  -	    sresponse.setIncluded(oldIncluded);
  +	    if (servlet != null) {
  +		if ((servlet instanceof HttpServlet) &&
  +		    (hrequest != null) && (hresponse != null))
  +		    ((HttpServlet) servlet).service(hrequest, hresponse);
  +		else
  +		    servlet.service(request, response);
  +	    }
   	} catch (IOException e) {
  -	    sresponse.setIncluded(oldIncluded);
  -	    throw e;
  +	    log(sm.getString("applicationDispatcher.serviceException",
  +			     wrapper.getName()), e);
  +	} catch (UnavailableException e) {
  +	    log(sm.getString("applicationDispatcher.serviceException",
  +			     wrapper.getName()), e);
  +	    throwable = e;
  +	    // exception(request, response, e);
  +	    wrapper.unavailable(e);
   	} catch (ServletException e) {
  -	    sresponse.setIncluded(oldIncluded);
  -	    throw e;
  -	} catch (Throwable t) {
  -	    sresponse.setIncluded(oldIncluded);
  -	    throw new ServletException
  -	      (sm.getString("applicationDispatcher.include.throw"), t);
  +	    log(sm.getString("applicationDispatcher.serviceException",
  +			     wrapper.getName()), e);
  +	    throwable = e;
  +	    // exception(request, response, e);
  +	} catch (Throwable e) {
  +	    log(sm.getString("applicationDispatcher.serviceException",
  +			     wrapper.getName()), e);
  +	    throwable = e;
  +	    // exception(request, response, e);
   	}
   
  -    }
  +	// Deallocate the allocated servlet instance
  +	try {
  +	    if (servlet != null)
  +		wrapper.deallocate(servlet);
  +	} catch (ServletException e) {
  +	    log(sm.getString("applicationDispatcher.deallocateException",
  +			     wrapper.getName()), e);
  +	    throwable = e;
  +	    // exception(request, response, e);
  +	} catch (Throwable e) {
  +	    log(sm.getString("applicationDispatcher.deallocateException",
  +			     wrapper.getName()), e);
  +	    throwable = e;
  +	    // exception(request, response, e);
  +	}
   
  +	// Generate a response for the generated HTTP status and message
  +	// if (throwable == null)
  +	//     status(request, response);
   
  -    // -------------------------------------------------------- Private Methods
  +    }
   
   
       /**
  @@ -448,15 +553,13 @@
        */
       private void log(String message) {
   
  -	Logger logger = null;
  -	if (context != null)
  -	    logger = context.getLogger();
  +	Logger logger = context.getLogger();
   	if (logger != null)
  -	    logger.log("ApplicationDispatcher[" + context.getPath() + "]: "
  -		       + message);
  +	    logger.log("ApplicationDispatcher[" + context.getPath() +
  +		       "]: " + message);
   	else
  -	    System.out.println("ApplicationDispatcher[" + context.getPath()
  -			       + "]: " + message);
  +	    System.out.println("ApplicationDispatcher[" +
  +			       context.getPath() + "]: " + message);
   
       }
   
  @@ -469,15 +572,13 @@
        */
       private void log(String message, Throwable throwable) {
   
  -	Logger logger = null;
  -	if (context != null)
  -	    logger = context.getLogger();
  +	Logger logger = context.getLogger();
   	if (logger != null)
  -	    logger.log("ApplicationDispatcher[" + context.getPath() + "] "
  -		       + message, throwable);
  +	    logger.log("ApplicationDispatcher[" + context.getPath() +
  +		       "] " + message, throwable);
   	else {
  -	    System.out.println("ApplicationDispatcher[" + context.getPath()
  -			       + "]: " + message);
  +	    System.out.println("ApplicationDispatcher[" +
  +			       context.getPath() + "]: " + message);
   	    throwable.printStackTrace(System.out);
   	}
   
  
  
  
  1.2       +50 -23    jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ApplicationFilterConfig.java
  
  Index: ApplicationFilterConfig.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ApplicationFilterConfig.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ApplicationFilterConfig.java	2000/08/22 00:14:02	1.1
  +++ ApplicationFilterConfig.java	2000/08/23 01:07:10	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ApplicationFilterConfig.java,v 1.1 2000/08/22 00:14:02 craigmcc Exp $
  - * $Revision: 1.1 $
  - * $Date: 2000/08/22 00:14:02 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ApplicationFilterConfig.java,v 1.2 2000/08/23 01:07:10 craigmcc Exp $
  + * $Revision: 1.2 $
  + * $Date: 2000/08/23 01:07:10 $
    *
    * ====================================================================
    *
  @@ -73,6 +73,7 @@
   import javax.servlet.FilterConfig;
   import javax.servlet.ServletContext;
   import org.apache.catalina.Context;
  +import org.apache.catalina.Wrapper;
   import org.apache.catalina.deploy.FilterDef;
   import org.apache.catalina.util.Enumerator;
   
  @@ -82,7 +83,7 @@
    * constructing stacks of filters for a particular request.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.1 $ $Date: 2000/08/22 00:14:02 $
  + * @version $Revision: 1.2 $ $Date: 2000/08/23 01:07:10 $
    */
   
   final class ApplicationFilterConfig implements FilterConfig {
  @@ -97,7 +98,7 @@
        *
        * @param filterDef Filter definition for which a FilterConfig is to be
        *  constructed
  -     * @param context The Context with which we are associated
  +     * @param wrapper The Wrapper with which we are associated
        *
        * @exception ClassCastException if the specified class does not implement
        *  the <code>javax.servlet.Filter</code> interface
  @@ -107,12 +108,12 @@
        * @exception InstantiationException if an exception occurs while
        *  instantiating the filter object
        */
  -    public ApplicationFilterConfig(FilterDef filterDef, Context context)
  +    public ApplicationFilterConfig(FilterDef filterDef, Wrapper wrapper)
   	throws ClassCastException, ClassNotFoundException,
   	       IllegalAccessException, InstantiationException {
   
   	super();
  -	setContext(context);
  +	setWrapper(wrapper);
   	setFilterDef(filterDef);
   
       }
  @@ -146,6 +147,12 @@
       private ApplicationFilterConfig nextConfig = null;
   
   
  +    /**
  +     * The Wrapper with which we are associated.
  +     */
  +    private Wrapper wrapper = null;
  +
  +
       // --------------------------------------------------- FilterConfig Methods
   
   
  @@ -239,29 +246,23 @@
       }
   
   
  -    // -------------------------------------------------------- Package Methods
  -
  -
       /**
  -     * Return the Context we are configured for.
  +     * Return a String representation of this object.
        */
  -    Context getContext() {
  +    public String toString() {
   
  -	return (this.context);
  +	StringBuffer sb = new StringBuffer("ApplicationFilterConfig[");
  +	sb.append("wrapper=");
  +	sb.append(wrapper.getName());
  +	sb.append(", filterClass=");
  +	sb.append(filterDef.getFilterClass());
  +	sb.append("]");
  +	return (sb.toString());
   
       }
   
  -
  -    /**
  -     * Set the Context we are configured for.
  -     *
  -     * @param context The new Context
  -     */
  -    void setContext(Context context) {
  -
  -	this.context = context;
   
  -    }
  +    // -------------------------------------------------------- Package Methods
   
   
       /**
  @@ -366,6 +367,32 @@
   	    this.filter = null;
   	    this.context = null;
   	}
  +
  +    }
  +
  +
  +    /**
  +     * Return the Wrapper we are configured for.
  +     */
  +    Wrapper getWrapper() {
  +
  +	return (this.wrapper);
  +
  +    }
  +
  +
  +    /**
  +     * Set the Wrapper we are configured for.
  +     *
  +     * @param wrapper The new Wrapper
  +     */
  +    void setWrapper(Wrapper wrapper) {
  +
  +	this.wrapper = wrapper;
  +	if (this.wrapper == null)
  +	    this.context = null;
  +	else
  +	    this.context = (Context) this.wrapper.getParent();
   
       }
   
  
  
  
  1.5       +8 -0      jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/LocalStrings.properties
  
  Index: LocalStrings.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/LocalStrings.properties,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- LocalStrings.properties	2000/08/22 00:14:02	1.4
  +++ LocalStrings.properties	2000/08/23 01:07:11	1.5
  @@ -1,8 +1,16 @@
   applicationContext.attributeEvent=Exception thrown by attributes event listener
   applicationContext.requestDispatcher.iae=Path {0} does not start with a "/" character
  +applicationDispatcher.allocateException=Allocate exception for servlet {0}
  +applicationDispatcher.deallocateException=Deallocate exception for servlet {0}
   applicationDispatcher.forward.ise=Cannot forward after response has been committed
   applicationDispatcher.forward.throw=Forwarded resource threw an exception
   applicationDispatcher.include.throw=Included resource threw an exception
  +applicationDispatcher.isUnavailable=Servlet {0} is currently unavailable
  +applicationDispatcher.serviceException=Servlet.service() for servlet {0} threw exception
  +applicationRequest.badParent=Cannot locate parent Request implementation
  +applicationRequest.badRequest=Request is not a javax.servlet.ServletRequestWrapper
  +applicationResponse.badParent=Cannot locate parent Response implementation
  +applicationResponse.badResponse=Response is not a javax.servlet.ServletResponseWrapper
   containerBase.addDefaultMapper=Exception configuring default mapper of class {0}
   containerBase.alreadyStarted=Container has already been started
   containerBase.notConfigured=No basic Valve has been configured
  
  
  
  1.3       +28 -28    jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/StandardWrapper.java
  
  Index: StandardWrapper.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/StandardWrapper.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- StandardWrapper.java	2000/08/22 00:14:02	1.2
  +++ StandardWrapper.java	2000/08/23 01:07:12	1.3
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/StandardWrapper.java,v 1.2 2000/08/22 00:14:02 craigmcc Exp $
  - * $Revision: 1.2 $
  - * $Date: 2000/08/22 00:14:02 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/StandardWrapper.java,v 1.3 2000/08/23 01:07:12 craigmcc Exp $
  + * $Revision: 1.3 $
  + * $Date: 2000/08/23 01:07:12 $
    *
    * ====================================================================
    *
  @@ -100,7 +100,7 @@
    * make them efficient are counter-productive.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.2 $ $Date: 2000/08/22 00:14:02 $
  + * @version $Revision: 1.3 $ $Date: 2000/08/23 01:07:12 $
    */
   
   public final class StandardWrapper
  @@ -806,6 +806,30 @@
   
   
       /**
  +     * Process an UnavailableException, marking this servlet as unavailable
  +     * for the specified amount of time.
  +     *
  +     * @param unavailable The exception that occurred, or <code>null</code>
  +     *  to mark this servlet as permanently unavailable
  +     */
  +    public void unavailable(UnavailableException unavailable) {
  +	log(sm.getString("standardWrapper.unavailable", getName()));
  +	if (unavailable == null)
  +	    setAvailable(Long.MAX_VALUE);
  +	else if (unavailable.isPermanent())
  +	    setAvailable(Long.MAX_VALUE);
  +	else {
  +	    int unavailableSeconds = unavailable.getUnavailableSeconds();
  +	    if (unavailableSeconds <= 0)
  +		unavailableSeconds = 60;	// Arbitrary default
  +	    setAvailable(System.currentTimeMillis() +
  +			 (unavailableSeconds * 1000L));
  +	}
  +
  +    }
  +
  +
  +    /**
        * Unload all initialized instances of this servlet, after calling the
        * <code>destroy()</code> method for each instance.  This can be used,
        * for example, prior to shutting down the entire servlet engine, or
  @@ -900,30 +924,6 @@
   
   
       // -------------------------------------------------------- Package Methods
  -
  -
  -    /**
  -     * Process an UnavailableException, marking this servlet as unavailable
  -     * for the specified amount of time.
  -     *
  -     * @param unavailable The exception that occurred, or <code>null</code>
  -     *  to mark this servlet as permanently unavailable
  -     */
  -    void unavailable(UnavailableException unavailable) {
  -	log(sm.getString("standardWrapper.unavailable", getName()));
  -	if (unavailable == null)
  -	    setAvailable(Long.MAX_VALUE);
  -	else if (unavailable.isPermanent())
  -	    setAvailable(Long.MAX_VALUE);
  -	else {
  -	    int unavailableSeconds = unavailable.getUnavailableSeconds();
  -	    if (unavailableSeconds <= 0)
  -		unavailableSeconds = 60;	// Arbitrary default
  -	    setAvailable(System.currentTimeMillis() +
  -			 (unavailableSeconds * 1000L));
  -	}
  -
  -    }
   
   
       // -------------------------------------------------------- Private Methods
  
  
  
  1.5       +7 -7      jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/StandardWrapperValve.java
  
  Index: StandardWrapperValve.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/StandardWrapperValve.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- StandardWrapperValve.java	2000/08/22 02:18:40	1.4
  +++ StandardWrapperValve.java	2000/08/23 01:07:12	1.5
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/StandardWrapperValve.java,v 1.4 2000/08/22 02:18:40 craigmcc Exp $
  - * $Revision: 1.4 $
  - * $Date: 2000/08/22 02:18:40 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/StandardWrapperValve.java,v 1.5 2000/08/23 01:07:12 craigmcc Exp $
  + * $Revision: 1.5 $
  + * $Date: 2000/08/23 01:07:12 $
    *
    * ====================================================================
    *
  @@ -102,7 +102,7 @@
    * <code>StandardWrapper</code> container implementation.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.4 $ $Date: 2000/08/22 02:18:40 $
  + * @version $Revision: 1.5 $ $Date: 2000/08/23 01:07:12 $
    */
   
   final class StandardWrapperValve
  @@ -361,7 +361,7 @@
   	    }
   	    if (debug >= 2)
   		log(" Adding filter '" + filterDef.getFilterName() + "'");
  -	    next = new ApplicationFilterConfig(filterDef, context);
  +	    next = new ApplicationFilterConfig(filterDef, wrapper);
   	    if (first == null)
   		first = next;
   	    if (last != null)
  @@ -382,7 +382,7 @@
   	    }
   	    if (debug >= 2)
   		log(" Adding filter '" + filterDef.getFilterName() + "'");
  -	    next = new ApplicationFilterConfig(filterDef, context);
  +	    next = new ApplicationFilterConfig(filterDef, wrapper);
   	    if (first == null)
   		first = next;
   	    if (last != null)
  @@ -400,7 +400,7 @@
   	    newDef.setFilterName("org.apache.catalina.core.ApplicationFilterWrapper");
   	    this.filterDef = newDef;
   	}
  -	next = new ApplicationFilterConfig(this.filterDef, context);
  +	next = new ApplicationFilterConfig(this.filterDef, wrapper);
   	ApplicationFilterWrapper filter =
   	    (ApplicationFilterWrapper) next.getFilter();
   	filter.setServlet(servlet);
  
  
  
  1.1                  jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ApplicationHttpRequest.java
  
  Index: ApplicationHttpRequest.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ApplicationHttpRequest.java,v 1.1 2000/08/23 01:07:11 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/08/23 01:07:11 $
   *
   * ====================================================================
   *
   * 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.catalina.core;
  
  
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.Enumeration;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletRequestWrapper;
  import org.apache.catalina.HttpRequest;
  import org.apache.catalina.util.Enumerator;
  import org.apache.catalina.util.RequestUtil;
  import org.apache.catalina.util.StringManager;
  
  
  /**
   * Wrapper around a <code>javax.servlet.http.HttpServletRequest</code>
   * that transforms an application request object (which might be the original
   * one passed to a servlet, or might be based on the 2.3
   * <code>javax.servlet.http.HttpServletRequestWrapper</code> class)
   * back into an internal <code>org.apache.catalina.HttpRequest</code>.
   * <p>
   * <strong>WARNING</strong>:  Due to Java's lack of support for multiple
   * inheritance, all of the logic in <code>ApplicationRequest</code> is
   * duplicated in <code>ApplicationHttpRequest</code>.  Make sure that you
   * keep these two classes in synchronization when making changes!
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/08/23 01:07:11 $
   */
  
  class ApplicationHttpRequest extends HttpServletRequestWrapper {
  
  
      // ----------------------------------------------------------- Constructors
  
  
      /**
       * Construct a new wrapped request around the specified servlet request.
       *
       * @param request The servlet request being wrapped
       */
      public ApplicationHttpRequest(HttpServletRequest request) {
  
  	super(request);
  	setRequest(request);
  
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The request attributes for this request.  This is initialized from the
       * wrapped request, but updates are allowed.
       */
      protected HashMap attributes = new HashMap();
  
  
      /**
       * The context path for this request.
       */
      protected String contextPath = null;
  
  
      /**
       * The request parameters for this request.  This is initialized from the
       * wrapped request, but updates are allowed.
       */
      protected Map parameters = new HashMap();
  
  
      /**
       * The parent object that is actually an internal request object.
       */
      protected HttpRequest parent = null;
  
  
      /**
       * The path information for this request.
       */
      protected String pathInfo = null;
  
  
      /**
       * The query string for this request.
       */
      protected String queryString = null;
  
  
      /**
       * The request URI for this request.
       */
      protected String requestURI = null;
  
  
      /**
       * The servlet path for this request.
       */
      protected String servletPath = null;
  
  
      /**
       * The string manager for this package.
       */
      protected static StringManager sm =
  	StringManager.getManager(Constants.Package);
  
  
      // ------------------------------------------------- ServletRequest Methods
  
  
      /**
       * Override the <code>getAttribute()</code> method of the wrapped request.
       *
       * @param name Name of the attribute to retrieve
       */
      public Object getAttribute(String name) {
  
  	synchronized (attributes) {
  	    return (attributes.get(name));
  	}
  
      }
  
  
      /**
       * Override the <code>getAttributeNames()</code> method of the wrapped
       * request.
       */
      public Enumeration getAttributeNames() {
  
  	synchronized (attributes) {
  	    return (new Enumerator(attributes.keySet()));
  	}
  
      }
  
  
      /**
       * Override the <code>removeAttribute()</code> method of the
       * wrapped request.
       *
       * @param name Name of the attribute to remove
       */
      public void removeAttribute(String name) {
  
  	synchronized (attributes) {
  	    attributes.remove(name);
  	}
  
      }
  
  
      /**
       * Override the <code>setAttribute()</code> method of the
       * wrapped request.
       *
       * @param name Name of the attribute to set
       * @param value Value of the attribute to set
       */
      public void setAttribute(String name, Object value) {
  
  	synchronized (attributes) {
  	    attributes.put(name, value);
  	}
  
      }
  
  
      // --------------------------------------------- HttpServletRequest Methods
  
  
      /**
       * Override the <code>getContextPath()</code> method of the wrapped
       * request.
       */
      public String getContextPath() {
  
  	return (this.contextPath);
  
      }
  
  
      /**
       * Override the <code>getParameter()</code> method of the wrapped request.
       *
       * @param name Name of the requested parameter
       */
      public String getParameter(String name) {
  
  	synchronized (parameters) {
  	    Object value = parameters.get(name);
  	    if (value == null)
  		return (null);
  	    else if (value instanceof String[])
  		return (((String[]) value)[0]);
  	    else if (value instanceof String)
  		return ((String) value);
  	    else
  		return (value.toString());
  	}
  
      }
  
  
      /**
       * Override the <code>getParameterMap()</code> method of the
       * wrapped request.
       */
      public Map getParameterMap() {
  
  	return (parameters);
  
      }
  
  
      /**
       * Override the <code>getParameterNames()</code> method of the
       * wrapped request.
       */
      public Enumeration getParameterNames() {
  
  	synchronized (parameters) {
  	    return (new Enumerator(parameters.keySet()));
  	}
  
      }
  
  
      /**
       * Override the <code>getParameterValues()</code> method of the
       * wrapped request.
       *
       * @param name Name of the requested parameter
       */
      public String[] getParameterValues(String name) {
  
  	synchronized (parameters) {
  	    Object value = parameters.get(name);
  	    if (value == null)
  		return ((String[]) null);
  	    else if (value instanceof String[])
  		return ((String[]) value);
  	    else if (value instanceof String) {
  		String values[] = new String[1];
  		values[0] = (String) value;
  		return (values);
  	    } else {
  		String values[] = new String[1];
  		values[0] = value.toString();
  		return (values);
  	    }
  	}
  
      }
  
  
      /**
       * Override the <code>getPathInfo()</code> method of the wrapped request.
       */
      public String getPathInfo() {
  
  	return (this.pathInfo);
  
      }
  
  
      /**
       * Override the <code>getQueryString()</code> method of the wrapped
       * request.
       */
      public String getQueryString() {
  
  	return (this.queryString);
  
      }
  
  
      /**
       * Override the <code>getRequestURI()</code> method of the wrapped
       * request.
       */
      public String getRequestURI() {
  
  	return (this.requestURI);
  
      }
  
  
      /**
       * Override the <code>getServletPath()</code> method of the wrapped
       * request.
       */
      public String getServletPath() {
  
  	return (this.servletPath);
  
      }
  
  
      // -------------------------------------------------------- Package Methods
  
  
  
      /**
       * Calculate and set the parent of the wrapped servlet request that is
       * actually an internal <code>Request</code> implementation.
       *
       * @exception IllegalArgumentException if a parent Request cannot be
       *  identified
       */
      void calculateParent() {
  
  	HttpServletRequest request = (HttpServletRequest) getRequest();
  	if (request == null) {
  	    this.parent = null;
  	    return;
  	}
  	while (request != null) {
  	    if (request instanceof HttpRequest)
  		break;
  	    if (!(request instanceof HttpServletRequestWrapper)) {
  		throw new IllegalArgumentException
  		    (sm.getString("applicationRequest.badRequest"));
  	    }
  	    request = (HttpServletRequest)
  		((HttpServletRequestWrapper) request).getRequest();
  	}
  	if (request == null) {
  	    throw new IllegalArgumentException
  		(sm.getString("applicationRequest.badParent"));
  	}
  	this.parent = (HttpRequest) request;
  
      }
  
  
      /**
       * Perform a shallow copy of the specified Map, and return the result.
       *
       * @param orig Origin Map to be copied
       */
      Map copyMap(Map orig) {
  
  	if (orig == null)
  	    return (new HashMap());
  	HashMap dest = new HashMap();
  	synchronized (orig) {
  	    Iterator keys = orig.keySet().iterator();
  	    while (keys.hasNext()) {
  		String key = (String) keys.next();
  		dest.put(key, orig.get(key));
  	    }
  	}
  	return (dest);
  
      }
  
  
      /**
       * Get the parent of the wrapped servlet request that is actually an
       * internal Request implementation.
       */
      HttpRequest getParent() {
  
  	return (this.parent);
  
      }
  
  
      /**
       * Merge the parameters from the specified query string (if any), and
       * the parameters already present on this request (if any), such that
       * the parameter values from the query string show up first if there are
       * duplicate parameter names.
       *
       * @param queryString The query string containing parameters to be merged
       */
      void mergeParameters(String queryString) {
  
  	if ((queryString == null) || (queryString.length() < 1))
  	    return;
  
  	HashMap queryParameters = new HashMap();
  	RequestUtil.parseParameters(queryParameters, queryString);
  	synchronized (parameters) {
  	    Iterator keys = parameters.keySet().iterator();
  	    while (keys.hasNext()) {
  		String key = (String) keys.next();
  		Object value = queryParameters.get(key);
  		if (value == null) {
  		    queryParameters.put(key, parameters.get(key));
  		    continue;
  		}
  		queryParameters.put
  		    (key, mergeValues(value, parameters.get(key)));
  	    }
  	    parameters = queryParameters;
  	}
  
      }
  
  
      /**
       * Set the context path for this request.
       *
       * @param contextPath The new context path
       */
      void setContextPath(String contextPath) {
  
  	this.contextPath = contextPath;
  
      }
  
  
      /**
       * Set the path information for this request.
       *
       * @param pathInfo The new path info
       */
      void setPathInfo(String pathInfo) {
  
  	this.pathInfo = pathInfo;
  
      }
  
  
      /**
       * Set the query string for this request.
       *
       * @param queryString The new query string
       */
      void setQueryString(String queryString) {
  
  	this.queryString = queryString;
  
      }
  
  
      /**
       * Set the request that we are wrapping.
       *
       * @param request The new wrapped request
       *
       * @exception IllegalArgumentException if a parent Request implementation
       *  cannot be identified
       */
      void setRequest(HttpServletRequest request) {
  
  	;	// FIXME - cannot change the private "request" variable
  	calculateParent();
  
  	// Initialize the attributes for this request
  	synchronized (attributes) {
  	    attributes.clear();
  	    Enumeration names = request.getAttributeNames();
  	    while (names.hasMoreElements()) {
  		String name = (String) names.nextElement();
  		Object value = request.getAttribute(name);
  		attributes.put(name, value);
  	    }
  	}
  
  	// Initialize the parameters for this request
  	synchronized (parameters) {
  	    parameters = copyMap(request.getParameterMap());
  	}
  
  	// Initialize the path elements for this request
  	contextPath = request.getContextPath();
  	pathInfo = request.getPathInfo();
  	queryString = request.getQueryString();
  	requestURI = request.getRequestURI();
  	servletPath = request.getServletPath();
  
      }
  
  
      /**
       * Set the request URI for this request.
       *
       * @param requestURI The new request URI
       */
      void setRequestURI(String requestURI) {
  
  	this.requestURI = requestURI;
  
      }
  
  
      /**
       * Set the servlet path for this request.
       *
       * @param servletPath The new servlet path
       */
      void setServletPath(String servletPath) {
  
  	this.servletPath = servletPath;
  
      }
  
  
      // ------------------------------------------------------ Protected Methods
  
  
      /**
       * Merge the two sets of parameter values into a single String array.
       *
       * @param values1 First set of values
       * @param values2 Second set of values
       */
      protected String[] mergeValues(Object values1, Object values2) {
  
  	ArrayList results = new ArrayList();
  
  	if (values1 == null)
  	    ;
  	else if (values1 instanceof String)
  	    results.add(values1);
  	else if (values1 instanceof String[]) {
  	    String values[] = (String[]) values1;
  	    for (int i = 0; i < values.length; i++)
  		results.add(values[i]);
  	} else
  	    results.add(values1.toString());
  
  	if (values2 == null)
  	    ;
  	else if (values2 instanceof String)
  	    results.add(values2);
  	else if (values2 instanceof String[]) {
  	    String values[] = (String[]) values2;
  	    for (int i = 0; i < values.length; i++)
  		results.add(values[i]);
  	} else
  	    results.add(values2.toString());
  
  	String values[] = new String[results.size()];
  	return ((String[]) results.toArray(values));
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ApplicationHttpResponse.java
  
  Index: ApplicationHttpResponse.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ApplicationHttpResponse.java,v 1.1 2000/08/23 01:07:11 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/08/23 01:07:11 $
   *
   * ====================================================================
   *
   * 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.catalina.core;
  
  
  import java.io.IOException;
  import javax.servlet.http.Cookie;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.http.HttpServletResponseWrapper;
  import org.apache.catalina.HttpResponse;
  import org.apache.catalina.util.StringManager;
  
  
  /**
   * Wrapper around a <code>javax.servlet.http.HttpServletResponse</code>
   * that transforms an application response object (which might be the original
   * one passed to a servlet, or might be based on the 2.3
   * <code>javax.servlet.http.HttpServletResponseWrapper</code> class)
   * back into an internal <code>org.apache.catalina.HttpResponse</code>.
   * <p>
   * <strong>WARNING</strong>:  Due to Java's lack of support for multiple
   * inheritance, all of the logic in <code>ApplicationResponse</code> is
   * duplicated in <code>ApplicationHttpResponse</code>.  Make sure that you
   * keep these two classes in synchronization when making changes!
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/08/23 01:07:11 $
   */
  
  class ApplicationHttpResponse extends HttpServletResponseWrapper {
  
  
      // ----------------------------------------------------------- Constructors
  
  
      /**
       * Construct a new wrapped response around the specified servlet response.
       *
       * @param response The servlet response being wrapped
       */
      public ApplicationHttpResponse(HttpServletResponse response) {
  
  	this(response, false);
  
      }
  
  
      /**
       * Construct a new wrapped response around the specified servlet response.
       *
       * @param response The servlet response being wrapped
       * @param included <code>true</code> if this response is being processed
       *  by a <code>RequestDispatcher.include()</code> call
       *
       * @exception IllegalArgumentException if a parent Response implementation
       *  cannot be identified
       */
      public ApplicationHttpResponse(HttpServletResponse response,
  				   boolean included) {
  
  	super(response);
  	setIncluded(included);
  	calculateParent();
  
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * Is this wrapped response the subject of an <code>include()</code>
       * call?
       */
      protected boolean included = false;
  
  
      /**
       * The parent object that is actually an internal response object.
       */
      protected HttpResponse parent = null;
  
  
      /**
       * The string manager for this package.
       */
      protected static StringManager sm =
  	StringManager.getManager(Constants.Package);
  
  
      // ------------------------------------------------ ServletResponse Methods
  
  
      /**
       * Disallow <code>reset()</code> calls on a included response.
       *
       * @exception IllegalStateException if the response has already
       *  been committed
       */
      public void reset() {
  
  	// If already committed, the wrapped response will throw ISE
  	if (!included || getResponse().isCommitted())
  	    getResponse().reset();
  
      }
  
  
      /**
       * Disallow <code>setContentLength()</code> calls on an included response.
       *
       * @param len The new content length
       */
      public void setContentLength(int len) {
  
  	if (!included)
  	    getResponse().setContentLength(len);
  
      }
  
  
      /**
       * Disallow <code>setContentType()</code> calls on an included response.
       *
       * @param type The new content type
       */
      public void setContentType(String type) {
  
  	if (!included)
  	    getResponse().setContentType(type);
  
      }
  
  
      // -------------------------------------------- HttpServletResponse Methods
  
  
      /**
       * Disallow <code>addCookie()</code> calls on an included response.
       *
       * @param cookie The new cookie
       */
      public void addCookie(Cookie cookie) {
  
  	if (!included)
  	    ((HttpServletResponse) getResponse()).addCookie(cookie);
  
      }
  
  
      /**
       * Disallow <code>addDateHeader()</code> calls on an included response.
       *
       * @param name The new header name
       * @param value The new header value
       */
      public void addDateHeader(String name, long value) {
  
  	if (!included)
  	    ((HttpServletResponse) getResponse()).addDateHeader(name, value);
  
      }
  
  
      /**
       * Disallow <code>addHeader()</code> calls on an included response.
       *
       * @param name The new header name
       * @param value The new header value
       */
      public void addHeader(String name, String value) {
  
  	if (!included)
  	    ((HttpServletResponse) getResponse()).addHeader(name, value);
  
      }
  
  
      /**
       * Disallow <code>addIntHeader()</code> calls on an included response.
       *
       * @param name The new header name
       * @param value The new header value
       */
      public void addIntHeader(String name, int value) {
  
  	if (!included)
  	    ((HttpServletResponse) getResponse()).addIntHeader(name, value);
  
      }
  
  
      /**
       * Disallow <code>sendError()</code> calls on an included response.
       *
       * @param sc The new status code
       *
       * @exception IOException if an input/output error occurs
       */
      public void sendError(int sc) throws IOException {
  
  	if (!included)
  	    ((HttpServletResponse) getResponse()).sendError(sc);
  
      }
  
  
      /**
       * Disallow <code>sendError()</code> calls on an included response.
       *
       * @param sc The new status code
       * @param msg The new message
       *
       * @exception IOException if an input/output error occurs
       */
      public void sendError(int sc, String msg) throws IOException {
  
  	if (!included)
  	    ((HttpServletResponse) getResponse()).sendError(sc, msg);
  
      }
  
  
      /**
       * Disallow <code>sendRedirect()</code> calls on an included response.
       *
       * @param location The new location
       *
       * @exception IOException if an input/output error occurs
       */
      public void sendRedirect(String location) throws IOException {
  
  	if (!included)
  	    ((HttpServletResponse) getResponse()).sendRedirect(location);
  
      }
  
  
      /**
       * Disallow <code>setDateHeader()</code> calls on an included response.
       *
       * @param name The new header name
       * @param value The new header value
       */
      public void setDateHeader(String name, long value) {
  
  	if (!included)
  	    ((HttpServletResponse) getResponse()).setDateHeader(name, value);
  
      }
  
  
      /**
       * Disallow <code>setHeader()</code> calls on an included response.
       *
       * @param name The new header name
       * @param value The new header value
       */
      public void setHeader(String name, String value) {
  
  	if (!included)
  	    ((HttpServletResponse) getResponse()).setHeader(name, value);
  
      }
  
  
      /**
       * Disallow <code>setIntHeader()</code> calls on an included response.
       *
       * @param name The new header name
       * @param value The new header value
       */
      public void setIntHeader(String name, int value) {
  
  	if (!included)
  	    ((HttpServletResponse) getResponse()).setIntHeader(name, value);
  
      }
  
  
      /**
       * Disallow <code>setStatus()</code> calls on an included response.
       *
       * @param sc The new status code
       */
      public void setStatus(int sc) {
  
  	if (!included)
  	    ((HttpServletResponse) getResponse()).setStatus(sc);
  
      }
  
  
      /**
       * Disallow <code>setStatus()</code> calls on an included response.
       *
       * @param sc The new status code
       * @param msg The new message
       */
      public void setStatus(int sc, String msg) {
  
  	if (!included)
  	    ((HttpServletResponse) getResponse()).setStatus(sc, msg);
  
      }
  
  
      // -------------------------------------------------------- Package Methods
  
  
      /**
       * Calculate and set the parent of the wrapped servlet response that is
       * actually an internal <code>Response</code> implementation.
       *
       * @exception IllegalArgumentException if a parent Response cannot be
       *  identified
       */
      void calculateParent() {
  
  	HttpServletResponse response = (HttpServletResponse) getResponse();
  	if (response == null) {
  	    this.parent = null;
  	    return;
  	}
  	while (response != null) {
  	    if (response instanceof HttpResponse)
  		break;
  	    if (!(response instanceof HttpServletResponseWrapper)) {
  		throw new IllegalArgumentException
  		    (sm.getString("applicationResponse.badResponse"));
  	    }
  	    response = (HttpServletResponse)
  		((HttpServletResponseWrapper) response).getResponse();
  	}
  	if (response == null) {
  	    throw new IllegalArgumentException
  		(sm.getString("applicationResponse.badParent"));
  	}
  	this.parent = (HttpResponse) response;
  
      }
  
  
      /**
       * Get the parent of the wrapped servlet response that is actually an
       * internal Response implementation.
       */
      HttpResponse getParent() {
  
  	return (this.parent);
  
      }
  
  
      /**
       * Return the included flag for this response.
       */
      boolean isIncluded() {
  
  	return (this.included);
  
      }
  
  
      /**
       * Set the included flag for this response.
       *
       * @param included The new included flag
       */
      void setIncluded(boolean included) {
  
  	this.included = included;
  
      }
  
  
      /**
       * Set the response that we are wrapping.
       *
       * @param response The new wrapped response
       *
       * @exception IllegalArgumentException if a parent Response implementation
       *  cannot be identified
       */
      void setResponse(HttpServletResponse response) {
  
  	;	// FIXME - cannot change the private "response" variable
  	calculateParent();
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ApplicationRequest.java
  
  Index: ApplicationRequest.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ApplicationRequest.java,v 1.1 2000/08/23 01:07:11 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/08/23 01:07:11 $
   *
   * ====================================================================
   *
   * 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.catalina.core;
  
  
  import java.io.IOException;
  import java.util.Enumeration;
  import java.util.HashMap;
  import javax.servlet.ServletRequest;
  import javax.servlet.ServletRequestWrapper;
  import org.apache.catalina.Request;
  import org.apache.catalina.util.Enumerator;
  import org.apache.catalina.util.StringManager;
  
  
  /**
   * Wrapper around a <code>javax.servlet.ServletRequest</code>
   * that transforms an application request object (which might be the original
   * one passed to a servlet, or might be based on the 2.3
   * <code>javax.servlet.ServletRequestWrapper</code> class)
   * back into an internal <code>org.apache.catalina.Request</code>.
   * <p>
   * <strong>WARNING</strong>:  Due to Java's lack of support for multiple
   * inheritance, all of the logic in <code>ApplicationRequest</code> is
   * duplicated in <code>ApplicationHttpRequest</code>.  Make sure that you
   * keep these two classes in synchronization when making changes!
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/08/23 01:07:11 $
   */
  
  class ApplicationRequest extends ServletRequestWrapper {
  
  
      // ----------------------------------------------------------- Constructors
  
  
      /**
       * Construct a new wrapped request around the specified servlet request.
       *
       * @param request The servlet request being wrapped
       */
      public ApplicationRequest(ServletRequest request) {
  
  	super(request);
  	setRequest(request);
  
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The request attributes for this request.  This is initialized from the
       * wrapped request, but updates are allowed.
       */
      protected HashMap attributes = new HashMap();
  
  
      /**
       * The parent object that is actually an internal request object.
       */
      protected Request parent = null;
  
  
      /**
       * The string manager for this package.
       */
      protected static StringManager sm =
  	StringManager.getManager(Constants.Package);
  
  
      // ------------------------------------------------- ServletRequest Methods
  
  
      /**
       * Override the <code>getAttribute()</code> method of the wrapped request.
       *
       * @param name Name of the attribute to retrieve
       */
      public Object getAttribute(String name) {
  
  	synchronized (attributes) {
  	    return (attributes.get(name));
  	}
  
      }
  
  
      /**
       * Override the <code>getAttributeNames()</code> method of the wrapped
       * request.
       */
      public Enumeration getAttributeNames() {
  
  	synchronized (attributes) {
  	    return (new Enumerator(attributes.keySet()));
  	}
  
      }
  
  
      /**
       * Override the <code>removeAttribute()</code> method of the
       * wrapped request.
       *
       * @param name Name of the attribute to remove
       */
      public void removeAttribute(String name) {
  
  	synchronized (attributes) {
  	    attributes.remove(name);
  	}
  
      }
  
  
      /**
       * Override the <code>setAttribute()</code> method of the
       * wrapped request.
       *
       * @param name Name of the attribute to set
       * @param value Value of the attribute to set
       */
      public void setAttribute(String name, Object value) {
  
  	synchronized (attributes) {
  	    attributes.put(name, value);
  	}
  
      }
  
  
      // -------------------------------------------------------- Package Methods
  
  
  
      /**
       * Calculate and set the parent of the wrapped servlet request that is
       * actually an internal <code>Request</code> implementation.
       *
       * @exception IllegalArgumentException if a parent Request cannot be
       *  identified
       */
      void calculateParent() {
  
  	ServletRequest request = getRequest();
  	if (request == null) {
  	    this.parent = null;
  	    return;
  	}
  	while (request != null) {
  	    if (request instanceof Request)
  		break;
  	    if (!(request instanceof ServletRequestWrapper)) {
  		throw new IllegalArgumentException
  		    (sm.getString("applicationRequest.badRequest"));
  	    }
  	    request = ((ServletRequestWrapper) request).getRequest();
  	}
  	if (request == null) {
  	    throw new IllegalArgumentException
  		(sm.getString("applicationRequest.badParent"));
  	}
  	this.parent = (Request) request;
  
      }
  
  
      /**
       * Get the parent of the wrapped servlet request that is actually an
       * internal Request implementation.
       */
      Request getParent() {
  
  	return (this.parent);
  
      }
  
  
      /**
       * Set the request that we are wrapping.
       *
       * @param request The new wrapped request
       *
       * @exception IllegalArgumentException if a parent Request implementation
       *  cannot be identified
       */
      void setRequest(ServletRequest request) {
  
  	;	// FIXME - cannot change the private "request" variable
  	calculateParent();
  
  	// Initialize the attributes for this request
  	synchronized (attributes) {
  	    attributes.clear();
  	    Enumeration names = request.getAttributeNames();
  	    while (names.hasMoreElements()) {
  		String name = (String) names.nextElement();
  		Object value = request.getAttribute(name);
  		attributes.put(name, value);
  	    }
  	}
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ApplicationResponse.java
  
  Index: ApplicationResponse.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ApplicationResponse.java,v 1.1 2000/08/23 01:07:11 craigmcc Exp $
   * $Revision: 1.1 $
   * $Date: 2000/08/23 01:07:11 $
   *
   * ====================================================================
   *
   * 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.catalina.core;
  
  
  import java.io.IOException;
  import java.io.PrintWriter;
  import java.util.Locale;
  import javax.servlet.ServletOutputStream;
  import javax.servlet.ServletResponse;
  import javax.servlet.ServletResponseWrapper;
  import org.apache.catalina.Response;
  import org.apache.catalina.util.StringManager;
  
  
  /**
   * Wrapper around a <code>javax.servlet.ServletResponse</code>
   * that transforms an application response object (which might be the original
   * one passed to a servlet, or might be based on the 2.3
   * <code>javax.servlet.ServletResponseWrapper</code> class)
   * back into an internal <code>org.apache.catalina.Response</code>.
   * <p>
   * <strong>WARNING</strong>:  Due to Java's lack of support for multiple
   * inheritance, all of the logic in <code>ApplicationResponse</code> is
   * duplicated in <code>ApplicationHttpResponse</code>.  Make sure that you
   * keep these two classes in synchronization when making changes!
   *
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2000/08/23 01:07:11 $
   */
  
  class ApplicationResponse extends ServletResponseWrapper {
  
  
      // ----------------------------------------------------------- Constructors
  
  
      /**
       * Construct a new wrapped response around the specified servlet response.
       *
       * @param response The servlet response being wrapped
       */
      public ApplicationResponse(ServletResponse response) {
  
  	this(response, false);
  
      }
  
  
      /**
       * Construct a new wrapped response around the specified servlet response.
       *
       * @param response The servlet response being wrapped
       * @param included <code>true</code> if this response is being processed
       *  by a <code>RequestDispatcher.include()</code> call
       *
       * @exception IllegalArgumentException if a parent Response implementation
       *  cannot be identified
       */
      public ApplicationResponse(ServletResponse response, boolean included) {
  
  	super(response);
  	setIncluded(included);
  	calculateParent();
  
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * Is this wrapped response the subject of an <code>include()</code>
       * call?
       */
      protected boolean included = false;
  
  
      /**
       * The parent object that is actually an internal response object.
       */
      protected Response parent = null;
  
  
      /**
       * The string manager for this package.
       */
      protected static StringManager sm =
  	StringManager.getManager(Constants.Package);
  
  
      // ------------------------------------------------ ServletResponse Methods
  
  
      /**
       * Disallow <code>reset()</code> calls on a included response.
       *
       * @exception IllegalStateException if the response has already
       *  been committed
       */
      public void reset() {
  
  	// If already committed, the wrapped response will throw ISE
  	if (!included || getResponse().isCommitted())
  	    getResponse().reset();
  
      }
  
  
      /**
       * Disallow <code>setContentLength()</code> calls on an included response.
       *
       * @param len The new content length
       */
      public void setContentLength(int len) {
  
  	if (!included)
  	    getResponse().setContentLength(len);
  
      }
  
  
      /**
       * Disallow <code>setContentType()</code> calls on an included response.
       *
       * @param type The new content type
       */
      public void setContentType(String type) {
  
  	if (!included)
  	    getResponse().setContentType(type);
  
      }
  
  
      // -------------------------------------------------------- Package Methods
  
  
      /**
       * Calculate and set the parent of the wrapped servlet response that is
       * actually an internal <code>Response</code> implementation.
       *
       * @exception IllegalArgumentException if a parent Response cannot be
       *  identified
       */
      void calculateParent() {
  
  	ServletResponse response = getResponse();
  	if (response == null) {
  	    this.parent = null;
  	    return;
  	}
  	while (response != null) {
  	    if (response instanceof Response)
  		break;
  	    if (!(response instanceof ServletResponseWrapper)) {
  		throw new IllegalArgumentException
  		    (sm.getString("applicationResponse.badResponse"));
  	    }
  	    response = ((ServletResponseWrapper) response).getResponse();
  	}
  	if (response == null) {
  	    throw new IllegalArgumentException
  		(sm.getString("applicationResponse.badParent"));
  	}
  	this.parent = (Response) response;
  
      }
  
  
      /**
       * Get the parent of the wrapped servlet response that is actually an
       * internal Response implementation.
       */
      Response getParent() {
  
  	return (this.parent);
  
      }
  
  
      /**
       * Return the included flag for this response.
       */
      boolean isIncluded() {
  
  	return (this.included);
  
      }
  
  
      /**
       * Set the included flag for this response.
       *
       * @param included The new included flag
       */
      void setIncluded(boolean included) {
  
  	this.included = included;
  
      }
  
  
      /**
       * Set the response that we are wrapping.
       *
       * @param response The new wrapped response
       *
       * @exception IllegalArgumentException if a parent Response implementation
       *  cannot be identified
       */
      void setResponse(ServletResponse response) {
  
  	;	// FIXME - cannot change the private "response" variable
  	calculateParent();
  
      }
  
  
  }
  
  
  
  1.2       +67 -4     jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/util/RequestUtil.java
  
  Index: RequestUtil.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/util/RequestUtil.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- RequestUtil.java	2000/08/11 17:01:50	1.1
  +++ RequestUtil.java	2000/08/23 01:07:15	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/util/RequestUtil.java,v 1.1 2000/08/11 17:01:50 craigmcc Exp $
  - * $Revision: 1.1 $
  - * $Date: 2000/08/11 17:01:50 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/util/RequestUtil.java,v 1.2 2000/08/23 01:07:15 craigmcc Exp $
  + * $Revision: 1.2 $
  + * $Date: 2000/08/23 01:07:15 $
    *
    * ====================================================================
    *
  @@ -67,6 +67,7 @@
   
   import java.text.SimpleDateFormat;
   import java.util.Date;
  +import java.util.Map;
   import java.util.StringTokenizer;
   import java.util.TimeZone;
   import java.util.Vector;
  @@ -77,7 +78,7 @@
    * General purpose request parsing and encoding utility methods.
    *
    * @author Craig R. McClanahan
  - * @version $Revision: 1.1 $ $Date: 2000/08/11 17:01:50 $
  + * @version $Revision: 1.2 $ $Date: 2000/08/23 01:07:15 $
    */
   
   public final class RequestUtil {
  @@ -198,6 +199,68 @@
   	Cookie[] cookies = new Cookie[cookieJar.size()];
   	cookieJar.copyInto(cookies);
   	return (cookies);
  +
  +    }
  +
  +
  +    /**
  +     * Append request parameters from the specified String to the specified
  +     * Map.  It is presumed that the specified Map is not accessed from any
  +     * other thread, so no synchronization is performed.
  +     *
  +     * @param map Map that accumulates the resulting parameters
  +     * @param data Input string containing request parameters
  +     *
  +     * @exception IllegalArgumentException if the data is malformed
  +     */
  +    public static void parseParameters(Map map, String data) {
  +
  +        if ((data == null) || (data.length() < 1))
  +	    return;
  +
  +	// Initialize the variables we will require
  +	StringParser parser = new StringParser(data);
  +	boolean first = true;
  +	int nameStart = 0;
  +	int nameEnd = 0;
  +	int valueStart = 0;
  +	int valueEnd = 0;
  +	String name = null;
  +	String value = null;
  +	String oldValues[] = null;
  +	String newValues[] = null;
  +
  +	// Loop through the "name=value" entries in the input data
  +	while (true) {
  +
  +	    // Extract the name and value components
  +	    if (first)
  +	        first = false;
  +	    else
  +	        parser.advance();
  +	    nameStart = parser.getIndex();
  +	    nameEnd = parser.findChar('=');
  +	    parser.advance();
  +	    valueStart = parser.getIndex();
  +	    valueEnd = parser.findChar('&');
  +	    name = parser.extract(nameStart, nameEnd);
  +	    value = parser.extract(valueStart, valueEnd);
  +
  +	    // A zero-length name or value means we are done
  +	    if ((name.length() < 1) || (value.length() < 1))
  +	        break;
  +
  +	    // Create or update the array of values for this name
  +	    oldValues = (String[]) map.get(name);
  +	    if (oldValues == null)
  +	        oldValues = new String[0];
  +	    newValues = new String[oldValues.length + 1];
  +	    System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
  +	    newValues[oldValues.length] = value;
  +	    map.put(name, newValues);
  +
  +	}
  +
   
       }