|
Jetty example source code file (CGI.java)
The Jetty CGI.java source code//======================================================================== //Copyright 2006 Mort Bay Consulting Pty. Ltd. //------------------------------------------------------------------------ //Licensed under the Apache License, Version 2.0 (the "License"); //you may not use this file except in compliance with the License. //You may obtain a copy of the License at //http://www.apache.org/licenses/LICENSE-2.0 //Unless required by applicable law or agreed to in writing, software //distributed under the License is distributed on an "AS IS" BASIS, //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //See the License for the specific language governing permissions and //limitations under the License. //======================================================================== package org.mortbay.servlet; 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.io.PrintWriter; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.mortbay.log.Log; import org.mortbay.util.IO; import org.mortbay.util.StringUtil; //----------------------------------------------------------------------------- /** * CGI Servlet. * * The cgi bin directory can be set with the "cgibinResourceBase" init parameter * or it will default to the resource base of the context. * * The "commandPrefix" init parameter may be used to set a prefix to all * commands passed to exec. This can be used on systems that need assistance to * execute a particular file type. For example on windows this can be set to * "perl" so that perl scripts are executed. * * The "Path" init param is passed to the exec environment as PATH. Note: Must * be run unpacked somewhere in the filesystem. * * Any initParameter that starts with ENV_ is used to set an environment * variable with the name stripped of the leading ENV_ and using the init * parameter value. * * @author Julian Gosnell * @author Thanassis Papathanasiou - Some minor modifications for Jetty6 port */ public class CGI extends HttpServlet { private boolean _ok; private File _docRoot; private String _path; private String _cmdPrefix; private EnvList _env; private boolean _ignoreExitState; /* ------------------------------------------------------------ */ public void init() throws ServletException { _env=new EnvList(); _cmdPrefix=getInitParameter("commandPrefix"); String tmp=getInitParameter("cgibinResourceBase"); if (tmp==null) { tmp=getInitParameter("resourceBase"); if (tmp==null) tmp=getServletContext().getRealPath("/"); } if (tmp==null) { Log.warn("CGI: no CGI bin !"); return; } File dir=new File(tmp); if (!dir.exists()) { Log.warn("CGI: CGI bin does not exist - "+dir); return; } if (!dir.canRead()) { Log.warn("CGI: CGI bin is not readable - "+dir); return; } if (!dir.isDirectory()) { Log.warn("CGI: CGI bin is not a directory - "+dir); return; } try { _docRoot=dir.getCanonicalFile(); } catch (IOException e) { Log.warn("CGI: CGI bin failed - "+dir,e); return; } _path=getInitParameter("Path"); if (_path!=null) _env.set("PATH",_path); _ignoreExitState="true".equalsIgnoreCase(getInitParameter("ignoreExitState")); Enumeration e=getInitParameterNames(); while (e.hasMoreElements()) { String n=(String)e.nextElement(); if (n!=null&&n.startsWith("ENV_")) _env.set(n.substring(4),getInitParameter(n)); } if(!_env.envMap.containsKey("SystemRoot")) { String os = System.getProperty("os.name"); if (os!=null && os.toLowerCase().indexOf("windows")!=-1) { String windir = System.getProperty("windir"); _env.set("SystemRoot", windir!=null ? windir : "C:\\WINDOWS"); } } _ok=true; } /* ------------------------------------------------------------ */ public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { if (!_ok) { res.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); return; } String pathInContext=StringUtil.nonNull(req.getServletPath())+StringUtil.nonNull(req.getPathInfo()); if (Log.isDebugEnabled()) { Log.debug("CGI: ContextPath : "+req.getContextPath()); Log.debug("CGI: ServletPath : "+req.getServletPath()); Log.debug("CGI: PathInfo : "+req.getPathInfo()); Log.debug("CGI: _docRoot : "+_docRoot); Log.debug("CGI: _path : "+_path); Log.debug("CGI: _ignoreExitState: "+_ignoreExitState); } // pathInContext may actually comprises scriptName/pathInfo...We will // walk backwards up it until we find the script - the rest must // be the pathInfo; String both=pathInContext; String first=both; String last=""; File exe=new File(_docRoot,first); while ((first.endsWith("/")||!exe.exists())&&first.length()>=0) { int index=first.lastIndexOf('/'); first=first.substring(0,index); last=both.substring(index,both.length()); exe=new File(_docRoot,first); } if (first.length()==0||!exe.exists()||exe.isDirectory()||!exe.getCanonicalPath().equals(exe.getAbsolutePath())) { res.sendError(404); } else { if (Log.isDebugEnabled()) { Log.debug("CGI: script is "+exe); Log.debug("CGI: pathInfo is "+last); } exec(exe,last,req,res); } } /* ------------------------------------------------------------ */ /* * @param root @param path @param req @param res @exception IOException */ private void exec(File command, String pathInfo, HttpServletRequest req, HttpServletResponse res) throws IOException { String path=command.getAbsolutePath(); File dir=command.getParentFile(); String scriptName=req.getRequestURI().substring(0,req.getRequestURI().length()-pathInfo.length()); String scriptPath=getServletContext().getRealPath(scriptName); String pathTranslated=req.getPathTranslated(); int len=req.getContentLength(); if (len<0) len=0; if ((pathTranslated==null)||(pathTranslated.length()==0)) pathTranslated=path; EnvList env=new EnvList(_env); // these ones are from "The WWW Common Gateway Interface Version 1.1" // look at : // http://Web.Golux.Com/coar/cgi/draft-coar-cgi-v11-03-clean.html#6.1.1 env.set("AUTH_TYPE",req.getAuthType()); env.set("CONTENT_LENGTH",Integer.toString(len)); env.set("CONTENT_TYPE",req.getContentType()); env.set("GATEWAY_INTERFACE","CGI/1.1"); if ((pathInfo!=null)&&(pathInfo.length()>0)) { env.set("PATH_INFO",pathInfo); } env.set("PATH_TRANSLATED",pathTranslated); env.set("QUERY_STRING",req.getQueryString()); env.set("REMOTE_ADDR",req.getRemoteAddr()); env.set("REMOTE_HOST",req.getRemoteHost()); // The identity information reported about the connection by a // RFC 1413 [11] request to the remote agent, if // available. Servers MAY choose not to support this feature, or // not to request the data for efficiency reasons. // "REMOTE_IDENT" => "NYI" env.set("REMOTE_USER",req.getRemoteUser()); env.set("REQUEST_METHOD",req.getMethod()); env.set("SCRIPT_NAME",scriptName); env.set("SCRIPT_FILENAME",scriptPath); env.set("SERVER_NAME",req.getServerName()); env.set("SERVER_PORT",Integer.toString(req.getServerPort())); env.set("SERVER_PROTOCOL",req.getProtocol()); env.set("SERVER_SOFTWARE",getServletContext().getServerInfo()); Enumeration enm=req.getHeaderNames(); while (enm.hasMoreElements()) { String name=(String)enm.nextElement(); String value=req.getHeader(name); env.set("HTTP_"+name.toUpperCase().replace('-','_'),value); } // these extra ones were from printenv on www.dev.nomura.co.uk env.set("HTTPS",(req.isSecure()?"ON":"OFF")); // "DOCUMENT_ROOT" => root + "/docs", // "SERVER_URL" => "NYI - http://us0245", // "TZ" => System.getProperty("user.timezone"), // are we meant to decode args here ? or does the script get them // via PATH_INFO ? if we are, they should be decoded and passed // into exec here... String execCmd=path; if ((execCmd.charAt(0)!='"')&&(execCmd.indexOf(" ")>=0)) execCmd="\""+execCmd+"\""; if (_cmdPrefix!=null) execCmd=_cmdPrefix+" "+execCmd; Process p=(dir==null)?Runtime.getRuntime().exec(execCmd,env.getEnvArray()):Runtime.getRuntime().exec(execCmd,env.getEnvArray(),dir); // hook processes input to browser's output (async) final InputStream inFromReq=req.getInputStream(); final OutputStream outToCgi=p.getOutputStream(); final int inLength=len; IO.copyThread(p.getErrorStream(),System.err); new Thread(new Runnable() { public void run() { try { if (inLength>0) IO.copy(inFromReq,outToCgi,inLength); outToCgi.close(); } catch (IOException e) { Log.ignore(e); } } }).start(); // hook processes output to browser's input (sync) // if browser closes stream, we should detect it and kill process... OutputStream os = null; try { // read any headers off the top of our input stream // NOTE: Multiline header items not supported! String line=null; InputStream inFromCgi=p.getInputStream(); //br=new BufferedReader(new InputStreamReader(inFromCgi)); //while ((line=br.readLine())!=null) while( (line = getTextLineFromStream( inFromCgi )).length() > 0 ) { if (!line.startsWith("HTTP")) { int k=line.indexOf(':'); if (k>0) { String key=line.substring(0,k).trim(); String value = line.substring(k+1).trim(); if ("Location".equals(key)) { res.sendRedirect(value); } else if ("Status".equals(key)) { String[] token = value.split( " " ); int status=Integer.parseInt(token[0]); res.setStatus(status); } else { // add remaining header items to our response header res.addHeader(key,value); } } } } // copy cgi content to response stream... os = res.getOutputStream(); IO.copy(inFromCgi, os); p.waitFor(); if (!_ignoreExitState) { int exitValue=p.exitValue(); if (0!=exitValue) { Log.warn("Non-zero exit status ("+exitValue+") from CGI program: "+path); if (!res.isCommitted()) res.sendError(500,"Failed to exec CGI"); } } } catch (IOException e) { // browser has probably closed its input stream - we // terminate and clean up... Log.debug("CGI: Client closed connection!"); } catch (InterruptedException ie) { Log.debug("CGI: interrupted!"); } finally { if( os != null ) os.close(); os = null; p.destroy(); // Log.debug("CGI: terminated!"); } } /** * Utility method to get a line of text from the input stream. * @param is the input stream * @return the line of text * @throws IOException */ private String getTextLineFromStream( InputStream is ) throws IOException { StringBuffer buffer = new StringBuffer(); int b; while( (b = is.read()) != -1 && b != (int) '\n' ) { buffer.append( (char) b ); } return buffer.toString().trim(); } /* ------------------------------------------------------------ */ /** * private utility class that manages the Environment passed to exec. */ private static class EnvList { private Map envMap; EnvList() { envMap=new HashMap(); } EnvList(EnvList l) { envMap=new HashMap(l.envMap); } /** * Set a name/value pair, null values will be treated as an empty String */ public void set(String name, String value) { envMap.put(name,name+"="+StringUtil.nonNull(value)); } /** Get representation suitable for passing to exec. */ public String[] getEnvArray() { return (String[])envMap.values().toArray(new String[envMap.size()]); } public String toString() { return envMap.toString(); } } } Other Jetty examples (source code examples)Here is a short list of links related to this Jetty CGI.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.