Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / jigsaw / WWW / Doc / Programmer / samples / CgiFrame.html
diff --git a/JMCR-Stable/real-world application/jigsaw/WWW/Doc/Programmer/samples/CgiFrame.html b/JMCR-Stable/real-world application/jigsaw/WWW/Doc/Programmer/samples/CgiFrame.html
new file mode 100644 (file)
index 0000000..2773531
--- /dev/null
@@ -0,0 +1,719 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"\r
+                      "http://www.w3.org/TR/REC-html40/strict.dtd">\r
+<html>\r
+  <head>\r
+    <title>CgiFrame.java</title>\r
+    <meta name="Author" content="Benoit Mahe">\r
+    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">\r
+    <meta name="Generator" content="*emacs: emacs-css">\r
+\r
+    <link rel="Stylesheet" media="screen" type="text/css" href="default-html.css">\r
+  </head>\r
+  <body>\r
+\r
+    <pre>\r
+<span class="comment">// CgiFrame.java\r
+// $Id: CgiFrame.html,v 1.1 2010/06/15 12:20:01 smhuang Exp $\r
+// (c) COPYRIGHT MIT and INRIA, 1996.\r
+// Please first read the full copyright statement in file COPYRIGHT.html\r
+</span>\r
+<span class="keyword">package</span> <span class="reference">org</span>.<span class="reference">w3c</span>.<span class="reference">jigsaw</span>.<span class="type">frames</span> ;\r
+\r
+<span class="keyword">import</span> <span class="reference">java</span>.<span class="reference">io</span>.* ;\r
+<span class="keyword">import</span> <span class="reference">java</span>.<span class="reference">util</span>.*;\r
+<span class="keyword">import</span> <span class="reference">java</span>.<span class="reference">net</span>.*;\r
+\r
+<span class="keyword">import</span> <span class="reference">org</span>.<span class="reference">w3c</span>.<span class="reference">tools</span>.<span class="reference">resources</span>.*;\r
+<span class="keyword">import</span> <span class="reference">org</span>.<span class="reference">w3c</span>.<span class="reference">tools</span>.<span class="reference">resources</span>.<span class="type">ProtocolException</span>;\r
+<span class="keyword">import</span> <span class="reference">org</span>.<span class="reference">w3c</span>.<span class="reference">www</span>.<span class="reference">mime</span>.* ;\r
+<span class="keyword">import</span> <span class="reference">org</span>.<span class="reference">w3c</span>.<span class="reference">jigsaw</span>.<span class="reference">http</span>.* ;\r
+<span class="keyword">import</span> <span class="reference">org</span>.<span class="reference">w3c</span>.<span class="reference">www</span>.<span class="reference">http</span>.*;\r
+<span class="keyword">import</span> <span class="reference">org</span>.<span class="reference">w3c</span>.<span class="reference">jigsaw</span>.<span class="reference">auth</span>.<span class="type">AuthFilter</span>;\r
+\r
+<span class="comment">/**\r
+ * Parsing the CGI output - The CGIHeaderHolder, to hold CGI headers.\r
+ */</span>\r
+<span class="keyword">class</span> <span class="function-name">CGIHeaderHolder</span> <span class="keyword">implements</span> <span class="type">MimeHeaderHolder</span> {\r
+    <span class="comment">// Status and Location deserve special treatments:\r
+</span>    <span class="type">String</span> <span class="variable-name">status</span>   = <span class="keyword">null</span>;\r
+    <span class="type">String</span> <span class="variable-name">location</span> = <span class="keyword">null</span>;\r
+    <span class="comment">// Anyway, he is going to pay for using CGI\r
+</span>    <span class="type">Hashtable</span> <span class="variable-name">headers</span> = <span class="keyword">null</span>;\r
+    <span class="comment">// The MIME parse we are attached to:\r
+</span>    <span class="type">MimeParser</span> <span class="variable-name">parser</span> = <span class="keyword">null</span>;\r
+\r
+    <span class="comment">/**\r
+     * The parsing is now about to start, take any appropriate action.\r
+     * This hook can return a &lt;strong&gt;true&lt;/strong&gt; boolean value to enforce\r
+     * the MIME parser into transparent mode (eg the parser will &lt;em&gt;not&lt;/em&gt;\r
+     * try to parse any headers.\r
+     * &lt;p&gt;This hack is primarily defined for HTTP/0.9 support, it might\r
+     * also be usefull for other hacks.\r
+     * </span><span class="keyword">@param </span><span class="variable-name">parser</span><span class="comment"> The Mime parser.\r
+     * </span><span class="keyword">@return </span><span class="comment">A boolean &lt;strong&gt;true&lt;/strong&gt; if the MimeParser shouldn't\r
+     * continue the parsing, &lt;strong&gt;false&lt;/strong&gt; otherwise.\r
+     */</span>\r
+\r
+    <span class="reference">public</span> <span class="type">boolean</span> <span class="function-name">notifyBeginParsing</span>(<span class="type">MimeParser</span> <span class="variable-name">parser</span>)\r
+       <span class="keyword">throws</span> <span class="type">IOException</span>\r
+    {\r
+       <span class="keyword">return</span> <span class="keyword">false</span>;\r
+    }\r
+\r
+    <span class="comment">/**\r
+     * All the headers have been parsed, take any appropriate actions.\r
+     * </span><span class="keyword">@param </span><span class="variable-name">parser</span><span class="comment"> The Mime parser.\r
+     */</span>\r
+\r
+    <span class="reference">public</span> <span class="type">void</span> <span class="function-name">notifyEndParsing</span>(<span class="type">MimeParser</span> <span class="variable-name">parser</span>)\r
+       <span class="keyword">throws</span> <span class="type">IOException</span>\r
+    {\r
+       <span class="keyword">return</span> ;\r
+    }\r
+\r
+    <span class="comment">/**\r
+     * A new header has been emited by the script.\r
+     * If the script is not an NPH, then it &lt;strong&gt;must&lt;/strong&gt; at least\r
+     * emit one header, so we are safe here, although people may not be safe \r
+     * against the spec.\r
+     * </span><span class="keyword">@param </span><span class="variable-name">name</span><span class="comment"> The header name.\r
+     * </span><span class="keyword">@param </span><span class="variable-name">buf</span><span class="comment"> The header bytes.\r
+     * </span><span class="keyword">@param </span><span class="variable-name">off</span><span class="comment"> The begining of the value bytes  in above buffer.\r
+     * </span><span class="keyword">@param </span><span class="variable-name">len</span><span class="comment"> The length of the value bytes  in above buffer.\r
+     */</span>\r
+\r
+    <span class="reference">public</span> <span class="type">void</span> <span class="function-name">notifyHeader</span>(<span class="type">String</span> <span class="variable-name">name</span>, <span class="type">byte</span> <span class="variable-name">buf</span>[], <span class="type">int</span> <span class="variable-name">off</span>, <span class="type">int</span> <span class="variable-name">len</span>)\r
+       <span class="keyword">throws</span> <span class="type">MimeParserException</span>\r
+    {\r
+       <span class="keyword">if</span> ( name.equalsIgnoreCase("<span class="string">status</span>") ) {\r
+           status = <span class="keyword">new</span> <span class="type">String</span>(buf, 0, off, len);\r
+       } <span class="keyword">else</span> <span class="keyword">if</span> ( name.equalsIgnoreCase("<span class="string">location</span>") ) {\r
+           location = <span class="keyword">new</span> <span class="type">String</span>(buf, 0, off, len);\r
+       } <span class="keyword">else</span> {\r
+           <span class="type">String</span> <span class="variable-name">extraval</span> =  <span class="keyword">new</span> <span class="type">String</span>(buf, 0, off, len);\r
+           <span class="keyword">if</span> ( headers == <span class="keyword">null</span> ) {\r
+               headers = <span class="keyword">new</span> <span class="type">Hashtable</span>(11);\r
+           } <span class="keyword">else</span> {\r
+               <span class="type">String</span> <span class="variable-name">val</span> = (<span class="type">String</span>) headers.get(name.toLowerCase());\r
+               <span class="keyword">if</span> ( val != <span class="keyword">null</span> )\r
+                   extraval = val + "<span class="string">,</span>" + extraval;\r
+           }\r
+           headers.put(name.toLowerCase(), extraval);\r
+       }\r
+    }\r
+\r
+    <span class="comment">/**\r
+     * Get the status emited by the script.\r
+     */</span>\r
+    \r
+    <span class="reference">public</span> <span class="type">String</span> <span class="function-name">getStatus</span>() {\r
+       <span class="keyword">return</span> status;\r
+    }\r
+\r
+    <span class="comment">/**\r
+     * Get the location header value emited by the script.\r
+     */</span>\r
+\r
+    <span class="reference">public</span> <span class="type">String</span> <span class="function-name">getLocation</span>() {\r
+       <span class="keyword">return</span> location;\r
+    }\r
+\r
+    <span class="comment">/**\r
+     * Get any header value (except status and location).\r
+     * </span><span class="keyword">@param </span><span class="variable-name">name</span><span class="comment"> The name of the header to fetch.\r
+     * </span><span class="keyword">@return </span><span class="comment">The string value of requested header, or &lt;strong&gt;null&lt;/strong&gt;\r
+     * if header was not defined.\r
+     */</span>\r
+\r
+    <span class="reference">public</span> <span class="type">String</span> <span class="function-name">getValue</span>(<span class="type">String</span> <span class="variable-name">name</span>) {\r
+       <span class="keyword">return</span> (headers == <span class="keyword">null</span>) ? <span class="keyword">null</span> : (<span class="type">String</span>) headers.get(name);\r
+    }\r
+\r
+    <span class="comment">/**\r
+     * Enumerate the headers defined by the holder.\r
+     * </span><span class="keyword">@return </span><span class="comment">A enumeration of header names, or &lt;strong&gt;null&lt;/strong&gt; if no\r
+     * header is defined.\r
+     */</span>\r
+    \r
+    <span class="reference">public</span> <span class="type">Enumeration</span> <span class="function-name">enumerateHeaders</span>() {\r
+       <span class="keyword">if</span> ( headers == <span class="keyword">null</span> )\r
+           <span class="keyword">return</span> <span class="keyword">null</span>;\r
+       <span class="keyword">return</span> headers.keys();\r
+    }\r
+\r
+    <span class="comment">/**\r
+     * Get the remaining output of the stream.\r
+     * This should be called only once header parsing is done.\r
+     */</span>\r
+\r
+    <span class="reference">public</span> <span class="type">InputStream</span> <span class="function-name">getInputStream</span>() {\r
+       <span class="keyword">return</span> parser.getInputStream();\r
+    }\r
+\r
+    <span class="function-name">CGIHeaderHolder</span>(<span class="type">MimeParser</span> <span class="variable-name">parser</span>) {\r
+       <span class="reference">this</span>.parser = parser;\r
+    }\r
+\r
+}\r
+\r
+<span class="comment">/**\r
+ * Parsing the CGI output - Always create a CGIHeaderHolder.\r
+ */</span>\r
+\r
+<span class="keyword">class</span> <span class="function-name">CGIHeaderHolderFactory</span> <span class="keyword">implements</span> <span class="type">MimeParserFactory</span> {\r
+    \r
+    <span class="comment">/**\r
+     * Create a new header holder to hold the parser's result.\r
+     * </span><span class="keyword">@param </span><span class="variable-name">parser</span><span class="comment"> The parser that has something to parse.\r
+     * </span><span class="keyword">@return </span><span class="comment">A MimeParserHandler compliant object.\r
+     */</span>\r
+\r
+    <span class="reference">public</span> <span class="type">MimeHeaderHolder</span> <span class="function-name">createHeaderHolder</span>(<span class="type">MimeParser</span> <span class="variable-name">parser</span>) {\r
+       <span class="keyword">return</span> <span class="keyword">new</span> <span class="type">CGIHeaderHolder</span>(parser);\r
+    }\r
+\r
+    <span class="function-name">CGIHeaderHolderFactory</span>() {\r
+    }\r
+\r
+}\r
+\r
+<span class="comment">/**\r
+ * A simple process feeder class.\r
+ */</span>\r
+\r
+<span class="keyword">class</span> <span class="function-name">ProcessFeeder</span> <span class="keyword">extends</span> <span class="type">Thread</span> {\r
+    <span class="type">Process</span>      <span class="variable-name">proc</span>    = <span class="keyword">null</span> ;\r
+    <span class="type">OutputStream</span> <span class="variable-name">out</span>     = <span class="keyword">null</span> ;\r
+    <span class="type">InputStream</span>  <span class="variable-name">in</span>      = <span class="keyword">null</span> ;\r
+    <span class="type">int</span>          <span class="variable-name">count</span> = -1 ;\r
+\r
+    <span class="reference">public</span> <span class="type">void</span> <span class="function-name">run</span> () {\r
+       <span class="keyword">try</span> {\r
+           <span class="type">byte</span> <span class="variable-name">buffer</span>[] = <span class="keyword">new</span> <span class="type">byte</span>[4096] ;\r
+           <span class="type">int</span>  <span class="variable-name">got</span>      = -1 ;\r
+           \r
+           <span class="comment">// Send the data to the target process:\r
+</span>            <span class="keyword">if</span> ( count >= 0 ) {\r
+               <span class="keyword">while</span> ( (count > 0) && ((got = in.read(buffer)) > 0) ) {\r
+                   out.write (buffer, 0, got) ;\r
+                   count -= got ;\r
+               }\r
+           } <span class="keyword">else</span> {\r
+               <span class="keyword">while</span> ( (got = in.read(buffer)) > 0 ) {\r
+                   out.write (buffer, 0, got) ;\r
+               }\r
+           }\r
+       } <span class="keyword">catch</span> (<span class="type">Exception</span> <span class="variable-name">e</span>) {\r
+           System.out.println ("<span class="string">ProcessFeeder: caught exception !</span>") ;\r
+           e.printStackTrace() ;\r
+       } <span class="keyword">finally</span> {\r
+           <span class="comment">// Clean up the process:\r
+</span>            <span class="keyword">try</span> { out.flush() ; } <span class="keyword">catch</span> (<span class="type">IOException</span> <span class="variable-name">ex</span>) {}\r
+           <span class="keyword">try</span> { out.close() ; } <span class="keyword">catch</span> (<span class="type">IOException</span> <span class="variable-name">ex</span>) {}\r
+           <span class="keyword">try</span> { proc.waitFor() ; } <span class="keyword">catch</span> (<span class="type">Exception</span> <span class="variable-name">ex</span>) {}\r
+       }\r
+    }\r
+       \r
+    <span class="function-name">ProcessFeeder</span> (<span class="type">Process</span> <span class="variable-name">proc</span>, <span class="type">InputStream</span> <span class="variable-name">in</span>) {\r
+       <span class="reference">this</span> (proc, in, -1) ;\r
+    }\r
+       \r
+    <span class="function-name">ProcessFeeder</span> (<span class="type">Process</span> <span class="variable-name">proc</span>, <span class="type">InputStream</span> <span class="variable-name">in</span>, <span class="type">int</span> <span class="variable-name">count</span>) {\r
+       <span class="reference">this</span>.proc   = proc ;\r
+       <span class="reference">this</span>.out    = proc.getOutputStream() ;\r
+       <span class="reference">this</span>.in     = in ;\r
+       <span class="reference">this</span>.count  = count ;\r
+    }\r
+}\r
+\r
+<span class="comment">/**\r
+ * Handle CGI scripts.\r
+ */</span>\r
+<span class="reference">public</span> <span class="keyword">class</span> <span class="function-name">CgiFrame</span> <span class="keyword">extends</span> <span class="type">HTTPFrame</span> {\r
+\r
+    <span class="string">private</span> <span class="type">final</span> <span class="type">static</span> \r
+       <span class="type">String</span> <span class="variable-name">STATE_EXTRA_PATH</span> = "<span class="doc-string">org.w3c.jigsaw.frames.CgiFrame.extraPath</span>";\r
+\r
+    <span class="comment">/**\r
+     * Attribute index - The interpreter to use, if any.\r
+     */</span>\r
+    <span class="preprocessor">protected</span> <span class="type">static</span> <span class="type">int</span> <span class="variable-name">ATTR_INTERPRETER</span> = -1;\r
+    <span class="comment">/**\r
+     * Attribute index - The array of string that makes the command to run.\r
+     */</span>\r
+    <span class="preprocessor">protected</span> <span class="type">static</span> <span class="type">int</span> <span class="variable-name">ATTR_COMMAND</span> = -1 ;\r
+    <span class="comment">/**\r
+     * Attribute index - Does the script takes care of its headers ?\r
+     */</span>\r
+    <span class="preprocessor">protected</span> <span class="type">static</span> <span class="type">int</span> <span class="variable-name">ATTR_NOHEADER</span> = -1 ;\r
+    <span class="comment">/**\r
+     * Attribute index - Does the script generates the form on GET ?\r
+     */</span>\r
+    <span class="preprocessor">protected</span> <span class="type">static</span> <span class="type">int</span> <span class="variable-name">ATTR_GENERATES_FORM</span> = -1 ;\r
+    <span class="comment">/**\r
+     * Attribute index - Do DNS, to fill in REMOTE_HOST env var.\r
+     */</span>\r
+    <span class="preprocessor">protected</span> <span class="type">static</span> <span class="type">int</span> <span class="variable-name">ATTR_REMOTE_HOST</span> = -1;\r
+    <span class="comment">/**\r
+     * Attribute index - Turn the script in debug mode.\r
+     */</span>\r
+    <span class="preprocessor">protected</span> <span class="type">static</span> <span class="type">int</span> <span class="variable-name">ATTR_CGI_DEBUG</span> = -1;\r
+\r
+    <span class="type">static</span> {\r
+       <span class="type">Attribute</span> <span class="variable-name">a</span>   = <span class="keyword">null</span> ;\r
+       <span class="type">Class</span>     <span class="variable-name">cls</span> = <span class="keyword">null</span> ;\r
+       <span class="keyword">try</span> {\r
+           cls = Class.forName("<span class="string">org.w3c.jigsaw.frames.CgiFrame</span>") ;\r
+       } <span class="keyword">catch</span> (<span class="type">Exception</span> <span class="variable-name">ex</span>) {\r
+           ex.printStackTrace() ;\r
+           System.exit(1) ;\r
+       }\r
+       <span class="comment">// The interpreter attribute:\r
+</span>        a = <span class="keyword">new</span> <span class="type">StringAttribute</span>("<span class="string">interpreter</span>"\r
+                               , <span class="keyword">null</span>\r
+                               , Attribute.EDITABLE);\r
+       ATTR_INTERPRETER = AttributeRegistry.registerAttribute(cls, a);\r
+       <span class="comment">// The command attribute:\r
+</span>        a = <span class="keyword">new</span> <span class="type">StringArrayAttribute</span>("<span class="string">command</span>"\r
+                                    , <span class="keyword">null</span>\r
+                                    , Attribute.MANDATORY|Attribute.EDITABLE);\r
+       ATTR_COMMAND = AttributeRegistry.registerAttribute(cls, a) ;\r
+       <span class="comment">// The noheader attribute:\r
+</span>        a = <span class="keyword">new</span> <span class="type">BooleanAttribute</span>("<span class="string">noheader</span>"\r
+                                , <span class="reference">Boolean</span>.<span class="type">FALSE</span>\r
+                                , Attribute.EDITABLE) ;\r
+       ATTR_NOHEADER = AttributeRegistry.registerAttribute(cls, a) ;\r
+       <span class="comment">// The generates form attribute\r
+</span>        a = <span class="keyword">new</span> <span class="type">BooleanAttribute</span>("<span class="string">generates-form</span>"\r
+                                , <span class="reference">Boolean</span>.<span class="type">TRUE</span>\r
+                                , Attribute.EDITABLE) ;\r
+       ATTR_GENERATES_FORM = AttributeRegistry.registerAttribute(cls, a);\r
+       <span class="comment">// Registerr the DODNS attribute.\r
+</span>        a = <span class="keyword">new</span> <span class="type">BooleanAttribute</span>("<span class="string">remote-host</span>"\r
+                                , <span class="keyword">null</span>\r
+                                , Attribute.EDITABLE);\r
+       ATTR_REMOTE_HOST = AttributeRegistry.registerAttribute(cls, a);\r
+       <span class="comment">// Register the debug mode flag:\r
+</span>        a = <span class="keyword">new</span> <span class="type">BooleanAttribute</span>("<span class="string">cgi-debug</span>"\r
+                                , <span class="reference">Boolean</span>.<span class="type">FALSE</span>\r
+                                , Attribute.EDITABLE);\r
+       ATTR_CGI_DEBUG = AttributeRegistry.registerAttribute(cls, a);\r
+    }\r
+\r
+    <span class="comment">/**\r
+     * Get the interpreter to use to execute the script.\r
+     * This is most usefull for operating systems that don't have a\r
+     * &lt;code&gt;!#&lt;/code&gt; convention ala UNIX.\r
+     * </span><span class="keyword">@return </span><span class="comment">The interpreter to run the script.\r
+     */</span>\r
+\r
+    <span class="reference">public</span> <span class="type">String</span> <span class="function-name">getInterpreter</span>() {\r
+       <span class="keyword">return</span> getString(ATTR_INTERPRETER, <span class="keyword">null</span>);\r
+    }\r
+\r
+    <span class="comment">/**\r
+     * Get the command string array.\r
+     */</span>\r
+\r
+    <span class="reference">public</span> <span class="type">String</span>[] <span class="function-name">getCommand</span>() {\r
+       <span class="keyword">return</span> (<span class="type">String</span>[]) getValue(ATTR_COMMAND, <span class="keyword">null</span>) ;\r
+    }\r
+\r
+    <span class="comment">/**\r
+     * Get the noheader flag.\r
+     * </span><span class="keyword">@return </span><span class="comment">The boolean value of the noheader flag.\r
+     */</span>\r
+\r
+    <span class="reference">public</span> <span class="type">boolean</span> <span class="function-name">checkNoheaderFlag</span>() {\r
+       <span class="keyword">return</span> getBoolean(ATTR_NOHEADER, <span class="keyword">false</span>) ;\r
+    }\r
+\r
+    <span class="comment">/**\r
+     * Get the generates form flag.\r
+     * </span><span class="keyword">@return </span><span class="comment">The boolean value of the generates form flag.\r
+     */</span>\r
+\r
+    <span class="reference">public</span> <span class="type">boolean</span> <span class="function-name">checkGeneratesFormFlag</span>() {\r
+       <span class="keyword">return</span> getBoolean(ATTR_GENERATES_FORM, <span class="keyword">true</span>) ;\r
+    }\r
+\r
+    <span class="comment">/**\r
+     * Get the remote host attribute value.\r
+     * If turned on, this flag will enable the REMOTE_HOST env var computation.\r
+     * </span><span class="keyword">@return </span><span class="comment">A boolean.\r
+     */</span>\r
+\r
+    <span class="reference">public</span> <span class="type">boolean</span> <span class="function-name">checkRemoteHost</span>() {\r
+       <span class="keyword">return</span> getBoolean(ATTR_REMOTE_HOST, <span class="keyword">false</span>);\r
+    }\r
+\r
+    <span class="comment">/**\r
+     * Get the CGI debug flag.\r
+     * </span><span class="keyword">@return </span><span class="comment">The boolean value of the CGI debug flag.\r
+     */</span>\r
+\r
+    <span class="reference">public</span> <span class="type">boolean</span> <span class="function-name">checkCgiDebug</span>() {\r
+       <span class="keyword">return</span> getBoolean(ATTR_CGI_DEBUG, <span class="keyword">false</span>);\r
+    }\r
+\r
+    <span class="comment">/**\r
+     * Turn the given header name into it's env var canonical name.\r
+     * This guy is crazy enough to run CGI scripts, he can pay for that \r
+     * overhead.\r
+     * </span><span class="keyword">@param </span><span class="variable-name">name</span><span class="comment"> The header name.\r
+     * </span><span class="keyword">@return </span><span class="comment">A String giving the official env variable name for that header.\r
+     */</span>\r
+\r
+    <span class="reference">public</span> <span class="type">String</span> <span class="function-name">getEnvName</span>(<span class="type">String</span> <span class="variable-name">name</span>) {\r
+       <span class="type">int</span>          <span class="variable-name">sl</span> = name.length();\r
+       <span class="type">StringBuffer</span> <span class="variable-name">sb</span> = <span class="keyword">new</span> <span class="type">StringBuffer</span>(5+sl);\r
+       sb.append("<span class="string">HTTP_</span>");\r
+       <span class="keyword">for</span> (<span class="type">int</span> <span class="variable-name">i</span> = 0 ; i < sl ; i++) {\r
+           <span class="type">char</span> <span class="variable-name">ch</span> = name.charAt(i);\r
+           sb.append((ch == '<span class="string">-</span>') ? '<span class="string">_</span>' : Character.toUpperCase(ch));\r
+       }\r
+       <span class="keyword">return</span> sb.toString();\r
+    }\r
+\r
+    <span class="comment">/**\r
+     * Handle the CGI script output.\r
+     * This methods handles the CGI script output. Depending on the\r
+     * value of the &lt;strong&gt;noheader&lt;/strong&gt; attribute it either:\r
+     * &lt;ul&gt;\r
+     * &lt;li&gt;Sends back the script output directly,&lt;/li&gt;\r
+     * &lt;li&gt;Parses the script output, looking for a status header or a \r
+     * location header, or a content-length header, or any combination\r
+     * of those three.\r
+     * &lt;/ul&gt;\r
+     * </span><span class="keyword">@param </span><span class="variable-name">process</span><span class="comment"> The underlying CGI process.\r
+     * </span><span class="keyword">@param </span><span class="variable-name">request</span><span class="comment"> The processed request.\r
+     * </span><span class="keyword">@exception </span><span class="type">ProtocolException</span><span class="comment"> If an HTTP error should be sent back \r
+     * to the client.\r
+     */</span>\r
+\r
+    <span class="preprocessor">protected</span> <span class="type">Reply</span> <span class="function-name">handleCGIOutput</span> (<span class="type">Process</span> <span class="variable-name">process</span>, <span class="type">Request</span> <span class="variable-name">request</span>) \r
+       <span class="keyword">throws</span> <span class="type">ProtocolException</span>\r
+    {\r
+       <span class="comment">// No header script don't deserve attention:\r
+</span>        <span class="keyword">if</span> ( checkNoheaderFlag() ) {\r
+           <span class="type">Reply</span> <span class="variable-name">reply</span> = request.makeReply(HTTP.NOHEADER) ;\r
+           reply.setStream (process.getInputStream()) ;\r
+           <span class="keyword">return</span> reply ;\r
+       }\r
+       <span class="comment">// Check for debugging mode:\r
+</span>        <span class="keyword">if</span> ( checkCgiDebug() ) {\r
+           <span class="type">Reply</span> <span class="variable-name">reply</span> = request.makeReply(HTTP.OK);\r
+           reply.setContentType(MimeType.TEXT_PLAIN);\r
+           reply.setStream(process.getInputStream());\r
+           <span class="keyword">return</span> reply;\r
+       }\r
+       <span class="comment">// We MUST parse at least one header:\r
+</span>        <span class="type">MimeParser</span> <span class="variable-name">p</span> = <span class="keyword">new</span> <span class="type">MimeParser</span>(process.getInputStream(),\r
+                                     <span class="keyword">new</span> <span class="type">CGIHeaderHolderFactory</span>());\r
+       <span class="type">Reply</span>           <span class="variable-name">reply</span>  = <span class="keyword">null</span> ;\r
+       <span class="keyword">try</span> {\r
+           <span class="type">CGIHeaderHolder</span> <span class="variable-name">h</span> = (<span class="type">CGIHeaderHolder</span>) p.parse();\r
+           <span class="comment">// Check for a status code:\r
+</span>            <span class="type">String</span> <span class="variable-name">svalue</span>   = h.getStatus();\r
+           <span class="type">String</span> <span class="variable-name">location</span> = h.getLocation();\r
+           <span class="keyword">if</span> ( svalue != <span class="keyword">null</span> ) {\r
+               <span class="type">int</span> <span class="variable-name">status</span> = -1;\r
+               <span class="keyword">try</span> {\r
+                   status = Integer.parseInt(svalue);\r
+               } <span class="keyword">catch</span> (<span class="type">Exception</span> <span class="variable-name">ex</span>) {\r
+                   <span class="comment">// This script has emited an invalid status line:\r
+</span>                    <span class="type">String</span> <span class="variable-name">msg</span> = ("<span class="string">Emited an invalid status line [</span>"+\r
+                                 svalue + "<span class="string">].</span>");\r
+                   getServer().errlog(<span class="reference">this</span>, msg);\r
+                   <span class="comment">// Throw an HTTPException:\r
+</span>                    reply = request.makeReply(HTTP.INTERNAL_SERVER_ERROR);\r
+                   reply.setContent("<span class="string">CGI script emited invalid status.</span>");\r
+                   <span class="keyword">throw</span> <span class="keyword">new</span> <span class="type">HTTPException</span>(reply);\r
+               }\r
+               reply = request.makeReply(status);\r
+           } <span class="keyword">else</span> {\r
+               <span class="comment">// No status code available, any location header ?\r
+</span>                reply = request.makeReply((location == <span class="keyword">null</span>)\r
+                                         ? <span class="reference">HTTP</span>.<span class="type">OK</span>\r
+                                         : HTTP.FOUND);\r
+           }\r
+           <span class="comment">// Set up the location header if needed:\r
+</span>            <span class="keyword">if</span> ( location != <span class="keyword">null</span> ) {\r
+               <span class="keyword">try</span> {\r
+                   reply.setLocation(<span class="keyword">new</span> <span class="type">URL</span>(getURL(request), location));\r
+               } <span class="keyword">catch</span> (<span class="type">MalformedURLException</span> <span class="variable-name">ex</span>) {\r
+                   <span class="comment">// This should really not happen:\r
+</span>                    getServer().errlog(<span class="reference">this</span>, "<span class="string">unable to create location url </span>"+\r
+                                      location+\r
+                                      "<span class="string"> in base </span>"+getURL(request));\r
+               }\r
+           }\r
+           <span class="comment">// And then, the remaining headers:\r
+</span>            <span class="type">Enumeration</span> <span class="variable-name">e</span> = h.enumerateHeaders();\r
+           <span class="keyword">if</span> ( e != <span class="keyword">null</span> ) {\r
+               <span class="keyword">while</span> ( e.hasMoreElements() ) {\r
+                   <span class="type">String</span> <span class="variable-name">hname</span> = (<span class="type">String</span>) e.nextElement();\r
+                   reply.setValue(hname, (<span class="type">String</span>) h.getValue(hname));\r
+               }\r
+           }\r
+           reply.setStream(p.getInputStream()) ;\r
+       } <span class="keyword">catch</span> (<span class="type">IOException</span> <span class="variable-name">ex</span>) {\r
+           ex.printStackTrace();\r
+       } <span class="keyword">catch</span> (<span class="type">MimeParserException</span> <span class="variable-name">ex</span>) {\r
+           <span class="comment">// This script has generated invalid output:\r
+</span>            <span class="type">String</span> <span class="variable-name">msg</span> = (getURL(request)\r
+                         +"<span class="string">: emited invalid output [</span>"+\r
+                         ex.getMessage() +"<span class="string">]</span>");\r
+           getServer().errlog(<span class="reference">this</span>, msg);\r
+           <span class="comment">// Throw an HTTPException:\r
+</span>            <span class="type">Reply</span> <span class="variable-name">error</span> = request.makeReply(HTTP.INTERNAL_SERVER_ERROR) ;\r
+           error.setContent("<span class="string">CGI error: unable to parse script headers.</span>") ;\r
+           <span class="keyword">throw</span> <span class="keyword">new</span> <span class="type">HTTPException</span> (error) ;\r
+       }\r
+       <span class="keyword">return</span> reply ;\r
+    }\r
+\r
+    <span class="comment">/**\r
+     * Add an enviornment binding to the given vector.\r
+     * </span><span class="keyword">@param </span><span class="variable-name">name</span><span class="comment"> The name of the enviornment variable.\r
+     * </span><span class="keyword">@param </span><span class="variable-name">val</span><span class="comment"> Its value.\r
+     * </span><span class="keyword">@param </span><span class="variable-name">into</span><span class="comment"> The vector to which accumulate bindings.\r
+     */</span>\r
+\r
+    <span class="string">private</span> <span class="type">void</span> <span class="function-name">addEnv</span> (<span class="type">String</span> <span class="variable-name">name</span>, <span class="type">String</span> <span class="variable-name">val</span>, <span class="type">Vector</span> <span class="variable-name">into</span>) {\r
+       into.addElement (name+"<span class="string">=</span>"+val) ;\r
+    }\r
+    \r
+    <span class="comment">/**\r
+     * Prepare the command to run for this CGI script, and run it.\r
+     * </span><span class="keyword">@param </span><span class="variable-name">request</span><span class="comment"> The request to handle.\r
+     * </span><span class="keyword">@return </span><span class="comment">The running CGI process object.\r
+     * </span><span class="keyword">@exception </span><span class="type">HTTPException</span><span class="comment"> If we weren't able to build the command or\r
+     *    the environment.\r
+     */</span>\r
+\r
+    <span class="preprocessor">protected</span> <span class="type">Process</span> <span class="function-name">makeCgiCommand</span> (<span class="type">Request</span> <span class="variable-name">request</span>) \r
+       <span class="keyword">throws</span> <span class="type">ProtocolException</span>, <span class="type">IOException</span> \r
+    {\r
+       <span class="comment">// Check the command attribute first:\r
+</span>        <span class="type">String</span>      <span class="variable-name">query</span>     = <span class="keyword">null</span>;\r
+       <span class="type">String</span>      <span class="variable-name">command</span>[] = getCommand() ;\r
+       <span class="keyword">if</span> ( command == <span class="keyword">null</span> ) {\r
+           <span class="type">Reply</span> <span class="variable-name">error</span> = request.makeReply(HTTP.INTERNAL_SERVER_ERROR) ;\r
+           error.setContent("<span class="string">CgiResource mis-configured: it doesn't have a </span>"\r
+                            + "<span class="string"> command attribute</span>");\r
+           <span class="keyword">throw</span> <span class="keyword">new</span> <span class="type">HTTPException</span>(error);\r
+       }\r
+       <span class="comment">// Ok:\r
+</span>        <span class="type">Vector</span>      <span class="variable-name">env</span>       = <span class="keyword">new</span> <span class="type">Vector</span>(32) ;\r
+       httpd       server    = request.getClient().getServer() ;\r
+       <span class="type">InetAddress</span> <span class="variable-name">sadr</span>      = server.getInetAddress() ;\r
+       <span class="comment">// Specified environment variables:\r
+</span>        <span class="comment">// We do not handle the following variables:\r
+</span>        <span class="comment">// - PATH_TRANSLATED: I don't understand it\r
+</span>        <span class="comment">// - REMOTE_IDENT: would require usage of IDENT protocol.\r
+</span>        <span class="comment">// Authentification type, if any:\r
+</span>        <span class="type">String</span> <span class="variable-name">svalue</span> = (<span class="type">String</span>) request.getState(AuthFilter.STATE_AUTHTYPE);\r
+       <span class="keyword">if</span> ( svalue != <span class="keyword">null</span> )\r
+           addEnv("<span class="string">AUTH_TYPE</span>", svalue, env);\r
+       <span class="comment">// Content length, if available:\r
+</span>        svalue = request.getValue("<span class="string">content-length</span>");\r
+       <span class="keyword">if</span> ( svalue != <span class="keyword">null</span> )\r
+           addEnv("<span class="string">CONTENT_LENGTH</span>", svalue, env);\r
+       <span class="comment">// Content type, if available:\r
+</span>        svalue = request.getValue("<span class="string">content-type</span>");\r
+       <span class="keyword">if</span> ( svalue != <span class="keyword">null</span> )\r
+           addEnv("<span class="string">CONTENT_TYPE</span>", svalue, env);\r
+       <span class="comment">// The gateway interface, hopefully 1.1 !\r
+</span>        addEnv ("<span class="string">GATEWAY_INTERFACE</span>", "<span class="string">CGI/1.1</span>", env) ;\r
+       <span class="comment">// The PATH_INFO, which I am afraid I still don't understand:\r
+</span>        svalue = (<span class="type">String</span>) request.getState(STATE_EXTRA_PATH);\r
+       <span class="keyword">if</span> ( svalue == <span class="keyword">null</span> )\r
+           addEnv ("<span class="string">PATH_INFO</span>", "<span class="string">/</span>", env) ; \r
+       <span class="keyword">else</span>\r
+           addEnv ("<span class="string">PATH_INFO</span>", svalue, env) ; \r
+       <span class="comment">// The query string:\r
+</span>        query = request.getQueryString();\r
+       <span class="keyword">if</span> ( query != <span class="keyword">null</span> ) \r
+           addEnv("<span class="string">QUERY_STRING</span>", query, env) ;\r
+       <span class="comment">// The remote client IP address:\r
+</span>        svalue = request.getClient().getInetAddress().toString();\r
+       addEnv ("<span class="string">REMOTE_ADDR</span>", svalue, env);\r
+       <span class="comment">// Authentified user:\r
+</span>        svalue = (<span class="type">String</span>) request.getState(AuthFilter.STATE_AUTHUSER);\r
+       <span class="keyword">if</span> ( svalue != <span class="keyword">null</span> )\r
+           addEnv("<span class="string">REMOTE_USER</span>", svalue, env);\r
+       <span class="comment">// Remote host name, if allowed:\r
+</span>        <span class="keyword">if</span> ( checkRemoteHost() ) {\r
+           <span class="type">String</span> <span class="variable-name">host</span> = request.getClient().getInetAddress().getHostName();\r
+           addEnv("<span class="string">REMOTE_HOST</span>", host, env);\r
+       }\r
+       <span class="comment">// The request method:\r
+</span>        addEnv ("<span class="string">REQUEST_METHOD</span>", request.getMethod(), env) ;\r
+       <span class="comment">// The script name :\r
+</span>        addEnv("<span class="string">SCRIPT_NAME</span>", getURLPath(), env);\r
+       <span class="comment">// Server name:\r
+</span>        addEnv ("<span class="string">SERVER_NAME</span>", getServer().getHost(), env) ;\r
+       <span class="comment">// Server port:\r
+</span>        svalue = Integer.toString(getServer().getLocalPort());\r
+       addEnv ("<span class="string">SERVER_PORT</span>", svalue, env);\r
+       <span class="comment">// Server protocol:\r
+</span>        addEnv ("<span class="string">SERVER_PROTOCOL</span>", request.getVersion(), env) ;\r
+       <span class="comment">// Server software:\r
+</span>        addEnv ("<span class="string">SERVER_SOFTWARE</span>", server.getSoftware(), env) ;\r
+       <span class="comment">// All other request fields, yeah, let's lose even more time:\r
+</span>        <span class="type">Enumeration</span> <span class="variable-name">e</span> = request.enumerateHeaderDescriptions(<span class="keyword">false</span>);\r
+       <span class="keyword">while</span> ( e.hasMoreElements() ) {\r
+           <span class="type">HeaderDescription</span> <span class="variable-name">d</span> = (<span class="type">HeaderDescription</span>) e.nextElement();\r
+           addEnv(getEnvName(d.getName())\r
+                  , request.getHeaderValue(d).toString()\r
+                  , env);\r
+       }\r
+       <span class="comment">// Command line:\r
+</span>        <span class="keyword">if</span> ( query != <span class="keyword">null</span> ) {\r
+           <span class="type">String</span> <span class="variable-name">querycmd</span>[] = <span class="keyword">new</span> <span class="type">String</span>[command.length+1] ;\r
+           System.arraycopy(command, 0, querycmd, 0, command.length) ;\r
+           querycmd[command.length] = query ;\r
+           command = querycmd ;\r
+       }\r
+       <span class="type">String</span> <span class="variable-name">aenv</span>[] = <span class="keyword">new</span> <span class="type">String</span>[env.size()] ;\r
+       env.copyInto (aenv) ;\r
+       <span class="comment">// Run the process:\r
+</span>        <span class="keyword">if</span> ( getInterpreter() != <span class="keyword">null</span> ) {\r
+           <span class="type">String</span> <span class="variable-name">run</span>[] = <span class="keyword">new</span> <span class="type">String</span>[command.length+1];\r
+           run[0] = getInterpreter();\r
+           System.arraycopy(command, 0, run, 1, command.length);\r
+           <span class="keyword">return</span> Runtime.getRuntime().exec (run, aenv) ;\r
+       } <span class="keyword">else</span> {\r
+           <span class="keyword">return</span> Runtime.getRuntime().exec (command, aenv) ;\r
+       }\r
+    }\r
+\r
+    <span class="comment">/**\r
+     * Lookup sub-resources.\r
+     * Accumulate the remaning path in some special state of the request.\r
+     * &lt;p&gt;This allows us to implement the &lt;code&gt;PATH_INFO&lt;/code&gt; \r
+     * CGI variable properly.\r
+     * </span><span class="keyword">@param </span><span class="variable-name">ls</span><span class="comment"> Current lookup state.\r
+     * </span><span class="keyword">@param </span><span class="variable-name">lr</span><span class="comment"> Lookup result under construction.\r
+     * </span><span class="keyword">@return </span><span class="comment">A boolean &lt;strong&gt;true&lt;/strong&gt; if lookup should continue,\r
+     * &lt;strong&gt;false&lt;/strong&gt; otherwise.\r
+     */</span>\r
+\r
+    <span class="reference">public</span> <span class="type">boolean</span> <span class="function-name">lookup</span>(<span class="type">LookupState</span> <span class="variable-name">ls</span>, <span class="type">LookupResult</span> <span class="variable-name">lr</span>) \r
+       <span class="keyword">throws</span> <span class="type">ProtocolException</span> \r
+    {\r
+       <span class="comment">// Get the extra path information:\r
+</span>        <span class="type">String</span> <span class="variable-name">extraPath</span> = ls.getRemainingPath(<span class="keyword">true</span>);\r
+       <span class="keyword">if</span> ((extraPath == <span class="keyword">null</span>) || extraPath.equals(""))\r
+           extraPath = "<span class="string">/</span>";\r
+       <span class="comment">// Keep this path info into the request, if possible:\r
+</span>        <span class="type">Request</span> <span class="variable-name">request</span> = (<span class="type">Request</span>) ls.getRequest();\r
+       <span class="keyword">if</span> ( request != <span class="keyword">null</span> )\r
+           request.setState(STATE_EXTRA_PATH, extraPath);\r
+       lr.setTarget(getResource().getResourceReference());\r
+       <span class="keyword">return</span> <span class="reference">super</span>.lookup(ls, lr);\r
+    }\r
+  \r
+    <span class="comment">/** \r
+     * GET method implementation.\r
+     * this method is splitted into two cases:\r
+     * &lt;p&gt;If the resource is able to generates its form, than run the script\r
+     * to emit the form. Otherwsie, use our super class (FileResource) ability\r
+     * to send the file that contains the form.\r
+     * &lt;p&gt;Note that there is no need to feed the underlying process with\r
+     * data in the GET case.\r
+     * </span><span class="keyword">@param </span><span class="variable-name">request</span><span class="comment"> The request to handle.\r
+     * </span><span class="keyword">@exception </span><span class="type">ProtocolException</span><span class="comment"> If processing the request failed.\r
+     */</span>\r
+    <span class="reference">public</span> <span class="type">Reply</span> <span class="function-name">get</span>(<span class="type">Request</span> <span class="variable-name">request</span>)\r
+       <span class="keyword">throws</span> <span class="type">ProtocolException</span>, <span class="type">NotAProtocolException</span>\r
+   {\r
+       <span class="keyword">if</span> ( ! checkGeneratesFormFlag() )\r
+          <span class="keyword">return</span> <span class="reference">super</span>.get (request) ;\r
+       <span class="type">Process</span>       <span class="variable-name">process</span> = <span class="keyword">null</span> ;\r
+       <span class="keyword">try</span> {\r
+          process = makeCgiCommand (request) ;\r
+       } <span class="keyword">catch</span> (<span class="type">IOException</span> <span class="variable-name">e</span>) {\r
+          <span class="type">Reply</span> <span class="variable-name">error</span> = request.makeReply(HTTP.NOT_FOUND) ;\r
+          error.setContent("<span class="string">The resource's script wasn't found.</span>") ;\r
+          <span class="keyword">throw</span> <span class="keyword">new</span> <span class="type">HTTPException</span> (error) ;\r
+       }\r
+       <span class="keyword">return</span> handleCGIOutput (process, request) ;\r
+   }\r
+\r
+\r
+    <span class="comment">/**\r
+     * Handle the POST method according to CGI/1.1 specification.\r
+     * The request body is sent back to the launched CGI script, as is, and\r
+     * the script output is handled by the handleCGIOutput method.\r
+     * </span><span class="keyword">@param </span><span class="variable-name">request</span><span class="comment"> The request to process.\r
+     * </span><span class="keyword">@exception </span><span class="type">ProtocolException</span><span class="comment"> If the processing failed.\r
+     */</span>\r
+    <span class="reference">public</span> <span class="type">Reply</span> <span class="function-name">post</span>(<span class="type">Request</span> <span class="variable-name">request</span>)\r
+       <span class="keyword">throws</span> <span class="type">ProtocolException</span>, <span class="type">NotAProtocolException</span>\r
+    {\r
+       <span class="type">Process</span>       <span class="variable-name">process</span> = <span class="keyword">null</span> ;\r
+       <span class="comment">// Launch the CGI process:\r
+</span>        <span class="keyword">try</span> {\r
+           process = makeCgiCommand(request) ;\r
+       } <span class="keyword">catch</span> (<span class="type">IOException</span> <span class="variable-name">ex</span>) {\r
+           <span class="comment">// The process wasn't executable, emit a errlog message:\r
+</span>            <span class="type">String</span> <span class="variable-name">msg</span> = ("<span class="string">The process </span>"+\r
+                         getCommand()[0] +"<span class="string"> couldn't be executed [</span>"+\r
+                         ex.getMessage() + "<span class="string">]</span>");\r
+           getServer().errlog(<span class="reference">this</span>, msg);\r
+           <span class="comment">// Throw an internal server error:\r
+</span>            <span class="type">Reply</span> <span class="variable-name">error</span> = request.makeReply(HTTP.INTERNAL_SERVER_ERROR) ;\r
+           error.setContent("<span class="string">CGI script is misconfigured.</span>");\r
+           <span class="keyword">throw</span> <span class="keyword">new</span> <span class="type">HTTPException</span> (error) ;\r
+       }\r
+       <span class="comment">// Now feed the process:\r
+</span>        <span class="keyword">try</span> {\r
+           <span class="comment">// Send the 100 status code:\r
+</span>            <span class="type">Client</span> <span class="variable-name">client</span> = request.getClient();\r
+           <span class="keyword">if</span> ( client != <span class="keyword">null</span> ) \r
+               client.sendContinue();\r
+           <span class="type">InputStream</span> <span class="variable-name">in</span> = request.getInputStream();\r
+           <span class="keyword">if</span> ( in == <span class="keyword">null</span> ) {\r
+               <span class="comment">// There was no input to that CCI, close process stream\r
+</span>                process.getOutputStream().close();\r
+           } <span class="keyword">else</span> {\r
+               <span class="comment">// Some input to feed the process with:\r
+</span>                (<span class="keyword">new</span> <span class="type">ProcessFeeder</span>(process, in)).start();\r
+           }\r
+       } <span class="keyword">catch</span> (<span class="type">IOException</span> <span class="variable-name">ex</span>) {\r
+           <span class="comment">// This is most probably a bad request:\r
+</span>            <span class="type">Reply</span> <span class="variable-name">error</span> = request.makeReply(HTTP.BAD_REQUEST);\r
+           error.setContent("<span class="string">The request didn't have a valid input.</span>");\r
+           <span class="keyword">throw</span> <span class="keyword">new</span> <span class="type">HTTPException</span>(error);\r
+       }\r
+       <span class="keyword">return</span> handleCGIOutput(process, request);\r
+    }\r
+    \r
+    <span class="comment">/**\r
+     * At register time, if no command, use a suitable default.\r
+     * THis method will set the command to the identifier, if it is not\r
+     * provided.\r
+     * </span><span class="keyword">@param </span><span class="variable-name">values</span><span class="comment"> Default attribute values.\r
+     */</span>\r
+    \r
+    <span class="reference">public</span> <span class="type">void</span> <span class="function-name">registerResource</span>(<span class="type">FramedResource</span> <span class="variable-name">resource</span>) {\r
+       <span class="reference">super</span>.registerResource(resource);\r
+       <span class="comment">//if no command is specified look for a file resource attached\r
+</span>        <span class="comment">//and get its File absolute path if available.\r
+</span>        <span class="keyword">if</span> (getCommand() == <span class="keyword">null</span>) {\r
+           <span class="keyword">if</span> (getFileResource() != <span class="keyword">null</span>) {\r
+               <span class="keyword">if</span> (getFileResource().getFile() != <span class="keyword">null</span>) {\r
+                   <span class="type">String</span> <span class="variable-name">cmd</span>[] = <span class="keyword">new</span> <span class="type">String</span>[1];\r
+                   cmd[0] = getFileResource().getFile().getAbsolutePath();\r
+                   setValue(ATTR_COMMAND, cmd);\r
+               }\r
+           }\r
+       }\r
+    }\r
+}\r
+\r
+    </pre>\r
+  </body>\r
+</html>\r