📄 cgiframe.java
字号:
/** * Get the CGI debug flag. * @return The boolean value of the CGI debug flag. */ public boolean checkCgiDebug() { return getBoolean(ATTR_CGI_DEBUG, false); } /** * Turn the given header name into it's env var canonical name. * This guy is crazy enough to run CGI scripts, he can pay for that * overhead. * @param name The header name. * @return A String giving the official env variable name for that header. */ public String getEnvName(String name) { int sl = name.length(); StringBuffer sb = new StringBuffer(5+sl); sb.append("HTTP_"); for (int i = 0 ; i < sl ; i++) { char ch = name.charAt(i); sb.append((ch == '-') ? '_' : Character.toUpperCase(ch)); } return sb.toString(); } /** * Get this resource Etag * @return an instance of HttpEntityTag, or <strong>null</strong> if not * defined. */ public HttpEntityTag getETag() { if (etag == null) { HttpEntityTag netag = super.getETag(); if (netag != null) { etag.setWeak(true); } } return etag; } /** * Handle the CGI script output. * This methods handles the CGI script output. Depending on the * value of the <strong>noheader</strong> attribute it either: * <ul> * <li>Sends back the script output directly,</li> * <li>Parses the script output, looking for a status header or a * location header, or a content-length header, or any combination * of those three. * </ul> * @param process The underlying CGI process. * @param request The processed request. * @exception ProtocolException If an HTTP error * should be sent back to the client. */ protected Reply handleCGIOutput (Process process, Request request) throws ProtocolException { // first, take care of error stream (new ProcessErrorReader(process)).start(); // No header script don't deserve attention: if ( checkNoheaderFlag() ) { Reply reply = request.makeReply(HTTP.NOHEADER) ; reply.setStream (process.getInputStream()) ; return reply ; } // Check for debugging mode: if ( checkCgiDebug() ) { Reply reply = request.makeReply(HTTP.OK); reply.setContentType(MimeType.TEXT_PLAIN); reply.setStream(process.getInputStream()); return reply; } // We MUST parse at least one header: MimeParser p = new MimeParser(process.getInputStream(), new CGIHeaderHolderFactory()); Reply reply = null ; try { CGIHeaderHolder h = (CGIHeaderHolder) p.parse(); // Check for a status code: String svalue = h.getStatus(); String location = h.getLocation(); if ( svalue != null ) { int status = -1; try { String _st = svalue.trim(); int _space = _st.indexOf(' '); if (_space != -1) { _st = _st.substring(0, _space); } status = Integer.parseInt(_st); } catch (Exception ex) { // This script has emited an invalid status line: String msg = ("Emited an invalid status line ["+ svalue + "]."); getServer().errlog(this, msg); // Throw an HTTPException: reply = request.makeReply(HTTP.INTERNAL_SERVER_ERROR); reply.setContent("CGI script emited invalid status."); throw new HTTPException(reply); } // we will use the default for this frame, but remove // the length calculated from the script size. reply = createDefaultReply(request, status); reply.setContentLength(-1); } else { // No status code available, any location header ? if (location != null) { reply = request.makeReply(HTTP.FOUND); } else { reply = createDefaultReply(request, HTTP.OK); reply.setContentLength(-1); } } // Set up the location header if needed: if ( location != null ) { try { reply.setLocation(new URL(getURL(request), location)); } catch (MalformedURLException ex) { // This should really not happen: getServer().errlog(this, "unable to create location url "+ location+ " in base "+getURL(request)); } } // And then, the remaining headers: Enumeration e = h.enumerateHeaders(); if ( e != null ) { while ( e.hasMoreElements() ) { String hname = (String) e.nextElement(); reply.setValue(hname, (String) h.getValue(hname)); } } reply.setStream(p.getInputStream()) ; } catch (IOException ex) { ex.printStackTrace(); } catch (MimeParserException ex) { // This script has generated invalid output: String msg = (getURL(request) +": emited invalid output ["+ ex.getMessage() +"]"); getServer().errlog(this, msg); // Throw an HTTPException: Reply error = request.makeReply(HTTP.INTERNAL_SERVER_ERROR) ; error.setContent("CGI error: unable to parse script headers.") ; throw new HTTPException (error) ; } if (reply != null) { reply.setDynamic(true); } return reply ; } /** * Add an enviornment binding to the given vector. * @param name The name of the enviornment variable. * @param val Its value. * @param into The vector to which accumulate bindings. */ private void addEnv (String name, String val, Vector into) { into.addElement (name+"="+val) ; } /** * Prepare the command to run for this CGI script, and run it. * @param request The request to handle. * @return The running CGI process object. * @exception ProtocolException If we weren't able * to build the command or the environment. * @exception IOException if an IO erro occurs. */ protected Process makeCgiCommand (Request request) throws ProtocolException, IOException { // Check the command attribute first: String query = null; String command[] = getCommand() ; if ( command == null ) { Reply error = request.makeReply(HTTP.INTERNAL_SERVER_ERROR) ; error.setContent("CgiResource mis-configured: it doesn't have a " + " command attribute"); throw new HTTPException(error); } // Ok: Vector env = new Vector(32) ; httpd server = request.getClient().getServer() ; InetAddress sadr = server.getInetAddress() ; // Specified environment variables: // We do not handle the following variables: // - REMOTE_IDENT: would require usage of IDENT protocol. // Authentification type, if any: String svalue = (String) request.getState(AuthFilter.STATE_AUTHTYPE); if ( svalue != null ) addEnv("AUTH_TYPE", svalue, env); // Content length, if available: svalue = request.getValue("content-length"); if ( svalue != null ) addEnv("CONTENT_LENGTH", svalue, env); // Content type, if available: svalue = request.getValue("content-type"); if ( svalue != null ) addEnv("CONTENT_TYPE", svalue, env); // The gateway interface, hopefully 1.1 ! addEnv ("GATEWAY_INTERFACE", "CGI/1.1", env) ; // The PATH_INFO, which I am afraid I still don't understand: svalue = (String) request.getState(STATE_EXTRA_PATH); if ( svalue == null ) addEnv ("PATH_INFO", "/", env) ; else addEnv ("PATH_INFO", svalue, env) ; // The query string: query = request.getQueryString(); if ( query != null ) addEnv("QUERY_STRING", query, env) ; // The remote client IP address: svalue = request.getClient().getInetAddress().toString(); addEnv ("REMOTE_ADDR", svalue, env); // Authentified user: svalue = (String) request.getState(AuthFilter.STATE_AUTHUSER); if ( svalue != null ) addEnv("REMOTE_USER", svalue, env); // Remote host name, if allowed: if ( checkRemoteHost() ) { String host = request.getClient().getInetAddress().getHostName(); addEnv("REMOTE_HOST", host, env); } // The request method: addEnv ("REQUEST_METHOD", request.getMethod(), env) ; // The script name : addEnv("SCRIPT_NAME", getURLPath(), env); // Server name: addEnv ("SERVER_NAME", getServer().getHost(), env) ; // Server port: svalue = Integer.toString(getServer().getLocalPort()); addEnv ("SERVER_PORT", svalue, env); // Server protocol: addEnv ("SERVER_PROTOCOL", request.getVersion(), env) ; // Server software: addEnv ("SERVER_SOFTWARE", server.getSoftware(), env) ; if (getFileResource()!= null) { addEnv("PATH_TRANSLATED", getFileResource().getFile().getAbsolutePath(), env); } //Add user env ArrayDictionary uenv = getUserEnv(); if (uenv != null) { Enumeration names = uenv.keys(); while (names.hasMoreElements()) { String var = (String)names.nextElement(); addEnv(var, (String)uenv.get(var), env); } } // All other request fields, yeah, let's lose even more time: Enumeration e = request.enumerateHeaderDescriptions(false); while ( e.hasMoreElements() ) { HeaderDescription d = (HeaderDescription) e.nextElement(); addEnv(getEnvName(d.getName()) , request.getHeaderValue(d).toString() , env); } // Command line: if ( query != null ) { String querycmd[] = new String[command.length+1] ; System.arraycopy(command, 0, querycmd, 0, command.length) ; querycmd[command.length] = query ; command = querycmd ; } String aenv[] = new String[env.size()] ; env.copyInto (aenv) ; // Run the process: if ( getInterpreter() != null ) { String run[] = new String[command.length+1]; run[0] = getInterpreter(); System.arraycopy(command, 0, run, 1, command.length); return Runtime.getRuntime().exec (run, aenv) ; } else { return Runtime.getRuntime().exec (command, aenv) ; } } /** * Lookup sub-resources. * Accumulate the remaning path in some special state of the request. * <p>This allows us to implement the <code>PATH_INFO</code> * CGI variable properly. * @param ls Current lookup state. * @param lr Lookup result under construction. * @return A boolean <strong>true</strong> if lookup should continue, * <strong>false</strong> otherwise. * @exception ProtocolException (fixme doc) */ public boolean lookup(LookupState ls, LookupResult lr) throws ProtocolException { // Get the extra path information: String extraPath = ls.getRemainingPath(true); if ((extraPath == null) || extraPath.equals("")) extraPath = "/"; // Keep this path info into the request, if possible: Request request = (Request) ls.getRequest(); if ( request != null ) request.setState(STATE_EXTRA_PATH, extraPath); lr.setTarget(getResource().getResourceReference()); return super.lookup(ls, lr); } /** * GET method implementation. * this method is splitted into two cases: * <p>If the resource is able to generates its form, than run the script * to emit the form. Otherwsie, use our super class (FileResource) ability * to send the file that contains the form. * <p>Note that there is no need to feed the underlying process with * data in the GET case. * @param request The request to handle. * @exception ProtocolException If processing the request failed. * @exception ResourceException If the resource got a fatal error. */ public Reply get(Request request) throws ProtocolException, ResourceException { if ( ! checkGeneratesFormFlag() ) return super.get (request) ; Process process = null ; try { process = makeCgiCommand (request) ; } catch (IOException e) { e.printStackTrace(); Reply error = request.makeReply(HTTP.NOT_FOUND) ; error.setContent("The resource's script wasn't found.") ; throw new HTTPException (error) ; } return handleCGIOutput (process, request) ; } /** * Handle the POST method according to CGI/1.1 specification. * The request body is sent back to the launched CGI script, as is, and * the script output is handled by the handleCGIOutput method. * @param request The request to process. * @exception ProtocolException If the processing failed. * @exception ResourceException If the resource got a fatal error. */ public Reply post(Request request) throws ProtocolException, ResourceException { Process process = null ; // Launch the CGI process: try { process = makeCgiCommand(request) ; } catch (IOException ex) { // The process wasn't executable, emit a errlog message: String msg = ("The process "+ getCommand()[0] +" couldn't be executed ["+ ex.getMessage() + "]"); getServer().errlog(this, msg); // Throw an internal server error: Reply error = request.makeReply(HTTP.INTERNAL_SERVER_ERROR) ; error.setContent("CGI script is misconfigured."); throw new HTTPException (error) ; } // Now feed the process: try { // Send the 100 status code: Client client = request.getClient(); if ( client != null ) client.sendContinue(); InputStream in = request.getInputStream(); if ( in == null ) { // There was no input to that CCI, close process stream process.getOutputStream().close(); } else { // Some input to feed the process with: (new ProcessFeeder(process, in)).start(); } } catch (IOException ex) { // This is most probably a bad request: Reply error = request.makeReply(HTTP.BAD_REQUEST); error.setContent("The request didn't have a valid input."); throw new HTTPException(error); } return handleCGIOutput(process, request); } /** * At register time, if no command, use a suitable default. * THis method will set the command to the identifier, if it is not * provided. * @param values Default attribute values. */ public void registerResource(FramedResource resource) { super.registerResource(resource); //if no command is specified look for a file resource attached //and get its File absolute path if available. if (getCommand() == null) { if (getFileResource() != null) { try { if (getFileResource().getFile() != null) { String cmd[] = new String[1]; cmd[0] = getFileResource().getFile().getAbsolutePath(); setValue(ATTR_COMMAND, cmd); } } catch (InvalidParentException ex) { //nothing to do //probably an indexer operation } } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -