Socket
Socket
Sign inDemoInstall

q-io

Package Overview
Dependencies
Maintainers
1
Versions
80
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

q-io - npm Package Compare versions

Comparing version 2.0.3 to 2.0.4

30

CHANGES.md
<!-- vim:ts=4:sts=4:sw=4:et:tw=60 -->
## 2.0.4
Streams:
- Added support for progress observers on readable stream `read` promise.
File system:
- Added support for `targetFs` argument to `copy` and `copyTree`.
- Fixed `canonical` by implementing in JavaScript based on `readLink`.
Depending on Node.js `realpath` was an error since realpath does not handle
path remainders.
- Fixed rerooted base file systems.
- Quietly added `rejoin` to file system, for reversing `split` properly.
Must consider finding a better narrative about `join`, `absolute`, `split`
and the distinguishing of relative and absolute paths in their split form,
as well as handling the issue of drive letters for Windows properly.
HTTP:
- Server request's now decode `pathInfo` on demand.
If the encoding is invalid, accessing `pathInfo` will throw an error.
This change makes it possible to receive requests with file names.
Using an accessor is questionable.
A future release might elect to pass `null` for path info if it does not
parse properly.
- File service now uses the configured `listDirectory` function if overridden.
- The client now supports requests with all of the same properteis as the
options that can be passed to the Node.js request function.
## 2.0.2

@@ -4,0 +34,0 @@

36

fs-base.js

@@ -7,2 +7,3 @@ "use strict";

// TODO function to return the Windows drive root
// TODO patternToRegExp

@@ -28,8 +29,3 @@ // TODO glob

BaseFs.prototype.split = function (path) {
var parts;
try {
parts = String(path).split(this.separatorsExpression);
} catch (exception) {
throw new Error("Cannot split " + (typeof path) + ", " + JSON.stringify(path));
}
var parts = String(path).split(this.separatorsExpression);
// this special case helps isAbsolute

@@ -45,2 +41,8 @@ // distinguish an empty path from an absolute path

BaseFs.prototype.rejoin = function (parts) {
if (parts.length === 1 && parts[0] === "")
return this.root;
return parts.join(this.separator);
};
/**

@@ -196,13 +198,2 @@ * Takes file system paths as variadic arguments and treats

/**
* @returns {String} the Unix root path or corresponding
* Windows drive for a given path.
*/
BaseFs.prototype.root = function (path) {
if (!this.isAbsolute(path))
path = require("./fs").absolute(path);
var parts = this.split(path);
return this.join(parts[0], "");
};
/**
* @returns {String} the parent directory of the given path.

@@ -237,13 +228,2 @@ */

BaseFs.prototype.relative = function (source, target) {
var self = this;
return this.isDirectory(source).then(function (isDirectory) {
if (isDirectory) {
return self.relativeFromDirectory(source, target);
} else {
return self.relativeFromFile(source, target);
}
});
};
BaseFs.prototype.relativeFromFile = function (source, target) {

@@ -250,0 +230,0 @@ source = this.absolute(source);

@@ -120,2 +120,3 @@ "use strict";

// TODO support targetFs
CommonFs.prototype.move = function (source, target) {

@@ -136,7 +137,8 @@ var self = this;

CommonFs.prototype.copy = function (source, target) {
var self = this;
CommonFs.prototype.copy = function (source, target, targetFs) {
var sourceFs = this;
targetFs = targetFs || sourceFs;
return Q([
self.open(source, {flags: "rb"}),
self.open(target, {flags: "wb"})
sourceFs.open(source, {flags: "rb"}),
targetFs.open(target, {flags: "wb"})
]).spread(function (reader, writer) {

@@ -154,14 +156,16 @@ return reader.forEach(function (block) {

CommonFs.prototype.copyTree = function (source, target) {
var self = this;
return self.stat(source).then(function (stat) {
CommonFs.prototype.copyTree = function (source, target, targetFs) {
var sourceFs = this;
targetFs = targetFs || sourceFs;
return sourceFs.statLink(source).then(function (stat) {
if (stat.isFile()) {
return self.copy(source, target);
return sourceFs.copy(source, target, targetFs);
} else if (stat.isDirectory()) {
return self.exists(target).then(function (targetExists) {
var copySubTree = self.list(source).then(function (list) {
return sourceFs.exists(target).then(function (targetExists) {
var copySubTree = sourceFs.list(source).then(function (list) {
return Q.all(list.map(function (child) {
return self.copyTree(
self.join(source, child),
self.join(target, child)
return sourceFs.copyTree(
sourceFs.join(source, child),
targetFs.join(target, child),
targetFs
);

@@ -173,3 +177,3 @@ }));

} else {
return self.makeDirectory(target).then(function () {
return targetFs.makeDirectory(target).then(function () {
return copySubTree;

@@ -180,5 +184,16 @@ });

} else if (stat.isSymbolicLink()) {
// TODO copy the link and type with readPath (but what about
// Windows junction type?)
return self.symbolicCopy(source, target);
// Convert symbolic links to relative links and replicate on the
// target file system.
return sourceFs.isDirectory(source)
.then(function (isDirectory) {
var relative, type;
if (isDirectory) {
relative = sourceFs.relativeFromDirectory(source, target);
type = "directory";
} else {
relative = sourceFs.relativeFromFile(source, target);
type = "file";
}
return targetFs.symbolicLink(target, relative, type);
})
}

@@ -285,2 +300,45 @@ });

CommonFs.prototype.relative = function (source, target) {
var self = this;
return this.isDirectory(source).then(function (isDirectory) {
if (isDirectory) {
return self.relativeFromDirectory(source, target);
} else {
return self.relativeFromFile(source, target);
}
});
};
CommonFs.prototype.canonical = function (path) {
var self = this;
path = self.absolute(path);
var input = self.split(path);
return this._canonicalWalk(input, 1, this.root);
};
CommonFs.prototype._canonicalWalk = function (parts, index, via) {
if (index >= parts.length) {
return via;
}
var self = this;
var path = self.join(via, parts[index]);
return this.statLink(path)
.then(function (stat) {
if (stat.isSymbolicLink()) {
return self.readLink(path)
.then(function (relative) {
var absolute = self.join(self.directory(path), relative);
return self.canonical(absolute)
.then(function (canonical) {
return self._canonicalWalk(parts, index + 1, canonical);
});
});
} else {
return self._canonicalWalk(parts, index + 1, self.join(via, parts[index]));
}
}, function (error) {
return self.join(via, parts.slice(index).join(self.separator));
});
};
CommonFs.prototype.exists = function (path) {

@@ -319,3 +377,4 @@ return this.stat(path).then(returnTrue, returnFalse);

path = path || this.root;
return require("./fs-root")(self, path);
var RootFs = require("./fs-root");
return new RootFs(self, path);
}

@@ -357,3 +416,4 @@

return done.then(function () {
return require("./fs-mock")(tree);
var MockFs = require("./fs-mock");
return new MockFs(tree);
});

@@ -363,3 +423,4 @@ };

CommonFs.prototype.mock = function (path) {
return require("./fs-mock").mock(this, path);
var MockFs = require("./fs-mock");
return MockFs.mock(this, path);
};

@@ -366,0 +427,0 @@

@@ -336,15 +336,2 @@ "use strict";

NodeFs.prototype.canonical = function (path) {
var result = Q.defer();
FS.realpath(path, function (error, canonicalPath) {
if (error) {
error.message = "Can't get canonical path of " + JSON.stringify(path) + " by way of C realpath: " + error.message;
result.reject(error);
} else {
result.resolve(canonicalPath);
}
});
return result.promise;
};
NodeFs.prototype.readLink = function (path) {

@@ -351,0 +338,0 @@ var result = Q.defer();

@@ -335,10 +335,2 @@ "use strict";

MockFs.prototype.canonical = function (path) {
var self = this;
return Q.try(function () {
path = self.absolute(path);
return self._root._canonical(path);
});
};
MockFs.mock = mock;

@@ -345,0 +337,0 @@ function mock(fs, root) {

@@ -16,52 +16,36 @@ "use strict";

function attenuate(path) {
var workingDirectory = inner.root;
// the machinations of projecting a path inside a
// subroot
var actual;
// if it's absolute, we want the path relative to
// the root of the inner file system
if (outer.isAbsolute(path)) {
actual = outer.relativeFromDirectory(outer.root, path);
} else {
actual = path;
}
// we join the path onto the root of the inner file
// system so that parent references from the root
// return to the root, emulating standard unix
// behavior
actual = outer.join(outer.root, actual);
// then we reconstruct the path relative to the
// inner root
actual = outer.relativeFromDirectory(outer.root, actual);
// and rejoin it on the outer root
actual = outer.join(root, actual);
var IN = actual;
// and find the corresponding real path
return outer.canonical(actual)
.then(function (actual) {
return actual;
}, function () {
return actual;
}).then(function (actual) {
// and verify that the outer canonical path is
// actually inside the inner canonical path, to
// prevent break-outs
if (outer.contains(root, actual)) {
return {
"inner": outer.join(outer.root, outer.relativeFromDirectory(root, actual)),
"outer": actual
};
} else {
var error = new Error("Can't find: " + JSON.stringify(path));
delete error.stack;
throw error;
}
});
}
root = outer.canonical(root);
function workingDirectory() {
return outer.root;
function attenuate(innerPath) {
return root.then(function (root) {
// Construct an inner path that is relative to the emulated root
innerPath = inner.absolute(innerPath);
innerPath = inner.relativeFromDirectory(inner.root, innerPath);
var outerPath = outer.join(root, innerPath);
return outer.canonical(outerPath)
.then(function (outerPath) {
if (outer.contains(root, outerPath)) {
return {
"inner": innerPath,
"outer": outerPath
};
} else {
var error = new Error("Can't find: " + JSON.stringify(path));
// XXX TODO delete error.stack;
throw error;
}
})
})
}
inner.workingDirectory = function () {
return inner.root;
};
inner.list = function (path) {

@@ -99,7 +83,7 @@ return attenuate(path).then(function (path) {

inner.canonical = function (path) {
inner.readLink = function (path) {
return attenuate(path).then(function (path) {
return path.inner;
return outer.readLink(path.outer);
}).then(null, function (reason) {
throw new Error("Can't find canonical of " + JSON.stringify(path));
throw new Error("Can't read link at " + JSON.stringify(path));
});

@@ -124,7 +108,4 @@ };

return outer.canonical(root).then(function (_root) {
root = _root;
return inner;
});
return inner;
}

@@ -213,3 +213,3 @@ "use strict";

if (response.directory !== void 0) {
return exports.listDirectory(request, response);
return listDirectory(request, response);
} else {

@@ -216,0 +216,0 @@ return response;

@@ -36,3 +36,3 @@ "use strict";

var server = HTTP.createServer(function (_request, _response) {
var request = exports.ServerRequest(_request);
var request = new exports.ServerRequest(_request);
return respond.call(void 0, request)

@@ -138,18 +138,17 @@ .then(function (response) {

exports.ServerRequest = function (_request, ssl) {
var request = Object.create(_request);
/*** {Array} HTTP version. (JSGI) */
request.version = _request.httpVersion.split(".").map(Math.floor);
this.version = _request.httpVersion.split(".").map(Math.floor);
/*** {String} HTTP method, e.g., `"GET"` (JSGI) */
request.method = _request.method;
this.method = _request.method;
/*** {String} path, starting with `"/"` */
request.path = _request.url;
this.path = _request.url;
/*** {String} pathInfo, starting with `"/"`, the
* portion of the path that has not yet
* been routed (JSGI) */
request.pathInfo = URL.parse(_request.url).pathname;
this._pathInfo = null;
/*** {String} scriptName, the portion of the path that
* has already been routed (JSGI) */
request.scriptName = "";
this.scriptName = "";
/*** {String} (JSGI) */
request.scheme = "http";
this.scheme = "http";

@@ -159,37 +158,48 @@ var address = _request.connection.address();

if (_request.headers.host) {
request.hostname = _request.headers.host.split(":")[0];
this.hostname = _request.headers.host.split(":")[0];
} else {
request.hostname = address.address;
this.hostname = address.address;
}
/*** {String} host */
request.port = address.port;
var defaultPort = request.port === (ssl ? 443 : 80);
request.host = request.hostname + (defaultPort ? "" : ":" + request.port);
this.port = address.port;
var defaultPort = this.port === (ssl ? 443 : 80);
this.host = this.hostname + (defaultPort ? "" : ":" + this.port);
var socket = _request.socket;
/*** {String} */
request.remoteHost = socket.remoteAddress;
this.remoteHost = socket.remoteAddress;
/*** {Number} */
request.remotePort = socket.remotePort;
this.remotePort = socket.remotePort;
/*** {String} url */
request.url = URL.format({
protocol: request.scheme,
this.url = URL.format({
protocol: this.scheme,
host: _request.headers.host,
port: request.port === (ssl ? 443 : 80) ? null : request.port,
path: request.path
port: this.port === (ssl ? 443 : 80) ? null : this.port,
path: this.path
});
/*** A Q IO asynchronous text reader */
request.body = NodeReader(_request);
this.body = NodeReader(_request, null, +_request.headers["content-length"]);
/*** {Object} HTTP headers (JSGI)*/
request.headers = _request.headers;
this.headers = _request.headers;
/*** The underlying Node request */
request.node = _request;
request.nodeRequest = _request; // Deprecated
/*** The underlying Node TCP connection */
request.nodeConnection = _request.connection;
return request;
this.node = _request;
};
Object.defineProperty(exports.ServerRequest.prototype, "pathInfo", {
get: function () {
// Postpone this until the server requests it because
// decodeURIComponent may throw an error if the path is not valid.
// If we throw while making a server request, it will crash the
// server and be uncatchable.
if (this._pathInfo === null) {
this._pathInfo = decodeURIComponent(URL.parse(this.url).pathname);
}
return this._pathInfo;
},
set: function (pathInfo) {
this._pathInfo = pathInfo;
}
});
exports.ServerResponse = function (_response, ssl) {

@@ -216,11 +226,3 @@ var response = Object.create(_response);

request.path = (url.pathname || "") + (url.search || "");
if (url.auth) {
request.auth = url.auth;
if (!request.headers["authorization"]) {
request.headers["authorization"] = (
"Basic " + new Buffer(url.auth)
.toString("base64")
);
}
}
request.auth = url.auth || void 0;
}

@@ -274,7 +276,10 @@ request.host = request.host || request.headers.host;

var requestOptions = {
"host": request.hostname, // Node.js quirk
"port": request.port || (request.ssl ? 443 : 80),
"path": request.path || "/",
"method": request.method || "GET",
"headers": request.headers
hostname: request.hostname,
port: request.port || (request.ssl ? 443 : 80),
localAddress: request.localAddress,
socketPath: request.socketPath,
method: request.method,
path: request.path,
headers: request.headers,
auth: request.auth // Generates the appropriate header
};

@@ -348,5 +353,3 @@

response.node = _response;
response.nodeResponse = _response; // Deprecated
response.nodeConnection = _response.connection; // Deprecated
response.body = NodeReader(_response, charset);
response.body = NodeReader(_response, charset, +response.headers["content-length"]);
return response;

@@ -353,0 +356,0 @@ };

@@ -11,3 +11,3 @@

module.exports = Reader;
function Reader(_stream, charset) {
function Reader(_stream, charset, length) {
if (charset && _stream.setEncoding) // TODO complain about inconsistency

@@ -17,2 +17,3 @@ _stream.setEncoding(charset);

var window = 0;
var index = 0;
var drained = true;

@@ -24,3 +25,3 @@ var queue = new Queue();

if (window > 0) {
tick();
flush();
}

@@ -32,17 +33,7 @@ return queue.get();

// this triggers a switch in StreamReader#read
// this triggers a switch in `read`
output.charset = charset;
// also used in `read` for progress estimates
output.length = length;
function tick() {
if (window > 0 && !drained) {
var chunk = _stream.read();
if (chunk === null) {
drained = true;
return;
}
window--;
output.yield(chunk);
}
}
_stream.on("error", function (error) {

@@ -56,12 +47,18 @@ output.throw(error);

_stream.on("readable", function () {
drained = false;
flush();
});
if (supportsReadable) {
_stream.on("readable", function () {
drained = false;
tick();
});
} else {
_stream.on("data", function (chunk) {
output.yield(chunk);
});
function flush() {
if (window > 0 && !drained) {
var chunk = _stream.read();
if (chunk === null) {
drained = true;
return;
}
window--;
output.yield(chunk, index);
index += chunk.length;
}
}

@@ -68,0 +65,0 @@

{
"name": "q-io",
"version": "2.0.3",
"version": "2.0.4",
"publishConfig": {

@@ -5,0 +5,0 @@ "tag": "future"

@@ -226,12 +226,23 @@ "use strict";

var self = this;
return this.forEach(function (chunk) {
var deferred = Q.defer();
var index = 0;
var start = Date.now();
this.forEach(function (chunk) {
chunks.push(chunk);
})
.then(function () {
index += chunk.length;
if (this.length) {
var now = Date.now(); // milliseconds
var speed = index / (now - start); // bytes per milliseconds
var remaining = this.length - index; // bytes
deferred.setEstimate(now + remaining / speed); // milliseconds
}
}, this)
.done(function () {
if (self.charset) {
return chunks.join("");
deferred.resolve(chunks.join(""));
} else {
return Buffer.concat(chunks);
deferred.resolve(Buffer.concat(chunks));
}
});
}, deferred.reject);
return deferred.promise;
}

@@ -238,0 +249,0 @@

@@ -8,2 +8,3 @@ "use strict";

describe("copyTree", function () {
it("should copy a tree", function () {

@@ -55,3 +56,45 @@

it("copies trees between systems", function () {
var mock = Mock({
"a/b": {
"c": {
"d": 66,
"e": 99
}
}
});
var mock2 = Mock();
return Q.try(function () {
return mock.copyTree("a/b", "f", mock2);
})
.then(function () {
return Q.all([
mock2.isDirectory("f"),
mock2.exists("f/c"),
mock2.isFile("f/c/d"),
mock2.read("f/c/e")
])
})
.then(function (existence) {
expect(existence.every(Boolean)).toBe(true);
})
.then(function () {
return mock2.listTree();
})
.then(function (list) {
expect(list).toEqual([
".",
"f",
FS.normal("f/c"),
FS.normal("f/c/d"),
FS.normal("f/c/e")
]);
})
});
});

@@ -19,3 +19,3 @@ "use strict";

return chroot.invoke("listTree")
return chroot.listTree()
.then(function (list) {

@@ -22,0 +22,0 @@ expect(list).toEqual([

@@ -6,7 +6,5 @@ var FS = require("../../fs");

it("should still have makeDirectory()", function() {
return FS.reroot("/")
.then(function(fs) {
expect(fs.makeTree instanceof Function).toBe(true);
expect(fs.makeDirectory instanceof Function).toBe(true);
});
var fs = FS.reroot("/")
expect(fs.makeTree instanceof Function).toBe(true);
expect(fs.makeDirectory instanceof Function).toBe(true);
});

@@ -27,4 +25,3 @@

}).then(function() {
return FS.reroot(tmpdir);
}).then(function(fs) {
var fs = FS.reroot(tmpdir);
return fs.makeDirectory('/foo');

@@ -31,0 +28,0 @@ }).then(function() {

@@ -27,3 +27,4 @@

"foo": Apps.Branch({
"bar": new Apps.Chain()
"bar": (
new Apps.Chain()
.use(Apps.Cap)

@@ -34,2 +35,3 @@ .use(function () {

.end()
)
})

@@ -42,3 +44,3 @@ })

return Q.when(server1.listen(0))
return server1.listen(0)
.then(function (server1) {

@@ -67,3 +69,4 @@ var port = server1.node.address().port;

return Http.read({
url: "http://127.0.0.1:" + port + "/bar",
port: port,
path: "/bar",
charset: "utf-8"

@@ -70,0 +73,0 @@ })

@@ -93,8 +93,2 @@

it('should set correct HTTP Basic authentication headers when username and password are passed in the URL',function(){
request = HTTP.normalizeRequest('http://username:password@www.google.com/');
expect(request.auth).toBe('username:password');
expect(request.headers.authorization).toBe('Basic dXNlcm5hbWU6cGFzc3dvcmQ=');
});
it('should successfully access resources that require HTTP Basic authentication when using the username:password@host.com URL syntax', function(){

@@ -101,0 +95,0 @@ // This tries to access a public resource, see http://test.webdav.org/

@@ -15,3 +15,4 @@ var normalizeRequest = require("../../http").normalizeRequest;

path: "/",
headers: { host: "google.com" }
headers: { host: "google.com" },
auth: void 0
});

@@ -30,3 +31,4 @@ });

path: "/search?q=q-io",
headers: { host: "google.com" }
headers: { host: "google.com" },
auth: void 0
});

@@ -45,3 +47,4 @@ });

path: "/search?q=q-io",
headers: { host: "google.com:8080" }
headers: { host: "google.com:8080" },
auth: void 0
});

@@ -60,3 +63,4 @@ });

path: "/",
headers: { host: "google.com" }
headers: { host: "google.com" },
auth: void 0
});

@@ -75,3 +79,4 @@ });

path: "/",
headers: { host: "google.com:8080" }
headers: { host: "google.com:8080" },
auth: void 0
});

@@ -90,3 +95,4 @@ });

path: "/search?q=q-io",
headers: { host: "google.com" }
headers: { host: "google.com" },
auth: void 0
});

@@ -108,3 +114,4 @@ });

path: "/search?q=q-io",
headers: { host: "google.com" }
headers: { host: "google.com" },
auth: void 0
});

@@ -126,3 +133,4 @@ });

path: "/search?q=q-io",
headers: { host: "yahoo.com" }
headers: { host: "yahoo.com" },
auth: void 0
});

@@ -145,3 +153,4 @@ });

path: "/search?q=q-io",
headers: { host: "google.com" }
headers: { host: "google.com" },
auth: void 0
});

@@ -163,3 +172,4 @@ });

path: "/search?q=q-io",
headers: { host: "google.com" }
headers: { host: "google.com" },
auth: void 0
});

@@ -181,3 +191,4 @@ });

path: "/search?q=q-io",
headers: { host: "google.com" }
headers: { host: "google.com" },
auth: void 0
});

@@ -196,3 +207,4 @@ });

path: "/",
headers: { host: "google.com" }
headers: { host: "google.com" },
auth: void 0
});

@@ -212,3 +224,4 @@ });

path: "/",
headers: { host: "yahoo.com" }
headers: { host: "yahoo.com" },
auth: void 0
});

@@ -215,0 +228,0 @@ });

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc