Commits

Sebastian Sdorra committed 6724c83

remove unused apache cgiservlet

Comments (0)

Files changed (2)

scm-web-api/src/main/java/org/apache/catalina/Globals.java

-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package org.apache.catalina;
-
-
-/**
- * Global constants that are applicable to multiple packages within Catalina.
- *
- * @author Craig R. McClanahan
- * @version $Id$
- */
-
-public final class Globals {
-
-    /**
-     * The servlet context attribute under which we store the alternate
-     * deployment descriptor for this web application
-     */
-    public static final String ALT_DD_ATTR =
-        "org.apache.catalina.deploy.alt_dd";
-
-    /**
-     * The request attribute under which we store the array of X509Certificate
-     * objects representing the certificate chain presented by our client,
-     * if any.
-     */
-    public static final String CERTIFICATES_ATTR =
-        "javax.servlet.request.X509Certificate";
-
-    /**
-     * The request attribute under which we store the name of the cipher suite
-     * being used on an SSL connection (as an object of type
-     * java.lang.String).
-     */
-    public static final String CIPHER_SUITE_ATTR =
-        "javax.servlet.request.cipher_suite";
-
-
-    /**
-     * The servlet context attribute under which we store the class loader
-     * used for loading servlets (as an object of type java.lang.ClassLoader).
-     */
-    public static final String CLASS_LOADER_ATTR =
-        "org.apache.catalina.classloader";
-
-    /**
-     * Request dispatcher state.
-     */
-    public static final String DISPATCHER_TYPE_ATTR =
-        "org.apache.catalina.core.DISPATCHER_TYPE";
-
-    /**
-     * Request dispatcher path.
-     */
-    public static final String DISPATCHER_REQUEST_PATH_ATTR =
-        "org.apache.catalina.core.DISPATCHER_REQUEST_PATH";
-
-    /**
-     * The JNDI directory context which is associated with the context. This
-     * context can be used to manipulate static files.
-     */
-    public static final String RESOURCES_ATTR =
-        "org.apache.catalina.resources";
-
-
-    /**
-     * The servlet context attribute under which we store the class path
-     * for our application class loader (as an object of type String),
-     * delimited with the appropriate path delimiter for this platform.
-     */
-    public static final String CLASS_PATH_ATTR =
-        "org.apache.catalina.jsp_classpath";
-
-
-    /**
-     * The request attribute under which we forward a Java exception
-     * (as an object of type Throwable) to an error page.
-     */
-    public static final String EXCEPTION_ATTR =
-        "javax.servlet.error.exception";
-
-
-    /**
-     * The request attribute under which we forward the request URI
-     * (as an object of type String) of the page on which an error occurred.
-     */
-    public static final String EXCEPTION_PAGE_ATTR =
-        "javax.servlet.error.request_uri";
-
-
-    /**
-     * The request attribute under which we forward a Java exception type
-     * (as an object of type Class) to an error page.
-     */
-    public static final String EXCEPTION_TYPE_ATTR =
-        "javax.servlet.error.exception_type";
-
-
-    /**
-     * The request attribute under which we forward an HTTP status message
-     * (as an object of type STring) to an error page.
-     */
-    public static final String ERROR_MESSAGE_ATTR =
-        "javax.servlet.error.message";
-
-
-    /**
-     * The request attribute under which we expose the value of the
-     * <code>&lt;jsp-file&gt;</code> value associated with this servlet,
-     * if any.
-     */
-    public static final String JSP_FILE_ATTR =
-        "org.apache.catalina.jsp_file";
-
-
-    /**
-     * The request attribute under which we store the key size being used for
-     * this SSL connection (as an object of type java.lang.Integer).
-     */
-    public static final String KEY_SIZE_ATTR =
-        "javax.servlet.request.key_size";
-
-    /**
-     * The request attribute under which we store the session id being used
-     * for this SSL connection (as an object of type java.lang.String).
-     */
-    public static final String SSL_SESSION_ID_ATTR =
-        "javax.servlet.request.ssl_session";
-
-
-    /**
-     * The request attribute key for the session manager.
-     * This one is a Tomcat extension to the Servlet spec.
-     */
-    public static final String SSL_SESSION_MGR_ATTR =
-        "javax.servlet.request.ssl_session_mgr";
-
-
-    /**
-     * The servlet context attribute under which the managed bean Registry
-     * will be stored for privileged contexts (if enabled).
-     */
-    public static final String MBEAN_REGISTRY_ATTR =
-        "org.apache.catalina.Registry";
-
-
-    /**
-     * The servlet context attribute under which the MBeanServer will be stored
-     * for privileged contexts (if enabled).
-     */
-    public static final String MBEAN_SERVER_ATTR =
-        "org.apache.catalina.MBeanServer";
-
-
-    /**
-     * The request attribute under which we store the servlet name on a
-     * named dispatcher request.
-     */
-    public static final String NAMED_DISPATCHER_ATTR =
-        "org.apache.catalina.NAMED";
-
-
-    /**
-     * Platform specific new line sequence.
-     */
-    public static final String NEWLINE = System.getProperty("line.separator");
-
-
-    /**
-     * The request attribute under which the request URI of the included
-     * servlet is stored on an included dispatcher request.
-     */
-    public static final String INCLUDE_REQUEST_URI_ATTR =
-        "javax.servlet.include.request_uri";
-
-
-    /**
-     * The request attribute under which the context path of the included
-     * servlet is stored on an included dispatcher request.
-     */
-    public static final String INCLUDE_CONTEXT_PATH_ATTR =
-        "javax.servlet.include.context_path";
-
-
-    /**
-     * The request attribute under which the path info of the included
-     * servlet is stored on an included dispatcher request.
-     */
-    public static final String INCLUDE_PATH_INFO_ATTR =
-        "javax.servlet.include.path_info";
-
-
-    /**
-     * The request attribute under which the servlet path of the included
-     * servlet is stored on an included dispatcher request.
-     */
-    public static final String INCLUDE_SERVLET_PATH_ATTR =
-        "javax.servlet.include.servlet_path";
-
-
-    /**
-     * The request attribute under which the query string of the included
-     * servlet is stored on an included dispatcher request.
-     */
-    public static final String INCLUDE_QUERY_STRING_ATTR =
-        "javax.servlet.include.query_string";
-
-
-    /**
-     * The request attribute under which the original request URI is stored
-     * on an forwarded dispatcher request.
-     */
-    public static final String FORWARD_REQUEST_URI_ATTR =
-        "javax.servlet.forward.request_uri";
-
-
-    /**
-     * The request attribute under which the original context path is stored
-     * on an forwarded dispatcher request.
-     */
-    public static final String FORWARD_CONTEXT_PATH_ATTR =
-        "javax.servlet.forward.context_path";
-
-
-    /**
-     * The request attribute under which the original path info is stored
-     * on an forwarded dispatcher request.
-     */
-    public static final String FORWARD_PATH_INFO_ATTR =
-        "javax.servlet.forward.path_info";
-
-
-    /**
-     * The request attribute under which the original servlet path is stored
-     * on an forwarded dispatcher request.
-     */
-    public static final String FORWARD_SERVLET_PATH_ATTR =
-        "javax.servlet.forward.servlet_path";
-
-
-    /**
-     * The request attribute under which the original query string is stored
-     * on an forwarded dispatcher request.
-     */
-    public static final String FORWARD_QUERY_STRING_ATTR =
-        "javax.servlet.forward.query_string";
-
-
-    /**
-     * The request attribute under which we forward a servlet name to
-     * an error page.
-     */
-    public static final String SERVLET_NAME_ATTR =
-        "javax.servlet.error.servlet_name";
-
-
-    /**
-     * The servlet context attribute under which we store a flag used
-     * to mark this request as having been processed by the SSIServlet.
-     * We do this because of the pathInfo mangling happening when using
-     * the CGIServlet in conjunction with the SSI servlet. (value stored
-     * as an object of type String)
-     */
-     public static final String SSI_FLAG_ATTR =
-         "org.apache.catalina.ssi.SSIServlet";
-
-
-    /**
-     * The request attribute under which we forward an HTTP status code
-     * (as an object of type Integer) to an error page.
-     */
-    public static final String STATUS_CODE_ATTR =
-        "javax.servlet.error.status_code";
-
-
-    /**
-     * The subject under which the AccessControlContext is running.
-     */
-    public static final String SUBJECT_ATTR =
-        "javax.security.auth.subject";
-
-
-    /**
-     * The servlet context attribute under which we record the set of
-     * welcome files (as an object of type String[]) for this application.
-     */
-    public static final String WELCOME_FILES_ATTR =
-        "org.apache.catalina.WELCOME_FILES";
-
-
-    /**
-     * The master flag which controls strict servlet specification
-     * compliance.
-     */
-    public static final boolean STRICT_SERVLET_COMPLIANCE =
-        Boolean.valueOf(System.getProperty("org.apache.catalina.STRICT_SERVLET_COMPLIANCE", "false")).booleanValue();
-
-
-    /**
-     * Has security been turned on?
-     */
-    public static final boolean IS_SECURITY_ENABLED =
-        (System.getSecurityManager() != null);
-
-    /**
-     *
-     */
-    public static final String ASYNC_SUPPORTED_ATTR =
-        "org.apache.catalina.ASYNC_SUPPORTED";
-
-
-    /**
-     * Default domain for MBeans if none can be determined
-     */
-    public static final String DEFAULT_MBEAN_DOMAIN = "Catalina";
-
-    /**
-     * Name of the system property containing
-     * the tomcat product installation path
-     */
-    public static final String CATALINA_HOME_PROP = "catalina.home";
-
-    /**
-     * Name of the system property containing
-     * the tomcat instance installation path
-     */
-    public static final String CATALINA_BASE_PROP = "catalina.base";
-}

scm-web-api/src/main/java/org/apache/catalina/servlets/CGIServlet.java

-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package org.apache.catalina.servlets;
-
-import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Locale;
-import java.util.StringTokenizer;
-import java.util.Vector;
-
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-import org.apache.catalina.Globals;
-import sonia.scm.util.Util;
-
-
-/**
- *  CGI-invoking servlet for web applications, used to execute scripts which
- *  comply to the Common Gateway Interface (CGI) specification and are named
- *  in the path-info used to invoke this servlet.
- *
- * <p>
- * <i>Note: This code compiles and even works for simple CGI cases.
- *          Exhaustive testing has not been done.  Please consider it beta
- *          quality.  Feedback is appreciated to the author (see below).</i>
- * </p>
- * <p>
- *
- * <b>Example</b>:<br>
- * If an instance of this servlet was mapped (using
- *       <code>&lt;web-app&gt;/WEB-INF/web.xml</code>) to:
- * </p>
- * <p>
- * <code>
- * &lt;web-app&gt;/cgi-bin/*
- * </code>
- * </p>
- * <p>
- * then the following request:
- * </p>
- * <p>
- * <code>
- * http://localhost:8080/&lt;web-app&gt;/cgi-bin/dir1/script/pathinfo1
- * </code>
- * </p>
- * <p>
- * would result in the execution of the script
- * </p>
- * <p>
- * <code>
- * &lt;web-app-root&gt;/WEB-INF/cgi/dir1/script
- * </code>
- * </p>
- * <p>
- * with the script's <code>PATH_INFO</code> set to <code>/pathinfo1</code>.
- * </p>
- * <p>
- * Recommendation:  House all your CGI scripts under
- * <code>&lt;webapp&gt;/WEB-INF/cgi</code>.  This will ensure that you do not
- * accidentally expose your cgi scripts' code to the outside world and that
- * your cgis will be cleanly ensconced underneath the WEB-INF (i.e.,
- * non-content) area.
- * </p>
- * <p>
- * The default CGI location is mentioned above.  You have the flexibility to
- * put CGIs wherever you want, however:
- * </p>
- * <p>
- *   The CGI search path will start at
- *   webAppRootDir + File.separator + cgiPathPrefix
- *   (or webAppRootDir alone if cgiPathPrefix is
- *   null).
- * </p>
- * <p>
- *   cgiPathPrefix is defined by setting
- *   this servlet's cgiPathPrefix init parameter
- * </p>
- *
- * <p>
- *
- * <B>CGI Specification</B>:<br> derived from
- * <a href="http://cgi-spec.golux.com">http://cgi-spec.golux.com</a>.
- * A work-in-progress & expired Internet Draft.  Note no actual RFC describing
- * the CGI specification exists.  Where the behavior of this servlet differs
- * from the specification cited above, it is either documented here, a bug,
- * or an instance where the specification cited differs from Best
- * Community Practice (BCP).
- * Such instances should be well-documented here.  Please email the
- * <a href="mailto:dev@tomcat.apache.org">Tomcat group [dev@tomcat.apache.org]</a>
- * with amendments.
- *
- * </p>
- * <p>
- *
- * <b>Canonical metavariables</b>:<br>
- * The CGI specification defines the following canonical metavariables:
- * <br>
- * [excerpt from CGI specification]
- * <PRE>
- *  AUTH_TYPE
- *  CONTENT_LENGTH
- *  CONTENT_TYPE
- *  GATEWAY_INTERFACE
- *  PATH_INFO
- *  PATH_TRANSLATED
- *  QUERY_STRING
- *  REMOTE_ADDR
- *  REMOTE_HOST
- *  REMOTE_IDENT
- *  REMOTE_USER
- *  REQUEST_METHOD
- *  SCRIPT_NAME
- *  SERVER_NAME
- *  SERVER_PORT
- *  SERVER_PROTOCOL
- *  SERVER_SOFTWARE
- * </PRE>
- * <p>
- * Metavariables with names beginning with the protocol name (<EM>e.g.</EM>,
- * "HTTP_ACCEPT") are also canonical in their description of request header
- * fields.  The number and meaning of these fields may change independently
- * of this specification.  (See also section 6.1.5 [of the CGI specification].)
- * </p>
- * [end excerpt]
- *
- * </p>
- * <h2> Implementation notes</h2>
- * <p>
- *
- * <b>standard input handling</b>: If your script accepts standard input,
- * then the client must start sending input within a certain timeout period,
- * otherwise the servlet will assume no input is coming and carry on running
- * the script.  The script's the standard input will be closed and handling of
- * any further input from the client is undefined.  Most likely it will be
- * ignored.  If this behavior becomes undesirable, then this servlet needs
- * to be enhanced to handle threading of the spawned process' stdin, stdout,
- * and stderr (which should not be too hard).
- * <br>
- * If you find your cgi scripts are timing out receiving input, you can set
- * the init parameter <code></code> of your webapps' cgi-handling servlet
- * to be
- * </p>
- * <p>
- *
- * <b>Metavariable Values</b>: According to the CGI specification,
- * implementations may choose to represent both null or missing values in an
- * implementation-specific manner, but must define that manner.  This
- * implementation chooses to always define all required metavariables, but
- * set the value to "" for all metavariables whose value is either null or
- * undefined.  PATH_TRANSLATED is the sole exception to this rule, as per the
- * CGI Specification.
- *
- * </p>
- * <p>
- *
- * <b>NPH --  Non-parsed-header implementation</b>:  This implementation does
- * not support the CGI NPH concept, whereby server ensures that the data
- * supplied to the script are precisely as supplied by the client and
- * unaltered by the server.
- * </p>
- * <p>
- * The function of a servlet container (including Tomcat) is specifically
- * designed to parse and possible alter CGI-specific variables, and as
- * such makes NPH functionality difficult to support.
- * </p>
- * <p>
- * The CGI specification states that compliant servers MAY support NPH output.
- * It does not state servers MUST support NPH output to be unconditionally
- * compliant.  Thus, this implementation maintains unconditional compliance
- * with the specification though NPH support is not present.
- * </p>
- * <p>
- *
- * The CGI specification is located at
- * <a href="http://cgi-spec.golux.com">http://cgi-spec.golux.com</a>.
- *
- * </p>
- * <p>
- * <h3>TODO:</h3>
- * <ul>
- * <li> Support for setting headers (for example, Location headers don't work)
- * <li> Support for collapsing multiple header lines (per RFC 2616)
- * <li> Ensure handling of POST method does not interfere with 2.3 Filters
- * <li> Refactor some debug code out of core
- * <li> Ensure header handling preserves encoding
- * <li> Possibly rewrite CGIRunner.run()?
- * <li> Possibly refactor CGIRunner and CGIEnvironment as non-inner classes?
- * <li> Document handling of cgi stdin when there is no stdin
- * <li> Revisit IOException handling in CGIRunner.run()
- * <li> Better documentation
- * <li> Confirm use of ServletInputStream.available() in CGIRunner.run() is
- *      not needed
- * <li> Make checking for "." and ".." in servlet & cgi PATH_INFO less
- *      draconian
- * <li> [add more to this TODO list]
- * </ul>
- * </p>
- *
- * @author Martin T Dengler [root@martindengler.com]
- * @author Amy Roh
- * @version $Id$
- * @since Tomcat 4.0
- *
- */
-
-
-public final class CGIServlet extends HttpServlet {
-
-    /* some vars below copied from Craig R. McClanahan's InvokerServlet */
-
-    private static final long serialVersionUID = 1L;
-
-    /** the debugging detail level for this servlet. */
-    private int debug = 0;
-
-    /**
-     *  The CGI search path will start at
-     *    webAppRootDir + File.separator + cgiPathPrefix
-     *    (or webAppRootDir alone if cgiPathPrefix is
-     *    null)
-     */
-    private String cgiPathPrefix = null;
-
-    /** the executable to use with the script */
-    private String cgiExecutable = "perl";
-
-    /** the encoding to use for parameters */
-    private String parameterEncoding =
-        System.getProperty("file.encoding", "UTF-8");
-
-    /**
-     * The time (in milliseconds) to wait for the reading of stderr to complete
-     * before terminating the CGI process.
-     */
-    private long stderrTimeout = 2000;
-
-    /** object used to ensure multiple threads don't try to expand same file */
-    static Object expandFileLock = new Object();
-
-    /** the shell environment variables to be passed to the CGI script */
-    static Hashtable<String,String> shellEnv = new Hashtable<String,String>();
-
-    /**
-     * Sets instance variables.
-     * <P>
-     * Modified from Craig R. McClanahan's InvokerServlet
-     * </P>
-     *
-     * @param config                    a <code>ServletConfig</code> object
-     *                                  containing the servlet's
-     *                                  configuration and initialization
-     *                                  parameters
-     *
-     * @exception ServletException      if an exception has occurred that
-     *                                  interferes with the servlet's normal
-     *                                  operation
-     */
-    @Override
-    public void init(ServletConfig config) throws ServletException {
-
-        super.init(config);
-
-        // Set our properties from the initialization parameters
-        if (getServletConfig().getInitParameter("debug") != null)
-            debug = Integer.parseInt(getServletConfig().getInitParameter("debug"));
-        cgiPathPrefix = getServletConfig().getInitParameter("cgiPathPrefix");
-        boolean passShellEnvironment =
-            Boolean.valueOf(getServletConfig().getInitParameter("passShellEnvironment")).booleanValue();
-
-        if (passShellEnvironment) {
-            shellEnv.putAll(System.getenv());
-        }
-
-        if (getServletConfig().getInitParameter("executable") != null) {
-            cgiExecutable = getServletConfig().getInitParameter("executable");
-        }
-
-        if (getServletConfig().getInitParameter("parameterEncoding") != null) {
-            parameterEncoding = getServletConfig().getInitParameter("parameterEncoding");
-        }
-
-        if (getServletConfig().getInitParameter("stderrTimeout") != null) {
-            stderrTimeout = Long.parseLong(getServletConfig().getInitParameter(
-                    "stderrTimeout"));
-        }
-
-    }
-
-    public void setCgiExecutable(String cgiExecutable)
-    {
-      this.cgiExecutable = cgiExecutable;
-    }    
-
-    /**
-     * Prints out important Servlet API and container information
-     *
-     * <p>
-     * Copied from SnoopAllServlet by Craig R. McClanahan
-     * </p>
-     *
-     * @param  out    ServletOutputStream as target of the information
-     * @param  req    HttpServletRequest object used as source of information
-     * @param  res    HttpServletResponse object currently not used but could
-     *                provide future information
-     *
-     * @exception  IOException  if a write operation exception occurs
-     *
-     */
-    protected void printServletEnvironment(ServletOutputStream out,
-        HttpServletRequest req,
-        @SuppressWarnings("unused") HttpServletResponse res)
-    throws IOException {
-
-        // Document the properties from ServletRequest
-        out.println("<h1>ServletRequest Properties</h1>");
-        out.println("<ul>");
-        Enumeration<String> attrs = req.getAttributeNames();
-        while (attrs.hasMoreElements()) {
-            String attr = attrs.nextElement();
-            out.println("<li><b>attribute</b> " + attr + " = " +
-                           req.getAttribute(attr));
-        }
-        out.println("<li><b>characterEncoding</b> = " +
-                       req.getCharacterEncoding());
-        out.println("<li><b>contentLength</b> = " +
-                       req.getContentLength());
-        out.println("<li><b>contentType</b> = " +
-                       req.getContentType());
-        Enumeration<Locale> locales = req.getLocales();
-        while (locales.hasMoreElements()) {
-            Locale locale = locales.nextElement();
-            out.println("<li><b>locale</b> = " + locale);
-        }
-        Enumeration<String> params = req.getParameterNames();
-        while (params.hasMoreElements()) {
-            String param = params.nextElement();
-            String values[] = req.getParameterValues(param);
-            for (int i = 0; i < values.length; i++)
-                out.println("<li><b>parameter</b> " + param + " = " +
-                               values[i]);
-        }
-        out.println("<li><b>protocol</b> = " + req.getProtocol());
-        out.println("<li><b>remoteAddr</b> = " + req.getRemoteAddr());
-        out.println("<li><b>remoteHost</b> = " + req.getRemoteHost());
-        out.println("<li><b>scheme</b> = " + req.getScheme());
-        out.println("<li><b>secure</b> = " + req.isSecure());
-        out.println("<li><b>serverName</b> = " + req.getServerName());
-        out.println("<li><b>serverPort</b> = " + req.getServerPort());
-        out.println("</ul>");
-        out.println("<hr>");
-
-        // Document the properties from HttpServletRequest
-        out.println("<h1>HttpServletRequest Properties</h1>");
-        out.println("<ul>");
-        out.println("<li><b>authType</b> = " + req.getAuthType());
-        out.println("<li><b>contextPath</b> = " +
-                       req.getContextPath());
-        Cookie cookies[] = req.getCookies();
-        if (cookies!=null) {
-            for (int i = 0; i < cookies.length; i++)
-                out.println("<li><b>cookie</b> " + cookies[i].getName() +" = " +cookies[i].getValue());
-        }
-        Enumeration<String> headers = req.getHeaderNames();
-        while (headers.hasMoreElements()) {
-            String header = headers.nextElement();
-            out.println("<li><b>header</b> " + header + " = " +
-                           req.getHeader(header));
-        }
-        out.println("<li><b>method</b> = " + req.getMethod());
-        out.println("<li><a name=\"pathInfo\"><b>pathInfo</b></a> = "
-                    + req.getPathInfo());
-        out.println("<li><b>pathTranslated</b> = " +
-                       req.getPathTranslated());
-        out.println("<li><b>queryString</b> = " +
-                       req.getQueryString());
-        out.println("<li><b>remoteUser</b> = " +
-                       req.getRemoteUser());
-        out.println("<li><b>requestedSessionId</b> = " +
-                       req.getRequestedSessionId());
-        out.println("<li><b>requestedSessionIdFromCookie</b> = " +
-                       req.isRequestedSessionIdFromCookie());
-        out.println("<li><b>requestedSessionIdFromURL</b> = " +
-                       req.isRequestedSessionIdFromURL());
-        out.println("<li><b>requestedSessionIdValid</b> = " +
-                       req.isRequestedSessionIdValid());
-        out.println("<li><b>requestURI</b> = " +
-                       req.getRequestURI());
-        out.println("<li><b>servletPath</b> = " +
-                       req.getServletPath());
-        out.println("<li><b>userPrincipal</b> = " +
-                       req.getUserPrincipal());
-        out.println("</ul>");
-        out.println("<hr>");
-
-        // Document the servlet request attributes
-        out.println("<h1>ServletRequest Attributes</h1>");
-        out.println("<ul>");
-        attrs = req.getAttributeNames();
-        while (attrs.hasMoreElements()) {
-            String attr = attrs.nextElement();
-            out.println("<li><b>" + attr + "</b> = " +
-                           req.getAttribute(attr));
-        }
-        out.println("</ul>");
-        out.println("<hr>");
-
-        // Process the current session (if there is one)
-        HttpSession session = req.getSession(false);
-        if (session != null) {
-
-            // Document the session properties
-            out.println("<h1>HttpSession Properties</h1>");
-            out.println("<ul>");
-            out.println("<li><b>id</b> = " +
-                           session.getId());
-            out.println("<li><b>creationTime</b> = " +
-                           new Date(session.getCreationTime()));
-            out.println("<li><b>lastAccessedTime</b> = " +
-                           new Date(session.getLastAccessedTime()));
-            out.println("<li><b>maxInactiveInterval</b> = " +
-                           session.getMaxInactiveInterval());
-            out.println("</ul>");
-            out.println("<hr>");
-
-            // Document the session attributes
-            out.println("<h1>HttpSession Attributes</h1>");
-            out.println("<ul>");
-            attrs = session.getAttributeNames();
-            while (attrs.hasMoreElements()) {
-                String attr = attrs.nextElement();
-                out.println("<li><b>" + attr + "</b> = " +
-                               session.getAttribute(attr));
-            }
-            out.println("</ul>");
-            out.println("<hr>");
-
-        }
-
-        // Document the servlet configuration properties
-        out.println("<h1>ServletConfig Properties</h1>");
-        out.println("<ul>");
-        out.println("<li><b>servletName</b> = " +
-                       getServletConfig().getServletName());
-        out.println("</ul>");
-        out.println("<hr>");
-
-        // Document the servlet configuration initialization parameters
-        out.println("<h1>ServletConfig Initialization Parameters</h1>");
-        out.println("<ul>");
-        params = getServletConfig().getInitParameterNames();
-        while (params.hasMoreElements()) {
-            String param = params.nextElement();
-            String value = getServletConfig().getInitParameter(param);
-            out.println("<li><b>" + param + "</b> = " + value);
-        }
-        out.println("</ul>");
-        out.println("<hr>");
-
-        // Document the servlet context properties
-        out.println("<h1>ServletContext Properties</h1>");
-        out.println("<ul>");
-        out.println("<li><b>majorVersion</b> = " +
-                       getServletContext().getMajorVersion());
-        out.println("<li><b>minorVersion</b> = " +
-                       getServletContext().getMinorVersion());
-        out.println("<li><b>realPath('/')</b> = " +
-                       getServletContext().getRealPath("/"));
-        out.println("<li><b>serverInfo</b> = " +
-                       getServletContext().getServerInfo());
-        out.println("</ul>");
-        out.println("<hr>");
-
-        // Document the servlet context initialization parameters
-        out.println("<h1>ServletContext Initialization Parameters</h1>");
-        out.println("<ul>");
-        params = getServletContext().getInitParameterNames();
-        while (params.hasMoreElements()) {
-            String param = params.nextElement();
-            String value = getServletContext().getInitParameter(param);
-            out.println("<li><b>" + param + "</b> = " + value);
-        }
-        out.println("</ul>");
-        out.println("<hr>");
-
-        // Document the servlet context attributes
-        out.println("<h1>ServletContext Attributes</h1>");
-        out.println("<ul>");
-        attrs = getServletContext().getAttributeNames();
-        while (attrs.hasMoreElements()) {
-            String attr = attrs.nextElement();
-            out.println("<li><b>" + attr + "</b> = " +
-                           getServletContext().getAttribute(attr));
-        }
-        out.println("</ul>");
-        out.println("<hr>");
-
-
-    }
-
-
-    /**
-     * Provides CGI Gateway service -- delegates to <code>doGet</code>
-     *
-     * @param  req   HttpServletRequest passed in by servlet container
-     * @param  res   HttpServletResponse passed in by servlet container
-     *
-     * @exception  ServletException  if a servlet-specific exception occurs
-     * @exception  IOException  if a read/write exception occurs
-     *
-     * @see javax.servlet.http.HttpServlet
-     *
-     */
-    @Override
-    protected void doPost(HttpServletRequest req, HttpServletResponse res)
-        throws IOException, ServletException {
-        doGet(req, res);
-    }
-
-
-    /**
-     * Provides CGI Gateway service
-     *
-     * @param  req   HttpServletRequest passed in by servlet container
-     * @param  res   HttpServletResponse passed in by servlet container
-     *
-     * @exception  ServletException  if a servlet-specific exception occurs
-     * @exception  IOException  if a read/write exception occurs
-     *
-     * @see javax.servlet.http.HttpServlet
-     *
-     */
-    @Override
-    protected void doGet(HttpServletRequest req, HttpServletResponse res)
-        throws ServletException, IOException {
-
-        CGIEnvironment cgiEnv = new CGIEnvironment(req, getServletContext());
-
-        if (cgiEnv.isValid()) {
-            CGIRunner cgi = new CGIRunner(cgiEnv.getCommand(),
-                                          cgiEnv.getEnvironment(),
-                                          cgiEnv.getWorkingDirectory(),
-                                          cgiEnv.getParameters());
-            //if POST, we need to cgi.setInput
-            //REMIND: how does this interact with Servlet API 2.3's Filters?!
-            if ("POST".equals(req.getMethod())) {
-                cgi.setInput(req.getInputStream());
-            }
-            cgi.setResponse(res);
-            cgi.run();
-        }
-
-        if (!cgiEnv.isValid()) {
-            res.setStatus(404);
-        }
-
-        if (debug >= 10) {
-
-            ServletOutputStream out = res.getOutputStream();
-            out.println("<HTML><HEAD><TITLE>$Name$</TITLE></HEAD>");
-            out.println("<BODY>$Header$<p>");
-
-            if (cgiEnv.isValid()) {
-                out.println(cgiEnv.toString());
-            } else {
-                out.println("<H3>");
-                out.println("CGI script not found or not specified.");
-                out.println("</H3>");
-                out.println("<H4>");
-                out.println("Check the <b>HttpServletRequest ");
-                out.println("<a href=\"#pathInfo\">pathInfo</a></b> ");
-                out.println("property to see if it is what you meant ");
-                out.println("it to be.  You must specify an existant ");
-                out.println("and executable file as part of the ");
-                out.println("path-info.");
-                out.println("</H4>");
-                out.println("<H4>");
-                out.println("For a good discussion of how CGI scripts ");
-                out.println("work and what their environment variables ");
-                out.println("mean, please visit the <a ");
-                out.println("href=\"http://cgi-spec.golux.com\">CGI ");
-                out.println("Specification page</a>.");
-                out.println("</H4>");
-
-            }
-
-            printServletEnvironment(out, req, res);
-
-            out.println("</BODY></HTML>");
-
-        }
-
-
-    } //doGet
-
-
-    /**
-     * Encapsulates the CGI environment and rules to derive
-     * that environment from the servlet container and request information.
-     *
-     * <p>
-     * </p>
-     *
-     * @version  $Id$
-     * @since    Tomcat 4.0
-     *
-     */
-    protected class CGIEnvironment {
-
-
-        /** context of the enclosing servlet */
-        private ServletContext context = null;
-
-        /** context path of enclosing servlet */
-        private String contextPath = null;
-
-        /** servlet URI of the enclosing servlet */
-        private String servletPath = null;
-
-        /** pathInfo for the current request */
-        private String pathInfo = null;
-
-        /** real file system directory of the enclosing servlet's web app */
-        private String webAppRootDir = null;
-
-        /** tempdir for context - used to expand scripts in unexpanded wars */
-        private File tmpDir = null;
-
-        /** derived cgi environment */
-        private Hashtable<String, String> env = null;
-
-        /** cgi command to be invoked */
-        private String command = null;
-
-        /** cgi command's desired working directory */
-        private File workingDirectory = null;
-
-        /** cgi command's command line parameters */
-        private ArrayList<String> cmdLineParameters = new ArrayList<String>();
-
-        /** whether or not this object is valid or not */
-        private boolean valid = false;
-
-
-        /**
-         * Creates a CGIEnvironment and derives the necessary environment,
-         * query parameters, working directory, cgi command, etc.
-         *
-         * @param  req       HttpServletRequest for information provided by
-         *                   the Servlet API
-         * @param  context   ServletContext for information provided by the
-         *                   Servlet API
-         *
-         */
-        protected CGIEnvironment(HttpServletRequest req,
-                                 ServletContext context) throws IOException {
-            setupFromContext(context);
-            setupFromRequest(req);
-
-            this.valid = setCGIEnvironment(req);
-
-            if (this.valid) {
-                workingDirectory = new File(command.substring(0,
-                      command.lastIndexOf(File.separator)));
-            }
-
-        }
-
-
-        /**
-         * Uses the ServletContext to set some CGI variables
-         *
-         * @param  context   ServletContext for information provided by the
-         *                   Servlet API
-         */
-        protected void setupFromContext(ServletContext context) {
-            this.context = context;
-            this.webAppRootDir = context.getRealPath("/");
-            this.tmpDir = (File) context.getAttribute(System.getProperty("java.io.tmpdir"));
-        }
-
-
-        /**
-         * Uses the HttpServletRequest to set most CGI variables
-         *
-         * @param  req   HttpServletRequest for information provided by
-         *               the Servlet API
-         * @throws UnsupportedEncodingException
-         */
-        protected void setupFromRequest(HttpServletRequest req)
-                throws UnsupportedEncodingException {
-
-            boolean isIncluded = false;
-
-            // Look to see if this request is an include
-            if (req.getAttribute(Globals.INCLUDE_REQUEST_URI_ATTR) != null) {
-                isIncluded = true;
-            }
-            if (isIncluded) {
-                this.contextPath = (String) req.getAttribute(
-                        Globals.INCLUDE_CONTEXT_PATH_ATTR);
-                this.servletPath = (String) req.getAttribute(
-                        Globals.INCLUDE_SERVLET_PATH_ATTR);
-                this.pathInfo = (String) req.getAttribute(
-                        Globals.INCLUDE_PATH_INFO_ATTR);
-            } else {
-                this.contextPath = req.getContextPath();
-                this.servletPath = req.getServletPath();
-                this.pathInfo = req.getPathInfo();
-            }
-            // If getPathInfo() returns null, must be using extension mapping
-            // In this case, pathInfo should be same as servletPath
-            if (this.pathInfo == null) {
-                this.pathInfo = this.servletPath;
-            }
-
-            // If the request method is GET, POST or HEAD and the query string
-            // does not contain an unencoded "=" this is an indexed query.
-            // The parsed query string becomes the command line parameters
-            // for the cgi command.
-            if (req.getMethod().equals("GET")
-                || req.getMethod().equals("POST")
-                || req.getMethod().equals("HEAD")) {
-                String qs;
-                if (isIncluded) {
-                    qs = (String) req.getAttribute(
-                            Globals.INCLUDE_QUERY_STRING_ATTR);
-                } else {
-                    qs = req.getQueryString();
-                }
-                if (qs != null && qs.indexOf("=") == -1) {
-                    StringTokenizer qsTokens = new StringTokenizer(qs, "+");
-                    while ( qsTokens.hasMoreTokens() ) {
-                        cmdLineParameters.add(URLDecoder.decode(qsTokens.nextToken(),
-                                              parameterEncoding));
-                    }
-                }
-            }
-        }
-
-
-        /**
-         * Resolves core information about the cgi script.
-         *
-         * <p>
-         * Example URI:
-         * <PRE> /servlet/cgigateway/dir1/realCGIscript/pathinfo1 </PRE>
-         * <ul>
-         * <LI><b>path</b> = $CATALINA_HOME/mywebapp/dir1/realCGIscript
-         * <LI><b>scriptName</b> = /servlet/cgigateway/dir1/realCGIscript
-         * <LI><b>cgiName</b> = /dir1/realCGIscript
-         * <LI><b>name</b> = realCGIscript
-         * </ul>
-         * </p>
-         * <p>
-         * CGI search algorithm: search the real path below
-         *    &lt;my-webapp-root&gt; and find the first non-directory in
-         *    the getPathTranslated("/"), reading/searching from left-to-right.
-         *</p>
-         *<p>
-         *   The CGI search path will start at
-         *   webAppRootDir + File.separator + cgiPathPrefix
-         *   (or webAppRootDir alone if cgiPathPrefix is
-         *   null).
-         *</p>
-         *<p>
-         *   cgiPathPrefix is defined by setting
-         *   this servlet's cgiPathPrefix init parameter
-         *
-         *</p>
-         *
-         * @param pathInfo       String from HttpServletRequest.getPathInfo()
-         * @param webAppRootDir  String from context.getRealPath("/")
-         * @param contextPath    String as from
-         *                       HttpServletRequest.getContextPath()
-         * @param servletPath    String as from
-         *                       HttpServletRequest.getServletPath()
-         * @param cgiPathPrefix  subdirectory of webAppRootDir below which
-         *                       the web app's CGIs may be stored; can be null.
-         *                       The CGI search path will start at
-         *                       webAppRootDir + File.separator + cgiPathPrefix
-         *                       (or webAppRootDir alone if cgiPathPrefix is
-         *                       null).  cgiPathPrefix is defined by setting
-         *                       the servlet's cgiPathPrefix init parameter.
-         *
-         *
-         * @return
-         * <ul>
-         * <li>
-         * <code>path</code> -    full file-system path to valid cgi script,
-         *                        or null if no cgi was found
-         * <li>
-         * <code>scriptName</code> -
-         *                        CGI variable SCRIPT_NAME; the full URL path
-         *                        to valid cgi script or null if no cgi was
-         *                        found
-         * <li>
-         * <code>cgiName</code> - servlet pathInfo fragment corresponding to
-         *                        the cgi script itself, or null if not found
-         * <li>
-         * <code>name</code> -    simple name (no directories) of the
-         *                        cgi script, or null if no cgi was found
-         * </ul>
-         *
-         * @since Tomcat 4.0
-         */
-        protected String[] findCGI(String pathInfo, String webAppRootDir,
-                                   String contextPath, String servletPath,
-                                   String cgiPathPrefix) {
-            String path = null;
-            String name = null;
-            String scriptname = null;
-            String cginame = "";
-
-            if ((webAppRootDir != null)
-                && (webAppRootDir.lastIndexOf(File.separator) ==
-                    (webAppRootDir.length() - 1))) {
-                    //strip the trailing "/" from the webAppRootDir
-                    webAppRootDir =
-                    webAppRootDir.substring(0, (webAppRootDir.length() - 1));
-            }
-
-            if (cgiPathPrefix != null) {
-                webAppRootDir = webAppRootDir + File.separator
-                    + cgiPathPrefix;
-            }
-
-            if (debug >= 2) {
-                log("findCGI: path=" + pathInfo + ", " + webAppRootDir);
-            }
-
-            File currentLocation = new File(webAppRootDir);
-            StringTokenizer dirWalker =
-            new StringTokenizer(pathInfo, "/");
-            if (debug >= 3) {
-                log("findCGI: currentLoc=" + currentLocation);
-            }
-            while (!currentLocation.isFile() && dirWalker.hasMoreElements()) {
-                if (debug >= 3) {
-                    log("findCGI: currentLoc=" + currentLocation);
-                }
-                String nextElement = (String) dirWalker.nextElement();
-                currentLocation = new File(currentLocation, nextElement);
-                cginame = cginame + "/" + nextElement;
-            }
-            if (!currentLocation.isFile()) {
-                return new String[] { null, null, null, null };
-            }
-
-            if (debug >= 2) {
-                log("findCGI: FOUND cgi at " + currentLocation);
-            }
-            path = currentLocation.getAbsolutePath();
-            name = currentLocation.getName();
-
-            if (".".equals(contextPath)) {
-                scriptname = servletPath;
-            } else {
-                scriptname = contextPath + servletPath;
-            }
-            if (!servletPath.equals(cginame)) {
-                scriptname = scriptname + cginame;
-            }
-
-            if (debug >= 1) {
-                log("findCGI calc: name=" + name + ", path=" + path
-                    + ", scriptname=" + scriptname + ", cginame=" + cginame);
-            }
-            return new String[] { path, scriptname, cginame, name };
-        }
-
-        /**
-         * Constructs the CGI environment to be supplied to the invoked CGI
-         * script; relies heavily on Servlet API methods and findCGI
-         *
-         * @param    req request associated with the CGI
-         *           Invocation
-         *
-         * @return   true if environment was set OK, false if there
-         *           was a problem and no environment was set
-         */
-        protected boolean setCGIEnvironment(HttpServletRequest req) throws IOException {
-
-            /*
-             * This method is slightly ugly; c'est la vie.
-             * "You cannot stop [ugliness], you can only hope to contain [it]"
-             * (apologies to Marv Albert regarding MJ)
-             */
-
-            Hashtable<String,String> envp = new Hashtable<String,String>();
-
-            // Add the shell environment variables (if any)
-            envp.putAll(shellEnv);
-
-            // Add the CGI environment variables
-            String sPathInfoOrig = null;
-            String sPathInfoCGI = null;
-            String sPathTranslatedCGI = null;
-            String sCGIFullPath = null;
-            String sCGIScriptName = null;
-            String sCGIFullName = null;
-            String sCGIName = null;
-            String[] sCGINames;
-
-
-            sPathInfoOrig = this.pathInfo;
-            sPathInfoOrig = sPathInfoOrig == null ? "" : sPathInfoOrig;
-
-            if (webAppRootDir == null ) {
-                // The app has not been deployed in exploded form
-                webAppRootDir = tmpDir.toString();
-                expandCGIScript();
-            }
-
-            sCGINames = findCGI(sPathInfoOrig,
-                                webAppRootDir,
-                                contextPath,
-                                servletPath,
-                                cgiPathPrefix);
-
-            sCGIFullPath = sCGINames[0];
-            sCGIScriptName = sCGINames[1];
-            sCGIFullName = sCGINames[2];
-            sCGIName = sCGINames[3];
-
-            if (sCGIFullPath == null
-                || sCGIScriptName == null
-                || sCGIFullName == null
-                || sCGIName == null) {
-                return false;
-            }
-
-            envp.put("SERVER_SOFTWARE", "TOMCAT");
-
-            envp.put("SERVER_NAME", nullsToBlanks(req.getServerName()));
-
-            envp.put("GATEWAY_INTERFACE", "CGI/1.1");
-
-            envp.put("SERVER_PROTOCOL", nullsToBlanks(req.getProtocol()));
-
-            int port = req.getServerPort();
-            Integer iPort =
-                (port == 0 ? Integer.valueOf(-1) : Integer.valueOf(port));
-            envp.put("SERVER_PORT", iPort.toString());
-
-            envp.put("REQUEST_METHOD", nullsToBlanks(req.getMethod()));
-
-            envp.put("REQUEST_URI", nullsToBlanks(req.getRequestURI()));
-
-
-            /*-
-             * PATH_INFO should be determined by using sCGIFullName:
-             * 1) Let sCGIFullName not end in a "/" (see method findCGI)
-             * 2) Let sCGIFullName equal the pathInfo fragment which
-             *    corresponds to the actual cgi script.
-             * 3) Thus, PATH_INFO = request.getPathInfo().substring(
-             *                      sCGIFullName.length())
-             *
-             * (see method findCGI, where the real work is done)
-             *
-             */
-            if (pathInfo == null
-                || (pathInfo.substring(sCGIFullName.length()).length() <= 0)) {
-                sPathInfoCGI = "";
-            } else {
-                sPathInfoCGI = pathInfo.substring(sCGIFullName.length());
-            }
-            envp.put("PATH_INFO", sPathInfoCGI);
-
-
-            /*-
-             * PATH_TRANSLATED must be determined after PATH_INFO (and the
-             * implied real cgi-script) has been taken into account.
-             *
-             * The following example demonstrates:
-             *
-             * servlet info   = /servlet/cgigw/dir1/dir2/cgi1/trans1/trans2
-             * cgifullpath    = /servlet/cgigw/dir1/dir2/cgi1
-             * path_info      = /trans1/trans2
-             * webAppRootDir  = servletContext.getRealPath("/")
-             *
-             * path_translated = servletContext.getRealPath("/trans1/trans2")
-             *
-             * That is, PATH_TRANSLATED = webAppRootDir + sPathInfoCGI
-             * (unless sPathInfoCGI is null or blank, then the CGI
-             * specification dictates that the PATH_TRANSLATED metavariable
-             * SHOULD NOT be defined.
-             *
-             */
-            if (sPathInfoCGI != null && !("".equals(sPathInfoCGI))) {
-                sPathTranslatedCGI = context.getRealPath(sPathInfoCGI);
-            }
-            if (sPathTranslatedCGI == null || "".equals(sPathTranslatedCGI)) {
-                //NOOP
-            } else {
-                envp.put("PATH_TRANSLATED", nullsToBlanks(sPathTranslatedCGI));
-            }
-
-
-            envp.put("SCRIPT_NAME", nullsToBlanks(sCGIScriptName));
-
-            envp.put("QUERY_STRING", nullsToBlanks(req.getQueryString()));
-
-            envp.put("REMOTE_HOST", nullsToBlanks(req.getRemoteHost()));
-
-            envp.put("REMOTE_ADDR", nullsToBlanks(req.getRemoteAddr()));
-
-            envp.put("AUTH_TYPE", nullsToBlanks(req.getAuthType()));
-
-            envp.put("REMOTE_USER", nullsToBlanks(req.getRemoteUser()));
-
-            envp.put("REMOTE_IDENT", ""); //not necessary for full compliance
-
-            envp.put("CONTENT_TYPE", nullsToBlanks(req.getContentType()));
-
-
-            /* Note CGI spec says CONTENT_LENGTH must be NULL ("") or undefined
-             * if there is no content, so we cannot put 0 or -1 in as per the
-             * Servlet API spec.
-             */
-            int contentLength = req.getContentLength();
-            String sContentLength = (contentLength <= 0 ? "" :
-                (Integer.valueOf(contentLength)).toString());
-            envp.put("CONTENT_LENGTH", sContentLength);
-
-
-            Enumeration<String> headers = req.getHeaderNames();
-            String header = null;
-            while (headers.hasMoreElements()) {
-                header = null;
-                header = headers.nextElement().toUpperCase(Locale.ENGLISH);
-                //REMIND: rewrite multiple headers as if received as single
-                //REMIND: change character set
-                //REMIND: I forgot what the previous REMIND means
-                if ("AUTHORIZATION".equalsIgnoreCase(header) ||
-                    "PROXY_AUTHORIZATION".equalsIgnoreCase(header)) {
-                    //NOOP per CGI specification section 11.2
-                } else {
-                    envp.put("HTTP_" + header.replace('-', '_'),
-                             req.getHeader(header));
-                }
-            }
-
-            File fCGIFullPath = new File(sCGIFullPath);
-            command = fCGIFullPath.getCanonicalPath();
-
-            envp.put("X_TOMCAT_SCRIPT_PATH", command);  //for kicks
-
-            envp.put("SCRIPT_FILENAME", command);  //for PHP
-
-            this.env = envp;
-
-            return true;
-
-        }
-
-        /**
-         * Extracts requested resource from web app archive to context work
-         * directory to enable CGI script to be executed.
-         */
-        protected void expandCGIScript() {
-            StringBuilder srcPath = new StringBuilder();
-            StringBuilder destPath = new StringBuilder();
-            InputStream is = null;
-
-            // paths depend on mapping
-            if (cgiPathPrefix == null ) {
-                srcPath.append(pathInfo);
-                is = context.getResourceAsStream(srcPath.toString());
-                destPath.append(tmpDir);
-                destPath.append(pathInfo);
-            } else {
-                // essentially same search algorithm as findCGI()
-                srcPath.append(cgiPathPrefix);
-                StringTokenizer pathWalker =
-                        new StringTokenizer (pathInfo, "/");
-                // start with first element
-                while (pathWalker.hasMoreElements() && (is == null)) {
-                    srcPath.append("/");
-                    srcPath.append(pathWalker.nextElement());
-                    is = context.getResourceAsStream(srcPath.toString());
-                }
-                destPath.append(tmpDir);
-                destPath.append("/");
-                destPath.append(srcPath);
-            }
-
-            if (is == null) {
-                // didn't find anything, give up now
-                if (debug >= 2) {
-                    log("expandCGIScript: source '" + srcPath + "' not found");
-                }
-                 return;
-            }
-
-            File f = new File(destPath.toString());
-            if (f.exists()) {
-                // Don't need to expand if it already exists
-                return;
-            }
-
-            // create directories
-            String dirPath = destPath.toString().substring(
-                    0,destPath.toString().lastIndexOf("/"));
-            File dir = new File(dirPath);
-            if (!dir.mkdirs() && debug >= 2) {
-                log("expandCGIScript: failed to create directories for '" +
-                        dir.getAbsolutePath() + "'");
-                return;
-            }
-
-            try {
-                synchronized (expandFileLock) {
-                    // make sure file doesn't exist
-                    if (f.exists()) {
-                        return;
-                    }
-
-                    // create file
-                    if (!f.createNewFile()) {
-                        return;
-                    }
-                    FileOutputStream fos = new FileOutputStream(f);
-
-                    // copy data
-                    Util.copy(is, fos);
-                    is.close();
-                    fos.close();
-                    if (debug >= 2) {
-                        log("expandCGIScript: expanded '" + srcPath + "' to '" + destPath + "'");
-                    }
-                }
-            } catch (IOException ioe) {
-                // delete in case file is corrupted
-                if (f.exists()) {
-                    if (!f.delete() && debug >= 2) {
-                        log("expandCGIScript: failed to delete '" +
-                                f.getAbsolutePath() + "'");
-                    }
-                }
-            }
-        }
-
-
-        /**
-         * Print important CGI environment information in a easy-to-read HTML
-         * table
-         *
-         * @return  HTML string containing CGI environment info
-         *
-         */
-        @Override
-        public String toString() {
-
-            StringBuilder sb = new StringBuilder();
-
-            sb.append("<TABLE border=2>");
-
-            sb.append("<tr><th colspan=2 bgcolor=grey>");
-            sb.append("CGIEnvironment Info</th></tr>");
-
-            sb.append("<tr><td>Debug Level</td><td>");
-            sb.append(debug);
-            sb.append("</td></tr>");
-
-            sb.append("<tr><td>Validity:</td><td>");
-            sb.append(isValid());
-            sb.append("</td></tr>");
-
-            if (isValid()) {
-                Enumeration<String> envk = env.keys();
-                while (envk.hasMoreElements()) {
-                    String s = envk.nextElement();
-                    sb.append("<tr><td>");
-                    sb.append(s);
-                    sb.append("</td><td>");
-                    sb.append(blanksToString(env.get(s),
-                                             "[will be set to blank]"));
-                    sb.append("</td></tr>");
-                }
-            }
-
-            sb.append("<tr><td colspan=2><HR></td></tr>");
-
-            sb.append("<tr><td>Derived Command</td><td>");
-            sb.append(nullsToBlanks(command));
-            sb.append("</td></tr>");
-
-            sb.append("<tr><td>Working Directory</td><td>");
-            if (workingDirectory != null) {
-                sb.append(workingDirectory.toString());
-            }
-            sb.append("</td></tr>");
-
-            sb.append("<tr><td>Command Line Params</td><td>");
-            for (int i=0; i < cmdLineParameters.size(); i++) {
-                String param = cmdLineParameters.get(i);
-                sb.append("<p>");
-                sb.append(param);
-                sb.append("</p>");
-            }
-            sb.append("</td></tr>");
-
-            sb.append("</TABLE><p>end.");
-
-            return sb.toString();
-        }
-
-
-        /**
-         * Gets derived command string
-         *
-         * @return  command string
-         *
-         */
-        protected String getCommand() {
-            return command;
-        }
-
-
-        /**
-         * Gets derived CGI working directory
-         *
-         * @return  working directory
-         *
-         */
-        protected File getWorkingDirectory() {
-            return workingDirectory;
-        }
-
-
-        /**
-         * Gets derived CGI environment
-         *
-         * @return   CGI environment
-         *
-         */
-        protected Hashtable<String,String> getEnvironment() {
-            return env;
-        }
-
-
-        /**
-         * Gets derived CGI query parameters
-         *
-         * @return   CGI query parameters
-         *
-         */
-        protected ArrayList<String> getParameters() {
-            return cmdLineParameters;
-        }
-
-
-        /**
-         * Gets validity status
-         *
-         * @return   true if this environment is valid, false
-         *           otherwise
-         *
-         */
-        protected boolean isValid() {
-            return valid;
-        }
-
-
-        /**
-         * Converts null strings to blank strings ("")
-         *
-         * @param    s string to be converted if necessary
-         * @return   a non-null string, either the original or the empty string
-         *           ("") if the original was <code>null</code>
-         */
-        protected String nullsToBlanks(String s) {
-            return nullsToString(s, "");
-        }
-
-
-        /**
-         * Converts null strings to another string
-         *
-         * @param    couldBeNull string to be converted if necessary
-         * @param    subForNulls string to return instead of a null string
-         * @return   a non-null string, either the original or the substitute
-         *           string if the original was <code>null</code>
-         */
-        protected String nullsToString(String couldBeNull,
-                                       String subForNulls) {
-            return (couldBeNull == null ? subForNulls : couldBeNull);
-        }
-
-
-        /**
-         * Converts blank strings to another string
-         *
-         * @param    couldBeBlank string to be converted if necessary
-         * @param    subForBlanks string to return instead of a blank string
-         * @return   a non-null string, either the original or the substitute
-         *           string if the original was <code>null</code> or empty ("")
-         */
-        protected String blanksToString(String couldBeBlank,
-                                      String subForBlanks) {
-            return (("".equals(couldBeBlank) || couldBeBlank == null)
-                    ? subForBlanks
-                    : couldBeBlank);
-        }
-
-
-    } //class CGIEnvironment
-
-
-    /**
-     * Encapsulates the knowledge of how to run a CGI script, given the
-     * script's desired environment and (optionally) input/output streams
-     *
-     * <p>
-     *
-     * Exposes a <code>run</code> method used to actually invoke the
-     * CGI.
-     *
-     * </p>
-     * <p>
-     *
-     * The CGI environment and settings are derived from the information
-     * passed to the constructor.
-     *
-     * </p>
-     * <p>
-     *
-     * The input and output streams can be set by the <code>setInput</code>
-     * and <code>setResponse</code> methods, respectively.
-     * </p>
-     *
-     * @version $Id$
-     */
-
-    protected class CGIRunner {
-
-        /** script/command to be executed */
-        private String command = null;
-
-        /** environment used when invoking the cgi script */
-        private Hashtable<String,String> env = null;
-
-        /** working directory used when invoking the cgi script */
-        private File wd = null;
-
-        /** command line parameters to be passed to the invoked script */
-        private ArrayList<String> params = null;
-
-        /** stdin to be passed to cgi script */
-        private InputStream stdin = null;
-
-        /** response object used to set headers & get output stream */
-        private HttpServletResponse response = null;
-
-        /** boolean tracking whether this object has enough info to run() */
-        private boolean readyToRun = false;
-
-
-        /**
-         *  Creates a CGIRunner and initializes its environment, working
-         *  directory, and query parameters.
-         *  <BR>
-         *  Input/output streams (optional) are set using the
-         *  <code>setInput</code> and <code>setResponse</code> methods,
-         *  respectively.
-         *
-         * @param  command  string full path to command to be executed
-         * @param  env      Hashtable with the desired script environment
-         * @param  wd       File with the script's desired working directory
-         * @param  params   ArrayList with the script's query command line
-         *                  parameters as strings
-         */
-        protected CGIRunner(String command, Hashtable<String,String> env,
-                            File wd, ArrayList<String> params) {
-            this.command = command;
-            this.env = env;
-            this.wd = wd;
-            this.params = params;
-            updateReadyStatus();
-        }
-
-
-        /**
-         * Checks & sets ready status
-         */
-        protected void updateReadyStatus() {
-            if (command != null
-                && env != null
-                && wd != null
-                && params != null
-                && response != null) {
-                readyToRun = true;
-            } else {
-                readyToRun = false;
-            }
-        }
-
-
-        /**
-         * Gets ready status
-         *
-         * @return   false if not ready (<code>run</code> will throw
-         *           an exception), true if ready
-         */
-        protected boolean isReady() {
-            return readyToRun;
-        }
-
-
-        /**
-         * Sets HttpServletResponse object used to set headers and send
-         * output to
-         *
-         * @param  response   HttpServletResponse to be used
-         *
-         */
-        protected void setResponse(HttpServletResponse response) {
-            this.response = response;