You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by pa...@apache.org on 2002/08/04 21:39:50 UTC

cvs commit: jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5 Constants.java CoyoteAdapter.java CoyoteConnector.java CoyoteInputStream.java CoyoteOutputStream.java CoyoteRequest.java CoyoteRequestFacade.java CoyoteResponse.java CoyoteResponseFacade.java CoyoteServerSocketFactory.java CoyoteWriter.java LocalStrings.properties OutputBuffer.java

patrickl    2002/08/04 12:39:50

  Modified:    coyote   build.xml
               coyote/src/java/org/apache/coyote/tomcat4
                        CoyoteResponse.java
  Added:       coyote/src/java/org/apache/coyote/tomcat5 Constants.java
                        CoyoteAdapter.java CoyoteConnector.java
                        CoyoteInputStream.java CoyoteOutputStream.java
                        CoyoteRequest.java CoyoteRequestFacade.java
                        CoyoteResponse.java CoyoteResponseFacade.java
                        CoyoteServerSocketFactory.java CoyoteWriter.java
                        LocalStrings.properties OutputBuffer.java
  Log:
  Create separate Tomcat 5 Coyote adapter and back out recent commits to Tomcat 4 Coyote adapter
  
  Revision  Changes    Path
  1.11      +41 -4     jakarta-tomcat-connectors/coyote/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-connectors/coyote/build.xml,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- build.xml	24 Jun 2002 19:32:39 -0000	1.10
  +++ build.xml	4 Aug 2002 19:39:49 -0000	1.11
  @@ -111,6 +111,9 @@
   <!-- ========== Detection and Reports ===================================== -->
   
   
  +    <target name="report-tc5" if="tomcat5.detect" >
  +	<echo message="Tomcat5 detected "  />
  +    </target>
       <target name="report-tc4" if="tomcat4.detect" >
   	<echo message="Tomcat4 detected "  />
       </target>
  @@ -118,7 +121,7 @@
   	<echo message="Tomcat3.3 detected "  />
       </target>
   
  -    <target name="report" depends="report-tc4, report-tc33" />
  +    <target name="report" depends="report-tc5, report-tc4, report-tc33" />
   
   
   <!-- ========== Executable Targets ======================================== -->
  @@ -141,7 +144,26 @@
       <mkdir dir="${build.home}/docs/api"/>
       <mkdir dir="${build.home}/lib"/>
       <mkdir dir="${build.home}/tests"/>
  -    <available property="tomcat4.detect" file="${catalina.home}/server/lib/catalina.jar" />
  +    <condition property="tomcat5.detect">
  +      <and>
  +        <available file="${catalina.home}/server/lib/catalina.jar" />
  +        <available
  +          classname="javax.servlet.ServletRequestEvent"
  +          classpath="${catalina.home}/common/lib/servlet.jar"
  +        />
  +      </and>
  +    </condition>
  +    <condition property="tomcat4.detect">
  +      <and>
  +        <available file="${catalina.home}/server/lib/catalina.jar" />
  +        <not>
  +          <available
  +            classname="javax.servlet.ServletRequestEvent"
  +            classpath="${catalina.home}/common/lib/servlet.jar"
  +          />
  +        </not>
  +      </and>
  +    </condition>
       <available property="tomcat33.detect" file="${tomcat33.home}/lib/common/tomcat_core.jar" />
     </target>
   
  @@ -172,6 +194,21 @@
     </target>
   
   
  +  <target name="compile.tomcat5" if="tomcat5.detect"
  +   description="Compile Tomcat 5.x Adapter">
  +    <javac  srcdir="${source.home}"
  +           destdir="${build.home}/classes"
  +             debug="${compile.debug}"
  +       deprecation="${compile.deprecation}"
  +          optimize="${compile.optimize}">
  +      <classpath refid="compile.classpath"/>
  +      <include name="org/apache/coyote/tomcat5/**" />
  +    </javac>
  +    <copy    todir="${build.home}/classes" filtering="on">
  +      <fileset dir="${source.home}" excludes="**/*.java"/>
  +    </copy>
  +  </target>
  +
     <target name="compile.tomcat4" if="tomcat4.detect"
      description="Compile Tomcat 4.x Adapter">
       <javac  srcdir="${source.home}"
  @@ -280,4 +317,4 @@
     </target>
   
   
  -</project>
  \ No newline at end of file
  +</project>
  
  
  
  1.20      +0 -18     jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteResponse.java
  
  Index: CoyoteResponse.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteResponse.java,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- CoyoteResponse.java	1 Aug 2002 17:20:36 -0000	1.19
  +++ CoyoteResponse.java	4 Aug 2002 19:39:49 -0000	1.20
  @@ -717,24 +717,6 @@
       }
   
   
  -    /*
  -     * Overrides the name of the character encoding used in the body
  -     * of the request. This method must be called prior to reading
  -     * request parameters or reading input using getReader().
  -     *
  -     * @param charset String containing the name of the chararacter encoding.
  -     */
  -    public void setCharacterEncoding(String charset) {
  -
  -        if (isCommitted())
  -            return;
  -
  -        if (included)
  -            return;     // Ignore any call from an included servlet
  -
  -	coyoteResponse.setCharacterEncoding(charset);
  -    }
  -
       /**
        * Set the Locale that is appropriate for this response, including
        * setting the appropriate character encoding.
  
  
  
  1.1                  jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/Constants.java
  
  Index: Constants.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.coyote.tomcat5;
  
  import java.util.Locale;
  
  /**
   * Constants.
   *
   * @author Remy Maucherat
   */
  public final class Constants {
  
  
      // -------------------------------------------------------------- Constants
  
  
      public static final String Package = "org.apache.coyote.tomcat5";
      public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
  
      public static final int PROCESSOR_IDLE = 0;
      public static final int PROCESSOR_ACTIVE = 1;
  
      /**
       * Default header names.
       */
      public static final String AUTHORIZATION_HEADER = "authorization";
  
  }
  
  
  
  1.1                  jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteAdapter.java
  
  Index: CoyoteAdapter.java
  ===================================================================
  /* * $Header: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteAdapter.java,v 1.1 2002/08/04 19:39:49 patrickl Exp $
   * $Revision: 1.1 $
   * $Date: 2002/08/04 19:39:49 $
   *
   * ====================================================================
   *
   * 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.coyote.tomcat5;
  
  
  import java.io.BufferedInputStream;
  import java.io.EOFException;
  import java.io.InterruptedIOException;
  import java.io.InputStream;
  import java.io.IOException;
  import java.io.OutputStream;
  import java.net.InetAddress;
  import java.net.Socket;
  import java.util.ArrayList;
  import java.util.Enumeration;
  import java.util.Iterator;
  import java.util.Locale;
  import java.util.StringTokenizer;
  import java.util.TreeMap;
  import javax.servlet.ServletException;
  import javax.servlet.http.Cookie;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  
  import org.apache.tomcat.util.buf.ByteChunk;
  import org.apache.tomcat.util.buf.HexUtils;
  import org.apache.tomcat.util.buf.MessageBytes;
  import org.apache.tomcat.util.http.Cookies;
  import org.apache.tomcat.util.http.ServerCookie;
  
  import org.apache.coyote.ActionCode;
  import org.apache.coyote.ActionHook;
  import org.apache.coyote.Adapter;
  import org.apache.coyote.InputBuffer;
  import org.apache.coyote.OutputBuffer;
  import org.apache.coyote.Request;
  import org.apache.coyote.Response;
  
  import org.apache.catalina.Connector;
  import org.apache.catalina.Container;
  import org.apache.catalina.Globals;
  import org.apache.catalina.HttpRequest;
  import org.apache.catalina.HttpResponse;
  import org.apache.catalina.Lifecycle;
  import org.apache.catalina.LifecycleEvent;
  import org.apache.catalina.LifecycleException;
  import org.apache.catalina.LifecycleListener;
  import org.apache.catalina.Logger;
  import org.apache.catalina.util.LifecycleSupport;
  import org.apache.catalina.util.RequestUtil;
  import org.apache.catalina.util.StringManager;
  import org.apache.catalina.util.StringParser;
  
  
  /**
   * Implementation of a request processor which delegates the processing to a
   * Coyote processor.
   *
   * @author Craig R. McClanahan
   * @author Remy Maucherat
   * @version $Revision: 1.1 $ $Date: 2002/08/04 19:39:49 $
   */
  
  final class CoyoteAdapter
      implements Adapter {
  
  
      // -------------------------------------------------------------- Constants
  
  
      public static final int ADAPTER_NOTES = 1;
  
  
      // ----------------------------------------------------------- Constructors
  
  
      /**
       * Construct a new CoyoteProcessor associated with the specified connector.
       *
       * @param connector CoyoteConnector that owns this processor
       * @param id Identifier of this CoyoteProcessor (unique per connector)
       */
      public CoyoteAdapter(CoyoteConnector connector) {
  
          super();
          this.connector = connector;
          this.debug = connector.getDebug();
  
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The CoyoteConnector with which this processor is associated.
       */
      private CoyoteConnector connector = null;
  
  
      /**
       * The debugging detail level for this component.
       */
      private int debug = 0;
  
  
      /**
       * The match string for identifying a session ID parameter.
       */
      private static final String match =
          ";" + Globals.SESSION_PARAMETER_NAME + "=";
  
  
      /**
       * The match string for identifying a session ID parameter.
       */
      private static final char[] SESSION_ID = match.toCharArray();
  
  
      /**
       * The string manager for this package.
       */
      protected StringManager sm =
          StringManager.getManager(Constants.Package);
  
  
      // -------------------------------------------------------- Adapter Methods
  
  
      /**
       * Service method.
       */
      public void service(Request req, Response res)
          throws Exception {
  
          CoyoteRequest request = (CoyoteRequest) req.getNote(ADAPTER_NOTES);
          CoyoteResponse response = (CoyoteResponse) res.getNote(ADAPTER_NOTES);
  
          if (request == null) {
  
              // Create objects
              request = (CoyoteRequest) connector.createRequest();
              request.setCoyoteRequest(req);
              response = (CoyoteResponse) connector.createResponse();
              response.setCoyoteResponse(res);
  
              // Link objects
              request.setResponse(response);
              response.setRequest(request);
  
              // Set as notes
              req.setNote(ADAPTER_NOTES, request);
              res.setNote(ADAPTER_NOTES, response);
  
          }
  
          try {
              // Parse and set Catalina and configuration specific 
              // request parameters
              postParseRequest(req, request, res, response);
              // Calling the container
              connector.getContainer().invoke(request, response);
              response.finishResponse();
  
              req.action( ActionCode.ACTION_POST_REQUEST , null);
          } catch (IOException e) {
              ;
          } catch (Throwable t) {
              log(sm.getString("coyoteAdapter.service"), t);
          } finally {
              // Recycle the wrapper request and response
              request.recycle();
              response.recycle();
          }
  
      }
  
  
      // ------------------------------------------------------ Protected Methods
  
  
      /**
       * Parse additional request parameters.
       */
      protected void postParseRequest(Request req, CoyoteRequest request,
                                      Response res, CoyoteResponse response)
          throws IOException {
  
          request.setSecure(connector.getSecure());
          req.scheme().setString(connector.getScheme());
  
          request.setAuthorization
              (req.getHeader(Constants.AUTHORIZATION_HEADER));
  
          // Replace the default port if we are in secure mode
          if (req.getServerPort() == 80 
              && connector.getScheme().equals("https")) {
              req.setServerPort(443);
          }
  
          // At this point the Host header has been processed.
          // Override if the proxyPort/proxyHost are set 
          String proxyName = connector.getProxyName();
          int proxyPort = connector.getProxyPort();
          if (proxyPort != 0) {
              request.setServerPort(proxyPort);
              req.setServerPort(proxyPort);
          } else {
              request.setServerPort(req.getServerPort());
          }
          if (proxyName != null) {
              request.setServerName(proxyName);
              req.serverName().setString(proxyName);
          } else {
              request.setServerName(req.serverName().toString());
          }
  
          // URI decoding
          req.decodedURI().duplicate(req.requestURI());
          req.getURLDecoder().convert(req.decodedURI(), true);
          req.decodedURI().setEncoding("UTF-8");
  
          // Normalize decoded URI
          if (!normalize(req.decodedURI())) {
              res.setStatus(400);
              res.setMessage("Invalid URI");
              throw new IOException("Invalid URI");
          }
  
          // Parse session Id
          parseSessionId(req, request);
  
          // Additional URI normalization and validation is needed for security 
          // reasons on Tomcat 4.0.x
          if (connector.getUseURIValidationHack()) {
              String uri = validate(request.getRequestURI());
              if (uri == null) {
                  res.setStatus(400);
                  res.setMessage("Invalid URI");
                  throw new IOException("Invalid URI");
              } else {
                  req.requestURI().setString(uri);
                  // Redoing the URI decoding
                  req.decodedURI().duplicate(req.requestURI());
                  req.getURLDecoder().convert(req.decodedURI(), true);
              }
          }
  
          // Parse cookies
          parseCookies(req, request);
  	
  	// Set the SSL properties
  	res.action(ActionCode.ACTION_REQ_SSL_ATTRIBUTE,request.getRequest());
      }
  
      /**
       * Parse session id in URL.
       * FIXME: Optimize this.
       */
      protected void parseSessionId(Request req, CoyoteRequest request) {
  
          ByteChunk uriBC = req.decodedURI().getByteChunk();
          int semicolon = uriBC.indexOf(match, 0, match.length(), 0);
  
          if (semicolon > 0) {
  
              // Parse session ID, and extract it from the decoded request URI
              String uri = uriBC.toString();
              String rest = uri.substring(semicolon + match.length());
              int semicolon2 = rest.indexOf(';');
              if (semicolon2 >= 0) {
                  request.setRequestedSessionId(rest.substring(0, semicolon2));
                  rest = rest.substring(semicolon2);
              } else {
                  request.setRequestedSessionId(rest);
                  rest = "";
              }
              request.setRequestedSessionURL(true);
              req.decodedURI().setString(uri.substring(0, semicolon) + rest);
  
              // Extract session ID from request URI
              uri = req.requestURI().toString();
              semicolon = uri.indexOf(match);
  
              if (semicolon > 0) {
                  rest = uri.substring(semicolon + match.length());
                  semicolon2 = rest.indexOf(';');
                  if (semicolon2 >= 0) {
                      rest = rest.substring(semicolon2);
                  } else {
                      rest = "";
                  }
                  req.requestURI().setString(uri.substring(0, semicolon) + rest);
              }
  
          } else {
              request.setRequestedSessionId(null);
              request.setRequestedSessionURL(false);
          }
  
      }
  
  
      /**
       * Parse cookies.
       */
      protected void parseCookies(Request req, CoyoteRequest request) {
  
          Cookies serverCookies = req.getCookies();
          int count = serverCookies.getCookieCount();
          if (count <= 0)
              return;
  
          Cookie[] cookies = new Cookie[count];
  
          for (int i = 0; i < count; i++) {
              ServerCookie scookie = serverCookies.getCookie(i);
              if (scookie.getName().equals(Globals.SESSION_COOKIE_NAME)) {
                  // Override anything requested in the URL
                  if (!request.isRequestedSessionIdFromCookie()) {
                      // Accept only the first session id cookie
                      request.setRequestedSessionId
                          (scookie.getValue().toString());
                      request.setRequestedSessionCookie(true);
                      request.setRequestedSessionURL(false);
                      if (debug >= 1)
                          log(" Requested cookie session id is " +
                              ((HttpServletRequest) request.getRequest())
                              .getRequestedSessionId());
                  }
              }
              Cookie cookie = new Cookie(scookie.getName().toString(),
                                         scookie.getValue().toString());
              cookies[i] = cookie;
          }
  
          request.setCookies(cookies);
  
      }
  
  
      /**
       * Return a context-relative path, beginning with a "/", that represents
       * the canonical version of the specified path after ".." and "." elements
       * are resolved out.  If the specified path attempts to go outside the
       * boundaries of the current context (i.e. too many ".." path elements
       * are present), return <code>null</code> instead.
       * This code is not optimized, and is only needed for Tomcat 4.0.x.
       *
       * @param path Path to be validated
       */
      protected static String validate(String path) {
  
          if (path == null)
              return null;
  
          // Create a place for the normalized path
          String normalized = path;
  
          // Normalize "/%7E" and "/%7e" at the beginning to "/~"
          if (normalized.startsWith("/%7E") ||
              normalized.startsWith("/%7e"))
              normalized = "/~" + normalized.substring(4);
  
          // Prevent encoding '%', '/', '.' and '\', which are special reserved
          // characters
          if ((normalized.indexOf("%25") >= 0)
              || (normalized.indexOf("%2F") >= 0)
              || (normalized.indexOf("%2E") >= 0)
              || (normalized.indexOf("%5C") >= 0)
              || (normalized.indexOf("%2f") >= 0)
              || (normalized.indexOf("%2e") >= 0)
              || (normalized.indexOf("%5c") >= 0)) {
              return null;
          }
  
          if (normalized.equals("/."))
              return "/";
  
          // Normalize the slashes and add leading slash if necessary
          if (normalized.indexOf('\\') >= 0)
              normalized = normalized.replace('\\', '/');
          if (!normalized.startsWith("/"))
              normalized = "/" + normalized;
  
          // Resolve occurrences of "//" in the normalized path
          while (true) {
              int index = normalized.indexOf("//");
              if (index < 0)
                  break;
              normalized = normalized.substring(0, index) +
                  normalized.substring(index + 1);
          }
  
          // Resolve occurrences of "/./" in the normalized path
          while (true) {
              int index = normalized.indexOf("/./");
              if (index < 0)
                  break;
              normalized = normalized.substring(0, index) +
                  normalized.substring(index + 2);
          }
  
          // Resolve occurrences of "/../" in the normalized path
          while (true) {
              int index = normalized.indexOf("/../");
              if (index < 0)
                  break;
              if (index == 0)
                  return (null);  // Trying to go outside our context
              int index2 = normalized.lastIndexOf('/', index - 1);
              normalized = normalized.substring(0, index2) +
                  normalized.substring(index + 3);
          }
  
          // Declare occurrences of "/..." (three or more dots) to be invalid
          // (on some Windows platforms this walks the directory tree!!!)
          if (normalized.indexOf("/...") >= 0)
              return (null);
  
          // Return the normalized path that we have completed
          return (normalized);
  
      }
  
  
      /**
       * Normalize URI.
       * <p>
       * This method normalizes "\", "//", "/./" and "/../". This method will
       * return false when trying to go above the root, or if the URI contains
       * a null byte.
       * 
       * @param uriMB URI to be normalized
       */
      public static boolean normalize(MessageBytes uriMB) {
  
          ByteChunk uriBC = uriMB.getByteChunk();
          byte[] b = uriBC.getBytes();
          int start = uriBC.getStart();
          int end = uriBC.getEnd();
  
          int pos = 0;
          int index = 0;
  
          // Replace '\' with '/'
          // Check for null byte
          for (pos = start; pos < end; pos++) {
              if (b[pos] == (byte) '\\')
                  b[pos] = (byte) '/';
              if (b[pos] == (byte) 0)
                  return false;
          }
  
          // Replace "//" with "/"
          for (pos = start; pos < (end - 1); pos++) {
              if ((b[pos] == (byte) '/') && (b[pos + 1] == (byte) '/')) {
                  copyBytes(b, pos, pos + 1, end - pos - 1);
                  end--;
              }
          }
  
          // If the URI ends with "/." or "/..", then we append an extra "/"
          // Note: It is possible to extend the URI by 1 without any side effect
          // as the next character is a non-significant WS.
          if (((end - start) > 2) && (b[end - 1] == (byte) '.')) {
              if ((b[end - 2] == (byte) '/') 
                  || ((b[end - 2] == (byte) '.') 
                      && (b[end - 3] == (byte) '/'))) {
                  b[end] = (byte) '/';
                  end++;
              }
          }
  
          uriBC.setEnd(end);
  
          index = 0;
  
          // Resolve occurrences of "/./" in the normalized path
          while (true) {
              index = uriBC.indexOf("/./", 0, 3, index);
              if (index < 0)
                  break;
              copyBytes(b, start + index, start + index + 2, 
                        end - start - index - 2);
              end = end - 2;
              uriBC.setEnd(end);
          }
  
          index = 0;
  
          // Resolve occurrences of "/../" in the normalized path
          while (true) {
              index = uriBC.indexOf("/../", 0, 4, index);
              if (index < 0)
                  break;
              // Prevent from going outside our context
              if (index == 0)
                  return false;
              int index2 = -1;
              for (pos = start + index - 1; (pos >= 0) && (index2 < 0); pos --) {
                  if (b[pos] == (byte) '/') {
                      index2 = pos;
                  }
              }
              copyBytes(b, start + index2, start + index + 3,
                        end - start - index - 3);
              end = end + index2 - index - 3;
              uriBC.setEnd(end);
              index = index2;
          }
  
          uriBC.setBytes(b, start, end);
  
          return true;
  
      }
  
  
      // ------------------------------------------------------ Protected Methods
  
  
      /**
       * Copy an array of bytes to a different position. Used during 
       * normalization.
       */
      protected static void copyBytes(byte[] b, int dest, int src, int len) {
          for (int pos = 0; pos < len; pos++) {
              b[pos + dest] = b[pos + src];
          }
      }
  
  
      /**
       * Log a message on the Logger associated with our Container (if any)
       *
       * @param message Message to be logged
       */
      protected void log(String message) {
  
          Logger logger = connector.getContainer().getLogger();
          if (logger != null)
              logger.log("CoyoteAdapter " + message);
  
      }
  
  
      /**
       * Log a message on the Logger associated with our Container (if any)
       *
       * @param message Message to be logged
       * @param throwable Associated exception
       */
      protected void log(String message, Throwable throwable) {
  
          Logger logger = connector.getContainer().getLogger();
          if (logger != null)
              logger.log("CoyoteAdapter " + message, throwable);
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteConnector.java
  
  Index: CoyoteConnector.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteConnector.java,v 1.1 2002/08/04 19:39:49 patrickl Exp $
   * $Revision: 1.1 $
   * $Date: 2002/08/04 19:39:49 $
   *
   * ====================================================================
   *
   * 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.coyote.tomcat5;
  
  
  import java.io.IOException;
  import java.net.InetAddress;
  import java.net.ServerSocket;
  import java.net.Socket;
  import java.net.UnknownHostException;
  import java.security.AccessControlException;
  import java.util.Stack;
  import java.util.Vector;
  import java.util.Enumeration;
  import java.security.KeyStoreException;
  import java.security.NoSuchAlgorithmException;
  import java.security.cert.CertificateException;
  import java.security.UnrecoverableKeyException;
  import java.security.KeyManagementException;
  
  import org.apache.tomcat.util.IntrospectionUtils;
  
  import org.apache.coyote.ActionCode;
  import org.apache.coyote.ActionHook;
  import org.apache.coyote.Adapter;
  import org.apache.coyote.InputBuffer;
  import org.apache.coyote.OutputBuffer;
  import org.apache.coyote.ProtocolHandler;
  
  import org.apache.catalina.Connector;
  import org.apache.catalina.Container;
  import org.apache.catalina.HttpRequest;
  import org.apache.catalina.HttpResponse;
  import org.apache.catalina.Lifecycle;
  import org.apache.catalina.LifecycleEvent;
  import org.apache.catalina.LifecycleException;
  import org.apache.catalina.LifecycleListener;
  import org.apache.catalina.Logger;
  import org.apache.catalina.Request;
  import org.apache.catalina.Response;
  import org.apache.catalina.Service;
  import org.apache.catalina.net.DefaultServerSocketFactory;
  import org.apache.catalina.net.ServerSocketFactory;
  import org.apache.catalina.util.LifecycleSupport;
  import org.apache.catalina.util.StringManager;
  
  
  /**
   * Implementation of a Coyote connector for Tomcat 5.x.
   *
   * @author Craig R. McClanahan
   * @author Remy Maucherat
   * @version $Revision: 1.1 $ $Date: 2002/08/04 19:39:49 $
   */
  
  
  public final class CoyoteConnector
      implements Connector, Lifecycle {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The <code>Service</code> we are associated with (if any).
       */
      private Service service = null;
  
  
      /**
       * The accept count for this Connector.
       */
      private int acceptCount = 10;
  
  
      /**
       * The IP address on which to bind, if any.  If <code>null</code>, all
       * addresses on the server will be bound.
       */
      private String address = null;
  
  
      /**
       * The input buffer size we should create on input streams.
       */
      private int bufferSize = 2048;
  
  
      /**
       * The Container used for processing requests received by this Connector.
       */
      protected Container container = null;
  
  
      /**
       * The set of processors that have ever been created.
       */
      private Vector created = new Vector();
  
  
      /**
       * The current number of processors that have been created.
       */
      private int curProcessors = 0;
  
  
      /**
       * The debugging detail level for this component.
       */
      private int debug = 0;
  
  
      /**
       * The "enable DNS lookups" flag for this Connector.
       */
      private boolean enableLookups = false;
  
  
      /**
       * The server socket factory for this component.
       */
      private ServerSocketFactory factory = null;
  
  
      /**
       * Descriptive information about this Connector implementation.
       */
      private static final String info =
          "org.apache.coyote.tomcat5.CoyoteConnector2/1.0";
  
  
      /**
       * The lifecycle event support for this component.
       */
      protected LifecycleSupport lifecycle = new LifecycleSupport(this);
  
  
      /**
       * The minimum number of processors to start at initialization time.
       */
      protected int minProcessors = 5;
  
  
      /**
       * The maximum number of processors allowed, or <0 for unlimited.
       */
      private int maxProcessors = 20;
  
  
      /**
       * Timeout value on the incoming connection.
       * Note : a value of 0 means no timeout.
       */
      private int connectionTimeout = Constants.DEFAULT_CONNECTION_TIMEOUT;
  
  
      /**
       * The port number on which we listen for requests.
       */
      private int port = 8080;
  
  
      /**
       * The server name to which we should pretend requests to this Connector
       * were directed.  This is useful when operating Tomcat behind a proxy
       * server, so that redirects get constructed accurately.  If not specified,
       * the server name included in the <code>Host</code> header is used.
       */
      private String proxyName = null;
  
  
      /**
       * The server port to which we should pretent requests to this Connector
       * were directed.  This is useful when operating Tomcat behind a proxy
       * server, so that redirects get constructed accurately.  If not specified,
       * the port number specified by the <code>port</code> property is used.
       */
      private int proxyPort = 0;
  
  
      /**
       * The redirect port for non-SSL to SSL redirects.
       */
      private int redirectPort = 443;
  
  
      /**
       * The request scheme that will be set on all requests received
       * through this connector.
       */
      private String scheme = "http";
  
  
      /**
       * The secure connection flag that will be set on all requests received
       * through this connector.
       */
      private boolean secure = false;
  
  
      /**
       * The string manager for this package.
       */
      private StringManager sm =
          StringManager.getManager(Constants.Package);
  
  
      /**
       * Has this component been initialized yet?
       */
      private boolean initialized = false;
  
  
      /**
       * Has this component been started yet?
       */
      private boolean started = false;
  
  
      /**
       * The shutdown signal to our background thread
       */
      private boolean stopped = false;
  
  
      /**
       * The background thread.
       */
      private Thread thread = null;
  
  
      /**
       * Use TCP no delay ?
       */
      private boolean tcpNoDelay = true;
  
  
      /**
       * Coyote Protocol handler class name.
       * Defaults to the Coyote HTTP/1.1 protocolHandler.
       */
      private String protocolHandlerClassName = 
          "org.apache.coyote.http11.Http11Protocol";
  
  
      /**
       * Use URI validation for Tomcat 5.0.x.
       */
      private boolean useURIValidationHack = true;
  
  
      /**
       * Coyote protocol handler.
       */
      private ProtocolHandler protocolHandler = null;
  
  
      /**
       * Coyote adapter.
       */
      private Adapter adapter = null;
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Return the <code>Service</code> with which we are associated (if any).
       */
      public Service getService() {
  
          return (this.service);
  
      }
  
  
      /**
       * Set the <code>Service</code> with which we are associated (if any).
       *
       * @param service The service that owns this Engine
       */
      public void setService(Service service) {
  
          this.service = service;
  
      }
  
  
      /**
       * Return the connection timeout for this Connector.
       */
      public int getConnectionTimeout() {
  
          return (connectionTimeout);
  
      }
  
  
      /**
       * Set the connection timeout for this Connector.
       *
       * @param count The new connection timeout
       */
      public void setConnectionTimeout(int connectionTimeout) {
  
          this.connectionTimeout = connectionTimeout;
  
      }
  
  
      /**
       * Return the accept count for this Connector.
       */
      public int getAcceptCount() {
  
          return (acceptCount);
  
      }
  
  
      /**
       * Set the accept count for this Connector.
       *
       * @param count The new accept count
       */
      public void setAcceptCount(int count) {
  
          this.acceptCount = count;
  
      }
  
  
      /**
       * Return the bind IP address for this Connector.
       */
      public String getAddress() {
  
          return (this.address);
  
      }
  
  
      /**
       * Set the bind IP address for this Connector.
       *
       * @param address The bind IP address
       */
      public void setAddress(String address) {
  
          this.address = address;
  
      }
  
  
      /**
       * Is this connector available for processing requests?
       */
      public boolean isAvailable() {
  
          return (started);
  
      }
  
  
      /**
       * Return the input buffer size for this Connector.
       */
      public int getBufferSize() {
  
          return (this.bufferSize);
  
      }
  
  
      /**
       * Set the input buffer size for this Connector.
       *
       * @param bufferSize The new input buffer size.
       */
      public void setBufferSize(int bufferSize) {
  
          this.bufferSize = bufferSize;
  
      }
  
  
      /**
       * Return the Container used for processing requests received by this
       * Connector.
       */
      public Container getContainer() {
  
          return (container);
  
      }
  
  
      /**
       * Set the Container used for processing requests received by this
       * Connector.
       *
       * @param container The new Container to use
       */
      public void setContainer(Container container) {
  
          this.container = container;
  
      }
  
  
      /**
       * Return the current number of processors that have been created.
       */
      public int getCurProcessors() {
  
          return (curProcessors);
  
      }
  
  
      /**
       * Return the debugging detail level for this component.
       */
      public int getDebug() {
  
          return (debug);
  
      }
  
  
      /**
       * Set the debugging detail level for this component.
       *
       * @param debug The new debugging detail level
       */
      public void setDebug(int debug) {
  
          this.debug = debug;
  
      }
  
  
      /**
       * Return the "enable DNS lookups" flag.
       */
      public boolean getEnableLookups() {
  
          return (this.enableLookups);
  
      }
  
  
      /**
       * Set the "enable DNS lookups" flag.
       *
       * @param enableLookups The new "enable DNS lookups" flag value
       */
      public void setEnableLookups(boolean enableLookups) {
  
          this.enableLookups = enableLookups;
  
      }
  
  
      /**
       * Return the server socket factory used by this Container.
       */
      public ServerSocketFactory getFactory() {
  
          if (this.factory == null) {
              synchronized (this) {
                  this.factory = new DefaultServerSocketFactory();
              }
          }
          return (this.factory);
  
      }
  
  
      /**
       * Set the server socket factory used by this Container.
       *
       * @param factory The new server socket factory
       */
      public void setFactory(ServerSocketFactory factory) {
  
          this.factory = factory;
  
      }
  
  
      /**
       * Return descriptive information about this Connector implementation.
       */
      public String getInfo() {
  
          return (info);
  
      }
  
  
      /**
       * Return the minimum number of processors to start at initialization.
       */
      public int getMinProcessors() {
  
          return (minProcessors);
  
      }
  
  
      /**
       * Set the minimum number of processors to start at initialization.
       *
       * @param minProcessors The new minimum processors
       */
      public void setMinProcessors(int minProcessors) {
  
          this.minProcessors = minProcessors;
  
      }
  
  
      /**
       * Return the maximum number of processors allowed, or <0 for unlimited.
       */
      public int getMaxProcessors() {
  
          return (maxProcessors);
  
      }
  
  
      /**
       * Set the maximum number of processors allowed, or <0 for unlimited.
       *
       * @param maxProcessors The new maximum processors
       */
      public void setMaxProcessors(int maxProcessors) {
  
          this.maxProcessors = maxProcessors;
  
      }
  
  
      /**
       * Return the port number on which we listen for requests.
       */
      public int getPort() {
  
          return (this.port);
  
      }
  
  
      /**
       * Set the port number on which we listen for requests.
       *
       * @param port The new port number
       */
      public void setPort(int port) {
  
          this.port = port;
  
      }
  
  
      /**
       * Return the class name of the Coyote protocol handler in use.
       */
      public String getProtocolHandlerClassName() {
  
          return (this.protocolHandlerClassName);
  
      }
  
  
      /**
       * Set the class name of the Coyote protocol handler which will be used 
       * by the connector.
       * 
       * @param protocolHandlerClassName The new class name
       */
      public void setProtocolHandlerClassName(String protocolHandlerClassName) {
  
          this.protocolHandlerClassName = protocolHandlerClassName;
  
      }
  
  
      /**
       * Return the proxy server name for this Connector.
       */
      public String getProxyName() {
  
          return (this.proxyName);
  
      }
  
  
      /**
       * Set the proxy server name for this Connector.
       *
       * @param proxyName The new proxy server name
       */
      public void setProxyName(String proxyName) {
  
          this.proxyName = proxyName;
  
      }
  
  
      /**
       * Return the proxy server port for this Connector.
       */
      public int getProxyPort() {
  
          return (this.proxyPort);
  
      }
  
  
      /**
       * Set the proxy server port for this Connector.
       *
       * @param proxyPort The new proxy server port
       */
      public void setProxyPort(int proxyPort) {
  
          this.proxyPort = proxyPort;
  
      }
  
  
      /**
       * Return the port number to which a request should be redirected if
       * it comes in on a non-SSL port and is subject to a security constraint
       * with a transport guarantee that requires SSL.
       */
      public int getRedirectPort() {
  
          return (this.redirectPort);
  
      }
  
  
      /**
       * Set the redirect port number.
       *
       * @param redirectPort The redirect port number (non-SSL to SSL)
       */
      public void setRedirectPort(int redirectPort) {
  
          this.redirectPort = redirectPort;
  
      }
  
  
      /**
       * Return the scheme that will be assigned to requests received
       * through this connector.  Default value is "http".
       */
      public String getScheme() {
  
          return (this.scheme);
  
      }
  
  
      /**
       * Set the scheme that will be assigned to requests received through
       * this connector.
       *
       * @param scheme The new scheme
       */
      public void setScheme(String scheme) {
  
          this.scheme = scheme;
  
      }
  
  
      /**
       * Return the secure connection flag that will be assigned to requests
       * received through this connector.  Default value is "false".
       */
      public boolean getSecure() {
  
          return (this.secure);
  
      }
  
  
      /**
       * Set the secure connection flag that will be assigned to requests
       * received through this connector.
       *
       * @param secure The new secure connection flag
       */
      public void setSecure(boolean secure) {
  
          this.secure = secure;
  
      }
  
  
      /**
       * Return the TCP no delay flag value.
       */
      public boolean getTcpNoDelay() {
  
          return (this.tcpNoDelay);
  
      }
  
  
      /**
       * Set the TCP no delay flag which will be set on the socket after
       * accepting a connection.
       *
       * @param tcpNoDelay The new TCP no delay flag
       */
      public void setTcpNoDelay(boolean tcpNoDelay) {
  
          this.tcpNoDelay = tcpNoDelay;
  
      }
  
  
      /**
       * Return the value of the Uri validation flag.
       */
      public boolean getUseURIValidationHack() {
  
          return (this.useURIValidationHack);
  
      }
  
  
      /**
       * Set the value of the Uri validation flag.
       * 
       * @param useURIValidationHack The new flag value
       */
      public void setUseURIValidationHack(boolean useURIValidationHack) {
  
          this.useURIValidationHack = useURIValidationHack;
  
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Create (or allocate) and return a Request object suitable for
       * specifying the contents of a Request to the responsible Container.
       */
      public Request createRequest() {
  
          CoyoteRequest request = new CoyoteRequest();
          request.setConnector(this);
          return (request);
  
      }
  
  
      /**
       * Create (or allocate) and return a Response object suitable for
       * receiving the contents of a Response from the responsible Container.
       */
      public Response createResponse() {
  
          CoyoteResponse response = new CoyoteResponse();
          response.setConnector(this);
          return (response);
  
      }
  
  
      // -------------------------------------------------------- Private Methods
  
  
      /**
       * Log a message on the Logger associated with our Container (if any).
       *
       * @param message Message to be logged
       */
      private void log(String message) {
  
          Logger logger = container.getLogger();
          String localName = "CoyoteConnector";
          if (logger != null)
              logger.log(localName + " " + message);
          else
              System.out.println(localName + " " + message);
  
      }
  
  
      /**
       * Log a message on the Logger associated with our Container (if any).
       *
       * @param message Message to be logged
       * @param throwable Associated exception
       */
      private void log(String message, Throwable throwable) {
  
          Logger logger = container.getLogger();
          String localName = "CoyoteConnector";
          if (logger != null)
              logger.log(localName + " " + message, throwable);
          else {
              System.out.println(localName + " " + message);
              throwable.printStackTrace(System.out);
          }
  
      }
  
  
      // ------------------------------------------------------ Lifecycle Methods
  
  
      /**
       * Add a lifecycle event listener to this component.
       *
       * @param listener The listener to add
       */
      public void addLifecycleListener(LifecycleListener listener) {
  
          lifecycle.addLifecycleListener(listener);
  
      }
  
  
      /**
       * Get the lifecycle listeners associated with this lifecycle. If this 
       * Lifecycle has no listeners registered, a zero-length array is returned.
       */
      public LifecycleListener[] findLifecycleListeners() {
  
          return null;//lifecycle.findLifecycleListeners();
  
      }
  
  
      /**
       * Remove a lifecycle event listener from this component.
       *
       * @param listener The listener to add
       */
      public void removeLifecycleListener(LifecycleListener listener) {
  
          lifecycle.removeLifecycleListener(listener);
  
      }
  
  
      /**
       * Initialize this connector (create ServerSocket here!)
       */
      public void initialize()
          throws LifecycleException {
  
          if (initialized)
              throw new LifecycleException 
                  (sm.getString("coyoteConnector.alreadyInitialized"));
  
          this.initialized = true;
  
          // Initializa adapter
          adapter = new CoyoteAdapter(this);
  
          // Instantiate protocol handler
          try {
              Class clazz = Class.forName(protocolHandlerClassName);
              protocolHandler = (ProtocolHandler) clazz.newInstance();
          } catch (Exception e) {
              e.printStackTrace();
              throw new LifecycleException
                  (sm.getString
                   ("coyoteConnector.protocolHandlerInstantiationFailed", e));
          }
          protocolHandler.setAdapter(adapter);
  
          IntrospectionUtils.setProperty(protocolHandler, "jkHome", 
                                         System.getProperty("catalina.base"));
  
          // Set attributes
          IntrospectionUtils.setProperty(protocolHandler, "port", "" + port);
          IntrospectionUtils.setProperty(protocolHandler, "maxThreads", 
                                         "" + maxProcessors);
          IntrospectionUtils.setProperty(protocolHandler, "backlog", 
                                         "" + acceptCount);
          IntrospectionUtils.setProperty(protocolHandler, "tcpNoDelay", 
                                         "" + tcpNoDelay);
          IntrospectionUtils.setProperty(protocolHandler, "soTimeout", 
                                         "" + connectionTimeout);
          IntrospectionUtils.setProperty(protocolHandler, "timeout", 
                                         "" + connectionTimeout);
          if (address != null) {
              IntrospectionUtils.setProperty(protocolHandler, "address", 
                                             address);
          }
  
          // Configure secure socket factory
          if (factory instanceof CoyoteServerSocketFactory) {
              IntrospectionUtils.setProperty(protocolHandler, "secure", 
                                             "" + true);
              CoyoteServerSocketFactory ssf = 
                  (CoyoteServerSocketFactory) factory;
              IntrospectionUtils.setProperty(protocolHandler, "algorithm", 
                                             ssf.getAlgorithm());
              if (ssf.getClientAuth()) {
                  IntrospectionUtils.setProperty(protocolHandler, "clientauth", 
                                                 "" + ssf.getClientAuth());
              }
              IntrospectionUtils.setProperty(protocolHandler, "keystore", 
                                             ssf.getKeystoreFile());
              IntrospectionUtils.setProperty(protocolHandler, "randomfile", 
                                             ssf.getRandomFile());
              IntrospectionUtils.setProperty(protocolHandler, "rootfile", 
                                             ssf.getRootFile());
  			
              IntrospectionUtils.setProperty(protocolHandler, "keypass", 
                                             ssf.getKeystorePass());
              IntrospectionUtils.setProperty(protocolHandler, "keytype", 
                                             ssf.getKeystoreType());
              IntrospectionUtils.setProperty(protocolHandler, "protocol", 
                                             ssf.getProtocol());
              IntrospectionUtils.setProperty(protocolHandler, 
                                             "sSLImplementation", 
                                             ssf.getSSLImplementation());
          } else {
              IntrospectionUtils.setProperty(protocolHandler, "secure", 
                                             "" + false);
          }
  
          try {
              protocolHandler.init();
          } catch (Exception e) {
              throw new LifecycleException
                  (sm.getString
                   ("coyoteConnector.protocolHandlerInitializationFailed", e));
          }
      }
  
  
      /**
       * Begin processing requests via this Connector.
       *
       * @exception LifecycleException if a fatal startup error occurs
       */
      public void start() throws LifecycleException {
  
          // Validate and update our current state
          if (started)
              throw new LifecycleException
                  (sm.getString("coyoteConnector.alreadyStarted"));
          lifecycle.fireLifecycleEvent(START_EVENT, null);
          started = true;
  
          try {
              protocolHandler.start();
          } catch (Exception e) {
              throw new LifecycleException
                  (sm.getString
                   ("coyoteConnector.protocolHandlerStartFailed", e));
          }
  
      }
  
  
      /**
       * Terminate processing requests via this Connector.
       *
       * @exception LifecycleException if a fatal shutdown error occurs
       */
      public void stop() throws LifecycleException {
  
          // Validate and update our current state
          if (!started)
              throw new LifecycleException
                  (sm.getString("coyoteConnector.notStarted"));
          lifecycle.fireLifecycleEvent(STOP_EVENT, null);
          started = false;
  
          try {
              protocolHandler.destroy();
          } catch (Exception e) {
              throw new LifecycleException
                  (sm.getString
                   ("coyoteConnector.protocolHandlerDestroyFailed", e));
          }
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteInputStream.java
  
  Index: CoyoteInputStream.java
  ===================================================================
  /*
   * ====================================================================
   * 
   * 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.coyote.tomcat5;
  
  import java.io.InputStream;
  import java.io.IOException;
  
  import javax.servlet.ServletInputStream;
  
  import org.apache.tomcat.util.buf.ByteChunk;
  
  import org.apache.coyote.Request;
  
  
  /**
   * This class handles the readin input bytes, as well as the input buffering.
   * 
   * @author Remy Maucherat
   */
  public class CoyoteInputStream extends ServletInputStream {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      private boolean closed = false;
  
      private Request coyoteRequest;
  
      private ByteChunk readChunk = new ByteChunk();
  
      /**
       * Current read position in the byte buffer.
       */
      private int pos = -1;
      private int end = -1;
      private byte[] readBuffer = null;
  
  
      // --------------------------------------------------------- Public Methods
  
  
      void setRequest(Request coyoteRequest) {
          this.coyoteRequest = coyoteRequest;
      }
  
  
      /**
       * Recycle the input stream.
       */
      void recycle() {
          closed = false;
          pos = -1;
          end = -1;
          readBuffer = null;
      }
  
  
      // --------------------------------------------- ServletInputStream Methods
  
  
      public int read()
          throws IOException {
  
          if (closed)
              throw new IOException("Stream closed");
  
          // Read additional bytes if none are available
          while (pos >= end) {
              if (readBytes() < 0)
                  return -1;
          }
  
          return (readBuffer[pos++] & 0xFF);
  
      }
  
  
      public int read(byte[] b) throws IOException {
  
          return read(b, 0, b.length);
  
      }
  
  
      public int read(byte[] b, int off, int len)
          throws IOException {
  
          if (closed)
              throw new IOException("Stream closed");
  
          // Read additional bytes if none are available
          while (pos >= end) {
              if (readBytes() < 0)
                  return -1;
          }
  
          int n = -1;
          if ((end - pos) > len) {
              n = len;
          } else {
              n = end - pos;
          }
  
          System.arraycopy(readBuffer, pos, b, off, n);
  
          pos += n;
          return n;
  
      }
  
  
      public int readLine(byte[] b, int off, int len) throws IOException {
          return super.readLine(b, off, len);
      }
  
  
      /** 
       * Close the stream
       * Since we re-cycle, we can't allow the call to super.close()
       * which would permantely disable us.
       */
      public void close() {
          closed = true;
      }
  
  
      // ------------------------------------------------------ Protected Methods
  
  
      /**
       * Read bytes to the read chunk buffer.
       */
      protected int readBytes()
          throws IOException {
  
          int result = coyoteRequest.doRead(readChunk);
          if (result > 0) {
              readBuffer = readChunk.getBytes();
              end = readChunk.getEnd();
              pos = readChunk.getStart();
          }
          return result;
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteOutputStream.java
  
  Index: CoyoteOutputStream.java
  ===================================================================
  /*
   * ====================================================================
   * 
   * 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.coyote.tomcat5;
  
  import java.io.IOException;
  
  import javax.servlet.ServletOutputStream;
  
  import org.apache.coyote.Response;
  
  /**
   * Coyote implementation of the servlet output stream.
   * 
   * @author Costin Manolache
   * @author Remy Maucherat
   */
  final class CoyoteOutputStream 
      extends ServletOutputStream {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      protected OutputBuffer ob;
  
  
      // ----------------------------------------------------------- Constructors
  
  
      protected CoyoteOutputStream(OutputBuffer ob) {
          this.ob = ob;
      }
  
  
      // --------------------------------------------------- OutputStream Methods
  
  
      public void write(int i)
          throws IOException {
          ob.writeByte(i);
      }
  
  
      public void write(byte[] b)
          throws IOException {
          write(b, 0, b.length);
      }
  
  
      public void write(byte[] b, int off, int len)
          throws IOException {
          ob.write(b, off, len);
      }
  
  
      /**
       * Will send the buffer to the client.
       */
      public void flush()
          throws IOException {
          if (ob.flushCharsNeeded())
              ob.flushChars();
          ob.flushBytes();
      }
  
  
      public void close()
          throws IOException {
          if (ob.flushCharsNeeded())
              ob.flushChars();
          ob.flushBytes();
      }
  
  
      // -------------------------------------------- ServletOutputStream Methods
  
  
      public void print(String s)
          throws IOException {
          ob.write(s);
      }
  
  
  }
  
  
  
  
  1.1                  jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteRequest.java
  
  Index: CoyoteRequest.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteRequest.java,v 1.1 2002/08/04 19:39:49 patrickl Exp $
   * $Revision: 1.1 $
   * $Date: 2002/08/04 19:39:49 $
   *
   * ====================================================================
   *
   * 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.coyote.tomcat5;
  
  
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.io.IOException;
  import java.io.BufferedReader;
  import java.io.UnsupportedEncodingException;
  import java.net.InetAddress;
  import java.net.Socket;
  import java.security.AccessController;
  import java.security.Principal;
  import java.security.PrivilegedAction;
  import java.text.ParseException;
  import java.text.SimpleDateFormat;
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.Enumeration;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Locale;
  import java.util.Map;
  import java.util.TreeMap;
  
  import javax.servlet.RequestDispatcher;
  import javax.servlet.ServletContext;
  import javax.servlet.ServletException;
  import javax.servlet.ServletInputStream;
  import javax.servlet.ServletRequest;
  import javax.servlet.http.Cookie;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.http.HttpSession;
  
  import org.apache.tomcat.util.http.Parameters;
  
  import org.apache.coyote.ActionCode;
  import org.apache.coyote.Request;
  
  import org.apache.catalina.Connector;
  import org.apache.catalina.Context;
  import org.apache.catalina.Globals;
  import org.apache.catalina.HttpRequest;
  import org.apache.catalina.Manager;
  import org.apache.catalina.Realm;
  import org.apache.catalina.Session;
  import org.apache.catalina.Wrapper;
  
  import org.apache.catalina.util.Enumerator;
  import org.apache.catalina.util.ParameterMap;
  import org.apache.catalina.util.RequestUtil;
  import org.apache.catalina.util.StringManager;
  import org.apache.catalina.util.StringParser;
  
  import org.apache.tomcat.util.net.SSLSupport;
  
  /**
   * Wrapper object for the Coyote request.
   *
   * @author Remy Maucherat
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2002/08/04 19:39:49 $
   */
  
  public class CoyoteRequest
      implements HttpRequest, HttpServletRequest {
  
  
      // --------------------------------------- PrivilegedGetSession Inner Class
  
  
      protected class PrivilegedGetSession
          implements PrivilegedAction {
  
          private boolean create;
  
          PrivilegedGetSession(boolean create) {
              this.create = create;
          }
  
          public Object run() {
              return doGetSession(create);
          }
  
      }
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Coyote request.
       */
      protected Request coyoteRequest;
  
      /**
       * Set the Coyote request.
       * 
       * @param coyoteRequest The Coyote request
       */
      public void setCoyoteRequest(Request coyoteRequest) {
          this.coyoteRequest = coyoteRequest;
          inputStream.setRequest(coyoteRequest);
      }
  
      /**
       * Get the Coyote request.
       */
      public Request getCoyoteRequest() {
          return (this.coyoteRequest);
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The string manager for this package.
       */
      protected static StringManager sm =
          StringManager.getManager(Constants.Package);
  
  
      /**
       * The set of cookies associated with this Request.
       */
      protected Cookie[] cookies = null;
  
  
      /**
       * The set of SimpleDateFormat formats to use in getDateHeader().
       */
      protected SimpleDateFormat formats[] = {
          new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
          new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
          new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
      };
  
  
      /**
       * The default Locale if none are specified.
       */
      protected static Locale defaultLocale = Locale.getDefault();
  
  
      /**
       * The attributes associated with this Request, keyed by attribute name.
       */
      protected HashMap attributes = new HashMap();
  
  
      /**
       * The preferred Locales assocaited with this Request.
       */
      protected ArrayList locales = new ArrayList();
  
  
      /**
       * Internal notes associated with this request by Catalina components
       * and event listeners.
       */
      private transient HashMap notes = new HashMap();
  
  
      /**
       * Authentication type.
       */
      protected String authType = null;
  
  
      /**
       * Reader.
       * Note: At the moment, no attempt is being made at recycling the reader,
       * but this could be implemented in the future, using a design like the one
       * used for the output buffer.
       */
      protected BufferedReader reader = null;
  
  
      /**
       * ServletInputStream.
       */
      protected CoyoteInputStream inputStream = new CoyoteInputStream();
  
  
      /**
       * Using stream flag.
       */
      protected boolean usingInputStream = false;
  
  
      /**
       * Using writer flag.
       */
      protected boolean usingReader = false;
  
  
      /**
       * Context path.
       */
      protected String contextPath = "";
  
  
      /**
       * Path info.
       */
      protected String pathInfo = null;
  
  
      /**
       * Servlet path.
       */
      protected String servletPath = null;
  
  
      /**
       * User principal.
       */
      protected Principal userPrincipal = null;
  
  
      /**
       * Session parsed flag.
       */
      protected boolean sessionParsed = false;
  
  
      /**
       * Request parameters parsed flag.
       */
      protected boolean requestParametersParsed = false;
  
  
      /**
       * Secure flag.
       */
      protected boolean secure = false;
  
  
      /**
       * Post data buffer.
       */
      protected static int CACHED_POST_LEN = 8192;
      protected byte[] postData = null;
  
  
      /**
       * Hash map used in the getParametersMap method.
       */
      protected ParameterMap parameterMap = new ParameterMap();
  
  
      /**
       * The currently active session for this request.
       */
      protected Session session = null;
  
  
      /**
       * Was the requested session ID received in a cookie?
       */
      protected boolean requestedSessionCookie = false;
  
  
      /**
       * The requested session ID (if any) for this request.
       */
      protected String requestedSessionId = null;
  
  
      /**
       * Was the requested session ID received in a URL?
       */
      protected boolean requestedSessionURL = false;
  
  
      /**
       * The socket through which this Request was received.
       */
      protected Socket socket = null;
  
  
      /**
       * Parse locales.
       */
      protected boolean localesParsed = false;
  
  
      /**
       * The string parser we will use for parsing request lines.
       */
      private StringParser parser = new StringParser();
  
  
      /**
       * Remote address.
       */
      protected String remoteAddr = null;
  
  
      /**
       * Remote host.
       */
      protected String remoteHost = null;
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Release all object references, and initialize instance variables, in
       * preparation for reuse of this object.
       */
      public void recycle() {
  
          context = null;
          wrapper = null;
  
          authorization = null;
          authType = null;
          usingInputStream = false;
          usingReader = false;
          contextPath = "";
          pathInfo = null;
          servletPath = null;
          reader = null;
          inputStream.recycle();
          userPrincipal = null;
          sessionParsed = false;
          authorization = null;
          requestParametersParsed = false;
          locales.clear();
          localesParsed = false;
          secure = false;
          remoteAddr = null;
          remoteHost = null;
  
          attributes.clear();
          notes.clear();
          cookies = null;
  
          session = null;
          requestedSessionCookie = false;
          requestedSessionId = null;
          requestedSessionURL = false;
  
          parameterMap.setLocked(false);
          parameterMap.clear();
  
          if (facade != null) {
              facade.clear();
              facade = null;
          }
  
      }
  
  
      // -------------------------------------------------------- Request Methods
  
  
      /**
       * The authorization credentials sent with this Request.
       */
      protected String authorization = null;
  
      /**
       * Return the authorization credentials sent with this request.
       */
      public String getAuthorization() {
  
          return (this.authorization);
  
      }
  
      /**
       * Set the authorization credentials sent with this request.
       *
       * @param authorization The new authorization credentials
       */
      public void setAuthorization(String authorization) {
          this.authorization = authorization;
      }
  
  
      /**
       * Associated Catalina connector.
       */
      protected Connector connector;
  
      /**
       * Return the Connector through which this Request was received.
       */
      public Connector getConnector() {
          return (this.connector);
      }
  
      /**
       * Set the Connector through which this Request was received.
       *
       * @param connector The new connector
       */
      public void setConnector(Connector connector) {
          this.connector = connector;
      }
  
      /**
       * The Context within which this Request is being processed.
       */
      protected Context context = null;
  
      /**
       * Return the Context within which this Request is being processed.
       */
      public Context getContext() {
          return (this.context);
      }
  
      /**
       * Set the Context within which this Request is being processed.  This
       * must be called as soon as the appropriate Context is identified, because
       * it identifies the value to be returned by <code>getContextPath()</code>,
       * and thus enables parsing of the request URI.
       *
       * @param context The newly associated Context
       */
      public void setContext(Context context) {
          this.context = context;
      }
  
  
      /**
       * Descriptive information about this Request implementation.
       */
      protected static final String info =
          "org.apache.coyote.catalina.CoyoteRequest/1.0";
  
      /**
       * Return descriptive information about this Request implementation and
       * the corresponding version number, in the format
       * <code>&lt;description&gt;/&lt;version&gt;</code>.
       */
      public String getInfo() {
          return (info);
      }
  
  
      /**
       * The facade associated with this request.
       */
      protected CoyoteRequestFacade facade = null;
  
      /**
       * Return the <code>ServletRequest</code> for which this object
       * is the facade.  This method must be implemented by a subclass.
       */
      public ServletRequest getRequest() {
          if (facade == null) {
              facade = new CoyoteRequestFacade(this);
          }
          return (facade);
      }
  
  
      /**
       * The response with which this request is associated.
       */
      protected org.apache.catalina.Response response = null;
  
      /**
       * Return the Response with which this Request is associated.
       */
      public org.apache.catalina.Response getResponse() {
          return (this.response);
      }
  
      /**
       * Set the Response with which this Request is associated.
       *
       * @param response The new associated response
       */
      public void setResponse(org.apache.catalina.Response response) {
          this.response = response;
      }
  
  
      /**
       * Return the Socket (if any) through which this Request was received.
       * This should <strong>only</strong> be used to access underlying state
       * information about this Socket, such as the SSLSession associated with
       * an SSLSocket.
       */
      public Socket getSocket() {
          return (socket);
      }
  
      /**
       * Set the Socket (if any) through which this Request was received.
       *
       * @param socket The socket through which this request was received
       */
      public void setSocket(Socket socket) {
          this.socket = socket;
          remoteHost = null;
          remoteAddr = null;
      }
  
  
      /**
       * Return the input stream associated with this Request.
       */
      public InputStream getStream() {
          return inputStream;
      }
  
      /**
       * Set the input stream associated with this Request.
       *
       * @param stream The new input stream
       */
      public void setStream(InputStream stream) {
          // Ignore
      }
  
  
      /**
       * The Wrapper within which this Request is being processed.
       */
      protected Wrapper wrapper = null;
  
      /**
       * Return the Wrapper within which this Request is being processed.
       */
      public Wrapper getWrapper() {
          return (this.wrapper);
      }
  
      /**
       * Set the Wrapper within which this Request is being processed.  This
       * must be called as soon as the appropriate Wrapper is identified, and
       * before the Request is ultimately passed to an application servlet.
       *
       * @param wrapper The newly associated Wrapper
       */
      public void setWrapper(Wrapper wrapper) {
          this.wrapper = wrapper;
      }
  
  
      // ------------------------------------------------- Request Public Methods
  
  
      /**
       * Create and return a ServletInputStream to read the content
       * associated with this Request.
       *
       * @exception IOException if an input/output error occurs
       */
      public ServletInputStream createInputStream() 
          throws IOException {
          return inputStream;
      }
  
  
      /**
       * Perform whatever actions are required to flush and close the input
       * stream or reader, in a single operation.
       *
       * @exception IOException if an input/output error occurs
       */
      public void finishRequest() throws IOException {
          // The reader and input stream don't need to be closed
      }
  
  
      /**
       * Return the object bound with the specified name to the internal notes
       * for this request, or <code>null</code> if no such binding exists.
       *
       * @param name Name of the note to be returned
       */
      public Object getNote(String name) {
          return (notes.get(name));
      }
  
  
      /**
       * Return an Iterator containing the String names of all notes bindings
       * that exist for this request.
       */
      public Iterator getNoteNames() {
          return (notes.keySet().iterator());
      }
  
  
      /**
       * Remove any object bound to the specified name in the internal notes
       * for this request.
       *
       * @param name Name of the note to be removed
       */
      public void removeNote(String name) {
          notes.remove(name);
      }
  
  
      /**
       * Bind an object to a specified name in the internal notes associated
       * with this request, replacing any existing binding for this name.
       *
       * @param name Name to which the object should be bound
       * @param value Object to be bound to the specified name
       */
      public void setNote(String name, Object value) {
          notes.put(name, value);
      }
  
  
      /**
       * Set the content length associated with this Request.
       *
       * @param length The new content length
       */
      public void setContentLength(int length) {
          // Not used
      }
  
  
      /**
       * Set the content type (and optionally the character encoding)
       * associated with this Request.  For example,
       * <code>text/html; charset=ISO-8859-4</code>.
       *
       * @param type The new content type
       */
      public void setContentType(String type) {
          // Not used
      }
  
  
      /**
       * Set the protocol name and version associated with this Request.
       *
       * @param protocol Protocol name and version
       */
      public void setProtocol(String protocol) {
          // Not used
      }
  
  
      /**
       * Set the IP address of the remote client associated with this Request.
       *
       * @param remoteAddr The remote IP address
       */
      public void setRemoteAddr(String remoteAddr) {
          // Not used
      }
  
  
      /**
       * Set the fully qualified name of the remote client associated with this
       * Request.
       *
       * @param remoteHost The remote host name
       */
      public void setRemoteHost(String remoteHost) {
          // Not used
      }
  
  
      /**
       * Set the name of the scheme associated with this request.  Typical values
       * are <code>http</code>, <code>https</code>, and <code>ftp</code>.
       *
       * @param scheme The scheme
       */
      public void setScheme(String scheme) {
          // Not used
      }
  
  
      /**
       * Set the value to be returned by <code>isSecure()</code>
       * for this Request.
       *
       * @param secure The new isSecure value
       */
      public void setSecure(boolean secure) {
          this.secure = secure;
      }
  
  
      /**
       * Set the name of the server (virtual host) to process this request.
       *
       * @param name The server name
       */
      public void setServerName(String name) {
          coyoteRequest.serverName().setString(name);
      }
  
  
      /**
       * Set the port number of the server to process this request.
       *
       * @param port The server port
       */
      public void setServerPort(int port) {
          coyoteRequest.setServerPort(port);
      }
  
  
      // ------------------------------------------------- ServletRequest Methods
  
  
      /**
       * Return the specified request attribute if it exists; otherwise, return
       * <code>null</code>.
       *
       * @param name Name of the request attribute to return
       */
      public Object getAttribute(String name) {
  	Object attr=attributes.get(name);
  
  	if(attr!=null)
  	    return(attr);
  
  	return coyoteRequest.getAttribute(name);
      }
  
  
      /**
       * Return the names of all request attributes for this Request, or an
       * empty <code>Enumeration</code> if there are none.
       */
      public Enumeration getAttributeNames() {
          return (new Enumerator(attributes.keySet()));
      }
  
  
      /**
       * Return the character encoding for this Request.
       */
      public String getCharacterEncoding() {
        return (coyoteRequest.getCharacterEncoding());
      }
  
  
      /**
       * Return the content length for this Request.
       */
      public int getContentLength() {
          return (coyoteRequest.getContentLength());
      }
  
  
      /**
       * Return the content type for this Request.
       */
      public String getContentType() {
          return (coyoteRequest.getContentType());
      }
  
  
      /**
       * Return the servlet input stream for this Request.  The default
       * implementation returns a servlet input stream created by
       * <code>createInputStream()</code>.
       *
       * @exception IllegalStateException if <code>getReader()</code> has
       *  already been called for this request
       * @exception IOException if an input/output error occurs
       */
      public ServletInputStream getInputStream() throws IOException {
  
          if (usingReader)
              throw new IllegalStateException
                  (sm.getString("coyoteRequest.getInputStream.ise"));
  
          usingInputStream = true;
          return inputStream;
  
      }
  
  
      /**
       * Return the preferred Locale that the client will accept content in,
       * based on the value for the first <code>Accept-Language</code> header
       * that was encountered.  If the request did not specify a preferred
       * language, the server's default Locale is returned.
       */
      public Locale getLocale() {
  
          if (!localesParsed)
              parseLocales();
  
          if (locales.size() > 0) {
              return ((Locale) locales.get(0));
          } else {
              return (defaultLocale);
          }
  
      }
  
  
      /**
       * Return the set of preferred Locales that the client will accept
       * content in, based on the values for any <code>Accept-Language</code>
       * headers that were encountered.  If the request did not specify a
       * preferred language, the server's default Locale is returned.
       */
      public Enumeration getLocales() {
  
          if (!localesParsed)
              parseLocales();
  
          if (locales.size() > 0)
              return (new Enumerator(locales));
          ArrayList results = new ArrayList();
          results.add(defaultLocale);
          return (new Enumerator(results));
  
      }
  
  
      /**
       * Return the value of the specified request parameter, if any; otherwise,
       * return <code>null</code>.  If there is more than one value defined,
       * return only the first one.
       *
       * @param name Name of the desired request parameter
       */
      public String getParameter(String name) {
  
          if (!requestParametersParsed)
              parseRequestParameters();
  
          return coyoteRequest.getParameters().getParameter(name);
  
      }
  
  
  
      /**
       * Returns a <code>Map</code> of the parameters of this request.
       * Request parameters are extra information sent with the request.
       * For HTTP servlets, parameters are contained in the query string
       * or posted form data.
       *
       * @return A <code>Map</code> containing parameter names as keys
       *  and parameter values as map values.
       */
      public Map getParameterMap() {
  
          if (parameterMap.isLocked())
              return parameterMap;
  
          Enumeration enum = getParameterNames();
          while (enum.hasMoreElements()) {
              String name = enum.nextElement().toString();
              String[] values = getParameterValues(name);
              parameterMap.put(name, values);
          }
  
          parameterMap.setLocked(true);
  
          return parameterMap;
  
      }
  
  
      /**
       * Return the names of all defined request parameters for this request.
       */
      public Enumeration getParameterNames() {
  
          if (!requestParametersParsed)
              parseRequestParameters();
  
          return coyoteRequest.getParameters().getParameterNames();
  
      }
  
  
      /**
       * Return the defined values for the specified request parameter, if any;
       * otherwise, return <code>null</code>.
       *
       * @param name Name of the desired request parameter
       */
      public String[] getParameterValues(String name) {
  
          if (!requestParametersParsed)
              parseRequestParameters();
  
          return coyoteRequest.getParameters().getParameterValues(name);
  
      }
  
  
      /**
       * Return the protocol and version used to make this Request.
       */
      public String getProtocol() {
          return coyoteRequest.protocol().toString();
      }
  
  
      /**
       * Read the Reader wrapping the input stream for this Request.  The
       * default implementation wraps a <code>BufferedReader</code> around the
       * servlet input stream returned by <code>createInputStream()</code>.
       *
       * @exception IllegalStateException if <code>getInputStream()</code>
       *  has already been called for this request
       * @exception IOException if an input/output error occurs
       */
      public BufferedReader getReader() throws IOException {
  
          if (usingInputStream)
              throw new IllegalStateException
                  (sm.getString("coyoteRequest.getReader.ise"));
  
          usingReader = true;
          if (reader == null) {
              String encoding = getCharacterEncoding();
              if (encoding == null) {
                  encoding = 
                      org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
              }
              InputStreamReader r = new InputStreamReader(inputStream, encoding);
              reader = new BufferedReader(r);
          }
          return (reader);
  
      }
  
  
      /**
       * Return the real path of the specified virtual path.
       *
       * @param path Path to be translated
       *
       * @deprecated As of version 2.1 of the Java Servlet API, use
       *  <code>ServletContext.getRealPath()</code>.
       */
      public String getRealPath(String path) {
  
          if (context == null)
              return (null);
          ServletContext servletContext = context.getServletContext();
          if (servletContext == null)
              return (null);
          else {
              try {
                  return (servletContext.getRealPath(path));
              } catch (IllegalArgumentException e) {
                  return (null);
              }
          }
  
      }
  
  
      /**
       * Return the remote IP address making this Request.
       */
      public String getRemoteAddr() {
          if (remoteAddr == null) {
              if (socket != null) {
                  InetAddress inet = socket.getInetAddress();
                  remoteAddr = inet.getHostAddress();
              } else {
                  remoteAddr = coyoteRequest.remoteAddr().toString();
              }
          }
          return remoteAddr;
      }
  
  
      /**
       * Return the remote host name making this Request.
       */
      public String getRemoteHost() {
          if (remoteHost == null) {
              if (!connector.getEnableLookups()) {
                  remoteHost = getRemoteAddr();
              } else if (socket != null) {
                  InetAddress inet = socket.getInetAddress();
                  remoteHost = inet.getHostName();
              } else {
                  coyoteRequest.action
                      (ActionCode.ACTION_REQ_HOST_ATTRIBUTE, coyoteRequest);
                  remoteHost = coyoteRequest.remoteHost().toString();
              }
          }
          return remoteHost;
      }
  
  
      /**
       * Return a RequestDispatcher that wraps the resource at the specified
       * path, which may be interpreted as relative to the current request path.
       *
       * @param path Path of the resource to be wrapped
       */
      public RequestDispatcher getRequestDispatcher(String path) {
  
          if (context == null)
              return (null);
  
          // If the path is already context-relative, just pass it through
          if (path == null)
              return (null);
          else if (path.startsWith("/"))
              return (context.getServletContext().getRequestDispatcher(path));
  
          // Convert a request-relative path to a context-relative one
          String servletPath = (String) getAttribute(Globals.SERVLET_PATH_ATTR);
          if (servletPath == null)
              servletPath = getServletPath();
  
          int pos = servletPath.lastIndexOf('/');
          String relative = null;
          if (pos >= 0) {
              relative = RequestUtil.normalize
                  (servletPath.substring(0, pos + 1) + path);
          } else {
              relative = RequestUtil.normalize(servletPath + path);
          }
  
          return (context.getServletContext().getRequestDispatcher(relative));
  
      }
  
  
      /**
       * Return the scheme used to make this Request.
       */
      public String getScheme() {
          return (coyoteRequest.scheme().toString());
      }
  
  
      /**
       * Return the server name responding to this Request.
       */
      public String getServerName() {
          return (coyoteRequest.serverName().toString());
      }
  
  
      /**
       * Return the server port responding to this Request.
       */
      public int getServerPort() {
          return (coyoteRequest.getServerPort());
      }
  
  
      /**
       * Was this request received on a secure connection?
       */
      public boolean isSecure() {
          return (secure);
      }
  
  
      /**
       * Remove the specified request attribute if it exists.
       *
       * @param name Name of the request attribute to remove
       */
      public void removeAttribute(String name) {
          attributes.remove(name);
      }
  
  
      /**
       * Set the specified request attribute to the specified value.
       *
       * @param name Name of the request attribute to set
       * @param value The associated value
       */
      public void setAttribute(String name, Object value) {
  	
          // Name cannot be null
          if (name == null)
              throw new IllegalArgumentException
                  (sm.getString("coyoteRequest.setAttribute.namenull"));
  
          // Null value is the same as removeAttribute()
          if (value == null) {
              removeAttribute(name);
              return;
          }
  
          attributes.put(name, value);
  
      }
  
  
      /**
       * Overrides the name of the character encoding used in the body of
       * this request.  This method must be called prior to reading request
       * parameters or reading input using <code>getReader()</code>.
       *
       * @param enc The character encoding to be used
       *
       * @exception UnsupportedEncodingException if the specified encoding
       *  is not supported
       *
       * @since Servlet 2.3
       */
      public void setCharacterEncoding(String enc)
          throws UnsupportedEncodingException {
  
          // Ensure that the specified encoding is valid
          byte buffer[] = new byte[1];
          buffer[0] = (byte) 'a';
          String dummy = new String(buffer, enc);
  
          // Save the validated encoding
          coyoteRequest.setCharacterEncoding(enc);
  
      }
  
  
      // ---------------------------------------------------- HttpRequest Methods
  
  
      /**
       * Add a Cookie to the set of Cookies associated with this Request.
       *
       * @param cookie The new cookie
       */
      public void addCookie(Cookie cookie) {
  
          // For compatibility only
  
          int size = 0;
          if (cookies != null) {
              size = cookies.length;
          }
  
          Cookie[] newCookies = new Cookie[size + 1];
          for (int i = 0; i < size; i++) {
              newCookies[i] = cookies[i];
          }
          newCookies[size] = cookie;
  
          cookies = newCookies;
  
      }
  
  
      /**
       * Add a Header to the set of Headers associated with this Request.
       *
       * @param name The new header name
       * @param value The new header value
       */
      public void addHeader(String name, String value) {
          // Not used
      }
  
  
      /**
       * Add a Locale to the set of preferred Locales for this Request.  The
       * first added Locale will be the first one returned by getLocales().
       *
       * @param locale The new preferred Locale
       */
      public void addLocale(Locale locale) {
          locales.add(locale);
      }
  
  
      /**
       * Add a parameter name and corresponding set of values to this Request.
       * (This is used when restoring the original request on a form based
       * login).
       *
       * @param name Name of this request parameter
       * @param values Corresponding values for this request parameter
       */
      public void addParameter(String name, String values[]) {
          // Not used
      }
  
  
      /**
       * Clear the collection of Cookies associated with this Request.
       */
      public void clearCookies() {
          cookies = null;
      }
  
  
      /**
       * Clear the collection of Headers associated with this Request.
       */
      public void clearHeaders() {
          // Not used
      }
  
  
      /**
       * Clear the collection of Locales associated with this Request.
       */
      public void clearLocales() {
          locales.clear();
      }
  
  
      /**
       * Clear the collection of parameters associated with this Request.
       */
      public void clearParameters() {
          // Not used
      }
  
  
      /**
       * Set the authentication type used for this request, if any; otherwise
       * set the type to <code>null</code>.  Typical values are "BASIC",
       * "DIGEST", or "SSL".
       *
       * @param type The authentication type used
       */
      public void setAuthType(String type) {
          this.authType = type;
      }
  
  
      /**
       * Set the context path for this Request.  This will normally be called
       * when the associated Context is mapping the Request to a particular
       * Wrapper.
       *
       * @param path The context path
       */
      public void setContextPath(String path) {
  
          if (path == null) {
              this.contextPath = "";
          } else {
              this.contextPath = path;
          }
  
      }
  
  
      /**
       * Set the HTTP request method used for this Request.
       *
       * @param method The request method
       */
      public void setMethod(String method) {
          // Not used
      }
  
  
      /**
       * Set the query string for this Request.  This will normally be called
       * by the HTTP Connector, when it parses the request headers.
       *
       * @param query The query string
       */
      public void setQueryString(String query) {
          // Not used
      }
  
  
      /**
       * Set the path information for this Request.  This will normally be called
       * when the associated Context is mapping the Request to a particular
       * Wrapper.
       *
       * @param path The path information
       */
      public void setPathInfo(String path) {
          this.pathInfo = path;
      }
  
  
      /**
       * Set a flag indicating whether or not the requested session ID for this
       * request came in through a cookie.  This is normally called by the
       * HTTP Connector, when it parses the request headers.
       *
       * @param flag The new flag
       */
      public void setRequestedSessionCookie(boolean flag) {
  
          this.requestedSessionCookie = flag;
  
      }
  
  
      /**
       * Set the requested session ID for this request.  This is normally called
       * by the HTTP Connector, when it parses the request headers.
       *
       * @param id The new session id
       */
      public void setRequestedSessionId(String id) {
  
          this.requestedSessionId = id;
  
      }
  
  
      /**
       * Set a flag indicating whether or not the requested session ID for this
       * request came in through a URL.  This is normally called by the
       * HTTP Connector, when it parses the request headers.
       *
       * @param flag The new flag
       */
      public void setRequestedSessionURL(boolean flag) {
  
          this.requestedSessionURL = flag;
  
      }
  
  
      /**
       * Set the unparsed request URI for this Request.  This will normally be
       * called by the HTTP Connector, when it parses the request headers.
       *
       * @param uri The request URI
       */
      public void setRequestURI(String uri) {
          // Not used
      }
  
  
      /**
       * Set the decoded request URI.
       * 
       * @param uri The decoded request URI
       */
      public void setDecodedRequestURI(String uri) {
          // Not used
      }
  
  
      /**
       * Get the decoded request URI.
       * 
       * @return the URL decoded request URI
       */
      public String getDecodedRequestURI() {
          return (coyoteRequest.decodedURI().toString());
      }
  
  
      /**
       * Set the servlet path for this Request.  This will normally be called
       * when the associated Context is mapping the Request to a particular
       * Wrapper.
       *
       * @param path The servlet path
       */
      public void setServletPath(String path) {
          this.servletPath = path;
      }
  
  
      /**
       * Set the Principal who has been authenticated for this Request.  This
       * value is also used to calculate the value to be returned by the
       * <code>getRemoteUser()</code> method.
       *
       * @param principal The user Principal
       */
      public void setUserPrincipal(Principal principal) {
          this.userPrincipal = principal;
      }
  
  
      // --------------------------------------------- HttpServletRequest Methods
  
  
      /**
       * Return the authentication type used for this Request.
       */
      public String getAuthType() {
          return (authType);
      }
  
  
      /**
       * Return the portion of the request URI used to select the Context
       * of the Request.
       */
      public String getContextPath() {
          return (contextPath);
      }
  
  
      /**
       * Return the set of Cookies received with this Request.
       */
      public Cookie[] getCookies() {
  
          return cookies;
  
      }
  
  
      /**
       * Set the set of cookies recieved with this Request.
       */
      public void setCookies(Cookie[] cookies) {
  
          this.cookies = cookies;
  
      }
  
  
      /**
       * Return the value of the specified date header, if any; otherwise
       * return -1.
       *
       * @param name Name of the requested date header
       *
       * @exception IllegalArgumentException if the specified header value
       *  cannot be converted to a date
       */
      public long getDateHeader(String name) {
  
          String value = getHeader(name);
          if (value == null)
              return (-1L);
  
          // Work around a bug in SimpleDateFormat in pre-JDK1.2b4
          // (Bug Parade bug #4106807)
          value += " ";
  
          // Attempt to convert the date header in a variety of formats
          for (int i = 0; i < formats.length; i++) {
              try {
                  Date date = formats[i].parse(value);
                  return (date.getTime());
              } catch (ParseException e) {
                  ;
              }
          }
          throw new IllegalArgumentException(value);
  
      }
  
  
      /**
       * Return the first value of the specified header, if any; otherwise,
       * return <code>null</code>
       *
       * @param name Name of the requested header
       */
      public String getHeader(String name) {
          return coyoteRequest.getHeader(name);
      }
  
  
      /**
       * Return all of the values of the specified header, if any; otherwise,
       * return an empty enumeration.
       *
       * @param name Name of the requested header
       */
      public Enumeration getHeaders(String name) {
          return coyoteRequest.getMimeHeaders().values(name);
      }
  
  
      /**
       * Return the names of all headers received with this request.
       */
      public Enumeration getHeaderNames() {
          return coyoteRequest.getMimeHeaders().names();
      }
  
  
      /**
       * Return the value of the specified header as an integer, or -1 if there
       * is no such header for this request.
       *
       * @param name Name of the requested header
       *
       * @exception IllegalArgumentException if the specified header value
       *  cannot be converted to an integer
       */
      public int getIntHeader(String name) {
  
          String value = getHeader(name);
          if (value == null) {
              return (-1);
          } else {
              return (Integer.parseInt(value));
          }
  
      }
  
  
      /**
       * Return the HTTP request method used in this Request.
       */
      public String getMethod() {
          return coyoteRequest.method().toString();
      }
  
  
      /**
       * Return the path information associated with this Request.
       */
      public String getPathInfo() {
          return (pathInfo);
      }
  
  
      /**
       * Return the extra path information for this request, translated
       * to a real path.
       */
      public String getPathTranslated() {
  
          if (context == null)
              return (null);
  
          if (pathInfo == null) {
              return (null);
          } else {
              return (context.getServletContext().getRealPath(pathInfo));
          }
  
      }
  
  
      /**
       * Return the query string associated with this request.
       */
      public String getQueryString() {
          String queryString = coyoteRequest.queryString().toString();
          if (queryString.equals("")) {
              return (null);
          } else {
              return queryString;
          }
      }
  
  
      /**
       * Return the name of the remote user that has been authenticated
       * for this Request.
       */
      public String getRemoteUser() {
  
          if (userPrincipal != null) {
              return (userPrincipal.getName());
          } else {
              return (null);
          }
  
      }
  
  
      /**
       * Return the session identifier included in this request, if any.
       */
      public String getRequestedSessionId() {
          return (requestedSessionId);
      }
  
  
      /**
       * Return the request URI for this request.
       */
      public String getRequestURI() {
          return coyoteRequest.requestURI().toString();
      }
  
  
      /**
       * Reconstructs the URL the client used to make the request.
       * The returned URL contains a protocol, server name, port
       * number, and server path, but it does not include query
       * string parameters.
       * <p>
       * Because this method returns a <code>StringBuffer</code>,
       * not a <code>String</code>, you can modify the URL easily,
       * for example, to append query parameters.
       * <p>
       * This method is useful for creating redirect messages and
       * for reporting errors.
       *
       * @return A <code>StringBuffer</code> object containing the
       *  reconstructed URL
       */
      public StringBuffer getRequestURL() {
  
          StringBuffer url = new StringBuffer();
          String scheme = getScheme();
          int port = getServerPort();
          if (port < 0)
              port = 80; // Work around java.net.URL bug
  
          url.append(scheme);
          url.append("://");
          url.append(getServerName());
          if ((scheme.equals("http") && (port != 80))
              || (scheme.equals("https") && (port != 443))) {
              url.append(':');
              url.append(port);
          }
          url.append(getRequestURI());
  
          return (url);
  
      }
  
  
      /**
       * Return the portion of the request URI used to select the servlet
       * that will process this request.
       */
      public String getServletPath() {
          return (servletPath);
      }
  
  
      /**
       * Return the session associated with this Request, creating one
       * if necessary.
       */
      public HttpSession getSession() {
          return (getSession(true));
      }
  
  
      /**
       * Return the session associated with this Request, creating one
       * if necessary and requested.
       *
       * @param create Create a new session if one does not exist
       */
      public HttpSession getSession(boolean create) {
  
          if (System.getSecurityManager() != null) {
              PrivilegedGetSession dp = new PrivilegedGetSession(create);
              return (HttpSession) AccessController.doPrivileged(dp);
          }
          return doGetSession(create);
  
      }
  
  
      /**
       * Return <code>true</code> if the session identifier included in this
       * request came from a cookie.
       */
      public boolean isRequestedSessionIdFromCookie() {
  
          if (requestedSessionId != null)
              return (requestedSessionCookie);
          else
              return (false);
  
      }
  
  
      /**
       * Return <code>true</code> if the session identifier included in this
       * request came from the request URI.
       */
      public boolean isRequestedSessionIdFromURL() {
  
          if (requestedSessionId != null)
              return (requestedSessionURL);
          else
              return (false);
  
      }
  
  
      /**
       * Return <code>true</code> if the session identifier included in this
       * request came from the request URI.
       *
       * @deprecated As of Version 2.1 of the Java Servlet API, use
       *  <code>isRequestedSessionIdFromURL()</code> instead.
       */
      public boolean isRequestedSessionIdFromUrl() {
          return (isRequestedSessionIdFromURL());
      }
  
  
      /**
       * Return <code>true</code> if the session identifier included in this
       * request identifies a valid session.
       */
      public boolean isRequestedSessionIdValid() {
  
          if (requestedSessionId == null)
              return (false);
          if (context == null)
              return (false);
          Manager manager = context.getManager();
          if (manager == null)
              return (false);
          Session session = null;
          try {
              session = manager.findSession(requestedSessionId);
          } catch (IOException e) {
              session = null;
          }
          if ((session != null) && session.isValid())
              return (true);
          else
              return (false);
  
      }
  
  
      /**
       * Return <code>true</code> if the authenticated user principal
       * possesses the specified role name.
       *
       * @param role Role name to be validated
       */
      public boolean isUserInRole(String role) {
  
          // Have we got an authenticated principal at all?
          if (userPrincipal == null)
              return (false);
  
          // Identify the Realm we will use for checking role assignmenets
          if (context == null)
              return (false);
          Realm realm = context.getRealm();
          if (realm == null)
              return (false);
  
          // Check for a role alias defined in a <security-role-ref> element
          if (wrapper != null) {
              String realRole = wrapper.findSecurityReference(role);
              if ((realRole != null) &&
                  realm.hasRole(userPrincipal, realRole))
                  return (true);
          }
  
          // Check for a role defined directly as a <security-role>
          return (realm.hasRole(userPrincipal, role));
  
      }
  
  
      /**
       * Return the principal that has been authenticated for this Request.
       */
      public Principal getUserPrincipal() {
          return (userPrincipal);
      }
  
  
      // ------------------------------------------------------ Protected Methods
  
  
      protected HttpSession doGetSession(boolean create) {
  
          // There cannot be a session if no context has been assigned yet
          if (context == null)
              return (null);
  
          // Return the current session if it exists and is valid
          if ((session != null) && !session.isValid())
              session = null;
          if (session != null)
              return (session.getSession());
  
          // Return the requested session if it exists and is valid
          Manager manager = null;
          if (context != null)
              manager = context.getManager();
          if (manager == null)
              return (null);      // Sessions are not supported
          if (requestedSessionId != null) {
              try {
                  session = manager.findSession(requestedSessionId);
              } catch (IOException e) {
                  session = null;
              }
              if ((session != null) && !session.isValid())
                  session = null;
              if (session != null) {
                  return (session.getSession());
              }
          }
  
          // Create a new session if requested and the response is not committed
          if (!create)
              return (null);
          if ((context != null) && (response != null) &&
              context.getCookies() &&
              response.getResponse().isCommitted()) {
              throw new IllegalStateException
                (sm.getString("coyoteRequest.sessionCreateCommitted"));
          }
  
          session = manager.createSession();
  
          // Creating a new session cookie based on that session
          if ((session != null) && (getContext() != null)
              && getContext().getCookies()) {
              Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,
                                         session.getId());
              cookie.setMaxAge(-1);
              String contextPath = null;
              if (context != null)
                  contextPath = context.getPath();
              if ((contextPath != null) && (contextPath.length() > 0))
                  cookie.setPath(contextPath);
              else
                  cookie.setPath("/");
              if (isSecure())
                  cookie.setSecure(true);
              ((HttpServletResponse) response).addCookie(cookie);
          }
  
          if (session != null)
              return (session.getSession());
          else
              return (null);
  
      }
  
  
      /**
       * Parse request parameters.
       */
      protected void parseRequestParameters() {
  
          requestParametersParsed = true;
  
          Parameters parameters = coyoteRequest.getParameters();
  
          String enc = coyoteRequest.getCharacterEncoding();
          if (enc != null) {
              parameters.setEncoding(enc);
          } else {
              parameters.setEncoding
                  (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
          }
  
          parameters.handleQueryParameters();
  
          if (usingInputStream || usingReader)
              return;
  
          if (!getMethod().equalsIgnoreCase("POST"))
              return;
  
          String contentType = getContentType();
          if (contentType == null)
              contentType = "";
          int semicolon = contentType.indexOf(';');
          if (semicolon >= 0) {
              contentType = contentType.substring(0, semicolon).trim();
          } else {
              contentType = contentType.trim();
          }
          if (!("application/x-www-form-urlencoded".equals(contentType)))
              return;
  
          int len = getContentLength();
  
          if (len > 0) {
              try {
                  byte[] formData = null;
                  if (len < CACHED_POST_LEN) {
                      if (postData == null)
                          postData = new byte[CACHED_POST_LEN];
                      formData = postData;
                  } else {
                      formData = new byte[len];
                  }
                  readPostBody(formData, len);
                  parameters.processParameters(formData, 0, len);
              } catch (Throwable t) {
                  ; // Ignore
              }
          }
  
      }
  
  
      /**
       * Read post body in an array.
       */
      protected int readPostBody(byte body[], int len)
          throws IOException {
  
          int offset = 0;
          do {
              int inputLen = getStream().read(body, offset, len - offset);
              if (inputLen <= 0) {
                  return offset;
              }
              offset += inputLen;
          } while ((len - offset) > 0);
          return len;
  
      }
  
  
      /**
       * Parse request locales.
       */
      protected void parseLocales() {
  
          localesParsed = true;
  
          Enumeration values = getHeaders("accept-language");
  
          while (values.hasMoreElements()) {
              String value = values.nextElement().toString();
              parseLocalesHeader(value);
          }
  
      }
  
  
      /**
       * Parse accept-language header value.
       */
      protected void parseLocalesHeader(String value) {
  
          // Store the accumulated languages that have been requested in
          // a local collection, sorted by the quality value (so we can
          // add Locales in descending order).  The values will be ArrayLists
          // containing the corresponding Locales to be added
          TreeMap locales = new TreeMap();
  
          // Preprocess the value to remove all whitespace
          int white = value.indexOf(' ');
          if (white < 0)
              white = value.indexOf('\t');
          if (white >= 0) {
              StringBuffer sb = new StringBuffer();
              int len = value.length();
              for (int i = 0; i < len; i++) {
                  char ch = value.charAt(i);
                  if ((ch != ' ') && (ch != '\t'))
                      sb.append(ch);
              }
              value = sb.toString();
          }
  
          // Process each comma-delimited language specification
          parser.setString(value);        // ASSERT: parser is available to us
          int length = parser.getLength();
          while (true) {
  
              // Extract the next comma-delimited entry
              int start = parser.getIndex();
              if (start >= length)
                  break;
              int end = parser.findChar(',');
              String entry = parser.extract(start, end).trim();
              parser.advance();   // For the following entry
  
              // Extract the quality factor for this entry
              double quality = 1.0;
              int semi = entry.indexOf(";q=");
              if (semi >= 0) {
                  try {
                      quality = Double.parseDouble(entry.substring(semi + 3));
                  } catch (NumberFormatException e) {
                      quality = 0.0;
                  }
                  entry = entry.substring(0, semi);
              }
  
              // Skip entries we are not going to keep track of
              if (quality < 0.00005)
                  continue;       // Zero (or effectively zero) quality factors
              if ("*".equals(entry))
                  continue;       // FIXME - "*" entries are not handled
  
              // Extract the language and country for this entry
              String language = null;
              String country = null;
              String variant = null;
              int dash = entry.indexOf('-');
              if (dash < 0) {
                  language = entry;
                  country = "";
                  variant = "";
              } else {
                  language = entry.substring(0, dash);
                  country = entry.substring(dash + 1);
                  int vDash = country.indexOf('-');
                  if (vDash > 0) {
                      String cTemp = country.substring(0, vDash);
                      variant = country.substring(vDash + 1);
                      country = cTemp;
                  } else {
                      variant = "";
                  }
              }
  
              // Add a new Locale to the list of Locales for this quality level
              Locale locale = new Locale(language, country, variant);
              Double key = new Double(-quality);  // Reverse the order
              ArrayList values = (ArrayList) locales.get(key);
              if (values == null) {
                  values = new ArrayList();
                  locales.put(key, values);
              }
              values.add(locale);
  
          }
  
          // Process the quality values in highest->lowest order (due to
          // negating the Double value when creating the key)
          Iterator keys = locales.keySet().iterator();
          while (keys.hasNext()) {
              Double key = (Double) keys.next();
              ArrayList list = (ArrayList) locales.get(key);
              Iterator values = list.iterator();
              while (values.hasNext()) {
                  Locale locale = (Locale) values.next();
                  addLocale(locale);
              }
          }
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteRequestFacade.java
  
  Index: CoyoteRequestFacade.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteRequestFacade.java,v 1.1 2002/08/04 19:39:49 patrickl Exp $
   * $Revision: 1.1 $
   * $Date: 2002/08/04 19:39:49 $
   *
   * ====================================================================
   *
   * 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.coyote.tomcat5;
  
  
  import java.io.InputStream;
  import java.io.BufferedReader;
  import java.io.IOException;
  import java.util.Enumeration;
  import java.util.Map;
  import java.util.Locale;
  import java.net.Socket;
  import javax.servlet.ServletException;
  import javax.servlet.ServletInputStream;
  import javax.servlet.ServletRequest;
  import javax.servlet.RequestDispatcher;
  import javax.servlet.http.Cookie;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpSession;
  
  import org.apache.catalina.connector.RequestFacade;
  import org.apache.catalina.session.StandardSessionFacade;
  
  
  /**
   * Facade class that wraps a Coyote request object.  
   * All methods are delegated to the wrapped request.
   *
   * @author Craig R. McClanahan
   * @author Remy Maucherat
   * @version $Revision: 1.1 $ $Date: 2002/08/04 19:39:49 $
   */
  
  public class CoyoteRequestFacade 
      extends RequestFacade
      implements HttpServletRequest {
  
  
      // ----------------------------------------------------------- Constructors
  
  
      /**
       * Construct a wrapper for the specified request.
       *
       * @param request The request to be wrapped
       */
      public CoyoteRequestFacade(CoyoteRequest request) {
  
          super(request);
          this.request = request;
  
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The wrapped request.
       */
      protected CoyoteRequest request = null;
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Clear facade.
       */
      public void clear() {
          request = null;
      }
  
  
      // ------------------------------------------------- ServletRequest Methods
  
  
      public Object getAttribute(String name) {
          return request.getAttribute(name);
      }
  
  
      public Enumeration getAttributeNames() {
          return request.getAttributeNames();
      }
  
  
      public String getCharacterEncoding() {
          return request.getCharacterEncoding();
      }
  
  
      public void setCharacterEncoding(String env)
          throws java.io.UnsupportedEncodingException {
          request.setCharacterEncoding(env);
      }
  
  
      public int getContentLength() {
          return request.getContentLength();
      }
  
  
      public String getContentType() {
          return request.getContentType();
      }
  
  
      public ServletInputStream getInputStream()
          throws IOException {
          return request.getInputStream();
      }
  
  
      public String getParameter(String name) {
          return request.getParameter(name);
      }
  
  
      public Enumeration getParameterNames() {
          return request.getParameterNames();
      }
  
  
      public String[] getParameterValues(String name) {
          return request.getParameterValues(name);
      }
  
  
      public Map getParameterMap() {
          return request.getParameterMap();
      }
  
  
      public String getProtocol() {
          return request.getProtocol();
      }
  
  
      public String getScheme() {
          return request.getScheme();
      }
  
  
      public String getServerName() {
          return request.getServerName();
      }
  
  
      public int getServerPort() {
          return request.getServerPort();
      }
  
  
      public BufferedReader getReader()
          throws IOException {
          return request.getReader();
      }
  
  
      public String getRemoteAddr() {
          return request.getRemoteAddr();
      }
  
  
      public String getRemoteHost() {
          return request.getRemoteHost();
      }
  
  
      public void setAttribute(String name, Object o) {
          request.setAttribute(name, o);
      }
  
  
      public void removeAttribute(String name) {
          request.removeAttribute(name);
      }
  
  
      public Locale getLocale() {
          return request.getLocale();
      }
  
  
      public Enumeration getLocales() {
          return request.getLocales();
      }
  
  
      public boolean isSecure() {
          return request.isSecure();
      }
  
  
      public RequestDispatcher getRequestDispatcher(String path) {
          // TODO : Facade !!
          return request.getRequestDispatcher(path);
      }
  
  
      public String getRealPath(String path) {
          return request.getRealPath(path);
      }
  
  
      public String getAuthType() {
          return request.getAuthType();
      }
  
  
      public Cookie[] getCookies() {
          return request.getCookies();
      }
  
  
      public long getDateHeader(String name) {
          return request.getDateHeader(name);
      }
  
  
      public String getHeader(String name) {
          return request.getHeader(name);
      }
  
  
      public Enumeration getHeaders(String name) {
          return request.getHeaders(name);
      }
  
  
      public Enumeration getHeaderNames() {
          return request.getHeaderNames();
      }
  
  
      public int getIntHeader(String name) {
          return request.getIntHeader(name);
      }
  
  
      public String getMethod() {
          return request.getMethod();
      }
  
  
      public String getPathInfo() {
          return request.getPathInfo();
      }
  
  
      public String getPathTranslated() {
          return request.getPathTranslated();
      }
  
  
      public String getContextPath() {
          return request.getContextPath();
      }
  
  
      public String getQueryString() {
          return request.getQueryString();
      }
  
  
      public String getRemoteUser() {
          return request.getRemoteUser();
      }
  
  
      public boolean isUserInRole(String role) {
          return request.isUserInRole(role);
      }
  
  
      public java.security.Principal getUserPrincipal() {
          return request.getUserPrincipal();
      }
  
  
      public String getRequestedSessionId() {
          return request.getRequestedSessionId();
      }
  
  
      public String getRequestURI() {
          return request.getRequestURI();
      }
  
  
      public StringBuffer getRequestURL() {
          return request.getRequestURL();
      }
  
  
      public String getServletPath() {
          return request.getServletPath();
      }
  
  
      public HttpSession getSession(boolean create) {
          HttpSession session =
              request.getSession(create);
          if (session == null)
              return null;
          else
              return new StandardSessionFacade(session);
      }
  
  
      public HttpSession getSession() {
          return getSession(true);
      }
  
  
      public boolean isRequestedSessionIdValid() {
          return request.isRequestedSessionIdValid();
      }
  
  
      public boolean isRequestedSessionIdFromCookie() {
          return request.isRequestedSessionIdFromCookie();
      }
  
  
      public boolean isRequestedSessionIdFromURL() {
          return request.isRequestedSessionIdFromURL();
      }
  
  
      public boolean isRequestedSessionIdFromUrl() {
          return request.isRequestedSessionIdFromURL();
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteResponse.java
  
  Index: CoyoteResponse.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteResponse.java,v 1.1 2002/08/04 19:39:49 patrickl Exp $
   * $Revision: 1.1 $
   * $Date: 2002/08/04 19:39:49 $
   *
   * ====================================================================
   *
   * 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.coyote.tomcat5;
  
  
  import java.io.IOException;
  import java.io.OutputStream;
  import java.io.PrintWriter;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.text.SimpleDateFormat;
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.Enumeration;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Locale;
  import java.util.Map;
  import java.util.TimeZone;
  
  import javax.servlet.ServletContext;
  import javax.servlet.ServletException;
  import javax.servlet.ServletOutputStream;
  import javax.servlet.ServletResponse;
  import javax.servlet.http.Cookie;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.http.HttpSession;
  import javax.servlet.http.HttpUtils;
  
  import org.apache.tomcat.util.buf.CharChunk;
  import org.apache.tomcat.util.buf.UEncoder;
  import org.apache.tomcat.util.http.MimeHeaders;
  import org.apache.tomcat.util.http.ServerCookie;
  
  import org.apache.coyote.Response;
  
  import org.apache.catalina.Connector;
  import org.apache.catalina.Context;
  import org.apache.catalina.Globals;
  import org.apache.catalina.HttpResponse;
  import org.apache.catalina.Manager;
  import org.apache.catalina.Realm;
  import org.apache.catalina.Session;
  import org.apache.catalina.Wrapper;
  import org.apache.catalina.util.CharsetMapper;
  import org.apache.catalina.util.RequestUtil;
  import org.apache.catalina.util.StringManager;
  
  
  /**
   * Wrapper object for the Coyote response.
   *
   * @author Remy Maucherat
   * @author Craig R. McClanahan
   * @version $Revision: 1.1 $ $Date: 2002/08/04 19:39:49 $
   */
  
  public class CoyoteResponse
      implements HttpResponse, HttpServletResponse {
  
  
      // ----------------------------------------------------------- Constructors
  
  
      public CoyoteResponse() {
  
          format.setTimeZone(TimeZone.getTimeZone("GMT"));
          urlEncoder.addSafeCharacter('/');
  
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The date format we will use for creating date headers.
       */
      protected final SimpleDateFormat format =
          new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
  
  
      /**
       * Descriptive information about this Response implementation.
       */
      protected static final String info =
          "org.apache.coyote.tomcat5.CoyoteResponse/1.0";
  
  
      /**
       * The string manager for this package.
       */
      protected static StringManager sm =
          StringManager.getManager(Constants.Package);
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Associated Catalina connector.
       */
      protected Connector connector;
  
      /**
       * Return the Connector through which this Request was received.
       */
      public Connector getConnector() {
          return (this.connector);
      }
  
      /**
       * Set the Connector through which this Request was received.
       *
       * @param connector The new connector
       */
      public void setConnector(Connector connector) {
          this.connector = connector;
      }
  
  
      /**
       * Coyote response.
       */
      protected Response coyoteResponse;
  
      /**
       * Set the Coyote response.
       * 
       * @param response The Coyote response
       */
      public void setCoyoteResponse(Response coyoteResponse) {
          this.coyoteResponse = coyoteResponse;
          outputBuffer.setResponse(coyoteResponse);
      }
  
      /**
       * Get the Coyote response.
       */
      public Response getCoyoteResponse() {
          return (coyoteResponse);
      }
  
  
      /**
       * The Context within which this Request is being processed.
       */
      protected Context context = null;
  
      /**
       * Return the Context within which this Request is being processed.
       */
      public Context getContext() {
          return (this.context);
      }
  
      /**
       * Set the Context within which this Request is being processed.  This
       * must be called as soon as the appropriate Context is identified, because
       * it identifies the value to be returned by <code>getContextPath()</code>,
       * and thus enables parsing of the request URI.
       *
       * @param context The newly associated Context
       */
      public void setContext(Context context) {
          this.context = context;
      }
  
  
      /**
       * The associated output buffer.
       */
      protected OutputBuffer outputBuffer = new OutputBuffer();
  
  
      /**
       * The associated output stream.
       */
      protected CoyoteOutputStream outputStream = 
          new CoyoteOutputStream(outputBuffer);
  
  
      /**
       * The associated writer.
       */
      protected CoyoteWriter writer = new CoyoteWriter(outputBuffer);
  
  
      /**
       * The application commit flag.
       */
      protected boolean appCommitted = false;
  
  
      /**
       * The included flag.
       */
      protected boolean included = false;
  
  
      /**
       * The error flag.
       */
      protected boolean error = false;
  
  
      /**
       * The set of Cookies associated with this Response.
       */
      protected ArrayList cookies = new ArrayList();
  
  
      /**
       * Using output stream flag.
       */
      protected boolean usingOutputStream = false;
  
  
      /**
       * Using writer flag.
       */
      protected boolean usingWriter = false;
  
  
      /**
       * URL encoder.
       */
      protected UEncoder urlEncoder = new UEncoder();
  
  
      /**
       * Recyclable buffer to hold the redirect URL.
       */
      protected CharChunk redirectURLCC = new CharChunk();
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Release all object references, and initialize instance variables, in
       * preparation for reuse of this object.
       */
      public void recycle() {
  
          outputBuffer.recycle();
          usingOutputStream = false;
          usingWriter = false;
          appCommitted = false;
          included = false;
          error = false;
          cookies.clear();
  
          if (facade != null) {
              facade.clear();
              facade = null;
          }
  
      }
  
  
      // ------------------------------------------------------- Response Methods
  
  
      /**
       * Return the number of bytes actually written to the output stream.
       */
      public int getContentCount() {
          return outputBuffer.getBytesWritten();
      }
  
  
      /**
       * Set the application commit flag.
       * 
       * @param appCommitted The new application committed flag value
       */
      public void setAppCommitted(boolean appCommitted) {
          this.appCommitted = appCommitted;
      }
  
  
      /**
       * Application commit flag accessor.
       */
      public boolean isAppCommitted() {
          return (this.appCommitted || isCommitted());
      }
  
  
      /**
       * Return the "processing inside an include" flag.
       */
      public boolean getIncluded() {
          return included;
      }
  
  
      /**
       * Set the "processing inside an include" flag.
       *
       * @param included <code>true</code> if we are currently inside a
       *  RequestDispatcher.include(), else <code>false</code>
       */
      public void setIncluded(boolean included) {
          this.included = included;
      }
  
  
      /**
       * Return descriptive information about this Response implementation and
       * the corresponding version number, in the format
       * <code>&lt;description&gt;/&lt;version&gt;</code>.
       */
      public String getInfo() {
          return (info);
      }
  
  
      /**
       * The request with which this response is associated.
       */
      protected CoyoteRequest request = null;
  
      /**
       * Return the Request with which this Response is associated.
       */
      public org.apache.catalina.Request getRequest() {
          return (this.request);
      }
  
      /**
       * Set the Request with which this Response is associated.
       *
       * @param request The new associated request
       */
      public void setRequest(org.apache.catalina.Request request) {
          this.request = (CoyoteRequest) request;
      }
  
  
      /**
       * The facade associated with this response.
       */
      protected CoyoteResponseFacade facade = null;
  
      /**
       * Return the <code>ServletResponse</code> for which this object
       * is the facade.
       */
      public ServletResponse getResponse() {
          if (facade == null) {
              facade = new CoyoteResponseFacade(this);
          }
          return (facade);
      }
  
  
      /**
       * Return the output stream associated with this Response.
       */
      public OutputStream getStream() {
          return outputStream;
      }
  
  
      /**
       * Set the output stream associated with this Response.
       *
       * @param stream The new output stream
       */
      public void setStream(OutputStream stream) {
          // This method is evil
      }
  
  
      /**
       * Set the suspended flag.
       * 
       * @param suspended The new suspended flag value
       */
      public void setSuspended(boolean suspended) {
          outputBuffer.setSuspended(suspended);
      }
  
  
      /**
       * Suspended flag accessor.
       */
      public boolean isSuspended() {
          return outputBuffer.isSuspended();
      }
  
  
      /**
       * Set the error flag.
       */
      public void setError() {
          error = true;
      }
  
  
      /**
       * Error flag accessor.
       */
      public boolean isError() {
          return error;
      }
  
  
      /**
       * Create and return a ServletOutputStream to write the content
       * associated with this Response.
       *
       * @exception IOException if an input/output error occurs
       */
      public ServletOutputStream createOutputStream() 
          throws IOException {
          // Probably useless
          return outputStream;
      }
  
  
      /**
       * Perform whatever actions are required to flush and close the output
       * stream or writer, in a single operation.
       *
       * @exception IOException if an input/output error occurs
       */
      public void finishResponse() 
          throws IOException {
          // Writing leftover bytes
          try {
              outputBuffer.close();
          } catch(IOException e) {
  	    ;
          } catch(Throwable t) {
  	    t.printStackTrace();
          }
          coyoteResponse.finish();
      }
  
  
      /**
       * Return the content length that was set or calculated for this Response.
       */
      public int getContentLength() {
          return (coyoteResponse.getContentLength());
      }
  
  
      /**
       * Return the content type that was set or calculated for this response,
       * or <code>null</code> if no content type was set.
       */
      public String getContentType() {
          return (coyoteResponse.getContentType());
      }
  
  
      /**
       * Return a PrintWriter that can be used to render error messages,
       * regardless of whether a stream or writer has already been acquired.
       *
       * @return Writer which can be used for error reports. If the response is
       * not an error report returned using sendError or triggered by an
       * unexpected exception thrown during the servlet processing
       * (and only in that case), null will be returned if the response stream
       * has already been used.
       */
      public PrintWriter getReporter() {
          if (outputBuffer.isNew()) {
              return writer;
          } else {
              return null;
          }
      }
  
  
      // ------------------------------------------------ ServletResponse Methods
  
  
      /**
       * Flush the buffer and commit this response.
       *
       * @exception IOException if an input/output error occurs
       */
      public void flushBuffer() 
          throws IOException {
          outputBuffer.flush();
      }
  
  
      /**
       * Return the actual buffer size used for this Response.
       */
      public int getBufferSize() {
          return outputBuffer.getBufferSize();
      }
  
  
      /**
       * Return the character encoding used for this Response.
       */
      public String getCharacterEncoding() {
          return (coyoteResponse.getCharacterEncoding());
      }
  
  
      /**
       * Return the servlet output stream associated with this Response.
       *
       * @exception IllegalStateException if <code>getWriter</code> has
       *  already been called for this response
       * @exception IOException if an input/output error occurs
       */
      public ServletOutputStream getOutputStream() 
          throws IOException {
  
          if (usingWriter)
              throw new IllegalStateException
                  (sm.getString("coyoteResponse.getOutputStream.ise"));
  
          usingOutputStream = true;
          return outputStream;
  
      }
  
  
      /**
       * Return the Locale assigned to this response.
       */
      public Locale getLocale() {
          return (coyoteResponse.getLocale());
      }
  
  
      /**
       * Return the writer associated with this Response.
       *
       * @exception IllegalStateException if <code>getOutputStream</code> has
       *  already been called for this response
       * @exception IOException if an input/output error occurs
       */
      public PrintWriter getWriter() 
          throws IOException {
  
          if (usingOutputStream)
              throw new IllegalStateException
                  (sm.getString("coyoteResponse.getWriter.ise"));
  
          usingWriter = true;
          return writer;
  
      }
  
  
      /**
       * Has the output of this response already been committed?
       */
      public boolean isCommitted() {
          return (coyoteResponse.isCommitted());
      }
  
  
      /**
       * Clear any content written to the buffer.
       *
       * @exception IllegalStateException if this response has already
       *  been committed
       */
      public void reset() {
  
          if (included)
              return;     // Ignore any call from an included servlet
  
          coyoteResponse.reset();
          outputBuffer.reset();
  
      }
  
  
      /**
       * Reset the data buffer but not any status or header information.
       *
       * @exception IllegalStateException if the response has already
       *  been committed
       */
      public void resetBuffer() {
  
          if (isCommitted())
              throw new IllegalStateException
                  (sm.getString("coyoteResponse.resetBuffer.ise"));
  
          outputBuffer.reset();
  
      }
  
  
      /**
       * Set the buffer size to be used for this Response.
       *
       * @param size The new buffer size
       *
       * @exception IllegalStateException if this method is called after
       *  output has been committed for this response
       */
      public void setBufferSize(int size) {
  
          if (isCommitted() || !outputBuffer.isNew())
              throw new IllegalStateException
                  (sm.getString("coyoteResponse.setBufferSize.ise"));
  
          outputBuffer.setBufferSize(size);
  
      }
  
  
      /**
       * Set the content length (in bytes) for this Response.
       *
       * @param length The new content length
       */
      public void setContentLength(int length) {
  
          if (isCommitted())
              return;
  
          // Ignore any call from an included servlet
          if (included)
              return;
  
          coyoteResponse.setContentLength(length);
  
      }
  
  
      /**
       * Set the content type for this Response.
       *
       * @param type The new content type
       */
      public void setContentType(String type) {
  
          if (isCommitted())
              return;
  
          // Ignore any call from an included servlet
          if (included)
              return;
  
          coyoteResponse.setContentType(type);
  
      }
  
  
      /*
       * Overrides the name of the character encoding used in the body
       * of the request. This method must be called prior to reading
       * request parameters or reading input using getReader().
       *
       * @param charset String containing the name of the chararacter encoding.
       */
      public void setCharacterEncoding(String charset) {
  
          if (isCommitted())
              return;
  
          if (included)
              return;     // Ignore any call from an included servlet
  
  	coyoteResponse.setCharacterEncoding(charset);
      }
  
      /**
       * Set the Locale that is appropriate for this response, including
       * setting the appropriate character encoding.
       *
       * @param locale The new locale
       */
      public void setLocale(Locale locale) {
  
          if (isCommitted())
              return;
  
          // Ignore any call from an included servlet
          if (included)
              return;
  
          coyoteResponse.setLocale(locale);
  
      }
  
  
      // --------------------------------------------------- HttpResponse Methods
  
  
      /**
       * Return an array of all cookies set for this response, or
       * a zero-length array if no cookies have been set.
       */
      public Cookie[] getCookies() {
          return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()]));
      }
  
  
      /**
       * Return the value for the specified header, or <code>null</code> if this
       * header has not been set.  If more than one value was added for this
       * name, only the first is returned; use getHeaderValues() to retrieve all
       * of them.
       *
       * @param name Header name to look up
       */
      public String getHeader(String name) {
          return coyoteResponse.getMimeHeaders().getHeader(name);
      }
  
  
      /**
       * Return an array of all the header names set for this response, or
       * a zero-length array if no headers have been set.
       */
      public String[] getHeaderNames() {
  
          MimeHeaders headers = coyoteResponse.getMimeHeaders();
          int n = headers.size();
          String[] result = new String[n];
          for (int i = 0; i < n; i++) {
              result[i] = headers.getName(i).toString();
          }
          return result;
  
      }
  
  
      /**
       * Return an array of all the header values associated with the
       * specified header name, or an zero-length array if there are no such
       * header values.
       *
       * @param name Header name to look up
       */
      public String[] getHeaderValues(String name) {
  
          MimeHeaders headers = coyoteResponse.getMimeHeaders();
          int n = headers.size();
          String[] result = new String[n];
          for (int i = 0; i < n; i++) {
              result[i] = headers.getValue(i).toString();
          }
          return result;
  
      }
  
  
      /**
       * Return the error message that was set with <code>sendError()</code>
       * for this Response.
       */
      public String getMessage() {
          return coyoteResponse.getMessage();
      }
  
  
      /**
       * Return the HTTP status code associated with this Response.
       */
      public int getStatus() {
          return coyoteResponse.getStatus();
      }
  
  
      /**
       * Reset this response, and specify the values for the HTTP status code
       * and corresponding message.
       *
       * @exception IllegalStateException if this response has already been
       *  committed
       */
      public void reset(int status, String message) {
          reset();
          setStatus(status, message);
      }
  
  
      // -------------------------------------------- HttpServletResponse Methods
  
  
      /**
       * Add the specified Cookie to those that will be included with
       * this Response.
       *
       * @param cookie Cookie to be added
       */
      public void addCookie(Cookie cookie) {
  
          if (isCommitted())
              return;
  
          // Ignore any call from an included servlet
          if (included)
              return;
  
          cookies.add(cookie);
  
          StringBuffer sb = new StringBuffer();
          ServerCookie.appendCookieValue
              (sb, cookie.getVersion(), cookie.getName(), cookie.getValue(),
               cookie.getPath(), cookie.getDomain(), cookie.getComment(), 
               cookie.getMaxAge(), cookie.getSecure());
          // the header name is Set-Cookie for both "old" and v.1 ( RFC2109 )
          // RFC2965 is not supported by browsers and the Servlet spec
          // asks for 2109.
          addHeader("Set-Cookie", sb.toString());
  
      }
  
  
      /**
       * Add the specified date header to the specified value.
       *
       * @param name Name of the header to set
       * @param value Date value to be set
       */
      public void addDateHeader(String name, long value) {
  
          if (isCommitted())
              return;
  
          // Ignore any call from an included servlet
          if (included)
              return;
  
          addHeader(name, format.format(new Date(value)));
  
      }
  
  
      /**
       * Add the specified header to the specified value.
       *
       * @param name Name of the header to set
       * @param value Value to be set
       */
      public void addHeader(String name, String value) {
  
          if (isCommitted())
              return;
  
          // Ignore any call from an included servlet
          if (included)
              return;
  
          coyoteResponse.addHeader(name, value);
  
      }
  
  
      /**
       * Add the specified integer header to the specified value.
       *
       * @param name Name of the header to set
       * @param value Integer value to be set
       */
      public void addIntHeader(String name, int value) {
  
          if (isCommitted())
              return;
  
          // Ignore any call from an included servlet
          if (included)
              return;
  
          addHeader(name, "" + value);
  
      }
  
  
      /**
       * Has the specified header been set already in this response?
       *
       * @param name Name of the header to check
       */
      public boolean containsHeader(String name) {
          return coyoteResponse.containsHeader(name);
      }
  
  
      /**
       * Encode the session identifier associated with this response
       * into the specified redirect URL, if necessary.
       *
       * @param url URL to be encoded
       */
      public String encodeRedirectURL(String url) {
  
          if (isEncodeable(toAbsolute(url))) {
              HttpServletRequest hreq =
                  (HttpServletRequest) request.getRequest();
              return (toEncoded(url, hreq.getSession().getId()));
          } else {
              return (url);
          }
  
      }
  
  
      /**
       * Encode the session identifier associated with this response
       * into the specified redirect URL, if necessary.
       *
       * @param url URL to be encoded
       *
       * @deprecated As of Version 2.1 of the Java Servlet API, use
       *  <code>encodeRedirectURL()</code> instead.
       */
      public String encodeRedirectUrl(String url) {
          return (encodeRedirectURL(url));
      }
  
  
      /**
       * Encode the session identifier associated with this response
       * into the specified URL, if necessary.
       *
       * @param url URL to be encoded
       */
      public String encodeURL(String url) {
  
          if (isEncodeable(toAbsolute(url))) {
              HttpServletRequest hreq =
                  (HttpServletRequest) request.getRequest();
              return (toEncoded(url, hreq.getSession().getId()));
          } else {
              return (url);
          }
  
      }
  
  
      /**
       * Encode the session identifier associated with this response
       * into the specified URL, if necessary.
       *
       * @param url URL to be encoded
       *
       * @deprecated As of Version 2.1 of the Java Servlet API, use
       *  <code>encodeURL()</code> instead.
       */
      public String encodeUrl(String url) {
          return (encodeURL(url));
      }
  
  
      /**
       * Send an acknowledgment of a request.
       * 
       * @exception IOException if an input/output error occurs
       */
      public void sendAcknowledgement()
          throws IOException {
  
          if (isCommitted())
              return;
  
          // Ignore any call from an included servlet
          if (included)
              return; 
  
          coyoteResponse.acknowledge();
  
      }
  
  
      /**
       * Send an error response with the specified status and a
       * default message.
       *
       * @param status HTTP status code to send
       *
       * @exception IllegalStateException if this response has
       *  already been committed
       * @exception IOException if an input/output error occurs
       */
      public void sendError(int status) 
          throws IOException {
          sendError(status, null);
      }
  
  
      /**
       * Send an error response with the specified status and message.
       *
       * @param status HTTP status code to send
       * @param message Corresponding message to send
       *
       * @exception IllegalStateException if this response has
       *  already been committed
       * @exception IOException if an input/output error occurs
       */
      public void sendError(int status, String message) 
          throws IOException {
  
          if (isCommitted())
              throw new IllegalStateException
                  (sm.getString("coyoteResponse.sendError.ise"));
  
          // Ignore any call from an included servlet
          if (included)
              return; 
  
          setError();
  
          coyoteResponse.setStatus(status);
          coyoteResponse.setMessage(message);
  
          // Clear any data content that has been buffered
          resetBuffer();
  
          // Cause the response to be finished (from the application perspective)
          setSuspended(true);
  
      }
  
  
      /**
       * Send a temporary redirect to the specified redirect location URL.
       *
       * @param location Location URL to redirect to
       *
       * @exception IllegalStateException if this response has
       *  already been committed
       * @exception IOException if an input/output error occurs
       */
      public void sendRedirect(String location) 
          throws IOException {
  
          if (isCommitted())
              throw new IllegalStateException
                  (sm.getString("coyoteResponse.sendRedirect.ise"));
  
          // Ignore any call from an included servlet
          if (included)
              return; 
  
          // Clear any data content that has been buffered
          resetBuffer();
  
          // Generate a temporary redirect to the specified location
          try {
              String absolute = toAbsolute(location);
              setStatus(SC_MOVED_TEMPORARILY);
              setHeader("Location", absolute);
          } catch (IllegalArgumentException e) {
              setStatus(SC_NOT_FOUND);
          }
  
          // Cause the response to be finished (from the application perspective)
          setSuspended(true);
  
      }
  
  
      /**
       * Set the specified date header to the specified value.
       *
       * @param name Name of the header to set
       * @param value Date value to be set
       */
      public void setDateHeader(String name, long value) {
  
          if (isCommitted())
              return;
  
          // Ignore any call from an included servlet
          if (included)
              return;
  
          setHeader(name, format.format(new Date(value)));
  
      }
  
  
      /**
       * Set the specified header to the specified value.
       *
       * @param name Name of the header to set
       * @param value Value to be set
       */
      public void setHeader(String name, String value) {
  
          if (isCommitted())
              return;
  
          // Ignore any call from an included servlet
          if (included)
              return;
  
          coyoteResponse.setHeader(name, value);
  
      }
  
  
      /**
       * Set the specified integer header to the specified value.
       *
       * @param name Name of the header to set
       * @param value Integer value to be set
       */
      public void setIntHeader(String name, int value) {
  
          if (isCommitted())
              return;
  
          // Ignore any call from an included servlet
          if (included)
              return;
  
          setHeader(name, "" + value);
  
      }
  
  
      /**
       * Set the HTTP status to be returned with this response.
       *
       * @param status The new HTTP status
       */
      public void setStatus(int status) {
          setStatus(status, null);
      }
  
  
      /**
       * Set the HTTP status and message to be returned with this response.
       *
       * @param status The new HTTP status
       * @param message The associated text message
       *
       * @deprecated As of Version 2.1 of the Java Servlet API, this method
       *  has been deprecated due to the ambiguous meaning of the message
       *  parameter.
       */
      public void setStatus(int status, String message) {
  
          if (isCommitted())
              return;
  
          // Ignore any call from an included servlet
          if (included)
              return;
  
          coyoteResponse.setStatus(status);
          coyoteResponse.setMessage(message);
  
      }
  
  
      // ------------------------------------------------------ Protected Methods
  
  
      /**
       * Return <code>true</code> if the specified URL should be encoded with
       * a session identifier.  This will be true if all of the following
       * conditions are met:
       * <ul>
       * <li>The request we are responding to asked for a valid session
       * <li>The requested session ID was not received via a cookie
       * <li>The specified URL points back to somewhere within the web
       *     application that is responding to this request
       * </ul>
       *
       * @param location Absolute URL to be validated
       */
      protected boolean isEncodeable(String location) {
  
          if (location == null)
              return (false);
  
          // Is this an intra-document reference?
          if (location.startsWith("#"))
              return (false);
  
          // Are we in a valid session that is not using cookies?
          HttpServletRequest hreq = (HttpServletRequest) request.getRequest();
          HttpSession session = hreq.getSession(false);
          if (session == null)
              return (false);
          if (hreq.isRequestedSessionIdFromCookie())
              return (false);
  
          // Is this a valid absolute URL?
          URL url = null;
          try {
              url = new URL(location);
          } catch (MalformedURLException e) {
              return (false);
          }
  
          // Does this URL match down to (and including) the context path?
          if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol()))
              return (false);
          if (!hreq.getServerName().equalsIgnoreCase(url.getHost()))
              return (false);
          int serverPort = hreq.getServerPort();
          if (serverPort == -1) {
              if ("https".equals(hreq.getScheme()))
                  serverPort = 443;
              else
                  serverPort = 80;
          }
          int urlPort = url.getPort();
          if (urlPort == -1) {
              if ("https".equals(url.getProtocol()))
                  urlPort = 443;
              else
                  urlPort = 80;
          }
          if (serverPort != urlPort)
              return (false);
  
          String contextPath = getContext().getPath();
          if ((contextPath != null) && (contextPath.length() > 0)) {
              String file = url.getFile();
              if ((file == null) || !file.startsWith(contextPath))
                  return (false);
              if( file.indexOf(";jsessionid=" + session.getId()) >= 0 )
                  return (false);
          }
  
          // This URL belongs to our web application, so it is encodeable
          return (true);
  
      }
  
  
      /**
       * Convert (if necessary) and return the absolute URL that represents the
       * resource referenced by this possibly relative URL.  If this URL is
       * already absolute, return it unchanged.
       *
       * @param location URL to be (possibly) converted and then returned
       *
       * @exception IllegalArgumentException if a MalformedURLException is
       *  thrown when converting the relative URL to an absolute one
       */
      private String toAbsolute(String location) {
  
          if (location == null)
              return (location);
  
          boolean leadingSlash = location.startsWith("/");
  
          if (leadingSlash 
              || (!leadingSlash && (location.indexOf("://") == -1))) {
  
              redirectURLCC.recycle();
  
              String scheme = request.getScheme();
              String name = request.getServerName();
              int port = request.getServerPort();
  
              try {
                  redirectURLCC.append(scheme, 0, scheme.length());
                  redirectURLCC.append("://", 0, 3);
                  redirectURLCC.append(name, 0, name.length());
                  if ((scheme.equals("http") && port != 80)
                      || (scheme.equals("https") && port != 443)) {
                      redirectURLCC.append(':');
                      String portS = port + "";
                      redirectURLCC.append(portS, 0, portS.length());
                  }
                  if (!leadingSlash) {
                      String relativePath = request.getDecodedRequestURI();
                      int pos = relativePath.lastIndexOf('/');
                      relativePath = relativePath.substring(0, pos);
                      String encodedURI = urlEncoder.encodeURL(relativePath);
                      redirectURLCC.append(encodedURI, 0, encodedURI.length());
                      redirectURLCC.append('/');
                  }
                  redirectURLCC.append(location, 0, location.length());
              } catch (IOException e) {
                  throw new IllegalArgumentException(location);
              }
  
              return redirectURLCC.toString();
  
          } else {
  
              return (location);
  
          }
  
      }
  
  
      /**
       * Return the specified URL with the specified session identifier
       * suitably encoded.
       *
       * @param url URL to be encoded with the session id
       * @param sessionId Session id to be included in the encoded URL
       */
      private String toEncoded(String url, String sessionId) {
  
          if ((url == null) || (sessionId == null))
              return (url);
  
          String path = url;
          String query = "";
          String anchor = "";
          int question = url.indexOf('?');
          if (question >= 0) {
              path = url.substring(0, question);
              query = url.substring(question);
          }
          int pound = path.indexOf('#');
          if (pound >= 0) {
              anchor = path.substring(pound);
              path = path.substring(0, pound);
          }
          StringBuffer sb = new StringBuffer(path);
          if( sb.length() > 0 ) { // jsessionid can't be first.
              sb.append(";jsessionid=");
              sb.append(sessionId);
          }
          sb.append(anchor);
          sb.append(query);
          return (sb.toString());
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteResponseFacade.java
  
  Index: CoyoteResponseFacade.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteResponseFacade.java,v 1.1 2002/08/04 19:39:49 patrickl Exp $
   * $Revision: 1.1 $
   * $Date: 2002/08/04 19:39:49 $
   *
   * ====================================================================
   *
   * 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.coyote.tomcat5;
  
  
  import java.io.IOException;
  import java.io.OutputStream;
  import java.io.PrintWriter;
  import java.util.Locale;
  import javax.servlet.ServletException;
  import javax.servlet.ServletOutputStream;
  import javax.servlet.ServletResponse;
  import javax.servlet.http.Cookie;
  import javax.servlet.http.HttpServletResponse;
  
  import org.apache.catalina.connector.ResponseFacade;
  
  /**
   * Facade class that wraps a Coyote response object. 
   * All methods are delegated to the wrapped response.
   *
   * @author Remy Maucherat
   * @version $Revision: 1.1 $ $Date: 2002/08/04 19:39:49 $
   */
  
  public class CoyoteResponseFacade 
      extends ResponseFacade
      implements HttpServletResponse {
  
  
      // ----------------------------------------------------------- Constructors
  
  
      /**
       * Construct a wrapper for the specified response.
       *
       * @param response The response to be wrapped
       */
      public CoyoteResponseFacade(CoyoteResponse response) {
  
          super(response);
          this.response = response;
  
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The wrapped response.
       */
      protected CoyoteResponse response = null;
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Clear facade.
       */
      public void clear() {
          response = null;
      }
  
  
      public void finish() {
  
          response.setSuspended(true);
  
      }
  
  
      public boolean isFinished() {
  
          return response.isSuspended();
  
      }
  
  
      // ------------------------------------------------ ServletResponse Methods
  
  
      public String getCharacterEncoding() {
          return response.getCharacterEncoding();
      }
  
  
      public ServletOutputStream getOutputStream()
          throws IOException {
  
          //        if (isFinished())
          //            throw new IllegalStateException
          //                (/*sm.getString("responseFacade.finished")*/);
  
          ServletOutputStream sos = response.getOutputStream();
          if (isFinished())
              response.setSuspended(true);
          return (sos);
  
      }
  
  
      public PrintWriter getWriter()
          throws IOException {
  
          //        if (isFinished())
          //            throw new IllegalStateException
          //                (/*sm.getString("responseFacade.finished")*/);
  
          PrintWriter writer = response.getWriter();
          if (isFinished())
              response.setSuspended(true);
          return (writer);
  
      }
  
  
      public void setContentLength(int len) {
  
          if (isCommitted())
              return;
  
          response.setContentLength(len);
  
      }
  
  
      public void setContentType(String type) {
  
          if (isCommitted())
              return;
  
          response.setContentType(type);
  
      }
  
  
      public void setBufferSize(int size) {
  
          if (isCommitted())
              throw new IllegalStateException
                  (/*sm.getString("responseBase.reset.ise")*/);
  
          response.setBufferSize(size);
  
      }
  
  
      public int getBufferSize() {
          return response.getBufferSize();
      }
  
  
      public void flushBuffer()
          throws IOException {
  
          if (isFinished())
              //            throw new IllegalStateException
              //                (/*sm.getString("responseFacade.finished")*/);
              return;
  
          response.setAppCommitted(true);
  
          response.flushBuffer();
  
      }
  
  
      public void resetBuffer() {
  
          if (isCommitted())
              throw new IllegalStateException
                  (/*sm.getString("responseBase.reset.ise")*/);
  
          response.resetBuffer();
  
      }
  
  
      public boolean isCommitted() {
          return (response.isAppCommitted());
      }
  
  
      public void reset() {
  
          if (isCommitted())
              throw new IllegalStateException
                  (/*sm.getString("responseBase.reset.ise")*/);
  
          response.reset();
  
      }
  
  
      public void setLocale(Locale loc) {
  
          if (isCommitted())
              return;
  
          response.setLocale(loc);
      }
  
  
      public Locale getLocale() {
          return response.getLocale();
      }
  
  
      public void addCookie(Cookie cookie) {
  
          if (isCommitted())
              return;
  
          response.addCookie(cookie);
  
      }
  
  
      public boolean containsHeader(String name) {
          return response.containsHeader(name);
      }
  
  
      public String encodeURL(String url) {
          return response.encodeURL(url);
      }
  
  
      public String encodeRedirectURL(String url) {
          return response.encodeRedirectURL(url);
      }
  
  
      public String encodeUrl(String url) {
          return response.encodeURL(url);
      }
  
  
      public String encodeRedirectUrl(String url) {
          return response.encodeRedirectURL(url);
      }
  
  
      public void sendError(int sc, String msg)
          throws IOException {
  
          if (isCommitted())
              throw new IllegalStateException
                  (/*sm.getString("responseBase.reset.ise")*/);
  
          response.setAppCommitted(true);
  
          response.sendError(sc, msg);
  
      }
  
  
      public void sendError(int sc)
          throws IOException {
  
          if (isCommitted())
              throw new IllegalStateException
                  (/*sm.getString("responseBase.reset.ise")*/);
  
          response.setAppCommitted(true);
  
          response.sendError(sc);
  
      }
  
  
      public void sendRedirect(String location)
          throws IOException {
  
          if (isCommitted())
              throw new IllegalStateException
                  (/*sm.getString("responseBase.reset.ise")*/);
  
          response.setAppCommitted(true);
  
          response.sendRedirect(location);
  
      }
  
  
      public void setDateHeader(String name, long date) {
  
          if (isCommitted())
              return;
  
          response.setDateHeader(name, date);
  
      }
  
  
      public void addDateHeader(String name, long date) {
  
          if (isCommitted())
              return;
  
          response.addDateHeader(name, date);
  
      }
  
  
      public void setHeader(String name, String value) {
  
          if (isCommitted())
              return;
  
          response.setHeader(name, value);
  
      }
  
  
      public void addHeader(String name, String value) {
  
          if (isCommitted())
              return;
  
          response.addHeader(name, value);
  
      }
  
  
      public void setIntHeader(String name, int value) {
  
          if (isCommitted())
              return;
  
          response.setIntHeader(name, value);
  
      }
  
  
      public void addIntHeader(String name, int value) {
  
          if (isCommitted())
              return;
  
          response.addIntHeader(name, value);
  
      }
  
  
      public void setStatus(int sc) {
  
          if (isCommitted())
              return;
  
          response.setStatus(sc);
  
      }
  
  
      public void setStatus(int sc, String sm) {
  
          if (isCommitted())
              return;
  
          response.setStatus(sc, sm);
  
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteServerSocketFactory.java
  
  Index: CoyoteServerSocketFactory.java
  ===================================================================
  /*
   * ====================================================================
   *
   * 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.coyote.tomcat5;
  
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.IOException;
  import java.net.InetAddress;
  import java.net.ServerSocket;
  import java.security.KeyStore;
  import java.security.KeyStoreException;
  import java.security.NoSuchAlgorithmException;
  import java.security.UnrecoverableKeyException;
  import java.security.KeyManagementException;
  import java.security.Security;
  import java.security.cert.CertificateException;
  
  
  /**
   * This socket factory holds secure socket factory parameters. Besides the usual
   * configuration mechanism based on setting JavaBeans properties, this
   * component may also be configured by passing a series of attributes set
   * with calls to <code>setAttribute()</code>.  The following attribute
   * names are recognized, with default values in square brackets:
   * <ul>
   * <li><strong>algorithm</strong> - Certificate encoding algorithm
   *     to use. [SunX509]</li>
   * <li><strong>clientAuth</strong> - Require client authentication if
   *     set to <code>true</code>. [false]</li>
   * <li><strong>keystoreFile</strong> - Pathname to the Key Store file to be
   *     loaded.  This must be an absolute path, or a relative path that
   *     is resolved against the "catalina.base" system property.
   *     ["./keystore" in the user home directory]</li>
   * <li><strong>keystorePass</strong> - Password for the Key Store file to be
   *     loaded. ["changeit"]</li>
   * <li><strong>keystoreType</strong> - Type of the Key Store file to be
   *     loaded. ["JKS"]</li>
   * <li><strong>protocol</strong> - SSL protocol to use. [TLS]</li>
   * </ul>
   *
   * @author Harish Prabandham
   * @author Costin Manolache
   * @author Craig McClanahan
   */
  
  public class CoyoteServerSocketFactory
      implements org.apache.catalina.net.ServerSocketFactory {
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Certificate encoding algorithm to be used.
       */
      private String algorithm = null;
  
      public String getAlgorithm() {
          return (this.algorithm);
      }
  
      public void setAlgorithm(String algorithm) {
          this.algorithm = algorithm;
      }
  
  
      /**
       * Should we require client authentication?
       */
      private boolean clientAuth = false;
  
      public boolean getClientAuth() {
          return (this.clientAuth);
      }
  
      public void setClientAuth(boolean clientAuth) {
          this.clientAuth = clientAuth;
      }
  
  
      /**
       * Pathname to the key store file to be used.
       */
      private String keystoreFile =
          System.getProperty("user.home") + File.separator + ".keystore";
  
      public String getKeystoreFile() {
          return (this.keystoreFile);
      }
  
      public void setKeystoreFile(String keystoreFile) {
        
          File file = new File(keystoreFile);
          if (!file.isAbsolute())
              file = new File(System.getProperty("catalina.base"),
                              keystoreFile);
          this.keystoreFile = file.getAbsolutePath();
      }
  
      /**
       * Pathname to the random file to be used.
       */
      private String randomFile =
          System.getProperty("user.home") + File.separator + "random.pem";
  
      public String getRandomFile() {
          return (this.randomFile);
      }
  
      public void setRandomFile(String randomFile) {
        
          File file = new File(randomFile);
          if (!file.isAbsolute())
              file = new File(System.getProperty("catalina.base"),
                              randomFile);
          this.randomFile = file.getAbsolutePath();
      }
  
      /**
       * Pathname to the root list to be used.
       */
      private String rootFile =
          System.getProperty("user.home") + File.separator + "root.pem";
  
      public String getRootFile() {
          return (this.rootFile);
      }
  
      public void setRootFile(String rootFile) {
        
          File file = new File(rootFile);
          if (!file.isAbsolute())
              file = new File(System.getProperty("catalina.base"),
                              rootFile);
          this.rootFile = file.getAbsolutePath();
      }
       
      /**
       * Password for accessing the key store file.
       */
      private String keystorePass = "changeit";
  
      public String getKeystorePass() {
          return (this.keystorePass);
      }
  
      public void setKeystorePass(String keystorePass) {
          this.keystorePass = keystorePass;
      }
  
  
      /**
       * Storeage type of the key store file to be used.
       */
      private String keystoreType = "JKS";
  
      public String getKeystoreType() {
          return (this.keystoreType);
      }
  
      public void setKeystoreType(String keystoreType) {
          this.keystoreType = keystoreType;
      }
  
  
      /**
       * SSL protocol variant to use.
       */
      private String protocol = "TLS";
  
      public String getProtocol() {
          return (this.protocol);
      }
  
      public void setProtocol(String protocol) {
          this.protocol = protocol;
      }
  
  
      /**
       * SSL implementation to use.
       */
      private String sslImplementation = null;
  
      public String getSSLImplementation() {
          return (this.sslImplementation);
      }
  
      public void setSSLImplementation(String sslImplementation) {
          this.sslImplementation = sslImplementation;
      }
  
  
  
      // --------------------------------------------------------- Public Methods
  
  
      public ServerSocket createSocket(int port) {
          return (null);
      }
  
  
      public ServerSocket createSocket(int port, int backlog) {
          return (null);
      }
  
  
      public ServerSocket createSocket(int port, int backlog,
                                       InetAddress ifAddress) {
          return (null);
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteWriter.java
  
  Index: CoyoteWriter.java
  ===================================================================
  /*
   * ====================================================================
   * 
   * 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.coyote.tomcat5;
  
  import java.io.IOException;
  import java.io.PrintWriter;
  
  import javax.servlet.ServletOutputStream;
  
  /**
   * Coyote implementation of the servlet writer.
   * 
   * @author Costin Manolache
   * @author Remy Maucherat
   */
  final class CoyoteWriter
      extends PrintWriter {
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      protected OutputBuffer ob;
  
  
      // ----------------------------------------------------------- Constructors
  
  
      public CoyoteWriter(OutputBuffer ob) {
          super(ob);
          this.ob = ob;
      }
  
  
      // --------------------------------------------------------- Writer Methods
  
  
      public void flush() {
          super.flush();
      }
  
  
      public void write(char buf[], int offset, int count) {
          super.write(buf, offset, count);
      }
  
  
      public void write(String str) {
          super.write( str );
      }
  
  
      public void close() {
          // We don't close the PrintWriter - super() is not called,
          // so the stream can be reused. We close ob.
          try {
              ob.close();
          } catch (IOException ex ) {
              ex.printStackTrace();
          }
      }
  
  
      // ---------------------------------------------------- PrintWriter Methods
  
  
      public void print(String str) {
          super.print( str );
      }
  
  
      public void println(String str) {
          super.println(str);
      }
  
  
  }
  
  
  
  
  1.1                  jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/LocalStrings.properties
  
  Index: LocalStrings.properties
  ===================================================================
  
  #
  # CoyoteConnector
  #
  
  coyoteConnector.alreadyInitialized=The connector has already been initialized
  coyoteConnector.alreadyStarted=The connector has already been started
  coyoteConnector.notStarted=Coyote connector has not been started
  coyoteConnector.protocolHandlerDestroyFailed=Protocol handler destroy failed: {0}
  coyoteConnector.protocolHandlerInitializationFailed=Protocol handler initialization failed: {0}
  coyoteConnector.protocolHandlerInstantiationFailed=Protocol handler instantiation failed: {0}
  coyoteConnector.protocolHandlerStartFailed=Protocol handler start failed: {0}
  
  #
  # CoyoteAdapter
  #
  
  coyoteAdapter.service=An exception or error occurred in the container during the request processing
  
  #
  # CoyoteResponse
  #
  
  coyoteResponse.getOutputStream.ise=getWriter() has already been called for this response
  coyoteResponse.getWriter.ise=getOutputStream() has already been called for this response
  coyoteResponse.resetBuffer.ise=Cannot reset buffer after response has been committed
  coyoteResponse.sendError.ise=Cannot call sendError() after the response has been committed
  coyoteResponse.sendRedirect.ise=Cannot call sendRedirect() after the response has been committed
  coyoteResponse.setBufferSize.ise=Cannot change buffer size after data has been written
  
  #
  # CoyoteRequest
  #
  
  coyoteRequest.getInputStream.ise=getReader() has already been called for this request
  coyoteRequest.getReader.ise=getInputStream() has already been called for this request
  coyoteRequest.sessionCreateCommitted=Cannot create a session after the response has been committed
  coyoteRequest.setAttribute.namenull=Cannot call setAttribute with a null name
  
  
  
  1.1                  jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/OutputBuffer.java
  
  Index: OutputBuffer.java
  ===================================================================
  /*
   * ====================================================================
   * 
   * 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.coyote.tomcat5;
  
  import java.io.IOException;
  import java.io.OutputStream;
  import java.io.OutputStreamWriter;
  import java.io.UnsupportedEncodingException;
  import java.io.Writer;
  import java.util.Hashtable;
  
  import org.apache.tomcat.util.buf.ByteChunk;
  import org.apache.tomcat.util.buf.C2BConverter;
  import org.apache.tomcat.util.buf.CharChunk;
  
  import org.apache.coyote.Response;
  
  
  /**
   * The buffer used by Tomcat response. This is a derivative of the Tomcat 3.3
   * OutputBuffer, with the removal of some of the state handling (which in 
   * Coyote is mostly the Processor's responsability).
   *
   * @author Costin Manolache
   * @author Remy Maucherat
   */
  public class OutputBuffer extends Writer
      implements ByteChunk.ByteOutputChannel, CharChunk.CharOutputChannel {
  
  
      // -------------------------------------------------------------- Constants
  
  
      public static final String DEFAULT_ENCODING = 
          org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
      public static final int DEFAULT_BUFFER_SIZE = 8*1024;
      static final int debug = 0;
  
  
      // The buffer can be used for byte[] and char[] writing
      // ( this is needed to support ServletOutputStream and for
      // efficient implementations of templating systems )
      public final int INITIAL_STATE = 0;
      public final int CHAR_STATE = 1;
      public final int BYTE_STATE = 2;
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      /**
       * The byte buffer.
       */
      private ByteChunk bb;
  
  
      /**
       * The chunk buffer.
       */
      private CharChunk cb;
  
  
      /**
       * State of the output buffer.
       */
      private int state = 0;
  
  
      /**
       * Number of bytes written.
       */
      private int bytesWritten = 0;
  
  
      /**
       * Number of chars written.
       */
      private int charsWritten = 0;
  
  
      /**
       * Flag which indicates if the output buffer is closed.
       */
      private boolean closed = false;
  
  
      /**
       * Do a flush on the next operation.
       */
      private boolean doFlush = false;
  
  
      /**
       * Byte chunk used to output bytes.
       */
      private ByteChunk outputChunk = new ByteChunk();
  
  
      /**
       * Encoding to use.
       */
      private String enc;
  
  
      /**
       * Encoder is set.
       */
      private boolean gotEnc = false;
  
  
      /**
       * List of encoders.
       */
      protected Hashtable encoders = new Hashtable();
  
  
      /**
       * Current char to byte converter.
       */
      protected C2BConverter conv;
  
  
      /**
       * Associated Coyote response.
       */
      private Response coyoteResponse;
  
  
      /**
       * Suspended flag. All output bytes will be swallowed if this is true.
       */
      private boolean suspended = false;
  
  
      // ----------------------------------------------------------- Constructors
  
  
      /**
       * Default constructor. Allocate the buffer with the default buffer size.
       */
      public OutputBuffer() {
  
          this(DEFAULT_BUFFER_SIZE);
  
      }
  
  
      /**
       * Alternate constructor which allows specifying the initial buffer size.
       * 
       * @param size Buffer size to use
       */
      public OutputBuffer(int size) {
  
          bb = new ByteChunk(size);
          bb.setLimit(size);
          bb.setByteOutputChannel(this);
          cb = new CharChunk(size);
          cb.setCharOutputChannel(this);
          cb.setLimit(size);
  
      }
  
  
      // ------------------------------------------------------------- Properties
  
  
      /**
       * Associated Coyote response.
       * 
       * @param coyoteResponse Associated Coyote response
       */
      public void setResponse(Response coyoteResponse) {
  	this.coyoteResponse = coyoteResponse;
      }
  
  
      /**
       * Get associated Coyote response.
       * 
       * @return the associated Coyote response
       */
      public Response getResponse() {
          return this.coyoteResponse;
      }
  
  
      /**
       * Is the response output suspended ?
       * 
       * @return suspended flag value
       */
      public boolean isSuspended() {
          return this.suspended;
      }
  
  
      /**
       * Set the suspended flag.
       * 
       * @param suspended New suspended flag value
       */
      public void setSuspended(boolean suspended) {
          this.suspended = suspended;
      }
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Recycle the output buffer.
       */
      public void recycle() {
  
  	if (debug > 0)
              log("recycle()");
  
  	state = INITIAL_STATE;
  	bytesWritten = 0;
  	charsWritten = 0;
  
          cb.recycle();
          bb.recycle(); 
          closed = false;
          suspended = false;
  
          if (conv!= null) {
              conv.recycle();
          }
  
          gotEnc = false;
          enc = null;
  
      }
  
  
      /**
       * Close the output buffer. This tries to calculate the response size if 
       * the response has not been committed yet.
       * 
       * @throws IOException An underlying IOException occurred
       */
      public void close()
          throws IOException {
  
          if (suspended)
              return;
  
          if ((!coyoteResponse.isCommitted()) 
              && (coyoteResponse.getContentLength() == -1)) {
              // Flushing the char buffer
              if (state == CHAR_STATE) {
                  cb.flushBuffer();
                  state = BYTE_STATE;
              }
              // If this didn't cause a commit of the response, the final content
              // length can be calculated
              if (!coyoteResponse.isCommitted()) {
                  coyoteResponse.setContentLength(bb.getLength());
              }
          }
  
          flush();
          closed = true;
  
      }
  
  
      /**
       * Flush bytes or chars contained in the buffer.
       * 
       * @throws IOException An underlying IOException occurred
       */
      public void flush()
          throws IOException {
  
          if (suspended)
              return;
  
          doFlush = true;
          if (state == CHAR_STATE) {
              cb.flushBuffer();
              bb.flushBuffer();
              state = BYTE_STATE;
          } else if (state == BYTE_STATE) {
              bb.flushBuffer();
          } else if (state == INITIAL_STATE)
              realWriteBytes(null, 0, 0);       // nothing written yet
          doFlush = false;
  
      }
  
  
      // ------------------------------------------------- Bytes Handling Methods
  
  
      /** 
       * Sends the buffer data to the client output, checking the
       * state of Response and calling the right interceptors.
       * 
       * @param buf Byte buffer to be written to the response
       * @param off Offset
       * @param cnt Length
       * 
       * @throws IOException An underlying IOException occurred
       */
      public void realWriteBytes(byte buf[], int off, int cnt)
  	throws IOException {
  
          if (debug > 2)
              log("realWrite(b, " + off + ", " + cnt + ") " + coyoteResponse);
  
          if (closed)
              return;
          if (coyoteResponse == null)
              return;
  
          // If we really have something to write
          if (cnt > 0) {
              // real write to the adapter
              outputChunk.setBytes(buf, off, cnt);
              coyoteResponse.doWrite(outputChunk);
          }
  
      }
  
  
      public void write(byte b[], int off, int len) throws IOException {
  
          if (suspended)
              return;
  
          if (state == CHAR_STATE)
              cb.flushBuffer();
          state = BYTE_STATE;
          writeBytes(b, off, len);
  
      }
  
  
      private void writeBytes(byte b[], int off, int len) 
          throws IOException {
  
          if (closed)
              return;
          if (debug > 0)
              log("write(b,off,len)");
  
          bb.append(b, off, len);
          bytesWritten += len;
  
          // if called from within flush(), then immediately flush
          // remaining bytes
          if (doFlush) {
              bb.flushBuffer();
          }
  
      }
  
  
      // XXX Char or byte ?
      public void writeByte(int b)
          throws IOException {
  
          if (suspended)
              return;
  
          if (state == CHAR_STATE)
              cb.flushBuffer();
          state = BYTE_STATE;
  
          if (debug > 0)
              log("write(b)");
  
          bb.append( (byte)b );
          bytesWritten++;
  
      }
  
  
      // ------------------------------------------------- Chars Handling Methods
  
  
      public void write(int c)
          throws IOException {
  
          if (suspended)
              return;
  
          state = CHAR_STATE;
  
          if (debug > 0)
              log("writeChar(b)");
  
          cb.append((char) c);
          charsWritten++;
  
      }
  
  
      public void write(char c[])
          throws IOException {
  
          if (suspended)
              return;
  
          write(c, 0, c.length);
  
      }
  
  
      public void write(char c[], int off, int len)
          throws IOException {
  
          if (suspended)
              return;
  
          state = CHAR_STATE;
  
          if (debug > 0)
              log("write(c,off,len)" + cb.getLength() + " " + cb.getLimit());
  
          cb.append(c, off, len);
          charsWritten += len;
  
      }
  
  
      public void write(StringBuffer sb)
          throws IOException {
  
          if (suspended)
              return;
  
          state = CHAR_STATE;
  
          if (debug > 1)
              log("write(s,off,len)");
  
          int len = sb.length();
          charsWritten += len;
          cb.append(sb);
  
      }
  
  
      /**
       * Append a string to the buffer
       */
      public void write(String s, int off, int len)
          throws IOException {
  
          if (suspended)
              return;
  
          state=CHAR_STATE;
  
          if (debug > 1)
              log("write(s,off,len)");
  
          charsWritten += len;
          if (s==null)
              s="null";
          cb.append( s, off, len );
  
      }
  
  
      public void write(String s)
          throws IOException {
  
          if (suspended)
              return;
  
          state = CHAR_STATE;
          if (s==null)
              s="null";
          write(s, 0, s.length());
  
      } 
  
  
      public void flushChars()
          throws IOException {
  
          if (debug > 0)
              log("flushChars() " + cb.getLength());
  
          cb.flushBuffer();
          state = BYTE_STATE;
  
      }
  
  
      public boolean flushCharsNeeded() {
          return state == CHAR_STATE;
      }
  
  
      public void setEncoding(String s) {
          enc = s;
      }
  
  
      public void realWriteChars(char c[], int off, int len) 
          throws IOException {
  
          if (debug > 0)
              log("realWrite(c,o,l) " + cb.getOffset() + " " + len);
  
          if (!gotEnc)
              setConverter();
  
          if (debug > 0)
              log("encoder:  " + conv + " " + gotEnc);
  
          conv.convert(c, off, len);
          conv.flushBuffer();	// ???
  
      }
  
  
      protected void setConverter() {
  
          if (coyoteResponse != null)
              enc = coyoteResponse.getCharacterEncoding();
  
          if (debug > 0)
              log("Got encoding: " + enc);
  
          gotEnc = true;
          if (enc == null)
              enc = DEFAULT_ENCODING;
          conv = (C2BConverter) encoders.get(enc);
          if (conv == null) {
              try {
                  conv = new C2BConverter(bb, enc);
                  encoders.put(enc, conv);
              } catch (IOException e) {
                  conv = (C2BConverter) encoders.get(DEFAULT_ENCODING);
                  if (conv == null) {
                      try {
                          conv = new C2BConverter(bb, DEFAULT_ENCODING);
                          encoders.put(DEFAULT_ENCODING, conv);
                      } catch (IOException ex) {
                          // Ignore
                      }
                  }
              }
          }
      }
  
      
      // --------------------  BufferedOutputStream compatibility
  
  
      /**
       * Real write - this buffer will be sent to the client
       */
      public void flushBytes()
          throws IOException {
  
          if (debug > 0)
              log("flushBytes() " + bb.getLength());
          bb.flushBuffer();
  
      }
  
  
      public int getBytesWritten() {
          return bytesWritten;
      }
  
  
      public int getCharsWritten() {
          return charsWritten;
      }
  
  
      /** 
       * True if this buffer hasn't been used ( since recycle() ) -
       * i.e. no chars or bytes have been added to the buffer.  
       */
      public boolean isNew() {
          return (bytesWritten == 0) && (charsWritten == 0);
      }
  
  
      public void setBufferSize(int size) {
          if (size > bb.getLimit()) {// ??????
  	    bb.setLimit(size);
  	}
      }
  
  
      public void reset() {
  
          //count=0;
          bb.recycle();
          bytesWritten = 0;
          cb.recycle();
          charsWritten = 0;
          gotEnc = false;
          enc = null;
  
      }
  
  
      public int getBufferSize() {
  	return bb.getLimit();
      }
  
  
  
      protected void log( String s ) {
  	System.out.println("OutputBuffer: " + s);
      }
  
  
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>