From f1fa7566810e1ba7248f0aeab1a291378152f6b4 Mon Sep 17 00:00:00 2001 From: isaacs Date: Thu, 28 Mar 2013 14:39:52 -0700 Subject: [PATCH 01/26] blog: Update linux binary tarball shasums I just accidentally the binary release. --- doc/blog/release/v0.10.2.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/blog/release/v0.10.2.md b/doc/blog/release/v0.10.2.md index 92e834dfb62..67957dd547f 100644 --- a/doc/blog/release/v0.10.2.md +++ b/doc/blog/release/v0.10.2.md @@ -68,8 +68,8 @@ Shasums: ``` 860ed25d3e77d4676b5512f87f3f98b6783ee258 node-v0.10.2-darwin-x64.tar.gz 811eb3b66651dfffeaf928496e8eecab5c9304fb node-v0.10.2-darwin-x86.tar.gz -0013be477da5d066471390c9964f796356b48948 node-v0.10.2-linux-x64.tar.gz -97c3a052d833bfc799bc9b748520a15cfb189a58 node-v0.10.2-linux-x86.tar.gz +2914731bdbe809483ed9da2578ce19121494e437 node-v0.10.2-linux-x64.tar.gz +dbf039ee15e423738db4ffc9c498d6b0ad54da07 node-v0.10.2-linux-x86.tar.gz 17bc5bf26af7da790e6b0c4cbb2b73ea1c9f2ed5 node-v0.10.2-sunos-x64.tar.gz 5e02e35cc15ae56953921ad4c8e45b849c736e20 node-v0.10.2-sunos-x86.tar.gz 2adb1bf5919fb8adeaf96edd8a8ed16d71a3f8f8 node-v0.10.2-x86.msi From 1d17ced200c6ea3cf634edb62565faad11aa1cb9 Mon Sep 17 00:00:00 2001 From: isaacs Date: Thu, 28 Mar 2013 14:53:29 -0700 Subject: [PATCH 02/26] blog: v0.11.0 release --- doc/blog/release/v0.11.0.md | 86 +++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 doc/blog/release/v0.11.0.md diff --git a/doc/blog/release/v0.11.0.md b/doc/blog/release/v0.11.0.md new file mode 100644 index 00000000000..7f917b42474 --- /dev/null +++ b/doc/blog/release/v0.11.0.md @@ -0,0 +1,86 @@ +date: Thu Mar 28 14:52:55 PDT 2013 +version: 0.11.0 +category: release +title: Node v0.11.0 (Unstable) +slug: node-v0-11-0-stable + +2013.03.28, Version 0.11.0 (Unstable) + +* V8: update to 3.17.13 + +* os: use %SystemRoot% or %windir% in os.tmpdir() (Suwon Chae) + +* util: fix util.inspect() line width calculation (Marcin Kostrzewa) + +* buffer: remove _charsWritten (Trevor Norris) + +* fs: uv_[fl]stat now reports subsecond resolution (Timothy J Fontaine) + +* fs: Throw if error raised and missing callback (bnoordhuis) + +* tls: expose SSL_CTX_set_timeout via tls.createServer (Manav Rathi) + +* tls: remove harmful unnecessary bounds checking (Marcel Laverdet) + +* buffer: write ascii strings using WriteOneByte (Trevor Norris) + +* dtrace: fix generation of v8 constants on freebsd (Fedor Indutny) + +* dtrace: x64 ustack helper (Fedor Indutny) + +* readline: handle wide characters properly (Nao Iizuka) + +* repl: Use a domain to catch async errors safely (isaacs) + +* repl: emit 'reset' event when context is reset (Sami Samhuri) + +* util: custom `inspect()` method may return an Object (Nathan Rajlich) + +* console: `console.dir()` bypasses inspect() methods (Nathan Rajlich) + + +Source Code: http://nodejs.org/dist/v0.11.0/node-v0.11.0.tar.gz + +Macintosh Installer (Universal): http://nodejs.org/dist/v0.11.0/node-v0.11.0.pkg + +Windows Installer: http://nodejs.org/dist/v0.11.0/node-v0.11.0-x86.msi + +Windows x64 Installer: http://nodejs.org/dist/v0.11.0/x64/node-v0.11.0-x64.msi + +Windows x64 Files: http://nodejs.org/dist/v0.11.0/x64/ + +Linux 32-bit Binary: http://nodejs.org/dist/v0.11.0/node-v0.11.0-linux-x86.tar.gz + +Linux 64-bit Binary: http://nodejs.org/dist/v0.11.0/node-v0.11.0-linux-x64.tar.gz + +Solaris 32-bit Binary: http://nodejs.org/dist/v0.11.0/node-v0.11.0-sunos-x86.tar.gz + +Solaris 64-bit Binary: http://nodejs.org/dist/v0.11.0/node-v0.11.0-sunos-x64.tar.gz + +Other release files: http://nodejs.org/dist/v0.11.0/ + +Website: http://nodejs.org/docs/v0.11.0/ + +Documentation: http://nodejs.org/docs/v0.11.0/api/ + +Shasums: +``` +4889d63a4a08d146d59cd057b1c8b341ceac07cf node-v0.11.0-darwin-x64.tar.gz +4ef64fa36c095edfa3c6da852ed1ec46c6f3cf23 node-v0.11.0-darwin-x86.tar.gz +04c4d1fb71f98dfc921d9558667a727ca1aa6586 node-v0.11.0-linux-x64.tar.gz +b1507837292e23464e2d184007f2567db3db1483 node-v0.11.0-linux-x86.tar.gz +cd195da08ea5208a6c08b95511fa888d750f4cd7 node-v0.11.0-sunos-x64.tar.gz +4698b9a6cb911cbea3deac38ea191cef3051b3ab node-v0.11.0-sunos-x86.tar.gz +829649fe65133459c7fc231b8d048f19ae870c7b node-v0.11.0-x86.msi +7958b8212aaa9787724c552197d37cf5602ff645 node-v0.11.0.pkg +0402aae18f847238409e9d1a5ddd806beb5fe678 node-v0.11.0.tar.gz +320778de3329437815daa4f86d1a89db33458126 node.exe +1f4f509a9dc48c519064ca7f2deddeaff2b6b15b node.exp +5f83864acae194c0652a61af71262bd1ba55a04c node.lib +0d100a18ba569e5e9bb9e216355959261c4cd77b node.pdb +b55553c83e12f253f23dec4d998b05bd673db83b x64/node-v0.11.0-x64.msi +7100ef58f9a8428d2bdd9d4de8ffb679d0198b1e x64/node.exe +12bf810852e7097bde1bf4bff6cd7f802603cdb9 x64/node.exp +28f83178241353dc727ba6d8ff38f9b9177be79a x64/node.lib +6c0f43db501facc3d9ed542a090f9ba2e84bdc41 x64/node.pdb +``` From 7af075ee30485e6f2d295d3ad32923dd5ecb7536 Mon Sep 17 00:00:00 2001 From: isaacs Date: Fri, 29 Mar 2013 09:39:51 -0700 Subject: [PATCH 03/26] crypto: Pass options to ctor calls --- lib/crypto.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/crypto.js b/lib/crypto.js index 94c95695f18..f716ce00959 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -59,7 +59,7 @@ var StringDecoder = require('string_decoder').StringDecoder; function Credentials(secureProtocol, flags, context) { if (!(this instanceof Credentials)) { - return new Credentials(secureProtocol); + return new Credentials(secureProtocol, flags, context); } if (!crypto) { @@ -171,7 +171,7 @@ util.inherits(LazyTransform, stream.Transform); exports.createHash = exports.Hash = Hash; function Hash(algorithm, options) { if (!(this instanceof Hash)) - return new Hash(algorithm); + return new Hash(algorithm, options); this._binding = new binding.Hash(algorithm); LazyTransform.call(this, options); } @@ -209,7 +209,7 @@ exports.createHmac = exports.Hmac = Hmac; function Hmac(hmac, key, options) { if (!(this instanceof Hmac)) - return new Hmac(hmac, key); + return new Hmac(hmac, key, options); this._binding = new binding.Hmac(); this._binding.init(hmac, toBuf(key)); LazyTransform.call(this, options); @@ -233,7 +233,7 @@ function getDecoder(decoder, encoding) { exports.createCipher = exports.Cipher = Cipher; function Cipher(cipher, password, options) { if (!(this instanceof Cipher)) - return new Cipher(cipher, password); + return new Cipher(cipher, password, options); this._binding = new binding.Cipher; this._binding.init(cipher, toBuf(password)); @@ -293,7 +293,7 @@ Cipher.prototype.setAutoPadding = function(ap) { exports.createCipheriv = exports.Cipheriv = Cipheriv; function Cipheriv(cipher, key, iv, options) { if (!(this instanceof Cipheriv)) - return new Cipheriv(cipher, key, iv); + return new Cipheriv(cipher, key, iv, options); this._binding = new binding.Cipher(); this._binding.initiv(cipher, toBuf(key), toBuf(iv)); this._decoder = null; @@ -314,7 +314,7 @@ Cipheriv.prototype.setAutoPadding = Cipher.prototype.setAutoPadding; exports.createDecipher = exports.Decipher = Decipher; function Decipher(cipher, password, options) { if (!(this instanceof Decipher)) - return new Decipher(cipher, password); + return new Decipher(cipher, password, options); this._binding = new binding.Decipher; this._binding.init(cipher, toBuf(password)); @@ -337,7 +337,7 @@ Decipher.prototype.setAutoPadding = Cipher.prototype.setAutoPadding; exports.createDecipheriv = exports.Decipheriv = Decipheriv; function Decipheriv(cipher, key, iv, options) { if (!(this instanceof Decipheriv)) - return new Decipheriv(cipher, key, iv); + return new Decipheriv(cipher, key, iv, options); this._binding = new binding.Decipher; this._binding.initiv(cipher, toBuf(key), toBuf(iv)); @@ -360,7 +360,7 @@ Decipheriv.prototype.setAutoPadding = Cipher.prototype.setAutoPadding; exports.createSign = exports.Sign = Sign; function Sign(algorithm, options) { if (!(this instanceof Sign)) - return new Sign(algorithm); + return new Sign(algorithm, options); this._binding = new binding.Sign(); this._binding.init(algorithm); @@ -391,7 +391,7 @@ Sign.prototype.sign = function(key, encoding) { exports.createVerify = exports.Verify = Verify; function Verify(algorithm, options) { if (!(this instanceof Verify)) - return new Verify(algorithm); + return new Verify(algorithm, options); this._binding = new binding.Verify; this._binding.init(algorithm); From 085f9d636b260724af2e80d6757e9d0f4bcd9193 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Sat, 30 Mar 2013 13:10:30 -0700 Subject: [PATCH 04/26] repl: isSyntaxError() catches "strict mode" errors Closes #5178. --- lib/repl.js | 2 ++ test/simple/test-repl.js | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/lib/repl.js b/lib/repl.js index f0c1cb270f8..522bfd7d5bd 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -920,6 +920,8 @@ function isSyntaxError(e) { // RegExp syntax error !e.match(/^SyntaxError: Invalid regular expression/) && !e.match(/^SyntaxError: Invalid flags supplied to RegExp constructor/) && + // "strict mode" syntax errors + !e.match(/^SyntaxError: .*strict mode.*/i) && // JSON.parse() error !(e.match(/^SyntaxError: Unexpected (token .*|end of input)/) && e.match(/\n at Object.parse \(native\)\n/)); diff --git a/test/simple/test-repl.js b/test/simple/test-repl.js index 793346775b4..27c2058b013 100644 --- a/test/simple/test-repl.js +++ b/test/simple/test-repl.js @@ -144,6 +144,21 @@ function error_test() { // should throw (GH-4012) { client: client_unix, send: 'new RegExp("foo", "wrong modifier");', expect: /^SyntaxError: Invalid flags supplied to RegExp constructor/ }, + // strict mode syntax errors should be caught (GH-5178) + { client: client_unix, send: '(function() { "use strict"; return 0755; })()', + expect: /^SyntaxError: Octal literals are not allowed in strict mode/ }, + { client: client_unix, send: '(function() { "use strict"; return { p: 1, p: 2 }; })()', + expect: /^SyntaxError: Duplicate data property in object literal not allowed in strict mode/ }, + { client: client_unix, send: '(function(a, a, b) { "use strict"; return a + b + c; })()', + expect: /^SyntaxError: Strict mode function may not have duplicate parameter names/ }, + { client: client_unix, send: '(function() { "use strict"; with (this) {} })()', + expect: /^SyntaxError: Strict mode code may not include a with statement/ }, + { client: client_unix, send: '(function() { "use strict"; var x; delete x; })()', + expect: /^SyntaxError: Delete of an unqualified identifier in strict mode/ }, + { client: client_unix, send: '(function() { "use strict"; eval = 17; })()', + expect: /^SyntaxError: Assignment to eval or arguments is not allowed in strict mode/ }, + { client: client_unix, send: '(function() { "use strict"; if (true){ function f() { } } })()', + expect: /^SyntaxError: In strict mode code, functions can only be declared at top level or immediately within another function/ }, // Named functions can be used: { client: client_unix, send: 'function blah() { return 1; }', expect: prompt_unix }, From 55ea7ccf704806fee7b8bc3090206f385817690c Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Sat, 30 Mar 2013 13:35:36 -0700 Subject: [PATCH 05/26] repl: use more readable RegExp syntax for spaces This is just a cosmetic change really, nothing major. --- lib/repl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/repl.js b/lib/repl.js index 522bfd7d5bd..84441ef130c 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -924,5 +924,5 @@ function isSyntaxError(e) { !e.match(/^SyntaxError: .*strict mode.*/i) && // JSON.parse() error !(e.match(/^SyntaxError: Unexpected (token .*|end of input)/) && - e.match(/\n at Object.parse \(native\)\n/)); + e.match(/\n {4}at Object.parse \(native\)\n/)); } From e5b90a14b816000a00b3e97dcc2f36805b893ab7 Mon Sep 17 00:00:00 2001 From: Mitar Date: Sun, 31 Mar 2013 03:42:33 -0700 Subject: [PATCH 06/26] querystring: Removing unnecessary binding Binding of `http_parser` in querystring isn't used anywhere and should be removed. --- lib/querystring.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/querystring.js b/lib/querystring.js index 12b6013d525..0ab739a5226 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -22,7 +22,6 @@ // Query String Utilities var QueryString = exports; -var urlDecode = process.binding('http_parser').urlDecode; // If obj.hasOwnProperty has been overridden, then calling From 440dcae98744954d1528506f2648aff71aadde25 Mon Sep 17 00:00:00 2001 From: Michael Hart Date: Sat, 30 Mar 2013 12:29:50 +1100 Subject: [PATCH 07/26] Ensure BAD domain example actually uses domain --- doc/api/domain.markdown | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/api/domain.markdown b/doc/api/domain.markdown index 4a0ee67dbba..b93c3fcd622 100644 --- a/doc/api/domain.markdown +++ b/doc/api/domain.markdown @@ -48,9 +48,11 @@ d.on('error', function(er) { // This is no better than process.on('uncaughtException')! console.log('error, but oh well', er.message); }); -require('http').createServer(function(req, res) { - handleRequest(req, res); -}).listen(PORT); +d.run(function() { + require('http').createServer(function(req, res) { + handleRequest(req, res); + }).listen(PORT); +}); ``` By using the context of a domain, and the resilience of separating our From 164d5b3465571a88da59cdddc03bb869126548eb Mon Sep 17 00:00:00 2001 From: isaacs Date: Fri, 29 Mar 2013 18:23:39 -0700 Subject: [PATCH 08/26] tls: Destroy socket when encrypted side closes The v0.8 Stream.pipe() method automatically destroyed the destination stream whenever the src stream closed. However, this caused a lot of problems, and was removed by popular demand. (Many userland modules still have a no-op destroy() method just because of this.) It was also very hazardous because this would be done even if { end: false } was passed in the pipe options. In v0.10, we decided that the 'close' event and destroy() method are application-specific, and pipe() doesn't automatically call destroy(). However, TLS actually depended (silently) on this behavior. So, in this case, we should just go ahead and destroy the thing when close happens. Closes #5145 --- lib/tls.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/tls.js b/lib/tls.js index 53859121733..8650041c91f 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -1322,6 +1322,12 @@ function pipe(pair, socket) { pair.encrypted.pipe(socket); socket.pipe(pair.encrypted); + pair.encrypted.on('close', function() { + process.nextTick(function() { + socket.destroy(); + }); + }); + pair.fd = socket.fd; var cleartext = pair.cleartext; cleartext.socket = socket; From db8ce89fe4a8d857c5c35b0d4f5af6044e5330ac Mon Sep 17 00:00:00 2001 From: Andrew Hart Date: Sun, 31 Mar 2013 00:16:52 -0600 Subject: [PATCH 09/26] test: test intended code-paths The tests did not agree with the test comments. Tests first and second were both testing the !state.reading case. Now second tests the state.reading && state.length case. Fixes joyent/node#5183 --- test/simple/test-stream-readable-event.js | 34 ++++++++++++++++++----- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/test/simple/test-stream-readable-event.js b/test/simple/test-stream-readable-event.js index fdbcb481034..ba6a57724d2 100644 --- a/test/simple/test-stream-readable-event.js +++ b/test/simple/test-stream-readable-event.js @@ -26,13 +26,14 @@ var Readable = require('stream').Readable; (function first() { // First test, not reading when the readable is added. - // make sure that read(0) triggers a readable event. + // make sure that on('readable', ...) triggers a readable event. var r = new Readable({ highWaterMark: 3 }); + var _readCalled = false; r._read = function(n) { - r.push(new Buffer(new Array(n + 1).join('x'))); + _readCalled = true; }; // This triggers a 'readable' event, which is lost. @@ -40,12 +41,17 @@ var Readable = require('stream').Readable; var caughtReadable = false; setTimeout(function() { + // we're testing what we think we are + assert(!r._readableState.reading); r.on('readable', function() { caughtReadable = true; }); }); process.on('exit', function() { + // we're testing what we think we are + assert(!_readCalled); + assert(caughtReadable); console.log('ok 1'); }); @@ -59,23 +65,27 @@ var Readable = require('stream').Readable; highWaterMark: 3 }); + var _readCalled = false; r._read = function(n) { - setTimeout(function() { - r.push(new Buffer(new Array(n + 1).join('x'))); - }); + _readCalled = true; }; // This triggers a 'readable' event, which is lost. - r.push(new Buffer('blerg')); + r.push(new Buffer('bl')); var caughtReadable = false; - process.nextTick(function() { + setTimeout(function() { + // assert we're testing what we think we are + assert(r._readableState.reading); r.on('readable', function() { caughtReadable = true; }); }); process.on('exit', function() { + // we're testing what we think we are + assert(_readCalled); + assert(caughtReadable); console.log('ok 2'); }); @@ -88,18 +98,28 @@ var Readable = require('stream').Readable; highWaterMark: 30 }); + var _readCalled = false; + r._read = function(n) { + _readCalled = true; + }; + // This triggers a 'readable' event, which is lost. r.push(new Buffer('blerg')); r.push(null); var caughtReadable = false; setTimeout(function() { + // assert we're testing what we think we are + assert(!r._readableState.reading); r.on('readable', function() { caughtReadable = true; }); }); process.on('exit', function() { + // we're testing what we think we are + assert(!_readCalled); + assert(caughtReadable); console.log('ok 3'); }); From 234fb122bbdf87bb33d8fba41165ecfa92031b71 Mon Sep 17 00:00:00 2001 From: isaacs Date: Mon, 1 Apr 2013 17:19:05 -0700 Subject: [PATCH 10/26] http client: Ensure socket cleanup on response end If an http response has an 'end' handler that throws, then the socket will never be released back into the pool. Granted, we do NOT guarantee that throwing will never have adverse effects on Node internal state. Such a guarantee cannot be reasonably made in a shared-global mutable-state side-effecty language like JavaScript. However, in this case, it's a rather trivial patch to increase our resilience a little bit, so it seems like a win. There is no semantic change in this case, except that some event listeners are removed, and the `'free'` event is emitted on nextTick, so that you can schedule another request which will re-use the same socket. From the user's point of view, there should be no detectable difference. Closes #5107 --- lib/http.js | 10 ++- .../test-http-end-throw-socket-handling.js | 67 +++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 test/simple/test-http-end-throw-socket-handling.js diff --git a/lib/http.js b/lib/http.js index dacedd4477f..1f4db7a6475 100644 --- a/lib/http.js +++ b/lib/http.js @@ -1635,8 +1635,10 @@ function parserOnIncomingClient(res, shouldKeepAlive) { COUNTER_HTTP_CLIENT_RESPONSE(); req.res = res; res.req = req; - var handled = req.emit('response', res); + + // add our listener first, so that we guarantee socket cleanup res.on('end', responseOnEnd); + var handled = req.emit('response', res); // If the user did not listen for the 'response' event, then they // can't possibly read the data, so we ._dump() it into the void @@ -1667,7 +1669,11 @@ function responseOnEnd() { } socket.removeListener('close', socketCloseListener); socket.removeListener('error', socketErrorListener); - socket.emit('free'); + // Mark this socket as available, AFTER user-added end + // handlers have a chance to run. + process.nextTick(function() { + socket.emit('free'); + }); } } diff --git a/test/simple/test-http-end-throw-socket-handling.js b/test/simple/test-http-end-throw-socket-handling.js new file mode 100644 index 00000000000..50aa97ff18e --- /dev/null +++ b/test/simple/test-http-end-throw-socket-handling.js @@ -0,0 +1,67 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); + +// Make sure that throwing in 'end' handler doesn't lock +// up the socket forever. +// +// This is NOT a good way to handle errors in general, but all +// the same, we should not be so brittle and easily broken. + +var http = require('http'); + +var n = 0; +var server = http.createServer(function(req, res) { + if (++n === 10) server.close(); + res.end('ok'); +}); + +server.listen(common.PORT, function() { + for (var i = 0; i < 10; i++) { + var options = { port: common.PORT }; + + var req = http.request(options, function (res) { + res.resume() + res.on('end', function() { + throw new Error('gleep glorp'); + }); + }); + req.end(); + } +}); + +setTimeout(function() { + process.removeListener('uncaughtException', catcher); + throw new Error('Taking too long!'); +}, 1000).unref(); + +process.on('uncaughtException', catcher); +var errors = 0; +function catcher() { + errors++; +} + +process.on('exit', function() { + assert.equal(errors, 10); + console.log('ok'); +}); From 38106da7cddee38453a0c2393bd19e2d2bd6228b Mon Sep 17 00:00:00 2001 From: Brian White Date: Tue, 2 Apr 2013 12:27:19 -0400 Subject: [PATCH 11/26] src: remove unused variables --- src/node.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/node.cc b/src/node.cc index 8ba577582eb..391a17959ca 100644 --- a/src/node.cc +++ b/src/node.cc @@ -1513,12 +1513,11 @@ static uid_t uid_by_name(const char* name) { struct passwd pwd; struct passwd* pp; char buf[8192]; - int rc; errno = 0; pp = NULL; - if ((rc = getpwnam_r(name, &pwd, buf, sizeof(buf), &pp)) == 0 && pp != NULL) { + if (getpwnam_r(name, &pwd, buf, sizeof(buf), &pp) == 0 && pp != NULL) { return pp->pw_uid; } @@ -1551,12 +1550,11 @@ static gid_t gid_by_name(const char* name) { struct group pwd; struct group* pp; char buf[8192]; - int rc; errno = 0; pp = NULL; - if ((rc = getgrnam_r(name, &pwd, buf, sizeof(buf), &pp)) == 0 && pp != NULL) { + if (getgrnam_r(name, &pwd, buf, sizeof(buf), &pp) == 0 && pp != NULL) { return pp->gr_gid; } From ec69fcf4256dfe6b8c90e96e71c2dff570fd36c3 Mon Sep 17 00:00:00 2001 From: Dave Pacheco Date: Thu, 28 Mar 2013 11:36:00 -0700 Subject: [PATCH 12/26] build: allow building with dtrace on osx --- configure | 2 +- node.gyp | 34 +++++++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/configure b/configure index a5a18e33da3..09f3c40978e 100755 --- a/configure +++ b/configure @@ -468,7 +468,7 @@ def configure_node(o): # By default, enable DTrace on SunOS systems. Don't allow it on other # systems, since it won't work. (The MacOS build process is different than # SunOS, and we haven't implemented it.) - if sys.platform.startswith('sunos'): + if sys.platform.startswith('sunos') or sys.platform.startswith('darwin'): o['variables']['node_use_dtrace'] = b(not options.without_dtrace) elif sys.platform.startswith('linux'): o['variables']['node_use_dtrace'] = 'false' diff --git a/node.gyp b/node.gyp index b07a1e0cabe..fc7e2153f81 100644 --- a/node.gyp +++ b/node.gyp @@ -160,17 +160,33 @@ 'dependencies': [ 'node_dtrace_header' ], 'include_dirs': [ '<(SHARED_INTERMEDIATE_DIR)' ], # - # node_dtrace_provider.cc and node_dtrace_ustack.cc do not actually - # exist. They're here to trick GYP into linking the corresponding - # object files into the final "node" executable. These files are - # generated by "dtrace -G" using custom actions below, and the - # GYP-generated Makefiles will properly build them when needed. + # DTrace is supported on solaris, mac, and bsd. There are three + # object files associated with DTrace support, but they're not all + # used all the time: + # + # node_dtrace.o all configurations + # node_dtrace_ustack.o not supported on OS X + # node_dtrace_provider.o All except OS X. "dtrace -G" is not + # used on OS X. + # + # Note that node_dtrace_provider.cc and node_dtrace_ustack.cc do not + # actually exist. They're listed here to trick GYP into linking the + # corresponding object files into the final "node" executable. These + # object files are generated by "dtrace -G" using custom actions + # below, and the GYP-generated Makefiles will properly build them when + # needed. # 'sources': [ 'src/node_dtrace.cc', - 'src/node_dtrace_provider.cc', - 'src/node_dtrace_ustack.cc', ], + 'conditions': [ [ + 'OS!="mac"', { + 'sources': [ + 'src/node_dtrace_ustack.cc', + 'src/node_dtrace_provider.cc', + ] + } + ] ] } ], [ 'node_use_systemtap=="true"', { 'defines': [ 'HAVE_SYSTEMTAP=1', 'STAP_SDT_V1=1' ], @@ -397,7 +413,7 @@ 'target_name': 'node_dtrace_provider', 'type': 'none', 'conditions': [ - [ 'node_use_dtrace=="true"', { + [ 'node_use_dtrace=="true" and OS!="mac"', { 'actions': [ { 'action_name': 'node_dtrace_provider_o', @@ -419,7 +435,7 @@ 'target_name': 'node_dtrace_ustack', 'type': 'none', 'conditions': [ - [ 'node_use_dtrace=="true"', { + [ 'node_use_dtrace=="true" and OS!="mac"', { 'actions': [ { 'action_name': 'node_dtrace_ustack_constants', From bf22f99f3a17e33b78df5c8f85fab5372c032143 Mon Sep 17 00:00:00 2001 From: Dave Pacheco Date: Thu, 28 Mar 2013 13:52:43 -0700 Subject: [PATCH 13/26] dtrace: pass more arguments to probes OSX and other DTrace implementations don't support dereferencing structs in probes. To accomodate that pass members from the struct as arguments so that DTrace is useful on those systems. --- src/node_dtrace.cc | 18 ++++++++++-------- src/node_provider.d | 34 ++++++++++++++++++---------------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/node_dtrace.cc b/src/node_dtrace.cc index df42af2a977..85583905df8 100644 --- a/src/node_dtrace.cc +++ b/src/node_dtrace.cc @@ -139,7 +139,7 @@ Handle DTRACE_NET_SERVER_CONNECTION(const Arguments& args) { NODE_NET_SERVER_CONNECTION(conn.fd, conn.remote, conn.port, \ conn.buffered); #else - NODE_NET_SERVER_CONNECTION(&conn); + NODE_NET_SERVER_CONNECTION(&conn, conn.remote, conn.port); #endif return Undefined(); @@ -157,7 +157,7 @@ Handle DTRACE_NET_STREAM_END(const Arguments& args) { #ifdef HAVE_SYSTEMTAP NODE_NET_STREAM_END(conn.fd, conn.remote, conn.port, conn.buffered); #else - NODE_NET_STREAM_END(&conn); + NODE_NET_STREAM_END(&conn, conn.remote, conn.port); #endif return Undefined(); @@ -181,7 +181,7 @@ Handle DTRACE_NET_SOCKET_READ(const Arguments& args) { "argument 1 to be number of bytes")))); } int nbytes = args[1]->Int32Value(); - NODE_NET_SOCKET_READ(&conn, nbytes); + NODE_NET_SOCKET_READ(&conn, nbytes, conn.remote, conn.port); #endif return Undefined(); @@ -205,7 +205,7 @@ Handle DTRACE_NET_SOCKET_WRITE(const Arguments& args) { "argument 1 to be number of bytes")))); } int nbytes = args[1]->Int32Value(); - NODE_NET_SOCKET_WRITE(&conn, nbytes); + NODE_NET_SOCKET_WRITE(&conn, nbytes, conn.remote, conn.port); #endif return Undefined(); @@ -247,7 +247,8 @@ Handle DTRACE_HTTP_SERVER_REQUEST(const Arguments& args) { NODE_HTTP_SERVER_REQUEST(&req, conn.fd, conn.remote, conn.port, \ conn.buffered); #else - NODE_HTTP_SERVER_REQUEST(&req, &conn); + NODE_HTTP_SERVER_REQUEST(&req, &conn, conn.remote, conn.port, req.method, \ + req.url); #endif return Undefined(); } @@ -264,7 +265,7 @@ Handle DTRACE_HTTP_SERVER_RESPONSE(const Arguments& args) { #ifdef HAVE_SYSTEMTAP NODE_HTTP_SERVER_RESPONSE(conn.fd, conn.remote, conn.port, conn.buffered); #else - NODE_HTTP_SERVER_RESPONSE(&conn); + NODE_HTTP_SERVER_RESPONSE(&conn, conn.remote, conn.port); #endif return Undefined(); @@ -310,7 +311,8 @@ Handle DTRACE_HTTP_CLIENT_REQUEST(const Arguments& args) { NODE_HTTP_CLIENT_REQUEST(&req, conn.fd, conn.remote, conn.port, \ conn.buffered); #else - NODE_HTTP_CLIENT_REQUEST(&req, &conn); + NODE_HTTP_CLIENT_REQUEST(&req, &conn, conn.remote, conn.port, req.method, \ + req.url); #endif return Undefined(); } @@ -326,7 +328,7 @@ Handle DTRACE_HTTP_CLIENT_RESPONSE(const Arguments& args) { #ifdef HAVE_SYSTEMTAP NODE_HTTP_CLIENT_RESPONSE(conn.fd, conn.remote, conn.port, conn.buffered); #else - NODE_HTTP_CLIENT_RESPONSE(&conn); + NODE_HTTP_CLIENT_RESPONSE(&conn, conn.remote, conn.port); #endif return Undefined(); diff --git a/src/node_provider.d b/src/node_provider.d index 646e21a22d1..4c526d477ee 100644 --- a/src/node_provider.d +++ b/src/node_provider.d @@ -52,24 +52,26 @@ typedef struct { } node_http_request_t; provider node { - probe net__server__connection(node_dtrace_connection_t *c) : - (node_connection_t *c); - probe net__stream__end(node_dtrace_connection_t *c) : - (node_connection_t *c); - probe net__socket__read(node_dtrace_connection_t *c, int b) : - (node_connection_t *c, int b); - probe net__socket__write(node_dtrace_connection_t *c, int b) : - (node_connection_t *c, int b); + probe net__server__connection(node_dtrace_connection_t *c, + const char *a, int p) : (node_connection_t *c, string a, int p); + probe net__stream__end(node_dtrace_connection_t *c, const char *a, + int p) : (node_connection_t *c, string a, int p); + probe net__socket__read(node_dtrace_connection_t *c, int b, + const char *a, int p) : (node_connection_t *c, int b, string a, int p); + probe net__socket__write(node_dtrace_connection_t *c, int b, + const char *a, int p) : (node_connection_t *c, int b, string a, int p); probe http__server__request(node_dtrace_http_server_request_t *h, - node_dtrace_connection_t *c) : - (node_http_request_t *h, node_connection_t *c); - probe http__server__response(node_dtrace_connection_t *c) : - (node_connection_t *c); + node_dtrace_connection_t *c, const char *a, int p, const char *m, + const char *u) : (node_http_request_t *h, node_connection_t *c, + string a, int p, string m, string u); + probe http__server__response(node_dtrace_connection_t *c, const char *a, + int p) : (node_connection_t *c, string a, int p); probe http__client__request(node_dtrace_http_client_request_t *h, - node_dtrace_connection_t *c) : - (node_http_request_t *h, node_connection_t *c); - probe http__client__response(node_dtrace_connection_t *c) : - (node_connection_t *c); + node_dtrace_connection_t *c, const char *a, int p, const char *m, + const char *u) : (node_http_request_t *h, node_connection_t *c, string a, + int p, string m, string u); + probe http__client__response(node_dtrace_connection_t *c, const char *a, + int p) : (node_connection_t *c, string a, int p); probe gc__start(int t, int f); probe gc__done(int t, int f); }; From aca31e37f7bccbf229f460b236753072eecfeeab Mon Sep 17 00:00:00 2001 From: Timothy J Fontaine Date: Thu, 28 Mar 2013 16:51:52 -0700 Subject: [PATCH 14/26] dtrace: actually use the _handle.fd value When using the DTrace/systemtap subsystems it would be helpful to actually have an fd associated with the requests and responses. --- src/node_dtrace.cc | 19 ++++++++++--------- src/node_provider.d | 23 +++++++++++++---------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/node_dtrace.cc b/src/node_dtrace.cc index 85583905df8..9770ae23774 100644 --- a/src/node_dtrace.cc +++ b/src/node_dtrace.cc @@ -91,7 +91,8 @@ using namespace v8; } \ node_dtrace_connection_t conn; \ Local _##conn = Local::Cast(arg); \ - SLURP_INT(_##conn, fd, &conn.fd); \ + Local _handle = (_##conn)->Get(String::New("_handle"))->ToObject(); \ + SLURP_INT(_handle, fd, &conn.fd); \ SLURP_STRING(_##conn, remoteAddress, &conn.remote); \ SLURP_INT(_##conn, remotePort, &conn.port); \ SLURP_INT(_##conn, bufferSize, &conn.buffered); @@ -139,7 +140,7 @@ Handle DTRACE_NET_SERVER_CONNECTION(const Arguments& args) { NODE_NET_SERVER_CONNECTION(conn.fd, conn.remote, conn.port, \ conn.buffered); #else - NODE_NET_SERVER_CONNECTION(&conn, conn.remote, conn.port); + NODE_NET_SERVER_CONNECTION(&conn, conn.remote, conn.port, conn.fd); #endif return Undefined(); @@ -157,7 +158,7 @@ Handle DTRACE_NET_STREAM_END(const Arguments& args) { #ifdef HAVE_SYSTEMTAP NODE_NET_STREAM_END(conn.fd, conn.remote, conn.port, conn.buffered); #else - NODE_NET_STREAM_END(&conn, conn.remote, conn.port); + NODE_NET_STREAM_END(&conn, conn.remote, conn.port, conn.fd); #endif return Undefined(); @@ -181,7 +182,7 @@ Handle DTRACE_NET_SOCKET_READ(const Arguments& args) { "argument 1 to be number of bytes")))); } int nbytes = args[1]->Int32Value(); - NODE_NET_SOCKET_READ(&conn, nbytes, conn.remote, conn.port); + NODE_NET_SOCKET_READ(&conn, nbytes, conn.remote, conn.port, conn.fd); #endif return Undefined(); @@ -205,7 +206,7 @@ Handle DTRACE_NET_SOCKET_WRITE(const Arguments& args) { "argument 1 to be number of bytes")))); } int nbytes = args[1]->Int32Value(); - NODE_NET_SOCKET_WRITE(&conn, nbytes, conn.remote, conn.port); + NODE_NET_SOCKET_WRITE(&conn, nbytes, conn.remote, conn.port, conn.fd); #endif return Undefined(); @@ -248,7 +249,7 @@ Handle DTRACE_HTTP_SERVER_REQUEST(const Arguments& args) { conn.buffered); #else NODE_HTTP_SERVER_REQUEST(&req, &conn, conn.remote, conn.port, req.method, \ - req.url); + req.url, conn.fd); #endif return Undefined(); } @@ -265,7 +266,7 @@ Handle DTRACE_HTTP_SERVER_RESPONSE(const Arguments& args) { #ifdef HAVE_SYSTEMTAP NODE_HTTP_SERVER_RESPONSE(conn.fd, conn.remote, conn.port, conn.buffered); #else - NODE_HTTP_SERVER_RESPONSE(&conn, conn.remote, conn.port); + NODE_HTTP_SERVER_RESPONSE(&conn, conn.remote, conn.port, conn.fd); #endif return Undefined(); @@ -312,7 +313,7 @@ Handle DTRACE_HTTP_CLIENT_REQUEST(const Arguments& args) { conn.buffered); #else NODE_HTTP_CLIENT_REQUEST(&req, &conn, conn.remote, conn.port, req.method, \ - req.url); + req.url, conn.fd); #endif return Undefined(); } @@ -328,7 +329,7 @@ Handle DTRACE_HTTP_CLIENT_RESPONSE(const Arguments& args) { #ifdef HAVE_SYSTEMTAP NODE_HTTP_CLIENT_RESPONSE(conn.fd, conn.remote, conn.port, conn.buffered); #else - NODE_HTTP_CLIENT_RESPONSE(&conn, conn.remote, conn.port); + NODE_HTTP_CLIENT_RESPONSE(&conn, conn.remote, conn.port, conn.fd); #endif return Undefined(); diff --git a/src/node_provider.d b/src/node_provider.d index 4c526d477ee..6f95b03db74 100644 --- a/src/node_provider.d +++ b/src/node_provider.d @@ -53,25 +53,28 @@ typedef struct { provider node { probe net__server__connection(node_dtrace_connection_t *c, - const char *a, int p) : (node_connection_t *c, string a, int p); + const char *a, int p, int fd) : (node_connection_t *c, string a, int p, + int fd); probe net__stream__end(node_dtrace_connection_t *c, const char *a, - int p) : (node_connection_t *c, string a, int p); + int p, int fd) : (node_connection_t *c, string a, int p, int fd); probe net__socket__read(node_dtrace_connection_t *c, int b, - const char *a, int p) : (node_connection_t *c, int b, string a, int p); + const char *a, int p, int fd) : (node_connection_t *c, int b, string a, + int p, int fd); probe net__socket__write(node_dtrace_connection_t *c, int b, - const char *a, int p) : (node_connection_t *c, int b, string a, int p); + const char *a, int p, int fd) : (node_connection_t *c, int b, string a, + int p, int fd); probe http__server__request(node_dtrace_http_server_request_t *h, node_dtrace_connection_t *c, const char *a, int p, const char *m, - const char *u) : (node_http_request_t *h, node_connection_t *c, - string a, int p, string m, string u); + const char *u, int fd) : (node_http_request_t *h, node_connection_t *c, + string a, int p, string m, string u, int fd); probe http__server__response(node_dtrace_connection_t *c, const char *a, - int p) : (node_connection_t *c, string a, int p); + int p, int fd) : (node_connection_t *c, string a, int p, int fd); probe http__client__request(node_dtrace_http_client_request_t *h, node_dtrace_connection_t *c, const char *a, int p, const char *m, - const char *u) : (node_http_request_t *h, node_connection_t *c, string a, - int p, string m, string u); + const char *u, int fd) : (node_http_request_t *h, node_connection_t *c, + string a, int p, string m, string u, int fd); probe http__client__response(node_dtrace_connection_t *c, const char *a, - int p) : (node_connection_t *c, string a, int p); + int p, int fd) : (node_connection_t *c, string a, int p, int fd); probe gc__start(int t, int f); probe gc__done(int t, int f); }; From 75463899c8ef90e5a429cb1dcd578ee2886e71d4 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 30 Mar 2013 01:49:19 +0100 Subject: [PATCH 15/26] dtrace: check if _handle property is set Check that _handle is an object before trying to read its `fd` property, avoids bogus values. --- src/node_dtrace.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/node_dtrace.cc b/src/node_dtrace.cc index 9770ae23774..4318e8b49c8 100644 --- a/src/node_dtrace.cc +++ b/src/node_dtrace.cc @@ -91,8 +91,12 @@ using namespace v8; } \ node_dtrace_connection_t conn; \ Local _##conn = Local::Cast(arg); \ - Local _handle = (_##conn)->Get(String::New("_handle"))->ToObject(); \ - SLURP_INT(_handle, fd, &conn.fd); \ + Local _handle = (_##conn)->Get(String::New("_handle")); \ + if (_handle->IsObject()) { \ + SLURP_INT(_handle.As(), fd, &conn.fd); \ + } else { \ + conn.fd = -1; \ + } \ SLURP_STRING(_##conn, remoteAddress, &conn.remote); \ SLURP_INT(_##conn, remotePort, &conn.port); \ SLURP_INT(_##conn, bufferSize, &conn.buffered); From 9f65b1edf7bffe8e99bd6ac2539336128e2f5900 Mon Sep 17 00:00:00 2001 From: Timothy J Fontaine Date: Fri, 29 Mar 2013 20:46:36 -0700 Subject: [PATCH 16/26] etw: update prototypes to match dtrace provider The DTrace probes were updated to accomodate platforms that can't handle structs, update the prototypes for ETW but it's not necessary to do anything with the new arguments as it's redundant information. --- src/node_win32_etw_provider-inl.h | 20 +++++++++++++------- src/node_win32_etw_provider.h | 20 +++++++++++++------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/node_win32_etw_provider-inl.h b/src/node_win32_etw_provider-inl.h index db59eea5713..1c4a2431c68 100644 --- a/src/node_win32_etw_provider-inl.h +++ b/src/node_win32_etw_provider-inl.h @@ -112,7 +112,8 @@ extern int events_enabled; void NODE_HTTP_SERVER_REQUEST(node_dtrace_http_server_request_t* req, - node_dtrace_connection_t* conn) { + node_dtrace_connection_t* conn, const char *remote, int port, + const char *method, const char *url, int fd) { EVENT_DATA_DESCRIPTOR descriptors[7]; ETW_WRITE_HTTP_SERVER_REQUEST(descriptors, req); ETW_WRITE_NET_CONNECTION(descriptors + 3, conn); @@ -120,7 +121,8 @@ void NODE_HTTP_SERVER_REQUEST(node_dtrace_http_server_request_t* req, } -void NODE_HTTP_SERVER_RESPONSE(node_dtrace_connection_t* conn) { +void NODE_HTTP_SERVER_RESPONSE(node_dtrace_connection_t* conn, + const char *remote, int port, int fd) { EVENT_DATA_DESCRIPTOR descriptors[4]; ETW_WRITE_NET_CONNECTION(descriptors, conn); ETW_WRITE_EVENT(NODE_HTTP_SERVER_RESPONSE_EVENT, descriptors); @@ -128,7 +130,8 @@ void NODE_HTTP_SERVER_RESPONSE(node_dtrace_connection_t* conn) { void NODE_HTTP_CLIENT_REQUEST(node_dtrace_http_client_request_t* req, - node_dtrace_connection_t* conn) { + node_dtrace_connection_t* conn, const char *remote, int port, + const char *method, const char *url, int fd) { EVENT_DATA_DESCRIPTOR descriptors[6]; ETW_WRITE_HTTP_CLIENT_REQUEST(descriptors, req); ETW_WRITE_NET_CONNECTION(descriptors + 2, conn); @@ -136,21 +139,24 @@ void NODE_HTTP_CLIENT_REQUEST(node_dtrace_http_client_request_t* req, } -void NODE_HTTP_CLIENT_RESPONSE(node_dtrace_connection_t* conn) { +void NODE_HTTP_CLIENT_RESPONSE(node_dtrace_connection_t* conn, + const char *remote, int port, int fd) { EVENT_DATA_DESCRIPTOR descriptors[4]; ETW_WRITE_NET_CONNECTION(descriptors, conn); ETW_WRITE_EVENT(NODE_HTTP_CLIENT_RESPONSE_EVENT, descriptors); } -void NODE_NET_SERVER_CONNECTION(node_dtrace_connection_t* conn) { +void NODE_NET_SERVER_CONNECTION(node_dtrace_connection_t* conn, + const char *remote, int port, int fd) { EVENT_DATA_DESCRIPTOR descriptors[4]; ETW_WRITE_NET_CONNECTION(descriptors, conn); ETW_WRITE_EVENT(NODE_NET_SERVER_CONNECTION_EVENT, descriptors); } -void NODE_NET_STREAM_END(node_dtrace_connection_t* conn) { +void NODE_NET_STREAM_END(node_dtrace_connection_t* conn, + const char *remote, int port, int fd) { EVENT_DATA_DESCRIPTOR descriptors[4]; ETW_WRITE_NET_CONNECTION(descriptors, conn); ETW_WRITE_EVENT(NODE_NET_STREAM_END_EVENT, descriptors); @@ -262,4 +268,4 @@ bool NODE_NET_SOCKET_READ_ENABLED() { return events_enabled > 0; } bool NODE_NET_SOCKET_WRITE_ENABLED() { return events_enabled > 0; } bool NODE_V8SYMBOL_ENABLED() { return events_enabled > 0; } } -#endif // SRC_ETW_INL_H_ \ No newline at end of file +#endif // SRC_ETW_INL_H_ diff --git a/src/node_win32_etw_provider.h b/src/node_win32_etw_provider.h index cfc2c8658e6..b47b87cf48c 100644 --- a/src/node_win32_etw_provider.h +++ b/src/node_win32_etw_provider.h @@ -57,13 +57,19 @@ void init_etw(); void shutdown_etw(); INLINE void NODE_HTTP_SERVER_REQUEST(node_dtrace_http_server_request_t* req, - node_dtrace_connection_t* conn); -INLINE void NODE_HTTP_SERVER_RESPONSE(node_dtrace_connection_t* conn); + node_dtrace_connection_t* conn, const char *remote, int port, + const char *method, const char *url, int fd); +INLINE void NODE_HTTP_SERVER_RESPONSE(node_dtrace_connection_t* conn, + const char *remote, int port, int fd); INLINE void NODE_HTTP_CLIENT_REQUEST(node_dtrace_http_client_request_t* req, - node_dtrace_connection_t* conn); -INLINE void NODE_HTTP_CLIENT_RESPONSE(node_dtrace_connection_t* conn); -INLINE void NODE_NET_SERVER_CONNECTION(node_dtrace_connection_t* conn); -INLINE void NODE_NET_STREAM_END(node_dtrace_connection_t* conn); + node_dtrace_connection_t* conn, const char *remote, int port, + const char *method, const char *url, int fd); +INLINE void NODE_HTTP_CLIENT_RESPONSE(node_dtrace_connection_t* conn, + const char *remote, int port, int fd); +INLINE void NODE_NET_SERVER_CONNECTION(node_dtrace_connection_t* conn, + const char *remote, int port, int fd); +INLINE void NODE_NET_STREAM_END(node_dtrace_connection_t* conn, + const char *remote, int port, int fd); INLINE void NODE_GC_START(GCType type, GCCallbackFlags flags); INLINE void NODE_GC_DONE(GCType type, GCCallbackFlags flags); INLINE void NODE_V8SYMBOL_REMOVE(const void* addr1, const void* addr2); @@ -87,4 +93,4 @@ INLINE bool NODE_V8SYMBOL_ENABLED(); #define NODE_NET_SOCKET_READ(arg0, arg1) #define NODE_NET_SOCKET_WRITE(arg0, arg1) } -#endif // SRC_ETW_H_ \ No newline at end of file +#endif // SRC_ETW_H_ From 4716dc662d8d24d4d454dd4459ff724588e98eb1 Mon Sep 17 00:00:00 2001 From: isaacs Date: Wed, 3 Apr 2013 09:43:17 -0700 Subject: [PATCH 17/26] assert: Simplify AssertError creation --- lib/assert.js | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/lib/assert.js b/lib/assert.js index a2afdcfb0ba..078efe39c77 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -38,16 +38,14 @@ var assert = module.exports = ok; // expected: expected }) assert.AssertionError = function AssertionError(options) { - this.name = 'AssertionError'; this.message = options.message; this.actual = options.actual; this.expected = options.expected; this.operator = options.operator; var stackStartFunction = options.stackStartFunction || fail; - if (Error.captureStackTrace) { - Error.captureStackTrace(this, stackStartFunction); - } + this.name = getName(this, options.message); + Error.captureStackTrace(this, stackStartFunction); }; // assert.AssertionError instanceof Error @@ -74,18 +72,16 @@ function truncate(s, n) { } } -assert.AssertionError.prototype.toString = function() { - if (this.message) { - return [this.name + ':', this.message].join(' '); +function getName(self, message) { + if (message) { + return 'AssertionError: ' + message; } else { - return [ - this.name + ':', - truncate(JSON.stringify(this.actual, replacer), 128), - this.operator, - truncate(JSON.stringify(this.expected, replacer), 128) - ].join(' '); + return 'AssertionError: ' + + truncate(JSON.stringify(self.actual, replacer), 128) + ' ' + + self.operator + ' ' + + truncate(JSON.stringify(self.expected, replacer), 128); } -}; +} // At present only the three keys mentioned above are used and // understood by the spec. Implementations or sub modules can pass From 5902bc45c5e52df6ec821df54450acb7d7d7da83 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Tue, 2 Apr 2013 00:07:24 +0400 Subject: [PATCH 18/26] child_process: acknowledge sent handles Fix race-condition when multiple handles are sent and SCM_RIGHTS messages are gets merged by OS by avoiding sending multiple handles at once! fix #4885 --- lib/child_process.js | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/lib/child_process.js b/lib/child_process.js index e67615d21b3..e4fe26ecda7 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -24,6 +24,7 @@ var EventEmitter = require('events').EventEmitter; var net = require('net'); var dgram = require('dgram'); var Process = process.binding('process_wrap').Process; +var assert = require('assert'); var util = require('util'); var constants; // if (!constants) constants = process.binding('constants'); @@ -321,6 +322,7 @@ function handleMessage(target, message, handle) { function setupChannel(target, channel) { target._channel = channel; + target._handleQueue = null; var decoder = new StringDecoder('utf8'); var jsonBuffer = ''; @@ -358,8 +360,22 @@ function setupChannel(target, channel) { // handlers will go through this target.on('internalMessage', function(message, handle) { + // Once acknowledged - continue sending handles. + if (message.cmd === 'NODE_HANDLE_ACK') { + assert(Array.isArray(target._handleQueue)); + var queue = target._handleQueue; + target._handleQueue = null; + queue.forEach(function(args) { + target.send(args.message, args.handle); + }); + return; + } + if (message.cmd !== 'NODE_HANDLE') return; + // Acknowledge handle receival. + target.send({ cmd: 'NODE_HANDLE_ACK' }); + var obj = handleConversion[message.type]; // Update simultaneous accepts on Windows @@ -389,6 +405,7 @@ function setupChannel(target, channel) { // this message will be handled by an internalMessage event handler message = { cmd: 'NODE_HANDLE', + type: null, msg: message }; @@ -407,6 +424,12 @@ function setupChannel(target, channel) { throw new TypeError("This handle type can't be sent"); } + // Queue-up message and handle if we haven't received ACK yet. + if (this._handleQueue) { + this._handleQueue.push({ message: message.msg, handle: handle }); + return; + } + var obj = handleConversion[message.type]; // convert TCP object to native handle object @@ -416,6 +439,10 @@ function setupChannel(target, channel) { if (obj.simultaneousAccepts) { net._setSimultaneousAccepts(handle); } + } else if (this._handleQueue) { + // Queue request anyway to avoid out-of-order messages. + this._handleQueue.push({ message: message, handle: null }); + return; } var string = JSON.stringify(message) + '\n'; @@ -426,6 +453,8 @@ function setupChannel(target, channel) { 'write', 'cannot write to IPC channel.'); this.emit('error', er); + } else if (handle && !this._handleQueue) { + this._handleQueue = []; } if (obj && obj.postSend) { From b319264d849d4149c757b4978f56dd5ae7662b6c Mon Sep 17 00:00:00 2001 From: isaacs Date: Wed, 3 Apr 2013 10:01:50 -0700 Subject: [PATCH 19/26] test: fork-getconnections stricter, less chatty --- .../test-child-process-fork-getconnections.js | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/test/simple/test-child-process-fork-getconnections.js b/test/simple/test-child-process-fork-getconnections.js index ad04dd73362..597c23fd2b7 100644 --- a/test/simple/test-child-process-fork-getconnections.js +++ b/test/simple/test-child-process-fork-getconnections.js @@ -30,8 +30,14 @@ if (process.argv[2] === 'child') { var id = process.argv[3]; process.on('message', function(m, socket) { - if (socket) { + if (m.cmd === 'new') { + assert(socket); + assert(socket instanceof net.Socket, 'should be a net.Socket'); sockets.push(socket); + socket.on('end', function() { + if (!this.closingOnPurpose) + throw new Error('[c] closing by accident! ' + process._errno); + }); } if (m.cmd === 'close') { @@ -42,9 +48,15 @@ if (process.argv[2] === 'child') { sockets[m.id].destroy(); } }); + } else { var child = fork(process.argv[1], ['child']); + child.on('exit', function(code, signal) { + if (!childKilled) + throw new Error('child died unexpectedly!'); + }); + var server = net.createServer(); var sockets = []; var sent = 0; @@ -55,29 +67,31 @@ if (process.argv[2] === 'child') { if (sockets.length === count) { closeSockets(0); - server.close(); } }); var disconnected = 0; + var clients = []; server.on('listening', function() { - var j = count, client; while (j--) { client = net.connect(common.PORT, '127.0.0.1'); + client.id = j; client.on('close', function() { - console.error('[m] CLIENT: close event'); disconnected += 1; }); - // XXX This resume() should be unnecessary. - // a stream high water mark should be enough to keep - // consuming the input. - client.resume(); + clients.push(client); } }); + var childKilled = false; function closeSockets(i) { - if (i === count) return; + if (i === count) { + childKilled = true; + server.close(); + child.kill(); + return; + } sent++; child.send({ id: i, cmd: 'close' }); @@ -91,10 +105,7 @@ if (process.argv[2] === 'child') { var closeEmitted = false; server.on('close', function() { - console.error('[m] server close'); closeEmitted = true; - - child.kill(); }); server.listen(common.PORT, '127.0.0.1'); @@ -103,5 +114,6 @@ if (process.argv[2] === 'child') { assert.equal(sent, count); assert.equal(disconnected, count); assert.ok(closeEmitted); + console.log('ok'); }); } From d46ebffb66edea43d17f4a9799ccd9dba21c4000 Mon Sep 17 00:00:00 2001 From: isaacs Date: Wed, 3 Apr 2013 10:17:04 -0700 Subject: [PATCH 20/26] npm: Upgrade to 1.2.17 --- deps/npm/html/api/bin.html | 2 +- deps/npm/html/api/bugs.html | 2 +- deps/npm/html/api/commands.html | 2 +- deps/npm/html/api/config.html | 2 +- deps/npm/html/api/deprecate.html | 2 +- deps/npm/html/api/docs.html | 2 +- deps/npm/html/api/edit.html | 2 +- deps/npm/html/api/explore.html | 2 +- deps/npm/html/api/help-search.html | 2 +- deps/npm/html/api/init.html | 2 +- deps/npm/html/api/install.html | 2 +- deps/npm/html/api/link.html | 2 +- deps/npm/html/api/load.html | 2 +- deps/npm/html/api/ls.html | 2 +- deps/npm/html/api/npm.html | 4 +- deps/npm/html/api/outdated.html | 2 +- deps/npm/html/api/owner.html | 2 +- deps/npm/html/api/pack.html | 2 +- deps/npm/html/api/prefix.html | 2 +- deps/npm/html/api/prune.html | 2 +- deps/npm/html/api/publish.html | 2 +- deps/npm/html/api/rebuild.html | 2 +- deps/npm/html/api/restart.html | 2 +- deps/npm/html/api/root.html | 2 +- deps/npm/html/api/run-script.html | 2 +- deps/npm/html/api/search.html | 2 +- deps/npm/html/api/shrinkwrap.html | 2 +- deps/npm/html/api/start.html | 2 +- deps/npm/html/api/stop.html | 2 +- deps/npm/html/api/submodule.html | 2 +- deps/npm/html/api/tag.html | 2 +- deps/npm/html/api/test.html | 2 +- deps/npm/html/api/uninstall.html | 2 +- deps/npm/html/api/unpublish.html | 2 +- deps/npm/html/api/update.html | 2 +- deps/npm/html/api/version.html | 2 +- deps/npm/html/api/view.html | 2 +- deps/npm/html/api/whoami.html | 2 +- deps/npm/html/doc/README.html | 2 +- deps/npm/html/doc/adduser.html | 2 +- deps/npm/html/doc/bin.html | 2 +- deps/npm/html/doc/bugs.html | 2 +- deps/npm/html/doc/build.html | 2 +- deps/npm/html/doc/bundle.html | 2 +- deps/npm/html/doc/cache.html | 2 +- deps/npm/html/doc/changelog.html | 2 +- deps/npm/html/doc/coding-style.html | 2 +- deps/npm/html/doc/completion.html | 2 +- deps/npm/html/doc/config.html | 2 +- deps/npm/html/doc/dedupe.html | 2 +- deps/npm/html/doc/deprecate.html | 2 +- deps/npm/html/doc/developers.html | 2 +- deps/npm/html/doc/disputes.html | 2 +- deps/npm/html/doc/docs.html | 2 +- deps/npm/html/doc/edit.html | 2 +- deps/npm/html/doc/explore.html | 2 +- deps/npm/html/doc/faq.html | 2 +- deps/npm/html/doc/folders.html | 2 +- deps/npm/html/doc/global.html | 2 +- deps/npm/html/doc/help-search.html | 2 +- deps/npm/html/doc/help.html | 2 +- deps/npm/html/doc/index.html | 2 +- deps/npm/html/doc/init.html | 2 +- deps/npm/html/doc/install.html | 2 +- deps/npm/html/doc/json.html | 2 +- deps/npm/html/doc/link.html | 2 +- deps/npm/html/doc/ls.html | 4 +- deps/npm/html/doc/npm.html | 4 +- deps/npm/html/doc/outdated.html | 2 +- deps/npm/html/doc/owner.html | 2 +- deps/npm/html/doc/pack.html | 2 +- deps/npm/html/doc/prefix.html | 2 +- deps/npm/html/doc/prune.html | 2 +- deps/npm/html/doc/publish.html | 2 +- deps/npm/html/doc/rebuild.html | 2 +- deps/npm/html/doc/registry.html | 2 +- deps/npm/html/doc/removing-npm.html | 2 +- deps/npm/html/doc/restart.html | 2 +- deps/npm/html/doc/rm.html | 2 +- deps/npm/html/doc/root.html | 2 +- deps/npm/html/doc/run-script.html | 2 +- deps/npm/html/doc/scripts.html | 2 +- deps/npm/html/doc/search.html | 2 +- deps/npm/html/doc/semver.html | 2 +- deps/npm/html/doc/shrinkwrap.html | 2 +- deps/npm/html/doc/star.html | 2 +- deps/npm/html/doc/stars.html | 2 +- deps/npm/html/doc/start.html | 2 +- deps/npm/html/doc/stop.html | 2 +- deps/npm/html/doc/submodule.html | 2 +- deps/npm/html/doc/tag.html | 2 +- deps/npm/html/doc/test.html | 2 +- deps/npm/html/doc/uninstall.html | 2 +- deps/npm/html/doc/unpublish.html | 2 +- deps/npm/html/doc/update.html | 2 +- deps/npm/html/doc/version.html | 2 +- deps/npm/html/doc/view.html | 2 +- deps/npm/html/doc/whoami.html | 2 +- deps/npm/lib/build.js | 2 +- deps/npm/man/man1/README.1 | 2 +- deps/npm/man/man1/adduser.1 | 2 +- deps/npm/man/man1/bin.1 | 2 +- deps/npm/man/man1/bugs.1 | 2 +- deps/npm/man/man1/build.1 | 2 +- deps/npm/man/man1/bundle.1 | 2 +- deps/npm/man/man1/cache.1 | 2 +- deps/npm/man/man1/changelog.1 | 2 +- deps/npm/man/man1/coding-style.1 | 2 +- deps/npm/man/man1/completion.1 | 2 +- deps/npm/man/man1/config.1 | 2 +- deps/npm/man/man1/dedupe.1 | 2 +- deps/npm/man/man1/deprecate.1 | 2 +- deps/npm/man/man1/developers.1 | 2 +- deps/npm/man/man1/disputes.1 | 2 +- deps/npm/man/man1/docs.1 | 2 +- deps/npm/man/man1/edit.1 | 2 +- deps/npm/man/man1/explore.1 | 2 +- deps/npm/man/man1/faq.1 | 2 +- deps/npm/man/man1/folders.1 | 2 +- deps/npm/man/man1/global.1 | 2 +- deps/npm/man/man1/help-search.1 | 2 +- deps/npm/man/man1/help.1 | 2 +- deps/npm/man/man1/index.1 | 2 +- deps/npm/man/man1/init.1 | 2 +- deps/npm/man/man1/install.1 | 2 +- deps/npm/man/man1/json.1 | 2 +- deps/npm/man/man1/link.1 | 2 +- deps/npm/man/man1/ls.1 | 4 +- deps/npm/man/man1/npm.1 | 4 +- deps/npm/man/man1/outdated.1 | 2 +- deps/npm/man/man1/owner.1 | 2 +- deps/npm/man/man1/pack.1 | 2 +- deps/npm/man/man1/prefix.1 | 2 +- deps/npm/man/man1/prune.1 | 2 +- deps/npm/man/man1/publish.1 | 2 +- deps/npm/man/man1/rebuild.1 | 2 +- deps/npm/man/man1/registry.1 | 2 +- deps/npm/man/man1/removing-npm.1 | 2 +- deps/npm/man/man1/restart.1 | 2 +- deps/npm/man/man1/rm.1 | 2 +- deps/npm/man/man1/root.1 | 2 +- deps/npm/man/man1/run-script.1 | 2 +- deps/npm/man/man1/scripts.1 | 2 +- deps/npm/man/man1/search.1 | 2 +- deps/npm/man/man1/semver.1 | 2 +- deps/npm/man/man1/shrinkwrap.1 | 2 +- deps/npm/man/man1/star.1 | 2 +- deps/npm/man/man1/stars.1 | 2 +- deps/npm/man/man1/start.1 | 2 +- deps/npm/man/man1/stop.1 | 2 +- deps/npm/man/man1/submodule.1 | 2 +- deps/npm/man/man1/tag.1 | 2 +- deps/npm/man/man1/test.1 | 2 +- deps/npm/man/man1/uninstall.1 | 2 +- deps/npm/man/man1/unpublish.1 | 2 +- deps/npm/man/man1/update.1 | 2 +- deps/npm/man/man1/version.1 | 2 +- deps/npm/man/man1/view.1 | 2 +- deps/npm/man/man1/whoami.1 | 2 +- deps/npm/man/man3/bin.3 | 2 +- deps/npm/man/man3/bugs.3 | 2 +- deps/npm/man/man3/commands.3 | 2 +- deps/npm/man/man3/config.3 | 2 +- deps/npm/man/man3/deprecate.3 | 2 +- deps/npm/man/man3/docs.3 | 2 +- deps/npm/man/man3/edit.3 | 2 +- deps/npm/man/man3/explore.3 | 2 +- deps/npm/man/man3/help-search.3 | 2 +- deps/npm/man/man3/init.3 | 2 +- deps/npm/man/man3/install.3 | 2 +- deps/npm/man/man3/link.3 | 2 +- deps/npm/man/man3/load.3 | 2 +- deps/npm/man/man3/ls.3 | 2 +- deps/npm/man/man3/npm.3 | 4 +- deps/npm/man/man3/outdated.3 | 2 +- deps/npm/man/man3/owner.3 | 2 +- deps/npm/man/man3/pack.3 | 2 +- deps/npm/man/man3/prefix.3 | 2 +- deps/npm/man/man3/prune.3 | 2 +- deps/npm/man/man3/publish.3 | 2 +- deps/npm/man/man3/rebuild.3 | 2 +- deps/npm/man/man3/restart.3 | 2 +- deps/npm/man/man3/root.3 | 2 +- deps/npm/man/man3/run-script.3 | 2 +- deps/npm/man/man3/search.3 | 2 +- deps/npm/man/man3/shrinkwrap.3 | 2 +- deps/npm/man/man3/start.3 | 2 +- deps/npm/man/man3/stop.3 | 2 +- deps/npm/man/man3/submodule.3 | 2 +- deps/npm/man/man3/tag.3 | 2 +- deps/npm/man/man3/test.3 | 2 +- deps/npm/man/man3/uninstall.3 | 2 +- deps/npm/man/man3/unpublish.3 | 2 +- deps/npm/man/man3/update.3 | 2 +- deps/npm/man/man3/version.3 | 2 +- deps/npm/man/man3/view.3 | 2 +- deps/npm/man/man3/whoami.3 | 2 +- deps/npm/node_modules/cmd-shim/.npmignore | 16 ++ deps/npm/node_modules/cmd-shim/.travis.yml | 4 + deps/npm/node_modules/cmd-shim/LICENSE | 27 +++ deps/npm/node_modules/cmd-shim/README.md | 42 ++++ deps/npm/node_modules/cmd-shim/index.js | 180 ++++++++++++++++++ deps/npm/node_modules/cmd-shim/package.json | 28 +++ .../node_modules/cmd-shim/test/00-setup.js | 34 ++++ deps/npm/node_modules/cmd-shim/test/basic.js | 167 ++++++++++++++++ .../node_modules/cmd-shim/test/zz-cleanup.js | 13 ++ .../node-gyp/gyp/pylib/gyp/generator/make.py | 2 +- .../node-gyp/gyp/pylib/gyp/generator/ninja.py | 2 +- deps/npm/node_modules/node-gyp/package.json | 10 +- deps/npm/package.json | 8 +- 210 files changed, 726 insertions(+), 213 deletions(-) create mode 100644 deps/npm/node_modules/cmd-shim/.npmignore create mode 100644 deps/npm/node_modules/cmd-shim/.travis.yml create mode 100644 deps/npm/node_modules/cmd-shim/LICENSE create mode 100644 deps/npm/node_modules/cmd-shim/README.md create mode 100644 deps/npm/node_modules/cmd-shim/index.js create mode 100644 deps/npm/node_modules/cmd-shim/package.json create mode 100644 deps/npm/node_modules/cmd-shim/test/00-setup.js create mode 100644 deps/npm/node_modules/cmd-shim/test/basic.js create mode 100644 deps/npm/node_modules/cmd-shim/test/zz-cleanup.js diff --git a/deps/npm/html/api/bin.html b/deps/npm/html/api/bin.html index 7408820b374..8585991398e 100644 --- a/deps/npm/html/api/bin.html +++ b/deps/npm/html/api/bin.html @@ -19,7 +19,7 @@

This function should not be used programmatically. Instead, just refer to the npm.bin member.

- +