-
Notifications
You must be signed in to change notification settings - Fork 82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Experiment standalone nashorn #111
Changes from 1 commit
e1ae8a2
234ef1b
5ec6dab
5ea6949
4686d82
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package delight.nashornsandbox.internal; | ||
|
||
import jdk.nashorn.api.scripting.ClassFilter; | ||
|
||
public class JdkNashornClassFilter extends SandboxClassFilter implements ClassFilter { | ||
|
||
@Override | ||
public boolean exposeToScripts(final String className) { | ||
return super.exposeToScripts(className); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,13 @@ | ||
package delight.nashornsandbox.internal; | ||
|
||
import java.io.Writer; | ||
import java.lang.reflect.InvocationTargetException; | ||
import java.lang.reflect.Method; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.concurrent.ExecutorService; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
|
||
import javax.script.Bindings; | ||
import javax.script.Invocable; | ||
import javax.script.ScriptContext; | ||
import javax.script.ScriptEngine; | ||
import javax.script.ScriptException; | ||
import javax.script.*; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
@@ -19,7 +16,6 @@ | |
import delight.nashornsandbox.SecuredJsCache; | ||
import delight.nashornsandbox.exceptions.ScriptCPUAbuseException; | ||
import delight.nashornsandbox.exceptions.ScriptMemoryAbuseException; | ||
import jdk.nashorn.api.scripting.NashornScriptEngineFactory; | ||
|
||
/** | ||
* Nashorn sandbox implementation. | ||
|
@@ -39,9 +35,40 @@ | |
@SuppressWarnings("restriction") | ||
public class NashornSandboxImpl implements NashornSandbox { | ||
|
||
private static final Class<?> JDK_NASHORN_NashornScriptEngineFactory_CLASS; | ||
private static final Class<?> JDK_NASHORN_ClassFilter_CLASS; | ||
private static final Class<?> STANDALONE_NASHORN_NashornScriptEngineFactory_CLASS; | ||
private static final Class<?> STANDALONE_NASHORN_ClassFilter_CLASS; | ||
|
||
static { | ||
Class<?> tmp_JDK_NASHORN_NashornScriptEngineFactory_CLASS = null; | ||
Class<?> tmp_JDK_NASHORN_ClassFilter_CLASS = null; | ||
// TODO what behavior do we want here? | ||
// TODO move all JDK/standalone code to some dedicated class? | ||
try { | ||
tmp_JDK_NASHORN_NashornScriptEngineFactory_CLASS = Class.forName("jdk.nashorn.api.scripting.NashornScriptEngineFactory"); | ||
tmp_JDK_NASHORN_ClassFilter_CLASS = Class.forName("jdk.nashorn.api.scripting.ClassFilter"); | ||
} catch (ClassNotFoundException e) { | ||
System.out.println("JDK Nashorn not found"); | ||
} | ||
JDK_NASHORN_NashornScriptEngineFactory_CLASS = tmp_JDK_NASHORN_NashornScriptEngineFactory_CLASS; | ||
JDK_NASHORN_ClassFilter_CLASS = tmp_JDK_NASHORN_ClassFilter_CLASS; | ||
|
||
Class<?> tmp_STANDALONE_NASHORN_NashornScriptEngineFactory_CLASS = null; | ||
Class<?> tmp_STANDALONE_NASHORN_ClassFilter_CLASS = null; | ||
try { | ||
tmp_STANDALONE_NASHORN_NashornScriptEngineFactory_CLASS = Class.forName("org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory"); | ||
tmp_STANDALONE_NASHORN_ClassFilter_CLASS = Class.forName("org.openjdk.nashorn.api.scripting.ClassFilter"); | ||
} catch (ClassNotFoundException e) { | ||
System.out.println("Standalone Nashorn not found"); | ||
} | ||
STANDALONE_NASHORN_NashornScriptEngineFactory_CLASS = tmp_STANDALONE_NASHORN_NashornScriptEngineFactory_CLASS; | ||
STANDALONE_NASHORN_ClassFilter_CLASS = tmp_STANDALONE_NASHORN_ClassFilter_CLASS; | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably better to manage this in a centralised place? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Most certainly, that should move to a class like NashornDetection, that would do the detection and debug logs about what is going on. |
||
static final Logger LOG = LoggerFactory.getLogger(NashornSandbox.class); | ||
|
||
protected final SandboxClassFilter sandboxClassFilter = new SandboxClassFilter(); | ||
protected final SandboxClassFilter sandboxClassFilter; | ||
|
||
protected final ScriptEngine scriptEngine; | ||
|
||
|
@@ -95,15 +122,48 @@ public NashornSandboxImpl(ScriptEngine engine, String... params) { | |
"The engine parameter --no-java is not supported. Using it would interfere with the injected code to test for infinite loops."); | ||
} | ||
} | ||
sandboxClassFilter = createSandboxClassFilter(); | ||
this.scriptEngine = engine == null | ||
? new NashornScriptEngineFactory().getScriptEngine(params, this.getClass().getClassLoader(), | ||
this.sandboxClassFilter) | ||
? createNashornScriptEngineFactory(params) | ||
: engine; | ||
this.maxPreparedStatements = 0; | ||
this.allow(InterruptTest.class); | ||
this.engineAsserted = new AtomicBoolean(false); | ||
} | ||
|
||
private SandboxClassFilter createSandboxClassFilter() { | ||
if (JDK_NASHORN_ClassFilter_CLASS != null) { | ||
return new JdkNashornClassFilter(); | ||
} | ||
if (STANDALONE_NASHORN_ClassFilter_CLASS != null) { | ||
return new StandaloneNashornClassFilter(); | ||
} | ||
throw new IllegalStateException("Neither jdk.nashorn.api.scripting.ClassFilter or org.openjdk.nashorn.api.scripting.ClassFilter is present"); | ||
} | ||
|
||
public ScriptEngine createNashornScriptEngineFactory(String ... params) { | ||
try { | ||
Object nashornScriptEngineFactory = null; | ||
Class<?> classFilterClass = null; | ||
if (JDK_NASHORN_NashornScriptEngineFactory_CLASS != null) { | ||
nashornScriptEngineFactory = JDK_NASHORN_NashornScriptEngineFactory_CLASS.getConstructor().newInstance(); | ||
classFilterClass = JDK_NASHORN_ClassFilter_CLASS; | ||
} else if (STANDALONE_NASHORN_NashornScriptEngineFactory_CLASS != null) { | ||
nashornScriptEngineFactory = STANDALONE_NASHORN_NashornScriptEngineFactory_CLASS.getConstructor().newInstance(); | ||
classFilterClass = STANDALONE_NASHORN_ClassFilter_CLASS; | ||
} | ||
if (nashornScriptEngineFactory == null) { | ||
throw new IllegalStateException("Neither jdk.nashorn.api.scripting.NashornScriptEngineFactory or org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory is present"); | ||
} | ||
|
||
Method getScriptEngine = nashornScriptEngineFactory.getClass().getDeclaredMethod("getScriptEngine", String[].class, ClassLoader.class, classFilterClass); | ||
return (ScriptEngine) getScriptEngine.invoke(nashornScriptEngineFactory, params, this.getClass().getClassLoader(), | ||
classFilterClass.cast(this.sandboxClassFilter)); | ||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
private synchronized void assertScriptEngine() { | ||
try { | ||
if (!engineAsserted.get()) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package delight.nashornsandbox.internal; | ||
|
||
import org.openjdk.nashorn.api.scripting.ClassFilter; | ||
|
||
public class StandaloneNashornClassFilter extends SandboxClassFilter implements ClassFilter { | ||
|
||
@Override | ||
public boolean exposeToScripts(final String className) { | ||
return super.exposeToScripts(className); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,56 @@ | ||
package delight.nashornsandbox; | ||
|
||
import java.util.function.Function; | ||
|
||
import javax.script.ScriptException; | ||
|
||
import delight.nashornsandbox.exceptions.ScriptCPUAbuseException; | ||
import org.junit.Assert; | ||
import org.junit.Test; | ||
|
||
import delight.nashornsandbox.NashornSandbox; | ||
import delight.nashornsandbox.NashornSandboxes; | ||
import delight.nashornsandbox.exceptions.ScriptCPUAbuseException; | ||
import jdk.nashorn.api.scripting.ScriptObjectMirror; | ||
import javax.script.ScriptException; | ||
import java.lang.reflect.InvocationTargetException; | ||
|
||
@SuppressWarnings("all") | ||
public class TestAccessFunction { | ||
|
||
@Test | ||
public void test_access_variable() throws ScriptCPUAbuseException, ScriptException { | ||
private static final Class<?> JDK_NASHORN_ScriptObjectMirror_CLASS; | ||
private static final Class<?> STANDALONE_NASHORN_ScriptObjectMirror_CLASS; | ||
|
||
static { | ||
Class<?> tmp_JDK_NASHORN_ScriptObjectMirror_CLASS = null; | ||
// TODO what behavior do we want here? | ||
try { | ||
tmp_JDK_NASHORN_ScriptObjectMirror_CLASS = Class.forName("jdk.nashorn.api.scripting.ScriptObjectMirror"); | ||
} catch (ClassNotFoundException e) { | ||
System.out.println("JDK Nashorn not found"); | ||
} | ||
JDK_NASHORN_ScriptObjectMirror_CLASS= tmp_JDK_NASHORN_ScriptObjectMirror_CLASS; | ||
Class<?> tmp_STANDALONE_NASHORN_ScriptObjectMirror_CLASS = null; | ||
try { | ||
tmp_STANDALONE_NASHORN_ScriptObjectMirror_CLASS = Class.forName("org.openjdk.nashorn.api.scripting.ScriptObjectMirror"); | ||
} catch (ClassNotFoundException e) { | ||
System.out.println("Standalone Nashorn not found"); | ||
} | ||
STANDALONE_NASHORN_ScriptObjectMirror_CLASS = tmp_STANDALONE_NASHORN_ScriptObjectMirror_CLASS; | ||
} | ||
|
||
@Test | ||
public void test_access_variable() throws ScriptCPUAbuseException, ScriptException, InvocationTargetException, IllegalAccessException { | ||
final NashornSandbox sandbox = NashornSandboxes.create(); | ||
sandbox.eval("function callMe() { return 42; };"); | ||
final Object _get = sandbox.get("callMe"); | ||
Assert.assertEquals(Integer.valueOf(42), ((ScriptObjectMirror) _get).call(this)); | ||
Assert.assertEquals(Integer.valueOf(42), findAndCall(_get)); | ||
final Object _eval = sandbox.eval("callMe"); | ||
Assert.assertEquals(Integer.valueOf(42), ((ScriptObjectMirror) _eval).call(this)); | ||
Assert.assertEquals(Integer.valueOf(42), findAndCall(_get)); | ||
} | ||
|
||
|
||
private Object findAndCall(Object _get) { | ||
if (JDK_NASHORN_ScriptObjectMirror_CLASS != null && JDK_NASHORN_ScriptObjectMirror_CLASS.isInstance(_get)) { | ||
jdk.nashorn.api.scripting.ScriptObjectMirror scriptObjectMirror = (jdk.nashorn.api.scripting.ScriptObjectMirror) _get; | ||
return scriptObjectMirror.call(_get); | ||
} | ||
|
||
if (STANDALONE_NASHORN_ScriptObjectMirror_CLASS != null && STANDALONE_NASHORN_ScriptObjectMirror_CLASS.isInstance(_get)) { | ||
org.openjdk.nashorn.api.scripting.ScriptObjectMirror scriptObjectMirror = (org.openjdk.nashorn.api.scripting.ScriptObjectMirror) _get; | ||
return scriptObjectMirror.call(_get); | ||
} | ||
throw new IllegalStateException("Neither JDK nor standalone Nashorn has been found"); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume in the final version we wouldn't want to log out here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello, like I wrote in the description, this is a basis for discussion and must not be merged as is.
I think there should be somewhere a log statement indicating which version of Nashorn is used and why, but that should probably be at debug level.