Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / jigsaw / src / org / w3c / jigsaw / http / Request.java
diff --git a/JMCR-Stable/real-world application/jigsaw/src/org/w3c/jigsaw/http/Request.java b/JMCR-Stable/real-world application/jigsaw/src/org/w3c/jigsaw/http/Request.java
new file mode 100644 (file)
index 0000000..e645778
--- /dev/null
@@ -0,0 +1,434 @@
+// Request.java\r
+// $Id: Request.java,v 1.1 2010/06/15 12:21:58 smhuang Exp $\r
+// (c) COPYRIGHT MIT and INRIA, 1996.\r
+// Please first read the full copyright statement in file COPYRIGHT.html\r
+\r
+package org.w3c.jigsaw.http ;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+\r
+import java.net.URL;\r
+\r
+import org.w3c.www.mime.MimeParser;\r
+\r
+import org.w3c.www.http.ChunkedInputStream;\r
+import org.w3c.www.http.ContentLengthInputStream;\r
+import org.w3c.www.http.HTTP;\r
+import org.w3c.www.http.HttpCredential;\r
+import org.w3c.www.http.HttpEntityMessage;\r
+import org.w3c.www.http.HttpFactory;\r
+import org.w3c.www.http.HttpMessage;\r
+import org.w3c.www.http.HttpParserException;\r
+import org.w3c.www.http.HttpRequestMessage;\r
+\r
+import org.w3c.tools.resources.ReplyInterface;\r
+import org.w3c.tools.resources.RequestInterface;\r
+import org.w3c.tools.resources.ResourceFilter;\r
+import org.w3c.tools.resources.ResourceReference;\r
+\r
+import org.w3c.tools.codec.Base64Encoder;\r
+\r
+/**\r
+ * this class extends HttpRequestMessage to cope with HTTP request.\r
+ * One subtely here: note how each field acessor <em>never</em> throws an\r
+ * exception, but rather is provided with a default value: this is in the hope\r
+ * that sometime, HTTP will not require all the parsing it requires right now.\r
+ */\r
+\r
+public class Request extends HttpRequestMessage \r
+    implements RequestInterface\r
+{\r
+    /**\r
+     * The URL that means <strong>*</strong> for an <code>OPTIONS</code>\r
+     * method.\r
+     */\r
+    public static URL THE_SERVER = null;\r
+\r
+    /**\r
+     * the state of original URL\r
+     */\r
+    public static final String ORIG_URL_STATE = \r
+                                         "org.w3c.jigsaw.http.Request.origurl";\r
+\r
+    static {\r
+       try {\r
+           THE_SERVER = new URL("http://your.url.unknown");\r
+       } catch (Exception ex) {\r
+           ex.printStackTrace();\r
+       }\r
+    }\r
+\r
+    protected Client      client  = null;\r
+    protected MimeParser  parser  = null;\r
+    protected InputStream in      = null;\r
+    protected boolean     keepcon = true;\r
+    boolean is_proxy = false;\r
+\r
+    public void setState(String name, String state) {\r
+       super.setState(name, state);\r
+    }\r
+\r
+    /**\r
+     * Fix the target URL of the request, this is the only good time to do so.\r
+     * @param parser The MimeParser\r
+     * @exception HttpParserException if parsing failed.\r
+     * @exception IOException if an IO error occurs.\r
+     */\r
+\r
+    public void notifyEndParsing(MimeParser parser)\r
+       throws HttpParserException, IOException\r
+       {\r
+           super.notifyEndParsing(parser);\r
+           String target = getTarget();\r
+           String url    = null;\r
+           // Get rid of the nasty cases(there is a place in hell for someone)\r
+           if ( target.equals("*") ) {\r
+               setURL(THE_SERVER);\r
+               return;\r
+           }\r
+           // Is this a full http URL:\r
+           int    at    = -1;\r
+           int    colon = target.indexOf(':');\r
+           String proto = (colon != -1) ? target.substring(0, colon) : null;\r
+           if ((proto != null) &&\r
+               (proto.equals("http") || proto.equals("ftp"))) {\r
+               // Good we have a full URL:\r
+               try {\r
+                   // hugly hack, bug in URL for urls like:\r
+                   // http://user:passwd@host:port/file\r
+                   if ((at = target.indexOf('@',6)) != -1) {\r
+                       String auth = target.substring(colon+3,at);\r
+                       int    sep  = -1;\r
+                       if ((auth.indexOf('/') == -1) &&\r
+                           ((sep = auth.indexOf(':')) != -1)) {\r
+                           if (! hasAuthorization()) {\r
+                               String username = auth.substring(0,sep);\r
+                               String password = auth.substring(sep+1);\r
+                               HttpCredential credential =\r
+                                   HttpFactory.makeCredential("Basic");\r
+                               Base64Encoder encoder = \r
+                                   new Base64Encoder(username+":"+password);\r
+                               credential.setAuthParameter("cookie", \r
+                                                    encoder.processString());\r
+                               setAuthorization(credential);\r
+                           }\r
+                           setURL(new URL(proto+\r
+                                          "://"+target.substring(at+1)));\r
+                       } else {\r
+                           setURL(new URL(target));\r
+                       }\r
+                   } else {\r
+                       setURL(new URL(target));\r
+                   }\r
+               } catch (Exception ex) {\r
+                   throw new HttpParserException("Bogus URL ["+url+"]", this);\r
+               }\r
+           } else {\r
+               try {\r
+                   // Do we have a valid host header ?\r
+                   String host = getHost();\r
+                   if ( host == null ) {\r
+                       // If this claims to be 1.1, tell him he's wrong:\r
+                       if ((major == 1) && (minor >= 1))\r
+                           throw new HttpParserException("No Host Header");\r
+                       httpd server = getClient().getServer();\r
+                       setURL(new URL("http"\r
+                                      , server.getHost(), server.getPort()\r
+                                      , target));\r
+                   } else {\r
+                       int ic = host.indexOf(':');\r
+                       if ( ic < 0 ) {\r
+                           setURL(new URL("http", host, target));\r
+                       } else {\r
+                           setURL(new URL("http"\r
+                                          , host.substring(0, ic)\r
+                                          , Integer.parseInt(\r
+                                              host.substring(ic+1))\r
+                                          , target));\r
+                       }\r
+                   }\r
+               } catch (Exception ex) {\r
+                   throw new HttpParserException("Bogus URL ["+url+"]", this);\r
+               }\r
+           }\r
+       }\r
+\r
+    // FIXME\r
+    // This guy should also check that the (optional) request stream has been\r
+    // exhausted.\r
+\r
+    public boolean canKeepConnection() {\r
+       // HTTP/0.9 doesn't know about keeping connections alive:\r
+       if (( ! keepcon) || (major < 1))\r
+           return false;\r
+       if ( minor >= 1 ) \r
+           // HTTP/1.1 keeps connections alive by default\r
+           return hasConnection("close") ? false : true;\r
+       // For HTTP/1.0 check the [proxy] connection header:\r
+       if ( is_proxy )\r
+           return hasProxyConnection("keep-alive");\r
+       else\r
+           return hasConnection("keep-alive");\r
+    }\r
+\r
+    private ResourceReference target_resource = null;\r
+    protected void setTargetResource(ResourceReference resource) {\r
+       target_resource = resource;\r
+    }\r
+\r
+    /**\r
+     * Get this request target resource.\r
+     * @return An instance of HTTPResource, or <strong>null</strong> if\r
+     * not found.\r
+     */\r
+\r
+    public ResourceReference getTargetResource() {\r
+       return target_resource;\r
+    }\r
+\r
+    public void setProxy(boolean onoff) {\r
+       is_proxy = onoff;\r
+    }\r
+\r
+    public boolean isProxy() {\r
+       return is_proxy;\r
+    }\r
+\r
+    public String getURLPath() {\r
+       return url.getFile();\r
+    }\r
+\r
+    public void setURLPath(String path) {\r
+       try {\r
+           url = new URL(url, path);\r
+       } catch (Exception ex) {\r
+           ex.printStackTrace();\r
+       }\r
+    }\r
+\r
+    public boolean hasContentLength() {\r
+       return hasHeader(H_CONTENT_LENGTH);\r
+    }\r
+\r
+    public boolean hasContentType() {\r
+       return hasHeader(H_CONTENT_TYPE);\r
+    }\r
+\r
+    public boolean hasAccept() {\r
+       return hasHeader(H_ACCEPT);\r
+    }\r
+\r
+    public boolean hasAcceptCharset() {\r
+       return hasHeader(H_ACCEPT_CHARSET);\r
+    }\r
+\r
+    public boolean hasAcceptEncoding() {\r
+       return hasHeader(H_ACCEPT_ENCODING);\r
+    }\r
+\r
+    public boolean hasAcceptLanguage() {\r
+       return hasHeader(H_ACCEPT_LANGUAGE);\r
+    }\r
+\r
+    public boolean hasAuthorization() {\r
+       return hasHeader(H_AUTHORIZATION);\r
+    }\r
+\r
+    public boolean hasProxyAuthorization() {\r
+       return hasHeader(H_PROXY_AUTHORIZATION);\r
+    }\r
+\r
+    public String getQueryString() {\r
+       return (String) getState("query");\r
+    }\r
+\r
+    public boolean hasQueryString() {\r
+       return hasState("query");\r
+    }\r
+\r
+    protected boolean internal = false;\r
+    public boolean isInternal() {\r
+       return internal;\r
+    }\r
+\r
+    public void setInternal(boolean onoff) {\r
+       this.internal = onoff;\r
+    }\r
+\r
+    protected Request original = null;\r
+    public Request getOriginal() {\r
+       return original == null ? this : original ;\r
+    }\r
+\r
+    protected ResourceFilter filters[] = null;\r
+    protected int        infilters = -1;\r
+    protected void setFilters(ResourceFilter filters[], int infilters) {\r
+       this.filters   = filters;\r
+       this.infilters = infilters;\r
+    }\r
+\r
+    /**\r
+     * Clone this request, in order to launch an internal request.\r
+     * This method can be used to run a request in some given context, defined\r
+     * by an original request. It will preserve all the original information\r
+     * (such as authentication, etc), and will provide a <em>clone</em> of\r
+     * the original request.\r
+     * <p>The original request and its clone differ in the following way:\r
+     * <ul>\r
+     * <li>The clone is marked as <em>internal</em>, which can be tested\r
+     * by the <code>isInternal</code> method.\r
+     * <li>The clone will keep a pointer to the first request that was \r
+     * cloned. This original request can be accessed by the <code>getOriginal\r
+     * </code> method.\r
+     * </ul>\r
+     * <p>To run an internal request, the caller can then use the <code>\r
+     * org.w3c.jigsaw.http.httpd</code> <code>perform</code> method.\r
+     * @return A fresh Request instance, marked as internal.\r
+     */\r
+\r
+    public HttpMessage getClone() {\r
+       Request cl = (Request) super.getClone();\r
+       cl.internal = true;\r
+       if ( cl.original == null )\r
+           cl.original = this;\r
+       return cl;\r
+    }\r
+\r
+    /**\r
+     * Get this reply entity body.\r
+     * The reply entity body is returned as an InputStream, that the caller\r
+     * has to read to actually get the bytes of the content.\r
+     * @return An InputStream instance. If the reply has no body, the returned\r
+     * input stream will just return <strong>-1</strong> on first read.\r
+     */\r
+\r
+    public InputStream getInputStream()\r
+       throws IOException\r
+       {\r
+           if ( in != null )\r
+               return in;\r
+           // Find out which method is used to the length:\r
+           // first, chunked\r
+           String te[] = getTransferEncoding() ;\r
+           if ( te != null ) {\r
+               for (int i = 0 ; i < te.length ; i++) {\r
+                   if (te[i].equals("chunked")) \r
+                       in = new ChunkedInputStream(\r
+                           parser.getInputStream());\r
+               }\r
+           }\r
+           // if not, content-length\r
+           int len = getContentLength();\r
+           if ( (in == null) && (len >= 0) ) {\r
+               in = new ContentLengthInputStream(parser.getInputStream(),len);\r
+           }\r
+           // Handle broken HTTP/1.0 request\r
+           // It is mandatory for 1.1 requests to have been handled above.\r
+           if ((major == 1) && (minor == 0) && (in == null)) {\r
+               String m = getMethod();\r
+               if (m.equals("POST") || m.equals("PUT")) {\r
+                   keepcon = false;\r
+                   in      = parser.getInputStream();\r
+               }\r
+           }\r
+           return in;\r
+       }\r
+\r
+    /**\r
+     * Unescape a HTTP escaped string\r
+     * @param s The string to be unescaped\r
+     * @return the unescaped string.\r
+     */\r
+\r
+    public static String unescape (String s) {\r
+       StringBuffer sbuf = new StringBuffer () ;\r
+       int l  = s.length() ;\r
+       int ch = -1 ;\r
+       for (int i = 0 ; i < l ; i++) {\r
+           switch (ch = s.charAt(i)) {\r
+           case '%':\r
+               ch = s.charAt (++i) ;\r
+               int hb = (Character.isDigit ((char) ch) \r
+                         ? ch - '0'\r
+                         : 10+Character.toLowerCase ((char) ch)-'a') & 0xF ;\r
+               ch = s.charAt (++i) ;\r
+               int lb = (Character.isDigit ((char) ch)\r
+                         ? ch - '0'\r
+                         : 10+Character.toLowerCase ((char) ch)-'a') & 0xF ;\r
+               sbuf.append ((char) ((hb << 4) | lb)) ;\r
+               break ;\r
+           case '+':\r
+               sbuf.append (' ') ;\r
+               break ;\r
+           default:\r
+               sbuf.append ((char) ch) ;\r
+           }\r
+       }\r
+       return sbuf.toString() ;\r
+    }\r
+\r
+    public ReplyInterface makeBadRequestReply() {\r
+       return makeReply(HTTP.BAD_REQUEST);\r
+    }\r
+\r
+    /**\r
+     * Make an empty Reply object matching this request version.\r
+     * @param status The status of the reply.\r
+     */\r
+\r
+    public Reply makeReply(int status) {\r
+       Reply reply = new Reply(client\r
+                               , this\r
+                               , getMajorVersion()\r
+                               , getMinorVersion()\r
+                               , status);\r
+       if ((filters != null) && (infilters > 0))\r
+           reply.setFilters(filters, infilters);\r
+       return reply;\r
+    }\r
+\r
+    /**\r
+     * skip the body\r
+     */\r
+    public void skipBody() {\r
+       // don't skip when there is a 100-Continue\r
+       if (getExpect() != null)\r
+           return;\r
+       try {\r
+           InputStream is = getInputStream();\r
+           int avail = is.available();\r
+           \r
+           while (avail > 0) {\r
+               is.skip(avail);\r
+               avail = is.available();\r
+           }\r
+       } catch (Exception ex) {// nothing to skip \r
+       }\r
+    }\r
+\r
+    /**\r
+     * Get the client of this request.\r
+     */\r
+\r
+    public Client getClient() {\r
+       return client ;\r
+    }\r
+\r
+    public Request (Client client, MimeParser parser) {\r
+       super (parser);\r
+       this.parser = parser;\r
+       this.client = client ;\r
+    }\r
+\r
+\r
+    /**\r
+     * Set this reply entity body.\r
+        * @param is the InputStream instance. \r
+        * USE CAREFULLY : need to be thread-safe\r
+     */\r
+    public void setStream(InputStream is){\r
+       if (is != null)\r
+           this.in = is ;\r
+    }\r
+}\r