Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
37c97b1
test: add test-fs-read-constructor-errors test
bacriom Dec 27, 2017
d7326b2
test: add test-fs-readSync-constructor-errors test
bacriom Dec 27, 2017
bd3aa3e
test: add test-fs-read-constructor-errors test
bacriom Dec 27, 2017
5e59b4f
test: add test-fs-readSync-constructor-errors test
bacriom Dec 27, 2017
9ec700b
fs: validate path in fs.readFile
joyeecheung Dec 24, 2017
71396a2
fs: validate path in fs.exists{Sync}
joyeecheung Dec 24, 2017
c0e9cde
inspector: make Coverity happy
Dec 13, 2017
b0dd43c
tools: fix AttributeError: __exit__ on Python 2.6
dkasyanov Dec 13, 2017
6c0da34
http: add rawPacket in err of `clientError` event
XadillaX Dec 14, 2017
9e5ccf0
perf_hooks: refactor internals
jasnell Dec 21, 2017
46510f5
tls: fix SNICallback without .server option
addaleax Dec 23, 2017
b343671
test: refactor test-tls-securepair-fiftharg
addaleax Dec 23, 2017
cb3de88
crypto: add ocsp_request ClientHelloParser::Reset
danbev Dec 11, 2017
df30fd5
buffer: optimize readDouble and readFloat methods
bnoordhuis Dec 20, 2017
83e5215
async_hooks: use typed array stack as fast path
addaleax Dec 19, 2017
24c71fb
test: make test-tls-invoke-queued use public API
addaleax Dec 25, 2017
c569727
src: expose uv.errmap to binding
joyeecheung Dec 25, 2017
6ca10de
fs: simplify the error context collection in C++
joyeecheung Nov 27, 2017
9f122e3
fs: throw fs.close errors in JS
joyeecheung Nov 29, 2017
d3ac18a
lib: migrate _http_outgoing.js's remaining errors
b0yfriend Dec 23, 2017
c560ae4
test: add test-fs-read-constructor-errors test
bacriom Dec 27, 2017
bfae5ac
test: add test-fs-read-sync-constructor-errors test
bacriom Dec 27, 2017
25475ad
Merge remote-tracking branch 'remotes/origin/bacriom-branch' into bac…
bacriom Dec 27, 2017
047b2d7
Update test-fs-read-constructor-errors.js
bacriom Dec 27, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions benchmark/buffers/buffer-read-float.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use strict';
const common = require('../common.js');

const bench = common.createBenchmark(main, {
noAssert: ['false', 'true'],
type: ['Double', 'Float'],
endian: ['BE', 'LE'],
value: ['zero', 'big', 'small', 'inf', 'nan'],
millions: [1]
});

function main(conf) {
const noAssert = conf.noAssert === 'true';
const len = +conf.millions * 1e6;
const buff = Buffer.alloc(8);
const type = conf.type || 'Double';
const endian = conf.endian;
const fn = `read${type}${endian}`;
const values = {
Double: {
zero: 0,
big: 2 ** 1023,
small: 2 ** -1074,
inf: Infinity,
nan: NaN,
},
Float: {
zero: 0,
big: 2 ** 127,
small: 2 ** -149,
inf: Infinity,
nan: NaN,
},
};
const value = values[type][conf.value];

buff[`write${type}${endian}`](value, 0, noAssert);
const testFunction = new Function('buff', `
for (var i = 0; i !== ${len}; i++) {
buff.${fn}(0, ${JSON.stringify(noAssert)});
}
`);
bench.start();
testFunction(buff);
bench.end(len / 1e6);
}
11 changes: 11 additions & 0 deletions doc/api/http.md
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,11 @@ changes:
description: The default action of calling `.destroy()` on the `socket`
will no longer take place if there are listeners attached
for `clientError`.
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/17672
description: The rawPacket is the current buffer that just parsed. Adding
this buffer to the error object of clientError event is to make
it possible that developers can log the broken packet.
-->

* `exception` {Error}
Expand Down Expand Up @@ -765,6 +770,12 @@ object, so any HTTP response sent, including response headers and payload,
*must* be written directly to the `socket` object. Care must be taken to
ensure the response is a properly formatted HTTP response message.

`err` is an instance of `Error` with two extra columns:

+ `bytesParsed`: the bytes count of request packet that Node.js may have parsed
correctly;
+ `rawPacket`: the raw packet of current request.

### Event: 'close'
<!-- YAML
added: v0.1.4
Expand Down
4 changes: 2 additions & 2 deletions lib/_http_outgoing.js
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ OutgoingMessage.prototype.write = function write(chunk, encoding, callback) {

function write_(msg, chunk, encoding, callback, fromEnd) {
if (msg.finished) {
var err = new Error('write after end');
const err = new errors.Error('ERR_STREAM_WRITE_AFTER_END');
nextTick(msg.socket && msg.socket[async_id_symbol],
writeAfterEndNT.bind(msg),
err,
Expand Down Expand Up @@ -880,7 +880,7 @@ OutgoingMessage.prototype.flush = internalUtil.deprecate(function() {

OutgoingMessage.prototype.pipe = function pipe() {
// OutgoingMessage should be write-only. Piping from it is disabled.
this.emit('error', new Error('Cannot pipe, not readable'));
this.emit('error', new errors.Error('ERR_STREAM_CANNOT_PIPE'));
};

module.exports = {
Expand Down
1 change: 1 addition & 0 deletions lib/_http_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ function onParserExecuteCommon(server, socket, parser, state, ret, d) {
resetSocketTimeout(server, socket, state);

if (ret instanceof Error) {
ret.rawPacket = d || parser.getCurrentBuffer();
debug('parse error', ret);
socketOnError.call(socket, ret);
} else if (parser.incoming && parser.incoming.upgrade) {
Expand Down
3 changes: 1 addition & 2 deletions lib/_tls_wrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -505,9 +505,8 @@ TLSSocket.prototype._init = function(socket, wrap) {
if (process.features.tls_sni &&
options.isServer &&
options.SNICallback &&
options.server &&
(options.SNICallback !== SNICallback ||
options.server._contexts.length)) {
(options.server && options.server._contexts.length))) {
assert(typeof options.SNICallback === 'function');
this._SNICallback = options.SNICallback;
ssl.enableCertCb();
Expand Down
89 changes: 65 additions & 24 deletions lib/buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ const {
indexOfBuffer,
indexOfNumber,
indexOfString,
readDoubleBE: _readDoubleBE,
readDoubleLE: _readDoubleLE,
readFloatBE: _readFloatBE,
readFloatLE: _readFloatLE,
swap16: _swap16,
swap32: _swap32,
swap64: _swap64,
Expand Down Expand Up @@ -1201,35 +1197,80 @@ Buffer.prototype.readInt32BE = function readInt32BE(offset, noAssert) {
};


Buffer.prototype.readFloatLE = function readFloatLE(offset, noAssert) {
offset = offset >>> 0;
if (!noAssert)
checkOffset(offset, 4, this.length);
return _readFloatLE(this, offset);
// For the casual reader who has not at the current time memorized the
// IEEE-754 standard in full detail: floating point numbers consist of
// a fraction, an exponent and a sign bit: 23+8+1 bits for single precision
// numbers and 52+11+1 bits for double precision numbers.
//
// A zero exponent is either a positive or negative zero, if the fraction
// is zero, or a denormalized number when it is non-zero. Multiplying the
// fraction by the smallest possible denormal yields the denormalized number.
//
// An all-bits-one exponent is either a positive or negative infinity, if
// the fraction is zero, or NaN when it is non-zero. The standard allows
// both quiet and signalling NaNs but since NaN is a canonical value in
// JavaScript, we cannot (and do not) distinguish between the two.
//
// Other exponents are regular numbers and are computed by subtracting the bias
// from the exponent (127 for single precision, 1023 for double precision),
// yielding an exponent in the ranges -126-127 and -1022-1024 respectively.
//
// Of interest is that the fraction of a normal number has an extra bit of
// precision that is not stored but is reconstructed by adding one after
// multiplying the fraction with the result of 2**-bits_in_fraction.


function toDouble(x0, x1) {
const frac = x0 + 0x100000000 * (x1 & 0xFFFFF);
const expt = (x1 >>> 20) & 2047;
const sign = (x1 >>> 31) ? -1 : 1;
if (expt === 0) {
if (frac === 0) return sign * 0;
return sign * frac * 2 ** -1074;
} else if (expt === 2047) {
if (frac === 0) return sign * Infinity;
return NaN;
}
return sign * 2 ** (expt - 1023) * (1 + frac * 2 ** -52);
}


function toFloat(x) {
const frac = x & 0x7FFFFF;
const expt = (x >>> 23) & 255;
const sign = (x >>> 31) ? -1 : 1;
if (expt === 0) {
if (frac === 0) return sign * 0;
return sign * frac * 2 ** -149;
} else if (expt === 255) {
if (frac === 0) return sign * Infinity;
return NaN;
}
return sign * 2 ** (expt - 127) * (1 + frac * 2 ** -23);
}


Buffer.prototype.readDoubleBE = function(offset, noAssert) {
const x1 = this.readUInt32BE(offset + 0, noAssert);
const x0 = this.readUInt32BE(offset + 4, noAssert);
return toDouble(x0, x1);
};


Buffer.prototype.readFloatBE = function readFloatBE(offset, noAssert) {
offset = offset >>> 0;
if (!noAssert)
checkOffset(offset, 4, this.length);
return _readFloatBE(this, offset);
Buffer.prototype.readDoubleLE = function(offset, noAssert) {
const x0 = this.readUInt32LE(offset + 0, noAssert);
const x1 = this.readUInt32LE(offset + 4, noAssert);
return toDouble(x0, x1);
};


Buffer.prototype.readDoubleLE = function readDoubleLE(offset, noAssert) {
offset = offset >>> 0;
if (!noAssert)
checkOffset(offset, 8, this.length);
return _readDoubleLE(this, offset);
Buffer.prototype.readFloatBE = function(offset, noAssert) {
return toFloat(this.readUInt32BE(offset, noAssert));
};


Buffer.prototype.readDoubleBE = function readDoubleBE(offset, noAssert) {
offset = offset >>> 0;
if (!noAssert)
checkOffset(offset, 8, this.length);
return _readDoubleBE(this, offset);
Buffer.prototype.readFloatLE = function(offset, noAssert) {
return toFloat(this.readUInt32LE(offset, noAssert));
};


Expand Down
20 changes: 17 additions & 3 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -329,17 +329,21 @@ fs.accessSync = function(path, mode) {
else
mode = mode | 0;

const ctx = {};
const ctx = { path };
binding.access(pathModule.toNamespacedPath(path), mode, undefined, ctx);

if (ctx.code !== undefined) {
if (ctx.errno !== undefined) {
throw new errors.uvException(ctx);
}
};

fs.exists = function(path, callback) {
if (handleError((path = getPathFromURL(path)), cb))
return;
if (typeof path !== 'string' && !(path instanceof Buffer)) {
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'path',
['string', 'Buffer', 'URL']);
}
if (!nullCheck(path, cb)) return;
var req = new FSReqWrap();
req.oncomplete = cb;
Expand All @@ -361,6 +365,9 @@ Object.defineProperty(fs.exists, internalUtil.promisify.custom, {
fs.existsSync = function(path) {
try {
handleError((path = getPathFromURL(path)));
if (typeof path !== 'string' && !(path instanceof Buffer)) {
return false;
}
nullCheck(path);
binding.stat(pathModule.toNamespacedPath(path));
return true;
Expand Down Expand Up @@ -389,6 +396,9 @@ fs.readFile = function(path, options, callback) {
req.oncomplete(null, path);
});
return;
} else if (typeof path !== 'string' && !(path instanceof Buffer)) {
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'path',
['string', 'Buffer', 'URL']);
}

binding.open(pathModule.toNamespacedPath(path),
Expand Down Expand Up @@ -651,7 +661,11 @@ fs.closeSync = function(fd) {
if (!isUint32(fd))
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'fd', 'integer');

return binding.close(fd);
const ctx = {};
binding.close(fd, undefined, ctx);
if (ctx.errno !== undefined) {
throw new errors.uvException(ctx);
}
};

function modeNum(m, def) {
Expand Down
44 changes: 41 additions & 3 deletions lib/internal/async_hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@ const async_wrap = process.binding('async_wrap');
* retrieving the triggerAsyncId value is passing directly to the
* constructor -> value set in kDefaultTriggerAsyncId -> executionAsyncId of
* the current resource.
*
* async_ids_fast_stack is a Float64Array that contains part of the async ID
* stack. Each pushAsyncIds() call adds two doubles to it, and each
* popAsyncIds() call removes two doubles from it.
* It has a fixed size, so if that is exceeded, calls to the native
* side are used instead in pushAsyncIds() and popAsyncIds().
*/
const { async_hook_fields, async_id_fields } = async_wrap;
// Store the pair executionAsyncId and triggerAsyncId in a std::stack on
// Environment::AsyncHooks::ids_stack_ tracks the resource responsible for the
// current execution stack. This is unwound as each resource exits. In the case
// of a fatal exception this stack is emptied after calling each hook's after()
// callback.
const { pushAsyncIds, popAsyncIds } = async_wrap;
const { pushAsyncIds: pushAsyncIds_, popAsyncIds: popAsyncIds_ } = async_wrap;
// For performance reasons, only track Proimses when a hook is enabled.
const { enablePromiseHook, disablePromiseHook } = async_wrap;
// Properties in active_hooks are used to keep track of the set of hooks being
Expand Down Expand Up @@ -60,8 +66,8 @@ const active_hooks = {
// async execution. These are tracked so if the user didn't include callbacks
// for a given step, that step can bail out early.
const { kInit, kBefore, kAfter, kDestroy, kPromiseResolve,
kCheck, kExecutionAsyncId, kAsyncIdCounter,
kDefaultTriggerAsyncId } = async_wrap.constants;
kCheck, kExecutionAsyncId, kAsyncIdCounter, kTriggerAsyncId,
kDefaultTriggerAsyncId, kStackLength } = async_wrap.constants;

// Used in AsyncHook and AsyncResource.
const init_symbol = Symbol('init');
Expand Down Expand Up @@ -329,6 +335,38 @@ function emitDestroyScript(asyncId) {
}


// This is the equivalent of the native push_async_ids() call.
function pushAsyncIds(asyncId, triggerAsyncId) {
const offset = async_hook_fields[kStackLength];
if (offset * 2 >= async_wrap.async_ids_stack.length)
return pushAsyncIds_(asyncId, triggerAsyncId);
async_wrap.async_ids_stack[offset * 2] = async_id_fields[kExecutionAsyncId];
async_wrap.async_ids_stack[offset * 2 + 1] = async_id_fields[kTriggerAsyncId];
async_hook_fields[kStackLength]++;
async_id_fields[kExecutionAsyncId] = asyncId;
async_id_fields[kTriggerAsyncId] = triggerAsyncId;
}


// This is the equivalent of the native pop_async_ids() call.
function popAsyncIds(asyncId) {
if (async_hook_fields[kStackLength] === 0) return false;
const stackLength = async_hook_fields[kStackLength];

if (async_hook_fields[kCheck] > 0 &&
async_id_fields[kExecutionAsyncId] !== asyncId) {
// Do the same thing as the native code (i.e. crash hard).
return popAsyncIds_(asyncId);
}

const offset = stackLength - 1;
async_id_fields[kExecutionAsyncId] = async_wrap.async_ids_stack[2 * offset];
async_id_fields[kTriggerAsyncId] = async_wrap.async_ids_stack[2 * offset + 1];
async_hook_fields[kStackLength] = offset;
return offset > 0;
}


module.exports = {
// Private API
getHookArrays,
Expand Down
6 changes: 3 additions & 3 deletions lib/internal/bootstrap_node.js
Original file line number Diff line number Diff line change
Expand Up @@ -367,9 +367,9 @@
// Arrays containing hook flags and ids for async_hook calls.
const { async_hook_fields, async_id_fields } = async_wrap;
// Internal functions needed to manipulate the stack.
const { clearAsyncIdStack, asyncIdStackSize } = async_wrap;
const { clearAsyncIdStack } = async_wrap;
const { kAfter, kExecutionAsyncId,
kDefaultTriggerAsyncId } = async_wrap.constants;
kDefaultTriggerAsyncId, kStackLength } = async_wrap.constants;

process._fatalException = function(er) {
var caught;
Expand Down Expand Up @@ -407,7 +407,7 @@
do {
NativeModule.require('internal/async_hooks').emitAfter(
async_id_fields[kExecutionAsyncId]);
} while (asyncIdStackSize() > 0);
} while (async_hook_fields[kStackLength] > 0);
// Or completely empty the id stack.
} else {
clearAsyncIdStack();
Expand Down
Loading