From 671b5be6e9d74fec9e94b1ab88d2b2648c540078 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Fri, 27 Sep 2013 23:47:13 +0400 Subject: [PATCH 01/35] tls: fix sporadic hang and partial reads Do not decrement size in read loop, its used later, when comparing to `bytesRead`. fix #6270 NOTE: Original patch contributed by @roadrunner2 --- lib/tls.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/tls.js b/lib/tls.js index a758c8e01c..fe94a5121f 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -447,10 +447,9 @@ CryptoStream.prototype._read = function read(size) { var bytesRead = 0, start = this._buffer.offset; do { - var read = this._buffer.use(this.pair.ssl, out, size); + var read = this._buffer.use(this.pair.ssl, out, size - bytesRead); if (read > 0) { bytesRead += read; - size -= read; } // Handle and report errors From 994ce4c99fb1e284bcfdc2500ae62e0138bf140e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 28 Sep 2013 10:27:11 +0200 Subject: [PATCH 02/35] src: turn uv_pipe_open() failures into exceptions uv_pipe_open() is unlikely to fail but when it does, the failure should not be quietly ignored. Raise the error as an exception. See joyent/libuv#941. --- src/pipe_wrap.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc index 3952a0799c..14104b1a5d 100644 --- a/src/pipe_wrap.cc +++ b/src/pipe_wrap.cc @@ -269,9 +269,10 @@ Handle PipeWrap::Open(const Arguments& args) { UNWRAP(PipeWrap) - int fd = args[0]->IntegerValue(); - - uv_pipe_open(&wrap->handle_, fd); + if (uv_pipe_open(&wrap->handle_, args[0]->Int32Value())) { + uv_err_t err = uv_last_error(wrap->handle_.loop); + return ThrowException(UVException(err.code, "uv_pipe_open")); + } return scope.Close(v8::Null()); } From d7234c8d50a1af73f60d2d3c0cc7eed17429a481 Mon Sep 17 00:00:00 2001 From: Timothy J Fontaine Date: Mon, 30 Sep 2013 13:52:48 -0700 Subject: [PATCH 03/35] 2013.09.30, Version 0.10.20 (Stable) * tls: fix sporadic hang and partial reads (Fedor Indutny) - fixes "npm ERR! cb() never called!" --- ChangeLog | 8 +++++++- src/node_version.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 54cc5a2b96..95afb81362 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,10 @@ -2013.09.24, Version 0.10.19 (Stable) +2013.09.30, Version 0.10.20 (Stable) + +* tls: fix sporadic hang and partial reads (Fedor Indutny) + - fixes "npm ERR! cb() never called!" + + +2013.09.24, Version 0.10.19 (Stable), 6b5e6a5a3ec8d994c9aab3b800b9edbf1b287904 * uv: Upgrade to v0.10.17 diff --git a/src/node_version.h b/src/node_version.h index f02dbe3c2a..f30216795f 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -26,7 +26,7 @@ #define NODE_MINOR_VERSION 10 #define NODE_PATCH_VERSION 20 -#define NODE_VERSION_IS_RELEASE 0 +#define NODE_VERSION_IS_RELEASE 1 #ifndef NODE_TAG # define NODE_TAG "" From d537992d57b5f012206bcafdfd570c9b4cf07146 Mon Sep 17 00:00:00 2001 From: Timothy J Fontaine Date: Mon, 30 Sep 2013 15:06:14 -0700 Subject: [PATCH 04/35] Now working on 0.10.21 --- 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 f30216795f..3073630f97 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -24,9 +24,9 @@ #define NODE_MAJOR_VERSION 0 #define NODE_MINOR_VERSION 10 -#define NODE_PATCH_VERSION 20 +#define NODE_PATCH_VERSION 21 -#define NODE_VERSION_IS_RELEASE 1 +#define NODE_VERSION_IS_RELEASE 0 #ifndef NODE_TAG # define NODE_TAG "" From a63079f34cd29c0d599c43ab6142b271db2705a2 Mon Sep 17 00:00:00 2001 From: Timothy J Fontaine Date: Mon, 30 Sep 2013 15:06:14 -0700 Subject: [PATCH 05/35] blog: Post for v0.10.20 --- doc/blog/release/v0.10.20.md | 59 ++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 doc/blog/release/v0.10.20.md diff --git a/doc/blog/release/v0.10.20.md b/doc/blog/release/v0.10.20.md new file mode 100644 index 0000000000..70db1fe92c --- /dev/null +++ b/doc/blog/release/v0.10.20.md @@ -0,0 +1,59 @@ +date: Mon Sep 30 15:05:41 PDT 2013 +version: 0.10.20 +category: release +title: Node v0.10.20 (Stable) +slug: node-v0-10-20-stable + +2013.09.30, Version 0.10.20 (Stable) + +* tls: fix sporadic hang and partial reads (Fedor Indutny) + - fixes "npm ERR! cb() never called!" + + +Source Code: http://nodejs.org/dist/v0.10.20/node-v0.10.20.tar.gz + +Macintosh Installer (Universal): http://nodejs.org/dist/v0.10.20/node-v0.10.20.pkg + +Windows Installer: http://nodejs.org/dist/v0.10.20/node-v0.10.20-x86.msi + +Windows x64 Installer: http://nodejs.org/dist/v0.10.20/x64/node-v0.10.20-x64.msi + +Windows x64 Files: http://nodejs.org/dist/v0.10.20/x64/ + +Linux 32-bit Binary: http://nodejs.org/dist/v0.10.20/node-v0.10.20-linux-x86.tar.gz + +Linux 64-bit Binary: http://nodejs.org/dist/v0.10.20/node-v0.10.20-linux-x64.tar.gz + +Solaris 32-bit Binary: http://nodejs.org/dist/v0.10.20/node-v0.10.20-sunos-x86.tar.gz + +Solaris 64-bit Binary: http://nodejs.org/dist/v0.10.20/node-v0.10.20-sunos-x64.tar.gz + +Other release files: http://nodejs.org/dist/v0.10.20/ + +Website: http://nodejs.org/docs/v0.10.20/ + +Documentation: http://nodejs.org/docs/v0.10.20/api/ + +Shasums: +``` +6f827b5bb1184160a58e0aac711791b610c30afd node-v0.10.20-darwin-x64.tar.gz +89869942f09351a5256f9ff68c3e1c363f108e7a node-v0.10.20-darwin-x86.tar.gz +b7c0a79acddfaeda8af221acdd18640ef5c62e8a node-v0.10.20-linux-x64.tar.gz +709cd1a646447036abe3f57ea6e33bb1d411c229 node-v0.10.20-linux-x86.tar.gz +dbe318556bc7a4d7ea47947600edcdb375a92d8e node-v0.10.20-sunos-x64.tar.gz +b003527f645bfc8c65d890854e20c92edc1feb86 node-v0.10.20-sunos-x86.tar.gz +34015dac5e517492fec6584cacd2d9864056107e node-v0.10.20-x86.msi +a0408be15afd0b5d34b8762edab6420339a8c4ff node-v0.10.20.pkg +d8777ac318627c1413f01358ea5c455f0f86e4b5 node-v0.10.20.tar.gz +5f61f783345dc3663b03322d6387800d96560cd5 node.exe +bb81cb60eae4c6be9238aa05b5245f29609b6f96 node.exp +e06eab29b27de1908aa2cf624d438e15ee126640 node.lib +2495f7a88f0085df5206c0d0cb44131cf9715156 node.pdb +6036d6b1f2cf34a5055ed59b6519cb09cc6f86ff pkgsrc/nodejs-ia32-0.10.20.tgz +9b743d9a5d80758e8cd9d436e165c9569fa9d0fd pkgsrc/nodejs-x64-0.10.20.tgz +1b574ef4fe2ad61ce398415599f8f376b576e65d x64/node-v0.10.20-x64.msi +7137043329a25c36ad24d11d8e4ce6e5ff8a72b2 x64/node.exe +624c5bdb06ddd726457fa7b04197069ba021016b x64/node.exp +f61da5166124895495bd72520d6b6f730acc1cbc x64/node.lib +efa36de57eda469254fab252f24ef67c17f96f00 x64/node.pdb +``` From b7f36e187d1b5362a72b50779aff182d7131d8f5 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 1 Oct 2013 08:35:24 +0200 Subject: [PATCH 06/35] doc: link to pre-built binaries, add install note lLnk to http://nodejs.org/download/ and add a short primer on how to extract the tarballs. Fixes #6292. --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 2f018e5f9a..12fd05aa5f 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,19 @@ Windows: vcbuild.bat +You can download pre-built binaries for various operating systems from +[http://nodejs.org/download/](http://nodejs.org/download/). The Windows +and OS X installers will prompt you for the location to install to. +The tarballs are self-contained; you can extract them to a local directory +with: + + tar xzf /path/to/node---.tar.gz + +Or system-wide with: + + cd /usr/local && tar --strip-components 1 -xzf \ + /path/to/node---.tar.gz + ### To run the tests: Unix/Macintosh: From d97ea06d885c6c614bbe1d073cc9167cb66fd564 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 5 Oct 2013 14:45:10 +0200 Subject: [PATCH 07/35] doc: add warning to fs.exists() documentation Warn against the open-if-exists anti-pattern, it's susceptible to race conditions. --- doc/api/fs.markdown | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/api/fs.markdown b/doc/api/fs.markdown index 129f3c5767..f940e6364f 100644 --- a/doc/api/fs.markdown +++ b/doc/api/fs.markdown @@ -595,6 +595,13 @@ Then call the `callback` argument with either true or false. Example: util.debug(exists ? "it's there" : "no passwd!"); }); +`fs.exists()` is an anachronism and exists only for historical reasons. +There should almost never be a reason to use it in your own code. + +In particular, checking if a file exists before opening it is an anti-pattern +that leaves you vulnerable to race conditions: another process may remove the +file between the calls to `fs.exists()` and `fs.open()`. Just open the file +and handle the error when it's not there. ## fs.existsSync(path) From b011811a9ffec89721e6486e263e68db17546699 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 8 Oct 2013 11:25:22 +0200 Subject: [PATCH 08/35] fs: fix fs.truncate() file content zeroing bug fs.truncate() and its synchronous sibling are implemented in terms of open() + ftruncate(). Unfortunately, it opened the target file with mode 'w' a.k.a. 'write-only and create or truncate at open'. The subsequent call to ftruncate() then moved the end-of-file pointer from zero to the requested offset with the net result of a file that's neatly truncated at the right offset and filled with zero bytes only. This bug was introduced in commit 168a5557 but in fairness, before that commit fs.truncate() worked like fs.ftruncate() so it seems we've never had a working fs.truncate() until now. Fixes #6233. --- lib/fs.js | 4 +-- test/simple/test-fs-truncate-GH-6233.js | 44 +++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 test/simple/test-fs-truncate-GH-6233.js diff --git a/lib/fs.js b/lib/fs.js index 222efd1af6..2cc9431e45 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -556,7 +556,7 @@ fs.truncate = function(path, len, callback) { len = 0; } callback = maybeCallback(callback); - fs.open(path, 'w', function(er, fd) { + fs.open(path, 'r+', function(er, fd) { if (er) return callback(er); binding.ftruncate(fd, len, function(er) { fs.close(fd, function(er2) { @@ -575,7 +575,7 @@ fs.truncateSync = function(path, len) { len = 0; } // allow error to be thrown, but still close fd. - var fd = fs.openSync(path, 'w'); + var fd = fs.openSync(path, 'r+'); try { var ret = fs.ftruncateSync(fd, len); } finally { diff --git a/test/simple/test-fs-truncate-GH-6233.js b/test/simple/test-fs-truncate-GH-6233.js new file mode 100644 index 0000000000..472afdcab9 --- /dev/null +++ b/test/simple/test-fs-truncate-GH-6233.js @@ -0,0 +1,44 @@ +// 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 fs = require('fs'); + +var filename = common.tmpDir + '/truncate-file.txt'; + +// Synchronous test. +(function() { + fs.writeFileSync(filename, '0123456789'); + assert.equal(fs.readFileSync(filename).toString(), '0123456789'); + fs.truncateSync(filename, 5); + assert.equal(fs.readFileSync(filename).toString(), '01234'); +})(); + +// Asynchronous test. +(function() { + fs.writeFileSync(filename, '0123456789'); + assert.equal(fs.readFileSync(filename).toString(), '0123456789'); + fs.truncate(filename, 5, common.mustCall(function(err) { + if (err) throw err; + assert.equal(fs.readFileSync(filename).toString(), '01234'); + })); +})(); From 98c57c7c0724a3518f18a01a63fcc7bef2daf9f6 Mon Sep 17 00:00:00 2001 From: Dave Pacheco Date: Fri, 4 Oct 2013 15:02:42 -0700 Subject: [PATCH 09/35] dtrace: backport two byte string fix This is a partial backport of 5921158 Re #6309 Closes #6319 --- src/v8abbr.h | 16 ++++++ src/v8ustack.d | 136 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 125 insertions(+), 27 deletions(-) diff --git a/src/v8abbr.h b/src/v8abbr.h index 9a51e09f5d..7c662f4258 100644 --- a/src/v8abbr.h +++ b/src/v8abbr.h @@ -43,10 +43,24 @@ /* Instance types */ #define V8_IT_FIXEDARRAY V8DBG_TYPE_FIXEDARRAY__FIXED_ARRAY_TYPE #define V8_IT_CODE V8DBG_TYPE_CODE__CODE_TYPE +#define V8_IT_SCRIPT V8DBG_TYPE_SCRIPT__SCRIPT_TYPE /* Node-specific offsets */ #define NODE_OFF_EXTSTR_DATA sizeof(void*) +/* + * Not all versions of V8 have the offset for the "chars" array in the + * SeqTwoByteString class, but it's the same as the one for SeqOneByteString, + * which used to be called SeqAsciiString. + */ +#ifndef V8DBG_CLASS_SEQTWOBYTESTRING__CHARS__CHAR +#ifdef V8DBG_CLASS_SEQONEBYTESTRING__CHARS__CHAR +#define V8DBG_CLASS_SEQTWOBYTESTRING__CHARS__CHAR V8DBG_CLASS_SEQONEBYTESTRING__CHARS__CHAR +#else +#define V8DBG_CLASS_SEQTWOBYTESTRING__CHARS__CHAR V8DBG_CLASS_SEQASCIISTRING__CHARS__CHAR +#endif +#endif + /* Heap class->field offsets */ #define V8_OFF_HEAP(off) ((off) - 1) @@ -82,5 +96,7 @@ V8_OFF_HEAP(V8DBG_CLASS_HEAPOBJECT__MAP__MAP) #define V8_OFF_MAP_ATTRS \ V8_OFF_HEAP(V8DBG_CLASS_MAP__INSTANCE_ATTRIBUTES__INT) +#define V8_OFF_TWOBYTESTR_CHARS \ + V8_OFF_HEAP(V8DBG_CLASS_SEQTWOBYTESTRING__CHARS__CHAR) #endif /* V8_ABBR_H */ diff --git a/src/v8ustack.d b/src/v8ustack.d index d643f8fb8c..0b03bfa251 100644 --- a/src/v8ustack.d +++ b/src/v8ustack.d @@ -31,6 +31,9 @@ #define V8_MAP_PTR(ptr) \ ((ptr & ~V8_HeapObjectTagMask) | V8_HeapObjectTag) +#define V8_TYPE_SCRIPT(type) \ + ((type) == V8_IT_SCRIPT) + /* * Determine the encoding and representation of a V8 string. */ @@ -53,8 +56,11 @@ #define ASCII_SEQSTR(value) \ (V8_TYPE_STRING(value) && V8_STRENC_ASCII(value) && V8_STRREP_SEQ(value)) -#define ASCII_CONSSTR(value) \ - (V8_TYPE_STRING(value) && V8_STRENC_ASCII(value) && V8_STRREP_CONS(value)) +#define TWOBYTE_SEQSTR(value) \ + (V8_TYPE_STRING(value) && !V8_STRENC_ASCII(value) && V8_STRREP_SEQ(value)) + +#define IS_CONSSTR(value) \ + (V8_TYPE_STRING(value) && V8_STRREP_CONS(value)) #define ASCII_EXTSTR(value) \ (V8_TYPE_STRING(value) && V8_STRENC_ASCII(value) && V8_STRREP_EXT(value)) @@ -123,14 +129,16 @@ * "len": the string length * * "attrs": the type identifier for the string, which indicates the - * encoding and representation. We're only interested in ASCII - * encoded strings whose representation is one of: + * encoding and representation. We're only interested in strings + * whose representation is one of: + * + * SeqOneByteString stored directly as a char array inside the object * - * SeqString stored directly as a char array inside the object + * SeqTwoByteString stored as a UTF-16 char array inside the object * - * ConsString pointer to two strings that should be concatenated + * ConsString pointer to two strings that should be concatenated * - * ExternalString pointer to a char* outside the V8 heap + * ExternalString pointer to a char* outside the V8 heap */ /* @@ -141,27 +149,79 @@ this->map = V8_MAP_PTR(COPYIN_PTR(str + V8_OFF_HEAPOBJ_MAP)); \ attrs = COPYIN_UINT8(this->map + V8_OFF_MAP_ATTRS); +#define APPEND_SEQSTR(str, len, attrs) \ + APPEND_SEQONEBYTESTR(str, len, attrs) \ + APPEND_SEQTWOBYTESTR(str, len, attrs) + /* - * Print out the given SeqString, or do nothing if the string is not an ASCII - * SeqString. + * Print out the given SeqOneByteString, or do nothing if the string is not an ASCII + * SeqOneByteString. */ -#define APPEND_SEQSTR(str, len, attrs) \ - dtrace:helper:ustack: \ - /!this->done && len > 0 && ASCII_SEQSTR(attrs)/ \ - { \ +#define APPEND_SEQONEBYTESTR(str, len, attrs) \ + dtrace:helper:ustack: \ + /!this->done && len > 0 && ASCII_SEQSTR(attrs)/ \ + { \ copyinto(str + V8_OFF_STR_CHARS, len, this->buf + this->off); \ this->off += len; \ } +/* + * LOOP_ITER: macro to paste "block" while "ivar" is less than "dynmax" and + * "statmax". The subsequent LOOP_{4,8} macros facilitate pasting the same + * thing 4 and 8 times, respectively. Like much of the rest of the code in this + * file, this is regrettably necessary given the constraints under which we're + * expected to run. + */ +#define LOOP_ITER(ivar, dynmax, statmax, block) \ + ((ivar) < (dynmax)) && ((ivar) < (statmax)) && (block); (ivar)++; + +#define LOOP_4(block) \ + block \ + block \ + block \ + block \ + +#define LOOP_8(block) \ + LOOP_4(block) \ + LOOP_4(block) + +/* + * Print out the given SeqTwoByteString, or do nothing if the string is not an ASCII + * SeqTwoByteString. NOTE: if you bump MAX_TWOBYTESTR_CHARS, you'll also need + * to modify the LOOP_* macro calls below to match. + */ +#define MAX_TWOBYTESTR_CHARS 128 +#define MAX_TWOBYTESTR_BYTES (2 * MAX_TWOBYTESTR_CHARS) +#define TO_ASCII(c) ((c) < 128 ? (c) : '?') + +#define APPEND_SEQTWOBYTESTR(str, len, attrs) \ + dtrace:helper:ustack: \ + /!this->done && len > 0 && TWOBYTE_SEQSTR(attrs)/ \ + { \ + this->i = 0; \ + this->stbuf = (uint16_t *)alloca(MAX_TWOBYTESTR_BYTES + 2); \ + copyinto(str + V8_OFF_TWOBYTESTR_CHARS, \ + MAX_TWOBYTESTR_BYTES, this->stbuf); \ + this->stbuf[MAX_TWOBYTESTR_BYTES - 1] = '\0'; \ + this->stbuf[MAX_TWOBYTESTR_BYTES] = '\0'; \ + \ + LOOP_8(LOOP_8(LOOP_4(LOOP_ITER(this->i, len, \ + MAX_TWOBYTESTR_CHARS, \ + APPEND_CHR(TO_ASCII(this->stbuf[this->i])))))) \ + \ + this->i = 0; \ + this->stbuf = 0; \ + } + /* * Print out the given Node.js ExternalString, or do nothing if the string is * not an ASCII ExternalString. */ #define APPEND_NODESTR(str, len, attrs) \ - dtrace:helper:ustack: \ - /!this->done && len > 0 && ASCII_EXTSTR(attrs)/ \ - { \ - this->resource = COPYIN_PTR(str + V8_OFF_EXTSTR_RSRC); \ + dtrace:helper:ustack: \ + /!this->done && len > 0 && ASCII_EXTSTR(attrs)/ \ + { \ + this->resource = COPYIN_PTR(str + V8_OFF_EXTSTR_RSRC); \ this->dataptr = COPYIN_PTR(this->resource + NODE_OFF_EXTSTR_DATA); \ copyinto(this->dataptr, len, this->buf + this->off); \ this->off += len; \ @@ -226,7 +286,7 @@ */ #define EXPAND_STR(str, len, attrs, s1s, s1l, s1a, s2s, s2l, s2a) \ dtrace:helper:ustack: \ - /!this->done && len > 0 && ASCII_CONSSTR(attrs)/ \ + /!this->done && len > 0 && IS_CONSSTR(attrs)/ \ { \ len = 0; \ \ @@ -316,6 +376,7 @@ dtrace:helper:ustack: this->funcnamelen = 0; this->funcnameattrs = 0; this->script = (off_t) 0; + this->scriptattrs = 0; this->scriptnamestr = (off_t) 0; this->scriptnamelen = 0; this->scriptnameattrs = 0; @@ -477,24 +538,38 @@ dtrace:helper:ustack: APPEND_V8STR(this->funcnamestr, this->funcnamelen, this->funcnameattrs) /* - * Now look for the name of the script where the function was defined. + * Now look for the name of the script where the function was defined. The + * "script" itself may be undefined for special functions like "RegExp". */ dtrace:helper:ustack: /!this->done/ { this->script = COPYIN_PTR(this->shared + V8_OFF_SHARED_SCRIPT); + this->map = V8_MAP_PTR(COPYIN_PTR(this->script + V8_OFF_HEAPOBJ_MAP)); + this->scriptattrs = COPYIN_UINT8(this->map + V8_OFF_MAP_ATTRS); +} + +dtrace:helper:ustack: +/!this->done && !V8_TYPE_SCRIPT(this->scriptattrs)/ +{ + APPEND_CHR('\0'); + this->done = 1; + stringof(this->buf); +} + + +dtrace:helper:ustack: +/!this->done/ +{ this->scriptnamestr = COPYIN_PTR(this->script + V8_OFF_SCRIPT_NAME); LOAD_STRFIELDS(this->scriptnamestr, this->scriptnamelen, this->scriptnameattrs); - - APPEND_CHR4(' ','a','t',' '); } dtrace:helper:ustack: -/!this->done && this->scriptnamelen == 0/ +/!this->done && this->scriptnamelen != 0/ { - APPEND_CHR8('<','u','n','k','n','o','w','n'); - APPEND_CHR('>'); + APPEND_CHR4(' ','a','t',' '); } APPEND_V8STR(this->scriptnamestr, this->scriptnamelen, this->scriptnameattrs) @@ -511,6 +586,14 @@ dtrace:helper:ustack: this->le_attrs = COPYIN_UINT8(this->map + V8_OFF_MAP_ATTRS); } +dtrace:helper:ustack: +/!this->done && this->le_attrs != V8_IT_FIXEDARRAY && this->position == 0/ +{ + APPEND_CHR('\0'); + this->done = 1; + stringof(this->buf); +} + dtrace:helper:ustack: /!this->done && this->le_attrs != V8_IT_FIXEDARRAY/ { @@ -519,10 +602,9 @@ dtrace:helper:ustack: * undefined because V8 has not had to compute it yet. In this case we * just show the raw position and call it a day. */ - APPEND_CHR8(' ','p','o','s','i','t','i','o'); - APPEND_CHR('n'); + APPEND_CHR4(' ','p','o','s'); APPEND_CHR(' '); - APPEND_NUM(this->position); + APPEND_NUM(SMI_VALUE(this->position)); APPEND_CHR('\0'); this->done = 1; stringof(this->buf); From 9777890f5d9ce95f15c64d29f1c0a55c12d24c3e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 9 Oct 2013 17:46:17 +0200 Subject: [PATCH 10/35] tls: fix premature connection termination Destroying the TLS session implies destroying the underlying socket but before this commit, that was done with net.Socket#destroy() rather than net.Socket#destroySoon(). The former closes the connection right away, even when there is still data to write. In other words, sometimes the final TLS record got truncated. Fixes #6107. --- lib/tls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tls.js b/lib/tls.js index fe94a5121f..dcdd99a193 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -1400,7 +1400,7 @@ function pipe(pair, socket) { // Encrypted should be unpiped from socket to prevent possible // write after destroy. pair.encrypted.unpipe(socket); - socket.destroy(); + socket.destroySoon(); }); }); From 9c65387673eb51bfa17143edb24fc925045e62de Mon Sep 17 00:00:00 2001 From: isaacs Date: Mon, 9 Sep 2013 12:31:05 +0100 Subject: [PATCH 11/35] blog: Remove wp-to-markdown script --- tools/blog/wp-to-markdown.js | 189 ----------------------------------- 1 file changed, 189 deletions(-) delete mode 100644 tools/blog/wp-to-markdown.js diff --git a/tools/blog/wp-to-markdown.js b/tools/blog/wp-to-markdown.js deleted file mode 100644 index 65ec2d5b72..0000000000 --- a/tools/blog/wp-to-markdown.js +++ /dev/null @@ -1,189 +0,0 @@ -var sax = require('sax'); -var fs = require('fs'); -var parser = sax.parser(false, { lowercase: true }); -var assert = require('assert'); -var mkdirp = require('mkdirp'); -var url = require('url'); - -var input = fs.createReadStream(process.argv[2]); -input.on('data', function(c) { - parser.write(c.toString()); -}); -input.on('end', parser.end.bind(parser)); - -var post = null; -var author = null; -var authors = {}; -mkdirp.sync('out'); - -parser.onopentag = function (tag) { - switch (tag.name) { - case 'wp:author': - assert(author === null); - author = {}; - author.text = ''; - return; - - case 'wp:author_login': - assert(author); - author.field = 'login'; - author.text = ''; - return; - - case 'wp:author_display_name': - assert(author); - author.field = 'name'; - author.text = ''; - return - - case 'wp:author_first_name': - assert(author); - author.field = 'first_name'; - author.text = ''; - return; - - case 'wp:author_last_name': - assert(author); - author.field = 'last_name'; - author.text = ''; - return; - - case 'item': - assert(post === null); - post = {}; - post.text = ''; - return; - - case 'title': - if (post === null) return; - post.field = 'title'; - return - - case 'pubDate': - case 'wp:post_date': - post.field = 'date'; - return; - - case 'dc:creator': - post.field = 'author'; - return; - - case 'wp:status': - post.field = 'status'; - return; - - case 'category': - post.field = 'category'; - return; - - case 'content:encoded': - post.field = 'body'; - return; - - case 'link': - if (post) post.field = 'link'; - return; - - default: - if (post) post.field = null; - if (author) author.field = null; - return; - } -}; - -parser.onclosetag = function (tagName, tag) { - switch (tagName) { - case 'wp:author': - assert(author); - finishAuthor(); - return; - case 'item': - assert(post); - finishPost(); - return; - default: - if (post && post.field || author && author.field) finishField(); - return; - } -}; - -parser.ontext = parser.oncdata = function (text) { - if (author) { - if (author.field) author.text += text; - else author.text = ''; - } else if (post) { - if (post.field) post.text += text; - else post.field = ''; - } -}; - -function finishField() { - if (post && post.field) { - post[post.field] = post.text; - post.field = null; - post.text = ''; - } else if (author && author.field) { - author[author.field] = author.text; - author.field = null; - author.text = ''; - } -} - -function finishPost() { - // don't port drafts. - if (post.status === 'draft') { - return post = null; - } - post.date = new Date(post.date); - - if (post.link) { - post.slug = - url.parse(post.link) - .pathname - .replace(/\/+$/, '') - .split('/') - .pop(); - } - if (!post.slug) { - post.slug = - (post.title + '-' + post.date.toISOString()) - .replace(/[^a-z0-9]+/gi, '-') - .replace(/^-|-$/g, '') - .toLowerCase(); - } - post.slug = post.slug || '-'; - - delete post.text - delete post.link - delete post.field - post.author = authors[post.author] || post.author; - - post.body = post.body || ''; - - // actually write it! - var output = []; - Object.keys(post) - .filter(function (f) { return f !== 'body' }).forEach(function (k) { - output.push(k + ': ' + post[k]); - }) - output = output.join('\n') + '\n\n' + post.body.trim() + '\n'; - - var f = 'out/' + post.category + '/' + post.slug + '.md'; - console.log(f, post.title); - mkdirp.sync('out/' + post.category) - fs.writeFileSync(f, output, 'utf8'); - - post = null; -} - -function finishAuthor () { - author.name = author.name || - (author.first_name + ' ' + author.last_name) || - author.login; - delete author.first_name - delete author.last_name - delete author.text - delete author.field - authors[author.login] = author.name - author = null; -} From 51cdce8322b78814a8dbc9e1b8bd19eb305af312 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 10 Oct 2013 14:09:38 +0200 Subject: [PATCH 12/35] doc: addon: fix object instantiation examples * Extend examples to show how to handle non-constructor invocation in constructor callback functions. * Fix up examples to initialize member variables at object construction. * Fix up a few naming inconsistencies. Fixes #5701. --- doc/api/addons.markdown | 112 +++++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 41 deletions(-) diff --git a/doc/api/addons.markdown b/doc/api/addons.markdown index cb44538c82..65dce52e45 100644 --- a/doc/api/addons.markdown +++ b/doc/api/addons.markdown @@ -323,12 +323,13 @@ Then in `myobject.h` make your wrapper inherit from `node::ObjectWrap`: static void Init(v8::Handle exports); private: - MyObject(); + explicit MyObject(double value = 0); ~MyObject(); static v8::Handle New(const v8::Arguments& args); static v8::Handle PlusOne(const v8::Arguments& args); - double counter_; + static v8::Persistent constructor; + double value_; }; #endif @@ -343,8 +344,13 @@ prototype: using namespace v8; - MyObject::MyObject() {}; - MyObject::~MyObject() {}; + Persistent MyObject::constructor; + + MyObject::MyObject(double value) : value_(value) { + } + + MyObject::~MyObject() { + } void MyObject::Init(Handle exports) { // Prepare constructor template @@ -354,28 +360,34 @@ prototype: // Prototype tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"), FunctionTemplate::New(PlusOne)->GetFunction()); - - Persistent constructor = Persistent::New(tpl->GetFunction()); + constructor = Persistent::New(tpl->GetFunction()); exports->Set(String::NewSymbol("MyObject"), constructor); } Handle MyObject::New(const Arguments& args) { HandleScope scope; - MyObject* obj = new MyObject(); - obj->counter_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); - obj->Wrap(args.This()); - - return args.This(); + if (args.IsConstructCall()) { + // Invoked as constructor: `new MyObject(...)` + double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); + MyObject* obj = new MyObject(value); + obj->Wrap(args.This()); + return args.This(); + } else { + // Invoked as plain function `MyObject(...)`, turn into construct call. + const int argc = 1; + Local argv[argc] = { args[0] }; + return scope.Close(constructor->NewInstance(argc, argv)); + } } Handle MyObject::PlusOne(const Arguments& args) { HandleScope scope; MyObject* obj = ObjectWrap::Unwrap(args.This()); - obj->counter_ += 1; + obj->value_ += 1; - return scope.Close(Number::New(obj->counter_)); + return scope.Close(Number::New(obj->value_)); } Test it with: @@ -434,13 +446,13 @@ care of instantiating the object (i.e. it does the job of `new` in JavaScript): static v8::Handle NewInstance(const v8::Arguments& args); private: - MyObject(); + explicit MyObject(double value = 0); ~MyObject(); - static v8::Persistent constructor; static v8::Handle New(const v8::Arguments& args); static v8::Handle PlusOne(const v8::Arguments& args); - double counter_; + static v8::Persistent constructor; + double value_; }; #endif @@ -453,11 +465,14 @@ The implementation is similar to the above in `myobject.cc`: using namespace v8; - MyObject::MyObject() {}; - MyObject::~MyObject() {}; - Persistent MyObject::constructor; + MyObject::MyObject(double value) : value_(value) { + } + + MyObject::~MyObject() { + } + void MyObject::Init() { // Prepare constructor template Local tpl = FunctionTemplate::New(New); @@ -466,18 +481,24 @@ The implementation is similar to the above in `myobject.cc`: // Prototype tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"), FunctionTemplate::New(PlusOne)->GetFunction()); - constructor = Persistent::New(tpl->GetFunction()); } Handle MyObject::New(const Arguments& args) { HandleScope scope; - MyObject* obj = new MyObject(); - obj->counter_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); - obj->Wrap(args.This()); - - return args.This(); + if (args.IsConstructCall()) { + // Invoked as constructor: `new MyObject(...)` + double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); + MyObject* obj = new MyObject(value); + obj->Wrap(args.This()); + return args.This(); + } else { + // Invoked as plain function `MyObject(...)`, turn into construct call. + const int argc = 1; + Local argv[argc] = { args[0] }; + return scope.Close(constructor->NewInstance(argc, argv)); + } } Handle MyObject::NewInstance(const Arguments& args) { @@ -494,9 +515,9 @@ The implementation is similar to the above in `myobject.cc`: HandleScope scope; MyObject* obj = ObjectWrap::Unwrap(args.This()); - obj->counter_ += 1; + obj->value_ += 1; - return scope.Close(Number::New(obj->counter_)); + return scope.Close(Number::New(obj->value_)); } Test it with: @@ -540,7 +561,7 @@ In the following `addon.cc` we introduce a function `add()` that can take on two MyObject* obj2 = node::ObjectWrap::Unwrap( args[1]->ToObject()); - double sum = obj1->Val() + obj2->Val(); + double sum = obj1->Value() + obj2->Value(); return scope.Close(Number::New(sum)); } @@ -569,15 +590,15 @@ can probe private values after unwrapping the object: public: static void Init(); static v8::Handle NewInstance(const v8::Arguments& args); - double Val() const { return val_; } + double Value() const { return value_; } private: - MyObject(); + explicit MyObject(double value = 0); ~MyObject(); - static v8::Persistent constructor; static v8::Handle New(const v8::Arguments& args); - double val_; + static v8::Persistent constructor; + double value_; }; #endif @@ -590,28 +611,37 @@ The implementation of `myobject.cc` is similar as before: using namespace v8; - MyObject::MyObject() {}; - MyObject::~MyObject() {}; - Persistent MyObject::constructor; + MyObject::MyObject(double value) : value_(value) { + } + + MyObject::~MyObject() { + } + void MyObject::Init() { // Prepare constructor template Local tpl = FunctionTemplate::New(New); tpl->SetClassName(String::NewSymbol("MyObject")); tpl->InstanceTemplate()->SetInternalFieldCount(1); - constructor = Persistent::New(tpl->GetFunction()); } Handle MyObject::New(const Arguments& args) { HandleScope scope; - MyObject* obj = new MyObject(); - obj->val_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); - obj->Wrap(args.This()); - - return args.This(); + if (args.IsConstructCall()) { + // Invoked as constructor: `new MyObject(...)` + double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); + MyObject* obj = new MyObject(value); + obj->Wrap(args.This()); + return args.This(); + } else { + // Invoked as plain function `MyObject(...)`, turn into construct call. + const int argc = 1; + Local argv[argc] = { args[0] }; + return scope.Close(constructor->NewInstance(argc, argv)); + } } Handle MyObject::NewInstance(const Arguments& args) { From ff1efdd6eea23499797dd1b35c79cbdcd513fd09 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 10 Oct 2013 14:34:15 +0200 Subject: [PATCH 13/35] doc: net: remove bad net.Server description net.Server is not an instance of net.Socket so don't say it is. --- doc/api/net.markdown | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/api/net.markdown b/doc/api/net.markdown index 160e2375ef..d80e80b4a5 100644 --- a/doc/api/net.markdown +++ b/doc/api/net.markdown @@ -116,7 +116,6 @@ The `connectListener` parameter will be added as an listener for the ## Class: net.Server This class is used to create a TCP or UNIX server. -A server is a `net.Socket` that can listen for new incoming connections. ### server.listen(port, [host], [backlog], [callback]) From 720675e7dbec2d3aabb16f316747a0517845bd17 Mon Sep 17 00:00:00 2001 From: Dave Pacheco Date: Thu, 10 Oct 2013 09:41:59 -0700 Subject: [PATCH 14/35] test: use proper findjsobjects output format Closes #6329 --- test/pummel/test-postmortem-findjsobjects.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/pummel/test-postmortem-findjsobjects.js b/test/pummel/test-postmortem-findjsobjects.js index 568e2ff059..292b060933 100644 --- a/test/pummel/test-postmortem-findjsobjects.js +++ b/test/pummel/test-postmortem-findjsobjects.js @@ -67,7 +67,7 @@ gcore.on('exit', function (code) { } var lines = output.split('\n'); - var found = 0, i, expected = 'OBEY: ' + obj.OBEY, nexpected = 2; + var found = 0, i, expected = 'OBEY: "' + obj.OBEY + '"', nexpected = 2; for (var i = 0; i < lines.length; i++) { if (lines[i].indexOf(expected) != -1) From 56c5806da36204e46b68e7f2c050242b0f635596 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 14 Oct 2013 12:15:00 +0100 Subject: [PATCH 15/35] doc: document os.loadavg() behavior on windows The load average is a very UNIX-y concept. That's why os.loadavg() always returns zeros on Windows. Mention that in the documentation. --- doc/api/os.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/api/os.markdown b/doc/api/os.markdown index ae620e895c..177f499249 100644 --- a/doc/api/os.markdown +++ b/doc/api/os.markdown @@ -41,6 +41,7 @@ Returns the system uptime in seconds. ## os.loadavg() Returns an array containing the 1, 5, and 15 minute load averages. +This function always return `[0, 0, 0]` on Windows. ## os.totalmem() From 9a3a0ccc502f8799db34b7937a0e588980a8922d Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 15 Oct 2013 10:01:50 +0200 Subject: [PATCH 16/35] doc: expand os.loadavg() section Add a short explanation of what the load average is and why it's unavailable on Windows. Also sneak in a fix for a typo that I introduced in commit 56c5806. --- doc/api/os.markdown | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/api/os.markdown b/doc/api/os.markdown index 177f499249..7aa710585b 100644 --- a/doc/api/os.markdown +++ b/doc/api/os.markdown @@ -41,7 +41,14 @@ Returns the system uptime in seconds. ## os.loadavg() Returns an array containing the 1, 5, and 15 minute load averages. -This function always return `[0, 0, 0]` on Windows. + +The load average is a measure of system activity, calculated by the operating +system and expressed as a fractional number. As a rule of thumb, the load +average should ideally be less than the number of logical CPUs in the system. + +The load average is a very UNIX-y concept; there is no real equivalent on +Windows platforms. That is why this function always returns `[0, 0, 0]` on +Windows. ## os.totalmem() From 5ef03bc3eed4da297ffabafc633b07e4f0171861 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 16 Oct 2013 12:20:25 +0200 Subject: [PATCH 17/35] doc: http: add cross-links for easier clicking Make it a little easier to navigate the http module documentation by turning class names and methods into links to the appropriate section. --- doc/api/http.markdown | 57 +++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/doc/api/http.markdown b/doc/api/http.markdown index a1b1a598db..624b9a9506 100644 --- a/doc/api/http.markdown +++ b/doc/api/http.markdown @@ -56,8 +56,8 @@ This is an [EventEmitter][] with the following events: Emitted each time there is a request. Note that there may be multiple requests per connection (in the case of keep-alive connections). - `request` is an instance of `http.IncomingMessage` and `response` is - an instance of `http.ServerResponse` + `request` is an instance of [http.IncomingMessage][] and `response` is +an instance of [http.ServerResponse][]. ### Event: 'connection' @@ -83,7 +83,7 @@ Emitted each time a request with an http Expect: 100-continue is received. If this event isn't listened for, the server will automatically respond with a 100 Continue as appropriate. -Handling this event involves calling `response.writeContinue` if the client +Handling this event involves calling [response.writeContinue()][] if the client should continue to send the request body, or generating an appropriate HTTP response (e.g., 400 Bad Request) if the client should not continue to send the request body. @@ -233,7 +233,7 @@ The response implements the [Writable Stream][] interface. This is an `function () { }` Indicates that the underlying connection was terminated before -`response.end()` was called or able to flush. +[response.end()][] was called or able to flush. ### response.writeContinue() @@ -255,9 +255,9 @@ Example: 'Content-Type': 'text/plain' }); This method must only be called once on a message and it must -be called before `response.end()` is called. +be called before [response.end()][] is called. -If you call `response.write()` or `response.end()` before calling this, the +If you call [response.write()][] or [response.end()][] before calling this, the implicit/mutable headers will be calculated and call this function for you. Note: that Content-Length is given in bytes not characters. The above example @@ -284,9 +284,9 @@ sockets. ### response.statusCode -When using implicit headers (not calling `response.writeHead()` explicitly), this property -controls the status code that will be sent to the client when the headers get -flushed. +When using implicit headers (not calling [response.writeHead()][] explicitly), +this property controls the status code that will be sent to the client when +the headers get flushed. Example: @@ -342,8 +342,8 @@ Example: ### response.write(chunk, [encoding]) -If this method is called and `response.writeHead()` has not been called, it will -switch to implicit header mode and flush the implicit headers. +If this method is called and [response.writeHead()][] has not been called, +it will switch to implicit header mode and flush the implicit headers. This sends a chunk of the response body. This method may be called multiple times to provide successive parts of the body. @@ -424,7 +424,7 @@ Options: - `false`: opts out of connection pooling with an Agent, defaults request to `Connection: close`. -`http.request()` returns an instance of the `http.ClientRequest` +`http.request()` returns an instance of the [http.ClientRequest][] class. The `ClientRequest` instance is a writable stream. If one needs to upload a file with a POST request, then write to the `ClientRequest` object. @@ -556,7 +556,7 @@ data chunk or when closing the connection. To get the response, add a listener for `'response'` to the request object. `'response'` will be emitted from the request object when the response headers have been received. The `'response'` event is executed with one -argument which is an instance of `http.IncomingMessage`. +argument which is an instance of [http.IncomingMessage][]. During the `'response'` event, one can add listeners to the response object; particularly to listen for the `'data'` event. @@ -581,7 +581,7 @@ The request implements the [Writable Stream][] interface. This is an `function (response) { }` Emitted when a response is received to this request. This event is emitted only -once. The `response` argument will be an instance of `http.IncomingMessage`. +once. The `response` argument will be an instance of [http.IncomingMessage][]. Options: @@ -760,9 +760,10 @@ Once a socket is assigned to this request and is connected ## http.IncomingMessage -An `IncomingMessage` object is created by `http.Server` or `http.ClientRequest` -and passed as the first argument to the `'request'` and `'response'` event -respectively. It may be used to access response status, headers and data. +An `IncomingMessage` object is created by [http.Server][] or +[http.ClientRequest][] and passed as the first argument to the `'request'` +and `'response'` event respectively. It may be used to access response status, +headers and data. It implements the [Readable Stream][] interface, as well as the following additional events, methods, and properties. @@ -813,14 +814,14 @@ Calls `message.connection.setTimeout(msecs, callback)`. ### message.method -**Only valid for request obtained from `http.Server`.** +**Only valid for request obtained from [http.Server][].** The request method as a string. Read only. Example: `'GET'`, `'DELETE'`. ### message.url -**Only valid for request obtained from `http.Server`.** +**Only valid for request obtained from [http.Server][].** Request URL string. This contains only the URL that is present in the actual HTTP request. If the request is: @@ -867,21 +868,29 @@ request.connection.getPeerCertificate() to obtain the client's authentication details. -[Agent]: #http_class_http_agent ['checkContinue']: #http_event_checkcontinue +['listening']: net.html#net_event_listening +[Agent]: #http_class_http_agent [Buffer]: buffer.html#buffer_buffer [EventEmitter]: events.html#events_class_events_eventemitter +[Readable Stream]: stream.html#stream_readable_stream +[Writable Stream]: stream.html#stream_writable_stream [global Agent]: #http_http_globalagent +[http.ClientRequest]: #http_class_http_clientrequest +[http.IncomingMessage]: #http_http_incomingmessage +[http.ServerResponse]: #http_class_http_serverresponse +[http.Server]: #http_class_http_server +[http.request()]: #http_http_request_options_callback [http.request()]: #http_http_request_options_callback -[http.IncomingMessage]: #http_class_http_incomingmessage -['listening']: net.html#net_event_listening [net.Server.close()]: net.html#net_server_close_callback [net.Server.listen(path)]: net.html#net_server_listen_path_callback [net.Server.listen(port)]: net.html#net_server_listen_port_host_backlog_callback -[Readable Stream]: stream.html#stream_readable_stream +[response.end()]: #http_response_end_data_encoding +[response.write()]: #http_response_write_chunk_encoding +[response.writeContinue()]: #http_response_writecontinue +[response.writeHead()]: #http_response_writehead_statuscode_reasonphrase_headers [socket.setKeepAlive()]: net.html#net_socket_setkeepalive_enable_initialdelay [socket.setNoDelay()]: net.html#net_socket_setnodelay_nodelay [socket.setTimeout()]: net.html#net_socket_settimeout_timeout_callback [stream.setEncoding()]: stream.html#stream_stream_setencoding_encoding [url.parse()]: url.html#url_url_parse_urlstr_parsequerystring_slashesdenotehost -[Writable Stream]: stream.html#stream_writable_stream From 5bc5210b923697ab53f0ac0aa8616e28b16b73e9 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 16 Oct 2013 12:32:47 +0200 Subject: [PATCH 18/35] doc: http: reword IncomingMessage 'close' event The bit that says "before response.end() was called or able to flush" doesn't apply to incoming streams. Fixes #6359. --- doc/api/http.markdown | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/doc/api/http.markdown b/doc/api/http.markdown index 624b9a9506..88f313dbf3 100644 --- a/doc/api/http.markdown +++ b/doc/api/http.markdown @@ -772,11 +772,8 @@ following additional events, methods, and properties. `function () { }` -Indicates that the underlaying connection was terminated before -`response.end()` was called or able to flush. - -Just like `'end'`, this event occurs only once per response. See -[http.ServerResponse][]'s `'close'` event for more information. +Indicates that the underlaying connection was closed. +Just like `'end'`, this event occurs only once per response. ### message.httpVersion From ed186c971c3a3c724bdccdcc2e5b70f57588dd69 Mon Sep 17 00:00:00 2001 From: Sam Roberts Date: Thu, 25 Jul 2013 17:35:21 -0700 Subject: [PATCH 19/35] doc: child_process corrections and cleanups - Make explicit that .disconnected is set before the disconnect event, and it is not allowed to send messages after calling .disconnect(), even while waiting for a delayed disconect event. - Remove obsolete claim that explicit exit is required - Describe silent: in the options for fork() - Describe .connected as the property it is, not just as an aside in the disconnect() method --- doc/api/child_process.markdown | 44 +++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/doc/api/child_process.markdown b/doc/api/child_process.markdown index 846649429a..d21f7db3e6 100644 --- a/doc/api/child_process.markdown +++ b/doc/api/child_process.markdown @@ -52,6 +52,9 @@ of the signal, otherwise `null`. Note that the child process stdio streams might still be open. +Also, note that node establishes signal handlers for `'SIGINT'` and `'SIGTERM`', +so it will not terminate due to receipt of those signals, it will exit. + See `waitpid(2)`. ### Event: 'close' @@ -66,10 +69,9 @@ might share the same stdio streams. ### Event: 'disconnect' -This event is emitted after using the `.disconnect()` method in the parent or -in the child. After disconnecting it is no longer possible to send messages. -An alternative way to check if you can send messages is to see if the -`child.connected` property is `true`. +This event is emitted after calling the `.disconnect()` method in the parent +or in the child. After disconnecting it is no longer possible to send messages, +and the `.connected` property is false. ### Event: 'message' @@ -121,6 +123,12 @@ Example: console.log('Spawned child pid: ' + grep.pid); grep.stdin.end(); +### child.connected + +* {Boolean} Set to false after `.disconnect' is called + +If `.connected` is false, it is no longer possible to send messages. + ### child.kill([signal]) * `signal` {String} @@ -265,12 +273,15 @@ It is also recommended not to use `.maxConnections` in this condition. ### child.disconnect() -To close the IPC connection between parent and child use the -`child.disconnect()` method. This allows the child to exit gracefully since -there is no IPC channel keeping it alive. When calling this method the -`disconnect` event will be emitted in both parent and child, and the -`connected` flag will be set to `false`. Please note that you can also call -`process.disconnect()` in the child process. +Close the IPC channel between parent and child, allowing the child to exit +gracefully once there are no other connections keeping it alive. After calling +this method the `.connected` flag will be set to `false` in both the parent and +child, and it is no longer possible to send messages. + +The 'disconnect' event will be emitted when there are no messages in the process +of being received, most likely immediately. + +Note that you can also call `process.disconnect()` in the child process. ## child_process.spawn(command, [args], [options]) @@ -465,7 +476,7 @@ See also: `child_process.exec()` and `child_process.fork()` * `env` {Object} Environment key-value pairs * `encoding` {String} (Default: 'utf8') * `timeout` {Number} (Default: 0) - * `maxBuffer` {Number} (Default: 200*1024) + * `maxBuffer` {Number} (Default: `200*1024`) * `killSignal` {String} (Default: 'SIGTERM') * `callback` {Function} called with the output when process terminates * `error` {Error} @@ -531,7 +542,7 @@ subshell but rather the specified file directly. This makes it slightly leaner than `child_process.exec`. It has the same options. -## child\_process.fork(modulePath, [args], [options]) +## child_process.fork(modulePath, [args], [options]) * `modulePath` {String} The module to run in the child * `args` {Array} List of string arguments @@ -540,6 +551,8 @@ leaner than `child_process.exec`. It has the same options. * `env` {Object} Environment key-value pairs * `encoding` {String} (Default: 'utf8') * `execPath` {String} Executable used to create the child process + * `silent` {Boolean} If true, prevent stdout and stderr in the spawned node + process from being associated with the parent's (default is false) * Return: ChildProcess object This is a special case of the `spawn()` functionality for spawning Node @@ -547,13 +560,6 @@ processes. In addition to having all the methods in a normal ChildProcess instance, the returned object has a communication channel built-in. See `child.send(message, [sendHandle])` for details. -By default the spawned Node process will have the stdout, stderr associated -with the parent's. To change this behavior set the `silent` property in the -`options` object to `true`. - -The child process does not automatically exit once it's done, you need to call -`process.exit()` explicitly. This limitation may be lifted in the future. - These child Nodes are still whole new instances of V8. Assume at least 30ms startup and 10mb memory for each new Node. That is, you cannot create many thousands of them. From 2e16037201b6338914d41048660c1ce713094893 Mon Sep 17 00:00:00 2001 From: Sam Roberts Date: Thu, 25 Jul 2013 18:17:38 -0700 Subject: [PATCH 20/35] doc: cluster documentation cleanup and corrections - fixed some incomprehensible wording ("event assigned to..."?) - removed undocumented and unnecessary process properties from example - corrected the docs on the default for the exec setting - described when workers are removed from cluster.workers - described addressType, which was documented as existing, but not what values it might have - spell out more clearly the limitations of setupMaster - describe disconnect in sufficient detail that why a child does or does not exit can be understood - clarify which cluster functions and events are available on process or just on the worker, as well as which are not available in children, - don't describe events as the same, when they have receive different arguments - fix misleading disconnect example: since disconnect already calls close on all servers, doing it again in the example is a no-op, not the "force close" it was claimed to be - document the error event, not catching it will kill your node - describe suicide better, it is important, and a bit unintuitive (process.exit() is not suicide?) - use worker consistently throughout, instead of child. --- doc/api/cluster.markdown | 226 ++++++++++++++++++++++++--------------- 1 file changed, 141 insertions(+), 85 deletions(-) diff --git a/doc/api/cluster.markdown b/doc/api/cluster.markdown index 809efa5ed9..3e49368276 100644 --- a/doc/api/cluster.markdown +++ b/doc/api/cluster.markdown @@ -6,7 +6,7 @@ A single instance of Node runs in a single thread. To take advantage of multi-core systems the user will sometimes want to launch a cluster of Node processes to handle the load. -The cluster module allows you to easily create a network of processes that +The cluster module allows you to easily create child processes that all share server ports. var cluster = require('cluster'); @@ -58,7 +58,7 @@ arguments and passes the request to the master process. If the master process already has a listening server matching the worker's requirements, then it passes the handle to the worker. If it does not already have a listening server matching that requirement, then it will -create one, and pass the handle to the child. +create one, and pass the handle to the worker. This causes potentially surprising behavior in three edge cases: @@ -94,13 +94,18 @@ the worker pool for your application's needs. ## cluster.settings * {Object} - * `exec` {String} file path to worker file. (Default=`__filename`) + * `exec` {String} file path to worker file. (Default=`process.argv[1]`) * `args` {Array} string arguments passed to worker. (Default=`process.argv.slice(2)`) * `silent` {Boolean} whether or not to send output to parent's stdio. (Default=`false`) -All settings set by the `.setupMaster` is stored in this settings object. +After calling `.setupMaster()` (or `.fork()`) this settings object will contain +the settings, including the default values. + +It is effectively frozen after being set, because `.setupMaster()` can +only be called once. + This object is not supposed to be changed or set manually, by you. ## cluster.isMaster @@ -115,9 +120,7 @@ undefined, then `isMaster` is `true`. * {Boolean} -This boolean flag is true if the process is a worker forked from a master. -If the `process.env.NODE_UNIQUE_ID` is set to a value, then -`isWorker` is `true`. +True if the process is not a master (it is the negation of `cluster.isMaster`). ## Event: 'fork' @@ -146,11 +149,10 @@ This can be used to log worker activity, and create you own timeout. * `worker` {Worker object} -After forking a new worker, the worker should respond with a online message. -When the master receives a online message it will emit such event. +After forking a new worker, the worker should respond with an online message. +When the master receives an online message it will emit this event. The difference between 'fork' and 'online' is that fork is emitted when the -master tries to fork a worker, and 'online' is emitted when the worker is -being executed. +master forks a worker, and 'online' is emitted when the worker is running. cluster.on('online', function(worker) { console.log("Yay, the worker responded after it was forked"); @@ -161,9 +163,8 @@ being executed. * `worker` {Worker object} * `address` {Object} -When calling `listen()` from a worker, a 'listening' event is automatically assigned -to the server instance. When the server is listening a message is send to the master -where the 'listening' event is emitted. +After calling `listen()` from a worker, when the 'listening' event is emitted on +the server, a listening event will also be emitted on `cluster` in the master. The event handler is executed with two arguments, the `worker` contains the worker object and the `address` object contains the following connection properties: @@ -174,18 +175,24 @@ on more than one address. console.log("A worker is now connected to " + address.address + ":" + address.port); }); +The `addressType` is one of: + +* `4' (TCPv4) +* `6` (TCPv6) +* `-1` (unix domain socket) +* `"udp4"` or `"udp6"` (UDP v4 or v6) + ## Event: 'disconnect' * `worker` {Worker object} -When a workers IPC channel has disconnected this event is emitted. -This will happen when the worker dies, usually after calling -`.kill()`. +Emitted after the worker IPC channel has disconnected. This can occur when a +worker exits gracefully, is killed, or is disconnected manually (such as with +worker.disconnect()). -When calling `.disconnect()`, there may be a delay between the -`disconnect` and `exit` events. This event can be used to detect if -the process is stuck in a cleanup or if there are long-living -connections. +There may be a delay between the `disconnect` and `exit` events. These events +can be used to detect if the process is stuck in a cleanup or if there are +long-living connections. cluster.on('disconnect', function(worker) { console.log('The worker #' + worker.id + ' has disconnected'); @@ -199,33 +206,42 @@ connections. the process to be killed. When any of the workers die the cluster module will emit the 'exit' event. -This can be used to restart the worker by calling `fork()` again. + +This can be used to restart the worker by calling `.fork()` again. cluster.on('exit', function(worker, code, signal) { - var exitCode = worker.process.exitCode; - console.log('worker ' + worker.process.pid + ' died ('+exitCode+'). restarting...'); + console.log('worker %d died (%s). restarting...', + worker.process.pid, signal || code); cluster.fork(); }); -## Event: 'setup' +See [child_process event: 'exit'](child_process.html#child_process_event_exit). -* `worker` {Worker object} +## Event: 'setup' -When the `.setupMaster()` function has been executed this event emits. -If `.setupMaster()` was not executed before `fork()` this function will -call `.setupMaster()` with no arguments. +Emitted the first time that `.setupMaster()` is called. ## cluster.setupMaster([settings]) * `settings` {Object} - * `exec` {String} file path to worker file. (Default=`__filename`) + * `exec` {String} file path to worker file. (Default=`process.argv[1]`) * `args` {Array} string arguments passed to worker. (Default=`process.argv.slice(2)`) * `silent` {Boolean} whether or not to send output to parent's stdio. (Default=`false`) -`setupMaster` is used to change the default 'fork' behavior. The new settings -are effective immediately and permanently, they cannot be changed later on. +`setupMaster` is used to change the default 'fork' behavior. Once called, +the settings will be present in `cluster.settings`. + +Note that: + +* Only the first call to `.setupMaster()` has any effect, subsequent calls are + ignored +* That because of the above, the *only* attribute of a worker that may be + customized per-worker is the `env` passed to `.fork()` +* `.fork()` calls `.setupMaster()` internally to establish the defaults, so to + have any effect, `.setupMaster()` must be called *before* any calls to + `.fork()` Example: @@ -237,23 +253,31 @@ Example: }); cluster.fork(); +This can only be called from the master process. + ## cluster.fork([env]) -* `env` {Object} Key/value pairs to add to child process environment. +* `env` {Object} Key/value pairs to add to worker process environment. * return {Worker object} -Spawn a new worker process. This can only be called from the master process. +Spawn a new worker process. + +This can only be called from the master process. ## cluster.disconnect([callback]) -* `callback` {Function} called when all workers are disconnected and handlers are closed +* `callback` {Function} called when all workers are disconnected and handles are + closed -When calling this method, all workers will commit a graceful suicide. When they are -disconnected all internal handlers will be closed, allowing the master process to -die graceful if no other event is waiting. +Calls `.disconnect()` on each worker in `cluster.workers`. + +When they are disconnected all internal handles will be closed, allowing the +master process to die gracefully if no other event is waiting. The method takes an optional callback argument which will be called when finished. +This can only be called from the master process. + ## cluster.worker * {Object} @@ -278,6 +302,9 @@ A hash that stores the active worker objects, keyed by `id` field. Makes it easy to loop through all the workers. It is only available in the master process. +A worker is removed from cluster.workers just before the `'disconnect'` or +`'exit'` event is emitted. + // Go through all workers function eachWorker(callback) { for (var id in cluster.workers) { @@ -316,17 +343,33 @@ cluster.workers * {ChildProcess object} All workers are created using `child_process.fork()`, the returned object -from this function is stored in process. +from this function is stored as `.process`. In a worker, the global `process` +is stored. -See: [Child Process module](child_process.html) +See: [Child Process module]( +child_process.html#child_process_child_process_fork_modulepath_args_options) + +Note that workers will call `process.exit(0)` if the `'disconnect'` event occurs +on `process` and `.suicide` is not `true`. This protects against accidental +disconnection. ### worker.suicide * {Boolean} -This property is a boolean. It is set when a worker dies after calling -`.kill()` or immediately after calling the `.disconnect()` method. -Until then it is `undefined`. +Set by calling `.kill()` or `.disconnect()`, until then it is `undefined`. + +The boolean `worker.suicide` lets you distinguish between voluntary and accidental +exit, the master may choose not to respawn a worker based on this value. + + cluster.on('exit', function(worker, code, signal) { + if (worker.suicide === true) { + console.log('Oh, it was just suicide\' – no need to worry'). + } + }); + + // kill worker + worker.kill(); ### worker.send(message, [sendHandle]) @@ -335,8 +378,9 @@ Until then it is `undefined`. This function is equal to the send methods provided by `child_process.fork()`. In the master you should use this function to -send a message to a specific worker. However in a worker you can also use -`process.send(message)`, since this is the same function. +send a message to a specific worker. + +In a worker you can also use `process.send(message)`, it is the same function. This example will echo back all messages from the master: @@ -355,44 +399,54 @@ This example will echo back all messages from the master: * `signal` {String} Name of the kill signal to send to the worker process. -This function will kill the worker, and inform the master to not spawn a -new worker. The boolean `suicide` lets you distinguish between voluntary -and accidental exit. +This function will kill the worker. In the master, it does this by disconnecting +the `worker.process`, and once disconnected, killing with `signal`. In the +worker, it does it by disconnecting the channel, and then exiting with code `0`. - cluster.on('exit', function(worker, code, signal) { - if (worker.suicide === true) { - console.log('Oh, it was just suicide\' – no need to worry'). - } - }); +Causes `.suicide` to be set. - // kill worker - worker.kill(); +This method is aliased as `worker.destroy()` for backwards compatibility. -This method is aliased as `worker.destroy()` for backwards -compatibility. +Note that in a worker, `process.kill()` exists, but it is not this function, +it is [kill](process.html#process_process_kill_pid_signal). ### worker.disconnect() -When calling this function the worker will no longer accept new connections, but -they will be handled by any other listening worker. Existing connection will be -allowed to exit as usual. When no more connections exist, the IPC channel to the worker -will close allowing it to die graceful. When the IPC channel is closed the `disconnect` -event will emit, this is then followed by the `exit` event, there is emitted when -the worker finally die. +In a worker, this function will close all servers, wait for the 'close' event on +those servers, and then disconnect the IPC channel. + +In the master, an internal message is sent to the worker causing it to call +`.disconnect()` on itself. + +Causes `.suicide` to be set. -Because there might be long living connections, it is useful to implement a timeout. -This example ask the worker to disconnect and after 2 seconds it will destroy the -server. An alternative would be to execute `worker.kill()` after 2 seconds, but -that would normally not allow the worker to do any cleanup if needed. +Note that after a server is closed, it will no longer accept new connections, +but connections may be accepted by any other listening worker. Existing +connections will be allowed to close as usual. When no more connections exist, +see [server.close()](net.html#net_event_close), the IPC channel to the worker +will close allowing it to die gracefully. + +The above applies *only* to server connections, client connections are not +automatically closed by workers, and disconnect does not wait for them to close +before exiting. + +Note that in a worker, `process.disconnect` exists, but it is not this function, +it is [disconnect](child_process.html#child_process_child_disconnect). + +Because long living server connections may block workers from disconnecting, it +may be useful to send a message, so application specific actions may be taken to +close them. It also may be useful to implement a timeout, killing a worker if +the `disconnect` event has not been emitted after some time. if (cluster.isMaster) { var worker = cluster.fork(); var timeout; worker.on('listening', function(address) { + worker.send('shutdown'); worker.disconnect(); timeout = setTimeout(function() { - worker.send('force kill'); + worker.kill(); }, 2000); }); @@ -403,18 +457,14 @@ that would normally not allow the worker to do any cleanup if needed. } else if (cluster.isWorker) { var net = require('net'); var server = net.createServer(function(socket) { - // connection never end + // connections never end }); server.listen(8000); - server.on('close', function() { - // cleanup - }); - process.on('message', function(msg) { - if (msg === 'force kill') { - server.close(); + if(msg === 'shutdown') { + // initiate graceful close of any connections to server } }); } @@ -424,8 +474,8 @@ that would normally not allow the worker to do any cleanup if needed. * `message` {Object} This event is the same as the one provided by `child_process.fork()`. -In the master you should use this event, however in a worker you can also use -`process.on('message')` + +In a worker you can also use `process.on('message')`. As an example, here is a cluster that keeps count of the number of requests in the master process using the message system: @@ -472,28 +522,29 @@ in the master process using the message system: ### Event: 'online' -Same as the `cluster.on('online')` event, but emits only when the state change -on the specified worker. +Similar to the `cluster.on('online')` event, but specific to this worker. cluster.fork().on('online', function() { // Worker is online }); +It is not emitted in the worker. + ### Event: 'listening' * `address` {Object} -Same as the `cluster.on('listening')` event, but emits only when the state change -on the specified worker. +Similar to the `cluster.on('listening')` event, but specific to this worker. cluster.fork().on('listening', function(address) { // Worker is listening }); +It is not emitted in the worker. + ### Event: 'disconnect' -Same as the `cluster.on('disconnect')` event, but emits only when the state change -on the specified worker. +Similar to the `cluster.on('disconnect')` event, but specfic to this worker. cluster.fork().on('disconnect', function() { // Worker has disconnected @@ -505,8 +556,7 @@ on the specified worker. * `signal` {String} the name of the signal (eg. `'SIGHUP'`) that caused the process to be killed. -Emitted by the individual worker instance, when the underlying child process -is terminated. See [child_process event: 'exit'](child_process.html#child_process_event_exit). +Similar to the `cluster.on('exit')` event, but specific to this worker. var worker = cluster.fork(); worker.on('exit', function(code, signal) { @@ -518,3 +568,9 @@ is terminated. See [child_process event: 'exit'](child_process.html#child_proce console.log("worker success!"); } }); + +### Event: 'error' + +This event is the same as the one provided by `child_process.fork()`. + +In a worker you can also use `process.on('error')`. From f051b8919fec8efd8ef050f580cfcabea3d2534c Mon Sep 17 00:00:00 2001 From: Timothy J Fontaine Date: Mon, 14 Oct 2013 11:57:45 -0700 Subject: [PATCH 21/35] http_parser: expose pause/resume method for parser --- src/node_http_parser.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index 493f1e065e..47e229d1ed 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -495,6 +495,15 @@ public: } + template + static Handle Pause(const Arguments& args) { + HandleScope scope; + Parser* parser = ObjectWrap::Unwrap(args.This()); + http_parser_pause(&parser->parser_, should_pause); + return Undefined(); + } + + private: Local CreateHeaders() { @@ -574,6 +583,8 @@ void InitHttpParser(Handle target) { NODE_SET_PROTOTYPE_METHOD(t, "execute", Parser::Execute); NODE_SET_PROTOTYPE_METHOD(t, "finish", Parser::Finish); NODE_SET_PROTOTYPE_METHOD(t, "reinitialize", Parser::Reinitialize); + NODE_SET_PROTOTYPE_METHOD(t, "pause", Parser::Pause); + NODE_SET_PROTOTYPE_METHOD(t, "resume", Parser::Pause); target->Set(String::NewSymbol("HTTPParser"), t->GetFunction()); From b97c28f59ee898a81f0df988c249359c9b42701d Mon Sep 17 00:00:00 2001 From: isaacs Date: Wed, 16 Oct 2013 12:57:46 -0700 Subject: [PATCH 22/35] http: provide backpressure for pipeline flood If a client sends a lot more pipelined requests than we can handle, then we need to provide backpressure so that the client knows to back off. Do this by pausing both the stream and the parser itself when the responses are not being read by the downstream client. Backport of 085dd30 --- lib/http.js | 42 +++++++-- test/simple/test-http-pipeline-flood.js | 114 ++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 5 deletions(-) create mode 100644 test/simple/test-http-pipeline-flood.js diff --git a/lib/http.js b/lib/http.js index ec68f54668..32e2ef3072 100644 --- a/lib/http.js +++ b/lib/http.js @@ -37,7 +37,8 @@ if (process.env.NODE_DEBUG && /http/.test(process.env.NODE_DEBUG)) { } function readStart(socket) { - if (!socket || !socket._handle || !socket._handle.readStart) return; + if (!socket || !socket._handle || !socket._handle.readStart || socket._paused) + return; socket._handle.readStart(); } @@ -172,10 +173,8 @@ function parserOnMessageComplete() { stream.push(null); } - if (parser.socket.readable) { - // force to read the next incoming message - readStart(parser.socket); - } + // force to read the next incoming message + readStart(parser.socket); } @@ -1963,6 +1962,7 @@ function connectionListener(socket) { }); socket.ondata = function(d, start, end) { + assert(!socket._paused); var ret = parser.execute(d, start, end - start); if (ret instanceof Error) { debug('parse error'); @@ -1989,6 +1989,12 @@ function connectionListener(socket) { socket.destroy(); } } + + if (socket._paused) { + // onIncoming paused the socket, we should pause the parser as well + debug('pause parser'); + socket.parser.pause(); + } }; socket.onend = function() { @@ -2017,9 +2023,35 @@ function connectionListener(socket) { // The following callback is issued after the headers have been read on a // new message. In this callback we setup the response object and pass it // to the user. + + socket._paused = false; + function socketOnDrain() { + // If we previously paused, then start reading again. + if (socket._paused) { + socket._paused = false; + socket.parser.resume(); + readStart(socket); + } + } + socket.on('drain', socketOnDrain); + parser.onIncoming = function(req, shouldKeepAlive) { incoming.push(req); + // If the writable end isn't consuming, then stop reading + // so that we don't become overwhelmed by a flood of + // pipelined requests that may never be resolved. + if (!socket._paused) { + var needPause = socket._writableState.needDrain; + if (needPause) { + socket._paused = true; + // We also need to pause the parser, but don't do that until after + // the call to execute, because we may still be processing the last + // chunk. + readStop(socket); + } + } + var res = new ServerResponse(req); res.shouldKeepAlive = shouldKeepAlive; diff --git a/test/simple/test-http-pipeline-flood.js b/test/simple/test-http-pipeline-flood.js new file mode 100644 index 0000000000..30925eef38 --- /dev/null +++ b/test/simple/test-http-pipeline-flood.js @@ -0,0 +1,114 @@ +// 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'); + +switch (process.argv[2]) { + case undefined: + return parent(); + case 'child': + return child(); + default: + throw new Error('wtf'); +} + +function parent() { + var http = require('http'); + var bigResponse = new Buffer(10240) + bigResponse.fill('x'); + var gotTimeout = false; + var childClosed = false; + var requests = 0; + var connections = 0; + + var server = http.createServer(function(req, res) { + requests++; + res.setHeader('content-length', bigResponse.length); + res.end(bigResponse); + }); + + server.on('connection', function(conn) { + connections++; + }); + + // kill the connection after a bit, verifying that the + // flood of requests was eventually halted. + server.setTimeout(200, function(conn) { + gotTimeout = true; + conn.destroy(); + }); + + server.listen(common.PORT, function() { + var spawn = require('child_process').spawn; + var args = [__filename, 'child']; + var child = spawn(process.execPath, args, { stdio: 'inherit' }); + child.on('close', function(code) { + assert(!code); + childClosed = true; + server.close(); + }); + }); + + process.on('exit', function() { + assert(gotTimeout); + assert(childClosed); + assert.equal(connections, 1); + // 1213 works out to be the number of requests we end up processing + // before the outgoing connection backs up and requires a drain. + // however, to avoid being unnecessarily tied to a specific magic number, + // and making the test brittle, just assert that it's "a lot", which we + // can safely assume is more than 500. + assert(requests >= 500); + console.log('ok'); + }); +} + +function child() { + var net = require('net'); + + var gotEpipe = false; + var conn = net.connect({ port: common.PORT }); + + var req = 'GET / HTTP/1.1\r\nHost: localhost:' + + common.PORT + '\r\nAccept: */*\r\n\r\n'; + + req = new Array(10241).join(req); + + conn.on('connect', function() { + write(); + }); + + conn.on('drain', write); + + conn.on('error', function(er) { + gotEpipe = true; + }); + + process.on('exit', function() { + assert(gotEpipe); + console.log('ok - child'); + }); + + function write() { + while (false !== conn.write(req, 'ascii')); + } +} From 8fc48bcf4ca49f16b910b388481030870f78665f Mon Sep 17 00:00:00 2001 From: Timothy J Fontaine Date: Fri, 18 Oct 2013 13:52:15 -0700 Subject: [PATCH 23/35] uv: Upgrade to v0.10.18 --- deps/uv/ChangeLog | 15 +- deps/uv/include/uv-private/uv-darwin.h | 10 +- deps/uv/src/unix/darwin.c | 131 ++++- deps/uv/src/unix/fsevents.c | 655 +++++-------------------- deps/uv/src/unix/internal.h | 4 +- deps/uv/src/unix/kqueue.c | 2 +- deps/uv/src/unix/process.c | 17 +- deps/uv/src/unix/signal.c | 5 +- deps/uv/src/version.c | 2 +- 9 files changed, 301 insertions(+), 540 deletions(-) diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index 98fb44f978..794764e7d5 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,4 +1,17 @@ -2013.09.25, Version 0.10.17 (Stable) +2013.10.19, Version 0.10.18 (Stable) + +Changes since version 0.10.17: + +* unix: fix uv_spawn() NULL pointer deref on ENOMEM (Ben Noordhuis) + +* unix: don't close inherited fds on uv_spawn() fail (Ben Noordhuis) + +* unix: revert recent FSEvent changes (Ben Noordhuis) + +* unix: fix non-synchronized access in signal.c (Ben Noordhuis) + + +2013.09.25, Version 0.10.17 (Stable), 9670e0a93540c2f0d86c84a375f2303383c11e7e Changes since version 0.10.16: diff --git a/deps/uv/include/uv-private/uv-darwin.h b/deps/uv/include/uv-private/uv-darwin.h index 4037f5c51f..e861cbab9a 100644 --- a/deps/uv/include/uv-private/uv-darwin.h +++ b/deps/uv/include/uv-private/uv-darwin.h @@ -36,8 +36,8 @@ #define UV_PLATFORM_LOOP_FIELDS \ uv_thread_t cf_thread; \ - void* _cf_reserved; \ - void* cf_state; \ + void* cf_cb; \ + void* cf_loop; \ uv_mutex_t cf_mutex; \ uv_sem_t cf_sem; \ ngx_queue_t cf_signals; \ @@ -47,10 +47,10 @@ char* realpath; \ int realpath_len; \ int cf_flags; \ - void* cf_event; \ + void* cf_eventstream; \ uv_async_t* cf_cb; \ - ngx_queue_t cf_member; \ - uv_sem_t _cf_reserved; \ + ngx_queue_t cf_events; \ + uv_sem_t cf_sem; \ uv_mutex_t cf_mutex; \ #define UV_STREAM_PRIVATE_PLATFORM_FIELDS \ diff --git a/deps/uv/src/unix/darwin.c b/deps/uv/src/unix/darwin.c index 08da5139c1..77e662f4e1 100644 --- a/deps/uv/src/unix/darwin.c +++ b/deps/uv/src/unix/darwin.c @@ -28,6 +28,8 @@ #include #include +#include + #include #include #include /* _NSGetExecutablePath */ @@ -35,19 +37,144 @@ #include #include /* sysconf */ +/* Forward declarations */ +static void uv__cf_loop_runner(void* arg); +static void uv__cf_loop_cb(void* arg); + +typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t; +struct uv__cf_loop_signal_s { + void* arg; + cf_loop_signal_cb cb; + ngx_queue_t member; +}; + int uv__platform_loop_init(uv_loop_t* loop, int default_loop) { - loop->cf_state = NULL; + CFRunLoopSourceContext ctx; + int r; if (uv__kqueue_init(loop)) return -1; + loop->cf_loop = NULL; + if ((r = uv_mutex_init(&loop->cf_mutex))) + return r; + if ((r = uv_sem_init(&loop->cf_sem, 0))) + return r; + ngx_queue_init(&loop->cf_signals); + + memset(&ctx, 0, sizeof(ctx)); + ctx.info = loop; + ctx.perform = uv__cf_loop_cb; + loop->cf_cb = CFRunLoopSourceCreate(NULL, 0, &ctx); + + if ((r = uv_thread_create(&loop->cf_thread, uv__cf_loop_runner, loop))) + return r; + + /* Synchronize threads */ + uv_sem_wait(&loop->cf_sem); + assert(ACCESS_ONCE(CFRunLoopRef, loop->cf_loop) != NULL); + return 0; } void uv__platform_loop_delete(uv_loop_t* loop) { - uv__fsevents_loop_delete(loop); + ngx_queue_t* item; + uv__cf_loop_signal_t* s; + + assert(loop->cf_loop != NULL); + uv__cf_loop_signal(loop, NULL, NULL); + uv_thread_join(&loop->cf_thread); + + uv_sem_destroy(&loop->cf_sem); + uv_mutex_destroy(&loop->cf_mutex); + + /* Free any remaining data */ + while (!ngx_queue_empty(&loop->cf_signals)) { + item = ngx_queue_head(&loop->cf_signals); + + s = ngx_queue_data(item, uv__cf_loop_signal_t, member); + + ngx_queue_remove(item); + free(s); + } +} + + +static void uv__cf_loop_runner(void* arg) { + uv_loop_t* loop; + + loop = arg; + + /* Get thread's loop */ + ACCESS_ONCE(CFRunLoopRef, loop->cf_loop) = CFRunLoopGetCurrent(); + + CFRunLoopAddSource(loop->cf_loop, + loop->cf_cb, + kCFRunLoopDefaultMode); + + uv_sem_post(&loop->cf_sem); + + CFRunLoopRun(); + + CFRunLoopRemoveSource(loop->cf_loop, + loop->cf_cb, + kCFRunLoopDefaultMode); +} + + +static void uv__cf_loop_cb(void* arg) { + uv_loop_t* loop; + ngx_queue_t* item; + ngx_queue_t split_head; + uv__cf_loop_signal_t* s; + + loop = arg; + + uv_mutex_lock(&loop->cf_mutex); + ngx_queue_init(&split_head); + if (!ngx_queue_empty(&loop->cf_signals)) { + ngx_queue_t* split_pos = ngx_queue_next(&loop->cf_signals); + ngx_queue_split(&loop->cf_signals, split_pos, &split_head); + } + uv_mutex_unlock(&loop->cf_mutex); + + while (!ngx_queue_empty(&split_head)) { + item = ngx_queue_head(&split_head); + + s = ngx_queue_data(item, uv__cf_loop_signal_t, member); + + /* This was a termination signal */ + if (s->cb == NULL) + CFRunLoopStop(loop->cf_loop); + else + s->cb(s->arg); + + ngx_queue_remove(item); + free(s); + } +} + + +void uv__cf_loop_signal(uv_loop_t* loop, cf_loop_signal_cb cb, void* arg) { + uv__cf_loop_signal_t* item; + + item = malloc(sizeof(*item)); + /* XXX: Fail */ + if (item == NULL) + abort(); + + item->arg = arg; + item->cb = cb; + + uv_mutex_lock(&loop->cf_mutex); + ngx_queue_insert_tail(&loop->cf_signals, &item->member); + uv_mutex_unlock(&loop->cf_mutex); + + assert(loop->cf_loop != NULL); + CFRunLoopSourceSignal(loop->cf_cb); + CFRunLoopWakeUp(loop->cf_loop); } diff --git a/deps/uv/src/unix/fsevents.c b/deps/uv/src/unix/fsevents.c index 7636b80cec..b6d274675a 100644 --- a/deps/uv/src/unix/fsevents.c +++ b/deps/uv/src/unix/fsevents.c @@ -34,149 +34,112 @@ int uv__fsevents_close(uv_fs_event_t* handle) { return 0; } - -void uv__fsevents_loop_delete(uv_loop_t* loop) { - return 0; -} - #else /* TARGET_OS_IPHONE */ #include #include -#include #include -/* These are macros to avoid "initializer element is not constant" errors - * with old versions of gcc. - */ -#define kFSEventsModified (kFSEventStreamEventFlagItemFinderInfoMod | \ - kFSEventStreamEventFlagItemModified | \ - kFSEventStreamEventFlagItemInodeMetaMod | \ - kFSEventStreamEventFlagItemChangeOwner | \ - kFSEventStreamEventFlagItemXattrMod) - -#define kFSEventsRenamed (kFSEventStreamEventFlagItemCreated | \ - kFSEventStreamEventFlagItemRemoved | \ - kFSEventStreamEventFlagItemRenamed) - -#define kFSEventsSystem (kFSEventStreamEventFlagUserDropped | \ - kFSEventStreamEventFlagKernelDropped | \ - kFSEventStreamEventFlagEventIdsWrapped | \ - kFSEventStreamEventFlagHistoryDone | \ - kFSEventStreamEventFlagMount | \ - kFSEventStreamEventFlagUnmount | \ - kFSEventStreamEventFlagRootChanged) - typedef struct uv__fsevents_event_s uv__fsevents_event_t; -typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t; -typedef struct uv__cf_loop_state_s uv__cf_loop_state_t; - -struct uv__cf_loop_state_s { - CFRunLoopRef loop; - CFRunLoopSourceRef signal_source; - volatile int fsevent_need_reschedule; - FSEventStreamRef fsevent_stream; - uv_sem_t fsevent_sem; - uv_mutex_t fsevent_mutex; - ngx_queue_t fsevent_handles; - int fsevent_handle_count; -}; - -struct uv__cf_loop_signal_s { - ngx_queue_t member; - uv_fs_event_t* handle; -}; struct uv__fsevents_event_s { int events; - void* next; + ngx_queue_t member; char path[1]; }; -/* Forward declarations */ -static void uv__cf_loop_cb(void* arg); -static void* uv__cf_loop_runner(void* arg); -static int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle); -#define UV__FSEVENTS_PROCESS(handle, block) \ - do { \ +#define UV__FSEVENTS_WALK(handle, block) \ + { \ + ngx_queue_t* curr; \ + ngx_queue_t split_head; \ uv__fsevents_event_t* event; \ - uv__fsevents_event_t* next; \ uv_mutex_lock(&(handle)->cf_mutex); \ - event = (handle)->cf_event; \ - (handle)->cf_event = NULL; \ + ngx_queue_init(&split_head); \ + if (!ngx_queue_empty(&(handle)->cf_events)) { \ + ngx_queue_t* split_pos = ngx_queue_next(&(handle)->cf_events); \ + ngx_queue_split(&(handle)->cf_events, split_pos, &split_head); \ + } \ uv_mutex_unlock(&(handle)->cf_mutex); \ - while (event != NULL) { \ + while (!ngx_queue_empty(&split_head)) { \ + curr = ngx_queue_head(&split_head); \ /* Invoke callback */ \ + event = ngx_queue_data(curr, uv__fsevents_event_t, member); \ + ngx_queue_remove(curr); \ /* Invoke block code, but only if handle wasn't closed */ \ - if (!uv__is_closing((handle))) \ + if (((handle)->flags & (UV_CLOSING | UV_CLOSED)) == 0) \ block \ /* Free allocated data */ \ - next = event->next; \ free(event); \ - event = next; \ } \ - } while (0) + } -/* Runs in UV loop's thread, when there're events to report to handle */ -static void uv__fsevents_cb(uv_async_t* cb, int status) { +void uv__fsevents_cb(uv_async_t* cb, int status) { uv_fs_event_t* handle; handle = cb->data; - UV__FSEVENTS_PROCESS(handle, { + UV__FSEVENTS_WALK(handle, { if (handle->event_watcher.fd != -1) handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0); }); - if (!uv__is_closing(handle) && handle->event_watcher.fd == -1) + if ((handle->flags & (UV_CLOSING | UV_CLOSED)) == 0 && + handle->event_watcher.fd == -1) { uv__fsevents_close(handle); + } } -/* Runs in CF thread, when there're events in FSEventStream */ -static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, - void* info, - size_t numEvents, - void* eventPaths, - const FSEventStreamEventFlags eventFlags[], - const FSEventStreamEventId eventIds[]) { +void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, + void* info, + size_t numEvents, + void* eventPaths, + const FSEventStreamEventFlags eventFlags[], + const FSEventStreamEventId eventIds[]) { size_t i; int len; char** paths; char* path; char* pos; uv_fs_event_t* handle; - ngx_queue_t* q; - uv_loop_t* loop; - uv__cf_loop_state_t* state; uv__fsevents_event_t* event; - uv__fsevents_event_t* tail; - - loop = info; - state = loop->cf_state; - assert(state != NULL); + ngx_queue_t add_list; + int kFSEventsModified; + int kFSEventsRenamed; + + kFSEventsModified = kFSEventStreamEventFlagItemFinderInfoMod | + kFSEventStreamEventFlagItemModified | + kFSEventStreamEventFlagItemInodeMetaMod | + kFSEventStreamEventFlagItemChangeOwner | + kFSEventStreamEventFlagItemXattrMod; + kFSEventsRenamed = kFSEventStreamEventFlagItemCreated | + kFSEventStreamEventFlagItemRemoved | + kFSEventStreamEventFlagItemRenamed; + + handle = info; paths = eventPaths; + ngx_queue_init(&add_list); + + for (i = 0; i < numEvents; i++) { + /* Ignore system events */ + if (eventFlags[i] & (kFSEventStreamEventFlagUserDropped | + kFSEventStreamEventFlagKernelDropped | + kFSEventStreamEventFlagEventIdsWrapped | + kFSEventStreamEventFlagHistoryDone | + kFSEventStreamEventFlagMount | + kFSEventStreamEventFlagUnmount | + kFSEventStreamEventFlagRootChanged)) { + continue; + } - /* For each handle */ - ngx_queue_foreach(q, &state->fsevent_handles) { - handle = ngx_queue_data(q, uv_fs_event_t, cf_member); - tail = NULL; - - /* Process and filter out events */ - for (i = 0; i < numEvents; i++) { - /* Ignore system events */ - if (eventFlags[i] & kFSEventsSystem) - continue; - - path = paths[i]; - len = strlen(path); - - /* Filter out paths that are outside handle's request */ - if (strncmp(path, handle->realpath, handle->realpath_len) != 0) - continue; + /* TODO: Report errors */ + path = paths[i]; + len = strlen(path); + /* Remove absolute path prefix */ + if (strstr(path, handle->realpath) == path) { path += handle->realpath_len; len -= handle->realpath_len; @@ -185,81 +148,91 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, path++; len--; } + } #ifdef MAC_OS_X_VERSION_10_7 - /* Ignore events with path equal to directory itself */ - if (len == 0) - continue; + /* Ignore events with path equal to directory itself */ + if (len == 0) + continue; #endif /* MAC_OS_X_VERSION_10_7 */ - /* Do not emit events from subdirectories (without option set) */ - if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0) { - pos = strchr(path, '/'); - if (pos != NULL && pos != path + 1) - continue; - } + /* Do not emit events from subdirectories (without option set) */ + pos = strchr(path, '/'); + if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && + pos != NULL && + pos != path + 1) + continue; #ifndef MAC_OS_X_VERSION_10_7 - path = ""; - len = 0; + path = ""; + len = 0; #endif /* MAC_OS_X_VERSION_10_7 */ - event = malloc(sizeof(*event) + len); - if (event == NULL) - break; + event = malloc(sizeof(*event) + len); + if (event == NULL) + break; - memset(event, 0, sizeof(*event)); - memcpy(event->path, path, len + 1); + memcpy(event->path, path, len + 1); - if ((eventFlags[i] & kFSEventsModified) != 0 && - (eventFlags[i] & kFSEventsRenamed) == 0) - event->events = UV_CHANGE; - else - event->events = UV_RENAME; + if ((eventFlags[i] & kFSEventsModified) != 0 && + (eventFlags[i] & kFSEventsRenamed) == 0) + event->events = UV_CHANGE; + else + event->events = UV_RENAME; - if (tail != NULL) - tail->next = event; - tail = event; - } + ngx_queue_insert_tail(&add_list, &event->member); + } + uv_mutex_lock(&handle->cf_mutex); + ngx_queue_add(&handle->cf_events, &add_list); + uv_mutex_unlock(&handle->cf_mutex); - if (tail != NULL) { - uv_mutex_lock(&handle->cf_mutex); - tail->next = handle->cf_event; - handle->cf_event = tail; - uv_mutex_unlock(&handle->cf_mutex); + uv_async_send(handle->cf_cb); +} - uv_async_send(handle->cf_cb); - } - } + +void uv__fsevents_schedule(void* arg) { + uv_fs_event_t* handle; + + handle = arg; + FSEventStreamScheduleWithRunLoop(handle->cf_eventstream, + handle->loop->cf_loop, + kCFRunLoopDefaultMode); + FSEventStreamStart(handle->cf_eventstream); + uv_sem_post(&handle->cf_sem); } -/* Runs in CF thread */ -static void uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) { - uv__cf_loop_state_t* state; +int uv__fsevents_init(uv_fs_event_t* handle) { FSEventStreamContext ctx; FSEventStreamRef ref; + CFStringRef path; + CFArrayRef paths; CFAbsoluteTime latency; FSEventStreamCreateFlags flags; /* Initialize context */ ctx.version = 0; - ctx.info = loop; + ctx.info = handle; ctx.retain = NULL; ctx.release = NULL; ctx.copyDescription = NULL; + /* Get absolute path to file */ + handle->realpath = realpath(handle->filename, NULL); + if (handle->realpath != NULL) + handle->realpath_len = strlen(handle->realpath); + + /* Initialize paths array */ + path = CFStringCreateWithCString(NULL, + handle->filename, + CFStringGetSystemEncoding()); + paths = CFArrayCreate(NULL, (const void**)&path, 1, NULL); + latency = 0.15; /* Set appropriate flags */ flags = kFSEventStreamCreateFlagFileEvents; - /* - * NOTE: It might sound like a good idea to remember last seen StreamEventId, - * but in reality one dir might have last StreamEventId less than, the other, - * that is being watched now. Which will cause FSEventStream API to report - * changes to files from the past. - */ ref = FSEventStreamCreate(NULL, &uv__fsevents_event_cb, &ctx, @@ -267,419 +240,55 @@ static void uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) { kFSEventStreamEventIdSinceNow, latency, flags); - assert(ref != NULL); - - state = loop->cf_state; - FSEventStreamScheduleWithRunLoop(ref, - state->loop, - kCFRunLoopDefaultMode); - if (!FSEventStreamStart(ref)) - abort(); - - state->fsevent_stream = ref; -} - - -/* Runs in CF thread */ -static void uv__fsevents_destroy_stream(uv_loop_t* loop) { - uv__cf_loop_state_t* state; - - state = loop->cf_state; - - if (state->fsevent_stream == NULL) - return; - - /* Flush all accumulated events */ - FSEventStreamFlushSync(state->fsevent_stream); - - /* Stop emitting events */ - FSEventStreamStop(state->fsevent_stream); - - /* Release stream */ - FSEventStreamInvalidate(state->fsevent_stream); - FSEventStreamRelease(state->fsevent_stream); - state->fsevent_stream = NULL; -} - - -/* Runs in CF thread, when there're new fsevent handles to add to stream */ -static void uv__fsevents_reschedule(uv_fs_event_t* handle) { - uv__cf_loop_state_t* state; - ngx_queue_t* q; - uv_fs_event_t* curr; - CFArrayRef cf_paths; - CFStringRef* paths; - int i; - int path_count; - - state = handle->loop->cf_state; - - /* Optimization to prevent O(n^2) time spent when starting to watch - * many files simultaneously - */ - if (!state->fsevent_need_reschedule) - return; - state->fsevent_need_reschedule = 0; - - /* Destroy previous FSEventStream */ - uv__fsevents_destroy_stream(handle->loop); - - /* Create list of all watched paths */ - uv_mutex_lock(&state->fsevent_mutex); - path_count = state->fsevent_handle_count; - if (path_count != 0) { - paths = malloc(sizeof(*paths) * path_count); - if (paths == NULL) - abort(); - - q = &state->fsevent_handles; - for (i = 0; i < path_count; i++) { - q = ngx_queue_next(q); - assert(q != &state->fsevent_handles); - curr = ngx_queue_data(q, uv_fs_event_t, cf_member); - - assert(curr->realpath != NULL); - paths[i] = CFStringCreateWithCString(NULL, - curr->realpath, - CFStringGetSystemEncoding()); - if (paths[i] == NULL) - abort(); - } - } - uv_mutex_unlock(&state->fsevent_mutex); - - if (path_count != 0) { - /* Create new FSEventStream */ - cf_paths = CFArrayCreate(NULL, (const void**) paths, path_count, NULL); - if (cf_paths == NULL) - abort(); - uv__fsevents_create_stream(handle->loop, cf_paths); - } - - /* - * Main thread will block until the removal of handle from the list, - * we must tell it when we're ready. - * - * NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close` - */ - if (uv__is_closing(handle)) - uv_sem_post(&state->fsevent_sem); -} - - -/* Runs in UV loop */ -static int uv__fsevents_loop_init(uv_loop_t* loop) { - CFRunLoopSourceContext ctx; - uv__cf_loop_state_t* state; - pthread_attr_t attr_storage; - pthread_attr_t* attr; - int err; - - if (loop->cf_state != NULL) - return 0; - - state = calloc(1, sizeof(*state)); - if (state == NULL) - return -ENOMEM; - - err = uv_mutex_init(&loop->cf_mutex); - if (err) - return err; - - err = uv_sem_init(&loop->cf_sem, 0); - if (err) - goto fail_sem_init; - - ngx_queue_init(&loop->cf_signals); - - err = uv_sem_init(&state->fsevent_sem, 0); - if (err) - goto fail_fsevent_sem_init; - - err = uv_mutex_init(&state->fsevent_mutex); - if (err) - goto fail_fsevent_mutex_init; - - ngx_queue_init(&state->fsevent_handles); - state->fsevent_need_reschedule = 0; - state->fsevent_handle_count = 0; - - memset(&ctx, 0, sizeof(ctx)); - ctx.info = loop; - ctx.perform = uv__cf_loop_cb; - state->signal_source = CFRunLoopSourceCreate(NULL, 0, &ctx); - if (state->signal_source == NULL) { - err = -ENOMEM; - goto fail_signal_source_create; - } - - /* In the unlikely event that pthread_attr_init() fails, create the thread - * with the default stack size. We'll use a little more address space but - * that in itself is not a fatal error. - */ - attr = &attr_storage; - if (pthread_attr_init(attr)) - attr = NULL; - - if (attr != NULL) - if (pthread_attr_setstacksize(attr, 3 * PTHREAD_STACK_MIN)) - abort(); - - loop->cf_state = state; - - /* uv_thread_t is an alias for pthread_t. */ - err = -pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop); - - if (attr != NULL) - pthread_attr_destroy(attr); - - if (err) - goto fail_thread_create; - - /* Synchronize threads */ - uv_sem_wait(&loop->cf_sem); - return 0; - -fail_thread_create: - loop->cf_state = NULL; - -fail_signal_source_create: - uv_mutex_destroy(&state->fsevent_mutex); - -fail_fsevent_mutex_init: - uv_sem_destroy(&state->fsevent_sem); - -fail_fsevent_sem_init: - uv_sem_destroy(&loop->cf_sem); - -fail_sem_init: - uv_mutex_destroy(&loop->cf_mutex); - free(state); - return err; -} - - -/* Runs in UV loop */ -void uv__fsevents_loop_delete(uv_loop_t* loop) { - uv__cf_loop_signal_t* s; - uv__cf_loop_state_t* state; - ngx_queue_t* q; - - if (loop->cf_state == NULL) - return; - - if (uv__cf_loop_signal(loop, NULL) != 0) - abort(); - - uv_thread_join(&loop->cf_thread); - uv_sem_destroy(&loop->cf_sem); - uv_mutex_destroy(&loop->cf_mutex); - - /* Free any remaining data */ - while (!ngx_queue_empty(&loop->cf_signals)) { - q = ngx_queue_head(&loop->cf_signals); - s = ngx_queue_data(q, uv__cf_loop_signal_t, member); - ngx_queue_remove(q); - free(s); - } - - /* Destroy state */ - state = loop->cf_state; - uv_sem_destroy(&state->fsevent_sem); - uv_mutex_destroy(&state->fsevent_mutex); - CFRelease(state->signal_source); - free(state); - loop->cf_state = NULL; -} - - -/* Runs in CF thread. This is the CF loop's body */ -static void* uv__cf_loop_runner(void* arg) { - uv_loop_t* loop; - uv__cf_loop_state_t* state; - - loop = arg; - state = loop->cf_state; - state->loop = CFRunLoopGetCurrent(); - - CFRunLoopAddSource(state->loop, - state->signal_source, - kCFRunLoopDefaultMode); - - uv_sem_post(&loop->cf_sem); - - CFRunLoopRun(); - CFRunLoopRemoveSource(state->loop, - state->signal_source, - kCFRunLoopDefaultMode); - - return NULL; -} - - -/* Runs in CF thread, executed after `uv__cf_loop_signal()` */ -static void uv__cf_loop_cb(void* arg) { - uv_loop_t* loop; - uv__cf_loop_state_t* state; - ngx_queue_t* item; - ngx_queue_t split_head; - uv__cf_loop_signal_t* s; - - loop = arg; - state = loop->cf_state; - ngx_queue_init(&split_head); - - uv_mutex_lock(&loop->cf_mutex); - if (!ngx_queue_empty(&loop->cf_signals)) { - ngx_queue_t* split_pos = ngx_queue_head(&loop->cf_signals); - ngx_queue_split(&loop->cf_signals, split_pos, &split_head); - } - uv_mutex_unlock(&loop->cf_mutex); - - while (!ngx_queue_empty(&split_head)) { - item = ngx_queue_head(&split_head); - - s = ngx_queue_data(item, uv__cf_loop_signal_t, member); - - /* This was a termination signal */ - if (s->handle == NULL) - CFRunLoopStop(state->loop); - else - uv__fsevents_reschedule(s->handle); - - ngx_queue_remove(item); - free(s); - } -} - - -/* Runs in UV loop to notify CF thread */ -int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle) { - uv__cf_loop_signal_t* item; - uv__cf_loop_state_t* state; - - item = malloc(sizeof(*item)); - if (item == NULL) - return -ENOMEM; - - item->handle = handle; - - uv_mutex_lock(&loop->cf_mutex); - ngx_queue_insert_tail(&loop->cf_signals, &item->member); - uv_mutex_unlock(&loop->cf_mutex); - - state = loop->cf_state; - assert(state != NULL); - CFRunLoopSourceSignal(state->signal_source); - CFRunLoopWakeUp(state->loop); - - return 0; -} - - -/* Runs in UV loop to initialize handle */ -int uv__fsevents_init(uv_fs_event_t* handle) { - int err; - uv__cf_loop_state_t* state; - - err = uv__fsevents_loop_init(handle->loop); - if (err) - return err; - - /* Get absolute path to file */ - handle->realpath = realpath(handle->filename, NULL); - if (handle->realpath == NULL) - return -errno; - handle->realpath_len = strlen(handle->realpath); - - /* Initialize singly-linked list */ - handle->cf_event = NULL; + handle->cf_eventstream = ref; /* * Events will occur in other thread. * Initialize callback for getting them back into event loop's thread */ handle->cf_cb = malloc(sizeof(*handle->cf_cb)); - if (handle->cf_cb == NULL) { - err = uv__set_sys_error(handle->loop, ENOMEM); - goto fail_cf_cb_malloc; - } + if (handle->cf_cb == NULL) + return uv__set_sys_error(handle->loop, ENOMEM); handle->cf_cb->data = handle; uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb); handle->cf_cb->flags |= UV__HANDLE_INTERNAL; uv_unref((uv_handle_t*) handle->cf_cb); - err = uv_mutex_init(&handle->cf_mutex); - if (err) - goto fail_cf_mutex_init; + uv_mutex_init(&handle->cf_mutex); + uv_sem_init(&handle->cf_sem, 0); + ngx_queue_init(&handle->cf_events); - /* Insert handle into the list */ - state = handle->loop->cf_state; - uv_mutex_lock(&state->fsevent_mutex); - ngx_queue_insert_tail(&state->fsevent_handles, &handle->cf_member); - state->fsevent_handle_count++; - state->fsevent_need_reschedule = 1; - uv_mutex_unlock(&state->fsevent_mutex); - - /* Reschedule FSEventStream */ - assert(handle != NULL); - err = uv__cf_loop_signal(handle->loop, handle); - if (err) - goto fail_loop_signal; + uv__cf_loop_signal(handle->loop, uv__fsevents_schedule, handle); return 0; - -fail_loop_signal: - uv_mutex_destroy(&handle->cf_mutex); - -fail_cf_mutex_init: - free(handle->cf_cb); - handle->cf_cb = NULL; - -fail_cf_cb_malloc: - free(handle->realpath); - handle->realpath = NULL; - handle->realpath_len = 0; - - return err; } -/* Runs in UV loop to de-initialize handle */ int uv__fsevents_close(uv_fs_event_t* handle) { - int err; - uv__cf_loop_state_t* state; + if (handle->cf_eventstream == NULL) + return -1; - if (handle->cf_cb == NULL) - return -EINVAL; + /* Ensure that event stream was scheduled */ + uv_sem_wait(&handle->cf_sem); - /* Remove handle from the list */ - state = handle->loop->cf_state; - uv_mutex_lock(&state->fsevent_mutex); - ngx_queue_remove(&handle->cf_member); - state->fsevent_handle_count--; - state->fsevent_need_reschedule = 1; - uv_mutex_unlock(&state->fsevent_mutex); - - /* Reschedule FSEventStream */ - assert(handle != NULL); - err = uv__cf_loop_signal(handle->loop, handle); - if (err) - return -err; + /* Stop emitting events */ + FSEventStreamStop(handle->cf_eventstream); - /* Wait for deinitialization */ - uv_sem_wait(&state->fsevent_sem); + /* Release stream */ + FSEventStreamInvalidate(handle->cf_eventstream); + FSEventStreamRelease(handle->cf_eventstream); + handle->cf_eventstream = NULL; uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) free); - handle->cf_cb = NULL; /* Free data in queue */ - UV__FSEVENTS_PROCESS(handle, { + UV__FSEVENTS_WALK(handle, { /* NOP */ - }); + }) uv_mutex_destroy(&handle->cf_mutex); + uv_sem_destroy(&handle->cf_sem); free(handle->realpath); handle->realpath = NULL; handle->realpath_len = 0; diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 2bb4dc1b04..61cb1ec1f0 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -216,10 +216,12 @@ int uv__make_socketpair(int fds[2], int flags); int uv__make_pipe(int fds[2], int flags); #if defined(__APPLE__) +typedef void (*cf_loop_signal_cb)(void*); + +void uv__cf_loop_signal(uv_loop_t* loop, cf_loop_signal_cb cb, void* arg); int uv__fsevents_init(uv_fs_event_t* handle); int uv__fsevents_close(uv_fs_event_t* handle); -void uv__fsevents_loop_delete(uv_loop_t* loop); /* OSX < 10.7 has no file events, polyfill them */ #ifndef MAC_OS_X_VERSION_10_7 diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index a46c88f4bf..378903a627 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -307,7 +307,7 @@ int uv_fs_event_init(uv_loop_t* loop, #if defined(__APPLE__) /* Nullify field to perform checks later */ - handle->cf_cb = NULL; + handle->cf_eventstream = NULL; handle->realpath = NULL; handle->realpath_len = 0; handle->cf_flags = flags; diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index 7ef84d0d2a..389817f211 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -186,7 +186,7 @@ skip: /* * Used for initializing stdio streams like options.stdin_stream. Returns - * zero on success. + * zero on success. See also the cleanup section in uv_spawn(). */ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) { int mask; @@ -463,11 +463,18 @@ int uv_spawn(uv_loop_t* loop, error: uv__set_sys_error(process->loop, errno); - for (i = 0; i < stdio_count; i++) { - close(pipes[i][0]); - close(pipes[i][1]); + if (pipes != NULL) { + for (i = 0; i < stdio_count; i++) { + if (i < options.stdio_count) + if (options.stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM)) + continue; + if (pipes[i][0] != -1) + close(pipes[i][0]); + if (pipes[i][1] != -1) + close(pipes[i][1]); + } + free(pipes); } - free(pipes); return -1; } diff --git a/deps/uv/src/unix/signal.c b/deps/uv/src/unix/signal.c index 22c7783b9f..aa84ff2f2d 100644 --- a/deps/uv/src/unix/signal.c +++ b/deps/uv/src/unix/signal.c @@ -141,7 +141,10 @@ static void uv__signal_handler(int signum) { saved_errno = errno; memset(&msg, 0, sizeof msg); - uv__signal_lock(); + if (uv__signal_lock()) { + errno = saved_errno; + return; + } for (handle = uv__signal_first_handle(signum); handle != NULL && handle->signum == signum; diff --git a/deps/uv/src/version.c b/deps/uv/src/version.c index 5489601795..e272d5f4c3 100644 --- a/deps/uv/src/version.c +++ b/deps/uv/src/version.c @@ -34,7 +34,7 @@ #define UV_VERSION_MAJOR 0 #define UV_VERSION_MINOR 10 -#define UV_VERSION_PATCH 17 +#define UV_VERSION_PATCH 18 #define UV_VERSION_IS_RELEASE 1 From 5e41c022af741444def80967aab6ea0f9ec73057 Mon Sep 17 00:00:00 2001 From: Timothy J Fontaine Date: Fri, 18 Oct 2013 14:14:21 -0700 Subject: [PATCH 24/35] crypto: clear errors from verify failure OpenSSL will push errors onto the stack when a verify fails, which can disrupt TLS and other routines if we don't clear the error stack Fixes #6304 --- src/node_crypto.cc | 3 + test/simple/test-crypto-verify-failure.js | 81 +++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 test/simple/test-crypto-verify-failure.js diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 409be357ce..e3ece08541 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -3186,6 +3186,9 @@ class Verify : public ObjectWrap { int VerifyFinal(char* key_pem, int key_pemLen, unsigned char* sig, int siglen) { if (!initialised_) return 0; + ClearErrorOnReturn clear_error_on_return; + (void) &clear_error_on_return; // Silence compiler warning. + EVP_PKEY* pkey = NULL; BIO *bp = NULL; X509 *x509 = NULL; diff --git a/test/simple/test-crypto-verify-failure.js b/test/simple/test-crypto-verify-failure.js new file mode 100644 index 0000000000..6162d16519 --- /dev/null +++ b/test/simple/test-crypto-verify-failure.js @@ -0,0 +1,81 @@ +// 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'); + +try { + var crypto = require('crypto'); + var tls = require('tls'); +} catch (e) { + console.log('Not compiled with OPENSSL support.'); + process.exit(); +} + +crypto.DEFAULT_ENCODING = 'buffer'; + +var fs = require('fs'); + +var certPem = fs.readFileSync(common.fixturesDir + '/test_cert.pem', 'ascii'); + +var options = { + key: fs.readFileSync(common.fixturesDir + '/keys/agent1-key.pem'), + cert: fs.readFileSync(common.fixturesDir + '/keys/agent1-cert.pem') +}; + +var canSend = true; + +var server = tls.Server(options, function(socket) { + process.nextTick(function() { + console.log('sending'); + socket.destroy(); + verify(); + }); +}); + +var client; + +function verify() { + console.log('verify'); + var verified = crypto.createVerify('RSA-SHA1') + .update('Test') + .verify(certPem, 'asdfasdfas', 'base64'); +} + +server.listen(common.PORT, function() { + client = tls.connect({ + port: common.PORT, + rejectUnauthorized: false + }, function() { + verify(); + }).on('data', function(data) { + console.log(data); + }).on('error', function(err) { + throw err; + }).on('close', function() { + server.close(); + }).resume(); +}); + +server.unref(); From e2da042844a830fafb8031f6c477eb4f96195210 Mon Sep 17 00:00:00 2001 From: Timothy J Fontaine Date: Fri, 18 Oct 2013 14:26:27 -0700 Subject: [PATCH 25/35] 2013.10.18, Version 0.10.21 (Stable) * uv: Upgrade to v0.10.18 * crypto: clear errors from verify failure (Timothy J Fontaine) * dtrace: interpret two byte strings (Dave Pacheco) * fs: fix fs.truncate() file content zeroing bug (Ben Noordhuis) * http: provide backpressure for pipeline flood (isaacs) * tls: fix premature connection termination (Ben Noordhuis) --- ChangeLog | 17 ++++++++++++++++- src/node_version.h | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 95afb81362..d6a1233e7f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,19 @@ -2013.09.30, Version 0.10.20 (Stable) +2013.10.18, Version 0.10.21 (Stable) + +* uv: Upgrade to v0.10.18 + +* crypto: clear errors from verify failure (Timothy J Fontaine) + +* dtrace: interpret two byte strings (Dave Pacheco) + +* fs: fix fs.truncate() file content zeroing bug (Ben Noordhuis) + +* http: provide backpressure for pipeline flood (isaacs) + +* tls: fix premature connection termination (Ben Noordhuis) + + +2013.09.30, Version 0.10.20 (Stable), d7234c8d50a1af73f60d2d3c0cc7eed17429a481 * tls: fix sporadic hang and partial reads (Fedor Indutny) - fixes "npm ERR! cb() never called!" diff --git a/src/node_version.h b/src/node_version.h index 3073630f97..fd58d21d0d 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -26,7 +26,7 @@ #define NODE_MINOR_VERSION 10 #define NODE_PATCH_VERSION 21 -#define NODE_VERSION_IS_RELEASE 0 +#define NODE_VERSION_IS_RELEASE 1 #ifndef NODE_TAG # define NODE_TAG "" From 85b2aaea3d6a033642cc7ebe95bcf85ae37de24a Mon Sep 17 00:00:00 2001 From: Timothy J Fontaine Date: Fri, 18 Oct 2013 15:40:32 -0700 Subject: [PATCH 26/35] Now working on 0.10.22 --- 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 fd58d21d0d..f8b677ce3c 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -24,9 +24,9 @@ #define NODE_MAJOR_VERSION 0 #define NODE_MINOR_VERSION 10 -#define NODE_PATCH_VERSION 21 +#define NODE_PATCH_VERSION 22 -#define NODE_VERSION_IS_RELEASE 1 +#define NODE_VERSION_IS_RELEASE 0 #ifndef NODE_TAG # define NODE_TAG "" From 2649ae839589fde045c4afbd05eb2f3f15407279 Mon Sep 17 00:00:00 2001 From: Timothy J Fontaine Date: Fri, 18 Oct 2013 15:43:55 -0700 Subject: [PATCH 27/35] blog: Post for v0.8.26 --- doc/blog/release/v0.8.26.md | 71 +++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 doc/blog/release/v0.8.26.md diff --git a/doc/blog/release/v0.8.26.md b/doc/blog/release/v0.8.26.md new file mode 100644 index 0000000000..45e227a9b9 --- /dev/null +++ b/doc/blog/release/v0.8.26.md @@ -0,0 +1,71 @@ +date: Fri Oct 18 14:52:30 PDT 2013 +version: 0.8.26 +category: release +title: Node v0.8.26 (Maintenance) +slug: node-v0-8-26-maintenance + +This release contains a security fix for the http server implementation, please +upgrade as soon as possible. Details will be released soon. + +2013.10.13, Version 0.8.26 (maintenance) + +* v8: Upgrade to 3.11.10.26 + +* crypto: clear openssl error stack when handled (Ben Noordhuis) + +* crypto: clear errors from verify failure (Timothy J Fontaine) + +* crypto: fix memory leak in LoadPKCS12 (Fedor Indutny) + +* http: provide backpressure for pipeline flood (isaacs) + +* http_parser: expose pause/resume method for parser (Timothy J Fontaine) + +* readline: pause stdin before turning off terminal raw mode (Daniel Chatfield) + + +Source Code: http://nodejs.org/dist/v0.8.26/node-v0.8.26.tar.gz + +Macintosh Installer (Universal): http://nodejs.org/dist/v0.8.26/node-v0.8.26.pkg + +Windows Installer: http://nodejs.org/dist/v0.8.26/node-v0.8.26-x86.msi + +Windows x64 Installer: http://nodejs.org/dist/v0.8.26/x64/node-v0.8.26-x64.msi + +Windows x64 Files: http://nodejs.org/dist/v0.8.26/x64/ + +Linux 32-bit Binary: http://nodejs.org/dist/v0.8.26/node-v0.8.26-linux-x86.tar.gz + +Linux 64-bit Binary: http://nodejs.org/dist/v0.8.26/node-v0.8.26-linux-x64.tar.gz + +Solaris 32-bit Binary: http://nodejs.org/dist/v0.8.26/node-v0.8.26-sunos-x86.tar.gz + +Solaris 64-bit Binary: http://nodejs.org/dist/v0.8.26/node-v0.8.26-sunos-x64.tar.gz + +Other release files: http://nodejs.org/dist/v0.8.26/ + +Website: http://nodejs.org/docs/v0.8.26/ + +Documentation: http://nodejs.org/docs/v0.8.26/api/ + +Shasums: +``` +b9fa5fca6282a01d491ab585b6a6a64f23ea4da2 node-v0.8.26-darwin-x64.tar.gz +ba760b282f38f62ad333c2ecc69d3b296f87cf4a node-v0.8.26-darwin-x86.tar.gz +c96470908234656c6060cbe0dab4502f90ca7cd1 node-v0.8.26-linux-x64.tar.gz +3b5c776ae8632df2a4c67b89bdd37d843135be90 node-v0.8.26-linux-x86.tar.gz +6b9b6bb2676b37ff63f240931f68aa22e9187e99 node-v0.8.26-sunos-x64.tar.gz +cb3f975293f9561fdda0b46571aee570576e0406 node-v0.8.26-sunos-x86.tar.gz +668bbc8240497675bb4ed3b61c6f7fb79772b264 node-v0.8.26-x86.msi +e51a33c28e2c75b0e40826100e5f6b84d5cf8d98 node-v0.8.26.pkg +2ec960bcc8cd38da271f83c1b2007c12da5153b3 node-v0.8.26.tar.gz +860ec0bcb6e89fcee3e45e56e469dd28cfcf400c node.exe +ad0e366a82e8570768f5c92d97eebd8fd4a54f8f node.exp +559a7b4e3c49b1071d1cd1374cf4bc4bae2aa558 node.lib +687eeb71782ac36f26aaba60e07bd92f47bfcf36 node.pdb +b10e28a100ab40169759bd431ccc855de1763fa8 x64/node-v0.8.26-x64.msi +19b5210e212b3b5473c251786c3d22b8cb919f5f x64/node.exe +6129121aad9d48ffa19a712f59e6acb9bff14eb1 x64/node.exp +4eb1822b10ec3b7a17deff1126725c30c5ef65b1 x64/node.lib +7f39e38b62ad44c774ae381a661726494b2f066e x64/node.pdb +``` From 028e524bce9e361dc0f10e3f235c91862ba5ec67 Mon Sep 17 00:00:00 2001 From: Timothy J Fontaine Date: Fri, 18 Oct 2013 15:46:02 -0700 Subject: [PATCH 28/35] blog: Post for v0.10.21 --- doc/blog/release/v0.10.21.md | 71 ++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 doc/blog/release/v0.10.21.md diff --git a/doc/blog/release/v0.10.21.md b/doc/blog/release/v0.10.21.md new file mode 100644 index 0000000000..36bc2945bc --- /dev/null +++ b/doc/blog/release/v0.10.21.md @@ -0,0 +1,71 @@ +date: Fri Oct 18 15:39:23 PDT 2013 +version: 0.10.21 +category: release +title: Node v0.10.21 (Stable) +slug: node-v0-10-21-stable + +This release contains a security fix for the http server implementation, please +upgrade as soon as possible. Details will be released soon. + +2013.10.18, Version 0.10.21 (Stable) + +* uv: Upgrade to v0.10.18 + +* crypto: clear errors from verify failure (Timothy J Fontaine) + +* dtrace: interpret two byte strings (Dave Pacheco) + +* fs: fix fs.truncate() file content zeroing bug (Ben Noordhuis) + +* http: provide backpressure for pipeline flood (isaacs) + +* tls: fix premature connection termination (Ben Noordhuis) + + +Source Code: http://nodejs.org/dist/v0.10.21/node-v0.10.21.tar.gz + +Macintosh Installer (Universal): http://nodejs.org/dist/v0.10.21/node-v0.10.21.pkg + +Windows Installer: http://nodejs.org/dist/v0.10.21/node-v0.10.21-x86.msi + +Windows x64 Installer: http://nodejs.org/dist/v0.10.21/x64/node-v0.10.21-x64.msi + +Windows x64 Files: http://nodejs.org/dist/v0.10.21/x64/ + +Linux 32-bit Binary: http://nodejs.org/dist/v0.10.21/node-v0.10.21-linux-x86.tar.gz + +Linux 64-bit Binary: http://nodejs.org/dist/v0.10.21/node-v0.10.21-linux-x64.tar.gz + +Solaris 32-bit Binary: http://nodejs.org/dist/v0.10.21/node-v0.10.21-sunos-x86.tar.gz + +Solaris 64-bit Binary: http://nodejs.org/dist/v0.10.21/node-v0.10.21-sunos-x64.tar.gz + +Other release files: http://nodejs.org/dist/v0.10.21/ + +Website: http://nodejs.org/docs/v0.10.21/ + +Documentation: http://nodejs.org/docs/v0.10.21/api/ + +Shasums: +``` +fb1318fb7721aa292310599e7c6696edebcfd70d node-v0.10.21-darwin-x64.tar.gz +486235cc54d269d1961dfb150b1479ec14e83541 node-v0.10.21-darwin-x86.tar.gz +7528d2fa240a5dd88d37e4847cebec50ef40c8eb node-v0.10.21-linux-x64.tar.gz +b372abf9d9c53bfe675e2c3f71dcfdece44edddd node-v0.10.21-linux-x86.tar.gz +cb873cdff3f30aa198b52c8be3588745d2ee3933 node-v0.10.21-sunos-x64.tar.gz +020d202d7066b68f160d0ceebe8cc8306de25956 node-v0.10.21-sunos-x86.tar.gz +037ea0e3be3512da2bc94aa765fa89d61da3e275 node-v0.10.21-x86.msi +de2bd0e858f99098ef24f99f972b8088c1f0405c node-v0.10.21.pkg +b7fd2a3660635af40e3719ca0db49280d10359b2 node-v0.10.21.tar.gz +a0e3988170beee1273a2fb6d650bf17db8495c67 node.exe +99332a03aeba8a22254d671665b9b2161a64bd84 node.exp +263dafeec907bd1f28ceb8272b9caaadceacb4d6 node.lib +76d578bf352772dc4db9ebb95fb61cf18e34c80d node.pdb +b6d11b67ce7aaff5c7a456a4c85c80849a3d576e pkgsrc/nodejs-ia32-0.10.21.tgz +b116825d1d2cbcfd567f730b1c2452424508b062 pkgsrc/nodejs-x64-0.10.21.tgz +29632c5a21a4ebf89703e417852306a676f6ede8 x64/node-v0.10.21-x64.msi +033b0a2b57e031a9e47f0b28eb4dc50a5389b592 x64/node.exe +f62b53229d77eaddf1f3a7909ef6533eea0e2295 x64/node.exp +8d5cfe83c3bc78ddcf79de9d065d1b4f2af9347e x64/node.lib +6844e78e9ba80bfa48f6c150544e3e73d83dd316 x64/node.pdb +``` From 97813ae58d19687f3c61f6355b4307c88908058a Mon Sep 17 00:00:00 2001 From: isaacs Date: Tue, 22 Oct 2013 10:56:03 -0700 Subject: [PATCH 29/35] blog: HTTP server DoS vulnerability details CVE-2013-4450 --- .../http-server-pipeline-flood-dos.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 doc/blog/vulnerability/http-server-pipeline-flood-dos.md diff --git a/doc/blog/vulnerability/http-server-pipeline-flood-dos.md b/doc/blog/vulnerability/http-server-pipeline-flood-dos.md new file mode 100644 index 0000000000..e4a607d7a9 --- /dev/null +++ b/doc/blog/vulnerability/http-server-pipeline-flood-dos.md @@ -0,0 +1,37 @@ +title: DoS Vulnerability (fixed in Node v0.8.26 and v0.10.21) +date: Tue Oct 22 10:42:10 PDT 2013 +slug: cve-2013-4450-http-server-pipeline-flood-dos +category: vulnerability + +Node.js is vulnerable to a denial of service attack when a client +sends many pipelined HTTP requests on a single connection, and the +client does not read the responses from the connection. + +We recommend that anyone using Node.js v0.8 or v0.10 to run HTTP +servers in production please update as soon as possible. + +* v0.10.21 +* v0.8.26 + +This is fixed in Node.js by pausing both the socket and the HTTP +parser whenever the downstream writable side of the socket is awaiting +a drain event. In the attack scenario, the socket will eventually +time out, and be destroyed by the server. If the "attacker" is not +malicious, but merely sends a lot of requests and reacts to them +slowly, then the throughput on that connection will be reduced to what +the client can handle. + +There is no change to program semantics, and except in the +pathological cases described, no changes to behavior. + +If upgrading is not possible, then putting an HTTP proxy in front of +the Node.js server can mitigate the vulnerability, but only if the +proxy parses HTTP and is not itself vulnerable to a pipeline flood +DoS. + +For example, nginx will prevent the attack (since it closes +connections after 100 pipelined requests by default), but HAProxy in +raw TCP mode will not (since it proxies the TCP connection without +regard for HTTP semantics). + +This addresses CVE-2013-4450. From 91a0e52c03d8340f3aaf4c48a9f2c2d3a6fff368 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 23 Oct 2013 13:25:35 +0200 Subject: [PATCH 30/35] src: IsInt64() should return bool, not int --- src/node_file.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node_file.cc b/src/node_file.cc index 589ecdf7c9..54923b148c 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -75,7 +75,7 @@ static Persistent oncomplete_sym; #define GET_OFFSET(a) ((a)->IsNumber() ? (a)->IntegerValue() : -1) #define GET_TRUNCATE_LENGTH(a) ((a)->IntegerValue()) -static inline int IsInt64(double x) { +static inline bool IsInt64(double x) { return x == static_cast(static_cast(x)); } From eb291de00e6ec5c75d3c27d40403d3a842305d01 Mon Sep 17 00:00:00 2001 From: Zarko Stankovic Date: Thu, 12 Sep 2013 20:13:32 +0200 Subject: [PATCH 31/35] doc: add nodejs.rs to the community page --- doc/community/index.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/community/index.html b/doc/community/index.html index 823b77fa33..ee059ccbc6 100644 --- a/doc/community/index.html +++ b/doc/community/index.html @@ -186,6 +186,8 @@ Node.js blog & developers listing
nodejs.geek.nz Node.js site for Kiwis
+ nodejs.rs + Serbian Node.js community website

From 808a968409b6c6cc305506efd3caa4477a376125 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 23 Oct 2013 13:42:53 +0200 Subject: [PATCH 32/35] build: fix test-gc weakref build rule Make the build rule depend on the build artifact (weakref.node) itself rather than the directory it's built in. Depending on the directory means that a build failure won't trigger a rebuild on the next invocation because the directory's timestamp has been updated. This is a back-port of commit 1189571 from the master branch that hopefully fixes the following CI error: executing: make test/gc/node_modules/weak/build/ make: *** No rule to make target `test/gc/node_modules/weak/build/'. Command exited with non-zero: make test/gc/node_modules/weak/build/ Build step 'Execute NodeJS script' marked build as failure --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 01c689db53..14aeca3b8a 100644 --- a/Makefile +++ b/Makefile @@ -82,16 +82,16 @@ test-http1: all test-valgrind: all $(PYTHON) tools/test.py --mode=release --valgrind simple message -test/gc/node_modules/weak/build: +test/gc/node_modules/weak/build/Release/weakref.node: @if [ ! -f node ]; then make all; fi ./node deps/npm/node_modules/node-gyp/bin/node-gyp rebuild \ --directory="$(shell pwd)/test/gc/node_modules/weak" \ --nodedir="$(shell pwd)" -test-gc: all test/gc/node_modules/weak/build +test-gc: all test/gc/node_modules/weak/build/Release/weakref.node $(PYTHON) tools/test.py --mode=release gc -test-all: all test/gc/node_modules/weak/build +test-all: all test/gc/node_modules/weak/build/Release/weakref.node $(PYTHON) tools/test.py --mode=debug,release make test-npm From f6f176e10872cac9dcdcd46a92c9ebfe4740f117 Mon Sep 17 00:00:00 2001 From: isaacs Date: Thu, 24 Oct 2013 09:21:59 -0700 Subject: [PATCH 33/35] npm@1.3.12 --- deps/npm/Makefile | 6 +- deps/npm/doc/cli/npm-cache.md | 8 +- deps/npm/doc/cli/npm-dedupe.md | 4 + deps/npm/doc/cli/npm-install.md | 4 +- deps/npm/doc/cli/npm-outdated.md | 4 + deps/npm/doc/cli/npm-prune.md | 4 + deps/npm/doc/cli/npm-tag.md | 15 + deps/npm/doc/misc/npm-config.md | 2 +- deps/npm/html/doc/README.html | 2 +- deps/npm/html/doc/api/npm-bin.html | 2 +- deps/npm/html/doc/api/npm-bugs.html | 2 +- deps/npm/html/doc/api/npm-commands.html | 2 +- deps/npm/html/doc/api/npm-config.html | 2 +- deps/npm/html/doc/api/npm-deprecate.html | 2 +- deps/npm/html/doc/api/npm-docs.html | 2 +- deps/npm/html/doc/api/npm-edit.html | 2 +- deps/npm/html/doc/api/npm-explore.html | 2 +- deps/npm/html/doc/api/npm-help-search.html | 2 +- deps/npm/html/doc/api/npm-init.html | 2 +- deps/npm/html/doc/api/npm-install.html | 2 +- deps/npm/html/doc/api/npm-link.html | 2 +- deps/npm/html/doc/api/npm-load.html | 2 +- deps/npm/html/doc/api/npm-ls.html | 2 +- deps/npm/html/doc/api/npm-outdated.html | 2 +- deps/npm/html/doc/api/npm-owner.html | 2 +- deps/npm/html/doc/api/npm-pack.html | 2 +- deps/npm/html/doc/api/npm-prefix.html | 2 +- deps/npm/html/doc/api/npm-prune.html | 2 +- deps/npm/html/doc/api/npm-publish.html | 2 +- deps/npm/html/doc/api/npm-rebuild.html | 2 +- deps/npm/html/doc/api/npm-restart.html | 2 +- deps/npm/html/doc/api/npm-root.html | 2 +- deps/npm/html/doc/api/npm-run-script.html | 2 +- deps/npm/html/doc/api/npm-search.html | 2 +- deps/npm/html/doc/api/npm-shrinkwrap.html | 2 +- deps/npm/html/doc/api/npm-start.html | 2 +- deps/npm/html/doc/api/npm-stop.html | 2 +- deps/npm/html/doc/api/npm-submodule.html | 2 +- deps/npm/html/doc/api/npm-tag.html | 2 +- deps/npm/html/doc/api/npm-test.html | 2 +- deps/npm/html/doc/api/npm-uninstall.html | 2 +- deps/npm/html/doc/api/npm-unpublish.html | 2 +- deps/npm/html/doc/api/npm-update.html | 2 +- deps/npm/html/doc/api/npm-version.html | 2 +- deps/npm/html/doc/api/npm-view.html | 2 +- deps/npm/html/doc/api/npm-whoami.html | 2 +- deps/npm/html/doc/api/npm.html | 4 +- deps/npm/html/doc/api/repo.html | 2 +- deps/npm/html/doc/cli/npm-adduser.html | 2 +- deps/npm/html/doc/cli/npm-bin.html | 2 +- deps/npm/html/doc/cli/npm-bugs.html | 2 +- deps/npm/html/doc/cli/npm-build.html | 2 +- deps/npm/html/doc/cli/npm-bundle.html | 2 +- deps/npm/html/doc/cli/npm-cache.html | 10 +- deps/npm/html/doc/cli/npm-completion.html | 2 +- deps/npm/html/doc/cli/npm-config.html | 2 +- deps/npm/html/doc/cli/npm-dedupe.html | 6 +- deps/npm/html/doc/cli/npm-deprecate.html | 2 +- deps/npm/html/doc/cli/npm-docs.html | 2 +- deps/npm/html/doc/cli/npm-edit.html | 2 +- deps/npm/html/doc/cli/npm-explore.html | 2 +- deps/npm/html/doc/cli/npm-help-search.html | 2 +- deps/npm/html/doc/cli/npm-help.html | 2 +- deps/npm/html/doc/cli/npm-init.html | 2 +- deps/npm/html/doc/cli/npm-install.html | 6 +- deps/npm/html/doc/cli/npm-link.html | 2 +- deps/npm/html/doc/cli/npm-ls.html | 4 +- deps/npm/html/doc/cli/npm-outdated.html | 6 +- deps/npm/html/doc/cli/npm-owner.html | 2 +- deps/npm/html/doc/cli/npm-pack.html | 2 +- deps/npm/html/doc/cli/npm-prefix.html | 2 +- deps/npm/html/doc/cli/npm-prune.html | 8 +- deps/npm/html/doc/cli/npm-publish.html | 2 +- deps/npm/html/doc/cli/npm-rebuild.html | 2 +- deps/npm/html/doc/cli/npm-restart.html | 2 +- deps/npm/html/doc/cli/npm-rm.html | 2 +- deps/npm/html/doc/cli/npm-root.html | 2 +- deps/npm/html/doc/cli/npm-run-script.html | 2 +- deps/npm/html/doc/cli/npm-search.html | 2 +- deps/npm/html/doc/cli/npm-shrinkwrap.html | 2 +- deps/npm/html/doc/cli/npm-star.html | 2 +- deps/npm/html/doc/cli/npm-stars.html | 2 +- deps/npm/html/doc/cli/npm-start.html | 2 +- deps/npm/html/doc/cli/npm-stop.html | 2 +- deps/npm/html/doc/cli/npm-submodule.html | 2 +- deps/npm/html/doc/cli/npm-tag.html | 17 +- deps/npm/html/doc/cli/npm-test.html | 2 +- deps/npm/html/doc/cli/npm-uninstall.html | 2 +- deps/npm/html/doc/cli/npm-unpublish.html | 2 +- deps/npm/html/doc/cli/npm-update.html | 2 +- deps/npm/html/doc/cli/npm-version.html | 2 +- deps/npm/html/doc/cli/npm-view.html | 2 +- deps/npm/html/doc/cli/npm-whoami.html | 2 +- deps/npm/html/doc/cli/npm.html | 4 +- deps/npm/html/doc/cli/repo.html | 2 +- deps/npm/html/doc/files/npm-folders.html | 2 +- deps/npm/html/doc/files/npm-global.html | 2 +- deps/npm/html/doc/files/npm-json.html | 2 +- deps/npm/html/doc/files/npmrc.html | 2 +- deps/npm/html/doc/files/package.json.html | 2 +- deps/npm/html/doc/index.html | 2 +- deps/npm/html/doc/misc/npm-coding-style.html | 2 +- deps/npm/html/doc/misc/npm-config.html | 4 +- deps/npm/html/doc/misc/npm-developers.html | 2 +- deps/npm/html/doc/misc/npm-disputes.html | 2 +- deps/npm/html/doc/misc/npm-faq.html | 2 +- deps/npm/html/doc/misc/npm-index.html | 2 +- deps/npm/html/doc/misc/npm-registry.html | 2 +- deps/npm/html/doc/misc/npm-scripts.html | 2 +- deps/npm/html/doc/misc/removing-npm.html | 2 +- deps/npm/html/doc/misc/semver.html | 2 +- deps/npm/lib/cache.js | 5 +- deps/npm/lib/dedupe.js | 9 +- deps/npm/lib/docs.js | 14 +- deps/npm/lib/ls.js | 2 + deps/npm/lib/outdated.js | 58 ++- deps/npm/lib/repo.js | 10 +- deps/npm/lib/unbuild.js | 5 +- deps/npm/lib/utils/error-handler.js | 2 +- deps/npm/lib/utils/lifecycle.js | 71 ++-- deps/npm/make.bat | 3 + deps/npm/man/man1/npm-README.1 | 2 +- deps/npm/man/man1/npm-adduser.1 | 2 +- deps/npm/man/man1/npm-bin.1 | 2 +- deps/npm/man/man1/npm-bugs.1 | 2 +- deps/npm/man/man1/npm-build.1 | 2 +- deps/npm/man/man1/npm-bundle.1 | 2 +- deps/npm/man/man1/npm-cache.1 | 9 +- deps/npm/man/man1/npm-completion.1 | 2 +- deps/npm/man/man1/npm-config.1 | 2 +- deps/npm/man/man1/npm-dedupe.1 | 7 +- deps/npm/man/man1/npm-deprecate.1 | 2 +- deps/npm/man/man1/npm-docs.1 | 2 +- deps/npm/man/man1/npm-edit.1 | 2 +- deps/npm/man/man1/npm-explore.1 | 2 +- deps/npm/man/man1/npm-help-search.1 | 2 +- deps/npm/man/man1/npm-help.1 | 2 +- deps/npm/man/man1/npm-init.1 | 2 +- deps/npm/man/man1/npm-install.1 | 6 +- deps/npm/man/man1/npm-link.1 | 2 +- deps/npm/man/man1/npm-ls.1 | 4 +- deps/npm/man/man1/npm-outdated.1 | 7 +- deps/npm/man/man1/npm-owner.1 | 2 +- deps/npm/man/man1/npm-pack.1 | 2 +- deps/npm/man/man1/npm-prefix.1 | 2 +- deps/npm/man/man1/npm-prune.1 | 7 +- deps/npm/man/man1/npm-publish.1 | 2 +- deps/npm/man/man1/npm-rebuild.1 | 2 +- deps/npm/man/man1/npm-restart.1 | 2 +- deps/npm/man/man1/npm-rm.1 | 2 +- deps/npm/man/man1/npm-root.1 | 2 +- deps/npm/man/man1/npm-run-script.1 | 2 +- deps/npm/man/man1/npm-search.1 | 2 +- deps/npm/man/man1/npm-shrinkwrap.1 | 2 +- deps/npm/man/man1/npm-star.1 | 2 +- deps/npm/man/man1/npm-stars.1 | 2 +- deps/npm/man/man1/npm-start.1 | 2 +- deps/npm/man/man1/npm-stop.1 | 2 +- deps/npm/man/man1/npm-submodule.1 | 2 +- deps/npm/man/man1/npm-tag.1 | 39 +- deps/npm/man/man1/npm-test.1 | 2 +- deps/npm/man/man1/npm-uninstall.1 | 2 +- deps/npm/man/man1/npm-unpublish.1 | 2 +- deps/npm/man/man1/npm-update.1 | 2 +- deps/npm/man/man1/npm-version.1 | 2 +- deps/npm/man/man1/npm-view.1 | 2 +- deps/npm/man/man1/npm-whoami.1 | 2 +- deps/npm/man/man1/npm.1 | 4 +- deps/npm/man/man1/repo.1 | 2 +- deps/npm/man/man3/npm-bin.3 | 2 +- deps/npm/man/man3/npm-bugs.3 | 2 +- deps/npm/man/man3/npm-commands.3 | 2 +- deps/npm/man/man3/npm-config.3 | 2 +- deps/npm/man/man3/npm-deprecate.3 | 2 +- deps/npm/man/man3/npm-docs.3 | 2 +- deps/npm/man/man3/npm-edit.3 | 2 +- deps/npm/man/man3/npm-explore.3 | 2 +- deps/npm/man/man3/npm-help-search.3 | 2 +- deps/npm/man/man3/npm-init.3 | 2 +- deps/npm/man/man3/npm-install.3 | 2 +- deps/npm/man/man3/npm-link.3 | 2 +- deps/npm/man/man3/npm-load.3 | 2 +- deps/npm/man/man3/npm-ls.3 | 2 +- deps/npm/man/man3/npm-outdated.3 | 2 +- deps/npm/man/man3/npm-owner.3 | 2 +- deps/npm/man/man3/npm-pack.3 | 2 +- deps/npm/man/man3/npm-prefix.3 | 2 +- deps/npm/man/man3/npm-prune.3 | 2 +- deps/npm/man/man3/npm-publish.3 | 2 +- deps/npm/man/man3/npm-rebuild.3 | 2 +- deps/npm/man/man3/npm-restart.3 | 2 +- deps/npm/man/man3/npm-root.3 | 2 +- deps/npm/man/man3/npm-run-script.3 | 2 +- deps/npm/man/man3/npm-search.3 | 2 +- deps/npm/man/man3/npm-shrinkwrap.3 | 2 +- deps/npm/man/man3/npm-start.3 | 2 +- deps/npm/man/man3/npm-stop.3 | 2 +- deps/npm/man/man3/npm-submodule.3 | 2 +- deps/npm/man/man3/npm-tag.3 | 2 +- deps/npm/man/man3/npm-test.3 | 2 +- deps/npm/man/man3/npm-uninstall.3 | 2 +- deps/npm/man/man3/npm-unpublish.3 | 2 +- deps/npm/man/man3/npm-update.3 | 2 +- deps/npm/man/man3/npm-version.3 | 2 +- deps/npm/man/man3/npm-view.3 | 2 +- deps/npm/man/man3/npm-whoami.3 | 2 +- deps/npm/man/man3/npm.3 | 4 +- deps/npm/man/man3/repo.3 | 2 +- deps/npm/man/man5/npm-folders.5 | 2 +- deps/npm/man/man5/npm-global.5 | 2 +- deps/npm/man/man5/npm-json.5 | 2 +- deps/npm/man/man5/npmrc.5 | 2 +- deps/npm/man/man5/package.json.5 | 2 +- deps/npm/man/man7/npm-coding-style.7 | 2 +- deps/npm/man/man7/npm-config.7 | 4 +- deps/npm/man/man7/npm-developers.7 | 2 +- deps/npm/man/man7/npm-disputes.7 | 2 +- deps/npm/man/man7/npm-faq.7 | 2 +- deps/npm/man/man7/npm-index.7 | 2 +- deps/npm/man/man7/npm-registry.7 | 2 +- deps/npm/man/man7/npm-scripts.7 | 2 +- deps/npm/man/man7/removing-npm.7 | 2 +- deps/npm/man/man7/semver.7 | 2 +- deps/npm/node_modules/ansi/README.md | 8 - deps/npm/node_modules/ansi/color-spaces.pl | 67 ++++ .../ansi/examples/cursorPosition.js | 12 +- .../ansi/examples/imgcat/index.js | 50 --- .../ansi/examples/imgcat/yoshi.png | Bin 1341 -> 0 bytes .../node_modules/ansi/examples/starwars.js | 9 +- deps/npm/node_modules/ansi/lib/ansi.js | 45 ++- deps/npm/node_modules/ansi/package.json | 28 +- deps/npm/node_modules/cmd-shim/.npmignore | 32 +- deps/npm/node_modules/cmd-shim/.travis.yml | 4 + deps/npm/node_modules/cmd-shim/LICENSE | 54 +-- deps/npm/node_modules/cmd-shim/README.md | 82 ++-- deps/npm/node_modules/cmd-shim/index.js | 360 +++++++++--------- deps/npm/node_modules/cmd-shim/package.json | 12 +- .../node_modules/cmd-shim/test/00-setup.js | 70 ++-- deps/npm/node_modules/cmd-shim/test/basic.js | 336 ++++++++-------- .../node_modules/cmd-shim/test/zz-cleanup.js | 26 +- deps/npm/node_modules/editor/LICENSE | 18 + deps/npm/node_modules/editor/package.json | 9 +- .../node_modules/fstream-npm/fstream-npm.js | 2 +- .../node_modules/fstream-ignore/package.json | 6 +- .../npm/node_modules/fstream-npm/package.json | 6 +- .../github-url-from-username-repo/.npmignore | 13 + .../github-url-from-username-repo/.travis.yml | 4 + .../github-url-from-username-repo/LICENSE | 27 ++ .../github-url-from-username-repo/README.md | 14 + .../github-url-from-username-repo/index.js | 9 + .../package.json | 33 ++ .../test/index.js | 21 + deps/npm/node_modules/mkdirp/package.json | 9 +- .../node_modules/config-chain/index.js | 2 +- .../node_modules/proto-list/package.json | 1 + .../node_modules/config-chain/package.json | 6 +- .../node_modules/config-chain/test/get.js | 15 + deps/npm/node_modules/npmconf/package.json | 9 +- deps/npm/node_modules/npmlog/package.json | 6 +- deps/npm/node_modules/npmlog/test/basic.js | 265 +------------ deps/npm/node_modules/once/README.md | 18 + deps/npm/node_modules/once/once.js | 11 +- deps/npm/node_modules/once/package.json | 12 +- deps/npm/node_modules/once/test/once.js | 4 +- .../normalize-package-data/AUTHORS | 3 +- .../normalize-package-data/README.md | 2 + .../lib/core_module_names.json | 29 ++ .../lib/extract_description.js | 1 + .../normalize-package-data/lib/fixer.js | 35 +- .../normalize-package-data/package.json | 16 +- .../test/consistency.js | 2 +- .../test/fixtures/no-description.json | 4 + .../normalize-package-data/test/normalize.js | 68 ++++ .../read-package-json/package.json | 6 +- deps/npm/node_modules/slide/package.json | 2 +- deps/npm/package.json | 28 +- .../packages/npm-test-peer-deps/npm-ls.json | 4 +- .../packages/npm-test-peer-deps/package.json | 2 +- .../npm-test-shrinkwrap/npm-shrinkwrap.json | 2 +- .../packages/npm-test-shrinkwrap/package.json | 2 +- .../test/tap/fixtures/underscore-1-3-3.json | 1 - deps/npm/test/tap/fixtures/underscore.json | 1 - deps/npm/test/tap/ls-no-results.js | 12 + .../tap/outdated-include-devdependencies.js | 23 ++ .../package.json | 8 + deps/npm/test/tap/outdated-new-versions.js | 38 ++ .../tap/outdated-new-versions/package.json | 11 + deps/npm/test/tap/prepublish.js | 90 +++++ deps/npm/test/tap/publish-config.js | 4 +- deps/npm/test/tap/uninstall-package.js | 24 ++ .../test/tap/uninstall-package/package.json | 9 + 291 files changed, 1712 insertions(+), 1186 deletions(-) create mode 100644 deps/npm/make.bat create mode 100644 deps/npm/node_modules/ansi/color-spaces.pl delete mode 100755 deps/npm/node_modules/ansi/examples/imgcat/index.js delete mode 100644 deps/npm/node_modules/ansi/examples/imgcat/yoshi.png create mode 100644 deps/npm/node_modules/cmd-shim/.travis.yml mode change 100755 => 100644 deps/npm/node_modules/cmd-shim/test/basic.js create mode 100644 deps/npm/node_modules/editor/LICENSE create mode 100644 deps/npm/node_modules/github-url-from-username-repo/.npmignore create mode 100644 deps/npm/node_modules/github-url-from-username-repo/.travis.yml create mode 100644 deps/npm/node_modules/github-url-from-username-repo/LICENSE create mode 100644 deps/npm/node_modules/github-url-from-username-repo/README.md create mode 100644 deps/npm/node_modules/github-url-from-username-repo/index.js create mode 100644 deps/npm/node_modules/github-url-from-username-repo/package.json create mode 100644 deps/npm/node_modules/github-url-from-username-repo/test/index.js create mode 100644 deps/npm/node_modules/npmconf/node_modules/config-chain/test/get.js create mode 100644 deps/npm/node_modules/read-package-json/node_modules/normalize-package-data/lib/core_module_names.json create mode 100644 deps/npm/node_modules/read-package-json/node_modules/normalize-package-data/test/fixtures/no-description.json delete mode 100644 deps/npm/test/tap/fixtures/underscore-1-3-3.json delete mode 100644 deps/npm/test/tap/fixtures/underscore.json create mode 100644 deps/npm/test/tap/ls-no-results.js create mode 100644 deps/npm/test/tap/outdated-include-devdependencies.js create mode 100644 deps/npm/test/tap/outdated-include-devdependencies/package.json create mode 100644 deps/npm/test/tap/outdated-new-versions.js create mode 100644 deps/npm/test/tap/outdated-new-versions/package.json create mode 100644 deps/npm/test/tap/prepublish.js create mode 100644 deps/npm/test/tap/uninstall-package.js create mode 100644 deps/npm/test/tap/uninstall-package/package.json diff --git a/deps/npm/Makefile b/deps/npm/Makefile index 28c7ff6b3f..326d6f0d50 100644 --- a/deps/npm/Makefile +++ b/deps/npm/Makefile @@ -71,7 +71,7 @@ link: uninstall node cli.js link -f clean: ronnclean doc-clean uninstall - rm npmrc + rm -rf npmrc node cli.js cache clean uninstall: @@ -154,13 +154,13 @@ html/doc/misc/%.html: doc/misc/%.md $(html_docdeps) ronn: node_modules/.bin/ronn node_modules/.bin/ronn: - node cli.js install ronn + node cli.js install ronn --no-global doc: man man: $(cli_docs) $(api_docs) -test: +test: doc node cli.js test publish: link doc diff --git a/deps/npm/doc/cli/npm-cache.md b/deps/npm/doc/cli/npm-cache.md index 90a55d9b2a..af3cfac4da 100644 --- a/deps/npm/doc/cli/npm-cache.md +++ b/deps/npm/doc/cli/npm-cache.md @@ -33,9 +33,9 @@ Used to add, list, or clear the npm cache folder. ## DETAILS -npm stores cache data in `$HOME/.npm`. For each package that is added -to the cache, three pieces of information are stored in -`{cache}/{name}/{version}`: +npm stores cache data in the directory specified in `npm config get cache`. +For each package that is added to the cache, three pieces of information are +stored in `{cache}/{name}/{version}`: * .../package/: A folder containing the package contents as they appear in the tarball. @@ -57,7 +57,7 @@ they do not make an HTTP request to the registry. ### cache -Default: `$HOME/.npm` on Posix, or `$HOME/npm-cache` on Windows. +Default: `~/.npm` on Posix, or `%AppData%/npm-cache` on Windows. The root cache folder. diff --git a/deps/npm/doc/cli/npm-dedupe.md b/deps/npm/doc/cli/npm-dedupe.md index 849d98f20a..d3be01050c 100644 --- a/deps/npm/doc/cli/npm-dedupe.md +++ b/deps/npm/doc/cli/npm-dedupe.md @@ -47,6 +47,10 @@ registry. This feature is experimental, and may change in future versions. +The `--tag` argument will apply to all of the affected dependencies. If a +tag with the given name exists, the tagged version is preferred over newer +versions. + ## SEE ALSO * npm-ls(1) diff --git a/deps/npm/doc/cli/npm-install.md b/deps/npm/doc/cli/npm-install.md index 07ba2b03f9..a537bb878d 100644 --- a/deps/npm/doc/cli/npm-install.md +++ b/deps/npm/doc/cli/npm-install.md @@ -152,7 +152,9 @@ For example: npm install sax@">=0.1.0 <0.2.0" bench supervisor -The `--tag` argument will apply to all of the specified install targets. +The `--tag` argument will apply to all of the specified install targets. If a +tag with the given name exists, the tagged version is preferred over newer +versions. The `--force` argument will force npm to fetch remote resources even if a local copy exists on disk. diff --git a/deps/npm/doc/cli/npm-outdated.md b/deps/npm/doc/cli/npm-outdated.md index 25269eb8c0..4d58353787 100644 --- a/deps/npm/doc/cli/npm-outdated.md +++ b/deps/npm/doc/cli/npm-outdated.md @@ -10,6 +10,10 @@ npm-outdated(1) -- Check for outdated packages This command will check the registry to see if any (or, specific) installed packages are currently outdated. +The resulting field 'wanted' shows the latest version according to the +version specified in the package.json, the field 'latest' the very latest +version of the package. + ## SEE ALSO * npm-update(1) diff --git a/deps/npm/doc/cli/npm-prune.md b/deps/npm/doc/cli/npm-prune.md index 0410214d8d..88c54754bb 100644 --- a/deps/npm/doc/cli/npm-prune.md +++ b/deps/npm/doc/cli/npm-prune.md @@ -4,6 +4,7 @@ npm-prune(1) -- Remove extraneous packages ## SYNOPSIS npm prune [ [ [@ + +When installing dependencies, a preferred tagged version may be specified: + + npm install --tag + +This also applies to `npm dedupe`. + +Publishing a package always sets the "latest" tag to the published version. + ## SEE ALSO * npm-publish(1) +* npm-install(1) +* npm-dedupe(1) * npm-registry(7) * npm-config(1) * npm-config(7) diff --git a/deps/npm/doc/misc/npm-config.md b/deps/npm/doc/misc/npm-config.md index 19eaf9347e..750b80972c 100644 --- a/deps/npm/doc/misc/npm-config.md +++ b/deps/npm/doc/misc/npm-config.md @@ -146,7 +146,7 @@ See also the `strict-ssl` config. ### cache -* Default: Windows: `%APPDATA%\npm-cache`, Posix: `~/.npm` +* Default: Windows: `%AppData%\npm-cache`, Posix: `~/.npm` * Type: path The location of npm's cache directory. See `npm-cache(1)` diff --git a/deps/npm/html/doc/README.html b/deps/npm/html/doc/README.html index 94f7abc340..b17848121b 100644 --- a/deps/npm/html/doc/README.html +++ b/deps/npm/html/doc/README.html @@ -239,7 +239,7 @@ will no doubt tell you to put the output in a gist or email.

- +