moved ProxyAutoConfig.java from org.ibex.net.HTTP to this package
authoradam <adam@megacz.com>
Fri, 23 Dec 2005 00:23:02 +0000 (00:23 +0000)
committeradam <adam@megacz.com>
Fri, 23 Dec 2005 00:23:02 +0000 (00:23 +0000)
darcs-hash:20051223002302-5007d-e25ca6e561cb4b911851bded3b6ff1b95e13d359.gz

src/org/ibex/js/ProxyAutoConfig.java [new file with mode: 0644]

diff --git a/src/org/ibex/js/ProxyAutoConfig.java b/src/org/ibex/js/ProxyAutoConfig.java
new file mode 100644 (file)
index 0000000..5c20076
--- /dev/null
@@ -0,0 +1,218 @@
+// Copyright 2000-2005 the Contributors, as shown in the revision logs.
+// Licensed under the Apache Public Source License 2.0 ("the License").
+// You may not use this file except in compliance with the License.
+
+package org.ibex.js;
+
+import java.net.*;
+import java.io.*;
+import java.util.*;
+import java.net.*;
+import org.ibex.util.*;
+import org.ibex.net.*;
+import org.ibex.crypto.*;
+
+public class ProxyAutoConfig {
+
+    public static class PacProxy extends HTTP.Proxy {
+        private final JS pacFunc;
+        public PacProxy(JS pacFunc) { this.pacFunc = pacFunc; }
+        public Socket attempt(String url, String host, HTTP http) {
+            if (Log.verbose) Log.info(this, "evaluating PAC script");
+            String pac = null;
+            try {
+                pac = JSU.toString(pacFunc.call(null, new JS[] { JSU.S(url), JSU.S(host) }));
+                if (Log.verbose) Log.info(this, "  PAC script returned \"" + pac + "\"");
+            } catch (Throwable e) {
+                if (Log.on) Log.info(this, "PAC script threw exception " + e);
+                return null;
+            }
+            StringTokenizer st = new StringTokenizer(pac, ";", false);
+            while (st.hasMoreTokens()) {
+                String token = st.nextToken().trim();
+                if (Log.verbose) Log.info(this, "  trying \"" + token + "\"...");
+                try {
+                    Socket ret = null;
+                    if (token.startsWith("DIRECT"))
+                        ret = attemptDirect(http);
+                    else if (token.startsWith("PROXY"))
+                        ret = attemptHttpProxy(http,
+                                               token.substring(token.indexOf(' ') + 1, token.indexOf(':')),
+                                               Integer.parseInt(token.substring(token.indexOf(':') + 1)));
+                    else if (token.startsWith("SOCKS"))
+                        ret = attemptSocksProxy(http,
+                                                token.substring(token.indexOf(' ') + 1, token.indexOf(':')),
+                                                Integer.parseInt(token.substring(token.indexOf(':') + 1)));
+                    if (ret != null) return ret;
+                } catch (Throwable e) {
+                    if (Log.on) Log.info(this, "attempt at \"" + token + "\" failed due to " + e + "; trying next token");
+                }
+            }
+            if (Log.on) Log.info(this, "all PAC results exhausted");
+            return null;
+        }
+    }
+    
+    public static class ProxyAutoConfigRootScope extends JSScope.Global {
+
+        public ProxyAutoConfigRootScope() { super(); }
+        
+        private final static JS.Method METHOD = new JS.Method();
+        public JS get(JS name) throws JSExn {
+            //#jsswitch(name)
+            case "isPlainHostName": return METHOD;
+            case "dnsDomainIs": return METHOD;
+            case "localHostOrDomainIs": return METHOD;
+            case "isResolvable": return METHOD;
+            case "isInNet": return METHOD;
+            case "dnsResolve": return METHOD;
+            case "myIpAddress": return METHOD;
+            case "dnsDomainLevels": return METHOD;
+            case "shExpMatch": return METHOD;
+            case "weekdayRange": return METHOD;
+            case "dateRange": return METHOD;
+            case "timeRange": return METHOD;
+            case "ProxyConfig": return ProxyConfig;
+                //#end
+                return super.get(name);
+        }
+        
+        private static final JS proxyConfigBindings = new JS.Obj();
+        private static final JS ProxyConfig = new JS.Obj() {
+                public JS get(JS name) throws JSExn {
+                    //#jsswitch(name)
+                    case "bindings": return proxyConfigBindings;
+                        //#end
+                        return null;
+                }
+            };
+
+        public JS call(JS method, JS[] args) throws JSExn {
+            //#jsswitch(method)
+            case "isPlainHostName": return JSU.B(JSU.toString(args[0]).indexOf('.') == -1);
+            case "dnsDomainIs":     return JSU.B(JSU.toString(args[0]).endsWith(JSU.toString(args[1])));
+            case "localHostOrDomainIs":
+                return JSU.B(args[0].equals(args[1]) ||
+                             (JSU.toString(args[0]).indexOf('.') == -1 && JSU.toString(args[1]).startsWith(JSU.toString(args[0]))));
+            case "isResolvable": try {
+                return JSU.B(InetAddress.getByName(JSU.toString(args[0])) != null);
+            } catch (UnknownHostException e) { return JSU.F; }
+            case "isInNet":
+                if (args.length != 3) return JSU.F;
+                try {
+                    byte[] host = InetAddress.getByName(JSU.toString(args[0])).getAddress();
+                    byte[] net = InetAddress.getByName(JSU.toString(args[1])).getAddress();
+                    byte[] mask = InetAddress.getByName(args[2].toString()).getAddress();
+                    return JSU.B((host[0] & mask[0]) == net[0] &&
+                                 (host[1] & mask[1]) == net[1] &&
+                                 (host[2] & mask[2]) == net[2] &&
+                                 (host[3] & mask[3]) == net[3]);
+                } catch (Exception e) {
+                    throw new JSExn("exception in isInNet(): " + e);
+                }
+            case "dnsResolve":
+                try {
+                    return JSU.S(InetAddress.getByName(JSU.toString(args[0])).getHostAddress());
+                } catch (UnknownHostException e) {
+                    return null;
+                }
+            case "myIpAddress":
+                try {
+                    return JSU.S(InetAddress.getLocalHost().getHostAddress());
+                } catch (UnknownHostException e) {
+                    if (Log.on) Log.info(this, "strange... host does not know its own address");
+                    return null;
+                }
+            case "dnsDomainLevels":
+                String s = JSU.toString(args[0]);
+                int i = 0;
+                while((i = s.indexOf('.', i)) != -1) i++;
+                return JSU.N(i);
+            case "shExpMatch":
+                StringTokenizer st = new StringTokenizer(JSU.toString(args[1]), "*", false);
+                String[] arr = new String[st.countTokens()];
+                String s = JSU.toString(args[0]);
+                for (int i=0; st.hasMoreTokens(); i++) arr[i] = st.nextToken();
+                return JSU.B(match(arr, s, 0));
+            case "weekdayRange":
+                TimeZone tz = (args.length < 3 || args[2] == null || !args[2].equals("GMT")) ?
+                    TimeZone.getTimeZone("UTC") : TimeZone.getDefault();
+                Calendar c = new GregorianCalendar();
+                c.setTimeZone(tz);
+                c.setTime(new java.util.Date());
+                java.util.Date d = c.getTime();
+                int day = d.getDay();
+                String d1s = JSU.toString(args[0]).toUpperCase();
+                int d1 = 0, d2 = 0;
+                for(int i=0; i<days.length; i++) if (days[i].equals(d1s)) d1 = i;
+                    
+                if (args.length == 1) return JSU.B(d1 == day);
+                    
+                String d2s = JSU.toString(args[1]).toUpperCase();
+                for(int i=0; i<days.length; i++) if (days[i].equals(d2s)) d2 = i;
+                    
+                return JSU.B((d1 <= d2 && day >= d1 && day <= d2) || (d1 > d2 && (day >= d1 || day <= d2)));
+                    
+            case "dateRange": throw new JSExn("Ibex does not support dateRange() in PAC scripts");
+            case "timeRange": throw new JSExn("Ibex does not support timeRange() in PAC scripts");
+                //#end
+                return super.call(method, args);
+        }       
+        private static boolean match(String[] arr, String s, int index) {
+            if (index >= arr.length) return true;
+            for(int i=0; i<s.length(); i++) {
+                String s2 = s.substring(i);
+                if (s2.startsWith(arr[index]) && match(arr, s2.substring(arr[index].length()), index + 1)) return true;
+            }
+            return false;
+        }
+        public static String[] days = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
+    }
+
+    public static JS proxyAutoConfigRootScope = new ProxyAutoConfigRootScope();
+    public static JS getProxyAutoConfigFunction(String url) {
+        try { 
+            BufferedReader br = new BufferedReader(new InputStreamReader(new HTTP(url, true).GET(null, null)));
+            String s = null;
+            String script = "";
+            while((s = br.readLine()) != null) script += s + "\n";
+            if (Log.on) Log.info(Proxy.class, "successfully retrieved WPAD PAC:");
+            if (Log.on) Log.info(Proxy.class, script);
+            
+            // MS CARP hack
+            Vector carpHosts = new Vector();
+            for(int i=0; i<script.length(); i++)
+                if (script.regionMatches(i, "new Node(", 0, 9)) {
+                    String host = script.substring(i + 10, script.indexOf('\"', i + 11));
+                    if (Log.on) Log.info(Proxy.class, "Detected MS Proxy Server CARP Script, Host=" + host);
+                    carpHosts.addElement(host);
+                }
+            if (carpHosts.size() > 0) {
+                script = "function FindProxyForURL(url, host) {\nreturn \"";
+                for(int i=0; i<carpHosts.size(); i++)
+                    script += "PROXY " + carpHosts.elementAt(i) + "; ";
+                script += "\";\n}";
+                if (Log.on) Log.info(Proxy.class, "DeCARPed PAC script:");
+                if (Log.on) Log.info(Proxy.class, script);
+            }
+
+            JS scr = JSU.fromReader("PAC script at " + url, 0, new StringReader(script));
+            JSU.cloneWithNewGlobalScope(scr, proxyAutoConfigRootScope).call(null, null);
+            return (JS)proxyAutoConfigRootScope.get(JSU.S("FindProxyForURL"));
+        } catch (Exception e) {
+            if (Log.on) {
+                Log.info(ProxyAutoConfig.class, "WPAD detection failed due to:");
+                if (e instanceof JSExn) {
+                    try {
+                        org.ibex.js.JSArray arr = new org.ibex.js.JSArray();
+                        arr.add(((JSExn)e).getObject());
+                    } catch (Exception e2) {
+                        Log.info(ProxyAutoConfig.class, e);
+                    }
+                }
+                else Log.info(ProxyAutoConfig.class, e);
+            }
+            return null;
+        }
+    }
+}