diff --git a/pom.xml b/pom.xml index 992c7362..7512b837 100644 --- a/pom.xml +++ b/pom.xml @@ -61,6 +61,10 @@ org.javadelight delight-nashorn-sandbox + + org.javadelight + delight-rhino-sandbox + org.slf4j slf4j-api @@ -99,6 +103,13 @@ delight-nashorn-sandbox 0.1.14 + + org.javadelight + delight-rhino-sandbox + 0.0.9 + compile + true + org.slf4j slf4j-api diff --git a/src/main/java/com/github/markusbernhardt/proxy/ProxySearch.java b/src/main/java/com/github/markusbernhardt/proxy/ProxySearch.java index 610a473b..f48f7009 100644 --- a/src/main/java/com/github/markusbernhardt/proxy/ProxySearch.java +++ b/src/main/java/com/github/markusbernhardt/proxy/ProxySearch.java @@ -56,6 +56,7 @@ public class ProxySearch implements ProxySearchStrategy { private int pacCacheSize; private long pacCacheTTL; private CacheScope pacCacheScope; + private ScriptingEngineType engineType = ScriptingEngineType.NASHORHN; /***************************************************************************** * Types of proxy detection supported by the builder. @@ -83,6 +84,18 @@ public enum Strategy { /// Use Java Networking system properties JAVA } + + /***************************************************************************** + * Types of supported scripting engines. + ****************************************************************************/ + + public enum ScriptingEngineType { + // embedded in java + NASHORHN, + + // Mozilla Rhino, open-source implementation of JavaScript written entirely in Java. + RHINO + } /************************************************************************* * Constructor @@ -137,16 +150,16 @@ public void addStrategy(Strategy strategy) { this.strategies.add(new DesktopProxySearchStrategy()); break; case WPAD: - this.strategies.add(new WpadProxySearchStrategy()); + this.strategies.add(new WpadProxySearchStrategy(engineType)); break; case BROWSER: this.strategies.add(getDefaultBrowserStrategy()); break; case FIREFOX: - this.strategies.add(new FirefoxProxySearchStrategy()); + this.strategies.add(new FirefoxProxySearchStrategy(engineType)); break; case IE: - this.strategies.add(new IEProxySearchStrategy()); + this.strategies.add(new IEProxySearchStrategy(engineType)); break; case ENV_VAR: this.strategies.add(new EnvProxySearchStrategy()); @@ -155,11 +168,11 @@ public void addStrategy(Strategy strategy) { this.strategies.add(new WinProxySearchStrategy()); break; case KDE: - this.strategies.add(new KdeProxySearchStrategy()); + this.strategies.add(new KdeProxySearchStrategy(engineType)); break; case GNOME: - this.strategies.add(new GnomeDConfProxySearchStrategy()); - this.strategies.add(new GnomeProxySearchStrategy()); + this.strategies.add(new GnomeDConfProxySearchStrategy(engineType)); + this.strategies.add(new GnomeProxySearchStrategy(engineType)); break; case JAVA: this.strategies.add(new JavaProxySearchStrategy()); @@ -200,9 +213,9 @@ public void setPacCacheSettings(int size, long ttl, CacheScope cacheScope) { private ProxySearchStrategy getDefaultBrowserStrategy() { switch (PlatformUtil.getDefaultBrowser()) { case IE: - return new IEProxySearchStrategy(); + return new IEProxySearchStrategy(engineType); case FIREFOX: - return new FirefoxProxySearchStrategy(); + return new FirefoxProxySearchStrategy(engineType); } return null; } @@ -303,4 +316,23 @@ public void log(Class clazz, LogLevel loglevel, String msg, Object... params) ps.getProxySelector(); } + /************************************************************************* + * + * Returns scripting engine used to evaluate PAC scripts + * + ************************************************************************/ + public ScriptingEngineType getScriptingEngine() { + return engineType; + } + + /************************************************************************* + * + * Configures scripting engine used to evaluate PAC scripts + * + * @param scriptingEngine + ************************************************************************/ + public void setScriptingEngine(ScriptingEngineType scriptingEngine) { + this.engineType = scriptingEngine; + } + } diff --git a/src/main/java/com/github/markusbernhardt/proxy/search/browser/firefox/FirefoxProxySearchStrategy.java b/src/main/java/com/github/markusbernhardt/proxy/search/browser/firefox/FirefoxProxySearchStrategy.java index ac79aff3..abfd033a 100644 --- a/src/main/java/com/github/markusbernhardt/proxy/search/browser/firefox/FirefoxProxySearchStrategy.java +++ b/src/main/java/com/github/markusbernhardt/proxy/search/browser/firefox/FirefoxProxySearchStrategy.java @@ -5,6 +5,7 @@ import java.util.Properties; import com.github.markusbernhardt.proxy.ProxySearchStrategy; +import com.github.markusbernhardt.proxy.ProxySearch.ScriptingEngineType; import com.github.markusbernhardt.proxy.search.desktop.DesktopProxySearchStrategy; import com.github.markusbernhardt.proxy.search.wpad.WpadProxySearchStrategy; import com.github.markusbernhardt.proxy.selector.direct.NoProxySelector; @@ -71,6 +72,7 @@ public class FirefoxProxySearchStrategy implements ProxySearchStrategy { private FirefoxProfileSource profileScanner; private FirefoxSettingParser settingsParser; + private ScriptingEngineType engineType = ScriptingEngineType.NASHORHN; /************************************************************************* * ProxySelector @@ -89,6 +91,18 @@ public FirefoxProxySearchStrategy() { } this.settingsParser = new FirefoxSettingParser(); } + + /************************************************************************* + * ProxySelector + * + * @see java.net.ProxySelector#ProxySelector() + ************************************************************************/ + + public FirefoxProxySearchStrategy(ScriptingEngineType engineType) { + this(); + this.engineType = engineType; + } + /************************************************************************* * Loads the proxy settings and initializes a proxy selector for the firefox @@ -123,7 +137,7 @@ public ProxySelector getProxySelector() throws ProxyException { case 2: // PAC Script String pacScriptUrl = settings.getProperty("network.proxy.autoconfig_url", ""); Logger.log(getClass(), LogLevel.TRACE, "Firefox uses script (PAC) {0}", pacScriptUrl); - result = ProxyUtil.buildPacSelectorForUrl(pacScriptUrl); + result = ProxyUtil.buildPacSelectorForUrl(engineType, pacScriptUrl); break; case 3: // Backward compatibility to netscape. Logger.log(getClass(), LogLevel.TRACE, "Netscape compability mode -> uses no proxy"); diff --git a/src/main/java/com/github/markusbernhardt/proxy/search/browser/ie/IEProxySearchStrategy.java b/src/main/java/com/github/markusbernhardt/proxy/search/browser/ie/IEProxySearchStrategy.java index 64fa07f1..7fca123f 100644 --- a/src/main/java/com/github/markusbernhardt/proxy/search/browser/ie/IEProxySearchStrategy.java +++ b/src/main/java/com/github/markusbernhardt/proxy/search/browser/ie/IEProxySearchStrategy.java @@ -3,6 +3,7 @@ import java.net.ProxySelector; import java.util.Properties; +import com.github.markusbernhardt.proxy.ProxySearch.ScriptingEngineType; import com.github.markusbernhardt.proxy.jna.win.WinHttp; import com.github.markusbernhardt.proxy.jna.win.WinHttpCurrentUserIEProxyConfig; import com.github.markusbernhardt.proxy.jna.win.WinHttpHelpers; @@ -24,6 +25,17 @@ public class IEProxySearchStrategy extends CommonWindowsSearchStrategy { + public IEProxySearchStrategy() { + } + + public IEProxySearchStrategy(ScriptingEngineType engineType) { + this(); + this.engineType = engineType; + } + + + private ScriptingEngineType engineType = ScriptingEngineType.NASHORHN; + /************************************************************************* * getProxySelector * @@ -111,7 +123,7 @@ private PacProxySelector createPacSelector(IEProxyConfig ieProxyConfig) { if (pacUrl.startsWith("file://") && !pacUrl.startsWith("file:///")) { pacUrl = "file:///" + pacUrl.substring(7); } - return ProxyUtil.buildPacSelectorForUrl(pacUrl); + return ProxyUtil.buildPacSelectorForUrl(engineType, pacUrl); } return null; diff --git a/src/main/java/com/github/markusbernhardt/proxy/search/desktop/gnome/GnomeDConfProxySearchStrategy.java b/src/main/java/com/github/markusbernhardt/proxy/search/desktop/gnome/GnomeDConfProxySearchStrategy.java index 109f65fd..b598349a 100644 --- a/src/main/java/com/github/markusbernhardt/proxy/search/desktop/gnome/GnomeDConfProxySearchStrategy.java +++ b/src/main/java/com/github/markusbernhardt/proxy/search/desktop/gnome/GnomeDConfProxySearchStrategy.java @@ -5,6 +5,7 @@ import java.util.Properties; import com.github.markusbernhardt.proxy.ProxySearchStrategy; +import com.github.markusbernhardt.proxy.ProxySearch.ScriptingEngineType; import com.github.markusbernhardt.proxy.selector.direct.NoProxySelector; import com.github.markusbernhardt.proxy.selector.fixed.FixedProxySelector; import com.github.markusbernhardt.proxy.selector.misc.ProtocolDispatchSelector; @@ -67,6 +68,8 @@ public class GnomeDConfProxySearchStrategy implements ProxySearchStrategy { + private ScriptingEngineType engineType = ScriptingEngineType.NASHORHN; + /************************************************************************* * ProxySelector * @@ -76,6 +79,11 @@ public class GnomeDConfProxySearchStrategy implements ProxySearchStrategy { public GnomeDConfProxySearchStrategy() { super(); } + + public GnomeDConfProxySearchStrategy(ScriptingEngineType engineType) { + this(); + this.engineType = engineType; + } /************************************************************************* * Loads the proxy settings and initializes a proxy selector for the Gnome @@ -115,7 +123,7 @@ public ProxySelector getProxySelector() throws ProxyException { if ("auto".equals(type)) { String pacScriptUrl = settings.getProperty("org.gnome.system.proxy autoconfig-url", ""); Logger.log(getClass(), LogLevel.TRACE, "Gnome uses autodetect script {0}", pacScriptUrl); - result = ProxyUtil.buildPacSelectorForUrl(pacScriptUrl); + result = ProxyUtil.buildPacSelectorForUrl(engineType, pacScriptUrl); } // Wrap into white-list filter? diff --git a/src/main/java/com/github/markusbernhardt/proxy/search/desktop/gnome/GnomeProxySearchStrategy.java b/src/main/java/com/github/markusbernhardt/proxy/search/desktop/gnome/GnomeProxySearchStrategy.java index e5d953b0..fa90fcb6 100644 --- a/src/main/java/com/github/markusbernhardt/proxy/search/desktop/gnome/GnomeProxySearchStrategy.java +++ b/src/main/java/com/github/markusbernhardt/proxy/search/desktop/gnome/GnomeProxySearchStrategy.java @@ -16,6 +16,7 @@ import org.xml.sax.SAXException; import com.github.markusbernhardt.proxy.ProxySearchStrategy; +import com.github.markusbernhardt.proxy.ProxySearch.ScriptingEngineType; import com.github.markusbernhardt.proxy.selector.direct.NoProxySelector; import com.github.markusbernhardt.proxy.selector.fixed.FixedProxySelector; import com.github.markusbernhardt.proxy.selector.misc.ProtocolDispatchSelector; @@ -73,6 +74,8 @@ public class GnomeProxySearchStrategy implements ProxySearchStrategy { + private ScriptingEngineType engineType = ScriptingEngineType.NASHORHN; + /************************************************************************* * ProxySelector * @@ -82,7 +85,12 @@ public class GnomeProxySearchStrategy implements ProxySearchStrategy { public GnomeProxySearchStrategy() { super(); } - + + public GnomeProxySearchStrategy(ScriptingEngineType engineType) { + this(); + this.engineType = engineType; + } + /************************************************************************* * Loads the proxy settings and initializes a proxy selector for the Gnome * proxy settings. @@ -120,7 +128,7 @@ public ProxySelector getProxySelector() throws ProxyException { if ("auto".equals(type)) { String pacScriptUrl = settings.getProperty("/system/proxy/autoconfig_url", ""); Logger.log(getClass(), LogLevel.TRACE, "Gnome uses autodetect script {0}", pacScriptUrl); - result = ProxyUtil.buildPacSelectorForUrl(pacScriptUrl); + result = ProxyUtil.buildPacSelectorForUrl(engineType, pacScriptUrl); } // Wrap into white-list filter? diff --git a/src/main/java/com/github/markusbernhardt/proxy/search/desktop/kde/KdeProxySearchStrategy.java b/src/main/java/com/github/markusbernhardt/proxy/search/desktop/kde/KdeProxySearchStrategy.java index 27fadefb..907b37e6 100644 --- a/src/main/java/com/github/markusbernhardt/proxy/search/desktop/kde/KdeProxySearchStrategy.java +++ b/src/main/java/com/github/markusbernhardt/proxy/search/desktop/kde/KdeProxySearchStrategy.java @@ -5,6 +5,7 @@ import java.util.Properties; import com.github.markusbernhardt.proxy.ProxySearchStrategy; +import com.github.markusbernhardt.proxy.ProxySearch.ScriptingEngineType; import com.github.markusbernhardt.proxy.search.env.EnvProxySearchStrategy; import com.github.markusbernhardt.proxy.search.wpad.WpadProxySearchStrategy; import com.github.markusbernhardt.proxy.selector.direct.NoProxySelector; @@ -49,6 +50,8 @@ public class KdeProxySearchStrategy implements ProxySearchStrategy { + private ScriptingEngineType engineType = ScriptingEngineType.NASHORHN; + private KdeSettingsParser settingsParser; /************************************************************************* @@ -60,6 +63,11 @@ public class KdeProxySearchStrategy implements ProxySearchStrategy { public KdeProxySearchStrategy() { this(new KdeSettingsParser()); } + + public KdeProxySearchStrategy(ScriptingEngineType engineType) { + this(); + this.engineType = engineType; + } /************************************************************************* * ProxySelector @@ -107,7 +115,7 @@ public ProxySelector getProxySelector() throws ProxyException { case 2: // PAC Script String pacScriptUrl = settings.getProperty("Proxy Config Script", ""); Logger.log(getClass(), LogLevel.TRACE, "Kde uses autodetect script {0}", pacScriptUrl); - result = ProxyUtil.buildPacSelectorForUrl(pacScriptUrl); + result = ProxyUtil.buildPacSelectorForUrl(engineType, pacScriptUrl); break; case 3: // WPAD Logger.log(getClass(), LogLevel.TRACE, "Kde uses WPAD to detect the proxy"); diff --git a/src/main/java/com/github/markusbernhardt/proxy/search/desktop/osx/OsxProxySearchStrategy.java b/src/main/java/com/github/markusbernhardt/proxy/search/desktop/osx/OsxProxySearchStrategy.java index aaf97c7d..5e2b95ab 100644 --- a/src/main/java/com/github/markusbernhardt/proxy/search/desktop/osx/OsxProxySearchStrategy.java +++ b/src/main/java/com/github/markusbernhardt/proxy/search/desktop/osx/OsxProxySearchStrategy.java @@ -11,6 +11,7 @@ import java.util.List; import com.github.markusbernhardt.proxy.ProxySearchStrategy; +import com.github.markusbernhardt.proxy.ProxySearch.ScriptingEngineType; import com.github.markusbernhardt.proxy.search.browser.ie.IELocalByPassFilter; import com.github.markusbernhardt.proxy.search.wpad.WpadProxySearchStrategy; import com.github.markusbernhardt.proxy.selector.direct.NoProxySelector; @@ -62,6 +63,8 @@ public class OsxProxySearchStrategy implements ProxySearchStrategy { private static final String SETTINGS_FILE = "/Library/Preferences/SystemConfiguration/preferences.plist"; + private ScriptingEngineType engineType = ScriptingEngineType.NASHORHN; + /************************************************************************* * ProxySelector * @@ -71,6 +74,11 @@ public class OsxProxySearchStrategy implements ProxySearchStrategy { public OsxProxySearchStrategy() { super(); } + + public OsxProxySearchStrategy(ScriptingEngineType engineType) { + this(); + this.engineType = engineType; + } /************************************************************************* * Loads the proxy settings and initializes a proxy selector for the OSX @@ -323,7 +331,7 @@ private ProxySelector autodetectProxyIfAvailable(Dict proxySettings, ProxySelect private ProxySelector installPacProxyIfAvailable(Dict proxySettings, ProxySelector result) { if (isActive(proxySettings.get("ProxyAutoConfigEnable"))) { String url = (String) proxySettings.get("ProxyAutoConfigURLString"); - result = ProxyUtil.buildPacSelectorForUrl(url); + result = ProxyUtil.buildPacSelectorForUrl(engineType, url); } return result; } diff --git a/src/main/java/com/github/markusbernhardt/proxy/search/wpad/WpadProxySearchStrategy.java b/src/main/java/com/github/markusbernhardt/proxy/search/wpad/WpadProxySearchStrategy.java index 964eff2e..13ac4bce 100644 --- a/src/main/java/com/github/markusbernhardt/proxy/search/wpad/WpadProxySearchStrategy.java +++ b/src/main/java/com/github/markusbernhardt/proxy/search/wpad/WpadProxySearchStrategy.java @@ -14,6 +14,7 @@ import java.util.Random; import com.github.markusbernhardt.proxy.ProxySearchStrategy; +import com.github.markusbernhardt.proxy.ProxySearch.ScriptingEngineType; import com.github.markusbernhardt.proxy.search.wpad.dhcp.DHCPMessage; import com.github.markusbernhardt.proxy.search.wpad.dhcp.DHCPOptions; import com.github.markusbernhardt.proxy.search.wpad.dhcp.DHCPSocket; @@ -45,6 +46,8 @@ public class WpadProxySearchStrategy implements ProxySearchStrategy { + private ScriptingEngineType engineType = ScriptingEngineType.NASHORHN; + /************************************************************************* * Constructor ************************************************************************/ @@ -52,6 +55,11 @@ public class WpadProxySearchStrategy implements ProxySearchStrategy { public WpadProxySearchStrategy() { super(); } + + public WpadProxySearchStrategy(ScriptingEngineType engineType) { + this(); + this.engineType = engineType; + } /************************************************************************* * Loads the proxy settings from a PAC file. The location of the PAC file is @@ -75,7 +83,7 @@ public ProxySelector getProxySelector() throws ProxyException { return null; } Logger.log(getClass(), LogLevel.TRACE, "PAC script url found: {0}", pacScriptUrl); - return ProxyUtil.buildPacSelectorForUrl(pacScriptUrl); + return ProxyUtil.buildPacSelectorForUrl(engineType, pacScriptUrl); } catch (IOException e) { Logger.log(getClass(), LogLevel.ERROR, "Error during WPAD search.", e); throw new ProxyException(e); diff --git a/src/main/java/com/github/markusbernhardt/proxy/search/wpad/WpadProxySearchStrategyWithDHPC.java b/src/main/java/com/github/markusbernhardt/proxy/search/wpad/WpadProxySearchStrategyWithDHPC.java index 04fbd30c..4afdf6b9 100644 --- a/src/main/java/com/github/markusbernhardt/proxy/search/wpad/WpadProxySearchStrategyWithDHPC.java +++ b/src/main/java/com/github/markusbernhardt/proxy/search/wpad/WpadProxySearchStrategyWithDHPC.java @@ -10,6 +10,7 @@ import java.util.Properties; import com.github.markusbernhardt.proxy.ProxySearchStrategy; +import com.github.markusbernhardt.proxy.ProxySearch.ScriptingEngineType; import com.github.markusbernhardt.proxy.search.wpad.dhcp.DHCPMessage; import com.github.markusbernhardt.proxy.util.Logger; import com.github.markusbernhardt.proxy.util.ProxyException; @@ -39,6 +40,8 @@ public class WpadProxySearchStrategyWithDHPC implements ProxySearchStrategy { + private ScriptingEngineType engineType = ScriptingEngineType.NASHORHN; + /************************************************************************* * Constructor ************************************************************************/ @@ -46,6 +49,11 @@ public class WpadProxySearchStrategyWithDHPC implements ProxySearchStrategy { public WpadProxySearchStrategyWithDHPC() { super(); } + + public WpadProxySearchStrategyWithDHPC(ScriptingEngineType engineType) { + this(); + this.engineType = engineType; + } /************************************************************************* * Loads the proxy settings from a PAC file. The location of the PAC file is @@ -69,7 +77,7 @@ public ProxySelector getProxySelector() throws ProxyException { return null; } Logger.log(getClass(), LogLevel.TRACE, "PAC script url found: {0}", pacScriptUrl); - return ProxyUtil.buildPacSelectorForUrl(pacScriptUrl); + return ProxyUtil.buildPacSelectorForUrl(engineType, pacScriptUrl); } catch (IOException e) { Logger.log(getClass(), LogLevel.ERROR, "Error during WPAD search.", e); throw new ProxyException(e); diff --git a/src/main/java/com/github/markusbernhardt/proxy/selector/pac/PacProxySelector.java b/src/main/java/com/github/markusbernhardt/proxy/selector/pac/PacProxySelector.java index 2ba3d657..0bc1049b 100644 --- a/src/main/java/com/github/markusbernhardt/proxy/selector/pac/PacProxySelector.java +++ b/src/main/java/com/github/markusbernhardt/proxy/selector/pac/PacProxySelector.java @@ -9,6 +9,7 @@ import java.util.ArrayList; import java.util.List; +import com.github.markusbernhardt.proxy.ProxySearch.ScriptingEngineType; import com.github.markusbernhardt.proxy.util.Logger; import com.github.markusbernhardt.proxy.util.Logger.LogLevel; import com.github.markusbernhardt.proxy.util.ProxyUtil; @@ -36,9 +37,9 @@ public class PacProxySelector extends ProxySelector { * the source for the PAC file. ************************************************************************/ - public PacProxySelector(PacScriptSource pacSource) { + public PacProxySelector(ScriptingEngineType engineType, PacScriptSource pacSource) { super(); - selectEngine(pacSource); + selectEngine(engineType, pacSource); } /************************************************************************* @@ -70,14 +71,26 @@ public static boolean isEnabled() { * to use as input. ************************************************************************/ - private void selectEngine(PacScriptSource pacSource) { + private void selectEngine(ScriptingEngineType engineType, PacScriptSource pacSource) { try { Logger.log(getClass(), LogLevel.INFO, "Using javax.script JavaScript engine."); - pacScriptParser = new JavaxPacScriptParser(pacSource); + if (ScriptingEngineType.RHINO.equals(engineType)) { + pacScriptParser = createRhinoPacScriptParser(pacSource); + } else { + pacScriptParser = createJavaxPacScriptParser(pacSource); + } } catch (Exception e) { Logger.log(getClass(), LogLevel.ERROR, "PAC parser error.", e); } } + + private PacScriptParser createJavaxPacScriptParser(PacScriptSource pacSource) throws ProxyEvaluationException { + return new JavaxPacScriptParser(pacSource); + } + + private PacScriptParser createRhinoPacScriptParser(PacScriptSource pacSource) throws ProxyEvaluationException { + return new RhinoPacScriptParser(pacSource); + } /************************************************************************* * connectFailed diff --git a/src/main/java/com/github/markusbernhardt/proxy/selector/pac/RhinoPacScriptParser.java b/src/main/java/com/github/markusbernhardt/proxy/selector/pac/RhinoPacScriptParser.java new file mode 100644 index 00000000..95234333 --- /dev/null +++ b/src/main/java/com/github/markusbernhardt/proxy/selector/pac/RhinoPacScriptParser.java @@ -0,0 +1,146 @@ +package com.github.markusbernhardt.proxy.selector.pac; + +import com.github.markusbernhardt.proxy.util.Logger; +import com.github.markusbernhardt.proxy.util.Logger.LogLevel; +import delight.rhinosandox.RhinoSandbox; +import delight.rhinosandox.RhinoSandboxes; + +import java.lang.reflect.Method; + +/***************************************************************************** + * PAC parser using the Rhino JavaScript engine bundled with Java 1.6
+ * + * More information about PAC can be found there:
+ * Proxy_auto-config + *
+ * + * web-browser-auto-proxy-configuration + * + * @author Markus Bernhardt, Copyright 2016 + * @author Bernd Rosstauscher, Copyright 2009 + ****************************************************************************/ +public class RhinoPacScriptParser implements PacScriptParser { + static final String SCRIPT_METHODS_OBJECT = "__pacutil"; + static final String SOURCE_NAME = RhinoPacScriptParser.class.getName(); + + private final PacScriptSource source; + private final RhinoSandbox engine; + + /************************************************************************* + * Constructor + * + * @param source + * the source for the PAC script. + * @throws ProxyEvaluationException + * on error. + ************************************************************************/ + public RhinoPacScriptParser(PacScriptSource source) throws ProxyEvaluationException { + this.source = source; + this.engine = setupEngine(); + } + + /************************************************************************* + * Initializes the JavaScript engine and adds aliases for the functions + * defined in ScriptMethods. + * + * @throws ProxyEvaluationException + * on error. + ************************************************************************/ + private RhinoSandbox setupEngine() throws ProxyEvaluationException { + RhinoSandbox engine = RhinoSandboxes.create(); + engine.inject(SCRIPT_METHODS_OBJECT, new PacScriptMethods()); + // allow String + engine.allow(String.class); + + Class scriptMethodsClazz = ScriptMethods.class; + Method[] scriptMethods = scriptMethodsClazz.getMethods(); + + for (Method method : scriptMethods) { + String name = method.getName(); + int args = method.getParameterTypes().length; + StringBuilder toEval = new StringBuilder(name).append(" = function("); + for (int i = 0; i < args; i++) { + if (i > 0) { + toEval.append(","); + } + toEval.append("arg").append(i); + } + toEval.append(") {return "); + + String functionCall = buildFunctionCallCode(name, args); + + // If return type is java.lang.String convert it to a JS string + if (String.class.isAssignableFrom(method.getReturnType())) { + functionCall = "String(" + functionCall + ")"; + } + toEval.append(functionCall).append("; }"); + try { + // Add functions with calls to Java object to global scope + engine.evalWithGlobalScope(SOURCE_NAME, toEval.toString()); + } catch (Exception e) { + Logger.log(getClass(), LogLevel.ERROR, "JS evaluation error when creating alias for " + name + ".", e); + throw new ProxyEvaluationException("Error setting up script engine", e); + } + } + + return engine; + } + + /************************************************************************* + * Builds a JavaScript code snippet to call a function that we bind. + * + * @param functionName + * of the bound function + * @param args + * of the bound function + * @return the JS code to invoke the method. + ************************************************************************/ + + private String buildFunctionCallCode(String functionName, int args) { + StringBuilder functionCall = new StringBuilder(); + functionCall.append(SCRIPT_METHODS_OBJECT).append(".").append(functionName).append("("); + for (int i = 0; i < args; i++) { + if (i > 0) { + functionCall.append(","); + } + functionCall.append("arg").append(i); + } + functionCall.append(")"); + return functionCall.toString(); + } + + /*************************************************************************** + * Gets the source of the PAC script used by this parser. + * + * @return a PacScriptSource. + **************************************************************************/ + public PacScriptSource getScriptSource() { + return this.source; + } + + /************************************************************************* + * Evaluates the given URL and host against the PAC script. + * + * @param url + * the URL to evaluate. + * @param host + * the host name part of the URL. + * @return the script result. + * @throws ProxyEvaluationException + * on execution error. + ************************************************************************/ + public String evaluate(String url, String host) throws ProxyEvaluationException { + try { + StringBuilder script = new StringBuilder(this.source.getScriptContent()); + String evalMethod = " ;FindProxyForURL (\"" + url + "\",\"" + host + "\")"; + script.append(evalMethod); + Object result = this.engine.eval(SOURCE_NAME, script.toString()); + return (String) result; + } catch (Exception e) { + Logger.log(getClass(), LogLevel.ERROR, "JS evaluation error.", e); + throw new ProxyEvaluationException("Error while executing PAC script: " + e.getMessage(), e); + } + + } +} diff --git a/src/main/java/com/github/markusbernhardt/proxy/ui/ProxyTester.java b/src/main/java/com/github/markusbernhardt/proxy/ui/ProxyTester.java index 46fadfba..18175f6a 100644 --- a/src/main/java/com/github/markusbernhardt/proxy/ui/ProxyTester.java +++ b/src/main/java/com/github/markusbernhardt/proxy/ui/ProxyTester.java @@ -22,6 +22,7 @@ import javax.swing.UIManager; import com.github.markusbernhardt.proxy.ProxySearch; +import com.github.markusbernhardt.proxy.ProxySearch.ScriptingEngineType; import com.github.markusbernhardt.proxy.ProxySearch.Strategy; import com.github.markusbernhardt.proxy.util.Logger; import com.github.markusbernhardt.proxy.util.Logger.LogLevel; @@ -38,7 +39,8 @@ public class ProxyTester extends JFrame { private static final long serialVersionUID = 1L; - private JComboBox modes; + private JComboBox modes; + private JComboBox engines; private JButton testButton; private JTextField urlField; @@ -64,9 +66,11 @@ private void init() { JPanel p = new JPanel(); p.add(new JLabel("Mode:")); - - this.modes = new JComboBox(ProxySearch.Strategy.values()); - p.add(this.modes); + this.modes = new JComboBox(ProxySearch.Strategy.values()); + p.add(this.modes); + p.add(new JLabel("ScriptingEngine:")); + this.engines = new JComboBox(ProxySearch.ScriptingEngineType.values()); + p.add(this.engines); p.add(new JLabel("URL:")); this.urlField = new JTextField(30); @@ -118,7 +122,9 @@ protected void testUrl() { this.logArea.setText(""); Strategy pss = (Strategy) this.modes.getSelectedItem(); + ScriptingEngineType engineType = (ScriptingEngineType) this.engines.getSelectedItem(); ProxySearch ps = new ProxySearch(); + ps.setScriptingEngine(engineType); ps.addStrategy(pss); ProxySelector psel = ps.getProxySelector(); if (psel == null) { diff --git a/src/main/java/com/github/markusbernhardt/proxy/util/ProxyUtil.java b/src/main/java/com/github/markusbernhardt/proxy/util/ProxyUtil.java index 9fe88ee5..b2d18c8f 100644 --- a/src/main/java/com/github/markusbernhardt/proxy/util/ProxyUtil.java +++ b/src/main/java/com/github/markusbernhardt/proxy/util/ProxyUtil.java @@ -7,6 +7,7 @@ import java.util.Collections; import java.util.List; +import com.github.markusbernhardt.proxy.ProxySearch.ScriptingEngineType; import com.github.markusbernhardt.proxy.selector.fixed.FixedProxySelector; import com.github.markusbernhardt.proxy.selector.pac.PacProxySelector; import com.github.markusbernhardt.proxy.selector.pac.PacScriptSource; @@ -83,11 +84,11 @@ public static synchronized List noProxyList() { * working selector. ************************************************************************/ - public static PacProxySelector buildPacSelectorForUrl(String url) { + public static PacProxySelector buildPacSelectorForUrl(ScriptingEngineType engineType, String url) { PacProxySelector result = null; PacScriptSource pacSource = new UrlPacScriptSource(url); if (pacSource.isScriptValid()) { - result = new PacProxySelector(pacSource); + result = new PacProxySelector(engineType, pacSource); } return result; } diff --git a/src/test/java/com/github/markusbernhardt/proxy/selector/pac/JavaxPacScriptParserTest.java b/src/test/java/com/github/markusbernhardt/proxy/selector/pac/JavaxPacScriptParserTest.java index 38823655..49d7c1b4 100644 --- a/src/test/java/com/github/markusbernhardt/proxy/selector/pac/JavaxPacScriptParserTest.java +++ b/src/test/java/com/github/markusbernhardt/proxy/selector/pac/JavaxPacScriptParserTest.java @@ -61,7 +61,18 @@ public void testScriptExecution() throws ProxyException, MalformedURLException { PacScriptParser p = new JavaxPacScriptParser(new UrlPacScriptSource(toUrl("test1.pac"))); p.evaluate(TestUtil.HTTP_TEST_URI.toString(), "host1.unit-test.invalid"); } - + + /************************************************************************* + * Test method + * @throws Exception + ************************************************************************/ + @Test(expected = Exception.class) + public void testSemicolonBeforeElse() throws Exception { + PacScriptParser p = new JavaxPacScriptParser(new UrlPacScriptSource(toUrl("testSemicolonBeforeElse.pac"))); + String evaluate = p.evaluate(TestUtil.HTTP_TEST_URI.toString(), "host1.unit-test.invalid"); + Assert.assertEquals("PROXY proxy:3128", evaluate); + } + /************************************************************************* * Test method * diff --git a/src/test/java/com/github/markusbernhardt/proxy/selector/pac/PacPerProtocolTest.java b/src/test/java/com/github/markusbernhardt/proxy/selector/pac/PacPerProtocolTest.java index 44d08e86..0bcecf05 100644 --- a/src/test/java/com/github/markusbernhardt/proxy/selector/pac/PacPerProtocolTest.java +++ b/src/test/java/com/github/markusbernhardt/proxy/selector/pac/PacPerProtocolTest.java @@ -13,6 +13,7 @@ import org.junit.Test; import com.github.markusbernhardt.proxy.TestUtil; +import com.github.markusbernhardt.proxy.ProxySearch.ScriptingEngineType; import com.github.markusbernhardt.proxy.selector.pac.PacProxySelector; import com.github.markusbernhardt.proxy.selector.pac.UrlPacScriptSource; @@ -35,7 +36,7 @@ public void testPacForSocket() throws IOException, URISyntaxException { new URI("socket://host1.unit-test.invalid/"); - List result = new PacProxySelector(new UrlPacScriptSource(toUrl("test1.pac"))) + List result = new PacProxySelector(ScriptingEngineType.NASHORHN, new UrlPacScriptSource(toUrl("test1.pac"))) .select(TestUtil.SOCKET_TEST_URI); assertEquals(TestUtil.HTTP_TEST_PROXY, result.get(0)); diff --git a/src/test/java/com/github/markusbernhardt/proxy/selector/pac/PacProxySelectorTest.java b/src/test/java/com/github/markusbernhardt/proxy/selector/pac/PacProxySelectorTest.java index 3e4e2d0b..79eb0a18 100644 --- a/src/test/java/com/github/markusbernhardt/proxy/selector/pac/PacProxySelectorTest.java +++ b/src/test/java/com/github/markusbernhardt/proxy/selector/pac/PacProxySelectorTest.java @@ -16,6 +16,7 @@ import org.junit.Test; import com.github.markusbernhardt.proxy.TestUtil; +import com.github.markusbernhardt.proxy.ProxySearch.ScriptingEngineType; import com.github.markusbernhardt.proxy.selector.pac.PacProxySelector; import com.github.markusbernhardt.proxy.selector.pac.PacScriptMethods; import com.github.markusbernhardt.proxy.selector.pac.UrlPacScriptSource; @@ -40,7 +41,7 @@ public class PacProxySelectorTest { ************************************************************************/ @Test public void testScriptExecution() throws ProxyException, MalformedURLException { - List result = new PacProxySelector(new UrlPacScriptSource(toUrl("test1.pac"))) + List result = new PacProxySelector(ScriptingEngineType.NASHORHN, new UrlPacScriptSource(toUrl("test1.pac"))) .select(TestUtil.HTTP_TEST_URI); assertEquals(TestUtil.HTTP_TEST_PROXY, result.get(0)); @@ -56,7 +57,7 @@ public void testScriptExecution() throws ProxyException, MalformedURLException { ************************************************************************/ @Test public void testScriptExecution2() throws ProxyException, MalformedURLException { - PacProxySelector pacProxySelector = new PacProxySelector(new UrlPacScriptSource(toUrl("test2.pac"))); + PacProxySelector pacProxySelector = new PacProxySelector(ScriptingEngineType.NASHORHN, new UrlPacScriptSource(toUrl("test2.pac"))); List result = pacProxySelector.select(TestUtil.HTTP_TEST_URI); assertEquals(Proxy.NO_PROXY, result.get(0)); @@ -89,7 +90,7 @@ public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { }); PacProxySelector pacProxySelector = new PacProxySelector( - new UrlPacScriptSource("http://www.test.invalid/wpad.pac")); + ScriptingEngineType.NASHORHN, new UrlPacScriptSource("http://www.test.invalid/wpad.pac")); pacProxySelector.select(TestUtil.HTTPS_TEST_URI); } finally { ProxySelector.setDefault(oldOne); @@ -106,7 +107,8 @@ public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { ************************************************************************/ @Test public void testScriptMuliProxy() throws ProxyException, MalformedURLException { - PacProxySelector pacProxySelector = new PacProxySelector(new UrlPacScriptSource(toUrl("testMultiProxy.pac"))); + PacProxySelector pacProxySelector = new PacProxySelector(ScriptingEngineType.NASHORHN, + new UrlPacScriptSource(toUrl("testMultiProxy.pac"))); List result = pacProxySelector.select(TestUtil.HTTP_TEST_URI); assertEquals(4, result.size()); assertEquals(new Proxy(Type.HTTP, InetSocketAddress.createUnresolved("my-proxy.com", 80)), result.get(0)); @@ -127,7 +129,8 @@ public void testScriptMuliProxy() throws ProxyException, MalformedURLException { public void testLocalIPOverride() throws ProxyException, MalformedURLException { System.setProperty(PacScriptMethods.OVERRIDE_LOCAL_IP, "123.123.123.123"); try { - PacProxySelector pacProxySelector = new PacProxySelector(new UrlPacScriptSource(toUrl("testLocalIP.pac"))); + PacProxySelector pacProxySelector = new PacProxySelector(ScriptingEngineType.NASHORHN, + new UrlPacScriptSource(toUrl("testLocalIP.pac"))); List result = pacProxySelector.select(TestUtil.HTTP_TEST_URI); assertEquals(result.get(0), new Proxy(Type.HTTP, InetSocketAddress.createUnresolved("123.123.123.123", 8080))); diff --git a/src/test/java/com/github/markusbernhardt/proxy/selector/pac/RhinoPacScriptParserTest.java b/src/test/java/com/github/markusbernhardt/proxy/selector/pac/RhinoPacScriptParserTest.java new file mode 100644 index 00000000..5da79f99 --- /dev/null +++ b/src/test/java/com/github/markusbernhardt/proxy/selector/pac/RhinoPacScriptParserTest.java @@ -0,0 +1,178 @@ +package com.github.markusbernhardt.proxy.selector.pac; + +import java.io.File; +import java.net.MalformedURLException; +import java.util.Calendar; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.github.markusbernhardt.proxy.TestUtil; +import com.github.markusbernhardt.proxy.util.ProxyException; + +/***************************************************************************** + * Tests for the javax.script PAC script parser. + * + * @author Markus Bernhardt, Copyright 2016 + * @author Bernd Rosstauscher, Copyright 2009 + ****************************************************************************/ + +public class RhinoPacScriptParserTest { + + /************************************************************************* + * Set calendar for date and time base tests. Current date for all tests is: 15. + * December 1994 12:00.00 its a Thursday + ************************************************************************/ + @BeforeClass + public static void setup() { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.YEAR, 1994); + cal.set(Calendar.MONTH, Calendar.DECEMBER); + cal.set(Calendar.DAY_OF_MONTH, 15); + cal.set(Calendar.HOUR_OF_DAY, 12); + cal.set(Calendar.MINUTE, 00); + cal.set(Calendar.SECOND, 00); + cal.set(Calendar.MILLISECOND, 00); + + // TODO Rossi 26.08.2010 need to fake time + // RhinoPacScriptParser.setCurrentTime(cal); + } + + /************************************************************************* + * Cleanup after the tests. + ************************************************************************/ + @AfterClass + public static void teadDown() { + // RhinoPacScriptParser.setCurrentTime(null); + } + + /************************************************************************* + * Test method + * + * @throws ProxyException + * on proxy detection error. + * @throws MalformedURLException + * on URL erros + ************************************************************************/ + @Test + public void testScriptExecution() throws ProxyException, MalformedURLException { + PacScriptParser p = new RhinoPacScriptParser(new UrlPacScriptSource(toUrl("test1.pac"))); + p.evaluate(TestUtil.HTTP_TEST_URI.toString(), "host1.unit-test.invalid"); + } + + /************************************************************************* + * Test method + * + * @throws ProxyException + * on proxy detection error. + * @throws MalformedURLException + * on URL erros + ************************************************************************/ + @Test + public void testSemicolonBeforeElse() throws ProxyException, MalformedURLException { + PacScriptParser p = new RhinoPacScriptParser(new UrlPacScriptSource(toUrl("testSemicolonBeforeElse.pac"))); + String evaluate = p.evaluate(TestUtil.HTTP_TEST_URI.toString(), "host1.unit-test.invalid"); + Assert.assertEquals("PROXY proxy.:3128; PROXY dmzproxy:3128", evaluate); + } + + /************************************************************************* + * Test method + * + * @throws ProxyException + * on proxy detection error. + * @throws MalformedURLException + * on URL erros + ************************************************************************/ + @Test + public void testCommentsInScript() throws ProxyException, MalformedURLException { + PacScriptParser p = new RhinoPacScriptParser(new UrlPacScriptSource(toUrl("test2.pac"))); + p.evaluate(TestUtil.HTTP_TEST_URI.toString(), "host1.unit-test.invalid"); + } + + /************************************************************************* + * Test method + * + * @throws ProxyException + * on proxy detection error. + * @throws MalformedURLException + * on URL erros + ************************************************************************/ + @Test + public void testScriptWeekDayScript() throws ProxyException, MalformedURLException { + PacScriptParser p = new RhinoPacScriptParser(new UrlPacScriptSource(toUrl("testWeekDay.pac"))); + p.evaluate(TestUtil.HTTP_TEST_URI.toString(), "host1.unit-test.invalid"); + } + + /************************************************************************* + * Test method + * + * @throws ProxyException + * on proxy detection error. + * @throws MalformedURLException + * on URL erros + ************************************************************************/ + @Test + public void testDateRangeScript() throws ProxyException, MalformedURLException { + PacScriptParser p = new RhinoPacScriptParser(new UrlPacScriptSource(toUrl("testDateRange.pac"))); + p.evaluate(TestUtil.HTTP_TEST_URI.toString(), "host1.unit-test.invalid"); + } + + /************************************************************************* + * Test method + * + * @throws ProxyException + * on proxy detection error. + * @throws MalformedURLException + * on URL erros + ************************************************************************/ + @Test + public void testTimeRangeScript() throws ProxyException, MalformedURLException { + PacScriptParser p = new RhinoPacScriptParser(new UrlPacScriptSource(toUrl("testTimeRange.pac"))); + p.evaluate(TestUtil.HTTP_TEST_URI.toString(), "host1.unit-test.invalid"); + } + + /************************************************************************* + * Test method + * + * @throws ProxyException + * on proxy detection error. + * @throws MalformedURLException + * on URL erros + ************************************************************************/ + @Test + public void methodsShouldReturnJsStrings() throws ProxyException, MalformedURLException { + PacScriptParser p = new RhinoPacScriptParser(new UrlPacScriptSource(toUrl("testReturnTypes.pac"))); + String actual = p.evaluate(TestUtil.HTTP_TEST_URI.toString(), "host1.unit-test.invalid"); + Assert.assertEquals("number boolean string", actual); + } + + /************************************************************************* + * Test method + * + * @throws ProxyException + * on proxy detection error. + * @throws MalformedURLException + * on URL erros + ************************************************************************/ + @Test(expected = Exception.class) + public void shouldNotExecuteCodeInPac() throws ProxyException, MalformedURLException { + PacScriptParser p = new RhinoPacScriptParser(new UrlPacScriptSource(toUrl("testRemoteCodeExecution.pac"))); + p.evaluate(TestUtil.HTTP_TEST_URI.toString(), "host.does.not.matter"); + } + + /************************************************************************* + * Helper method to build the url to the given test file + * + * @param testFile + * the name of the test file. + * @return the URL. + * @throws MalformedURLException + ************************************************************************/ + + private String toUrl(String testFile) throws MalformedURLException { + return new File(TestUtil.TEST_DATA_FOLDER + "pac", testFile).toURI().toURL().toString(); + } + +} diff --git a/src/test/resources/pac/testSemicolonBeforeElse.pac b/src/test/resources/pac/testSemicolonBeforeElse.pac new file mode 100644 index 00000000..d03bfb56 --- /dev/null +++ b/src/test/resources/pac/testSemicolonBeforeElse.pac @@ -0,0 +1,26 @@ +// Nashorn scripting engine fails to parse this script with +// jdk.nashorn.internal.runtime.ParserException: :8:2 Expected an operand but found else +// else return "PROXY proxy:3128"; +function FindProxyForURL(url, host) + { + if (shExpMatch(host, "deploy.abc.eu")) + + return "PROXY proxy:3128"; + + else if (isInNet(myIpAddress(), "10.25.48.0", "255.255.240.0")) + + return "PROXY dmzproxy:3128; PROXY proxy:3128; DIRECT"; + + else if (isInNet(myIpAddress(), "10.26.128.0", "255.255.248.0")) + + return "PROXY proxy:3128; DIRECT"; + + else if (isInNet(myIpAddress(), "10.25.0.0", "255.255.0.0") + ) + + return "PROXY dmzproxy:3128; PROXY proxy:3128; DIRECT"; + + else + + return "PROXY proxy.:3128; PROXY dmzproxy:3128"; + } \ No newline at end of file