1 /* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.nashorn.internal.runtime.test; 27 28 import static org.testng.Assert.assertEquals; 29 import static org.testng.Assert.assertTrue; 30 import static org.testng.Assert.fail; 31 import javax.script.ScriptContext; 32 import javax.script.ScriptEngine; 33 import javax.script.ScriptEngineFactory; 34 import javax.script.ScriptEngineManager; 35 import javax.script.ScriptException; 36 import javax.script.SimpleScriptContext; 37 import jdk.nashorn.api.scripting.ClassFilter; 38 import jdk.nashorn.api.scripting.NashornScriptEngineFactory; 39 import jdk.nashorn.internal.runtime.Version; 40 import org.testng.annotations.Test; 41 42 /** 43 * Tests for trusted client usage of nashorn script engine factory extension API 44 */ 45 @SuppressWarnings("javadoc") 46 public class TrustedScriptEngineTest { 47 @Test 48 public void versionTest() { 49 final ScriptEngineManager m = new ScriptEngineManager(); 50 final ScriptEngine e = m.getEngineByName("nashorn"); 51 assertEquals(e.getFactory().getEngineVersion(), Version.version()); 52 } 53 54 private static class MyClassLoader extends ClassLoader { 55 // to check if script engine uses the specified class loader 56 private final boolean[] reached = new boolean[1]; 57 58 @Override 59 protected Class<?> findClass(final String name) throws ClassNotFoundException { 60 // flag that it reached here 61 reached[0] = true; 62 return super.findClass(name); 63 } 64 65 public boolean reached() { 66 return reached[0]; 67 } 68 } 69 70 // These are for "private" extension API of NashornScriptEngineFactory that 71 // accepts a ClassLoader and/or command line options. 72 73 @Test 74 public void factoryClassLoaderTest() { 75 final ScriptEngineManager sm = new ScriptEngineManager(); 76 for (final ScriptEngineFactory fac : sm.getEngineFactories()) { 77 if (fac instanceof NashornScriptEngineFactory) { 78 final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac; 79 final MyClassLoader loader = new MyClassLoader(); 80 // set the classloader as app class loader 81 final ScriptEngine e = nfac.getScriptEngine(loader); 82 try { 83 e.eval("Packages.foo"); 84 // check that the class loader was attempted 85 assertTrue(loader.reached(), "did not reach class loader!"); 86 } catch (final ScriptException se) { 87 se.printStackTrace(); 88 fail(se.getMessage()); 89 } 90 return; 91 } 92 } 93 94 fail("Cannot find nashorn factory!"); 95 } 96 97 @Test 98 public void factoryClassLoaderAndOptionsTest() { 99 final ScriptEngineManager sm = new ScriptEngineManager(); 100 for (final ScriptEngineFactory fac : sm.getEngineFactories()) { 101 if (fac instanceof NashornScriptEngineFactory) { 102 final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac; 103 final String[] options = new String[] { "-strict" }; 104 final MyClassLoader loader = new MyClassLoader(); 105 // set the classloader as app class loader 106 final ScriptEngine e = nfac.getScriptEngine(options, loader); 107 try { 108 e.eval("Packages.foo"); 109 // check that the class loader was attempted 110 assertTrue(loader.reached(), "did not reach class loader!"); 111 } catch (final ScriptException se) { 112 se.printStackTrace(); 113 fail(se.getMessage()); 114 } 115 116 try { 117 // strict mode - delete of a var should throw SyntaxError 118 e.eval("var d = 2; delete d;"); 119 } catch (final ScriptException se) { 120 // check that the error message contains "SyntaxError" 121 assertTrue(se.getMessage().contains("SyntaxError")); 122 } 123 124 return; 125 } 126 } 127 128 fail("Cannot find nashorn factory!"); 129 } 130 131 @Test 132 public void factoryOptionsTest() { 133 final ScriptEngineManager sm = new ScriptEngineManager(); 134 for (final ScriptEngineFactory fac : sm.getEngineFactories()) { 135 if (fac instanceof NashornScriptEngineFactory) { 136 final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac; 137 // specify --no-syntax-extensions flag 138 final String[] options = new String[] { "--no-syntax-extensions" }; 139 final ScriptEngine e = nfac.getScriptEngine(options); 140 try { 141 // try nashorn specific extension 142 e.eval("var f = funtion(x) 2*x;"); 143 fail("should have thrown exception!"); 144 } catch (final Exception ex) { 145 //empty 146 } 147 return; 148 } 149 } 150 151 fail("Cannot find nashorn factory!"); 152 } 153 154 @Test 155 /** 156 * Test repeated evals with --loader-per-compile=false 157 * We used to get "class redefinition error". 158 */ 159 public void noLoaderPerCompilerTest() { 160 final ScriptEngineManager sm = new ScriptEngineManager(); 161 for (final ScriptEngineFactory fac : sm.getEngineFactories()) { 162 if (fac instanceof NashornScriptEngineFactory) { 163 final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac; 164 final String[] options = new String[] { "--loader-per-compile=false" }; 165 final ScriptEngine e = nfac.getScriptEngine(options); 166 try { 167 e.eval("2 + 3"); 168 e.eval("4 + 4"); 169 } catch (final ScriptException se) { 170 se.printStackTrace(); 171 fail(se.getMessage()); 172 } 173 return; 174 } 175 } 176 fail("Cannot find nashorn factory!"); 177 } 178 179 @Test 180 /** 181 * Test that we can use same script name in repeated evals with --loader-per-compile=false 182 * We used to get "class redefinition error" as name was derived from script name. 183 */ 184 public void noLoaderPerCompilerWithSameNameTest() { 185 final ScriptEngineManager sm = new ScriptEngineManager(); 186 for (final ScriptEngineFactory fac : sm.getEngineFactories()) { 187 if (fac instanceof NashornScriptEngineFactory) { 188 final NashornScriptEngineFactory nfac = (NashornScriptEngineFactory)fac; 189 final String[] options = new String[] { "--loader-per-compile=false" }; 190 final ScriptEngine e = nfac.getScriptEngine(options); 191 e.put(ScriptEngine.FILENAME, "test.js"); 192 try { 193 e.eval("2 + 3"); 194 e.eval("4 + 4"); 195 } catch (final ScriptException se) { 196 se.printStackTrace(); 197 fail(se.getMessage()); 198 } 199 return; 200 } 201 } 202 fail("Cannot find nashorn factory!"); 203 } 204 205 @Test 206 public void globalPerEngineTest() throws ScriptException { 207 final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); 208 final String[] options = new String[] { "--global-per-engine" }; 209 final ScriptEngine e = fac.getScriptEngine(options); 210 211 e.eval("function foo() {}"); 212 213 final ScriptContext newCtx = new SimpleScriptContext(); 214 newCtx.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE); 215 216 // all global definitions shared and so 'foo' should be 217 // visible in new Bindings as well. 218 assertTrue(e.eval("typeof foo", newCtx).equals("function")); 219 220 e.eval("function bar() {}", newCtx); 221 222 // bar should be visible in default context 223 assertTrue(e.eval("typeof bar").equals("function")); 224 } 225 226 @Test 227 public void classFilterTest() throws ScriptException { 228 final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); 229 final ScriptEngine e = fac.getScriptEngine(new ClassFilter() { 230 @Override 231 public boolean exposeToScripts(final String fullName) { 232 // don't allow anything that is not "java." 233 return fullName.startsWith("java."); 234 } 235 }); 236 237 assertEquals(e.eval("typeof javax.script.ScriptEngine"), "object"); 238 assertEquals(e.eval("typeof java.util.Vector"), "function"); 239 240 try { 241 e.eval("Java.type('javax.script.ScriptContext')"); 242 fail("should not reach here"); 243 } catch (final ScriptException | RuntimeException se) { 244 if (! (se.getCause() instanceof ClassNotFoundException)) { 245 fail("ClassNotFoundException expected"); 246 } 247 } 248 } 249 250 @Test 251 public void classFilterTest2() throws ScriptException { 252 final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); 253 final ScriptEngine e = fac.getScriptEngine(new String[0], Thread.currentThread().getContextClassLoader(), 254 new ClassFilter() { 255 @Override 256 public boolean exposeToScripts(final String fullName) { 257 // don't allow anything that is not "java." 258 return fullName.startsWith("java."); 259 } 260 }); 261 262 assertEquals(e.eval("typeof javax.script.ScriptEngine"), "object"); 263 assertEquals(e.eval("typeof java.util.Vector"), "function"); 264 265 try { 266 e.eval("Java.type('javax.script.ScriptContext')"); 267 fail("should not reach here"); 268 } catch (final ScriptException | RuntimeException se) { 269 if (! (se.getCause() instanceof ClassNotFoundException)) { 270 fail("ClassNotFoundException expected"); 271 } 272 } 273 } 274 275 @Test 276 public void nullClassFilterTest() { 277 final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); 278 try { 279 fac.getScriptEngine((ClassFilter)null); 280 fail("should have thrown NPE"); 281 } catch (final NullPointerException e) { 282 //empty 283 } 284 } 285 286 @Test 287 public void nullClassFilterTest2() { 288 final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); 289 try { 290 fac.getScriptEngine(new String[0], null, null); 291 fail("should have thrown NPE"); 292 } catch (final NullPointerException e) { 293 //empty 294 } 295 } 296 297 @Test 298 public void nullArgsTest() { 299 final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); 300 try { 301 fac.getScriptEngine((String[])null); 302 fail("should have thrown NPE"); 303 } catch (final NullPointerException e) { 304 //empty 305 } 306 } 307 308 @Test 309 public void nullArgsTest2() { 310 final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); 311 try { 312 fac.getScriptEngine(null, null, new ClassFilter() { 313 @Override 314 public boolean exposeToScripts(final String name) { 315 return true; 316 } 317 }); 318 fail("should have thrown NPE"); 319 } catch (final NullPointerException e) { 320 //empty 321 } 322 } 323 324 @Test 325 public void nashornSwallowsConstKeyword() throws Exception { 326 final NashornScriptEngineFactory f = new NashornScriptEngineFactory(); 327 final String[] args = new String[] { "--const-as-var" }; 328 final ScriptEngine engine = f.getScriptEngine(args); 329 330 final Object ret = engine.eval("" 331 + "(function() {\n" 332 + " const x = 10;\n" 333 + " return x;\n" 334 + "})();" 335 ); 336 assertEquals(ret, 10, "Parsed and executed OK"); 337 } 338 339 @Test 340 public void evalDefaultFileNameTest() throws ScriptException { 341 final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); 342 final ScriptEngine engine = fac.getScriptEngine(new String[] { "--verify-code=true" }); 343 // default FILENAME being "<eval>" make sure generated code bytecode verifies. 344 engine.eval("var a = 3;"); 345 } 346 347 @Test 348 public void evalFileNameWithSpecialCharsTest() throws ScriptException { 349 final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); 350 final ScriptEngine engine = fac.getScriptEngine(new String[] { "--verify-code=true" }); 351 final ScriptContext ctxt = new SimpleScriptContext(); 352 // use file name with "dangerous" chars. 353 ctxt.setAttribute(ScriptEngine.FILENAME, "<myscript>", ScriptContext.ENGINE_SCOPE); 354 engine.eval("var a = 3;"); 355 ctxt.setAttribute(ScriptEngine.FILENAME, "[myscript]", ScriptContext.ENGINE_SCOPE); 356 engine.eval("var h = 'hello';"); 357 ctxt.setAttribute(ScriptEngine.FILENAME, ";/\\$.", ScriptContext.ENGINE_SCOPE); 358 engine.eval("var foo = 'world';"); 359 // name used by jjs shell tool for the interactive mode 360 ctxt.setAttribute(ScriptEngine.FILENAME, "<shell>", ScriptContext.ENGINE_SCOPE); 361 engine.eval("var foo = 'world';"); 362 } 363 }