amyroh 01/05/31 17:20:21
Added: catalina/src/share/org/apache/catalina/servlets
CGIServlet.java
Log:
Add CGI servlet submitted by Martin Dengler.
Revision Changes Path
1.1
jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/CGIServlet.java
Index: CGIServlet.java
===================================================================
/*
* CGIServlet.java $Header:
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/CGIServlet.java,v
1.1 2001/06/01 00:20:19 amyroh Exp $
* $Revision: 1.1 $, $Date: 2001/06/01 00:20:19 $
*
* ====================================================================
*
* 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 [EMAIL PROTECTED]
*
* 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/>.
*
*
*/
package org.apache.catalina.servlets;
import java.lang.Process;
import java.io.File;
import java.io.Writer;
import java.io.Reader;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Hashtable;
import java.util.Vector;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Locale;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletContext;
import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Cookie;
import org.apache.catalina.Context;
import org.apache.catalina.Wrapper;
// import org.apache.catalina.util.StringManager;
/**
* 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><web-app>/WEB-INF/web.xml</code>) to:
* </p>
* <p>
* <code>
* <web-app>/cgi-bin/*
* </code>
* </p>
* <p>
* then the following request:
* </p>
* <p>
* <code>
* http://localhost:8080/<web-app>/cgi-bin/dir1/script/pathinfo1
* </code>
* </p>
* <p>
* would result in the execution of the script
* </p>
* <p>
* <code>
* <web-app-root>/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><webapp>/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:[EMAIL PROTECTED]">Jakarta Tomcat group
[[EMAIL PROTECTED]]</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 specificion,
* 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 preceisely 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 [[EMAIL PROTECTED]]
* @author Amy Roh
* @version $Revision: 1.1 $, $Date: 2001/06/01 00:20:19 $
* @since Tomcat 4.0
*
*/
public class CGIServlet extends HttpServlet {
/* some vars below copied from Craig R. McClanahan's InvokerServlet */
/** the string manager for this package. */
/* YAGNI
private static StringManager sm =
StringManager.getManager(Constants.Package);
*/
/** the Context container associated with our web application. */
private ServletContext context = null;
/** the debugging detail level for this servlet. */
private int debug = 0;
/** the time in ms to wait for the client to send us CGI input data */
private int iClientInputTimeout = 100;
/**
* The CGI search path will start at
* webAppRootDir + File.separator + cgiPathPrefix
* (or webAppRootDir alone if cgiPathPrefix is
* null)
*/
private String cgiPathPrefix = null;
/**
* 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
*/
public void init(ServletConfig config) throws ServletException {
super.init(config);
// Set our properties from the initialization parameters
String value = null;
try {
value = getServletConfig().getInitParameter("debug");
debug = Integer.parseInt(value);
cgiPathPrefix =
getServletConfig().getInitParameter("cgiPathPrefix");
value =
getServletConfig().getInitParameter("iClientInputTimeout");
iClientInputTimeout = Integer.parseInt(value);
} catch (Throwable t) {
//NOOP
}
log("init: loglevel set to " + debug);
// Identify the internal container resources we need
//Wrapper wrapper = (Wrapper) getServletConfig();
//context = (Context) wrapper.getParent();
context = config.getServletContext();
if (debug >= 1) {
//log("init: Associated with Context '" + context.getPath() + "'");
}
}
/**
* 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, HttpServletResponse res) throws IOException {
// Document the properties from ServletRequest
out.println("<h1>ServletRequest Properties</h1>");
out.println("<ul>");
Enumeration attrs = req.getAttributeNames();
while (attrs.hasMoreElements()) {
String attr = (String) 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 locales = req.getLocales();
while (locales.hasMoreElements()) {
Locale locale = (Locale) locales.nextElement();
out.println("<li><b>locale</b> = " + locale);
}
Enumeration params = req.getParameterNames();
while (params.hasMoreElements()) {
String param = (String) 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 headers = req.getHeaderNames();
while (headers.hasMoreElements()) {
String header = (String) 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 = (String) 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 = (String) 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 = (String) 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 = (String) 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 = (String) 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
*
*/
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
*
*/
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();
}
//REMIND: change to debug method or something
if ((req.getParameter("X_TOMCAT_CGI_DEBUG") != null)
|| (!cgiEnv.isValid())) {
try {
ServletOutputStream out = res.getOutputStream();
out.println("<HTML><HEAD><TITLE>$Name: $</TITLE></HEAD>");
out.println("<BODY>$Header:
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/CGIServlet.java,v
1.1 2001/06/01 00:20:19 amyroh Exp $<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>");
} catch (IOException ignored) {
}
} //debugging
} //doGet
/** For future testing use only; does nothing right now */
public static void main(String[] args) {
System.out.println("$Header:
/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/servlets/CGIServlet.java,v
1.1 2001/06/01 00:20:19 amyroh Exp $");
}
/**
* Encapsulates the CGI environment and rules to derive
* that environment from the servlet container and request information.
*
* <p>
* </p>
*
* @author Martin Dengler [[EMAIL PROTECTED]]
* @version $Revision: 1.1 $, $Date: 2001/06/01 00:20:19 $
* @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;
/** derived cgi environment */
private Hashtable env = null;
/** cgi command to be invoked */
private String command = null;
/** cgi command's desired working directory */
private File workingDirectory = null;
/** cgi command's query parameters */
private Hashtable queryParameters = null;
/** 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) {
setupFromContext(context);
setupFromRequest(req);
queryParameters = new Hashtable();
Enumeration paramNames = req.getParameterNames();
while (paramNames != null && paramNames.hasMoreElements()) {
String param = paramNames.nextElement().toString();
if (param != null) {
queryParameters.put(
param, URLEncoder.encode(req.getParameter(param)));
}
}
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("/");
}
/**
* Uses the HttpServletRequest to set most CGI variables
*
* @param req HttpServletRequest for information provided by
* the Servlet API
*/
protected void setupFromRequest(HttpServletRequest req) {
this.contextPath = req.getContextPath();
this.pathInfo = req.getPathInfo();
this.servletPath = req.getServletPath();
}
/**
* Resolves core information about the cgi script.
*
* <p>
* Example URI:
* <PRE> /servlet/cgigateway/dir1/realCGIscript/pathinfo1 </PRE>
* <ul>
* <LI><b>path</b> = $TOMCAT_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
* <my-webapp-root> 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>
*
* @author Martin Dengler [[EMAIL PROTECTED]]
* @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 = null;
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, File.separator);
if (debug >= 3) {
log("findCGI: currentLoc=" + currentLocation);
}
while (!currentLocation.isFile() && dirWalker.hasMoreElements()) {
if (debug >= 3) {
log("findCGI: currentLoc=" + currentLocation);
}
currentLocation = new File(currentLocation,
(String) dirWalker.nextElement());
}
if (!currentLocation.isFile()) {
return new String[] { null, null, null, null };
} else {
if (debug >= 2) {
log("findCGI: FOUND cgi at " + currentLocation);
}
path = currentLocation.getAbsolutePath();
name = currentLocation.getName();
cginame =
currentLocation.getParent().substring(webAppRootDir.length())
+ File.separator
+ name;
if (".".equals(contextPath)) {
scriptname = servletPath + cginame;
} else {
scriptname = contextPath + servletPath + 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 heavliy on Servlet API methods and findCGI
*
* @param HttpServletRequest request associated with the CGI
* invokation
*
* @return true if environment was set OK, false if there
* was a problem and no environment was set
*/
protected boolean setCGIEnvironment(HttpServletRequest req) {
/*
* 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 envp = new Hashtable();
String sPathInfoOrig = null;
String sPathTranslatedOrig = 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;
sPathTranslatedOrig = req.getPathTranslated();
sPathTranslatedOrig =
sPathTranslatedOrig == null ? "" : sPathTranslatedOrig;
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 ? new Integer(-1) : new Integer(port));
envp.put("SERVER_PORT", iPort.toString());
envp.put("REQUEST_METHOD", nullsToBlanks(req.getMethod()));
/*-
* 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);
} else {
sPathTranslatedCGI = null;
}
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 ? "" :
(new Integer(contentLength)).toString());
envp.put("CONTENT_LENGTH", sContentLength);
Enumeration headers = req.getHeaderNames();
String header = null;
while (headers.hasMoreElements()) {
header = null;
header = ((String) headers.nextElement()).toUpperCase();
//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 if("HOST".equalsIgnoreCase(header)) {
String host = req.getHeader(header);
envp.put("HTTP_" + header.replace('-', '_'),
host.substring(0, host.indexOf(":")));
} else {
envp.put("HTTP_" + header.replace('-', '_'),
req.getHeader(header));
}
}
command = sCGIFullPath;
envp.put("X_TOMCAT_SCRIPT_PATH", command); //for kicks
this.env = envp;
return true;
}
/**
* Print important CGI environment information in a easy-to-read HTML
* table
*
* @return HTML string containing CGI environment info
*
*/
public String toString() {
StringBuffer sb = new StringBuffer();
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 envk = env.keys();
while (envk.hasMoreElements()) {
String s = (String) envk.nextElement();
sb.append("<tr><td>");
sb.append(s);
sb.append("</td><td>");
sb.append(blanksToString((String) 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 colspan=2>Query Params</td></tr>");
Enumeration paramk = queryParameters.keys();
while (paramk.hasMoreElements()) {
String s = paramk.nextElement().toString();
sb.append("<tr><td>");
sb.append(s);
sb.append("</td><td>");
sb.append(queryParameters.get(s).toString());
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 getEnvironment() {
return env;
}
/**
* Gets derived CGI query parameters
*
* @return CGI query parameters
*
*/
protected Hashtable getParameters() {
return queryParameters;
}
/**
* Gets validity status
*
* @return true if this environment is valid, false
* otherwise
*
*/
protected boolean isValid() {
return valid;
}
/**
* Converts null strings to blank strings ("")
*
* @param 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 string to be converted if necessary
* @param 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 string to be converted if necessary
* @param 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 constuctor.
*
* </p>
* <p>
*
* The input and output streams can be set by the <code>setInput</code>
* and <code>setResponse</code> methods, respectively.
* </p>
*
* @author Martin Dengler [[EMAIL PROTECTED]]
* @version $Revision: 1.1 $, $Date: 2001/06/01 00:20:19 $
*/
protected class CGIRunner {
/** script/command to be executed */
private String command = null;
/** environment used when invoking the cgi script */
private Hashtable env = null;
/** working directory used when invoking the cgi script */
private File wd = null;
/** query parameters to be passed to the invoked script */
private Hashtable 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 Hashtable with the script's query parameters
*
* @param res HttpServletResponse object for setting headers
* based on CGI script output
*
*/
protected CGIRunner(String command, Hashtable env, File wd,
Hashtable 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;
updateReadyStatus();
}
/**
* Sets standard input to be passed on to the invoked cgi script
*
* @param stdin InputStream to be used
*
*/
protected void setInput(InputStream stdin) {
this.stdin = stdin;
updateReadyStatus();
}
/**
* Converts a Hashtable to a String array by converting each
* key/value pair in the Hashtable to a String in the form
* "key=value" (hashkey + "=" + hash.get(hashkey).toString())
*
* @param h Hashtable to convert
*
* @return converted string array
*
* @exception NullPointerException if a hash key has a null value
*
*/
protected String[] hashToStringArray(Hashtable h)
throws NullPointerException {
Vector v = new Vector();
Enumeration e = h.keys();
while (e.hasMoreElements()) {
String k = e.nextElement().toString();
v.add(k + "=" + h.get(k));
}
String[] strArr = new String[v.size()];
v.copyInto(strArr);
return strArr;
}
/**
* Executes a CGI script with the desired environment, current working
* directory, and input/output streams
*
* <p>
* This implements the following CGI specification recommedations:
* <UL>
* <LI> Servers SHOULD provide the "<code>query</code>" component of
* the script-URI as command-line arguments to scripts if it
* does not contain any unencoded "=" characters and the
* command-line arguments can be generated in an unambiguous
* manner.
* <LI> Servers SHOULD set the AUTH_TYPE metavariable to the value
* of the "<code>auth-scheme</code>" token of the
* "<code>Authorization</code>" if it was supplied as part of the
* request header. See <code>getCGIEnvironment</code> method.
* <LI> Where applicable, servers SHOULD set the current working
* directory to the directory in which the script is located
* before invoking it.
* <LI> Server implementations SHOULD define their behavior for the
* following cases:
* <ul>
* <LI> <u>Allowed characters in pathInfo</u>: This implementation
* does not allow ASCII NUL nor any character which cannot
* be URL-encoded according to internet standards;
* <LI> <u>Allowed characters in path segments</u>: This
* implementation does not allow non-terminal NULL
* segments in the the path -- IOExceptions may be thrown;
* <LI> <u>"<code>.</code>" and "<code>..</code>" path
* segments</u>:
* This implementation does not allow "<code>.</code>" and
* "<code>..</code>" in the the path, and such characters
* will result in an IOException being thrown;
* <LI> <u>Implementation limitations</u>: This implementation
* does not impose any limitations except as documented
* above. This implementation may be limited by the
* servlet container used to house this implementation.
* In particular, all the primary CGI variable values
* are derived either directly or indirectly from the
* container's implementation of the Servlet API methods.
* </ul>
* </UL>
* </p>
*
* @exception IOException if problems during reading/writing occur
*
* @see java.lang.Runtime#exec(String command, String[] envp,
* File dir)
*/
protected void run() throws IOException {
/*
* REMIND: this method feels too big; should it be re-written?
*/
if (!isReady()) {
throw new IOException(this.getClass().getName()
+ ": not ready to run.");
}
if (debug >= 1 ) {
log("runCGI(envp=[" + env + "], command=" + command + ")");
}
if ((command.indexOf(File.separator + "." + File.separator) >= 0)
|| (command.indexOf(File.separator + "..") >= 0)
|| (command.indexOf(".." + File.separator) >= 0)) {
throw new IOException(this.getClass().getName()
+ "Illegal Character in CGI command "
+ "path ('.' or '..') detected. Not "
+ "running CGI [" + command + "].");
}
/* original content/structure of this section taken from
* http://developer.java.sun.com/developer/
* bugParade/bugs/4216884.html
* with major modifications by Martin Dengler
*/
Runtime rt = null;
BufferedReader commandsStdOut = null;
BufferedReader commandsStdErr = null;
BufferedOutputStream commandsStdIn = null;
Process proc = null;
byte[] bBuf = new byte[1024];
char[] cBuf = new char[1024];
int bufRead = -1;
//create query arguments
Enumeration paramNames = params.keys();
StringBuffer cmdAndArgs = new StringBuffer(command);
if (paramNames != null && paramNames.hasMoreElements()) {
cmdAndArgs.append(" ");
while (paramNames.hasMoreElements()) {
String k = (String) paramNames.nextElement();
String v = params.get(k).toString();
if ((k.indexOf("=") < 0) && (v.indexOf("=") < 0)) {
cmdAndArgs.append(k);
cmdAndArgs.append("=");
v = java.net.URLEncoder.encode(v);
cmdAndArgs.append(v);
cmdAndArgs.append(" ");
}
}
}
String postIn = getPostInput(params);
int contentLength = (postIn.length()
+ System.getProperty("line.separator").length());
if ("POST".equals(env.get("REQUEST_METHOD"))) {
env.put("CONTENT_LENGTH", new Integer(contentLength));
}
StringBuffer perlCommand = new StringBuffer("perl ");
if (command.endsWith(".pl") || command.endsWith(".cgi")) {
perlCommand.append(cmdAndArgs.toString());
cmdAndArgs = perlCommand;
}
rt = Runtime.getRuntime();
proc = rt.exec(cmdAndArgs.toString(), hashToStringArray(env), wd);
/*
* provide input to cgi
* First -- parameters
* Second -- any remaining input
*/
commandsStdIn = new BufferedOutputStream(proc.getOutputStream());
if (debug >= 2 ) {
log("runCGI stdin=[" + stdin + "], qs="
+ env.get("QUERY_STRING"));
}
if ("POST".equals(env.get("REQUEST_METHOD"))) {
if (debug >= 2) {
log("runCGI: writing ---------------\n");
log(postIn);
log("runCGI: new content_length=" + contentLength
+ "---------------\n");
}
commandsStdIn.write(postIn.getBytes());
}
if (stdin != null) {
//REMIND: document this
/* assume if nothing is available after a time, that nothing is
* coming...
*/
if (stdin.available() <= 0) {
if (debug >= 2 ) {
log("runCGI stdin is NOT available ["
+ stdin.available() + "]");
}
try {
Thread.currentThread().sleep(iClientInputTimeout);
} catch (InterruptedException ignored) {
}
}
if (stdin.available() > 0) {
if (debug >= 2 ) {
log("runCGI stdin IS available ["
+ stdin.available() + "]");
}
bBuf = new byte[1024];
bufRead = -1;
try {
while ((bufRead = stdin.read(bBuf)) != -1) {
if (debug >= 2 ) {
log("runCGI: read [" + bufRead
+ "] bytes from stdin");
}
commandsStdIn.write(bBuf, 0, bufRead);
}
if (debug >= 2 ) {
log("runCGI: DONE READING from stdin");
}
} catch (IOException ioe) {
//REMIND: replace with logging
//REMIND: should I throw this exception?
log("runCGI: couldn't write all bytes.");
ioe.printStackTrace();
}
}
}
commandsStdIn.flush();
commandsStdIn.close();
/* we want to wait for the process to exit, Process.waitFor()
* is useless in our situation; see
* http://developer.java.sun.com/developer/
* bugParade/bugs/4223650.html
*/
boolean isRunning = true;
commandsStdOut = new BufferedReader
(new InputStreamReader(proc.getInputStream()));
commandsStdErr = new BufferedReader
(new InputStreamReader(proc.getErrorStream()));
BufferedWriter servletContainerStdout = null;
try {
if (response.getOutputStream() != null) {
servletContainerStdout =
new BufferedWriter(new OutputStreamWriter
(response.getOutputStream()));
}
} catch (IOException ignored) {
//NOOP: no output will be written
}
while (isRunning) {
try {
//read stderr first
cBuf = new char[1024];
while ((bufRead = commandsStdErr.read(cBuf)) != -1) {
if (servletContainerStdout != null) {
servletContainerStdout.write(cBuf, 0, bufRead);
}
}
//set headers
String line = null;
while (((line = commandsStdOut.readLine()) != null)
&& !("".equals(line))) {
if (debug >= 2) {
log("runCGI: addHeader(\"" + line + "\")");
}
if (line.startsWith("HTTP")) {
//TODO: should set status codes (NPH support)
/*
* response.setStatus(getStatusCode(line));
*/
} else {
response.addHeader
(line.substring(0, line.indexOf(":")).trim(),
line.substring(line.indexOf(":") + 1).trim());
}
}
//write output
cBuf = new char[1024];
while ((bufRead = commandsStdOut.read(cBuf)) != -1) {
if (servletContainerStdout != null) {
if (debug >= 4) {
log("runCGI: write(\"" + cBuf + "\")");
}
servletContainerStdout.write(cBuf, 0, bufRead);
}
}
if (servletContainerStdout != null) {
servletContainerStdout.flush();
}
proc.exitValue(); // Throws exception if alive
isRunning = false;
} catch (IllegalThreadStateException e) {
try {
Thread.currentThread().sleep(500);
} catch (InterruptedException ignored) {
}
}
} //replacement for Process.waitFor()
}
/**
* Gets a string for input to a POST cgi script
*
* @param params Hashtable of query parameters to be passed to
* the CGI script
* @return for use as input to the CGI script
*/
protected String getPostInput(Hashtable params) {
String lineSeparator = System.getProperty("line.separator");
Enumeration paramNames = params.keys();
StringBuffer postInput = new StringBuffer("");
StringBuffer qs = new StringBuffer("");
if (paramNames != null && paramNames.hasMoreElements()) {
while (paramNames.hasMoreElements()) {
String k = (String) paramNames.nextElement();
String v = params.get(k).toString();
if ((k.indexOf("=") < 0) && (v.indexOf("=") < 0)) {
postInput.append(k);
qs.append(k);
postInput.append("=");
qs.append("=");
postInput.append(v);
qs.append(v);
postInput.append(lineSeparator);
qs.append("&");
}
}
}
qs.append(lineSeparator);
return qs.append(postInput).toString();
}
} //class CGIRunner
} //class CGIServlet