+++ /dev/null
-/*\r
- * Copyright 1999,2004 The Apache Software Foundation.\r
- * \r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- * \r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-\r
-package org.apache.catalina.util;\r
-\r
-import java.io.File;\r
-import java.net.URLEncoder;\r
-import java.util.Enumeration;\r
-import java.util.Hashtable;\r
-import java.util.StringTokenizer;\r
-\r
-import javax.servlet.ServletContext;\r
-import javax.servlet.http.HttpServletRequest;\r
-\r
-\r
-/**\r
- * Encapsulates the CGI Process' environment and rules to derive\r
- * that environment from the servlet container and request information.\r
- * @author Martin Dengler [root@martindengler.com]\r
- * @version $Revision: 303237 $, $Date: 2004-09-17 01:23:37 +0200 (ven., 17 sept. 2004) $\r
- * @since Tomcat 4.0\r
- */\r
-\r
-public class CGIProcessEnvironment extends ProcessEnvironment {\r
- \r
- \r
- private static org.apache.commons.logging.Log log=\r
- org.apache.commons.logging.LogFactory.getLog( CGIProcessEnvironment.class );\r
- \r
- /** cgi command's query parameters */\r
- private Hashtable queryParameters = null;\r
-\r
- /**\r
- * The CGI search path will start at\r
- * webAppRootDir + File.separator + cgiPathPrefix\r
- * (or webAppRootDir alone if cgiPathPrefix is\r
- * null)\r
- */\r
- private String cgiPathPrefix = null;\r
-\r
-\r
- /**\r
- * Creates a ProcessEnvironment and derives the necessary environment,\r
- * working directory, command, etc. The cgi path prefix is initialized\r
- * to "" (the empty string).\r
- *\r
- * @param req HttpServletRequest for information provided by\r
- * the Servlet API\r
- * @param context ServletContext for information provided by\r
- * the Servlet API\r
- */\r
- public CGIProcessEnvironment(HttpServletRequest req,\r
- ServletContext context) {\r
- this(req, context, "");\r
- }\r
-\r
-\r
-\r
- /**\r
- * Creates a ProcessEnvironment and derives the necessary environment,\r
- * working directory, command, etc.\r
- * @param req HttpServletRequest for information provided by\r
- * the Servlet API\r
- * @param context ServletContext for information provided by\r
- * the Servlet API\r
- * @param cgiPathPrefix subdirectory of webAppRootDir below which the\r
- * web app's CGIs may be stored; can be null or "".\r
- */\r
- public CGIProcessEnvironment(HttpServletRequest req,\r
- ServletContext context, String cgiPathPrefix) {\r
- this(req, context, cgiPathPrefix, 0);\r
- }\r
-\r
-\r
-\r
- /**\r
- * Creates a ProcessEnvironment and derives the necessary environment,\r
- * working directory, command, etc.\r
- * @param req HttpServletRequest for information provided by\r
- * the Servlet API\r
- * @param context ServletContext for information provided by\r
- * the Servlet API\r
- * @param debug int debug level (0 == none, 6 == lots)\r
- */\r
- public CGIProcessEnvironment(HttpServletRequest req,\r
- ServletContext context, int debug) {\r
- this(req, context, "", 0);\r
- }\r
-\r
-\r
-\r
-\r
- /**\r
- * Creates a ProcessEnvironment and derives the necessary environment,\r
- * working directory, command, etc.\r
- * @param req HttpServletRequest for information provided by\r
- * the Servlet API\r
- * @param context ServletContext for information provided by\r
- * the Servlet API\r
- * @param cgiPathPrefix subdirectory of webAppRootDir below which the\r
- * web app's CGIs may be stored; can be null or "".\r
- * @param debug int debug level (0 == none, 6 == lots)\r
- */\r
- public CGIProcessEnvironment(HttpServletRequest req,\r
- ServletContext context, String cgiPathPrefix, int debug) {\r
- super(req, context, debug);\r
- this.cgiPathPrefix = cgiPathPrefix;\r
- queryParameters = new Hashtable();\r
- Enumeration paramNames = req.getParameterNames();\r
- while (paramNames != null && paramNames.hasMoreElements()) {\r
- String param = paramNames.nextElement().toString();\r
- if (param != null) {\r
- queryParameters.put(param,\r
- URLEncoder.encode(req.getParameter(param)));\r
- }\r
- }\r
- this.valid = deriveProcessEnvironment(req);\r
- }\r
-\r
-\r
-\r
- /**\r
- * Constructs the CGI environment to be supplied to the invoked CGI\r
- * script; relies heavliy on Servlet API methods and findCGI\r
- * @param req request associated with the CGI invokation\r
- * @return true if environment was set OK, false if there was a problem\r
- * and no environment was set\r
- */\r
- protected boolean deriveProcessEnvironment(HttpServletRequest req) {\r
- /*\r
- * This method is slightly ugly; c'est la vie.\r
- * "You cannot stop [ugliness], you can only hope to contain [it]"\r
- * (apologies to Marv Albert regarding MJ)\r
- */\r
-\r
- Hashtable envp;\r
- super.deriveProcessEnvironment(req);\r
- envp = getEnvironment();\r
-\r
- String sPathInfoOrig = null;\r
- String sPathTranslatedOrig = null;\r
- String sPathInfoCGI = null;\r
- String sPathTranslatedCGI = null;\r
- String sCGIFullPath = null;\r
- String sCGIScriptName = null;\r
- String sCGIFullName = null;\r
- String sCGIName = null;\r
- String[] sCGINames;\r
- sPathInfoOrig = this.pathInfo;\r
- sPathInfoOrig = sPathInfoOrig == null ? "" : sPathInfoOrig;\r
- sPathTranslatedOrig = req.getPathTranslated();\r
- sPathTranslatedOrig = sPathTranslatedOrig == null ? "" :\r
- sPathTranslatedOrig;\r
- sCGINames =\r
- findCGI(sPathInfoOrig, getWebAppRootDir(), getContextPath(),\r
- getServletPath(), cgiPathPrefix);\r
- sCGIFullPath = sCGINames[0];\r
- sCGIScriptName = sCGINames[1];\r
- sCGIFullName = sCGINames[2];\r
- sCGIName = sCGINames[3];\r
- if (sCGIFullPath == null || sCGIScriptName == null\r
- || sCGIFullName == null || sCGIName == null) {\r
- return false;\r
- }\r
- envp.put("SERVER_SOFTWARE", "TOMCAT");\r
- envp.put("SERVER_NAME", nullsToBlanks(req.getServerName()));\r
- envp.put("GATEWAY_INTERFACE", "CGI/1.1");\r
- envp.put("SERVER_PROTOCOL", nullsToBlanks(req.getProtocol()));\r
- int port = req.getServerPort();\r
- Integer iPort = (port == 0 ? new Integer(-1) : new Integer(port));\r
- envp.put("SERVER_PORT", iPort.toString());\r
- envp.put("REQUEST_METHOD", nullsToBlanks(req.getMethod()));\r
-\r
- /*-\r
- * PATH_INFO should be determined by using sCGIFullName:\r
- * 1) Let sCGIFullName not end in a "/" (see method findCGI)\r
- * 2) Let sCGIFullName equal the pathInfo fragment which\r
- * corresponds to the actual cgi script.\r
- * 3) Thus, PATH_INFO = request.getPathInfo().substring(\r
- * sCGIFullName.length())\r
- *\r
- * (see method findCGI, where the real work is done)\r
- *\r
- */\r
-\r
- if (pathInfo == null ||\r
- (pathInfo.substring(sCGIFullName.length()).length() <= 0)) {\r
- sPathInfoCGI = "";\r
- } else {\r
- sPathInfoCGI = pathInfo.substring(sCGIFullName.length());\r
- }\r
- envp.put("PATH_INFO", sPathInfoCGI);\r
-\r
- /*-\r
- * PATH_TRANSLATED must be determined after PATH_INFO (and the\r
- * implied real cgi-script) has been taken into account.\r
- *\r
- * The following example demonstrates:\r
- *\r
- * servlet info = /servlet/cgigw/dir1/dir2/cgi1/trans1/trans2\r
- * cgifullpath = /servlet/cgigw/dir1/dir2/cgi1\r
- * path_info = /trans1/trans2\r
- * webAppRootDir = servletContext.getRealPath("/")\r
- *\r
- * path_translated = servletContext.getRealPath("/trans1/trans2")\r
- *\r
- * That is, PATH_TRANSLATED = webAppRootDir + sPathInfoCGI\r
- * (unless sPathInfoCGI is null or blank, then the CGI\r
- * specification dictates that the PATH_TRANSLATED metavariable\r
- * SHOULD NOT be defined.\r
- *\r
- */\r
-\r
- if (sPathInfoCGI != null && !("".equals(sPathInfoCGI))) {\r
- sPathTranslatedCGI = getContext().getRealPath(sPathInfoCGI);\r
- } else {\r
- sPathTranslatedCGI = null;\r
- }\r
- if (sPathTranslatedCGI == null || "".equals(sPathTranslatedCGI)) {\r
- //NOOP\r
- } else {\r
- envp.put("PATH_TRANSLATED", nullsToBlanks(sPathTranslatedCGI));\r
- }\r
- envp.put("SCRIPT_NAME", nullsToBlanks(sCGIScriptName));\r
- envp.put("QUERY_STRING", nullsToBlanks(req.getQueryString()));\r
- envp.put("REMOTE_HOST", nullsToBlanks(req.getRemoteHost()));\r
- envp.put("REMOTE_ADDR", nullsToBlanks(req.getRemoteAddr()));\r
- envp.put("AUTH_TYPE", nullsToBlanks(req.getAuthType()));\r
- envp.put("REMOTE_USER", nullsToBlanks(req.getRemoteUser()));\r
- envp.put("REMOTE_IDENT", ""); //not necessary for full compliance\r
- envp.put("CONTENT_TYPE", nullsToBlanks(req.getContentType()));\r
-\r
- /* Note CGI spec says CONTENT_LENGTH must be NULL ("") or undefined\r
- * if there is no content, so we cannot put 0 or -1 in as per the\r
- * Servlet API spec.\r
- */\r
-\r
- int contentLength = req.getContentLength();\r
- String sContentLength = (contentLength <= 0 ? "" : (\r
- new Integer(contentLength)).toString());\r
- envp.put("CONTENT_LENGTH", sContentLength);\r
- Enumeration headers = req.getHeaderNames();\r
- String header = null;\r
- while (headers.hasMoreElements()) {\r
- header = null;\r
- header = ((String)headers.nextElement()).toUpperCase();\r
- //REMIND: rewrite multiple headers as if received as single\r
- //REMIND: change character set\r
- //REMIND: I forgot what the previous REMIND means\r
- if ("AUTHORIZATION".equalsIgnoreCase(header)\r
- || "PROXY_AUTHORIZATION".equalsIgnoreCase(header)) {\r
- //NOOP per CGI specification section 11.2\r
- } else if ("HOST".equalsIgnoreCase(header)) {\r
- String host = req.getHeader(header);\r
- envp.put("HTTP_" + header.replace('-', '_'),\r
- host.substring(0, host.indexOf(":")));\r
- } else {\r
- envp.put("HTTP_" + header.replace('-', '_'),\r
- req.getHeader(header));\r
- }\r
- }\r
- command = sCGIFullPath;\r
- workingDirectory = new File(command.substring(0,\r
- command.lastIndexOf(File.separator)));\r
- envp.put("X_TOMCAT_COMMAND_PATH", command); //for kicks\r
- this.setEnvironment(envp);\r
- return true;\r
- }\r
-\r
-\r
- /**\r
- * Resolves core information about the cgi script. <p> Example URI:\r
- * <PRE> /servlet/cgigateway/dir1/realCGIscript/pathinfo1 </PRE> <ul>\r
- * <LI><b>path</b> = $CATALINA_HOME/mywebapp/dir1/realCGIscript\r
- * <LI><b>scriptName</b> = /servlet/cgigateway/dir1/realCGIscript</LI>\r
- * <LI><b>cgiName</b> = /dir1/realCGIscript\r
- * <LI><b>name</b> = realCGIscript\r
- * </ul>\r
- * </p>\r
- * <p>\r
- * CGI search algorithm: search the real path below\r
- * <my-webapp-root> and find the first non-directory in\r
- * the getPathTranslated("/"), reading/searching from left-to-right.\r
- * </p>\r
- * <p>\r
- * The CGI search path will start at\r
- * webAppRootDir + File.separator + cgiPathPrefix (or webAppRootDir\r
- * alone if cgiPathPrefix is null).\r
- * </p>\r
- * <p>\r
- * cgiPathPrefix is usually set by the calling servlet to the servlet's\r
- * cgiPathPrefix init parameter\r
- * </p>\r
- *\r
- * @param pathInfo String from HttpServletRequest.getPathInfo()\r
- * @param webAppRootDir String from context.getRealPath("/")\r
- * @param contextPath String as from HttpServletRequest.getContextPath()\r
- * @param servletPath String as from HttpServletRequest.getServletPath()\r
- * @param cgiPathPrefix subdirectory of webAppRootDir below which the\r
- * web app's CGIs may be stored; can be null.\r
- * @return\r
- * <ul> <li> <code>path</code> - full file-system path to valid cgi\r
- * script, or null if no cgi was found\r
- * <li> <code>scriptName</code> - CGI variable SCRIPT_NAME; the full\r
- * URL path to valid cgi script or\r
- * null if no cgi was found\r
- * <li> <code>cgiName</code> - servlet pathInfo fragment\r
- * corresponding to the cgi script\r
- * itself, or null if not found\r
- * <li> <code>name</code> - simple name (no directories) of\r
- * the cgi script, or null if no cgi\r
- * was found\r
- * </ul>\r
- * @since Tomcat 4.0\r
- */\r
- protected String[] findCGI(String pathInfo, String webAppRootDir,\r
- String contextPath, String servletPath, String cgiPathPrefix) {\r
- String path = null;\r
- String name = null;\r
- String scriptname = null;\r
- String cginame = null;\r
- if ((webAppRootDir != null)\r
- && (webAppRootDir.lastIndexOf("/")\r
- == (webAppRootDir.length() - 1))) {\r
- //strip the trailing "/" from the webAppRootDir\r
- webAppRootDir =\r
- webAppRootDir.substring(0,\r
- (webAppRootDir.length() - 1));\r
- }\r
- if (cgiPathPrefix != null) {\r
- webAppRootDir = webAppRootDir + File.separator\r
- + cgiPathPrefix;\r
- }\r
- \r
- if (log.isDebugEnabled()) {\r
- log.debug("findCGI: start = [" + webAppRootDir\r
- + "], pathInfo = [" + pathInfo + "] ");\r
- }\r
- File currentLocation = new File(webAppRootDir);\r
- StringTokenizer dirWalker = new StringTokenizer(pathInfo, "/");\r
- while (!currentLocation.isFile() && dirWalker.hasMoreElements()) {\r
- currentLocation = new\r
- File(currentLocation, (String) dirWalker.nextElement());\r
- if (log.isDebugEnabled()) {\r
- log.debug("findCGI: traversing to [" + currentLocation + "]");\r
- }\r
- }\r
- if (!currentLocation.isFile()) {\r
- return new String[] { null, null, null, null };\r
- } else {\r
- if (log.isDebugEnabled()) {\r
- log.debug("findCGI: FOUND cgi at [" + currentLocation + "]");\r
- }\r
- path = currentLocation.getAbsolutePath();\r
- name = currentLocation.getName();\r
- cginame = currentLocation.getParent()\r
- .substring(webAppRootDir.length())\r
- + File.separator + name;\r
- if (".".equals(contextPath)) {\r
- scriptname = servletPath + cginame;\r
- } else {\r
- scriptname = contextPath + servletPath + cginame;\r
- }\r
- }\r
- if (log.isDebugEnabled()) {\r
- log.debug("findCGI calc: name=" + name + ", path=" + path\r
- + ", scriptname=" + scriptname + ", cginame=" + cginame);\r
- }\r
- return new String[] { path, scriptname, cginame, name };\r
- }\r
-\r
-\r
- /**\r
- * Print important CGI environment information in an\r
- * easy-to-read HTML table\r
- * @return HTML string containing CGI environment info\r
- */\r
- public String toString() {\r
- StringBuffer sb = new StringBuffer();\r
- sb.append("<TABLE border=2>");\r
- sb.append("<tr><th colspan=2 bgcolor=grey>");\r
- sb.append("ProcessEnvironment Info</th></tr>");\r
- sb.append("<tr><td>Debug Level</td><td>");\r
- sb.append(debug);\r
- sb.append("</td></tr>");\r
- sb.append("<tr><td>Validity:</td><td>");\r
- sb.append(isValid());\r
- sb.append("</td></tr>");\r
- if (isValid()) {\r
- Enumeration envk = env.keys();\r
- while (envk.hasMoreElements()) {\r
- String s = (String)envk.nextElement();\r
- sb.append("<tr><td>");\r
- sb.append(s);\r
- sb.append("</td><td>");\r
- sb.append(blanksToString((String)env.get(s),\r
- "[will be set to blank]"));\r
- sb.append("</td></tr>");\r
- }\r
- }\r
- sb.append("<tr><td colspan=2><HR></td></tr>");\r
- sb.append("<tr><td>Derived Command</td><td>");\r
- sb.append(nullsToBlanks(command));\r
- sb.append("</td></tr>");\r
- sb.append("<tr><td>Working Directory</td><td>");\r
- if (workingDirectory != null) {\r
- sb.append(workingDirectory.toString());\r
- }\r
- sb.append("</td></tr>");\r
- sb.append("<tr><td colspan=2>Query Params</td></tr>");\r
- Enumeration paramk = queryParameters.keys();\r
- while (paramk.hasMoreElements()) {\r
- String s = paramk.nextElement().toString();\r
- sb.append("<tr><td>");\r
- sb.append(s);\r
- sb.append("</td><td>");\r
- sb.append(queryParameters.get(s).toString());\r
- sb.append("</td></tr>");\r
- }\r
-\r
- sb.append("</TABLE><p>end.");\r
- return sb.toString();\r
- }\r
-\r
-\r
- /**\r
- * Gets process' derived query parameters\r
- * @return process' query parameters\r
- */\r
- public Hashtable getParameters() {\r
- return queryParameters;\r
- }\r
-\r
-}\r
+++ /dev/null
-/*\r
- * Copyright 1999,2004 The Apache Software Foundation.\r
- * \r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- * \r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-package org.apache.catalina.util;\r
-\r
-import java.io.File;\r
-import java.util.Enumeration;\r
-import java.util.Hashtable;\r
-\r
-import javax.servlet.ServletContext;\r
-import javax.servlet.http.HttpServletRequest;\r
-\r
-\r
-\r
-/**\r
- * Encapsulates the Process environment and rules to derive\r
- * that environment from the servlet container and request information.\r
- * @author Martin Dengler [root@martindengler.com]\r
- * @version $Revision: 303236 $, $Date: 2004-09-17 01:19:54 +0200 (ven., 17 sept. 2004) $\r
- * @since Tomcat 4.0\r
- */\r
-public class ProcessEnvironment {\r
- \r
- private static org.apache.commons.logging.Log log=\r
- org.apache.commons.logging.LogFactory.getLog( ProcessEnvironment.class );\r
- \r
- /** context of the enclosing servlet */\r
- private ServletContext context = null;\r
-\r
- /** real file system directory of the enclosing servlet's web app */\r
- private String webAppRootDir = null;\r
-\r
- /** context path of enclosing servlet */\r
- private String contextPath = null;\r
-\r
- /** pathInfo for the current request */\r
- protected String pathInfo = null;\r
-\r
- /** servlet URI of the enclosing servlet */\r
- private String servletPath = null;\r
-\r
- /** derived process environment */\r
- protected Hashtable env = null;\r
-\r
- /** command to be invoked */\r
- protected String command = null;\r
-\r
- /** whether or not this object is valid or not */\r
- protected boolean valid = false;\r
-\r
- /** the debugging detail level for this instance. */\r
- protected int debug = 0;\r
-\r
- /** process' desired working directory */\r
- protected File workingDirectory = null;\r
-\r
-\r
- /**\r
- * Creates a ProcessEnvironment and derives the necessary environment,\r
- * working directory, command, etc.\r
- * @param req HttpServletRequest for information provided by\r
- * the Servlet API\r
- * @param context ServletContext for information provided by\r
- * the Servlet API\r
- */\r
- public ProcessEnvironment(HttpServletRequest req,\r
- ServletContext context) {\r
- this(req, context, 0);\r
- }\r
-\r
-\r
- /**\r
- * Creates a ProcessEnvironment and derives the necessary environment,\r
- * working directory, command, etc.\r
- * @param req HttpServletRequest for information provided by\r
- * the Servlet API\r
- * @param context ServletContext for information provided by\r
- * the Servlet API\r
- * @param debug int debug level (0 == none, 4 == medium, 6 == lots)\r
- */\r
- public ProcessEnvironment(HttpServletRequest req,\r
- ServletContext context, int debug) {\r
- this.debug = debug;\r
- setupFromContext(context);\r
- setupFromRequest(req);\r
- this.valid = deriveProcessEnvironment(req);\r
- if (log.isDebugEnabled()) \r
- log.debug(this.getClass().getName() + "() ctor, debug level " + \r
- debug);\r
- }\r
-\r
-\r
- /**\r
- * Uses the ServletContext to set some process variables\r
- * @param context ServletContext for information provided by\r
- * the Servlet API\r
- */\r
- protected void setupFromContext(ServletContext context) {\r
- this.context = context;\r
- this.webAppRootDir = context.getRealPath("/");\r
- }\r
-\r
-\r
- /**\r
- * Uses the HttpServletRequest to set most process variables\r
- * @param req HttpServletRequest for information provided by\r
- * the Servlet API\r
- */\r
- protected void setupFromRequest(HttpServletRequest req) {\r
- this.contextPath = req.getContextPath();\r
- this.pathInfo = req.getPathInfo();\r
- this.servletPath = req.getServletPath();\r
- }\r
-\r
-\r
- /**\r
- * Print important process environment information in an\r
- * easy-to-read HTML table\r
- * @return HTML string containing process environment info\r
- */\r
- public String toString() {\r
- StringBuffer sb = new StringBuffer();\r
- sb.append("<TABLE border=2>");\r
- sb.append("<tr><th colspan=2 bgcolor=grey>");\r
- sb.append("ProcessEnvironment Info</th></tr>");\r
- sb.append("<tr><td>Debug Level</td><td>");\r
- sb.append(debug);\r
- sb.append("</td></tr>");\r
- sb.append("<tr><td>Validity:</td><td>");\r
- sb.append(isValid());\r
- sb.append("</td></tr>");\r
- if (isValid()) {\r
- Enumeration envk = env.keys();\r
- while (envk.hasMoreElements()) {\r
- String s = (String)envk.nextElement();\r
- sb.append("<tr><td>");\r
- sb.append(s);\r
- sb.append("</td><td>");\r
- sb.append(blanksToString((String)env.get(s),\r
- "[will be set to blank]"));\r
- sb.append("</td></tr>");\r
- }\r
- }\r
- sb.append("<tr><td colspan=2><HR></td></tr>");\r
- sb.append("<tr><td>Derived Command</td><td>");\r
- sb.append(nullsToBlanks(command));\r
- sb.append("</td></tr>");\r
- sb.append("<tr><td>Working Directory</td><td>");\r
- if (workingDirectory != null) {\r
- sb.append(workingDirectory.toString());\r
- }\r
- sb.append("</td></tr>");\r
- sb.append("</TABLE><p>end.");\r
- return sb.toString();\r
- }\r
-\r
-\r
- /**\r
- * Gets derived command string\r
- * @return command string\r
- */\r
- public String getCommand() {\r
- return command;\r
- }\r
-\r
-\r
- /**\r
- * Sets the desired command string\r
- * @param command String command as desired\r
- * @return command string\r
- */\r
- protected String setCommand(String command) {\r
- return command;\r
- }\r
-\r
-\r
- /**\r
- * Gets this process' derived working directory\r
- * @return working directory\r
- */\r
- public File getWorkingDirectory() {\r
- return workingDirectory;\r
- }\r
-\r
-\r
- /**\r
- * Gets process' environment\r
- * @return process' environment\r
- */\r
- public Hashtable getEnvironment() {\r
- return env;\r
- }\r
-\r
-\r
- /**\r
- * Sets process' environment\r
- * @param env process' environment\r
- * @return Hashtable to which the process' environment was set\r
- */\r
- public Hashtable setEnvironment(Hashtable env) {\r
- this.env = env;\r
- return this.env;\r
- }\r
-\r
-\r
- /**\r
- * Gets validity status\r
- * @return true if this environment is valid, false otherwise\r
- */\r
- public boolean isValid() {\r
- return valid;\r
- }\r
-\r
-\r
- /**\r
- * Converts null strings to blank strings ("")\r
- * @param s string to be converted if necessary\r
- * @return a non-null string, either the original or the empty string\r
- * ("") if the original was <code>null</code>\r
- */\r
- protected String nullsToBlanks(String s) {\r
- return nullsToString(s, "");\r
- }\r
-\r
-\r
- /**\r
- * Converts null strings to another string\r
- * @param couldBeNull string to be converted if necessary\r
- * @param subForNulls string to return instead of a null string\r
- * @return a non-null string, either the original or the substitute\r
- * string if the original was <code>null</code>\r
- */\r
- protected String nullsToString(String couldBeNull, String subForNulls) {\r
- return (couldBeNull == null ? subForNulls : couldBeNull);\r
- }\r
-\r
-\r
- /**\r
- * Converts blank strings to another string\r
- * @param couldBeBlank string to be converted if necessary\r
- * @param subForBlanks string to return instead of a blank string\r
- * @return a non-null string, either the original or the substitute\r
- * string if the original was <code>null</code> or empty ("")\r
- */\r
- protected String blanksToString(String couldBeBlank,\r
- String subForBlanks) {\r
- return (("".equals(couldBeBlank) || couldBeBlank == null) ?\r
- subForBlanks : couldBeBlank);\r
- }\r
-\r
-\r
- /**\r
- * Constructs the Process environment to be supplied to the invoked\r
- * process. Defines an environment no environment variables.\r
- * <p>\r
- * Should be overriden by subclasses to perform useful setup.\r
- * </p>\r
- *\r
- * @param req request associated with the\r
- * Process' invocation\r
- * @return true if environment was set OK, false if there was a problem\r
- * and no environment was set\r
- */\r
- protected boolean deriveProcessEnvironment(HttpServletRequest req) {\r
-\r
- Hashtable envp = new Hashtable();\r
- command = getCommand();\r
- if (command != null) {\r
- workingDirectory = new\r
- File(command.substring(0,\r
- command.lastIndexOf(File.separator)));\r
- envp.put("X_TOMCAT_COMMAND_PATH", command); //for kicks\r
- }\r
- this.env = envp;\r
- return true;\r
- }\r
-\r
-\r
- /**\r
- * Gets the root directory of the web application to which this process\\r
- * belongs\r
- * @return root directory\r
- */\r
- public String getWebAppRootDir() {\r
- return webAppRootDir;\r
- }\r
-\r
-\r
- public String getContextPath(){\r
- return contextPath;\r
- }\r
-\r
-\r
- public ServletContext getContext(){\r
- return context;\r
- }\r
-\r
-\r
- public String getServletPath(){\r
- return servletPath;\r
- }\r
-}\r
+++ /dev/null
-/*\r
- * Copyright 1999,2004 The Apache Software Foundation.\r
- * \r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- * \r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-package org.apache.catalina.util;\r
-\r
-import java.io.BufferedOutputStream;\r
-import java.io.BufferedReader;\r
-import java.io.BufferedWriter;\r
-import java.io.File;\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
-import java.io.InputStreamReader;\r
-import java.io.OutputStreamWriter;\r
-import java.util.Enumeration;\r
-import java.util.Hashtable;\r
-import java.util.Vector;\r
-\r
-import javax.servlet.http.HttpServletResponse;\r
-\r
-/**\r
- * Encapsulates the knowledge of how to run a CGI script, given the\r
- * script's desired environment and (optionally) input/output streams\r
- *\r
- * <p>\r
- *\r
- * Exposes a <code>run</code> method used to actually invoke the\r
- * CGI.\r
- *\r
- * </p>\r
- * <p>\r
- *\r
- * The CGI environment and settings are derived from the information\r
- * passed to the constuctor.\r
- *\r
- * </p>\r
- * <p>\r
- *\r
- * The input and output streams can be set by the <code>setInput</code>\r
- * and <code>setResponse</code> methods, respectively.\r
- * </p>\r
- *\r
- * @author Martin Dengler [root@martindengler.com]\r
- * @version $Revision: 303236 $, $Date: 2004-09-17 01:19:54 +0200 (ven., 17 sept. 2004) $\r
- */\r
-public class ProcessHelper {\r
-\r
- private static org.apache.commons.logging.Log log=\r
- org.apache.commons.logging.LogFactory.getLog( ProcessHelper.class );\r
- \r
- /** script/command to be executed */\r
- private String command = null;\r
-\r
- /** environment used when invoking the cgi script */\r
- private Hashtable env = null;\r
-\r
- /** working directory used when invoking the cgi script */\r
- private File wd = null;\r
-\r
- /** query parameters to be passed to the invoked script */\r
- private Hashtable params = null;\r
-\r
- /** stdin to be passed to cgi script */\r
- private InputStream stdin = null;\r
-\r
- /** response object used to set headers & get output stream */\r
- private HttpServletResponse response = null;\r
-\r
- /** boolean tracking whether this object has enough info to run() */\r
- private boolean readyToRun = false;\r
-\r
- /** the debugging detail level for this instance. */\r
- private int debug = 0;\r
-\r
- /** the time in ms to wait for the client to send us CGI input data */\r
- private int iClientInputTimeout;\r
-\r
- /**\r
- * Creates a ProcessHelper and initializes its environment, working\r
- * directory, and query parameters.\r
- * <BR>\r
- * Input/output streams (optional) are set using the\r
- * <code>setInput</code> and <code>setResponse</code> methods,\r
- * respectively.\r
- *\r
- * @param command string full path to command to be executed\r
- * @param env Hashtable with the desired script environment\r
- * @param wd File with the script's desired working directory\r
- * @param params Hashtable with the script's query parameters\r
- */\r
- public ProcessHelper(\r
- String command,\r
- Hashtable env,\r
- File wd,\r
- Hashtable params) {\r
- this.command = command;\r
- this.env = env;\r
- this.wd = wd;\r
- this.params = params;\r
- updateReadyStatus();\r
- }\r
-\r
- /**\r
- * Checks & sets ready status\r
- */\r
- protected void updateReadyStatus() {\r
- if (command != null\r
- && env != null\r
- && wd != null\r
- && params != null\r
- && response != null) {\r
- readyToRun = true;\r
- } else {\r
- readyToRun = false;\r
- }\r
- }\r
-\r
- /**\r
- * Gets ready status\r
- *\r
- * @return false if not ready (<code>run</code> will throw\r
- * an exception), true if ready\r
- */\r
- public boolean isReady() {\r
- return readyToRun;\r
- }\r
-\r
- /**\r
- * Sets HttpServletResponse object used to set headers and send\r
- * output to\r
- *\r
- * @param response HttpServletResponse to be used\r
- *\r
- */\r
- public void setResponse(HttpServletResponse response) {\r
- this.response = response;\r
- updateReadyStatus();\r
- }\r
-\r
- /**\r
- * Sets standard input to be passed on to the invoked cgi script\r
- *\r
- * @param stdin InputStream to be used\r
- *\r
- */\r
- public void setInput(InputStream stdin) {\r
- this.stdin = stdin;\r
- updateReadyStatus();\r
- }\r
-\r
- /**\r
- * Converts a Hashtable to a String array by converting each\r
- * key/value pair in the Hashtable to a String in the form\r
- * "key=value" (hashkey + "=" + hash.get(hashkey).toString())\r
- *\r
- * @param h Hashtable to convert\r
- *\r
- * @return converted string array\r
- *\r
- * @exception NullPointerException if a hash key has a null value\r
- *\r
- */\r
- private String[] hashToStringArray(Hashtable h)\r
- throws NullPointerException {\r
- Vector v = new Vector();\r
- Enumeration e = h.keys();\r
- while (e.hasMoreElements()) {\r
- String k = e.nextElement().toString();\r
- v.add(k + "=" + h.get(k));\r
- }\r
- String[] strArr = new String[v.size()];\r
- v.copyInto(strArr);\r
- return strArr;\r
- }\r
-\r
- /**\r
- * Executes a process script with the desired environment, current working\r
- * directory, and input/output streams\r
- *\r
- * <p>\r
- * This implements the following CGI specification recommedations:\r
- * <UL>\r
- * <LI> Servers SHOULD provide the "<code>query</code>" component of\r
- * the script-URI as command-line arguments to scripts if it\r
- * does not contain any unencoded "=" characters and the\r
- * command-line arguments can be generated in an unambiguous\r
- * manner.\r
- * <LI> Servers SHOULD set the AUTH_TYPE metavariable to the value\r
- * of the "<code>auth-scheme</code>" token of the\r
- * "<code>Authorization</code>" if it was supplied as part of the\r
- * request header. See <code>getCGIEnvironment</code> method.\r
- * <LI> Where applicable, servers SHOULD set the current working\r
- * directory to the directory in which the script is located\r
- * before invoking it.\r
- * <LI> Server implementations SHOULD define their behavior for the\r
- * following cases:\r
- * <ul>\r
- * <LI> <u>Allowed characters in pathInfo</u>: This implementation\r
- * does not allow ASCII NUL nor any character which cannot\r
- * be URL-encoded according to internet standards;\r
- * <LI> <u>Allowed characters in path segments</u>: This\r
- * implementation does not allow non-terminal NULL\r
- * segments in the the path -- IOExceptions may be thrown;\r
- * <LI> <u>"<code>.</code>" and "<code>..</code>" path\r
- * segments</u>:\r
- * This implementation does not allow "<code>.</code>" and\r
- * "<code>..</code>" in the the path, and such characters\r
- * will result in an IOException being thrown;\r
- * <LI> <u>Implementation limitations</u>: This implementation\r
- * does not impose any limitations except as documented\r
- * above. This implementation may be limited by the\r
- * servlet container used to house this implementation.\r
- * In particular, all the primary CGI variable values\r
- * are derived either directly or indirectly from the\r
- * container's implementation of the Servlet API methods.\r
- * </ul>\r
- * </UL>\r
- * </p>\r
- *\r
- * For more information, see java.lang.Runtime#exec(String command, \r
- * String[] envp, File dir)\r
- *\r
- * @exception IOException if problems during reading/writing occur\r
- *\r
- */\r
- public void run() throws IOException {\r
-\r
- /*\r
- * REMIND: this method feels too big; should it be re-written?\r
- */\r
-\r
- if (!isReady()) {\r
- throw new IOException(\r
- this.getClass().getName() + ": not ready to run.");\r
- }\r
-\r
- if (log.isDebugEnabled()) {\r
- log.debug("runCGI(envp=[" + env + "], command=" + command + ")");\r
- }\r
-\r
- if ((command.indexOf(File.separator + "." + File.separator) >= 0)\r
- || (command.indexOf(File.separator + "..") >= 0)\r
- || (command.indexOf(".." + File.separator) >= 0)) {\r
- throw new IOException(\r
- this.getClass().getName()\r
- + "Illegal Character in CGI command "\r
- + "path ('.' or '..') detected. Not "\r
- + "running CGI ["\r
- + command\r
- + "].");\r
- }\r
-\r
- /* original content/structure of this section taken from\r
- * http://developer.java.sun.com/developer/\r
- * bugParade/bugs/4216884.html\r
- * with major modifications by Martin Dengler\r
- */\r
- Runtime rt = null;\r
- BufferedReader commandsStdOut = null;\r
- BufferedReader commandsStdErr = null;\r
- BufferedOutputStream commandsStdIn = null;\r
- Process proc = null;\r
- byte[] bBuf = new byte[1024];\r
- char[] cBuf = new char[1024];\r
- int bufRead = -1;\r
-\r
- //create query arguments\r
- Enumeration paramNames = params.keys();\r
- StringBuffer cmdAndArgs = new StringBuffer(command);\r
- if (paramNames != null && paramNames.hasMoreElements()) {\r
- cmdAndArgs.append(" ");\r
- while (paramNames.hasMoreElements()) {\r
- String k = (String) paramNames.nextElement();\r
- String v = params.get(k).toString();\r
- if ((k.indexOf("=") < 0) && (v.indexOf("=") < 0)) {\r
- cmdAndArgs.append(k);\r
- cmdAndArgs.append("=");\r
- v = java.net.URLEncoder.encode(v);\r
- cmdAndArgs.append(v);\r
- cmdAndArgs.append(" ");\r
- }\r
- }\r
- }\r
-\r
- String postIn = getPostInput(params);\r
- int contentLength =\r
- (postIn.length() + System.getProperty("line.separator").length());\r
- if ("POST".equals(env.get("REQUEST_METHOD"))) {\r
- env.put("CONTENT_LENGTH", new Integer(contentLength));\r
- }\r
-\r
- rt = Runtime.getRuntime();\r
- proc = rt.exec(cmdAndArgs.toString(), hashToStringArray(env), wd);\r
-\r
- /*\r
- * provide input to cgi\r
- * First -- parameters\r
- * Second -- any remaining input\r
- */\r
- commandsStdIn = new BufferedOutputStream(proc.getOutputStream());\r
- if (log.isDebugEnabled()) {\r
- log.debug("runCGI stdin=[" + stdin + "], qs=" + env.get("QUERY_STRING"));\r
- }\r
- if ("POST".equals(env.get("REQUEST_METHOD"))) {\r
- if (log.isDebugEnabled()) {\r
- log.debug("runCGI: writing ---------------\n");\r
- log.debug(postIn);\r
- log.debug(\r
- "runCGI: new content_length="\r
- + contentLength\r
- + "---------------\n");\r
- }\r
- commandsStdIn.write(postIn.getBytes());\r
- }\r
- if (stdin != null) {\r
- //REMIND: document this\r
- /* assume if nothing is available after a time, that nothing is\r
- * coming...\r
- */\r
- if (stdin.available() <= 0) {\r
- if (log.isDebugEnabled()) {\r
- log.debug(\r
- "runCGI stdin is NOT available ["\r
- + stdin.available()\r
- + "]");\r
- }\r
- try {\r
- Thread.sleep(iClientInputTimeout);\r
- } catch (InterruptedException ignored) {\r
- }\r
- }\r
- if (stdin.available() > 0) {\r
- if (log.isDebugEnabled()) {\r
- log.debug(\r
- "runCGI stdin IS available ["\r
- + stdin.available()\r
- + "]");\r
- }\r
- bBuf = new byte[1024];\r
- bufRead = -1;\r
- try {\r
- while ((bufRead = stdin.read(bBuf)) != -1) {\r
- if (log.isDebugEnabled()) {\r
- log.debug(\r
- "runCGI: read ["\r
- + bufRead\r
- + "] bytes from stdin");\r
- }\r
- commandsStdIn.write(bBuf, 0, bufRead);\r
- }\r
- if (log.isDebugEnabled()) {\r
- log.debug("runCGI: DONE READING from stdin");\r
- }\r
- } catch (IOException ioe) {\r
- log.error("runCGI: couldn't write all bytes.", ioe);\r
- }\r
- }\r
- }\r
- commandsStdIn.flush();\r
- commandsStdIn.close();\r
-\r
- /* we want to wait for the process to exit, Process.waitFor()\r
- * is useless in our situation; see\r
- * http://developer.java.sun.com/developer/\r
- * bugParade/bugs/4223650.html\r
- */\r
-\r
- boolean isRunning = true;\r
- commandsStdOut =\r
- new BufferedReader(new InputStreamReader(proc.getInputStream()));\r
- commandsStdErr =\r
- new BufferedReader(new InputStreamReader(proc.getErrorStream()));\r
- BufferedWriter servletContainerStdout = null;\r
-\r
- try {\r
- if (response.getOutputStream() != null) {\r
- servletContainerStdout =\r
- new BufferedWriter(\r
- new OutputStreamWriter(response.getOutputStream()));\r
- }\r
- } catch (IOException ignored) {\r
- //NOOP: no output will be written\r
- }\r
-\r
- while (isRunning) {\r
-\r
- try {\r
- //read stderr first\r
- cBuf = new char[1024];\r
- while ((bufRead = commandsStdErr.read(cBuf)) != -1) {\r
- if (servletContainerStdout != null) {\r
- servletContainerStdout.write(cBuf, 0, bufRead);\r
- }\r
- }\r
-\r
- //set headers\r
- String line = null;\r
- while (((line = commandsStdOut.readLine()) != null)\r
- && !("".equals(line))) {\r
- if (log.isDebugEnabled()) {\r
- log.debug("runCGI: addHeader(\"" + line + "\")");\r
- }\r
- if (line.startsWith("HTTP")) {\r
- //TODO: should set status codes (NPH support)\r
- /*\r
- * response.setStatus(getStatusCode(line));\r
- */\r
- } else {\r
- response.addHeader(\r
- line.substring(0, line.indexOf(":")).trim(),\r
- line.substring(line.indexOf(":") + 1).trim());\r
- }\r
- }\r
-\r
- //write output\r
- cBuf = new char[1024];\r
- while ((bufRead = commandsStdOut.read(cBuf)) != -1) {\r
- if (servletContainerStdout != null) {\r
- if (log.isDebugEnabled()) {\r
- log.debug("runCGI: write(\"" + new String(cBuf) + "\")");\r
- }\r
- servletContainerStdout.write(cBuf, 0, bufRead);\r
- }\r
- }\r
-\r
- if (servletContainerStdout != null) {\r
- servletContainerStdout.flush();\r
- }\r
-\r
- proc.exitValue(); // Throws exception if alive\r
-\r
- isRunning = false;\r
-\r
- } catch (IllegalThreadStateException e) {\r
- try {\r
- Thread.sleep(500);\r
- } catch (InterruptedException ignored) {\r
- }\r
- }\r
- } //replacement for Process.waitFor()\r
-\r
- }\r
-\r
- /**\r
- * Gets a string for input to a POST cgi script\r
- *\r
- * @param params Hashtable of query parameters to be passed to\r
- * the CGI script\r
- * @return for use as input to the CGI script\r
- */\r
-\r
- protected String getPostInput(Hashtable params) {\r
- String lineSeparator = System.getProperty("line.separator");\r
- Enumeration paramNames = params.keys();\r
- StringBuffer postInput = new StringBuffer("");\r
- StringBuffer qs = new StringBuffer("");\r
- if (paramNames != null && paramNames.hasMoreElements()) {\r
- while (paramNames.hasMoreElements()) {\r
- String k = (String) paramNames.nextElement();\r
- String v = params.get(k).toString();\r
- if ((k.indexOf("=") < 0) && (v.indexOf("=") < 0)) {\r
- postInput.append(k);\r
- qs.append(k);\r
- postInput.append("=");\r
- qs.append("=");\r
- postInput.append(v);\r
- qs.append(v);\r
- postInput.append(lineSeparator);\r
- qs.append("&");\r
- }\r
- }\r
- }\r
- qs.append(lineSeparator);\r
- return qs.append(postInput).toString();\r
- }\r
-\r
- public int getIClientInputTimeout() {\r
- return iClientInputTimeout;\r
- }\r
-\r
- public void setIClientInputTimeout(int iClientInputTimeout) {\r
- this.iClientInputTimeout = iClientInputTimeout;\r
- }\r
-}\r