diff --git a/build.gradle b/build.gradle index 872a3d918..fd7a0e33a 100644 --- a/build.gradle +++ b/build.gradle @@ -40,18 +40,18 @@ sourceSets { } dependencies { - implementation 'org.mozilla:rhino:1.7.13' - implementation 'org.eclipse.jetty:jetty-server:9.4.43.v20210629' - implementation 'org.eclipse.jetty:jetty-servlet:9.4.43.v20210629' - implementation 'org.eclipse.jetty.websocket:websocket-server:9.4.43.v20210629' - implementation 'org.eclipse.jetty.websocket:websocket-client:9.4.43.v20210629' - implementation 'org.eclipse.jetty:jetty-servlets:9.4.43.v20210629' - implementation 'org.eclipse.jetty:jetty-xml:9.4.43.v20210629' - implementation 'org.apache.logging.log4j:log4j-core:2.14.0' - implementation 'org.apache.logging.log4j:log4j-api:2.14.0' - implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.14.0' - implementation 'org.jline:jline:3.20.0' - implementation 'junit:junit:4.13.1' + implementation 'org.mozilla:rhino:1.7.14' + implementation 'org.eclipse.jetty:jetty-server:9.4.44.v20210927' + implementation 'org.eclipse.jetty:jetty-servlet:9.4.44.v20210927' + implementation 'org.eclipse.jetty.websocket:websocket-server:9.4.44.v20210927' + implementation 'org.eclipse.jetty.websocket:websocket-client:9.4.44.v20210927' + implementation 'org.eclipse.jetty:jetty-servlets:9.4.44.v20210927' + implementation 'org.eclipse.jetty:jetty-xml:9.4.44.v20210927' + implementation 'org.apache.logging.log4j:log4j-core:2.17.1' + implementation 'org.apache.logging.log4j:log4j-api:2.17.1' + implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.17.1' + implementation 'org.jline:jline:3.21.0' + implementation 'junit:junit:4.13.2' } tasks.withType(JavaCompile) { @@ -250,7 +250,7 @@ class DatesTestTask extends JavaExec { }) .distinct() .sorted() - .forEach({offset -> + .forEach({offset -> String timeZone = "GMT${offset}" logger.quiet("Testing ringo/utils/dates in timezone {} …", timeZone) systemProperty("user.timezone", timeZone); @@ -258,4 +258,4 @@ class DatesTestTask extends JavaExec { }) } -} \ No newline at end of file +} diff --git a/lib/ringo.policy b/lib/ringo.policy deleted file mode 100644 index b830e33d3..000000000 --- a/lib/ringo.policy +++ /dev/null @@ -1,41 +0,0 @@ -// Example policy file for RingoJS -// Run RingoJS with the -P or --policy option to activate this: -// ringo -P file:/.../ringo.policy -// replacing "..." with the absolute path of the policy file. -// -// The following URLs provide more information: -// http://java.sun.com/j2se/1.4.2/docs/guide/security/PolicyFiles.html -// http://java.sun.com/j2se/1.4.2/docs/guide/security/permissions.html - -grant codeBase "file:${ringo.home}/run.jar" { - permission java.security.AllPermission; -}; - -grant codeBase "file:${ringo.home}/lib/-" { - permission java.security.AllPermission; -}; - -grant codeBase "file:${ringo.home}/modules/-" { - permission java.security.AllPermission; -}; - -grant codeBase "file:${ringo.home}/apps/-" { - permission java.security.AllPermission; -}; - -grant codeBase "file:${ringo.home}/packages/-" { - permission java.security.AllPermission; -}; - -// example sandbox setup -grant codeBase "file:${ringo.home}/sandbox/-" { - permission java.io.FilePermission "${ringo.home}/modules/-", "read"; - permission java.io.FilePermission "${ringo.home}/packages/-", "read"; - permission java.io.FilePermission "${ringo.home}/sandbox/-", "read"; - permission java.io.FilePermission "${ringo.home}/sandbox/db/-", "read,write"; - permission java.util.PropertyPermission "*", "read"; - permission java.lang.RuntimePermission "getenv.*"; - // permission java.net.SocketPermission "*:80", "connect"; - // permission org.ringojs.security.RingoRuntimePermission "accessJava"; - // permission org.ringojs.security.RingoRuntimePermission "spawnThread"; -}; diff --git a/modules/fs.js b/modules/fs.js index 4fd9d8384..f1c0c7ec1 100644 --- a/modules/fs.js +++ b/modules/fs.js @@ -26,8 +26,6 @@ const io = require('io'); const binary = require('binary'); -const security = java.lang.System.getSecurityManager(); - const arrays = require('ringo/utils/arrays'); const {PosixPermissions} = require('ringo/utils/files'); @@ -769,10 +767,6 @@ const lastModified = exports.lastModified = function(path) { * @param {Number|String|java.util.Set} permissions optional the POSIX permissions */ const makeDirectory = exports.makeDirectory = function(path, permissions) { - if (security) { - security.checkWrite(path); - } - // single-argument Files.createDirectory() respects the current umask if (permissions == null) { Files.createDirectory(getPath(path)); @@ -824,9 +818,6 @@ const isDirectory = exports.isDirectory = function(path) { * @returns {Boolean} true if the given file exists and is a symbolic link */ const isLink = exports.isLink = function(path) { - if (security) { - security.checkRead(path); - } return Files.isSymbolicLink(resolvePath(path)); } @@ -840,10 +831,6 @@ const isLink = exports.isLink = function(path) { * @returns {Boolean} true iff the two paths locate the same file */ const same = exports.same = function(pathA, pathB) { - if (security) { - security.checkRead(pathA); - security.checkRead(pathB); - } // make canonical to resolve symbolic links const nioPathA = getPath(canonical(pathA)); const nioPathB = getPath(canonical(pathB)); @@ -859,10 +846,6 @@ const same = exports.same = function(pathA, pathB) { * @returns {Boolean} true if same file system, otherwise false */ const sameFilesystem = exports.sameFilesystem = function(pathA, pathB) { - if (security) { - security.checkRead(pathA); - security.checkRead(pathB); - } // make canonical to resolve symbolic links const nioPathA = getPath(canonical(pathA)); const nioPathB = getPath(canonical(pathB)); @@ -908,11 +891,6 @@ const touch = exports.touch = function(path, mtime) { * @returns {String} the path to the symbolic link */ const symbolicLink = exports.symbolicLink = function(existing, link) { - if (security) { - security.checkRead(existing); - security.checkWrite(link); - } - return String(Files.createSymbolicLink(getPath(link), getPath(existing))); } @@ -925,11 +903,6 @@ const symbolicLink = exports.symbolicLink = function(existing, link) { * @returns {String} the path to the link */ const hardLink = exports.hardLink = function(existing, link) { - if (security) { - security.checkRead(existing); - security.checkWrite(link); - } - return String(Files.createLink(getPath(link), getPath(existing))); } @@ -939,8 +912,6 @@ const hardLink = exports.hardLink = function(existing, link) { * @param {String} path a file path */ const readLink = exports.readLink = function(path) { - if (security) security.checkRead(path); - // Throws an exception if there is no symbolic link at the given path or the link cannot be read. if (!Files.isReadable(getPath(path))) { throw new Error("Path " + path + " is not readable!"); @@ -974,9 +945,6 @@ const iterate = exports.iterate = function(path) { * @returns PosixFilePermission the POSIX permissions for the given path */ const permissions = exports.permissions = function(path) { - if (security) { - security.checkRead(path); - } return new PosixPermissions(Files.getPosixFilePermissions(getPath(path))); } @@ -986,9 +954,6 @@ const permissions = exports.permissions = function(path) { * @returns {String} the username of the owner, or null if not possible to determine */ const owner = exports.owner = function(path) { - if (security) { - security.checkRead(path); - } try { return Files.getOwner(getPath(path)).getName(); } catch (error) { @@ -1004,9 +969,6 @@ const owner = exports.owner = function(path) { * @returns {String} the group's name, or null if not possible to determine */ const group = exports.group = function(path) { - if (security) { - security.checkRead(path); - } try { const attributes = Files.getFileAttributeView(getPath(path), PosixFileAttributeView); return attributes.readAttributes().group().getName(); @@ -1023,9 +985,6 @@ const group = exports.group = function(path) { * @param {Number|String|java.util.Set} permissions the POSIX permissions */ const changePermissions = exports.changePermissions = function(path, permissions) { - if (security) { - security.checkWrite(path); - } permissions = new PosixPermissions(permissions); return Files.setPosixFilePermissions(getPath(path), permissions.toJavaPosixFilePermissionSet()); } @@ -1037,10 +996,6 @@ const changePermissions = exports.changePermissions = function(path, permissions * @param {String} owner the user name string */ const changeOwner = exports.changeOwner = function(path, user) { - if (security) { - security.checkWrite(path); - } - const lookupService = FS.getUserPrincipalLookupService(); const userPrincipal = lookupService.lookupPrincipalByName(user); @@ -1054,10 +1009,6 @@ const changeOwner = exports.changeOwner = function(path, user) { * @param {String} group group name string */ const changeGroup = exports.changeGroup = function(path, group) { - if (security) { - security.checkWrite(path); - } - const lookupService = FS.getUserPrincipalLookupService(); const groupPrincipal = lookupService.lookupPrincipalByGroupName(group); diff --git a/modules/ringo/utils/http.js b/modules/ringo/utils/http.js index 0b8ff3ebf..92eaa3eb5 100644 --- a/modules/ringo/utils/http.js +++ b/modules/ringo/utils/http.js @@ -11,7 +11,7 @@ const {Buffer} = require('ringo/buffer'); const binary = require('binary'); const io = require('io'); -const {open} = require('fs').open; +const fs = require('fs'); const {createTempFile} = require('ringo/utils/files'); const PATH_CTL = java.util.regex.Pattern.compile("[\x00-\x1F\x7F\x3B]"); @@ -894,5 +894,5 @@ exports.TempFileFactory = function(data, encoding) { return BufferFactory(data, encoding) } data.tempfile = createTempFile("ringo-upload-"); - return open(data.tempfile, {write: true, binary: true}); + return fs.open(data.tempfile, {write: true, binary: true}); }; diff --git a/src/org/ringojs/engine/ReloadableScript.java b/src/org/ringojs/engine/ReloadableScript.java index 23c6db557..e0f4ad58c 100644 --- a/src/org/ringojs/engine/ReloadableScript.java +++ b/src/org/ringojs/engine/ReloadableScript.java @@ -149,9 +149,7 @@ protected synchronized Object compileScript(Context cx) Object script = null; String charset = engine.getCharset(); try { - CodeSource securityDomain = engine.isPolicyEnabled() ? - new CodeSource(resource.getUrl(), (CodeSigner[]) null) : null; - script = loader.load(cx, engine, securityDomain, moduleName, + script = loader.load(cx, engine, null, moduleName, charset, resource); } catch (Exception x) { exception = x; diff --git a/src/org/ringojs/engine/RhinoEngine.java b/src/org/ringojs/engine/RhinoEngine.java index 75e741d6d..95d64e45d 100644 --- a/src/org/ringojs/engine/RhinoEngine.java +++ b/src/org/ringojs/engine/RhinoEngine.java @@ -700,16 +700,9 @@ public static RhinoEngine getEngine(Scriptable scope) { */ public RhinoEngine createSandbox(RingoConfig config, Map globals) throws Exception { - config.setPolicyEnabled(this.config.isPolicyEnabled()); return new RhinoEngine(config, globals); } - protected boolean isPolicyEnabled() { - // only use security when ringo runs standalone with default security manager, - // not with google app engine - return config.isPolicyEnabled(); - } - /** * Wait until all daemon threads running in this engine have terminated. * @throws InterruptedException if the current thread has been interrupted diff --git a/src/org/ringojs/engine/RingoConfig.java b/src/org/ringojs/engine/RingoConfig.java index e9096af71..4f9e6240f 100644 --- a/src/org/ringojs/engine/RingoConfig.java +++ b/src/org/ringojs/engine/RingoConfig.java @@ -58,7 +58,6 @@ public class RingoConfig { private WrapFactory wrapFactory = null; private List bootstrapScripts; private boolean sealed = false; - private boolean policyEnabled = false; private boolean reloading = true; private String charset = "UTF-8"; @@ -537,14 +536,6 @@ public void setReloading(boolean reloading) { this.reloading = reloading; } - public boolean isPolicyEnabled() { - return policyEnabled; - } - - public void setPolicyEnabled(boolean hasPolicy) { - this.policyEnabled = hasPolicy; - } - public List getBootstrapScripts() { return bootstrapScripts; } diff --git a/src/org/ringojs/engine/RingoContextFactory.java b/src/org/ringojs/engine/RingoContextFactory.java index 3d4acd054..be6e514f6 100644 --- a/src/org/ringojs/engine/RingoContextFactory.java +++ b/src/org/ringojs/engine/RingoContextFactory.java @@ -82,10 +82,6 @@ public Void run() { if (classShutter != null) { cx.setClassShutter(classShutter); } - if (engine.isPolicyEnabled()) { - cx.setInstructionObserverThreshold(instructionLimit); - cx.setSecurityController(new PolicySecurityController()); - } cx.setErrorReporter(new ToolErrorReporter(true)); cx.setGeneratingDebug(generatingDebug); } diff --git a/src/org/ringojs/engine/RingoGlobal.java b/src/org/ringojs/engine/RingoGlobal.java index ebf79f94d..86cd62a10 100644 --- a/src/org/ringojs/engine/RingoGlobal.java +++ b/src/org/ringojs/engine/RingoGlobal.java @@ -30,7 +30,6 @@ import org.mozilla.javascript.tools.shell.QuitAction; import org.ringojs.repository.Repository; import org.ringojs.repository.Trackable; -import org.ringojs.security.RingoSecurityManager; import org.ringojs.util.ScriptUtils; import org.mozilla.javascript.tools.shell.Global; import org.ringojs.repository.Resource; @@ -48,7 +47,6 @@ public class RingoGlobal extends Global { private final RhinoEngine engine; - private final static SecurityManager securityManager = System.getSecurityManager(); private static ExecutorService threadPool; private static final AtomicInteger ids = new AtomicInteger(); @@ -147,9 +145,6 @@ public static Object getRepository(final Context cx, Scriptable thisObj, public static Object addToClasspath(final Context cx, Scriptable thisObj, Object[] args, Function funObj) { - if (securityManager != null) { - securityManager.checkPermission(RingoSecurityManager.GET_CLASSLOADER); - } if (args.length != 1) { throw Context.reportRuntimeError( "addToClasspath() requires one argument"); @@ -206,9 +201,6 @@ public PrivilegedAction run() { public static Object spawn(Context cx, Scriptable thisObj, Object[] args, Function funObj) { - if (securityManager != null) { - securityManager.checkPermission(RingoSecurityManager.SPAWN_THREAD); - } if (args.length < 1 || !(args[0] instanceof Function)) { throw Context.reportRuntimeError("spawn() requires a function argument"); } diff --git a/src/org/ringojs/security/RingoRuntimePermission.java b/src/org/ringojs/security/RingoRuntimePermission.java deleted file mode 100644 index fbc63dc9f..000000000 --- a/src/org/ringojs/security/RingoRuntimePermission.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.ringojs.security; - -import java.security.BasicPermission; - -/** - * This class represents a Ringo-specific runtime permission. Ringo - * must be run with {@link RingoSecurityManager} in order for - * RingoRuntimePermissions to take effect. - *

- * Currently the Ringo runtime recognizes the following permissions: - * - *

    - *
  • accessJava: grant JavaScript code access to Java classes
  • - *
  • spawnThread: allow JavaScript code to spawn threads
  • - *
- */ -public class RingoRuntimePermission extends BasicPermission { - - static final long serialVersionUID = -7850438718537722485L; - - public RingoRuntimePermission(String name) { - super(name); - } - - public RingoRuntimePermission(String name, String actions) { - super(name, actions); - } - -} diff --git a/src/org/ringojs/security/RingoSecurityManager.java b/src/org/ringojs/security/RingoSecurityManager.java deleted file mode 100644 index ca1ab46c6..000000000 --- a/src/org/ringojs/security/RingoSecurityManager.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.ringojs.security; - -import org.mozilla.javascript.RhinoSecurityManager; - -import java.security.*; - -public class RingoSecurityManager extends RhinoSecurityManager { - - public static final Permission - GET_CLASSLOADER = new RuntimePermission("getClassLoader"); - public static final Permission - ACCESS_JAVA = new RingoRuntimePermission("accessJava"); - public static final Permission - SPAWN_THREAD = new RingoRuntimePermission("spawnThread"); - - /** - * The default security manager does not provide a way to keep code from starting - * threads. We overide this method to be able to do so by checking the - * modifyThreadGroup permission on all thread groups, not just the root group. - * @param g the threadgroup - */ - @Override - public void checkAccess(ThreadGroup g) { - checkPermission(SPAWN_THREAD); - super.checkAccess(g); - } - - /** - * Check if the top-most application script has permission to access - * members of Java objects and classes. - * - * This checks if the script trying to access a java class or object has the - * accessEngine RingoRuntimePermission. - * - * @exception SecurityException if the caller does not have - * permission to access java classes. - */ - public void checkJavaAccess() { - - final Class c = getCurrentScriptClass(); - if (c == null) { - return; - } - - Boolean allowed = AccessController.doPrivileged((PrivilegedAction) () -> { - ProtectionDomain pd = c.getProtectionDomain(); - return pd == null || Policy.getPolicy().implies(pd, ACCESS_JAVA) ? - Boolean.TRUE : Boolean.FALSE; - }); - - if (!allowed) { - throw new AccessControlException("Java access denied", ACCESS_JAVA); - } - } - -} diff --git a/src/org/ringojs/security/SecureWrapFactory.java b/src/org/ringojs/security/SecureWrapFactory.java deleted file mode 100644 index d36759c91..000000000 --- a/src/org/ringojs/security/SecureWrapFactory.java +++ /dev/null @@ -1,133 +0,0 @@ -package org.ringojs.security; - -import org.mozilla.javascript.Context; -import org.mozilla.javascript.NativeJavaClass; -import org.mozilla.javascript.NativeJavaObject; -import org.mozilla.javascript.Scriptable; -import org.mozilla.javascript.WrappedException; -import org.ringojs.engine.RingoWrapFactory; - -public class SecureWrapFactory extends RingoWrapFactory { - - final static RingoSecurityManager secman; - - static { - SecurityManager sm = System.getSecurityManager(); - secman = (sm instanceof RingoSecurityManager) ? - (RingoSecurityManager) sm : null; - } - - private static void checkAccess(Class clazz) { - if (secman != null) { - try { - secman.checkJavaAccess(); - } catch (Exception x) { - throw new WrappedException(x); - } - } - } - - /** - * Wrap Java object as Scriptable instance to allow full access to its - * methods and fields from JavaScript. This implementation uses a custom wrappers - * that checks the SecurityManager for permission each time a Java member is - * accessed. - * - * @param cx the current Context for this thread - * @param scope the scope of the executing script - * @param javaObject the object to be wrapped - * @param staticType type hint. If security restrictions prevent to wrap - * object based on its class, staticType will be used instead. - * @return the wrapped value which shall not be null - */ - @Override - public Scriptable wrapAsJavaObject(Context cx, Scriptable scope, Object javaObject, Class staticType) { - return new SecureObjectWrapper(scope, javaObject, staticType); - } - - /** - * Wrap a Java class as Scriptable instance to allow access to its static - * members and fields and use as constructor from JavaScript. - *

- * Subclasses can override this method to provide custom wrappers for - * Java classes. - * - * @param cx the current Context for this thread - * @param scope the scope of the executing script - * @param javaClass the class to be wrapped - * @return the wrapped value which shall not be null - */ - @Override - public Scriptable wrapJavaClass(Context cx, Scriptable scope, Class javaClass) { - return new SecureClassWrapper(scope, javaClass); - } - - public static class SecureObjectWrapper extends NativeJavaObject { - - final Class clazz; - - public SecureObjectWrapper(Scriptable scope, Object javaObject, Class staticType) { - super(scope, javaObject, staticType); - clazz = javaObject.getClass(); - } - - @Override - public void put(String name, Scriptable start, Object value) { - checkAccess(clazz); - super.put(name, start, value); - } - - @Override - public Object get(String name, Scriptable start) { - checkAccess(clazz); - return super.get(name, start); - } - - @Override - public void delete(String name) { - checkAccess(clazz); - super.delete(name); - } - } - - public static class SecureClassWrapper extends NativeJavaClass { - - final Class clazz; - - public SecureClassWrapper(Scriptable scope, Class clazz) { - super(scope, clazz); - this.clazz = clazz; - } - - @Override - public Scriptable construct(Context cx, Scriptable scope, Object[] args) { - checkAccess(clazz); - return super.construct(cx, scope, args); - } - - @Override - public Object get(String name, Scriptable start) { - checkAccess(clazz); - return super.get(name, start); - } - - @Override - public Class getClassObject() { - checkAccess(clazz); - return super.getClassObject(); - } - - @Override - public void put(String name, Scriptable start, Object value) { - checkAccess(clazz); - super.put(name, start, value); - } - - @Override - public void delete(String name) { - checkAccess(clazz); - super.delete(name); - } - } -} - diff --git a/src/org/ringojs/tools/RingoRunner.java b/src/org/ringojs/tools/RingoRunner.java index 41e982868..9e0ba5505 100644 --- a/src/org/ringojs/tools/RingoRunner.java +++ b/src/org/ringojs/tools/RingoRunner.java @@ -26,8 +26,6 @@ import org.ringojs.repository.FileRepository; import org.ringojs.repository.Repository; import org.ringojs.repository.ZipRepository; -import org.ringojs.security.RingoSecurityManager; -import org.ringojs.security.SecureWrapFactory; import org.ringojs.util.StringUtils; import org.mozilla.javascript.Context; import org.mozilla.javascript.RhinoException; @@ -79,7 +77,6 @@ public class RingoRunner { {"m", "modules", "Add a directory to the module search path", "DIR"}, {"o", "optlevel", "Set Rhino optimization level (-1 to 9)", "OPT"}, {"p", "production", "Disable module reloading and warnings", ""}, - {"P", "policy", "Set java policy file and enable security manager", "URL"}, {"s", "silent", "Disable shell prompt and echo for piped stdin/stdout", ""}, {"V", "verbose", "Print java stack traces on errors", ""}, {"v", "version", "Print version number and exit", ""}, @@ -126,9 +123,6 @@ public void parseArgs(String[] args) throws Exception { String[] userModulePath = userModules.toArray(new String[userModules.size()]); config = new RingoConfig(home, userModulePath, systemModulePath); - boolean hasPolicy = System.getProperty("java.security.policy") != null; - config.setPolicyEnabled(hasPolicy); - config.setWrapFactory(hasPolicy ? new SecureWrapFactory() : new RingoWrapFactory()); config.setMainScript(scriptName); config.setArguments(scriptArgs); config.setOptLevel(optlevel); @@ -348,9 +342,6 @@ private void processOption(String option, String arg) { } else if ("modules".equals(option)) { Collections.addAll(userModules, StringUtils.split(arg, File.pathSeparator)); - } else if ("policy".equals(option)) { - System.setProperty("java.security.policy", arg); - System.setSecurityManager(new RingoSecurityManager()); } else if ("java-property".equals(option)) { if (arg.contains("=")) { String[] property = arg.split("=", 2); diff --git a/src/org/ringojs/tools/RingoShell.java b/src/org/ringojs/tools/RingoShell.java index ab3c7af30..40df72f32 100644 --- a/src/org/ringojs/tools/RingoShell.java +++ b/src/org/ringojs/tools/RingoShell.java @@ -74,11 +74,6 @@ public RingoShell(RhinoEngine engine, Path history, boolean silent) this.worker = engine.getWorker(); this.scope = engine.getShellScope(worker); this.silent = silent; - // FIXME give shell code a trusted code source in case security is on - if (config.isPolicyEnabled()) { - Repository modules = config.getRingoHome().getChildRepository("modules"); - codeSource = new CodeSource(modules.getUrl(), (CodeSigner[])null); - } } public void run() throws IOException { diff --git a/test/ringo/utils/http_test.js b/test/ringo/utils/http_test.js index 4e51d1e42..9519d6b63 100644 --- a/test/ringo/utils/http_test.js +++ b/test/ringo/utils/http_test.js @@ -1,4 +1,6 @@ +const fs = require("fs"); const assert = require("assert"); +const binary = require("binary"); const dates = require("ringo/utils/dates"); const strings = require("ringo/utils/strings"); const http = require("ringo/utils/http"); @@ -453,6 +455,40 @@ exports.testCanonicalRanges = function() { assert.deepEqual(http.canonicalRanges([[0,4], [90,99], [5,75], [100,199], [101,102]]), [[0, 75], [90,199]]); // overlapping }; +exports.testTempFileFactory = function() { + const ba = new binary.ByteArray([0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]); + const {TempFileFactory} = http; + + const data = { + name: "test", + filename: "uploadtest", + }; + + const stream = TempFileFactory(data, "UTF-8"); + try { + stream.write(ba); + stream.flush(); + } finally { + stream.close(); + assert.isTrue(stream.closed()); + } + + const checkStream = fs.openRaw(data.tempfile, "r"); + try { + const buff = new ByteArray(10); + assert.equal(checkStream.readInto(buff), 10); + + // Check the content + for (let i = 0; i < buff.length; i++) { + assert.equal(buff.charCodeAt(i), ba.charCodeAt(i)); + } + } finally { + checkStream.close(); + assert.isTrue(checkStream.closed()); + fs.remove(data.tempfile); + } +} + if (require.main === module) { require('system').exit(require("test").run(module.id)); }