--- /dev/null
+// 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;
+ }
+ }
+}