// CgiServlet - runs CGI programs // // Copyright (C)1996,1998 by Jef Poskanzer <jef@acme.com>. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. // // Visit the ACME Labs Java page for up-to-date versions of this and other // fine Java utilities: http://www.acme.com/java/ package Acme.Serve; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.util.Enumeration; import java.util.StringTokenizer; import java.util.Vector; /// Runs CGI programs. // <P> // Note: although many implementations of CGI set the working directory of // the subprocess to be the directory containing the executable file, the // CGI spec actually says nothing about the working directory. Since // Java has no method for setting the working directory, this implementation // does not set it. // <P> // <A HREF="/resources/classes/Acme/Serve/CgiServlet.java">Fetch the software.</A><BR> // <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A> // <P> // @see Acme.Serve.Serve /** * @deprecated See resteasy-undertow module. */ @Deprecated public class CgiServlet extends HttpServlet { // / Returns a string containing information about the author, version, and // copyright of the servlet. public String getServletInfo() { return "runs CGI programs"; } // / Services a single request from the client. // @param req the servlet request // @param req the servlet response // @exception ServletException when an exception has occurred public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { if (!(req.getMethod().equalsIgnoreCase("get") || req.getMethod().equalsIgnoreCase("post"))) { res.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED); return; } dispatchPathname(req, res, getServletContext().getRealPath(req.getServletPath() + req.getPathInfo())); } private void dispatchPathname(HttpServletRequest req, HttpServletResponse res, String path) throws IOException { if (new File(path).exists()) serveFile(req, res, path); else res.sendError(HttpServletResponse.SC_NOT_FOUND); } @SuppressWarnings(value = "unchecked") private void serveFile(HttpServletRequest req, HttpServletResponse res, String path) throws IOException { String queryString = req.getQueryString(); int contentLength = req.getContentLength(); int c; log("running " + path + "?" + queryString); // Make argument list. String argList[] = (path + (queryString != null && queryString.indexOf("=") == -1 ? "+" + queryString : "")) .split("\\+"); /* 1.4 */ // Make environment list. Vector envVec = new Vector(); envVec.addElement(makeEnv("PATH", "/usr/local/bin:/usr/ucb:/bin:/usr/bin")); envVec.addElement(makeEnv("GATEWAY_INTERFACE", "CGI/1.1")); envVec.addElement(makeEnv("SERVER_SOFTWARE", getServletContext().getServerInfo())); envVec.addElement(makeEnv("SERVER_NAME", req.getServerName())); envVec.addElement(makeEnv("SERVER_PORT", Integer.toString(req.getServerPort()))); envVec.addElement(makeEnv("REMOTE_ADDR", req.getRemoteAddr())); envVec.addElement(makeEnv("REMOTE_HOST", req.getRemoteHost())); envVec.addElement(makeEnv("REQUEST_METHOD", req.getMethod())); if (contentLength != -1) envVec.addElement(makeEnv("CONTENT_LENGTH", Integer.toString(contentLength))); if (req.getContentType() != null) envVec.addElement(makeEnv("CONTENT_TYPE", req.getContentType())); envVec.addElement(makeEnv("SCRIPT_NAME", req.getServletPath())); if (req.getPathInfo() != null) envVec.addElement(makeEnv("PATH_INFO", req.getPathInfo())); if (req.getPathTranslated() != null) envVec.addElement(makeEnv("PATH_TRANSLATED", req.getPathTranslated())); if (queryString != null) envVec.addElement(makeEnv("QUERY_STRING", queryString)); envVec.addElement(makeEnv("SERVER_PROTOCOL", req.getProtocol())); if (req.getRemoteUser() != null) envVec.addElement(makeEnv("REMOTE_USER", req.getRemoteUser())); if (req.getAuthType() != null) envVec.addElement(makeEnv("AUTH_TYPE", req.getAuthType())); Enumeration hnEnum = req.getHeaderNames(); while (hnEnum.hasMoreElements()) { String name = (String) hnEnum.nextElement(); String value = req.getHeader(name); if (value == null) value = ""; envVec.addElement(makeEnv("HTTP_" + name.toUpperCase().replace('-', '_'), value)); } String envList[] = makeList(envVec); // Start the command. Process proc = Runtime.getRuntime().exec(argList, envList); try { // If it's a POST, copy the request data to the process. if (req.getMethod().equalsIgnoreCase("post")) { InputStream reqIn = req.getInputStream(); OutputStream procOut = proc.getOutputStream(); for (int i = 0; i < contentLength; ++i) { c = reqIn.read(); if (c == -1) break; procOut.write(c); } procOut.close(); } // Now read the response from the process. BufferedReader procIn = new BufferedReader(new InputStreamReader(proc.getInputStream())); OutputStream resOut = res.getOutputStream(); // Some of the headers have to be intercepted and handled. boolean firstLine = true; while (true) { String line = procIn.readLine(); if (line == null) break; line = line.trim(); if (line.equals("")) break; int colon = line.indexOf(":"); if (colon == -1) { // No colon. If it's the first line, parse it for status. if (firstLine) { StringTokenizer tok = new StringTokenizer(line, " "); try { switch (tok.countTokens()) { case 2: tok.nextToken(); res.setStatus(Integer.parseInt(tok.nextToken())); break; case 3: tok.nextToken(); res.setStatus(Integer.parseInt(tok.nextToken()), tok.nextToken()); break; } } catch (NumberFormatException ignore) { } } else { // No colon and it's not the first line? Ignore. } } else { // There's a colon. Check for certain special headers. String name = line.substring(0, colon); String value = line.substring(colon + 1).trim(); if (name.equalsIgnoreCase("Status")) { StringTokenizer tok = new StringTokenizer(value, " "); try { switch (tok.countTokens()) { case 1: res.setStatus(Integer.parseInt(tok.nextToken())); break; case 2: res.setStatus(Integer.parseInt(tok.nextToken()), tok.nextToken()); break; } } catch (NumberFormatException ignore) { } } else if (name.equalsIgnoreCase("Content-type")) { res.setContentType(value); } else if (name.equalsIgnoreCase("Content-length")) { try { res.setContentLength(Integer.parseInt(value)); } catch (NumberFormatException ignore) { } } else if (name.equalsIgnoreCase("Location")) { res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); res.setHeader(name, value); } else { // Not a special header. Just set it. res.setHeader(name, value); } } } // Copy the rest of the data uninterpreted. Acme.Utils.copyStream(procIn, resOut, null); procIn.close(); resOut.close(); } catch (IOException e) { // res.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR ); // There's some weird bug in Java, when reading from a Process // you get a spurious IOException. We have to ignore it. } } private static String makeEnv(String name, String value) { return name + "=" + value; } private static String[] makeList(Vector vec) { String list[] = new String[vec.size()]; for (int i = 0; i < vec.size(); ++i) list[i] = (String) vec.elementAt(i); return list; } }