From 4d1e9e537029806cf873f21e41e92830c757e5cf Mon Sep 17 00:00:00 2001 From: isaacs Date: Fri, 8 Mar 2013 21:52:09 -0800 Subject: [PATCH 01/27] Now working on 0.10.0 --- src/node_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node_version.h b/src/node_version.h index 335892cb78..654fc54b7b 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -23,8 +23,8 @@ #define NODE_VERSION_H #define NODE_MAJOR_VERSION 0 -#define NODE_MINOR_VERSION 9 -#define NODE_PATCH_VERSION 13 +#define NODE_MINOR_VERSION 10 +#define NODE_PATCH_VERSION 0 #ifndef NODE_TAG # define NODE_TAG "" From 80472bc301234d9dc4142e62bbffc4300fffdd83 Mon Sep 17 00:00:00 2001 From: isaacs Date: Sat, 9 Mar 2013 07:00:21 -0800 Subject: [PATCH 02/27] domain: Fix double-exit on nested domains Minor oversight in fix for #4953. --- src/node.js | 4 ++- test/simple/test-domain-nested-throw.js | 42 ++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/node.js b/src/node.js index 9d6e75eef7..49aedaee00 100644 --- a/src/node.js +++ b/src/node.js @@ -258,7 +258,9 @@ // The domain error handler threw! oh no! // See if another domain can catch THIS error, // or else crash on the original one. - domainStack.pop(); + // If the user already exited it, then don't double-exit. + if (domain === domainModule.active) + domainStack.pop(); if (domainStack.length) { var parentDomain = domainStack[domainStack.length - 1]; process.domain = domainModule.active = parentDomain; diff --git a/test/simple/test-domain-nested-throw.js b/test/simple/test-domain-nested-throw.js index e1d3bb2d9c..e119486675 100644 --- a/test/simple/test-domain-nested-throw.js +++ b/test/simple/test-domain-nested-throw.js @@ -24,6 +24,34 @@ var assert = require('assert'); var domain = require('domain'); +var dispose; +switch (process.argv[2]) { + case 'true': + dispose = true; + break; + case 'false': + dispose = false; + break; + default: + parent(); + return; +} + +function parent() { + var node = process.execPath; + var spawn = require('child_process').spawn; + var opt = { stdio: 'inherit' }; + var child = spawn(node, [__filename, 'true'], opt); + child.on('exit', function(c) { + assert(!c); + child = spawn(node, [__filename, 'false'], opt); + child.on('exit', function(c) { + assert(!c); + console.log('ok'); + }); + }); +} + var gotDomain1Error = false; var gotDomain2Error = false; @@ -44,8 +72,11 @@ function inner(throw1, throw2) { var domain1 = domain.createDomain(); domain1.on('error', function (err) { - console.error('domain 1 error'); - if (gotDomain1Error) process.exit(1); + if (gotDomain1Error) { + console.error('got domain 1 twice'); + process.exit(1); + } + if (dispose) domain1.dispose(); gotDomain1Error = true; throw2(); }); @@ -59,7 +90,10 @@ function outer() { var domain2 = domain.createDomain(); domain2.on('error', function (err) { - console.error('domain 2 error'); + if (gotDomain2Error) { + console.error('got domain 2 twice'); + process.exit(1); + } gotDomain2Error = true; }); @@ -73,7 +107,7 @@ process.on('exit', function() { assert(gotDomain2Error); assert(threw1); assert(threw2); - console.log('ok'); + console.log('ok', dispose); }); outer(); From 7becf156a92180c9b6455f60b143e18729592dfb Mon Sep 17 00:00:00 2001 From: Andreas Madsen Date: Tue, 26 Feb 2013 18:26:09 +0100 Subject: [PATCH 03/27] timers: consistent this keyword in setImmediate When calling setImmediate with extra arguments the this keyword in the callback would refer to the global object, but when not calling setImmediate with extra arguments this would refer to the returned handle object. This commit fixes that inconsistency so its always set handle object. The handle object was chosen for performance reasons. --- lib/timers.js | 2 +- test/simple/test-timers-this.js | 64 +++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 test/simple/test-timers-this.js diff --git a/lib/timers.js b/lib/timers.js index 68890ab9f7..989050538e 100644 --- a/lib/timers.js +++ b/lib/timers.js @@ -324,7 +324,7 @@ exports.setImmediate = function(callback) { args = Array.prototype.slice.call(arguments, 1); immediate._onImmediate = function() { - callback.apply(null, args); + callback.apply(immediate, args); }; } diff --git a/test/simple/test-timers-this.js b/test/simple/test-timers-this.js new file mode 100644 index 0000000000..3d23e61dff --- /dev/null +++ b/test/simple/test-timers-this.js @@ -0,0 +1,64 @@ +// 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 assert = require('assert'); + +var immediateThis, intervalThis, timeoutThis, + immediateArgsThis, intervalArgsThis, timeoutArgsThis; + +var immediateHandler = setImmediate(function () { + immediateThis = this; +}); + +var immediateArgsHandler = setImmediate(function () { + immediateArgsThis = this; +}, "args ..."); + +var intervalHandler = setInterval(function () { + clearInterval(intervalHandler); + + intervalThis = this; +}); + +var intervalArgsHandler = setInterval(function () { + clearInterval(intervalArgsHandler); + + intervalArgsThis = this; +}, 0, "args ..."); + +var timeoutHandler = setTimeout(function () { + timeoutThis = this; +}); + +var timeoutArgsHandler = setTimeout(function () { + timeoutArgsThis = this; +}, 0, "args ..."); + +process.once('exit', function () { + assert.strictEqual(immediateThis, immediateHandler); + assert.strictEqual(immediateArgsThis, immediateArgsHandler); + + assert.strictEqual(intervalThis, intervalHandler); + assert.strictEqual(intervalArgsThis, intervalArgsHandler); + + assert.strictEqual(timeoutThis, timeoutHandler); + assert.strictEqual(timeoutArgsThis, timeoutArgsHandler); +}); From 5757ce48b41eaa0bfff89b3b9bc6f8f4ebbfeb53 Mon Sep 17 00:00:00 2001 From: hc Date: Fri, 8 Mar 2013 06:07:27 -0500 Subject: [PATCH 04/27] http: check if incoming parser has already been freed Fix #4948 This adds a check before setting the incoming parser to null. Under certain circumstances it'll already be set to null by freeParser(). Otherwise this will cause node to crash as it tries to set null on something that is already null. --- lib/http.js | 2 +- test/simple/test-regress-GH-4948.js | 62 +++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 test/simple/test-regress-GH-4948.js diff --git a/lib/http.js b/lib/http.js index aafbe5f60f..1f52d31514 100644 --- a/lib/http.js +++ b/lib/http.js @@ -420,7 +420,7 @@ IncomingMessage.prototype._dump = function() { return; this._dumped = true; - this.socket.parser.incoming = null; + if (this.socket.parser) this.socket.parser.incoming = null; this.push(null); readStart(this.socket); }; diff --git a/test/simple/test-regress-GH-4948.js b/test/simple/test-regress-GH-4948.js new file mode 100644 index 0000000000..5e717fad56 --- /dev/null +++ b/test/simple/test-regress-GH-4948.js @@ -0,0 +1,62 @@ +// 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. + +// https://github.com/joyent/node/issues/4948 + +var common = require('../common'); +var http = require('http'); + +var reqCount = 0; +var server = http.createServer(function(serverReq, serverRes){ + if (reqCount) { + serverRes.end(); + server.close(); + return; + } + reqCount = 1; + + + // normally the use case would be to call an external site + // does not require connecting locally or to itself to fail + var r = http.request({hostname: 'localhost', port: common.PORT}, function(res) { + // required, just needs to be in the client response somewhere + serverRes.end(); + + // required for test to fail + res.on('data', function(data) { }); + + }); + r.on('error', function(e) {}); + r.end(); + + serverRes.write('some data'); +}).listen(common.PORT); + +// simulate a client request that closes early +var net = require('net'); + +var sock = new net.Socket(); +sock.connect(common.PORT, 'localhost'); + +sock.on('connect', function() { + sock.write('GET / HTTP/1.1\r\n\r\n'); + sock.end(); +}); \ No newline at end of file From 31b5d41f57cb717c14a29d789f1c0c1bb40a8bca Mon Sep 17 00:00:00 2001 From: isaacs Date: Sat, 9 Mar 2013 09:11:22 -0800 Subject: [PATCH 05/27] npm: Upgrade to 1.2.14 (fixed) --- deps/npm/lib/search.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/deps/npm/lib/search.js b/deps/npm/lib/search.js index 3e9bdb15f7..edbdc70b13 100644 --- a/deps/npm/lib/search.js +++ b/deps/npm/lib/search.js @@ -86,6 +86,7 @@ function stripData (data) { }) , url: !Object.keys(data.versions || {}).length ? data.url : null , keywords: data.keywords || [] + , version: Object.keys(data.versions)[0] || [] , time: data.time && data.time.modified && (new Date(data.time.modified).toISOString() @@ -142,18 +143,19 @@ function prettify (data, args) { var longest = [] , spaces , maxLen = npm.config.get("description") - ? [20, 60, 20, 20, Infinity] - : [20, 20, 20, Infinity] + ? [20, 60, 20, 20, 10, Infinity] + : [20, 20, 20, 10, Infinity] , headings = npm.config.get("description") - ? ["NAME", "DESCRIPTION", "AUTHOR", "DATE", "KEYWORDS"] - : ["NAME", "AUTHOR", "DATE", "KEYWORDS"] + ? ["NAME", "DESCRIPTION", "AUTHOR", "DATE", "VERSION", "KEYWORDS"] + : ["NAME", "AUTHOR", "DATE", "VERSION", "KEYWORDS"] , lines , searchsort = (npm.config.get("searchsort") || "NAME").toLowerCase() , sortFields = { name: 0 , description: 1 , author: 2 , date: 3 - , keywords: 4 } + , version: 4 + , keywords: 5 } , searchRev = searchsort.charAt(0) === "-" , sortField = sortFields[searchsort.replace(/^\-+/, "")] @@ -171,6 +173,7 @@ function prettify (data, args) { , data.description || "" , data.maintainers.join(" ") , data.time + , data.version || "" , (data.keywords || []).join(" ") ] l.forEach(function (s, i) { From 12713c3bb781c854f347ea9a04e344e980bea2f1 Mon Sep 17 00:00:00 2001 From: isaacs Date: Sat, 9 Mar 2013 09:22:00 -0800 Subject: [PATCH 06/27] win/msi: Fix typos --- tools/msvs/msi/product.wxs | 14 +++++++------- tools/msvs/nodevars.bat | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/msvs/msi/product.wxs b/tools/msvs/msi/product.wxs index 2e8ef742b5..baaa0148be 100755 --- a/tools/msvs/msi/product.wxs +++ b/tools/msvs/msi/product.wxs @@ -65,8 +65,8 @@ + Title="npm package manager" + Description="Install npm, the recommended package manager for Node.js."> @@ -83,18 +83,18 @@ + Description="Add Node, npm, and modules that were globally installed by npm to the PATH environment variable."> + Title="Node and npm" + Description="Add Node and npm (if installed) to the PATH environment variable."> + Title="npm modules" + Description="Add modules that are installed globally by npm to the PATH environment variable. This option works for the current user only; other users need to update their PATH manually."> diff --git a/tools/msvs/nodevars.bat b/tools/msvs/nodevars.bat index b79bc823bc..064f83cbc8 100644 --- a/tools/msvs/nodevars.bat +++ b/tools/msvs/nodevars.bat @@ -1,6 +1,6 @@ @echo off -rem Ensure this Node.js and NPM are first in the PATH +rem Ensure this Node.js and npm are first in the PATH set PATH=%APPDATA%\npm;%~dp0;%PATH% setlocal enabledelayedexpansion @@ -12,7 +12,7 @@ for /F "usebackq delims=" %%v in (`%print_version%`) do set version=%%v rem Print message. if exist npm.cmd ( - echo Your environment has been set up for using Node.js !version! and NPM. + echo Your environment has been set up for using Node.js !version! and npm. ) else ( echo Your environment has been set up for using Node.js !version!. ) From 21a99664aedb12e06de6d5f6e5c76ad4811e6587 Mon Sep 17 00:00:00 2001 From: isaacs Date: Sat, 9 Mar 2013 18:34:59 -0800 Subject: [PATCH 07/27] uv: Upgrade to 5462dab --- deps/uv/src/win/pipe.c | 2 +- deps/uv/src/win/tcp.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index 2436b036f9..0fb70eae32 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -915,7 +915,7 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) { } else { memset(&req->overlapped, 0, sizeof(req->overlapped)); if (handle->flags & UV_HANDLE_EMULATE_IOCP) { - req->overlapped.hEvent = (HANDLE) ((DWORD) req->event_handle | 1); + req->overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1); } /* Do 0-read */ diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index 7158216131..c3ef6533d5 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -113,7 +113,8 @@ static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle, non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv4; } - if (pSetFileCompletionNotificationModes && !non_ifs_lsp) { + if (pSetFileCompletionNotificationModes && + !(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) { if (pSetFileCompletionNotificationModes((HANDLE) socket, FILE_SKIP_SET_EVENT_ON_HANDLE | FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { From e2400f88d85f67fb241a30f8f527f60f464bc04c Mon Sep 17 00:00:00 2001 From: isaacs Date: Sat, 9 Mar 2013 18:46:39 -0800 Subject: [PATCH 08/27] http: Do not setTimeout a not-yet-existent socket Fixes #4967 --- lib/http.js | 11 ++++- .../test-http-server-timeout-pipeline.js | 48 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 test/simple/test-http-server-timeout-pipeline.js diff --git a/lib/http.js b/lib/http.js index 1f52d31514..2f4bcc51e2 100644 --- a/lib/http.js +++ b/lib/http.js @@ -445,6 +445,9 @@ function OutgoingMessage() { this.finished = false; this._hangupClose = false; + + this.socket = null; + this.connection = null; } util.inherits(OutgoingMessage, Stream); @@ -455,7 +458,12 @@ exports.OutgoingMessage = OutgoingMessage; OutgoingMessage.prototype.setTimeout = function(msecs, callback) { if (callback) this.on('timeout', callback); - this.socket.setTimeout(msecs); + if (!this.socket) { + this.once('socket', function(socket) { + socket.setTimeout(msecs); + }); + } else + this.socket.setTimeout(msecs); }; @@ -1056,6 +1064,7 @@ ServerResponse.prototype.assignSocket = function(socket) { socket.on('close', onServerResponseClose); this.socket = socket; this.connection = socket; + this.emit('socket', socket); this._flush(); }; diff --git a/test/simple/test-http-server-timeout-pipeline.js b/test/simple/test-http-server-timeout-pipeline.js new file mode 100644 index 0000000000..0e4d41e6f1 --- /dev/null +++ b/test/simple/test-http-server-timeout-pipeline.js @@ -0,0 +1,48 @@ +// 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'); + +var http = require('http'); +var net = require('net'); + +var server = http.createServer(function(req, res) { + console.log('get', req.url); + res.setTimeout(100, function() { + console.log('timeout on response', req.url); + }); + req.on('end', function() { + console.log('end', req.url); + }); +}).listen(3000, function() { + var c = net.connect(3000, function() { + c.write('GET /1 HTTP/1.1\r\n' + + 'Host: localhost\r\n\r\n'); + c.write('GET /2 HTTP/1.1\r\n' + + 'Host: localhost\r\n\r\n'); + }); +}); +server.setTimeout(200, function(socket) { + console.log('timeout on server'); + socket.destroy(); + server.close(); +}); From c9a4ec9c6392fefa7ce6c66168f4c535ea0702e1 Mon Sep 17 00:00:00 2001 From: koichik Date: Sun, 10 Mar 2013 20:10:19 +0900 Subject: [PATCH 09/27] http: ServerRequest does not timeout after 'end' Fixes #4967 --- lib/http.js | 2 +- .../test-http-server-timeout-pipeline.js | 48 ----------- test/simple/test-http-set-timeout-server.js | 86 ++++++++++++++++++- 3 files changed, 86 insertions(+), 50 deletions(-) delete mode 100644 test/simple/test-http-server-timeout-pipeline.js diff --git a/lib/http.js b/lib/http.js index 2f4bcc51e2..0f7ea853c0 100644 --- a/lib/http.js +++ b/lib/http.js @@ -1873,7 +1873,7 @@ function connectionListener(socket) { socket.setTimeout(self.timeout); socket.on('timeout', function() { var req = socket.parser && socket.parser.incoming; - var reqTimeout = req && req.emit('timeout', socket); + var reqTimeout = req && !req.complete && req.emit('timeout', socket); var res = socket._httpMessage; var resTimeout = res && res.emit('timeout', socket); var serverTimeout = self.emit('timeout', socket); diff --git a/test/simple/test-http-server-timeout-pipeline.js b/test/simple/test-http-server-timeout-pipeline.js deleted file mode 100644 index 0e4d41e6f1..0000000000 --- a/test/simple/test-http-server-timeout-pipeline.js +++ /dev/null @@ -1,48 +0,0 @@ -// 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'); - -var http = require('http'); -var net = require('net'); - -var server = http.createServer(function(req, res) { - console.log('get', req.url); - res.setTimeout(100, function() { - console.log('timeout on response', req.url); - }); - req.on('end', function() { - console.log('end', req.url); - }); -}).listen(3000, function() { - var c = net.connect(3000, function() { - c.write('GET /1 HTTP/1.1\r\n' + - 'Host: localhost\r\n\r\n'); - c.write('GET /2 HTTP/1.1\r\n' + - 'Host: localhost\r\n\r\n'); - }); -}); -server.setTimeout(200, function(socket) { - console.log('timeout on server'); - socket.destroy(); - server.close(); -}); diff --git a/test/simple/test-http-set-timeout-server.js b/test/simple/test-http-set-timeout-server.js index 21be505b70..ff4144963a 100644 --- a/test/simple/test-http-set-timeout-server.js +++ b/test/simple/test-http-set-timeout-server.js @@ -22,6 +22,7 @@ var common = require('../common.js'); var assert = require('assert'); var http = require('http'); +var net = require('net'); var tests = []; @@ -73,7 +74,10 @@ test(function serverRequestTimeout(cb) { }); }); server.listen(common.PORT); - http.get({ port: common.PORT }).on('error', function() {}); + var req = http.request({ port: common.PORT, method: 'POST' }); + req.on('error', function() {}); + req.write('Hello'); + // req is in progress }); test(function serverResponseTimeout(cb) { @@ -93,3 +97,83 @@ test(function serverResponseTimeout(cb) { server.listen(common.PORT); http.get({ port: common.PORT }).on('error', function() {}); }); + +test(function serverRequestNotTimeoutAfterEnd(cb) { + var caughtTimeoutOnRequest = false; + var caughtTimeoutOnResponse = false; + process.on('exit', function() { + assert(!caughtTimeoutOnRequest); + assert(caughtTimeoutOnResponse); + }); + var server = http.createServer(function(req, res) { + // just do nothing, we should get a timeout event. + req.setTimeout(50, function(socket) { + caughtTimeoutOnRequest = true; + }); + res.on('timeout', function(socket) { + caughtTimeoutOnResponse = true; + }); + }); + server.on('timeout', function(socket) { + socket.destroy(); + server.close(); + cb(); + }); + server.listen(common.PORT); + http.get({ port: common.PORT }).on('error', function() {}); +}); + +test(function serverResponseTimeoutWithPipeline(cb) { + var caughtTimeout = ''; + process.on('exit', function() { + assert.equal(caughtTimeout, '/2'); + }); + var server = http.createServer(function(req, res) { + res.setTimeout(50, function() { + caughtTimeout += req.url; + }); + if (req.url === '/1') res.end(); + }); + server.on('timeout', function(socket) { + socket.destroy(); + server.close(); + cb(); + }); + server.listen(common.PORT); + var c = net.connect({ port: common.PORT, allowHalfOpen: true }, function() { + c.write('GET /1 HTTP/1.1\r\nHost: localhost\r\n\r\n'); + c.write('GET /2 HTTP/1.1\r\nHost: localhost\r\n\r\n'); + c.write('GET /3 HTTP/1.1\r\nHost: localhost\r\n\r\n'); + }); +}); + +test(function idleTimeout(cb) { + var caughtTimeoutOnRequest = false; + var caughtTimeoutOnResponse = false; + var caughtTimeoutOnServer = false; + process.on('exit', function() { + assert(!caughtTimeoutOnRequest); + assert(!caughtTimeoutOnResponse); + assert(caughtTimeoutOnServer); + }); + var server = http.createServer(function(req, res) { + req.on('timeout', function(socket) { + caughtTimeoutOnRequest = true; + }); + res.on('timeout', function(socket) { + caughtTimeoutOnResponse = true; + }); + res.end(); + }); + server.setTimeout(50, function(socket) { + caughtTimeoutOnServer = true; + socket.destroy(); + server.close(); + cb(); + }); + server.listen(common.PORT); + var c = net.connect({ port: common.PORT, allowHalfOpen: true }, function() { + c.write('GET /1 HTTP/1.1\r\nHost: localhost\r\n\r\n'); + // Keep-Alive + }); +}); From 738347b90433a38538ab298bf38860e83a4abc53 Mon Sep 17 00:00:00 2001 From: Julian Gruber Date: Fri, 8 Mar 2013 19:41:28 +0100 Subject: [PATCH 10/27] events: Handle missing error obj when domains in use so `ee.emit('error')` doesn't throw when domains are active create an empty error only when handled by a domain test for when no error is provided to an error event --- lib/events.js | 1 + ...mitter-no-error-provided-to-error-event.js | 42 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 test/simple/test-event-emitter-no-error-provided-to-error-event.js diff --git a/lib/events.js b/lib/events.js index 73b78b20da..38422dab0f 100644 --- a/lib/events.js +++ b/lib/events.js @@ -63,6 +63,7 @@ EventEmitter.prototype.emit = function(type) { !this._events.error.length)) { er = arguments[1]; if (this.domain) { + if (!er) er = new TypeError('Uncaught, unspecified "error" event.'); er.domainEmitter = this; er.domain = this.domain; er.domainThrown = false; diff --git a/test/simple/test-event-emitter-no-error-provided-to-error-event.js b/test/simple/test-event-emitter-no-error-provided-to-error-event.js new file mode 100644 index 0000000000..92d9f8ad01 --- /dev/null +++ b/test/simple/test-event-emitter-no-error-provided-to-error-event.js @@ -0,0 +1,42 @@ +// 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'); +var events = require('events'); +var domain = require('domain'); + +var errorCatched = false; + +var e = new events.EventEmitter(); + +var d = domain.create(); +d.add(e); +d.on('error', function (er) { + assert(er instanceof TypeError, 'type error created'); + errorCatched = true; +}); + +e.emit('error'); + +process.on('exit', function () { + assert(errorCatched, 'error got catched'); +}); From cd2b9f542c34ce59d2df7820a6237f7911c702f3 Mon Sep 17 00:00:00 2001 From: isaacs Date: Sat, 9 Mar 2013 10:56:17 -0800 Subject: [PATCH 11/27] stream: Avoid nextTick warning filling read buffer In the function that pre-emptively fills the Readable queue, it relies on a recursion through: stream.push(chunk) -> maybeReadMore(stream, state) -> if (not reading more and < hwm) stream.read(0) -> stream._read() -> stream.push(chunk) -> repeat. Since this was only calling read() a single time, and then relying on a future nextTick to collect more data, it ends up causing a nextTick recursion error (and potentially a RangeError, even) if you have a very high highWaterMark, and are getting very small chunks pushed synchronously in _read (as happens with TLS, or many simple test streams). This change implements a new approach, so that read(0) is called repeatedly as long as it is effective (that is, the length keeps increasing), and thus quickly fills up the buffer for streams such as these, without any stacks overflowing. --- lib/_stream_readable.js | 12 +++++++++--- test/simple/test-stream2-unpipe-leak.js | 15 +++++++++++++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index d6ef327a8a..41cf8e89cc 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -386,17 +386,23 @@ function maybeReadMore(stream, state) { if (!state.readingMore) { state.readingMore = true; process.nextTick(function() { - state.readingMore = false; maybeReadMore_(stream, state); }); } } function maybeReadMore_(stream, state) { - if (!state.reading && !state.flowing && !state.ended && - state.length < state.highWaterMark) { + var len = state.length; + while (!state.reading && !state.flowing && !state.ended && + state.length < state.highWaterMark) { stream.read(0); + if (len === state.length) + // didn't get any data, stop spinning. + break; + else + len = state.length; } + state.readingMore = false; } // abstract method. to be overridden in specific implementation classes. diff --git a/test/simple/test-stream2-unpipe-leak.js b/test/simple/test-stream2-unpipe-leak.js index c2cf9077f3..b9e8a960d8 100644 --- a/test/simple/test-stream2-unpipe-leak.js +++ b/test/simple/test-stream2-unpipe-leak.js @@ -24,6 +24,8 @@ var common = require('../common.js'); var assert = require('assert'); var stream = require('stream'); +var chunk = new Buffer('hallo'); + var util = require('util'); function TestWriter() { @@ -37,13 +39,15 @@ TestWriter.prototype._write = function(buffer, encoding, callback) { var dest = new TestWriter(); +// Set this high so that we'd trigger a nextTick warning +// and/or RangeError if we do maybeReadMore wrong. function TestReader() { - stream.Readable.call(this); + stream.Readable.call(this, { highWaterMark: 0x10000 }); } util.inherits(TestReader, stream.Readable); TestReader.prototype._read = function(size) { - this.push(new Buffer('hallo')); + this.push(chunk); }; var src = new TestReader(); @@ -61,3 +65,10 @@ assert.equal(dest.listeners('drain').length, 0); assert.equal(dest.listeners('error').length, 0); assert.equal(dest.listeners('close').length, 0); assert.equal(dest.listeners('finish').length, 0); + +console.error(src._readableState); +process.on('exit', function() { + assert(src._readableState.length >= src._readableState.highWaterMark); + src._readableState.buffer.length = 0; + console.error(src._readableState); +}); From 327b6e3e1de88ba1db83142d53b3a57f0d06d519 Mon Sep 17 00:00:00 2001 From: isaacs Date: Sat, 9 Mar 2013 18:05:39 -0800 Subject: [PATCH 12/27] stream: Don't emit 'end' unless read() called This solves the problem of calling `readable.pipe(writable)` after the readable stream has already emitted 'end', as often is the case when writing simple HTTP proxies. The spirit of streams2 is that things will work properly, even if you don't set them up right away on the first tick. This approach breaks down, however, because pipe()ing from an ended readable will just do nothing. No more data will ever arrive, and the writable will hang open forever never being ended. However, that does not solve the case of adding a `on('end')` listener after the stream has received the EOF chunk, if it was the first chunk received (and thus, length was 0, and 'end' got emitted). So, with this, we defer the 'end' event emission until the read() function is called. Also, in pipe(), if the source has emitted 'end' already, we call the cleanup/onend function on nextTick. Piping from an already-ended stream is thus the same as piping from a stream that is in the process of ending. Updates many tests that were relying on 'end' coming immediately, even though they never read() from the req. Fix #4942 --- lib/_stream_readable.js | 39 +++++---- lib/http.js | 14 +-- .../test-http-allow-req-after-204-res.js | 1 + .../test-http-client-response-domain.js | 1 + test/simple/test-http-contentLength0.js | 1 + test/simple/test-http-head-request.js | 1 + ...test-http-head-response-has-no-body-end.js | 1 + .../test-http-head-response-has-no-body.js | 1 + test/simple/test-http-legacy.js | 1 + test/simple/test-http-max-headers-count.js | 1 + test/simple/test-http-pipe-fs.js | 1 + test/simple/test-http-should-keep-alive.js | 1 + test/simple/test-http.js | 1 + test/simple/test-https-client-reject.js | 3 + test/simple/test-stream-pipe-after-end.js | 86 +++++++++++++++++++ 15 files changed, 131 insertions(+), 22 deletions(-) create mode 100644 test/simple/test-stream-pipe-after-end.js diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index 41cf8e89cc..b09694c071 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -49,6 +49,12 @@ function ReadableState(options, stream) { this.endEmitted = false; this.reading = false; + // In streams that never have any data, and do push(null) right away, + // the consumer can miss the 'end' event if they do some I/O before + // consuming the stream. So, we don't emit('end') until some reading + // happens. + this.calledRead = false; + // a flag to be able to tell if the onwrite cb is called immediately, // or on a later tick. We set this to true at first, becuase any // actions that shouldn't happen until "later" should generally also @@ -218,6 +224,7 @@ function howMuchToRead(n, state) { // you can override either this method, or the async _read(n) below. Readable.prototype.read = function(n) { var state = this._readableState; + state.calledRead = true; var nOrig = n; if (typeof n !== 'number' || n > 0) @@ -430,13 +437,15 @@ Readable.prototype.pipe = function(dest, pipeOpts) { } state.pipesCount += 1; - if ((!pipeOpts || pipeOpts.end !== false) && - dest !== process.stdout && - dest !== process.stderr) { - src.once('end', onend); - } else { - src.once('end', cleanup); - } + var doEnd = (!pipeOpts || pipeOpts.end !== false) && + dest !== process.stdout && + dest !== process.stderr; + + var endFn = doEnd ? onend : cleanup; + if (state.endEmitted) + process.nextTick(endFn); + else + src.once('end', endFn); dest.on('unpipe', onunpipe); function onunpipe(readable) { @@ -853,12 +862,12 @@ function endReadable(stream) { if (state.length > 0) throw new Error('endReadable called on non-empty stream'); - if (state.endEmitted) - return; - state.ended = true; - state.endEmitted = true; - process.nextTick(function() { - stream.readable = false; - stream.emit('end'); - }); + if (!state.endEmitted && state.calledRead) { + state.ended = true; + state.endEmitted = true; + process.nextTick(function() { + stream.readable = false; + stream.emit('end'); + }); + } } diff --git a/lib/http.js b/lib/http.js index 0f7ea853c0..2bceaa0152 100644 --- a/lib/http.js +++ b/lib/http.js @@ -416,13 +416,13 @@ IncomingMessage.prototype._addHeaderLine = function(field, value) { // Call this instead of resume() if we want to just // dump all the data to /dev/null IncomingMessage.prototype._dump = function() { - if (this._dumped) - return; - - this._dumped = true; - if (this.socket.parser) this.socket.parser.incoming = null; - this.push(null); - readStart(this.socket); + if (!this._dumped) { + this._dumped = true; + if (this.socket.parser) this.socket.parser.incoming = null; + this.push(null); + readStart(this.socket); + this.read(); + } }; diff --git a/test/simple/test-http-allow-req-after-204-res.js b/test/simple/test-http-allow-req-after-204-res.js index 8f89043094..225ff299e9 100644 --- a/test/simple/test-http-allow-req-after-204-res.js +++ b/test/simple/test-http-allow-req-after-204-res.js @@ -58,6 +58,7 @@ function nextRequest() { //process.nextTick(nextRequest); } }); + response.resume(); }); request.end(); } diff --git a/test/simple/test-http-client-response-domain.js b/test/simple/test-http-client-response-domain.js index 7a3c41bda4..e5a39913f4 100644 --- a/test/simple/test-http-client-response-domain.js +++ b/test/simple/test-http-client-response-domain.js @@ -60,6 +60,7 @@ function test() { res.on('end', function() { res.emit('error', new Error('should be caught by domain')); }); + res.resume(); }); req.end(); } diff --git a/test/simple/test-http-contentLength0.js b/test/simple/test-http-contentLength0.js index 4d6e616d53..c7f7b6b669 100644 --- a/test/simple/test-http-contentLength0.js +++ b/test/simple/test-http-contentLength0.js @@ -36,6 +36,7 @@ s.listen(common.PORT, function() { var request = http.request({ port: common.PORT }, function(response) { console.log('STATUS: ' + response.statusCode); s.close(); + response.resume(); }); request.end(); diff --git a/test/simple/test-http-head-request.js b/test/simple/test-http-head-request.js index 6b6b876aa6..60982abcc0 100644 --- a/test/simple/test-http-head-request.js +++ b/test/simple/test-http-head-request.js @@ -47,6 +47,7 @@ server.listen(common.PORT, function() { common.error('response end'); gotEnd = true; }); + response.resume(); }); request.end(); }); diff --git a/test/simple/test-http-head-response-has-no-body-end.js b/test/simple/test-http-head-response-has-no-body-end.js index 8ad3bcaf34..cde777a58d 100644 --- a/test/simple/test-http-head-response-has-no-body-end.js +++ b/test/simple/test-http-head-response-has-no-body-end.js @@ -51,6 +51,7 @@ server.on('listening', function() { server.close(); responseComplete = true; }); + res.resume(); }); common.error('req'); req.end(); diff --git a/test/simple/test-http-head-response-has-no-body.js b/test/simple/test-http-head-response-has-no-body.js index 620ad75877..ab6bd5b51f 100644 --- a/test/simple/test-http-head-response-has-no-body.js +++ b/test/simple/test-http-head-response-has-no-body.js @@ -48,6 +48,7 @@ server.on('listening', function() { server.close(); responseComplete = true; }); + res.resume(); }); common.error('req'); req.end(); diff --git a/test/simple/test-http-legacy.js b/test/simple/test-http-legacy.js index dd3eb6f7a3..c6605b0e4e 100644 --- a/test/simple/test-http-legacy.js +++ b/test/simple/test-http-legacy.js @@ -61,6 +61,7 @@ var server = http.createServer(function(req, res) { res.end(); responses_sent += 1; }); + req.resume(); //assert.equal('127.0.0.1', res.connection.remoteAddress); }); diff --git a/test/simple/test-http-max-headers-count.js b/test/simple/test-http-max-headers-count.js index 97fce2c169..4595b11e7c 100644 --- a/test/simple/test-http-max-headers-count.js +++ b/test/simple/test-http-max-headers-count.js @@ -75,6 +75,7 @@ server.listen(common.PORT, function() { server.close(); } }); + res.resume(); }); req.maxHeadersCount = max; req.end(); diff --git a/test/simple/test-http-pipe-fs.js b/test/simple/test-http-pipe-fs.js index bc033fe59f..57ebb11dca 100644 --- a/test/simple/test-http-pipe-fs.js +++ b/test/simple/test-http-pipe-fs.js @@ -54,6 +54,7 @@ var server = http.createServer(function(req, res) { server.close(); } }); + res.resume(); }); req.on('socket', function(s) { common.debug('req' + i + ' start'); diff --git a/test/simple/test-http-should-keep-alive.js b/test/simple/test-http-should-keep-alive.js index fc1f5c6c26..e2303be7bf 100644 --- a/test/simple/test-http-should-keep-alive.js +++ b/test/simple/test-http-should-keep-alive.js @@ -59,6 +59,7 @@ var server = net.createServer(function(socket) { } else { server.close(); } + res.resume(); }); } diff --git a/test/simple/test-http.js b/test/simple/test-http.js index 1915e24630..fa388356d8 100644 --- a/test/simple/test-http.js +++ b/test/simple/test-http.js @@ -58,6 +58,7 @@ var server = http.Server(function(req, res) { res.end(); responses_sent += 1; }); + req.resume(); //assert.equal('127.0.0.1', res.connection.remoteAddress); }); diff --git a/test/simple/test-https-client-reject.js b/test/simple/test-https-client-reject.js index 45788a8c89..bf191da1d9 100644 --- a/test/simple/test-https-client-reject.js +++ b/test/simple/test-https-client-reject.js @@ -41,6 +41,7 @@ var server = https.createServer(options, function(req, res) { ++reqCount; res.writeHead(200); res.end(); + req.resume(); }).listen(common.PORT, function() { unauthorized(); }); @@ -51,6 +52,7 @@ function unauthorized() { rejectUnauthorized: false }, function(res) { assert(!req.socket.authorized); + res.resume(); rejectUnauthorized(); }); req.on('error', function(err) { @@ -80,6 +82,7 @@ function authorized() { }; options.agent = new https.Agent(options); var req = https.request(options, function(res) { + res.resume(); assert(req.socket.authorized); server.close(); }); diff --git a/test/simple/test-stream-pipe-after-end.js b/test/simple/test-stream-pipe-after-end.js new file mode 100644 index 0000000000..b46ee90ad7 --- /dev/null +++ b/test/simple/test-stream-pipe-after-end.js @@ -0,0 +1,86 @@ +// 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'); + +var Readable = require('_stream_readable'); +var Writable = require('_stream_writable'); +var util = require('util'); + +util.inherits(TestReadable, Readable); +function TestReadable(opt) { + if (!(this instanceof TestReadable)) + return new TestReadable(opt); + Readable.call(this, opt); + this._ended = false; +} + +TestReadable.prototype._read = function(n) { + if (this._ended) + this.emit('error', new Error('_read called twice')); + this._ended = true; + this.push(null); +}; + +util.inherits(TestWritable, Writable); +function TestWritable(opt) { + if (!(this instanceof TestWritable)) + return new TestWritable(opt); + Writable.call(this, opt); + this._written = []; +} + +TestWritable.prototype._write = function(chunk, encoding, cb) { + this._written.push(chunk); + cb(); +}; + +// this one should not emit 'end' until we read() from it later. +var ender = new TestReadable(); +var enderEnded = false; + +// what happens when you pipe() a Readable that's already ended? +var piper = new TestReadable(); +// pushes EOF null, and length=0, so this will trigger 'end' +piper.read(); + +setTimeout(function() { + ender.on('end', function() { + enderEnded = true; + }); + assert(!enderEnded); + var c = ender.read(); + assert.equal(c, null); + + var w = new TestWritable(); + var writableFinished = false; + w.on('finish', function() { + writableFinished = true; + }); + piper.pipe(w); + + process.on('exit', function() { + assert(enderEnded); + assert(writableFinished); + console.log('ok'); + }); +}); From 163ca274230fce536afe76c64676c332693ad7c1 Mon Sep 17 00:00:00 2001 From: isaacs Date: Sat, 9 Mar 2013 09:24:56 -0800 Subject: [PATCH 13/27] 2013.03.11, Version 0.10.0 (Stable) * npm: Upgrade to 1.2.14 * core: Append filename properly in dlopen on windows (isaacs) * zlib: Manage flush flags appropriately (isaacs) * domains: Handle errors thrown in nested error handlers (isaacs) * buffer: Strip high bits when converting to ascii (Ben Noordhuis) * win/msi: Enable modify and repair (Bert Belder) * win/msi: Add feature selection for various node parts (Bert Belder) * win/msi: use consistent registry key paths (Bert Belder) * child_process: support sending dgram socket (Andreas Madsen) * fs: Raise EISDIR on Windows when calling fs.read/write on a dir (isaacs) * unix: fix strict aliasing warnings, macro-ify functions (Ben Noordhuis) * unix: honor UV_THREADPOOL_SIZE environment var (Ben Noordhuis) * win/tty: fix typo in color attributes enumeration (Bert Belder) * win/tty: don't touch insert mode or quick edit mode (Bert Belder) --- AUTHORS | 2 ++ ChangeLog | 33 ++++++++++++++++++++++++++++++++- src/node_version.h | 2 +- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index e2ad771ae5..d8470be27b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -426,3 +426,5 @@ Aaron Cannon Xidorn Quan Paolo Fragomeni Scott Blomquist +Henry Chin +Julian Gruber diff --git a/ChangeLog b/ChangeLog index 0ba20a7eea..5a5b8bc934 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,35 @@ -2013.03.06, Version 0.9.12 (Unstable) +2013.03.11, Version 0.10.0 (Stable) + +* npm: Upgrade to 1.2.14 + +* core: Append filename properly in dlopen on windows (isaacs) + +* zlib: Manage flush flags appropriately (isaacs) + +* domains: Handle errors thrown in nested error handlers (isaacs) + +* buffer: Strip high bits when converting to ascii (Ben Noordhuis) + +* win/msi: Enable modify and repair (Bert Belder) + +* win/msi: Add feature selection for various node parts (Bert Belder) + +* win/msi: use consistent registry key paths (Bert Belder) + +* child_process: support sending dgram socket (Andreas Madsen) + +* fs: Raise EISDIR on Windows when calling fs.read/write on a dir (isaacs) + +* unix: fix strict aliasing warnings, macro-ify functions (Ben Noordhuis) + +* unix: honor UV_THREADPOOL_SIZE environment var (Ben Noordhuis) + +* win/tty: fix typo in color attributes enumeration (Bert Belder) + +* win/tty: don't touch insert mode or quick edit mode (Bert Belder) + + +2013.03.06, Version 0.9.12 (Unstable), 0debf5a82934da805592b6496756cdf27c993abc * stream: Allow strings in Readable.push/unshift (isaacs) diff --git a/src/node_version.h b/src/node_version.h index 654fc54b7b..82555ece77 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -30,7 +30,7 @@ # define NODE_TAG "" #endif -#define NODE_VERSION_IS_RELEASE 0 +#define NODE_VERSION_IS_RELEASE 1 #ifndef NODE_STRINGIFY #define NODE_STRINGIFY(n) NODE_STRINGIFY_HELPER(n) From e2b293c360a73178462cb8d50b31c03f9d1fc411 Mon Sep 17 00:00:00 2001 From: isaacs Date: Mon, 11 Mar 2013 08:49:33 -0700 Subject: [PATCH 14/27] Now working on 0.10.1 --- src/node_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node_version.h b/src/node_version.h index 82555ece77..65323e7046 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -24,13 +24,13 @@ #define NODE_MAJOR_VERSION 0 #define NODE_MINOR_VERSION 10 -#define NODE_PATCH_VERSION 0 +#define NODE_PATCH_VERSION 1 #ifndef NODE_TAG # define NODE_TAG "" #endif -#define NODE_VERSION_IS_RELEASE 1 +#define NODE_VERSION_IS_RELEASE 0 #ifndef NODE_STRINGIFY #define NODE_STRINGIFY(n) NODE_STRINGIFY_HELPER(n) From 228ad9357c0ad6cd817e620b406f479c1824f3db Mon Sep 17 00:00:00 2001 From: isaacs Date: Mon, 11 Mar 2013 08:56:47 -0700 Subject: [PATCH 15/27] blog: Post about v0.10.0 --- doc/blog/release/v0.10.0.md | 487 ++++++++++++++++++++++++++++++++++++ 1 file changed, 487 insertions(+) create mode 100644 doc/blog/release/v0.10.0.md diff --git a/doc/blog/release/v0.10.0.md b/doc/blog/release/v0.10.0.md new file mode 100644 index 0000000000..b7bac4120e --- /dev/null +++ b/doc/blog/release/v0.10.0.md @@ -0,0 +1,487 @@ +title: Node v0.10.0 (Stable) +category: release +version: 0.10.0 +date: 2013-03-11T16:00:00.000Z +slug: node-v0-10-0-stable +author: Isaac Z. Schlueter + +I am pleased to announce a new stable version of Node. + +This branch brings significant improvements to many areas, with a +focus on API polish, ease of use, and backwards compatibility. + +For a very brief overview of the relevant API changes since v0.8, +please see [the API changes wiki +page](https://github.com/joyent/node/wiki/Api-changes-between-v0.8-and-v0.10). + +## Streams2 + +In a [previous post](http://blog.nodejs.org/2012/12/20/streams2/), we +introduced the +"[Streams2](http://blog.nodejs.org/2012/12/20/streams2/)" API changes. +If you haven't reviewed the changes, please go read that now (at least +the tl;dr section). + +The changes to the stream interface have been a long time in the +making. Even from the earliest days of Node, we've all sort of known +that this whole "data events come right away" and "pause() is +advisory" stuff was unnecessarily awful. In v0.10, we finally bit the +bullet and committed to making drastic changes in order to make these +things better. + +More importantly, all streams in Node-core are built using the same +set of easily-extended base classes, so their behavior is much more +consistent, and it's easier than ever to create streaming interfaces +in your own userland programs. + +In fact, the Streams2 API was developed while using it for modules in +the npm registry. At the time of this writing, [37 published Node +modules](https://npmjs.org/browse/depended/readable-stream) already +are using the +[readable-stream](https://npmjs.org/package/readable-stream) library +as a dependency. The readable-stream npm package allows you to use +the new Stream interface in your legacy v0.8 codebase. + +## Domains and Error Handling + +The `domain` module has been elevated from "Experimental" to +"Unstable" status. It's been given more of a first-class treatment +internally, making it easier to handle some of the edge cases that we +found using Domains for error handling in v0.8. Specifically, domain +error handler no longer relies on `process.on('uncaughtException')` +being raised, and the C++ code in Node is domain-aware. + +If you're not already using Domains to catch errors in your programs, +and you've found yourself wishing that you could get better debugging +information when errors are thrown (especially in the midst of lots of +requests and asynchronous calls), then definitely check it out. + +## Faster process.nextTick + +In v0.8 (and before), the `process.nextTick()` function scheduled its +callback using a spinner on the event loop. This *usually* caused the +callback to be fired before any other I/O. However, it was not +guaranteed. + +As a result, a lot of programs (including some parts of Node's +internals) began using `process.nextTick` as a "do later, but before +any actual I/O is performed" interface. Since it usually works that +way, it seemed fine. + +However, under load, it's possible for a server to have a lot of I/O +scheduled, to the point where the `nextTick` gets preempted for +something else. This led to some odd errors and race conditions, +which could not be fixed without changing the semantics of nextTick. + +So, that's what we did. In v0.10, `nextTick` handlers are run right +after each call from C++ into JavaScript. That means that, if your +JavaScript code calls `process.nextTick`, then the callback will fire +as soon as the code runs to completion, but *before* going back to +the event loop. The race is over, and all is good. + +However, there are programs out in the wild that use recursive calls +to `process.nextTick` to avoid pre-empting the I/O event loop for +long-running jobs. In order to avoid breaking horribly right away, +Node will now print a deprecation warning, and ask you to use +`setImmediate` for these kinds of tasks instead. + +## Latency and Idle Garbage Collection + +One of the toughest things to get right in a garbage collected +language is garbage collection. In order to try to avoid excessive +memory usage, Node used to try to tell V8 to collect some garbage +whenever the event loop was idle. + +However, knowing exactly when to do this is extremely difficult. +There are different degrees of "idleness", and if you get it wrong, +you can easily end up spending massive amounts of time collecting +garbage when you'd least expect. In practice, disabling the +`IdleNotification` call yields better performance without any +excessive memory usage, because V8 is pretty good at knowing when it's +the best time to run GC. + +So, in v0.10, we just ripped that feature out. (According to another +point of view, we fixed the bug that it was ever there in the first +place.) As a result, latency is much more predictable and stable. +You won't see a difference in the benchmarks as a result of this, but +you'll probably find that your app's response times are more reliable. + + +## Performance and Benchmarks + +When the Streams2 feature first landed in master, it disrupted a lot +of things. We focused first on correctness rather than speed, and as +a result of that, we got a correct implementation that was +significantly slower. + +We have a consistent rule in Node, that it cannot be allowed to get +slower for our main use cases. It took a lot of work, but over the +last few months, we've managed to get v0.10 to an appropriate level of +performance, without sacrificing the API goals that we had in mind. + +Benchmarks are complicated beasts. Until this release, we've gotten +by with a pretty ad-hoc approach to running benchmarks. However, as +we started actually having to track down regressions, the need for a +more comprehensive approach was obvious. + +Work is underway to figure out the optimum way to get statistically +significant benchmark results in an automated way. As it is, we're +still seeing significant jitter in some of the data, so take the red +and green colors with a grain of salt. + +The benchmarks below were run on an Apple 13-inch, Late 2011 MacBook +Pro with a 2.8 GHz Intel Core i7 processor, 8GB of 1333MHz DDR3 RAM, +running OS X Lion 10.7.5 (11G63b). The numbers are slightly different +on Linux and SmartOS, but the conclusions are the same. The [raw data +is available](http://nodejs.org/benchmarks-v0.10-vs-v0.8/), as well. + +## Benchmarks: http + +Node is for websites, and websites run over HTTP, so this is the one +that people usually care the most about: + +
+http/cluster.js type=bytes length=4: v0.10: 16843 v0.8: 16202 ................. 3.96%
+http/cluster.js type=bytes length=1024: v0.10: 15505 v0.8: 15065 .............. 2.92%
+http/cluster.js type=bytes length=102400: v0.10: 1555.2 v0.8: 1566.3 ......... -0.71%
+http/cluster.js type=buffer length=4: v0.10: 15308 v0.8: 14763 ................ 3.69%
+http/cluster.js type=buffer length=1024: v0.10: 15039 v0.8: 14830 ............. 1.41%
+http/cluster.js type=buffer length=102400: v0.10: 7584.6 v0.8: 7433.6 ......... 2.03%
+http/simple.js type=bytes length=4: v0.10: 12343 v0.8: 11761 .................. 4.95%
+http/simple.js type=bytes length=1024: v0.10: 11051 v0.8: 10287 ............... 7.43%
+http/simple.js type=bytes length=102400: v0.10: 853.19 v0.8: 892.75 .......... -4.43%
+http/simple.js type=buffer length=4: v0.10: 11316 v0.8: 10728 ................. 5.48%
+http/simple.js type=buffer length=1024: v0.10: 11199 v0.8: 10429 .............. 7.38%
+http/simple.js type=buffer length=102400: v0.10: 4942.1 v0.8: 4822.9 .......... 2.47%
+
+ +What we see here is that, overall, HTTP is faster. It's just slightly +slower (1-5%) when sending extremely large string messages (ie +`type=bytes` rather than `type=buffer`). But otherwise, things are +about the same, or slightly faster. + +## Benchmarks: fs + +The fs.ReadStream throughput is massively improved, and less affected +by the chunk size argument: + +
+fs/read-stream buf size=1024: v0.10: 1106.6 v0.8: 60.597 ................... 1726.12%
+fs/read-stream buf size=4096: v0.10: 1107.9 v0.8: 235.51 .................... 370.44%
+fs/read-stream buf size=65535: v0.10: 1108.2 v0.8: 966.84 .................... 14.62%
+fs/read-stream buf size=1048576: v0.10: 1103.3 v0.8: 959.66 .................. 14.97%
+fs/read-stream asc size=1024: v0.10: 1081.5 v0.8: 62.218 ................... 1638.21%
+fs/read-stream asc size=4096: v0.10: 1082.3 v0.8: 174.78 .................... 519.21%
+fs/read-stream asc size=65535: v0.10: 1083.9 v0.8: 627.91 .................... 72.62%
+fs/read-stream asc size=1048576: v0.10: 1083.2 v0.8: 627.49 .................. 72.62%
+fs/read-stream utf size=1024: v0.10: 46.553 v0.8: 16.944 .................... 174.74%
+fs/read-stream utf size=4096: v0.10: 46.585 v0.8: 32.933 ..................... 41.45%
+fs/read-stream utf size=65535: v0.10: 46.57 v0.8: 45.832 ...................... 1.61%
+fs/read-stream utf size=1048576: v0.10: 46.576 v0.8: 45.884 ................... 1.51%
+
+ +The fs.WriteStream throughput increases considerably, for most +workloads. As the size of the chunk goes up, the speed is limited by +the underlying system and the cost of string conversion, so v0.8 and +v0.10 converge. But for smaller chunk sizes (like you'd be more +likely to see in real applications), v0.10 is a significant +improvement. + +
+fs/write-stream buf size=2: v0.10: 0.12434 v0.8: 0.10097 ..................... 23.15%
+fs/write-stream buf size=1024: v0.10: 59.926 v0.8: 49.822 .................... 20.28%
+fs/write-stream buf size=65535: v0.10: 180.41 v0.8: 179.26 .................... 0.64%
+fs/write-stream buf size=1048576: v0.10: 181.49 v0.8: 176.73 .................. 2.70%
+fs/write-stream asc size=2: v0.10: 0.11133 v0.8: 0.08123 ..................... 37.06%
+fs/write-stream asc size=1024: v0.10: 53.023 v0.8: 36.708 .................... 44.45%
+fs/write-stream asc size=65535: v0.10: 178.54 v0.8: 174.36 .................... 2.39%
+fs/write-stream asc size=1048576: v0.10: 185.27 v0.8: 183.65 .................. 0.88%
+fs/write-stream utf size=2: v0.10: 0.11165 v0.8: 0.080079 .................... 39.43%
+fs/write-stream utf size=1024: v0.10: 45.166 v0.8: 32.636 .................... 38.39%
+fs/write-stream utf size=65535: v0.10: 176.1 v0.8: 175.34 ..................... 0.43%
+fs/write-stream utf size=1048576: v0.10: 182.3 v0.8: 182.82 .................. -0.28%
+
+ +## Benchmark: tls + +We switched to a newer version of OpenSSL, and the CryptoStream +implementation was significantly changed to support the Stream2 +interface. + +The throughput of TLS connections is massively improved: + +
+tls/throughput.js dur=5 type=buf size=2: v0.10: 0.90836 v0.8: 0.32381 ....... 180.52%
+tls/throughput.js dur=5 type=buf size=1024: v0.10: 222.84 v0.8: 116.75 ....... 90.87%
+tls/throughput.js dur=5 type=buf size=1048576: v0.10: 403.17 v0.8: 360.42 .... 11.86%
+tls/throughput.js dur=5 type=asc size=2: v0.10: 0.78323 v0.8: 0.28761 ....... 172.32%
+tls/throughput.js dur=5 type=asc size=1024: v0.10: 199.7 v0.8: 102.46 ........ 94.91%
+tls/throughput.js dur=5 type=asc size=1048576: v0.10: 375.85 v0.8: 317.81 .... 18.26%
+tls/throughput.js dur=5 type=utf size=2: v0.10: 0.78503 v0.8: 0.28834 ....... 172.26%
+tls/throughput.js dur=5 type=utf size=1024: v0.10: 182.43 v0.8: 100.3 ........ 81.88%
+tls/throughput.js dur=5 type=utf size=1048576: v0.10: 333.05 v0.8: 301.57 .... 10.44%
+
+ +However, the speed at which we can make connections is somewhat +reduced: + +
+tls/tls-connect.js concurrency=1 dur=5: v0.10: 433.05 v0.8: 560.43 .......... -22.73%
+tls/tls-connect.js concurrency=10 dur=5: v0.10: 438.38 v0.8: 577.93 ......... -24.15%
+
+ +At this point, it seems like the connection speed is related to the +new version of OpenSSL, but we'll be tracking that further. + +TLS still has more room for improvement, but this throughput increase +is a huge step. + +## Benchmark: net + +The net throughput tests tell an interesting story. When sending +ascii messages, they're much faster. + +
+net/net-c2s.js len=102400 type=asc dur=5: v0.10: 3.6551 v0.8: 2.0478 ......... 78.49%
+net/net-c2s.js len=16777216 type=asc dur=5: v0.10: 3.2428 v0.8: 2.0503 ....... 58.16%
+net/net-pipe.js len=102400 type=asc dur=5: v0.10: 4.4638 v0.8: 3.0798 ........ 44.94%
+net/net-pipe.js len=16777216 type=asc dur=5: v0.10: 3.9449 v0.8: 2.8906 ...... 36.48%
+net/net-s2c.js len=102400 type=asc dur=5: v0.10: 3.6306 v0.8: 2.0415 ......... 77.84%
+net/net-s2c.js len=16777216 type=asc dur=5: v0.10: 3.2271 v0.8: 2.0636 ....... 56.38%
+
+ +When sending Buffer messages, they're just slightly slower. (This +difference is less than the typical variability of the test, but they +were run 20 times and outliers were factored out for this post.) + +
+net/net-c2s.js len=102400 type=buf dur=5: v0.10: 5.5597 v0.8: 5.6967 ......... -2.40%
+net/net-c2s.js len=16777216 type=buf dur=5: v0.10: 6.1843 v0.8: 6.4595 ....... -4.26%
+net/net-pipe.js len=102400 type=buf dur=5: v0.10: 5.6898 v0.8: 5.986 ......... -4.95%
+net/net-pipe.js len=16777216 type=buf dur=5: v0.10: 5.9643 v0.8: 5.9251 ....... 0.66%
+net/net-s2c.js len=102400 type=buf dur=5: v0.10: 5.473 v0.8: 5.6492 .......... -3.12%
+net/net-s2c.js len=16777216 type=buf dur=5: v0.10: 6.1986 v0.8: 6.3236 ....... -1.98%
+
+ +When sending utf-8 messages, they're a bit slower than that: + +
+net/net-c2s.js len=102400 type=utf dur=5: v0.10: 2.2671 v0.8: 2.4606 ......... -7.87%
+net/net-c2s.js len=16777216 type=utf dur=5: v0.10: 1.7434 v0.8: 1.8771 ....... -7.12%
+net/net-pipe.js len=102400 type=utf dur=5: v0.10: 3.1679 v0.8: 3.5401 ....... -10.51%
+net/net-pipe.js len=16777216 type=utf dur=5: v0.10: 2.5615 v0.8: 2.7002 ...... -5.14%
+net/net-s2c.js len=102400 type=utf dur=5: v0.10: 2.2495 v0.8: 2.4578 ......... -8.48%
+net/net-s2c.js len=16777216 type=utf dur=5: v0.10: 1.7733 v0.8: 1.8975 ....... -6.55%
+
+ +You might suspect that this is a result of the new Streams +implementation. However, running the same benchmarks without using +any of the code in Node's `lib/` folder, just calling into the C++ +bindings directly, yields consistently similar results. + +This slight regression comes along with significant improvements in +everything that sits on *top* of TCP (that is, TLS and HTTP). + +Keep an eye out for more work in this area. Fast is never fast +enough! + + +## Continuous Integration + +To support a higher degree of stability, and hopefully catch issues +sooner, we have a Jenkins instance running every commit through the +test suite, on each operating system we support. You can watch the +action at [the Node Jenkins web portal](http://jenkins.nodejs.org/). + +Coming soon, we'll have automatically generated nightly builds every +day, and eventually, the entire release process will be automated. + +While we're pretty rigorous about running tests and benchmarks, it's +easy for things to slip by, and our ad-hoc methods are not cutting it +any longer. This promises a much lower incidence of the sort of +regressions that delayed the release of v0.10 for several months. + + +## Growing Out + +A year ago, we said that the innovation in the Node universe would be +happening in userland modules. Now, we've finally taken that to its +logical conclusion, and moved our iteration on **core** modules into +userland as well. Things like `readable-stream` and `tlsnappy` allow +us to get much more user-testing, experimentation, and contributions +to a feature. + +The userland module can live on as a compatibility layer so that +libraries can use the new features, even if they need to support older +versions of Node. This is a remarkably effective way to do node-core +development. Future developments will continue to be iterated in +userland modules. + +## Growing Up + +The question comes up pretty often whether Node is "ready for prime +time" yet. I usually answer that it depends on your requirements for +"prime time", but Node has been powering some high profile sites, and +the options for "real" companies using Node for The Business are +better than ever. + +It would be out of scope to try to provide an exhaustive list of all +the companies using Node, and all of the options for support and +training. However, here are a few resources that are quickly +expanding to fill the "Enterprise Node" space. + +For those looking for commercial support, +[StrongLoop](http://strongloop.com/) (Ben Noordhuis & Bert Belder's +company) has released a distribution containing node v0.10 that they +will support on Windows, Mac, Red Hat/Fedora, Debian/Ubuntu and +multiple cloud platforms. You can [download their Node distribution +here](http://strongloop.com/products#downloads). + +[The Node Firm](http://thenodefirm.com) is a worldwide network of key +Node contributors and community members that help organizations +succeed with Node. Through corporate training, consulting, +architectural guidance, and [ongoing consulting +subscriptions](http://thenodefirm.com/nodejs-consulting-subscriptions), +they have helped Skype, Qualcomm, and others quickly and effectively +embrace Node. + +Node would not be what it is without [npm](https://npmjs.org/), and +npm would not be what it is without the registry of published modules. +However, relying on the public registry is problematic for many +enterprise use-cases. [Iris npm](https://www.irisnpm.com/) is a fully +managed private npm registry, from [Iris +Couch](http://www.iriscouch.com), the team that runs the public npm +registry in production. + +[Joyent](http://joyent.com), the company you probably know as the +custodian of the Node project, provides high performance cloud +infrastructure specializing in real-time web and mobile applications. +Joyent uses Node extensively throughout their stack, and provides +impressive [post-mortem debugging and real-time performance analysis +tools](http://dtrace.org/blogs/dap/2012/05/31/debugging-node-js-in-production-fluent-slides/) +for Node.js applications. They are my also employer, so I'd probably +have to get a "real" job if they weren't sponsoring Node :) + +## Next Up: v0.12 + +The focus of Node v0.12 will be to make HTTP better. Node's current +HTTP implementation is pretty good, and clearly sufficient to do a lot +of interesting things with. However: + +1. The codebase is a mess. We share a lot of code between the Client + and Server implementations, but do so in a way that makes it + unnecessarily painful to read the code or fix bugs. It will be + split up so that client and server are clearly separated, and have + cleaner interfaces. +2. The socket pooling behavior is confusing and weird. We will be + adding configurable socket pooling as a standalone utility. This + will allow us to implement KeepAlive behavior in a more reasonable + manner, as well as providing something that you can use in your own + programs. + +There is some experimentation going on in the +[tlsnappy](https://github.com/indutny/tlsnappy) module, which may make +its way back into the core TLS implementation and speed things up +considerably. + +## 1.0 + +After 0.12, the next major stable release will be 1.0. At that point, +very little will change in terms of the day-to-day operation of the +project, but it will mark a significant milestone in terms of our +stability and willingness to add new features. However, we've already +gotten strict about maintaining backwards compatibility, so this won't +really be so much of a shift. + +New versions will still come out, especially to pull in new versions +of our dependencies, and bugs will continue to be fixed. There's been +talk of pinning our release cycles to V8, and automating the release +process in some interesting ways. + +The goal of Node has always been to eventually be "finished" with the +core program. Of course, that's a rather lofty goal, perhaps even +impossible. But as we take Node to more places, and use it in more +ways, we're getting closer to the day when the relevant innovation +happens outside of the core Node program. + +Stability in the platform enables growth on top of it. + +And now, the traditional release notes: + +## 2013.03.11, Version 0.10.0 (Stable) + +* npm: Upgrade to 1.2.14 + +* core: Append filename properly in dlopen on windows (isaacs) + +* zlib: Manage flush flags appropriately (isaacs) + +* domains: Handle errors thrown in nested error handlers (isaacs) + +* buffer: Strip high bits when converting to ascii (Ben Noordhuis) + +* win/msi: Enable modify and repair (Bert Belder) + +* win/msi: Add feature selection for various Node parts (Bert Belder) + +* win/msi: use consistent registry key paths (Bert Belder) + +* child_process: support sending dgram socket (Andreas Madsen) + +* fs: Raise EISDIR on Windows when calling fs.read/write on a dir (isaacs) + +* unix: fix strict aliasing warnings, macro-ify functions (Ben Noordhuis) + +* unix: honor UV_THREADPOOL_SIZE environment var (Ben Noordhuis) + +* win/tty: fix typo in color attributes enumeration (Bert Belder) + +* win/tty: don't touch insert mode or quick edit mode (Bert Belder) + + +Source Code: http://nodejs.org/dist/v0.10.0/node-v0.10.0.tar.gz + +Macintosh Installer (Universal): http://nodejs.org/dist/v0.10.0/node-v0.10.0.pkg + +Windows Installer: http://nodejs.org/dist/v0.10.0/node-v0.10.0-x86.msi + +Windows x64 Installer: http://nodejs.org/dist/v0.10.0/x64/node-v0.10.0-x64.msi + +Windows x64 Files: http://nodejs.org/dist/v0.10.0/x64/ + +Linux 32-bit Binary: http://nodejs.org/dist/v0.10.0/node-v0.10.0-linux-x86.tar.gz + +Linux 64-bit Binary: http://nodejs.org/dist/v0.10.0/node-v0.10.0-linux-x64.tar.gz + +Solaris 32-bit Binary: http://nodejs.org/dist/v0.10.0/node-v0.10.0-sunos-x86.tar.gz + +Solaris 64-bit Binary: http://nodejs.org/dist/v0.10.0/node-v0.10.0-sunos-x64.tar.gz + +Other release files: http://nodejs.org/dist/v0.10.0/ + +Website: http://nodejs.org/docs/v0.10.0/ + +Documentation: http://nodejs.org/docs/v0.10.0/api/ + +Shasums: + +``` +b9e9bca99cdb5563cad3d3f04baa262e317b827c node-v0.10.0-darwin-x64.tar.gz +0227c9bc3df5b62267b9d4e3b0a92b3a70732229 node-v0.10.0-darwin-x86.tar.gz +9f5f7350d6f889ea8e794516ecfea651e8e53d24 node-v0.10.0-linux-x64.tar.gz +cc5f1cd6a2f2530bc400e761144bbaf8fcb66cc4 node-v0.10.0-linux-x86.tar.gz +42c14b7eab398976b1ac0a8e6e96989059616af5 node-v0.10.0-sunos-x64.tar.gz +ddcadbac66d1acea48aa6c5462d0a0d7308ea823 node-v0.10.0-sunos-x86.tar.gz +70eacf2cca7abec79fac4ca502e8d99590a2108a node-v0.10.0-x86.msi +c48c269b9b0f0a95e6e9234d4597d1c8a1c45c5a node-v0.10.0.pkg +7321266347dc1c47ed2186e7d61752795ce8a0ef node-v0.10.0.tar.gz +f8c6f55469551243ea461f023cc57c024f57fef2 node.exe +253ae79e411fcfddcf28861559ececb4b335db64 node.exp +acb8febb5ea714c065f201ced5423b0838fdf1b6 node.lib +0fdad1400036dd26d720070f783d3beeb3bb9c0a node.pdb +abcaf8ef606655a05e73ee5d06715ffd022aad22 x64/node-v0.10.0-x64.msi +e5d0c235629b26430b6e07c07ee2c7dcda82f35e x64/node.exe +43b3fb3a6aaf6a04f578ee607a9455c1e23acf08 x64/node.exp +87dd6eb6c8127a1af0dcca639961441fc303d75a x64/node.lib +50aca715777fa42b854e6cfc56b6199a54aabd3c x64/node.pdb +``` From da10bb85ff0098836c53ce96e521a9d3d3422e86 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 12 Mar 2013 00:03:56 +0100 Subject: [PATCH 16/27] doc: events: add 'removeListener' event section Amends commit 84221fd by (also) documenting the 'removeListener' event in a dedicated section, like the 'newListener' event. Fixes #4977. --- doc/api/events.markdown | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/api/events.markdown b/doc/api/events.markdown index 10b9ed0441..940b8e242e 100644 --- a/doc/api/events.markdown +++ b/doc/api/events.markdown @@ -99,3 +99,11 @@ Return the number of listeners for a given event. * `listener` {Function} The event handler function This event is emitted any time someone adds a new listener. + + +### Event: 'removeListener' + +* `event` {String} The event name +* `listener` {Function} The event handler function + +This event is emitted any time someone removes a listener. From 598b5e4593bf39c71416183c36372d97e97852f5 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Tue, 12 Mar 2013 19:00:48 -0700 Subject: [PATCH 17/27] blog: fix small typo in v0.10.0 release article --- doc/blog/release/v0.10.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/blog/release/v0.10.0.md b/doc/blog/release/v0.10.0.md index b7bac4120e..076e956e9f 100644 --- a/doc/blog/release/v0.10.0.md +++ b/doc/blog/release/v0.10.0.md @@ -359,7 +359,7 @@ infrastructure specializing in real-time web and mobile applications. Joyent uses Node extensively throughout their stack, and provides impressive [post-mortem debugging and real-time performance analysis tools](http://dtrace.org/blogs/dap/2012/05/31/debugging-node-js-in-production-fluent-slides/) -for Node.js applications. They are my also employer, so I'd probably +for Node.js applications. They are also by employer, so I'd probably have to get a "real" job if they weren't sponsoring Node :) ## Next Up: v0.12 From 7a07b31a2f678a319fc7cbb0ee4ee023fa812b14 Mon Sep 17 00:00:00 2001 From: isaacs Date: Wed, 13 Mar 2013 10:15:30 -0700 Subject: [PATCH 18/27] blog: Fix typo in typo fix --- doc/blog/release/v0.10.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/blog/release/v0.10.0.md b/doc/blog/release/v0.10.0.md index 076e956e9f..35a65f5a44 100644 --- a/doc/blog/release/v0.10.0.md +++ b/doc/blog/release/v0.10.0.md @@ -359,7 +359,7 @@ infrastructure specializing in real-time web and mobile applications. Joyent uses Node extensively throughout their stack, and provides impressive [post-mortem debugging and real-time performance analysis tools](http://dtrace.org/blogs/dap/2012/05/31/debugging-node-js-in-production-fluent-slides/) -for Node.js applications. They are also by employer, so I'd probably +for Node.js applications. They are also my employer, so I'd probably have to get a "real" job if they weren't sponsoring Node :) ## Next Up: v0.12 From 53f2381455a0f8635168cd2b5728e2495086f2b7 Mon Sep 17 00:00:00 2001 From: isaacs Date: Wed, 13 Mar 2013 10:16:26 -0700 Subject: [PATCH 19/27] core: Unwrap without aborting in handle fd getter --- src/stream_wrap.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stream_wrap.cc b/src/stream_wrap.cc index 544c1f8cef..fb6edbc3a3 100644 --- a/src/stream_wrap.cc +++ b/src/stream_wrap.cc @@ -122,7 +122,7 @@ Handle StreamWrap::GetFD(Local, const AccessorInfo& args) { return v8::Null(); #else HandleScope scope; - UNWRAP(StreamWrap) + UNWRAP_NO_ABORT(StreamWrap) int fd = -1; if (wrap != NULL && wrap->stream_ != NULL) fd = wrap->stream_->io_watcher.fd; return scope.Close(Integer::New(fd)); From 8135ac1b7f6c44f20fc59c09a35e8ed181a1337e Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Wed, 13 Mar 2013 16:53:27 +0400 Subject: [PATCH 20/27] net: handle 'finish' event only after 'connect' --- lib/net.js | 6 +++ .../test-net-connect-immediate-finish.js | 41 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 test/simple/test-net-connect-immediate-finish.js diff --git a/lib/net.js b/lib/net.js index b994c27814..9541e1beea 100644 --- a/lib/net.js +++ b/lib/net.js @@ -184,6 +184,12 @@ util.inherits(Socket, stream.Duplex); // If allowHalfOpen is true, then we need to do a shutdown, // so that only the writable side will be cleaned up. function onSocketFinish() { + // If still connecting - defer handling 'finish' until 'connect' will happen + if (this._connecting) { + debug('osF: not yet connected'); + return this.once('connect', onSocketFinish); + } + debug('onSocketFinish'); if (!this.readable || this._readableState.ended) { debug('oSF: ended, destroy', this._readableState); diff --git a/test/simple/test-net-connect-immediate-finish.js b/test/simple/test-net-connect-immediate-finish.js new file mode 100644 index 0000000000..ac2a61331d --- /dev/null +++ b/test/simple/test-net-connect-immediate-finish.js @@ -0,0 +1,41 @@ +// 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'); +var net = require('net'); + +var gotError = false; + +var client = net.connect({ + host: 'no.way.you.will.resolve.this', + port: common.PORT +}); + +client.once('error', function(err) { + gotError = true; +}); + +client.end(); + +process.on('exit', function() { + assert(gotError); +}); From 9af0085f700294b3535fe9d324e3cdf71b071d03 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 13 Mar 2013 18:27:09 +0100 Subject: [PATCH 21/27] doc: path.join() arguments must be strings In v0.8, non-string arguments were ignored. v0.10 throws an exception. --- doc/api/path.markdown | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/api/path.markdown b/doc/api/path.markdown index 2541c62d82..df2e46005e 100644 --- a/doc/api/path.markdown +++ b/doc/api/path.markdown @@ -25,7 +25,9 @@ Example: ## path.join([path1], [path2], [...]) Join all arguments together and normalize the resulting path. -Non-string arguments are ignored. + +Arguments must be strings. In v0.8, non-string arguments were +silently ignored. In v0.10 and up, an exception is thrown. Example: From 110cacd1ed7350cd718b0d5aa0ce8c320c040bb1 Mon Sep 17 00:00:00 2001 From: isaacs Date: Wed, 13 Mar 2013 11:22:33 -0700 Subject: [PATCH 22/27] core: Move UNWRAP_NO_ABORT to handle_wrap.h Otherwise it cannot be used in StreamWrap. Forgot to include in last patch, broke the build. --- src/handle_wrap.cc | 6 ------ src/handle_wrap.h | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/handle_wrap.cc b/src/handle_wrap.cc index a667bb47c5..3f05c7d81b 100644 --- a/src/handle_wrap.cc +++ b/src/handle_wrap.cc @@ -23,12 +23,6 @@ #include "ngx-queue.h" #include "handle_wrap.h" -#define UNWRAP_NO_ABORT(type) \ - assert(!args.Holder().IsEmpty()); \ - assert(args.Holder()->InternalFieldCount() > 0); \ - type* wrap = static_cast( \ - args.Holder()->GetPointerFromInternalField(0)); - namespace node { using v8::Arguments; diff --git a/src/handle_wrap.h b/src/handle_wrap.h index 6780cd72fe..dbefc2a114 100644 --- a/src/handle_wrap.h +++ b/src/handle_wrap.h @@ -46,6 +46,12 @@ namespace node { // js/c++ boundary crossing. At the javascript layer that should all be // taken care of. +#define UNWRAP_NO_ABORT(type) \ + assert(!args.Holder().IsEmpty()); \ + assert(args.Holder()->InternalFieldCount() > 0); \ + type* wrap = static_cast( \ + args.Holder()->GetPointerFromInternalField(0)); + class HandleWrap { public: static void Initialize(v8::Handle target); From 615d809ac684a7d2cc7ee5e1aa58f0a921b529a0 Mon Sep 17 00:00:00 2001 From: Gil Pedersen Date: Tue, 12 Mar 2013 15:56:30 +0100 Subject: [PATCH 23/27] stream: Never call decoder.end() multiple times Fixes decoder.end() being called on every push(null). As the tls module does this, corrupt stream data could potentially be added to the end. --- lib/_stream_readable.js | 1 + test/simple/test-stream2-set-encoding.js | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index b09694c071..c669455d7d 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -349,6 +349,7 @@ function onEofChunk(stream, state) { state.buffer.push(chunk); state.length += state.objectMode ? 1 : chunk.length; } + state.decoder = null; } // if we've ended and we have some data left, then emit diff --git a/test/simple/test-stream2-set-encoding.js b/test/simple/test-stream2-set-encoding.js index 8c5973fb63..ad4d884680 100644 --- a/test/simple/test-stream2-set-encoding.js +++ b/test/simple/test-stream2-set-encoding.js @@ -163,6 +163,10 @@ test('setEncoding hex', function(t) { // just kick it off. tr.emit('readable'); + + process.on('exit', function() { + assert(!tr._readableState.decoder); + }); }); test('setEncoding hex with read(13)', function(t) { From 7b7235a232439c4bb2038ed5fbbe63e3bffd8202 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 13 Mar 2013 23:22:55 +0100 Subject: [PATCH 24/27] doc: add note on process.title max length Fixes #5006. --- doc/api/process.markdown | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/api/process.markdown b/doc/api/process.markdown index a6f160d945..639bdd74bd 100644 --- a/doc/api/process.markdown +++ b/doc/api/process.markdown @@ -379,10 +379,21 @@ The PID of the process. console.log('This process is pid ' + process.pid); + ## process.title Getter/setter to set what is displayed in 'ps'. +When used as a setter, the maximum length is platform-specific and probably +short. + +On Linux and OS X, it's limited to the size of the binary name plus the +length of the command line arguments because it overwrites the argv memory. + +v0.8 allowed for longer process title strings by also overwriting the environ +memory but that was potentially insecure/confusing in some (rather obscure) +cases. + ## process.arch From fa05e8a2706e20a191942fe2b2273481605a1f14 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 13 Mar 2013 22:52:33 +0100 Subject: [PATCH 25/27] doc: implicit fs callbacks don't throw in v0.10 But they will in v0.12. Re #5005. --- doc/api/fs.markdown | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/doc/api/fs.markdown b/doc/api/fs.markdown index 29d3aa3339..e7a562d17a 100644 --- a/doc/api/fs.markdown +++ b/doc/api/fs.markdown @@ -63,26 +63,11 @@ Relative path to filename can be used, remember however that this path will be relative to `process.cwd()`. Most fs functions let you omit the callback argument. If you do, a default -callback is used that rethrows errors. To get a trace to the original call -site, set the NODE_DEBUG environment variable: +callback is used that ignores errors, but prints a deprecation +warning. - $ cat script.js - function bad() { - require('fs').readFile('/'); - } - bad(); - - $ env NODE_DEBUG=fs node script.js - fs.js:66 - throw err; - ^ - Error: EISDIR, read - at rethrow (fs.js:61:21) - at maybeCallback (fs.js:79:42) - at Object.fs.readFile (fs.js:153:18) - at bad (/path/to/script.js:2:17) - at Object. (/path/to/script.js:5:1) - +**IMPORTANT**: Omitting the callback is deprecated. v0.12 will throw the +errors as exceptions. ## fs.rename(oldPath, newPath, [callback]) From 6bd8b7e5405e1cdc9f56214f5f6b741806c32e5f Mon Sep 17 00:00:00 2001 From: isaacs Date: Wed, 13 Mar 2013 14:59:42 -0700 Subject: [PATCH 26/27] fs: Missing cb errors are deprecated, not a throw Commit a804347 makes fs function rethrow errors when the callback is omitted. While the right thing to do, it's a change from the old v0.8 behavior where such errors were silently ignored. To give users time to upgrade, temporarily disable that and replace it with a function that warns once about the deprecated behavior. Close #5005 --- lib/fs.js | 34 +++++++++++++++++++-------- test/simple/test-fs-readfile-error.js | 11 ++++++++- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index 3d37a648a7..49bb027376 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -59,22 +59,36 @@ var DEBUG = process.env.NODE_DEBUG && /fs/.test(process.env.NODE_DEBUG); function rethrow() { // Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and // is fairly slow to generate. + var callback; if (DEBUG) { var backtrace = new Error; - return function(err) { - if (err) { - backtrace.message = err.message; - err = backtrace; - throw err; - } - }; + callback = debugCallback; + } else + callback = missingCallback; + + return callback; + + function debugCallback(err) { + if (err) { + backtrace.message = err.message; + err = backtrace; + missingCallback(err); + } } - return function(err) { + function missingCallback(err) { if (err) { - throw err; // Forgot a callback but don't know where? Use NODE_DEBUG=fs + if (process.throwDeprecation) + throw err; // Forgot a callback but don't know where? Use NODE_DEBUG=fs + else if (!process.noDeprecation) { + var msg = 'fs: missing callback ' + (err.stack || err.message); + if (process.traceDeprecation) + console.trace(msg); + else + console.error(msg); + } } - }; + } } function maybeCallback(cb) { diff --git a/test/simple/test-fs-readfile-error.js b/test/simple/test-fs-readfile-error.js index 72e1e2e7fb..97d2f06a61 100644 --- a/test/simple/test-fs-readfile-error.js +++ b/test/simple/test-fs-readfile-error.js @@ -28,7 +28,7 @@ var callbacks = 0; function test(env, cb) { var filename = path.join(common.fixturesDir, 'test-fs-readfile-error.js'); - var execPath = process.execPath + ' ' + filename; + var execPath = process.execPath + ' --throw-deprecation ' + filename; var options = { env: env || {} }; exec(execPath, options, function(err, stdout, stderr) { assert(err); @@ -53,3 +53,12 @@ test({ NODE_DEBUG: 'fs' }, function(data) { process.on('exit', function() { assert.equal(callbacks, 2); }); + +(function() { + console.error('the warnings are normal here.'); + // just make sure that this doesn't crash the process. + var fs = require('fs'); + fs.readFile(__dirname); + fs.readdir(__filename); + fs.unlink('gee-i-sure-hope-this-file-isnt-important-or-existing'); +})(); From 6399839c398056756c0d668557339b99a54500e8 Mon Sep 17 00:00:00 2001 From: isaacs Date: Wed, 13 Mar 2013 15:48:56 -0700 Subject: [PATCH 27/27] Revert "stream: Never call decoder.end() multiple times" This reverts commit 615d809ac684a7d2cc7ee5e1aa58f0a921b529a0. --- lib/_stream_readable.js | 1 - test/simple/test-stream2-set-encoding.js | 4 ---- 2 files changed, 5 deletions(-) diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index c669455d7d..b09694c071 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -349,7 +349,6 @@ function onEofChunk(stream, state) { state.buffer.push(chunk); state.length += state.objectMode ? 1 : chunk.length; } - state.decoder = null; } // if we've ended and we have some data left, then emit diff --git a/test/simple/test-stream2-set-encoding.js b/test/simple/test-stream2-set-encoding.js index ad4d884680..8c5973fb63 100644 --- a/test/simple/test-stream2-set-encoding.js +++ b/test/simple/test-stream2-set-encoding.js @@ -163,10 +163,6 @@ test('setEncoding hex', function(t) { // just kick it off. tr.emit('readable'); - - process.on('exit', function() { - assert(!tr._readableState.decoder); - }); }); test('setEncoding hex with read(13)', function(t) {