Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / jigsaw / src / org / w3c / www / protocol / http / proxy / ProxyDispatcher.java
diff --git a/JMCR-Stable/real-world application/jigsaw/src/org/w3c/www/protocol/http/proxy/ProxyDispatcher.java b/JMCR-Stable/real-world application/jigsaw/src/org/w3c/www/protocol/http/proxy/ProxyDispatcher.java
new file mode 100644 (file)
index 0000000..866a7e3
--- /dev/null
@@ -0,0 +1,345 @@
+// ProxyDispatcher.java\r
+// $Id: ProxyDispatcher.java,v 1.1 2010/06/15 12:28:31 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.www.protocol.http.proxy ;\r
+\r
+import java.io.BufferedInputStream;\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.PrintStream;\r
+\r
+import java.net.URL;\r
+import java.net.URLConnection;\r
+\r
+import org.w3c.util.ObservableProperties;\r
+import org.w3c.util.PropertyMonitoring;\r
+\r
+import org.w3c.www.protocol.http.HttpException;\r
+import org.w3c.www.protocol.http.HttpManager;\r
+import org.w3c.www.protocol.http.PropRequestFilter;\r
+import org.w3c.www.protocol.http.Reply;\r
+import org.w3c.www.protocol.http.Request;\r
+\r
+import org.w3c.www.http.HttpRequestMessage;\r
+\r
+/**\r
+ * The proxy dispatcher applies some <em>rules</em> to a request.\r
+ * The goal of that filter is to allow special pre-processing of requests\r
+ * based, on their target host, before sending them off the net.\r
+ * <p>The filter is configured through a <em>rule file</em> whose format\r
+ * is described by the following BNF:\r
+ * <code>\r
+ * rule-file=(<em>record</em>)*<br>\r
+ * record=<strong>EOL</strong>|<em>comment</em>|<em>rule</em><br>\r
+ * comment=<strong>#</strong>(<strong>^EOL</strong>)*<strong>EOL</strong><br>\r
+ * rule=<em>rule-lhs</em>(<strong>SPACE</strong>)*<em>rule-rhs</em><br>\r
+ * rule-lhs=(<strong>token</strong>)\r
+ *  |(<strong>token</strong> (<strong>.</strong> <strog>token</strong>)*<br>\r
+ * rule-lhr=<em>forbid</em>|<em>direct</em>|<em>redirect</em>\r
+ *          |<em>proxy</em>|<em>authorization</em>|<em>proxyauth</em><br>\r
+ * forbid=<strong>FORBID</strong>|<strong>forbid</strong><br>\r
+ * direct=<strong>DIRECT</strong>|<strong>direct</strong><br>\r
+ * redirect=(<strong>REDIRECT</strong>|<strong>proxy</strong>) <em>url</em><br>\r
+ * proxy=(<strong>PROXY</strong>|<strong>proxy</strong>) <em>url</em><br>\r
+ * url=<strong>any valid URL</strong></br>\r
+ * authorization=(<strong>AUTHORIZATION</strong>|<strong>authorization</strong>\r
+ *  <em>user</em> <em>password</em><br>\r
+ * proxyauth=(<strong>PROXYAUTH</strong>|<strong>proxyauth</strong>\r
+ *  <em>user</em> <em>password</em> <em>url</em><br>\r
+ * </code>\r
+ * <p>A sample rule file looks like this:\r
+ * <code>\r
+ * # Some comments\r
+ * \r
+ * edu proxy http://class.w3.org:8001/\r
+ * org proxy http://class.w3.org:8001/\r
+ * fr  direct\r
+ * www.evilsite.com redirect http://www.goodsite.com/warning.html\r
+ * www.w3.org direct\r
+ * 138.96.24 direct\r
+ * www.playboy.com forbid\r
+ * default proxy http://cache.inria.fr:8080/\r
+ * </code>\r
+ * <p>The algorithm used to lookup rules is the following: \r
+ * <ul>\r
+ * <li>Split all rules <em>left hand side</em> into its components, eg \r
+ * H1.H2.H3 is splitted into { H1, H2, H3 }, then reverse the components and \r
+ * map that to the rule. In our example above, { org, w3, www} would be mapped\r
+ * to <em>direct</em>.\r
+ * <li>Split the fully qualified host name into its components, eg, A.B.C is\r
+ * splitted into { A, B, C } and reverse it.\r
+ * <li>Find the longest match in the mapping table of rules, and get\r
+ * apply the given rule.\r
+ * </ul>\r
+ * <p>In our example, a request to <strong>www.isi.edu</strong> would match\r
+ * the <em>edu</em> rule, and a request for <strong>www.w3.org</strong>\r
+ * would match the <em>direct</em> rule, for example.\r
+ * <p>Three rules are defined:\r
+ * <dl>\r
+ * <dt>direct<dd>Run that request directly against the target host.\r
+ * <dt>forbid<dd>Emit a forbid message, indicating that the user is not\r
+ * allowed to contact this host.\r
+ * <dt>proxy<dd>Run that request through the given <em>proxy</em>.\r
+ * <dt>proxyauth<dd>Run that request through a proxy with the right proxy\r
+ * credentials.\r
+ * </dl>\r
+ * <p>For numeric IP addresses, the most significant part is the beginning,\r
+ * so {A, B, C} are deducted directly. In the example { 138, 96, 24 } is mapped\r
+ * to direct.\r
+ * <p>If no rules are applied, then the default rule (root rule) is applied.\r
+ * See the example.\r
+ */\r
+\r
+public class ProxyDispatcher\r
+    implements PropRequestFilter, PropertyMonitoring \r
+{\r
+    /**\r
+     * Name of the property giving the rule file URL.\r
+     */\r
+    public static final \r
+    String RULE_P = "org.w3c.www.protocol.http.proxy.rules";\r
+\r
+    /**\r
+     * Name of the property turning that filter in debug mode.\r
+     */\r
+    public static final\r
+    String DEBUG_P = "org.w3c.www.protocol.http.proxy.debug";\r
+\r
+    /**\r
+     * Name of the property turning that filter in debug mode.\r
+     */\r
+    public static final\r
+       String CHECK_RULES_LAST_MODIFIED_P = \r
+       "org.w3c.www.protocol.http.proxy.rules.check.lastmodified";\r
+\r
+    /**\r
+     * The properties we initialized ourself from.\r
+     */\r
+    protected ObservableProperties props = null;  \r
+    /**\r
+     * The current set of rules to apply.\r
+     */\r
+    protected RuleNode rules = null;\r
+    /**\r
+     * Are we in debug mode ?\r
+     */\r
+    protected boolean debug = false;\r
+\r
+    protected boolean check_rules = false;\r
+\r
+    protected static final String disabled = "disabled";\r
+\r
+    protected long lastParsingTime = -1;\r
+\r
+    /**\r
+     * Parse the given input stream as a rule file.\r
+     * @param in The input stream to parse.\r
+     * @exception IOException if an IO error occurs.\r
+     * @exception RuleParserException if parsing failed.\r
+     */\r
+\r
+    protected void parseRules(InputStream in)\r
+       throws IOException, RuleParserException\r
+    {\r
+       RuleParser parser = new RuleParser(in);\r
+       RuleNode   nroot  = parser.parse();\r
+       rules = nroot;\r
+       lastParsingTime = System.currentTimeMillis();\r
+    }\r
+\r
+    /**\r
+     * Parse the default set of rules.\r
+     * <p>IOf the rules cannot be parsed, the filter emits an error\r
+     * message to standard error, and turn itself into transparent mode.\r
+     */\r
+\r
+    protected void parseRules() {\r
+       if ( debug )\r
+           System.out.println("PARSING RULES...");\r
+       String ruleurl = props.getString(RULE_P, null);\r
+       InputStream in = null;\r
+       // Try opening the rule file as a URL:\r
+       try {\r
+           URL url = new URL(ruleurl);\r
+           in = url.openStream();\r
+       } catch (Exception ex) {\r
+       // If this fails, it may be just a file name:\r
+           try {\r
+               in = (new BufferedInputStream\r
+                     (new FileInputStream\r
+                      (new File(ruleurl))));\r
+           } catch (Exception nex) {\r
+               System.err.println("* ProxyDispatcher: unable to open rule "\r
+                                  + "file \"" + ruleurl + "\"");\r
+               rules = null;\r
+               return;\r
+           }\r
+       } \r
+       // Parse that input stream as a rule file:\r
+       try {\r
+           parseRules(in);\r
+       } catch (Exception ex) {\r
+           System.err.println("Error parsing rules from: "+ruleurl);\r
+           ex.printStackTrace();\r
+           rules = null;           \r
+       } finally {\r
+           if ( in != null ) {\r
+               try {\r
+                   in.close();\r
+               } catch (IOException ex) {\r
+               }\r
+           }\r
+       }\r
+       if ( debug )\r
+           System.out.println("DONE.");\r
+    }\r
+\r
+    protected boolean needsParsing() {\r
+       if (rules == null) \r
+           return true;\r
+       if (! check_rules)\r
+           return false;\r
+       long rulesStamp = -1;\r
+       String ruleurl  = props.getString(RULE_P, null);\r
+       try {\r
+           URL url = new URL(ruleurl);\r
+           if (url.getProtocol().equalsIgnoreCase("file")) {\r
+               File file = new File(url.getFile());\r
+               rulesStamp = file.lastModified();\r
+           } else {\r
+               URLConnection con = url.openConnection();\r
+               rulesStamp = con.getLastModified();\r
+           }\r
+       } catch (Exception ex) {\r
+           File file = new File(ruleurl);\r
+           rulesStamp = file.lastModified();\r
+       }\r
+       System.out.println("rulesStamp : "+rulesStamp);\r
+       return (lastParsingTime < rulesStamp);\r
+    }\r
+\r
+    /**\r
+     * Filter requests before they are emitted.\r
+     * Look for a matching rule, and if found apply it before continuing\r
+     * the process. If a forbid rule was apply, this method will return\r
+     * with a <em>forbidden</em> message.\r
+     * @param request The request to filter.\r
+     * @return A Reply instance, if processing is not to be continued,\r
+     * <strong>false</strong>otherwise.\r
+     */\r
+\r
+    public Reply ingoingFilter(Request request) {\r
+       if (needsParsing())\r
+           parseRules();\r
+       if ( rules != null ) {\r
+           URL    url  = request.getURL();\r
+           String host = url.getHost();\r
+           Rule   rule = rules.lookupRule(host);\r
+           if ( rule != null ) {\r
+               if ( debug ) {\r
+                   String args = rule.getRuleArgs();\r
+                   if (args == null) {\r
+                       args = "";\r
+                   } else {\r
+                       args = " "+args;\r
+                   }\r
+                   System.out.println("["+ getClass().getName() +\r
+                                      "]: applying rule <"+rule.getRuleName()+\r
+                                      args +"> to " + request.getURL());\r
+               }\r
+               return rule.apply(request);\r
+           }\r
+       }\r
+       return null;\r
+    }\r
+\r
+    /**\r
+     * Filter requests when an error occurs during the process.\r
+     * This filter tries to do a direct connection if it is needed\r
+     * @param reques The request to filter.\r
+     * @param reply It's associated reply.\r
+     * @return Always <strong>null</strong>.\r
+     */\r
+\r
+    public boolean exceptionFilter(Request request, HttpException ex) {\r
+       // if it was a proxy connection, try a direct one\r
+       // add test for exception here\r
+       if(request.hasProxy()) {\r
+           Reply reply       = null;\r
+           HttpManager hm    = HttpManager.getManager();\r
+           request.setProxy(null);\r
+           if ( debug )\r
+               System.out.println("["+getClass().getName()+"]: direct fetch "\r
+                                  +"for " + request.getURL());\r
+           return true;\r
+       }\r
+       return false;\r
+    }\r
+\r
+    /**\r
+     * Filter requests after processing.\r
+     * This filter doesn't do any post-processing.\r
+     * @param reques The request to filter.\r
+     * @param reply It's associated reply.\r
+     * @return Always <strong>null</strong>.\r
+     */\r
+\r
+    public Reply outgoingFilter(Request request, Reply reply) {\r
+       return null;\r
+    }\r
+\r
+   /**\r
+     * PropertyMonitoring implementation - Commit property changes.\r
+     * @param name The name of the property that has changed.\r
+     * @return A boolean <strong>true</strong> if change was commited, \r
+     * <strong>false</strong> otherwise.\r
+     */\r
+\r
+    public boolean propertyChanged(String name) {\r
+       if(name.equals(RULE_P)) {\r
+           try {\r
+               parseRules();\r
+           } catch (Exception ex) {\r
+               ex.printStackTrace();\r
+               return false;\r
+           }\r
+       } else if (name.equals(DEBUG_P)) {\r
+           debug = props.getBoolean(DEBUG_P, false);\r
+       } else if (name.equals(CHECK_RULES_LAST_MODIFIED_P)) {\r
+           check_rules = props.getBoolean(CHECK_RULES_LAST_MODIFIED_P, false);\r
+       }\r
+       return true;\r
+    }\r
+\r
+    public void initialize(HttpManager manager) {\r
+       // Prepare empty entry list:\r
+       props = manager.getProperties();\r
+       props.registerObserver(this);\r
+       // Initialize from properties:\r
+       parseRules();\r
+       if (debug = props.getBoolean(DEBUG_P, false)) \r
+           System.out.println("["+getClass().getName()+": debuging on.");\r
+       check_rules = props.getBoolean(CHECK_RULES_LAST_MODIFIED_P, false);\r
+       // Install ourself\r
+       manager.setFilter(this);\r
+    }\r
+\r
+    /**\r
+     * We don't maintain cached infos.\r
+     */\r
+\r
+    public void sync() {\r
+    }\r
+\r
+    /**\r
+     * Empty constructor, for dynamic instantiation.\r
+     */\r
+\r
+    public ProxyDispatcher() {\r
+       super();\r
+    }\r
+}\r