Source Code Cross Referenced for CGIServlet.java in  » Sevlet-Container » apache-tomcat-6.0.14 » org » apache » catalina » servlets » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Sevlet Container » apache tomcat 6.0.14 » org.apache.catalina.servlets 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one or more
0003:         * contributor license agreements.  See the NOTICE file distributed with
0004:         * this work for additional information regarding copyright ownership.
0005:         * The ASF licenses this file to You under the Apache License, Version 2.0
0006:         * (the "License"); you may not use this file except in compliance with
0007:         * the License.  You may obtain a copy of the License at
0008:         * 
0009:         *      http://www.apache.org/licenses/LICENSE-2.0
0010:         * 
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         */
0017:
0018:        package org.apache.catalina.servlets;
0019:
0020:        import java.io.BufferedOutputStream;
0021:        import java.io.BufferedReader;
0022:        import java.io.File;
0023:        import java.io.FileOutputStream;
0024:        import java.io.IOException;
0025:        import java.io.InputStream;
0026:        import java.io.InputStreamReader;
0027:        import java.io.OutputStream;
0028:        import java.io.UnsupportedEncodingException;
0029:        import java.net.URLDecoder;
0030:        import java.util.ArrayList;
0031:        import java.util.Date;
0032:        import java.util.Enumeration;
0033:        import java.util.Hashtable;
0034:        import java.util.Locale;
0035:        import java.util.StringTokenizer;
0036:        import java.util.Vector;
0037:
0038:        import javax.servlet.ServletConfig;
0039:        import javax.servlet.ServletContext;
0040:        import javax.servlet.ServletException;
0041:        import javax.servlet.ServletOutputStream;
0042:        import javax.servlet.UnavailableException;
0043:        import javax.servlet.http.Cookie;
0044:        import javax.servlet.http.HttpServlet;
0045:        import javax.servlet.http.HttpServletRequest;
0046:        import javax.servlet.http.HttpServletResponse;
0047:        import javax.servlet.http.HttpSession;
0048:
0049:        import org.apache.catalina.Globals;
0050:        import org.apache.catalina.util.IOTools;
0051:
0052:        /**
0053:         *  CGI-invoking servlet for web applications, used to execute scripts which
0054:         *  comply to the Common Gateway Interface (CGI) specification and are named
0055:         *  in the path-info used to invoke this servlet.
0056:         *
0057:         * <p>
0058:         * <i>Note: This code compiles and even works for simple CGI cases.
0059:         *          Exhaustive testing has not been done.  Please consider it beta
0060:         *          quality.  Feedback is appreciated to the author (see below).</i>
0061:         * </p>
0062:         * <p>
0063:         *
0064:         * <b>Example</b>:<br>
0065:         * If an instance of this servlet was mapped (using
0066:         *       <code>&lt;web-app&gt;/WEB-INF/web.xml</code>) to:
0067:         * </p>
0068:         * <p>
0069:         * <code>
0070:         * &lt;web-app&gt;/cgi-bin/*
0071:         * </code>
0072:         * </p>
0073:         * <p>
0074:         * then the following request:
0075:         * </p>
0076:         * <p>
0077:         * <code>
0078:         * http://localhost:8080/&lt;web-app&gt;/cgi-bin/dir1/script/pathinfo1
0079:         * </code>
0080:         * </p>
0081:         * <p>
0082:         * would result in the execution of the script
0083:         * </p>
0084:         * <p>
0085:         * <code>
0086:         * &lt;web-app-root&gt;/WEB-INF/cgi/dir1/script
0087:         * </code>
0088:         * </p>
0089:         * <p>
0090:         * with the script's <code>PATH_INFO</code> set to <code>/pathinfo1</code>.
0091:         * </p>
0092:         * <p>
0093:         * Recommendation:  House all your CGI scripts under
0094:         * <code>&lt;webapp&gt;/WEB-INF/cgi</code>.  This will ensure that you do not
0095:         * accidentally expose your cgi scripts' code to the outside world and that
0096:         * your cgis will be cleanly ensconced underneath the WEB-INF (i.e.,
0097:         * non-content) area.
0098:         * </p>
0099:         * <p>
0100:         * The default CGI location is mentioned above.  You have the flexibility to
0101:         * put CGIs wherever you want, however:
0102:         * </p>
0103:         * <p>
0104:         *   The CGI search path will start at
0105:         *   webAppRootDir + File.separator + cgiPathPrefix
0106:         *   (or webAppRootDir alone if cgiPathPrefix is
0107:         *   null).
0108:         * </p>
0109:         * <p>
0110:         *   cgiPathPrefix is defined by setting
0111:         *   this servlet's cgiPathPrefix init parameter
0112:         * </p>
0113:         *
0114:         * <p>
0115:         *
0116:         * <B>CGI Specification</B>:<br> derived from
0117:         * <a href="http://cgi-spec.golux.com">http://cgi-spec.golux.com</a>.
0118:         * A work-in-progress & expired Internet Draft.  Note no actual RFC describing
0119:         * the CGI specification exists.  Where the behavior of this servlet differs
0120:         * from the specification cited above, it is either documented here, a bug,
0121:         * or an instance where the specification cited differs from Best
0122:         * Community Practice (BCP).
0123:         * Such instances should be well-documented here.  Please email the
0124:         * <a href="mailto:tomcat-dev@jakarta.apache.org">Jakarta Tomcat group [tomcat-dev@jakarta.apache.org]</a>
0125:         * with amendments.
0126:         *
0127:         * </p>
0128:         * <p>
0129:         *
0130:         * <b>Canonical metavariables</b>:<br>
0131:         * The CGI specification defines the following canonical metavariables:
0132:         * <br>
0133:         * [excerpt from CGI specification]
0134:         * <PRE>
0135:         *  AUTH_TYPE
0136:         *  CONTENT_LENGTH
0137:         *  CONTENT_TYPE
0138:         *  GATEWAY_INTERFACE
0139:         *  PATH_INFO
0140:         *  PATH_TRANSLATED
0141:         *  QUERY_STRING
0142:         *  REMOTE_ADDR
0143:         *  REMOTE_HOST
0144:         *  REMOTE_IDENT
0145:         *  REMOTE_USER
0146:         *  REQUEST_METHOD
0147:         *  SCRIPT_NAME
0148:         *  SERVER_NAME
0149:         *  SERVER_PORT
0150:         *  SERVER_PROTOCOL
0151:         *  SERVER_SOFTWARE
0152:         * </PRE>
0153:         * <p>
0154:         * Metavariables with names beginning with the protocol name (<EM>e.g.</EM>,
0155:         * "HTTP_ACCEPT") are also canonical in their description of request header
0156:         * fields.  The number and meaning of these fields may change independently
0157:         * of this specification.  (See also section 6.1.5 [of the CGI specification].)
0158:         * </p>
0159:         * [end excerpt]
0160:         *
0161:         * </p>
0162:         * <h2> Implementation notes</h2>
0163:         * <p>
0164:         *
0165:         * <b>standard input handling</b>: If your script accepts standard input,
0166:         * then the client must start sending input within a certain timeout period,
0167:         * otherwise the servlet will assume no input is coming and carry on running
0168:         * the script.  The script's the standard input will be closed and handling of
0169:         * any further input from the client is undefined.  Most likely it will be
0170:         * ignored.  If this behavior becomes undesirable, then this servlet needs
0171:         * to be enhanced to handle threading of the spawned process' stdin, stdout,
0172:         * and stderr (which should not be too hard).
0173:         * <br>
0174:         * If you find your cgi scripts are timing out receiving input, you can set
0175:         * the init parameter <code></code> of your webapps' cgi-handling servlet
0176:         * to be
0177:         * </p>
0178:         * <p>
0179:         *
0180:         * <b>Metavariable Values</b>: According to the CGI specificion,
0181:         * implementations may choose to represent both null or missing values in an
0182:         * implementation-specific manner, but must define that manner.  This
0183:         * implementation chooses to always define all required metavariables, but
0184:         * set the value to "" for all metavariables whose value is either null or
0185:         * undefined.  PATH_TRANSLATED is the sole exception to this rule, as per the
0186:         * CGI Specification.
0187:         *
0188:         * </p>
0189:         * <p>
0190:         *
0191:         * <b>NPH --  Non-parsed-header implementation</b>:  This implementation does
0192:         * not support the CGI NPH concept, whereby server ensures that the data
0193:         * supplied to the script are preceisely as supplied by the client and
0194:         * unaltered by the server.
0195:         * </p>
0196:         * <p>
0197:         * The function of a servlet container (including Tomcat) is specifically
0198:         * designed to parse and possible alter CGI-specific variables, and as
0199:         * such makes NPH functionality difficult to support.
0200:         * </p>
0201:         * <p>
0202:         * The CGI specification states that compliant servers MAY support NPH output.
0203:         * It does not state servers MUST support NPH output to be unconditionally
0204:         * compliant.  Thus, this implementation maintains unconditional compliance
0205:         * with the specification though NPH support is not present.
0206:         * </p>
0207:         * <p>
0208:         *
0209:         * The CGI specification is located at
0210:         * <a href="http://cgi-spec.golux.com">http://cgi-spec.golux.com</a>.
0211:         *
0212:         * </p>
0213:         * <p>
0214:         * <h3>TODO:</h3>
0215:         * <ul>
0216:         * <li> Support for setting headers (for example, Location headers don't work)
0217:         * <li> Support for collapsing multiple header lines (per RFC 2616)
0218:         * <li> Ensure handling of POST method does not interfere with 2.3 Filters
0219:         * <li> Refactor some debug code out of core
0220:         * <li> Ensure header handling preserves encoding
0221:         * <li> Possibly rewrite CGIRunner.run()?
0222:         * <li> Possibly refactor CGIRunner and CGIEnvironment as non-inner classes?
0223:         * <li> Document handling of cgi stdin when there is no stdin
0224:         * <li> Revisit IOException handling in CGIRunner.run()
0225:         * <li> Better documentation
0226:         * <li> Confirm use of ServletInputStream.available() in CGIRunner.run() is
0227:         *      not needed
0228:         * <li> Make checking for "." and ".." in servlet & cgi PATH_INFO less
0229:         *      draconian
0230:         * <li> [add more to this TODO list]
0231:         * </ul>
0232:         * </p>
0233:         *
0234:         * @author Martin T Dengler [root@martindengler.com]
0235:         * @author Amy Roh
0236:         * @version $Revision: 543681 $, $Date: 2007-06-02 02:42:59 +0200 (sam., 02 juin 2007) $
0237:         * @since Tomcat 4.0
0238:         *
0239:         */
0240:
0241:        public final class CGIServlet extends HttpServlet {
0242:
0243:            /* some vars below copied from Craig R. McClanahan's InvokerServlet */
0244:
0245:            /** the debugging detail level for this servlet. */
0246:            private int debug = 0;
0247:
0248:            /**
0249:             *  The CGI search path will start at
0250:             *    webAppRootDir + File.separator + cgiPathPrefix
0251:             *    (or webAppRootDir alone if cgiPathPrefix is
0252:             *    null)
0253:             */
0254:            private String cgiPathPrefix = null;
0255:
0256:            /** the executable to use with the script */
0257:            private String cgiExecutable = "perl";
0258:
0259:            /** the encoding to use for parameters */
0260:            private String parameterEncoding = System.getProperty(
0261:                    "file.encoding", "UTF-8");
0262:
0263:            /** object used to ensure multiple threads don't try to expand same file */
0264:            static Object expandFileLock = new Object();
0265:
0266:            /** the shell environment variables to be passed to the CGI script */
0267:            static Hashtable<String, String> shellEnv = new Hashtable<String, String>();
0268:
0269:            /**
0270:             * Sets instance variables.
0271:             * <P>
0272:             * Modified from Craig R. McClanahan's InvokerServlet
0273:             * </P>
0274:             *
0275:             * @param config                    a <code>ServletConfig</code> object
0276:             *                                  containing the servlet's
0277:             *                                  configuration and initialization
0278:             *                                  parameters
0279:             *
0280:             * @exception ServletException      if an exception has occurred that
0281:             *                                  interferes with the servlet's normal
0282:             *                                  operation
0283:             */
0284:            public void init(ServletConfig config) throws ServletException {
0285:
0286:                super .init(config);
0287:
0288:                // Verify that we were not accessed using the invoker servlet
0289:                String servletName = getServletConfig().getServletName();
0290:                if (servletName == null)
0291:                    servletName = "";
0292:                if (servletName.startsWith("org.apache.catalina.INVOKER."))
0293:                    throw new UnavailableException(
0294:                            "Cannot invoke CGIServlet through the invoker");
0295:
0296:                // Set our properties from the initialization parameters
0297:                if (getServletConfig().getInitParameter("debug") != null)
0298:                    debug = Integer.parseInt(getServletConfig()
0299:                            .getInitParameter("debug"));
0300:                cgiPathPrefix = getServletConfig().getInitParameter(
0301:                        "cgiPathPrefix");
0302:                boolean passShellEnvironment = Boolean.valueOf(
0303:                        getServletConfig().getInitParameter(
0304:                                "passShellEnvironment")).booleanValue();
0305:
0306:                if (passShellEnvironment) {
0307:                    try {
0308:                        shellEnv.putAll(getShellEnvironment());
0309:                    } catch (IOException ioe) {
0310:                        ServletException e = new ServletException(
0311:                                "Unable to read shell environment variables",
0312:                                ioe);
0313:                        throw e;
0314:                    }
0315:                }
0316:
0317:                if (getServletConfig().getInitParameter("executable") != null) {
0318:                    cgiExecutable = getServletConfig().getInitParameter(
0319:                            "executable");
0320:                }
0321:
0322:                if (getServletConfig().getInitParameter("parameterEncoding") != null) {
0323:                    parameterEncoding = getServletConfig().getInitParameter(
0324:                            "parameterEncoding");
0325:                }
0326:
0327:            }
0328:
0329:            /**
0330:             * Prints out important Servlet API and container information
0331:             *
0332:             * <p>
0333:             * Copied from SnoopAllServlet by Craig R. McClanahan
0334:             * </p>
0335:             *
0336:             * @param  out    ServletOutputStream as target of the information
0337:             * @param  req    HttpServletRequest object used as source of information
0338:             * @param  res    HttpServletResponse object currently not used but could
0339:             *                provide future information
0340:             *
0341:             * @exception  IOException  if a write operation exception occurs
0342:             *
0343:             */
0344:            protected void printServletEnvironment(ServletOutputStream out,
0345:                    HttpServletRequest req, HttpServletResponse res)
0346:                    throws IOException {
0347:
0348:                // Document the properties from ServletRequest
0349:                out.println("<h1>ServletRequest Properties</h1>");
0350:                out.println("<ul>");
0351:                Enumeration attrs = req.getAttributeNames();
0352:                while (attrs.hasMoreElements()) {
0353:                    String attr = (String) attrs.nextElement();
0354:                    out.println("<li><b>attribute</b> " + attr + " = "
0355:                            + req.getAttribute(attr));
0356:                }
0357:                out.println("<li><b>characterEncoding</b> = "
0358:                        + req.getCharacterEncoding());
0359:                out.println("<li><b>contentLength</b> = "
0360:                        + req.getContentLength());
0361:                out.println("<li><b>contentType</b> = " + req.getContentType());
0362:                Enumeration locales = req.getLocales();
0363:                while (locales.hasMoreElements()) {
0364:                    Locale locale = (Locale) locales.nextElement();
0365:                    out.println("<li><b>locale</b> = " + locale);
0366:                }
0367:                Enumeration params = req.getParameterNames();
0368:                while (params.hasMoreElements()) {
0369:                    String param = (String) params.nextElement();
0370:                    String values[] = req.getParameterValues(param);
0371:                    for (int i = 0; i < values.length; i++)
0372:                        out.println("<li><b>parameter</b> " + param + " = "
0373:                                + values[i]);
0374:                }
0375:                out.println("<li><b>protocol</b> = " + req.getProtocol());
0376:                out.println("<li><b>remoteAddr</b> = " + req.getRemoteAddr());
0377:                out.println("<li><b>remoteHost</b> = " + req.getRemoteHost());
0378:                out.println("<li><b>scheme</b> = " + req.getScheme());
0379:                out.println("<li><b>secure</b> = " + req.isSecure());
0380:                out.println("<li><b>serverName</b> = " + req.getServerName());
0381:                out.println("<li><b>serverPort</b> = " + req.getServerPort());
0382:                out.println("</ul>");
0383:                out.println("<hr>");
0384:
0385:                // Document the properties from HttpServletRequest
0386:                out.println("<h1>HttpServletRequest Properties</h1>");
0387:                out.println("<ul>");
0388:                out.println("<li><b>authType</b> = " + req.getAuthType());
0389:                out.println("<li><b>contextPath</b> = " + req.getContextPath());
0390:                Cookie cookies[] = req.getCookies();
0391:                if (cookies != null) {
0392:                    for (int i = 0; i < cookies.length; i++)
0393:                        out.println("<li><b>cookie</b> " + cookies[i].getName()
0394:                                + " = " + cookies[i].getValue());
0395:                }
0396:                Enumeration headers = req.getHeaderNames();
0397:                while (headers.hasMoreElements()) {
0398:                    String header = (String) headers.nextElement();
0399:                    out.println("<li><b>header</b> " + header + " = "
0400:                            + req.getHeader(header));
0401:                }
0402:                out.println("<li><b>method</b> = " + req.getMethod());
0403:                out.println("<li><a name=\"pathInfo\"><b>pathInfo</b></a> = "
0404:                        + req.getPathInfo());
0405:                out.println("<li><b>pathTranslated</b> = "
0406:                        + req.getPathTranslated());
0407:                out.println("<li><b>queryString</b> = " + req.getQueryString());
0408:                out.println("<li><b>remoteUser</b> = " + req.getRemoteUser());
0409:                out.println("<li><b>requestedSessionId</b> = "
0410:                        + req.getRequestedSessionId());
0411:                out.println("<li><b>requestedSessionIdFromCookie</b> = "
0412:                        + req.isRequestedSessionIdFromCookie());
0413:                out.println("<li><b>requestedSessionIdFromURL</b> = "
0414:                        + req.isRequestedSessionIdFromURL());
0415:                out.println("<li><b>requestedSessionIdValid</b> = "
0416:                        + req.isRequestedSessionIdValid());
0417:                out.println("<li><b>requestURI</b> = " + req.getRequestURI());
0418:                out.println("<li><b>servletPath</b> = " + req.getServletPath());
0419:                out.println("<li><b>userPrincipal</b> = "
0420:                        + req.getUserPrincipal());
0421:                out.println("</ul>");
0422:                out.println("<hr>");
0423:
0424:                // Document the servlet request attributes
0425:                out.println("<h1>ServletRequest Attributes</h1>");
0426:                out.println("<ul>");
0427:                attrs = req.getAttributeNames();
0428:                while (attrs.hasMoreElements()) {
0429:                    String attr = (String) attrs.nextElement();
0430:                    out.println("<li><b>" + attr + "</b> = "
0431:                            + req.getAttribute(attr));
0432:                }
0433:                out.println("</ul>");
0434:                out.println("<hr>");
0435:
0436:                // Process the current session (if there is one)
0437:                HttpSession session = req.getSession(false);
0438:                if (session != null) {
0439:
0440:                    // Document the session properties
0441:                    out.println("<h1>HttpSession Properties</h1>");
0442:                    out.println("<ul>");
0443:                    out.println("<li><b>id</b> = " + session.getId());
0444:                    out.println("<li><b>creationTime</b> = "
0445:                            + new Date(session.getCreationTime()));
0446:                    out.println("<li><b>lastAccessedTime</b> = "
0447:                            + new Date(session.getLastAccessedTime()));
0448:                    out.println("<li><b>maxInactiveInterval</b> = "
0449:                            + session.getMaxInactiveInterval());
0450:                    out.println("</ul>");
0451:                    out.println("<hr>");
0452:
0453:                    // Document the session attributes
0454:                    out.println("<h1>HttpSession Attributes</h1>");
0455:                    out.println("<ul>");
0456:                    attrs = session.getAttributeNames();
0457:                    while (attrs.hasMoreElements()) {
0458:                        String attr = (String) attrs.nextElement();
0459:                        out.println("<li><b>" + attr + "</b> = "
0460:                                + session.getAttribute(attr));
0461:                    }
0462:                    out.println("</ul>");
0463:                    out.println("<hr>");
0464:
0465:                }
0466:
0467:                // Document the servlet configuration properties
0468:                out.println("<h1>ServletConfig Properties</h1>");
0469:                out.println("<ul>");
0470:                out.println("<li><b>servletName</b> = "
0471:                        + getServletConfig().getServletName());
0472:                out.println("</ul>");
0473:                out.println("<hr>");
0474:
0475:                // Document the servlet configuration initialization parameters
0476:                out.println("<h1>ServletConfig Initialization Parameters</h1>");
0477:                out.println("<ul>");
0478:                params = getServletConfig().getInitParameterNames();
0479:                while (params.hasMoreElements()) {
0480:                    String param = (String) params.nextElement();
0481:                    String value = getServletConfig().getInitParameter(param);
0482:                    out.println("<li><b>" + param + "</b> = " + value);
0483:                }
0484:                out.println("</ul>");
0485:                out.println("<hr>");
0486:
0487:                // Document the servlet context properties
0488:                out.println("<h1>ServletContext Properties</h1>");
0489:                out.println("<ul>");
0490:                out.println("<li><b>majorVersion</b> = "
0491:                        + getServletContext().getMajorVersion());
0492:                out.println("<li><b>minorVersion</b> = "
0493:                        + getServletContext().getMinorVersion());
0494:                out.println("<li><b>realPath('/')</b> = "
0495:                        + getServletContext().getRealPath("/"));
0496:                out.println("<li><b>serverInfo</b> = "
0497:                        + getServletContext().getServerInfo());
0498:                out.println("</ul>");
0499:                out.println("<hr>");
0500:
0501:                // Document the servlet context initialization parameters
0502:                out
0503:                        .println("<h1>ServletContext Initialization Parameters</h1>");
0504:                out.println("<ul>");
0505:                params = getServletContext().getInitParameterNames();
0506:                while (params.hasMoreElements()) {
0507:                    String param = (String) params.nextElement();
0508:                    String value = getServletContext().getInitParameter(param);
0509:                    out.println("<li><b>" + param + "</b> = " + value);
0510:                }
0511:                out.println("</ul>");
0512:                out.println("<hr>");
0513:
0514:                // Document the servlet context attributes
0515:                out.println("<h1>ServletContext Attributes</h1>");
0516:                out.println("<ul>");
0517:                attrs = getServletContext().getAttributeNames();
0518:                while (attrs.hasMoreElements()) {
0519:                    String attr = (String) attrs.nextElement();
0520:                    out.println("<li><b>" + attr + "</b> = "
0521:                            + getServletContext().getAttribute(attr));
0522:                }
0523:                out.println("</ul>");
0524:                out.println("<hr>");
0525:
0526:            }
0527:
0528:            /**
0529:             * Provides CGI Gateway service -- delegates to <code>doGet</code>
0530:             *
0531:             * @param  req   HttpServletRequest passed in by servlet container
0532:             * @param  res   HttpServletResponse passed in by servlet container
0533:             *
0534:             * @exception  ServletException  if a servlet-specific exception occurs
0535:             * @exception  IOException  if a read/write exception occurs
0536:             *
0537:             * @see javax.servlet.http.HttpServlet
0538:             *
0539:             */
0540:            protected void doPost(HttpServletRequest req,
0541:                    HttpServletResponse res) throws IOException,
0542:                    ServletException {
0543:                doGet(req, res);
0544:            }
0545:
0546:            /**
0547:             * Provides CGI Gateway service
0548:             *
0549:             * @param  req   HttpServletRequest passed in by servlet container
0550:             * @param  res   HttpServletResponse passed in by servlet container
0551:             *
0552:             * @exception  ServletException  if a servlet-specific exception occurs
0553:             * @exception  IOException  if a read/write exception occurs
0554:             *
0555:             * @see javax.servlet.http.HttpServlet
0556:             *
0557:             */
0558:            protected void doGet(HttpServletRequest req, HttpServletResponse res)
0559:                    throws ServletException, IOException {
0560:
0561:                // Verify that we were not accessed using the invoker servlet
0562:                if (req.getAttribute(Globals.INVOKED_ATTR) != null)
0563:                    throw new UnavailableException(
0564:                            "Cannot invoke CGIServlet through the invoker");
0565:
0566:                CGIEnvironment cgiEnv = new CGIEnvironment(req,
0567:                        getServletContext());
0568:
0569:                if (cgiEnv.isValid()) {
0570:                    CGIRunner cgi = new CGIRunner(cgiEnv.getCommand(), cgiEnv
0571:                            .getEnvironment(), cgiEnv.getWorkingDirectory(),
0572:                            cgiEnv.getParameters());
0573:                    //if POST, we need to cgi.setInput
0574:                    //REMIND: how does this interact with Servlet API 2.3's Filters?!
0575:                    if ("POST".equals(req.getMethod())) {
0576:                        cgi.setInput(req.getInputStream());
0577:                    }
0578:                    cgi.setResponse(res);
0579:                    cgi.run();
0580:                }
0581:
0582:                if (!cgiEnv.isValid()) {
0583:                    res.setStatus(404);
0584:                }
0585:
0586:                if (debug >= 10) {
0587:
0588:                    ServletOutputStream out = res.getOutputStream();
0589:                    out.println("<HTML><HEAD><TITLE>$Name$</TITLE></HEAD>");
0590:                    out.println("<BODY>$Header$<p>");
0591:
0592:                    if (cgiEnv.isValid()) {
0593:                        out.println(cgiEnv.toString());
0594:                    } else {
0595:                        out.println("<H3>");
0596:                        out.println("CGI script not found or not specified.");
0597:                        out.println("</H3>");
0598:                        out.println("<H4>");
0599:                        out.println("Check the <b>HttpServletRequest ");
0600:                        out.println("<a href=\"#pathInfo\">pathInfo</a></b> ");
0601:                        out.println("property to see if it is what you meant ");
0602:                        out.println("it to be.  You must specify an existant ");
0603:                        out.println("and executable file as part of the ");
0604:                        out.println("path-info.");
0605:                        out.println("</H4>");
0606:                        out.println("<H4>");
0607:                        out
0608:                                .println("For a good discussion of how CGI scripts ");
0609:                        out
0610:                                .println("work and what their environment variables ");
0611:                        out.println("mean, please visit the <a ");
0612:                        out.println("href=\"http://cgi-spec.golux.com\">CGI ");
0613:                        out.println("Specification page</a>.");
0614:                        out.println("</H4>");
0615:
0616:                    }
0617:
0618:                    printServletEnvironment(out, req, res);
0619:
0620:                    out.println("</BODY></HTML>");
0621:
0622:                }
0623:
0624:            } //doGet
0625:
0626:            /** For future testing use only; does nothing right now */
0627:            public static void main(String[] args) {
0628:                System.out.println("$Header$");
0629:            }
0630:
0631:            /**
0632:             * Get all shell environment variables. Have to do it this rather ugly way
0633:             * as the API to obtain is not available in 1.4 and earlier APIs.
0634:             *
0635:             * See <a href="http://www.rgagnon.com/javadetails/java-0150.html">Read environment
0636:             * variables from an application</a> for original source and article.
0637:             */
0638:            private Hashtable<String, String> getShellEnvironment()
0639:                    throws IOException {
0640:                Hashtable<String, String> envVars = new Hashtable<String, String>();
0641:                Process p = null;
0642:                Runtime r = Runtime.getRuntime();
0643:                String OS = System.getProperty("os.name").toLowerCase();
0644:                boolean ignoreCase;
0645:
0646:                if (OS.indexOf("windows 9") > -1) {
0647:                    p = r.exec("command.com /c set");
0648:                    ignoreCase = true;
0649:                } else if ((OS.indexOf("nt") > -1)
0650:                        || (OS.indexOf("windows 20") > -1)
0651:                        || (OS.indexOf("windows xp") > -1)) {
0652:                    // thanks to JuanFran for the xp fix!
0653:                    p = r.exec("cmd.exe /c set");
0654:                    ignoreCase = true;
0655:                } else {
0656:                    // our last hope, we assume Unix (thanks to H. Ware for the fix)
0657:                    p = r.exec("env");
0658:                    ignoreCase = false;
0659:                }
0660:
0661:                BufferedReader br = new BufferedReader(new InputStreamReader(p
0662:                        .getInputStream()));
0663:                String line;
0664:                while ((line = br.readLine()) != null) {
0665:                    int idx = line.indexOf('=');
0666:                    String key = line.substring(0, idx);
0667:                    String value = line.substring(idx + 1);
0668:                    if (ignoreCase) {
0669:                        key = key.toUpperCase();
0670:                    }
0671:                    envVars.put(key, value);
0672:                }
0673:                return envVars;
0674:            }
0675:
0676:            /**
0677:             * Encapsulates the CGI environment and rules to derive
0678:             * that environment from the servlet container and request information.
0679:             *
0680:             * <p>
0681:             * </p>
0682:             *
0683:             * @version  $Revision: 543681 $, $Date: 2007-06-02 02:42:59 +0200 (sam., 02 juin 2007) $
0684:             * @since    Tomcat 4.0
0685:             *
0686:             */
0687:            protected class CGIEnvironment {
0688:
0689:                /** context of the enclosing servlet */
0690:                private ServletContext context = null;
0691:
0692:                /** context path of enclosing servlet */
0693:                private String contextPath = null;
0694:
0695:                /** servlet URI of the enclosing servlet */
0696:                private String servletPath = null;
0697:
0698:                /** pathInfo for the current request */
0699:                private String pathInfo = null;
0700:
0701:                /** real file system directory of the enclosing servlet's web app */
0702:                private String webAppRootDir = null;
0703:
0704:                /** tempdir for context - used to expand scripts in unexpanded wars */
0705:                private File tmpDir = null;
0706:
0707:                /** derived cgi environment */
0708:                private Hashtable env = null;
0709:
0710:                /** cgi command to be invoked */
0711:                private String command = null;
0712:
0713:                /** cgi command's desired working directory */
0714:                private File workingDirectory = null;
0715:
0716:                /** cgi command's command line parameters */
0717:                private ArrayList<String> cmdLineParameters = new ArrayList<String>();
0718:
0719:                /** whether or not this object is valid or not */
0720:                private boolean valid = false;
0721:
0722:                /**
0723:                 * Creates a CGIEnvironment and derives the necessary environment,
0724:                 * query parameters, working directory, cgi command, etc.
0725:                 *
0726:                 * @param  req       HttpServletRequest for information provided by
0727:                 *                   the Servlet API
0728:                 * @param  context   ServletContext for information provided by the
0729:                 *                   Servlet API
0730:                 *
0731:                 */
0732:                protected CGIEnvironment(HttpServletRequest req,
0733:                        ServletContext context) throws IOException {
0734:                    setupFromContext(context);
0735:                    setupFromRequest(req);
0736:
0737:                    this .valid = setCGIEnvironment(req);
0738:
0739:                    if (this .valid) {
0740:                        workingDirectory = new File(command.substring(0,
0741:                                command.lastIndexOf(File.separator)));
0742:                    }
0743:
0744:                }
0745:
0746:                /**
0747:                 * Uses the ServletContext to set some CGI variables
0748:                 *
0749:                 * @param  context   ServletContext for information provided by the
0750:                 *                   Servlet API
0751:                 */
0752:                protected void setupFromContext(ServletContext context) {
0753:                    this .context = context;
0754:                    this .webAppRootDir = context.getRealPath("/");
0755:                    this .tmpDir = (File) context
0756:                            .getAttribute(Globals.WORK_DIR_ATTR);
0757:                }
0758:
0759:                /**
0760:                 * Uses the HttpServletRequest to set most CGI variables
0761:                 *
0762:                 * @param  req   HttpServletRequest for information provided by
0763:                 *               the Servlet API
0764:                 * @throws UnsupportedEncodingException 
0765:                 */
0766:                protected void setupFromRequest(HttpServletRequest req)
0767:                        throws UnsupportedEncodingException {
0768:
0769:                    this .contextPath = req.getContextPath();
0770:                    this .servletPath = req.getServletPath();
0771:                    this .pathInfo = req.getPathInfo();
0772:                    // If getPathInfo() returns null, must be using extension mapping
0773:                    // In this case, pathInfo should be same as servletPath
0774:                    if (this .pathInfo == null) {
0775:                        this .pathInfo = this .servletPath;
0776:                    }
0777:
0778:                    // If the request method is GET, POST or HEAD and the query string
0779:                    // does not contain an unencoded "=" this is an indexed query.
0780:                    // The parsed query string becomes the command line parameters
0781:                    // for the cgi command.
0782:                    if (req.getMethod().equals("GET")
0783:                            || req.getMethod().equals("POST")
0784:                            || req.getMethod().equals("HEAD")) {
0785:                        String qs = req.getQueryString();
0786:                        if (qs != null && qs.indexOf("=") == -1) {
0787:                            StringTokenizer qsTokens = new StringTokenizer(qs,
0788:                                    "+");
0789:                            while (qsTokens.hasMoreTokens()) {
0790:                                cmdLineParameters.add(URLDecoder
0791:                                        .decode(qsTokens.nextToken(),
0792:                                                parameterEncoding));
0793:                            }
0794:                        }
0795:                    }
0796:                }
0797:
0798:                /**
0799:                 * Resolves core information about the cgi script.
0800:                 *
0801:                 * <p>
0802:                 * Example URI:
0803:                 * <PRE> /servlet/cgigateway/dir1/realCGIscript/pathinfo1 </PRE>
0804:                 * <ul>
0805:                 * <LI><b>path</b> = $CATALINA_HOME/mywebapp/dir1/realCGIscript
0806:                 * <LI><b>scriptName</b> = /servlet/cgigateway/dir1/realCGIscript
0807:                 * <LI><b>cgiName</b> = /dir1/realCGIscript
0808:                 * <LI><b>name</b> = realCGIscript
0809:                 * </ul>
0810:                 * </p>
0811:                 * <p>
0812:                 * CGI search algorithm: search the real path below
0813:                 *    &lt;my-webapp-root&gt; and find the first non-directory in
0814:                 *    the getPathTranslated("/"), reading/searching from left-to-right.
0815:                 *</p>
0816:                 *<p>
0817:                 *   The CGI search path will start at
0818:                 *   webAppRootDir + File.separator + cgiPathPrefix
0819:                 *   (or webAppRootDir alone if cgiPathPrefix is
0820:                 *   null).
0821:                 *</p>
0822:                 *<p>
0823:                 *   cgiPathPrefix is defined by setting
0824:                 *   this servlet's cgiPathPrefix init parameter
0825:                 *
0826:                 *</p>
0827:                 *
0828:                 * @param pathInfo       String from HttpServletRequest.getPathInfo()
0829:                 * @param webAppRootDir  String from context.getRealPath("/")
0830:                 * @param contextPath    String as from
0831:                 *                       HttpServletRequest.getContextPath()
0832:                 * @param servletPath    String as from
0833:                 *                       HttpServletRequest.getServletPath()
0834:                 * @param cgiPathPrefix  subdirectory of webAppRootDir below which
0835:                 *                       the web app's CGIs may be stored; can be null.
0836:                 *                       The CGI search path will start at
0837:                 *                       webAppRootDir + File.separator + cgiPathPrefix
0838:                 *                       (or webAppRootDir alone if cgiPathPrefix is
0839:                 *                       null).  cgiPathPrefix is defined by setting
0840:                 *                       the servlet's cgiPathPrefix init parameter.
0841:                 *
0842:                 *
0843:                 * @return
0844:                 * <ul>
0845:                 * <li>
0846:                 * <code>path</code> -    full file-system path to valid cgi script,
0847:                 *                        or null if no cgi was found
0848:                 * <li>
0849:                 * <code>scriptName</code> -
0850:                 *                        CGI variable SCRIPT_NAME; the full URL path
0851:                 *                        to valid cgi script or null if no cgi was
0852:                 *                        found
0853:                 * <li>
0854:                 * <code>cgiName</code> - servlet pathInfo fragment corresponding to
0855:                 *                        the cgi script itself, or null if not found
0856:                 * <li>
0857:                 * <code>name</code> -    simple name (no directories) of the
0858:                 *                        cgi script, or null if no cgi was found
0859:                 * </ul>
0860:                 *
0861:                 * @since Tomcat 4.0
0862:                 */
0863:                protected String[] findCGI(String pathInfo,
0864:                        String webAppRootDir, String contextPath,
0865:                        String servletPath, String cgiPathPrefix) {
0866:                    String path = null;
0867:                    String name = null;
0868:                    String scriptname = null;
0869:                    String cginame = "";
0870:
0871:                    if ((webAppRootDir != null)
0872:                            && (webAppRootDir.lastIndexOf(File.separator) == (webAppRootDir
0873:                                    .length() - 1))) {
0874:                        //strip the trailing "/" from the webAppRootDir
0875:                        webAppRootDir = webAppRootDir.substring(0,
0876:                                (webAppRootDir.length() - 1));
0877:                    }
0878:
0879:                    if (cgiPathPrefix != null) {
0880:                        webAppRootDir = webAppRootDir + File.separator
0881:                                + cgiPathPrefix;
0882:                    }
0883:
0884:                    if (debug >= 2) {
0885:                        log("findCGI: path=" + pathInfo + ", " + webAppRootDir);
0886:                    }
0887:
0888:                    File currentLocation = new File(webAppRootDir);
0889:                    StringTokenizer dirWalker = new StringTokenizer(pathInfo,
0890:                            "/");
0891:                    if (debug >= 3) {
0892:                        log("findCGI: currentLoc=" + currentLocation);
0893:                    }
0894:                    while (!currentLocation.isFile()
0895:                            && dirWalker.hasMoreElements()) {
0896:                        if (debug >= 3) {
0897:                            log("findCGI: currentLoc=" + currentLocation);
0898:                        }
0899:                        String nextElement = (String) dirWalker.nextElement();
0900:                        currentLocation = new File(currentLocation, nextElement);
0901:                        cginame = cginame + "/" + nextElement;
0902:                    }
0903:                    if (!currentLocation.isFile()) {
0904:                        return new String[] { null, null, null, null };
0905:                    } else {
0906:                        if (debug >= 2) {
0907:                            log("findCGI: FOUND cgi at " + currentLocation);
0908:                        }
0909:                        path = currentLocation.getAbsolutePath();
0910:                        name = currentLocation.getName();
0911:
0912:                        if (".".equals(contextPath)) {
0913:                            scriptname = servletPath;
0914:                        } else {
0915:                            scriptname = contextPath + servletPath;
0916:                        }
0917:                        if (!servletPath.equals(cginame)) {
0918:                            scriptname = scriptname + cginame;
0919:                        }
0920:                    }
0921:
0922:                    if (debug >= 1) {
0923:                        log("findCGI calc: name=" + name + ", path=" + path
0924:                                + ", scriptname=" + scriptname + ", cginame="
0925:                                + cginame);
0926:                    }
0927:                    return new String[] { path, scriptname, cginame, name };
0928:                }
0929:
0930:                /**
0931:                 * Constructs the CGI environment to be supplied to the invoked CGI
0932:                 * script; relies heavliy on Servlet API methods and findCGI
0933:                 *
0934:                 * @param    req request associated with the CGI
0935:                 *           invokation
0936:                 *
0937:                 * @return   true if environment was set OK, false if there
0938:                 *           was a problem and no environment was set
0939:                 */
0940:                protected boolean setCGIEnvironment(HttpServletRequest req)
0941:                        throws IOException {
0942:
0943:                    /*
0944:                     * This method is slightly ugly; c'est la vie.
0945:                     * "You cannot stop [ugliness], you can only hope to contain [it]"
0946:                     * (apologies to Marv Albert regarding MJ)
0947:                     */
0948:
0949:                    Hashtable<String, String> envp = new Hashtable<String, String>();
0950:
0951:                    // Add the shell environment variables (if any)
0952:                    envp.putAll(shellEnv);
0953:
0954:                    // Add the CGI environment variables
0955:                    String sPathInfoOrig = null;
0956:                    String sPathTranslatedOrig = null;
0957:                    String sPathInfoCGI = null;
0958:                    String sPathTranslatedCGI = null;
0959:                    String sCGIFullPath = null;
0960:                    String sCGIScriptName = null;
0961:                    String sCGIFullName = null;
0962:                    String sCGIName = null;
0963:                    String[] sCGINames;
0964:
0965:                    sPathInfoOrig = this .pathInfo;
0966:                    sPathInfoOrig = sPathInfoOrig == null ? "" : sPathInfoOrig;
0967:
0968:                    sPathTranslatedOrig = req.getPathTranslated();
0969:                    sPathTranslatedOrig = sPathTranslatedOrig == null ? ""
0970:                            : sPathTranslatedOrig;
0971:
0972:                    if (webAppRootDir == null) {
0973:                        // The app has not been deployed in exploded form
0974:                        webAppRootDir = tmpDir.toString();
0975:                        expandCGIScript();
0976:                    }
0977:
0978:                    sCGINames = findCGI(sPathInfoOrig, webAppRootDir,
0979:                            contextPath, servletPath, cgiPathPrefix);
0980:
0981:                    sCGIFullPath = sCGINames[0];
0982:                    sCGIScriptName = sCGINames[1];
0983:                    sCGIFullName = sCGINames[2];
0984:                    sCGIName = sCGINames[3];
0985:
0986:                    if (sCGIFullPath == null || sCGIScriptName == null
0987:                            || sCGIFullName == null || sCGIName == null) {
0988:                        return false;
0989:                    }
0990:
0991:                    envp.put("SERVER_SOFTWARE", "TOMCAT");
0992:
0993:                    envp.put("SERVER_NAME", nullsToBlanks(req.getServerName()));
0994:
0995:                    envp.put("GATEWAY_INTERFACE", "CGI/1.1");
0996:
0997:                    envp.put("SERVER_PROTOCOL",
0998:                            nullsToBlanks(req.getProtocol()));
0999:
1000:                    int port = req.getServerPort();
1001:                    Integer iPort = (port == 0 ? new Integer(-1) : new Integer(
1002:                            port));
1003:                    envp.put("SERVER_PORT", iPort.toString());
1004:
1005:                    envp.put("REQUEST_METHOD", nullsToBlanks(req.getMethod()));
1006:
1007:                    envp.put("REQUEST_URI", nullsToBlanks(req.getRequestURI()));
1008:
1009:                    /*-
1010:                     * PATH_INFO should be determined by using sCGIFullName:
1011:                     * 1) Let sCGIFullName not end in a "/" (see method findCGI)
1012:                     * 2) Let sCGIFullName equal the pathInfo fragment which
1013:                     *    corresponds to the actual cgi script.
1014:                     * 3) Thus, PATH_INFO = request.getPathInfo().substring(
1015:                     *                      sCGIFullName.length())
1016:                     *
1017:                     * (see method findCGI, where the real work is done)
1018:                     *
1019:                     */
1020:                    if (pathInfo == null
1021:                            || (pathInfo.substring(sCGIFullName.length())
1022:                                    .length() <= 0)) {
1023:                        sPathInfoCGI = "";
1024:                    } else {
1025:                        sPathInfoCGI = pathInfo
1026:                                .substring(sCGIFullName.length());
1027:                    }
1028:                    envp.put("PATH_INFO", sPathInfoCGI);
1029:
1030:                    /*-
1031:                     * PATH_TRANSLATED must be determined after PATH_INFO (and the
1032:                     * implied real cgi-script) has been taken into account.
1033:                     *
1034:                     * The following example demonstrates:
1035:                     *
1036:                     * servlet info   = /servlet/cgigw/dir1/dir2/cgi1/trans1/trans2
1037:                     * cgifullpath    = /servlet/cgigw/dir1/dir2/cgi1
1038:                     * path_info      = /trans1/trans2
1039:                     * webAppRootDir  = servletContext.getRealPath("/")
1040:                     *
1041:                     * path_translated = servletContext.getRealPath("/trans1/trans2")
1042:                     *
1043:                     * That is, PATH_TRANSLATED = webAppRootDir + sPathInfoCGI
1044:                     * (unless sPathInfoCGI is null or blank, then the CGI
1045:                     * specification dictates that the PATH_TRANSLATED metavariable
1046:                     * SHOULD NOT be defined.
1047:                     *
1048:                     */
1049:                    if (sPathInfoCGI != null && !("".equals(sPathInfoCGI))) {
1050:                        sPathTranslatedCGI = context.getRealPath(sPathInfoCGI);
1051:                    } else {
1052:                        sPathTranslatedCGI = null;
1053:                    }
1054:                    if (sPathTranslatedCGI == null
1055:                            || "".equals(sPathTranslatedCGI)) {
1056:                        //NOOP
1057:                    } else {
1058:                        envp.put("PATH_TRANSLATED",
1059:                                nullsToBlanks(sPathTranslatedCGI));
1060:                    }
1061:
1062:                    envp.put("SCRIPT_NAME", nullsToBlanks(sCGIScriptName));
1063:
1064:                    envp.put("QUERY_STRING",
1065:                            nullsToBlanks(req.getQueryString()));
1066:
1067:                    envp.put("REMOTE_HOST", nullsToBlanks(req.getRemoteHost()));
1068:
1069:                    envp.put("REMOTE_ADDR", nullsToBlanks(req.getRemoteAddr()));
1070:
1071:                    envp.put("AUTH_TYPE", nullsToBlanks(req.getAuthType()));
1072:
1073:                    envp.put("REMOTE_USER", nullsToBlanks(req.getRemoteUser()));
1074:
1075:                    envp.put("REMOTE_IDENT", ""); //not necessary for full compliance
1076:
1077:                    envp.put("CONTENT_TYPE",
1078:                            nullsToBlanks(req.getContentType()));
1079:
1080:                    /* Note CGI spec says CONTENT_LENGTH must be NULL ("") or undefined
1081:                     * if there is no content, so we cannot put 0 or -1 in as per the
1082:                     * Servlet API spec.
1083:                     */
1084:                    int contentLength = req.getContentLength();
1085:                    String sContentLength = (contentLength <= 0 ? ""
1086:                            : (new Integer(contentLength)).toString());
1087:                    envp.put("CONTENT_LENGTH", sContentLength);
1088:
1089:                    Enumeration headers = req.getHeaderNames();
1090:                    String header = null;
1091:                    while (headers.hasMoreElements()) {
1092:                        header = null;
1093:                        header = ((String) headers.nextElement()).toUpperCase();
1094:                        //REMIND: rewrite multiple headers as if received as single
1095:                        //REMIND: change character set
1096:                        //REMIND: I forgot what the previous REMIND means
1097:                        if ("AUTHORIZATION".equalsIgnoreCase(header)
1098:                                || "PROXY_AUTHORIZATION"
1099:                                        .equalsIgnoreCase(header)) {
1100:                            //NOOP per CGI specification section 11.2
1101:                        } else {
1102:                            envp.put("HTTP_" + header.replace('-', '_'), req
1103:                                    .getHeader(header));
1104:                        }
1105:                    }
1106:
1107:                    File fCGIFullPath = new File(sCGIFullPath);
1108:                    command = fCGIFullPath.getCanonicalPath();
1109:
1110:                    envp.put("X_TOMCAT_SCRIPT_PATH", command); //for kicks
1111:
1112:                    envp.put("SCRIPT_FILENAME", command); //for PHP
1113:
1114:                    this .env = envp;
1115:
1116:                    return true;
1117:
1118:                }
1119:
1120:                /**
1121:                 * Extracts requested resource from web app archive to context work 
1122:                 * directory to enable CGI script to be executed.
1123:                 */
1124:                protected void expandCGIScript() {
1125:                    StringBuffer srcPath = new StringBuffer();
1126:                    StringBuffer destPath = new StringBuffer();
1127:                    InputStream is = null;
1128:
1129:                    // paths depend on mapping
1130:                    if (cgiPathPrefix == null) {
1131:                        srcPath.append(pathInfo);
1132:                        is = context.getResourceAsStream(srcPath.toString());
1133:                        destPath.append(tmpDir);
1134:                        destPath.append(pathInfo);
1135:                    } else {
1136:                        // essentially same search algorithm as findCGI()
1137:                        srcPath.append(cgiPathPrefix);
1138:                        StringTokenizer pathWalker = new StringTokenizer(
1139:                                pathInfo, "/");
1140:                        // start with first element
1141:                        while (pathWalker.hasMoreElements() && (is == null)) {
1142:                            srcPath.append("/");
1143:                            srcPath.append(pathWalker.nextElement());
1144:                            is = context
1145:                                    .getResourceAsStream(srcPath.toString());
1146:                        }
1147:                        destPath.append(tmpDir);
1148:                        destPath.append("/");
1149:                        destPath.append(srcPath);
1150:                    }
1151:
1152:                    if (is == null) {
1153:                        // didn't find anything, give up now
1154:                        if (debug >= 2) {
1155:                            log("expandCGIScript: source '" + srcPath
1156:                                    + "' not found");
1157:                        }
1158:                        return;
1159:                    }
1160:
1161:                    File f = new File(destPath.toString());
1162:                    if (f.exists()) {
1163:                        // Don't need to expand if it already exists
1164:                        return;
1165:                    }
1166:
1167:                    // create directories
1168:                    String dirPath = new String(destPath.toString().substring(
1169:                            0, destPath.toString().lastIndexOf("/")));
1170:                    File dir = new File(dirPath);
1171:                    dir.mkdirs();
1172:
1173:                    try {
1174:                        synchronized (expandFileLock) {
1175:                            // make sure file doesn't exist
1176:                            if (f.exists()) {
1177:                                return;
1178:                            }
1179:
1180:                            // create file
1181:                            if (!f.createNewFile()) {
1182:                                return;
1183:                            }
1184:                            FileOutputStream fos = new FileOutputStream(f);
1185:
1186:                            // copy data
1187:                            IOTools.flow(is, fos);
1188:                            is.close();
1189:                            fos.close();
1190:                            if (debug >= 2) {
1191:                                log("expandCGIScript: expanded '" + srcPath
1192:                                        + "' to '" + destPath + "'");
1193:                            }
1194:                        }
1195:                    } catch (IOException ioe) {
1196:                        // delete in case file is corrupted 
1197:                        if (f.exists()) {
1198:                            f.delete();
1199:                        }
1200:                    }
1201:                }
1202:
1203:                /**
1204:                 * Print important CGI environment information in a easy-to-read HTML
1205:                 * table
1206:                 *
1207:                 * @return  HTML string containing CGI environment info
1208:                 *
1209:                 */
1210:                public String toString() {
1211:
1212:                    StringBuffer sb = new StringBuffer();
1213:
1214:                    sb.append("<TABLE border=2>");
1215:
1216:                    sb.append("<tr><th colspan=2 bgcolor=grey>");
1217:                    sb.append("CGIEnvironment Info</th></tr>");
1218:
1219:                    sb.append("<tr><td>Debug Level</td><td>");
1220:                    sb.append(debug);
1221:                    sb.append("</td></tr>");
1222:
1223:                    sb.append("<tr><td>Validity:</td><td>");
1224:                    sb.append(isValid());
1225:                    sb.append("</td></tr>");
1226:
1227:                    if (isValid()) {
1228:                        Enumeration envk = env.keys();
1229:                        while (envk.hasMoreElements()) {
1230:                            String s = (String) envk.nextElement();
1231:                            sb.append("<tr><td>");
1232:                            sb.append(s);
1233:                            sb.append("</td><td>");
1234:                            sb.append(blanksToString((String) env.get(s),
1235:                                    "[will be set to blank]"));
1236:                            sb.append("</td></tr>");
1237:                        }
1238:                    }
1239:
1240:                    sb.append("<tr><td colspan=2><HR></td></tr>");
1241:
1242:                    sb.append("<tr><td>Derived Command</td><td>");
1243:                    sb.append(nullsToBlanks(command));
1244:                    sb.append("</td></tr>");
1245:
1246:                    sb.append("<tr><td>Working Directory</td><td>");
1247:                    if (workingDirectory != null) {
1248:                        sb.append(workingDirectory.toString());
1249:                    }
1250:                    sb.append("</td></tr>");
1251:
1252:                    sb.append("<tr><td>Command Line Params</td><td>");
1253:                    for (int i = 0; i < cmdLineParameters.size(); i++) {
1254:                        String param = (String) cmdLineParameters.get(i);
1255:                        sb.append("<p>");
1256:                        sb.append(param);
1257:                        sb.append("</p>");
1258:                    }
1259:                    sb.append("</td></tr>");
1260:
1261:                    sb.append("</TABLE><p>end.");
1262:
1263:                    return sb.toString();
1264:                }
1265:
1266:                /**
1267:                 * Gets derived command string
1268:                 *
1269:                 * @return  command string
1270:                 *
1271:                 */
1272:                protected String getCommand() {
1273:                    return command;
1274:                }
1275:
1276:                /**
1277:                 * Gets derived CGI working directory
1278:                 *
1279:                 * @return  working directory
1280:                 *
1281:                 */
1282:                protected File getWorkingDirectory() {
1283:                    return workingDirectory;
1284:                }
1285:
1286:                /**
1287:                 * Gets derived CGI environment
1288:                 *
1289:                 * @return   CGI environment
1290:                 *
1291:                 */
1292:                protected Hashtable getEnvironment() {
1293:                    return env;
1294:                }
1295:
1296:                /**
1297:                 * Gets derived CGI query parameters
1298:                 *
1299:                 * @return   CGI query parameters
1300:                 *
1301:                 */
1302:                protected ArrayList getParameters() {
1303:                    return cmdLineParameters;
1304:                }
1305:
1306:                /**
1307:                 * Gets validity status
1308:                 *
1309:                 * @return   true if this environment is valid, false
1310:                 *           otherwise
1311:                 *
1312:                 */
1313:                protected boolean isValid() {
1314:                    return valid;
1315:                }
1316:
1317:                /**
1318:                 * Converts null strings to blank strings ("")
1319:                 *
1320:                 * @param    s string to be converted if necessary
1321:                 * @return   a non-null string, either the original or the empty string
1322:                 *           ("") if the original was <code>null</code>
1323:                 */
1324:                protected String nullsToBlanks(String s) {
1325:                    return nullsToString(s, "");
1326:                }
1327:
1328:                /**
1329:                 * Converts null strings to another string
1330:                 *
1331:                 * @param    couldBeNull string to be converted if necessary
1332:                 * @param    subForNulls string to return instead of a null string
1333:                 * @return   a non-null string, either the original or the substitute
1334:                 *           string if the original was <code>null</code>
1335:                 */
1336:                protected String nullsToString(String couldBeNull,
1337:                        String subForNulls) {
1338:                    return (couldBeNull == null ? subForNulls : couldBeNull);
1339:                }
1340:
1341:                /**
1342:                 * Converts blank strings to another string
1343:                 *
1344:                 * @param    couldBeBlank string to be converted if necessary
1345:                 * @param    subForBlanks string to return instead of a blank string
1346:                 * @return   a non-null string, either the original or the substitute
1347:                 *           string if the original was <code>null</code> or empty ("")
1348:                 */
1349:                protected String blanksToString(String couldBeBlank,
1350:                        String subForBlanks) {
1351:                    return (("".equals(couldBeBlank) || couldBeBlank == null) ? subForBlanks
1352:                            : couldBeBlank);
1353:                }
1354:
1355:            } //class CGIEnvironment
1356:
1357:            /**
1358:             * Encapsulates the knowledge of how to run a CGI script, given the
1359:             * script's desired environment and (optionally) input/output streams
1360:             *
1361:             * <p>
1362:             *
1363:             * Exposes a <code>run</code> method used to actually invoke the
1364:             * CGI.
1365:             *
1366:             * </p>
1367:             * <p>
1368:             *
1369:             * The CGI environment and settings are derived from the information
1370:             * passed to the constuctor.
1371:             *
1372:             * </p>
1373:             * <p>
1374:             *
1375:             * The input and output streams can be set by the <code>setInput</code>
1376:             * and <code>setResponse</code> methods, respectively.
1377:             * </p>
1378:             *
1379:             * @version   $Revision: 543681 $, $Date: 2007-06-02 02:42:59 +0200 (sam., 02 juin 2007) $
1380:             */
1381:
1382:            protected class CGIRunner {
1383:
1384:                /** script/command to be executed */
1385:                private String command = null;
1386:
1387:                /** environment used when invoking the cgi script */
1388:                private Hashtable env = null;
1389:
1390:                /** working directory used when invoking the cgi script */
1391:                private File wd = null;
1392:
1393:                /** command line parameters to be passed to the invoked script */
1394:                private ArrayList params = null;
1395:
1396:                /** stdin to be passed to cgi script */
1397:                private InputStream stdin = null;
1398:
1399:                /** response object used to set headers & get output stream */
1400:                private HttpServletResponse response = null;
1401:
1402:                /** boolean tracking whether this object has enough info to run() */
1403:                private boolean readyToRun = false;
1404:
1405:                /**
1406:                 *  Creates a CGIRunner and initializes its environment, working
1407:                 *  directory, and query parameters.
1408:                 *  <BR>
1409:                 *  Input/output streams (optional) are set using the
1410:                 *  <code>setInput</code> and <code>setResponse</code> methods,
1411:                 *  respectively.
1412:                 *
1413:                 * @param  command  string full path to command to be executed
1414:                 * @param  env      Hashtable with the desired script environment
1415:                 * @param  wd       File with the script's desired working directory
1416:                 * @param  params   ArrayList with the script's query command line
1417:                 *                  paramters as strings
1418:                 */
1419:                protected CGIRunner(String command, Hashtable env, File wd,
1420:                        ArrayList params) {
1421:                    this .command = command;
1422:                    this .env = env;
1423:                    this .wd = wd;
1424:                    this .params = params;
1425:                    updateReadyStatus();
1426:                }
1427:
1428:                /**
1429:                 * Checks & sets ready status
1430:                 */
1431:                protected void updateReadyStatus() {
1432:                    if (command != null && env != null && wd != null
1433:                            && params != null && response != null) {
1434:                        readyToRun = true;
1435:                    } else {
1436:                        readyToRun = false;
1437:                    }
1438:                }
1439:
1440:                /**
1441:                 * Gets ready status
1442:                 *
1443:                 * @return   false if not ready (<code>run</code> will throw
1444:                 *           an exception), true if ready
1445:                 */
1446:                protected boolean isReady() {
1447:                    return readyToRun;
1448:                }
1449:
1450:                /**
1451:                 * Sets HttpServletResponse object used to set headers and send
1452:                 * output to
1453:                 *
1454:                 * @param  response   HttpServletResponse to be used
1455:                 *
1456:                 */
1457:                protected void setResponse(HttpServletResponse response) {
1458:                    this .response = response;
1459:                    updateReadyStatus();
1460:                }
1461:
1462:                /**
1463:                 * Sets standard input to be passed on to the invoked cgi script
1464:                 *
1465:                 * @param  stdin   InputStream to be used
1466:                 *
1467:                 */
1468:                protected void setInput(InputStream stdin) {
1469:                    this .stdin = stdin;
1470:                    updateReadyStatus();
1471:                }
1472:
1473:                /**
1474:                 * Converts a Hashtable to a String array by converting each
1475:                 * key/value pair in the Hashtable to a String in the form
1476:                 * "key=value" (hashkey + "=" + hash.get(hashkey).toString())
1477:                 *
1478:                 * @param  h   Hashtable to convert
1479:                 *
1480:                 * @return     converted string array
1481:                 *
1482:                 * @exception  NullPointerException   if a hash key has a null value
1483:                 *
1484:                 */
1485:                protected String[] hashToStringArray(Hashtable h)
1486:                        throws NullPointerException {
1487:                    Vector<String> v = new Vector<String>();
1488:                    Enumeration e = h.keys();
1489:                    while (e.hasMoreElements()) {
1490:                        String k = e.nextElement().toString();
1491:                        v.add(k + "=" + h.get(k));
1492:                    }
1493:                    String[] strArr = new String[v.size()];
1494:                    v.copyInto(strArr);
1495:                    return strArr;
1496:                }
1497:
1498:                /**
1499:                 * Executes a CGI script with the desired environment, current working
1500:                 * directory, and input/output streams
1501:                 *
1502:                 * <p>
1503:                 * This implements the following CGI specification recommedations:
1504:                 * <UL>
1505:                 * <LI> Servers SHOULD provide the "<code>query</code>" component of
1506:                 *      the script-URI as command-line arguments to scripts if it
1507:                 *      does not contain any unencoded "=" characters and the
1508:                 *      command-line arguments can be generated in an unambiguous
1509:                 *      manner.
1510:                 * <LI> Servers SHOULD set the AUTH_TYPE metavariable to the value
1511:                 *      of the "<code>auth-scheme</code>" token of the
1512:                 *      "<code>Authorization</code>" if it was supplied as part of the
1513:                 *      request header.  See <code>getCGIEnvironment</code> method.
1514:                 * <LI> Where applicable, servers SHOULD set the current working
1515:                 *      directory to the directory in which the script is located
1516:                 *      before invoking it.
1517:                 * <LI> Server implementations SHOULD define their behavior for the
1518:                 *      following cases:
1519:                 *     <ul>
1520:                 *     <LI> <u>Allowed characters in pathInfo</u>:  This implementation
1521:                 *             does not allow ASCII NUL nor any character which cannot
1522:                 *             be URL-encoded according to internet standards;
1523:                 *     <LI> <u>Allowed characters in path segments</u>: This
1524:                 *             implementation does not allow non-terminal NULL
1525:                 *             segments in the the path -- IOExceptions may be thrown;
1526:                 *     <LI> <u>"<code>.</code>" and "<code>..</code>" path
1527:                 *             segments</u>:
1528:                 *             This implementation does not allow "<code>.</code>" and
1529:                 *             "<code>..</code>" in the the path, and such characters
1530:                 *             will result in an IOException being thrown;
1531:                 *     <LI> <u>Implementation limitations</u>: This implementation
1532:                 *             does not impose any limitations except as documented
1533:                 *             above.  This implementation may be limited by the
1534:                 *             servlet container used to house this implementation.
1535:                 *             In particular, all the primary CGI variable values
1536:                 *             are derived either directly or indirectly from the
1537:                 *             container's implementation of the Servlet API methods.
1538:                 *     </ul>
1539:                 * </UL>
1540:                 * </p>
1541:                 *
1542:                 * @exception IOException if problems during reading/writing occur
1543:                 *
1544:                 * @see    java.lang.Runtime#exec(String command, String[] envp,
1545:                 *                                File dir)
1546:                 */
1547:                protected void run() throws IOException {
1548:
1549:                    /*
1550:                     * REMIND:  this method feels too big; should it be re-written?
1551:                     */
1552:
1553:                    if (!isReady()) {
1554:                        throw new IOException(this .getClass().getName()
1555:                                + ": not ready to run.");
1556:                    }
1557:
1558:                    if (debug >= 1) {
1559:                        log("runCGI(envp=[" + env + "], command=" + command
1560:                                + ")");
1561:                    }
1562:
1563:                    if ((command.indexOf(File.separator + "." + File.separator) >= 0)
1564:                            || (command.indexOf(File.separator + "..") >= 0)
1565:                            || (command.indexOf(".." + File.separator) >= 0)) {
1566:                        throw new IOException(this .getClass().getName()
1567:                                + "Illegal Character in CGI command "
1568:                                + "path ('.' or '..') detected.  Not "
1569:                                + "running CGI [" + command + "].");
1570:                    }
1571:
1572:                    /* original content/structure of this section taken from
1573:                     * http://developer.java.sun.com/developer/
1574:                     *                               bugParade/bugs/4216884.html
1575:                     * with major modifications by Martin Dengler
1576:                     */
1577:                    Runtime rt = null;
1578:                    InputStream cgiOutput = null;
1579:                    BufferedReader commandsStdErr = null;
1580:                    BufferedOutputStream commandsStdIn = null;
1581:                    Process proc = null;
1582:                    int bufRead = -1;
1583:
1584:                    //create query arguments
1585:                    StringBuffer cmdAndArgs = new StringBuffer();
1586:                    if (command.indexOf(" ") < 0) {
1587:                        cmdAndArgs.append(command);
1588:                    } else {
1589:                        // Spaces used as delimiter, so need to use quotes
1590:                        cmdAndArgs.append("\"");
1591:                        cmdAndArgs.append(command);
1592:                        cmdAndArgs.append("\"");
1593:                    }
1594:
1595:                    for (int i = 0; i < params.size(); i++) {
1596:                        cmdAndArgs.append(" ");
1597:                        String param = (String) params.get(i);
1598:                        if (param.indexOf(" ") < 0) {
1599:                            cmdAndArgs.append(param);
1600:                        } else {
1601:                            // Spaces used as delimiter, so need to use quotes
1602:                            cmdAndArgs.append("\"");
1603:                            cmdAndArgs.append(param);
1604:                            cmdAndArgs.append("\"");
1605:                        }
1606:                    }
1607:
1608:                    StringBuffer command = new StringBuffer(cgiExecutable);
1609:                    command.append(" ");
1610:                    command.append(cmdAndArgs.toString());
1611:                    cmdAndArgs = command;
1612:
1613:                    try {
1614:                        rt = Runtime.getRuntime();
1615:                        proc = rt.exec(cmdAndArgs.toString(),
1616:                                hashToStringArray(env), wd);
1617:
1618:                        String sContentLength = (String) env
1619:                                .get("CONTENT_LENGTH");
1620:
1621:                        if (!"".equals(sContentLength)) {
1622:                            commandsStdIn = new BufferedOutputStream(proc
1623:                                    .getOutputStream());
1624:                            IOTools.flow(stdin, commandsStdIn);
1625:                            commandsStdIn.flush();
1626:                            commandsStdIn.close();
1627:                        }
1628:
1629:                        /* we want to wait for the process to exit,  Process.waitFor()
1630:                         * is useless in our situation; see
1631:                         * http://developer.java.sun.com/developer/
1632:                         *                               bugParade/bugs/4223650.html
1633:                         */
1634:
1635:                        boolean isRunning = true;
1636:                        commandsStdErr = new BufferedReader(
1637:                                new InputStreamReader(proc.getErrorStream()));
1638:                        final BufferedReader stdErrRdr = commandsStdErr;
1639:
1640:                        new Thread() {
1641:                            public void run() {
1642:                                sendToLog(stdErrRdr);
1643:                            };
1644:                        }.start();
1645:
1646:                        InputStream cgiHeaderStream = new HTTPHeaderInputStream(
1647:                                proc.getInputStream());
1648:                        BufferedReader cgiHeaderReader = new BufferedReader(
1649:                                new InputStreamReader(cgiHeaderStream));
1650:
1651:                        while (isRunning) {
1652:                            try {
1653:                                //set headers
1654:                                String line = null;
1655:                                while (((line = cgiHeaderReader.readLine()) != null)
1656:                                        && !("".equals(line))) {
1657:                                    if (debug >= 2) {
1658:                                        log("runCGI: addHeader(\"" + line
1659:                                                + "\")");
1660:                                    }
1661:                                    if (line.startsWith("HTTP")) {
1662:                                        response
1663:                                                .setStatus(getSCFromHttpStatusLine(line));
1664:                                    } else if (line.indexOf(":") >= 0) {
1665:                                        String header = line.substring(0,
1666:                                                line.indexOf(":")).trim();
1667:                                        String value = line.substring(
1668:                                                line.indexOf(":") + 1).trim();
1669:                                        if (header.equalsIgnoreCase("status")) {
1670:                                            response
1671:                                                    .setStatus(getSCFromCGIStatusHeader(value));
1672:                                        } else {
1673:                                            response.addHeader(header, value);
1674:                                        }
1675:                                    } else {
1676:                                        log("runCGI: bad header line \"" + line
1677:                                                + "\"");
1678:                                    }
1679:                                }
1680:
1681:                                //write output
1682:                                byte[] bBuf = new byte[2048];
1683:
1684:                                OutputStream out = response.getOutputStream();
1685:                                cgiOutput = proc.getInputStream();
1686:
1687:                                try {
1688:                                    while ((bufRead = cgiOutput.read(bBuf)) != -1) {
1689:                                        if (debug >= 4) {
1690:                                            log("runCGI: output " + bufRead
1691:                                                    + " bytes of data");
1692:                                        }
1693:                                        out.write(bBuf, 0, bufRead);
1694:                                    }
1695:                                } finally {
1696:                                    // Attempt to consume any leftover byte if something bad happens,
1697:                                    // such as a socket disconnect on the servlet side; otherwise, the
1698:                                    // external process could hang
1699:                                    if (bufRead != -1) {
1700:                                        while ((bufRead = cgiOutput.read(bBuf)) != -1) {
1701:                                        }
1702:                                    }
1703:                                }
1704:
1705:                                proc.exitValue(); // Throws exception if alive
1706:
1707:                                isRunning = false;
1708:
1709:                            } catch (IllegalThreadStateException e) {
1710:                                try {
1711:                                    Thread.sleep(500);
1712:                                } catch (InterruptedException ignored) {
1713:                                }
1714:                            }
1715:                        } //replacement for Process.waitFor()
1716:
1717:                        // Close the output stream used
1718:                        cgiOutput.close();
1719:                    } catch (IOException e) {
1720:                        log("Caught exception " + e);
1721:                        throw e;
1722:                    } finally {
1723:                        if (debug > 4) {
1724:                            log("Running finally block");
1725:                        }
1726:                        if (proc != null) {
1727:                            proc.destroy();
1728:                            proc = null;
1729:                        }
1730:                    }
1731:                }
1732:
1733:                /**
1734:                 * Parses the Status-Line and extracts the status code.
1735:                 * 
1736:                 * @param line The HTTP Status-Line (RFC2616, section 6.1)
1737:                 * @return The extracted status code or the code representing an
1738:                 * internal error if a valid status code cannot be extracted. 
1739:                 */
1740:                private int getSCFromHttpStatusLine(String line) {
1741:                    int statusStart = line.indexOf(' ') + 1;
1742:
1743:                    if (statusStart < 1 || line.length() < statusStart + 3) {
1744:                        // Not a valid HTTP Status-Line
1745:                        log("runCGI: invalid HTTP Status-Line:" + line);
1746:                        return HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
1747:                    }
1748:
1749:                    String status = line
1750:                            .substring(statusStart, statusStart + 3);
1751:
1752:                    int statusCode;
1753:                    try {
1754:                        statusCode = Integer.parseInt(status);
1755:                    } catch (NumberFormatException nfe) {
1756:                        // Not a valid status code
1757:                        log("runCGI: invalid status code:" + status);
1758:                        return HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
1759:                    }
1760:
1761:                    return statusCode;
1762:                }
1763:
1764:                /**
1765:                 * Parses the CGI Status Header value and extracts the status code.
1766:                 * 
1767:                 * @param value The CGI Status value of the form <code>
1768:                 *             digit digit digit SP reason-phrase</code>
1769:                 * @return The extracted status code or the code representing an
1770:                 * internal error if a valid status code cannot be extracted. 
1771:                 */
1772:                private int getSCFromCGIStatusHeader(String value) {
1773:                    if (value.length() < 3) {
1774:                        // Not a valid status value
1775:                        log("runCGI: invalid status value:" + value);
1776:                        return HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
1777:                    }
1778:
1779:                    String status = value.substring(0, 3);
1780:
1781:                    int statusCode;
1782:                    try {
1783:                        statusCode = Integer.parseInt(status);
1784:                    } catch (NumberFormatException nfe) {
1785:                        // Not a valid status code
1786:                        log("runCGI: invalid status code:" + status);
1787:                        return HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
1788:                    }
1789:
1790:                    return statusCode;
1791:                }
1792:
1793:                private void sendToLog(BufferedReader rdr) {
1794:                    String line = null;
1795:                    int lineCount = 0;
1796:                    try {
1797:                        while ((line = rdr.readLine()) != null) {
1798:                            log("runCGI (stderr):" + line);
1799:                            lineCount++;
1800:                        }
1801:                    } catch (IOException e) {
1802:                        log("sendToLog error", e);
1803:                    } finally {
1804:                        try {
1805:                            rdr.close();
1806:                        } catch (IOException ce) {
1807:                            log("sendToLog error", ce);
1808:                        }
1809:                        ;
1810:                    }
1811:                    ;
1812:                    if (lineCount > 0 && debug > 2) {
1813:                        log("runCGI: " + lineCount
1814:                                + " lines received on stderr");
1815:                    }
1816:                    ;
1817:                }
1818:            } //class CGIRunner
1819:
1820:            /**
1821:             * This is an input stream specifically for reading HTTP headers. It reads
1822:             * upto and including the two blank lines terminating the headers. It
1823:             * allows the content to be read using bytes or characters as appropriate.
1824:             */
1825:            protected class HTTPHeaderInputStream extends InputStream {
1826:                private static final int STATE_CHARACTER = 0;
1827:                private static final int STATE_FIRST_CR = 1;
1828:                private static final int STATE_FIRST_LF = 2;
1829:                private static final int STATE_SECOND_CR = 3;
1830:                private static final int STATE_HEADER_END = 4;
1831:
1832:                private InputStream input;
1833:                private int state;
1834:
1835:                HTTPHeaderInputStream(InputStream theInput) {
1836:                    input = theInput;
1837:                    state = STATE_CHARACTER;
1838:                }
1839:
1840:                /**
1841:                 * @see java.io.InputStream#read()
1842:                 */
1843:                public int read() throws IOException {
1844:                    if (state == STATE_HEADER_END) {
1845:                        return -1;
1846:                    }
1847:
1848:                    int i = input.read();
1849:
1850:                    // Update the state
1851:                    // State machine looks like this
1852:                    //
1853:                    //    -------->--------
1854:                    //   |      (CR)       |
1855:                    //   |                 |
1856:                    //  CR1--->---         |
1857:                    //   |        |        |
1858:                    //   ^(CR)    |(LF)    |
1859:                    //   |        |        |
1860:                    // CHAR--->--LF1--->--EOH
1861:                    //      (LF)  |  (LF)  |
1862:                    //            |(CR)    ^(LF)
1863:                    //            |        |
1864:                    //          (CR2)-->---
1865:
1866:                    if (i == 10) {
1867:                        // LF
1868:                        switch (state) {
1869:                        case STATE_CHARACTER:
1870:                            state = STATE_FIRST_LF;
1871:                            break;
1872:                        case STATE_FIRST_CR:
1873:                            state = STATE_FIRST_LF;
1874:                            break;
1875:                        case STATE_FIRST_LF:
1876:                        case STATE_SECOND_CR:
1877:                            state = STATE_HEADER_END;
1878:                            break;
1879:                        }
1880:
1881:                    } else if (i == 13) {
1882:                        // CR
1883:                        switch (state) {
1884:                        case STATE_CHARACTER:
1885:                            state = STATE_FIRST_CR;
1886:                            break;
1887:                        case STATE_FIRST_CR:
1888:                            state = STATE_HEADER_END;
1889:                            break;
1890:                        case STATE_FIRST_LF:
1891:                            state = STATE_SECOND_CR;
1892:                            break;
1893:                        }
1894:
1895:                    } else {
1896:                        state = STATE_CHARACTER;
1897:                    }
1898:
1899:                    return i;
1900:                }
1901:            } // class HTTPHeaderInputStream
1902:
1903:        } //class CGIServlet
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.