From 3deceaf6e7351bec3572554baaccef70747f35f8 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 1 Feb 2012 22:25:55 +0100 Subject: [PATCH 01/22] Revert "Process symlinked shared library as .node" This reverts commit 7e0bf7d57de318f45a097e05644efa49beb65209. It's possible to make GYP generate an XCode project that produces a .node file, hence this commit is no longer needed. --- lib/module.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/module.js b/lib/module.js index 893de411391..bbb1556bb82 100644 --- a/lib/module.js +++ b/lib/module.js @@ -467,11 +467,11 @@ Module._extensions['.json'] = function(module, filename) { }; -//Native extension for .node and OS-specific equivalents +//Native extension for .node Module._extensions['.node'] = function(module, filename) { process.dlopen(filename, module.exports); }; -Module._extensions['.dylib'] = Module._extensions['.node']; + // bootstrap main module. Module.runMain = function() { From 5166758927e7538d413b030d3b586107cd53024d Mon Sep 17 00:00:00 2001 From: Philip Tellis Date: Sat, 3 Dec 2011 00:12:32 +0530 Subject: [PATCH 02/22] Make QueryString.parse run faster Use decodeURIComponent when appropriate, and only fall back to querystring.decode if it throws, or if the character is a '+'. Fix #2248 --- lib/querystring.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/querystring.js b/lib/querystring.js index 58b90250c44..d709c07fdf5 100644 --- a/lib/querystring.js +++ b/lib/querystring.js @@ -170,9 +170,17 @@ QueryString.parse = QueryString.decode = function(qs, sep, eq) { } qs.split(sep).forEach(function(kvp) { - var x = kvp.split(eq); - var k = QueryString.unescape(x[0], true); - var v = QueryString.unescape(x.slice(1).join(eq), true); + var x = kvp.split(eq), k, v, useQS=false; + try { + if (kvp.match(/\+/)) { // decodeURIComponent does not decode + to space + throw "has +"; + } + k = decodeURIComponent(x[0]); + v = decodeURIComponent(x.slice(1).join(eq) || ""); + } catch(e) { + k = QueryString.unescape(x[0], true); + v = QueryString.unescape(x.slice(1).join(eq), true); + } if (!hasOwnProperty(obj, k)) { obj[k] = v; From a661830569f424ac929a075bacaa94d70e732924 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 2 Feb 2012 16:56:58 +0100 Subject: [PATCH 03/22] Run path.exists paths through _makeLong --- lib/path.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/path.js b/lib/path.js index c10ff7efce5..6d410c70e51 100644 --- a/lib/path.js +++ b/lib/path.js @@ -402,7 +402,7 @@ exports.extname = function(path) { exports.exists = function(path, callback) { - process.binding('fs').stat(path, function(err, stats) { + process.binding('fs').stat(_makeLong(path), function(err, stats) { if (callback) callback(err ? false : true); }); }; @@ -410,7 +410,7 @@ exports.exists = function(path, callback) { exports.existsSync = function(path) { try { - process.binding('fs').stat(path); + process.binding('fs').stat(_makeLong(path)); return true; } catch (e) { return false; @@ -418,7 +418,7 @@ exports.existsSync = function(path) { }; -exports._makeLong = isWindows ? +var _makeLong = exports._makeLong = isWindows ? function(path) { var resolvedPath = exports.resolve(path); From e5ea6ad0f01e67db73a30190b520df25ba8e16f4 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 2 Feb 2012 16:57:45 +0100 Subject: [PATCH 04/22] _makeLong shouldn't turn the empty string into \\?\C:\ --- lib/path.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/path.js b/lib/path.js index 6d410c70e51..87451e93754 100644 --- a/lib/path.js +++ b/lib/path.js @@ -420,6 +420,11 @@ exports.existsSync = function(path) { var _makeLong = exports._makeLong = isWindows ? function(path) { + path = "" + path; + if (!path) { + return ""; + } + var resolvedPath = exports.resolve(path); if (resolvedPath.match(/^[a-zA-Z]\:\\/)) { From 67cd05472e0c3b2859469d2f1d83400b99464447 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 2 Feb 2012 17:42:08 +0100 Subject: [PATCH 05/22] uv: upgrade to 267e75d --- deps/uv/include/uv.h | 3 +- deps/uv/src/unix/error.c | 1 + deps/uv/src/win/error.c | 2 +- deps/uv/src/win/fs.c | 186 ++++++--------------------------------- deps/uv/test/test-fs.c | 26 ++++++ 5 files changed, 58 insertions(+), 160 deletions(-) diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 629435274ef..23e5e21d143 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -116,7 +116,8 @@ typedef intptr_t ssize_t; XX( 46, ESHUTDOWN, "") \ XX( 47, EEXIST, "file already exists") \ XX( 48, ESRCH, "no such process") \ - XX( 49, ENAMETOOLONG, "name too long") + XX( 49, ENAMETOOLONG, "name too long") \ + XX( 50, EPERM, "operation not permitted") #define UV_ERRNO_GEN(val, name, s) UV_##name = val, diff --git a/deps/uv/src/unix/error.c b/deps/uv/src/unix/error.c index 80d3270db06..1d38623f0be 100644 --- a/deps/uv/src/unix/error.c +++ b/deps/uv/src/unix/error.c @@ -59,6 +59,7 @@ void uv_fatal_error(const int errorno, const char* syscall) { uv_err_code uv_translate_sys_error(int sys_errno) { switch (sys_errno) { case 0: return UV_OK; + case EPERM: return UV_EPERM; case ENOSYS: return UV_ENOSYS; case ENOTSOCK: return UV_ENOTSOCK; case ENOENT: return UV_ENOENT; diff --git a/deps/uv/src/win/error.c b/deps/uv/src/win/error.c index 59c9ea83461..779061031f3 100644 --- a/deps/uv/src/win/error.c +++ b/deps/uv/src/win/error.c @@ -69,7 +69,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case ERROR_SUCCESS: return UV_OK; case ERROR_FILE_NOT_FOUND: return UV_ENOENT; case ERROR_PATH_NOT_FOUND: return UV_ENOENT; - case ERROR_ACCESS_DENIED: return UV_EACCES; + case ERROR_ACCESS_DENIED: return UV_EPERM; case ERROR_NOACCESS: return UV_EACCES; case WSAEACCES: return UV_EACCES; case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE; diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 5248ac2a99e..12ad514c485 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -489,191 +489,61 @@ void fs__readdir(uv_fs_t* req, const wchar_t* path, int flags) { } -#define IS_SLASH(c) \ - ((wchar_t) c == L'/' || (wchar_t) c == L'\\') -#define IS_COLON(c) \ - ((wchar_t) c == L':') -#define IS_LETTER(c) \ - ((((wchar_t) c >= L'a') && ((wchar_t) c <= L'z')) || \ - (((wchar_t) c >= L'A') && ((wchar_t) c <= L'Z'))) -#define IS_QUESTION(c) \ - ((wchar_t) c == L'?') - - -static int uv__count_slash_separated_words(const wchar_t* pos, - const wchar_t* end, - int limit) { - char last_was_slash = 1, count = 0; - - for (; pos < end; pos++) { - if (IS_SLASH(*pos)) { - /* Don't accept double slashes */ - if (last_was_slash) { - return 0; - } else { - last_was_slash = 1; - } - } else { - if (last_was_slash) { - /* Found a new word */ - count++; - if (count > limit) { - return -1; - } - last_was_slash = 0; - } - } - } - - return count; -} - -/* - * Returns true if the given path is a root directory. The following patterns - * are recognized: - * \ - * c:\ (must have trailing slash) - * \\server\share (trailing slash optional) - * \\?\c: (trailing slash optional) - * \\?\UNC\server\share (trailing slash optional) - */ -static int uv__is_root(const wchar_t* path) { - size_t len = wcslen(path); - - /* Test for \ */ - if (len == 1 && IS_SLASH(path[0])) { - return 1; - } - - if (len < 3) { - return 0; - } - - /* Test for c:\ */ - if (IS_LETTER(path[0]) && IS_COLON(path[1]) && IS_SLASH(path[2])) { - return 1; - } - - if (!IS_SLASH(path[0]) || !IS_SLASH(path[1])) { - return 0; - } - - /* Test for \\server\share */ - if (!IS_QUESTION(path[2])) { - return uv__count_slash_separated_words(path + 2, path + len, 2) == 2; - } - - if (!IS_SLASH(path[3])) { - return 0; - } - - if ((len == 6 || len == 7) && - IS_LETTER(path[4]) && IS_COLON(path[5]) && - (len == 6 || IS_SLASH(path[6]))) { - return 1; - } - - /* Test for \\?\UNC\server\share */ - if (len >= 8 && - (path[4] == L'u' || path[4] == L'U') && - (path[5] == L'n' || path[5] == L'N') && - (path[6] == L'c' || path[6] == L'C') && - IS_SLASH(path[7])) { - return uv__count_slash_separated_words(path + 8, path + len, 2) == 2; - } - - return 0; -} - - -void fs__stat(uv_fs_t* req, const wchar_t* path) { - HANDLE file; - WIN32_FIND_DATAW ent; +static void fs__stat(uv_fs_t* req, const wchar_t* path) { + HANDLE handle; int result; + BY_HANDLE_FILE_INFORMATION info; req->ptr = NULL; - if (uv__is_root(path)) { - /* We can't stat root directories like c:\. _wstati64 can't either, but */ - /* it will make up something reasonable. */ - DWORD drive_type = GetDriveTypeW(path); - if (drive_type == DRIVE_UNKNOWN || drive_type == DRIVE_NO_ROOT_DIR) { - req->last_error = ERROR_PATH_NOT_FOUND; - req->errorno = UV_ENOENT; - req->result = -1; - return; - } - - memset(&req->stat, 0, sizeof req->stat); - - req->stat.st_nlink = 1; - req->stat.st_mode = ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) + - ((_S_IREAD|_S_IWRITE) >> 6)) | S_IFDIR; - - req->last_error = ERROR_SUCCESS; - req->errorno = UV_OK; - req->result = 0; - req->ptr = &req->stat; - return; - } - - file = FindFirstFileExW(path, FindExInfoStandard, &ent, - FindExSearchNameMatch, NULL, 0); - - if (file == INVALID_HANDLE_VALUE) { + handle = CreateFileW(path, + FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (handle == INVALID_HANDLE_VALUE) { SET_REQ_RESULT_WIN32_ERROR(req, GetLastError()); return; } - FindClose(file); - - if (ent.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && - ent.dwReserved0 == IO_REPARSE_TAG_SYMLINK) { - fs__open(req, path, _O_RDONLY, 0); - if (req->result != -1) { - result = _fstati64(req->result, &req->stat); - _close(req->result); - - if (result != -1) { - req->ptr = &req->stat; - } - - SET_REQ_RESULT(req, result); - } - + if (!GetFileInformationByHandle(handle, &info)) { + SET_REQ_RESULT_WIN32_ERROR(req, GetLastError()); + CloseHandle(handle); return; } - req->stat.st_ino = 0; - req->stat.st_uid = 0; - req->stat.st_gid = 0; - req->stat.st_mode = 0; - req->stat.st_rdev = 0; - req->stat.st_dev = 0; - req->stat.st_nlink = 1; + memset(&req->stat, 0, sizeof req->stat); - if (ent.dwFileAttributes & FILE_ATTRIBUTE_READONLY ) { + /* TODO: set st_dev and st_ino? */ + + if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { req->stat.st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6)); } else { req->stat.st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) + ((_S_IREAD|_S_IWRITE) >> 6)); } - if (ent.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { req->stat.st_mode |= _S_IFDIR; } else { req->stat.st_mode |= _S_IFREG; } - uv_filetime_to_time_t(&ent.ftLastWriteTime, &(req->stat.st_mtime)); - uv_filetime_to_time_t(&ent.ftLastAccessTime, &(req->stat.st_atime)); - uv_filetime_to_time_t(&ent.ftCreationTime, &(req->stat.st_ctime)); + uv_filetime_to_time_t(&info.ftLastWriteTime, &(req->stat.st_mtime)); + uv_filetime_to_time_t(&info.ftLastAccessTime, &(req->stat.st_atime)); + uv_filetime_to_time_t(&info.ftCreationTime, &(req->stat.st_ctime)); - req->stat.st_size = ((int64_t)ent.nFileSizeHigh << 32) + - (int64_t)ent.nFileSizeLow; + req->stat.st_size = ((int64_t) info.nFileSizeHigh << 32) + + (int64_t) info.nFileSizeLow; + + req->stat.st_nlink = info.nNumberOfLinks; req->ptr = &req->stat; req->result = 0; + + CloseHandle(handle); } diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index b88636b01df..109ae014b40 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -184,6 +184,13 @@ static void chown_cb(uv_fs_t* req) { uv_fs_req_cleanup(req); } +static void chown_root_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_CHOWN); + ASSERT(req->result == -1); + ASSERT(req->errorno == UV_EPERM); + chown_cb_count++; + uv_fs_req_cleanup(req); +} static void unlink_cb(uv_fs_t* req) { ASSERT(req == &unlink_req); @@ -1018,6 +1025,12 @@ TEST_IMPL(fs_chown) { uv_run(loop); ASSERT(chown_cb_count == 1); + /* chown to root (fail) */ + chown_cb_count = 0; + r = uv_fs_chown(loop, &req, "test_file", 0, 0, chown_root_cb); + uv_run(loop); + ASSERT(chown_cb_count == 1); + /* async fchown */ r = uv_fs_fchown(loop, &req, file, -1, -1, fchown_cb); ASSERT(r == 0); @@ -1296,6 +1309,19 @@ TEST_IMPL(fs_stat_root) { r = uv_fs_stat(loop, &stat_req, "\\", NULL); ASSERT(r == 0); + r = uv_fs_stat(loop, &stat_req, "..\\..\\..\\..\\..\\..\\..", NULL); + ASSERT(r == 0); + + r = uv_fs_stat(loop, &stat_req, "..", NULL); + ASSERT(r == 0); + + r = uv_fs_stat(loop, &stat_req, "..\\", NULL); + ASSERT(r == 0); + + /* stats the current directory on c: */ + r = uv_fs_stat(loop, &stat_req, "c:", NULL); + ASSERT(r == 0); + r = uv_fs_stat(loop, &stat_req, "c:\\", NULL); ASSERT(r == 0); From f101f7c9babb31f077c78b52de7cc45ad687f57e Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 1 Feb 2012 22:07:42 +0100 Subject: [PATCH 06/22] buffers: honor length argument in base64 decoder Honor the length argument in `buf.write(s, 0, buf.length, 'base64')`. Before this commit, the length argument was ignored. The decoder would keep writing until it hit the end of the buffer. Since most buffers in Node are slices of a parent buffer (the slab), this bug would overwrite the content of adjacent buffers. The bug is trivially demonstrated with the following test case: var assert = require('assert'); var a = Buffer(3); var b = Buffer('xxx'); a.write('aaaaaaaa', 'base64'); assert.equal(b.toString(), 'xxx'); This commit coincidentally also fixes a bug where Buffer._charsWritten was not updated for zero length buffers. --- src/node_buffer.cc | 75 +++++++++++++++----------------------- test/simple/test-buffer.js | 13 ++++++- 2 files changed, 42 insertions(+), 46 deletions(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index d2335ff28f7..34ae5e5cc09 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -584,17 +584,6 @@ Handle Buffer::AsciiWrite(const Arguments &args) { Handle Buffer::Base64Write(const Arguments &args) { HandleScope scope; - assert(unbase64('/') == 63); - assert(unbase64('+') == 62); - assert(unbase64('T') == 19); - assert(unbase64('Z') == 25); - assert(unbase64('t') == 45); - assert(unbase64('z') == 51); - - assert(unbase64(' ') == -2); - assert(unbase64('\n') == -2); - assert(unbase64('\r') == -2); - Buffer *buffer = ObjectWrap::Unwrap(args.This()); if (!args[0]->IsString()) { @@ -604,67 +593,52 @@ Handle Buffer::Base64Write(const Arguments &args) { String::AsciiValue s(args[0]->ToString()); size_t offset = args[1]->Int32Value(); - - // handle zero-length buffers graciously - if (offset == 0 && buffer->length_ == 0) { - return scope.Close(Integer::New(0)); - } + size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset + : args[2]->Uint32Value(); + max_length = MIN(s.length(), MIN(buffer->length_ - offset, max_length)); if (offset >= buffer->length_) { return ThrowException(Exception::TypeError(String::New( "Offset is out of bounds"))); } - const size_t size = base64_decoded_size(*s, s.length()); - if (size > buffer->length_ - offset) { - // throw exception, don't silently truncate - return ThrowException(Exception::TypeError(String::New( - "Buffer too small"))); - } - char a, b, c, d; char* start = buffer->data_ + offset; char* dst = start; - const char *src = *s; - const char *const srcEnd = src + s.length(); + char* const dstEnd = dst + max_length; + const char* src = *s; + const char* const srcEnd = src + s.length(); - while (src < srcEnd) { + while (src < srcEnd && dst < dstEnd) { int remaining = srcEnd - src; - while (unbase64(*src) < 0 && src < srcEnd) { - src++; - remaining--; - } + while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--; if (remaining == 0 || *src == '=') break; a = unbase64(*src++); - while (unbase64(*src) < 0 && src < srcEnd) { - src++; - remaining--; - } + while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--; if (remaining <= 1 || *src == '=') break; b = unbase64(*src++); - *dst++ = (a << 2) | ((b & 0x30) >> 4); - while (unbase64(*src) < 0 && src < srcEnd) { - src++; - remaining--; - } + *dst++ = (a << 2) | ((b & 0x30) >> 4); + if (dst == dstEnd) break; + + while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--; if (remaining <= 2 || *src == '=') break; c = unbase64(*src++); - *dst++ = ((b & 0x0F) << 4) | ((c & 0x3C) >> 2); - while (unbase64(*src) < 0 && src < srcEnd) { - src++; - remaining--; - } + *dst++ = ((b & 0x0F) << 4) | ((c & 0x3C) >> 2); + if (dst == dstEnd) break; + + while (unbase64(*src) < 0 && src < srcEnd) src++, remaining--; if (remaining <= 3 || *src == '=') break; d = unbase64(*src++); + *dst++ = ((c & 0x03) << 6) | (d & 0x3F); } constructor_template->GetFunction()->Set(chars_written_sym, - Integer::New(s.length())); + Integer::New(dst - start)); return scope.Close(Integer::New(dst - start)); } @@ -759,6 +733,17 @@ bool Buffer::HasInstance(v8::Handle val) { void Buffer::Initialize(Handle target) { HandleScope scope; + // sanity checks + assert(unbase64('/') == 63); + assert(unbase64('+') == 62); + assert(unbase64('T') == 19); + assert(unbase64('Z') == 25); + assert(unbase64('t') == 45); + assert(unbase64('z') == 51); + assert(unbase64(' ') == -2); + assert(unbase64('\n') == -2); + assert(unbase64('\r') == -2); + length_symbol = Persistent::New(String::NewSymbol("length")); chars_written_sym = Persistent::New(String::NewSymbol("_charsWritten")); diff --git a/test/simple/test-buffer.js b/test/simple/test-buffer.js index b9f6ee042df..fd41ba3f8f2 100644 --- a/test/simple/test-buffer.js +++ b/test/simple/test-buffer.js @@ -687,7 +687,7 @@ assert.equal(Buffer._charsWritten, 9); buf.write('0123456789', 'binary'); assert.equal(Buffer._charsWritten, 9); buf.write('123456', 'base64'); -assert.equal(Buffer._charsWritten, 6); +assert.equal(Buffer._charsWritten, 4); buf.write('00010203040506070809', 'hex'); assert.equal(Buffer._charsWritten, 18); @@ -703,3 +703,14 @@ assert.equal(Buffer({length: 'BAM'}).length, 0); // Make sure that strings are not coerced to numbers. assert.equal(Buffer('99').length, 2); assert.equal(Buffer('13.37').length, 5); + +// Ensure that the length argument is respected. +'ascii utf8 hex base64 binary'.split(' ').forEach(function(enc) { + assert.equal(Buffer(1).write('aaaaaa', 0, 1, enc), 1); +}); + +// Regression test, guard against buffer overrun in the base64 decoder. +var a = Buffer(3); +var b = Buffer('xxx'); +a.write('aaaaaaaa', 'base64'); +assert.equal(b.toString(), 'xxx'); From 7e40c7ddc93f9260a3f4b1683ff6f86aff91e761 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Wed, 1 Feb 2012 22:37:26 +0100 Subject: [PATCH 07/22] buffers: fix intermittent out of bounds error The base64 decoder would intermittently throw an out-of-bounds exception when the buffer in `buf.write('', 'base64')` was a zero-sized buffer located at the end of the slab. Fixes #2657. --- src/node_buffer.cc | 2 +- test/simple/test-buffer-regress-GH-2659.js | 30 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 test/simple/test-buffer-regress-GH-2659.js diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 34ae5e5cc09..51e5423e5e6 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -597,7 +597,7 @@ Handle Buffer::Base64Write(const Arguments &args) { : args[2]->Uint32Value(); max_length = MIN(s.length(), MIN(buffer->length_ - offset, max_length)); - if (offset >= buffer->length_) { + if (max_length && offset >= buffer->length_) { return ThrowException(Exception::TypeError(String::New( "Offset is out of bounds"))); } diff --git a/test/simple/test-buffer-regress-GH-2659.js b/test/simple/test-buffer-regress-GH-2659.js new file mode 100644 index 00000000000..19a1362fd77 --- /dev/null +++ b/test/simple/test-buffer-regress-GH-2659.js @@ -0,0 +1,30 @@ +// 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'); + +// This is not a great test. It depends on a Node internal, namely the slab +// size. Maybe we should expose that in some way. Then again, maybe not... +for (var n = 1; n <= 8192; ++n) { + Buffer(n); + Buffer(0).write('', 'base64'); +} From 30fd2f7bb27addadaf4c620eacc77f29a5716e37 Mon Sep 17 00:00:00 2001 From: isaacs Date: Thu, 2 Feb 2012 14:57:12 -0800 Subject: [PATCH 08/22] Add npm msysgit bash shim to msi installer --- tools/msvs/msi/product.wxs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/msvs/msi/product.wxs b/tools/msvs/msi/product.wxs index 1d445d272a9..aa07c1e8eaf 100644 --- a/tools/msvs/msi/product.wxs +++ b/tools/msvs/msi/product.wxs @@ -46,6 +46,9 @@ + + + From 465f57c56f9b915d9c8b4f5549457f3e7276ee06 Mon Sep 17 00:00:00 2001 From: isaacs Date: Thu, 2 Feb 2012 15:35:14 -0800 Subject: [PATCH 09/22] Upgrade v8 to 3.6.6.20 --- deps/v8/SConstruct | 3 ++- deps/v8/src/heap.cc | 9 ++++++++- deps/v8/src/version.cc | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/deps/v8/SConstruct b/deps/v8/SConstruct index 1dcdce4a8ce..f9c33caae5d 100644 --- a/deps/v8/SConstruct +++ b/deps/v8/SConstruct @@ -288,6 +288,7 @@ V8_EXTRA_FLAGS = { 'gcc': { 'all': { 'WARNINGFLAGS': ['-Wall', + '-Werror', '-W', '-Wno-unused-parameter', '-Wnon-virtual-dtor'] @@ -381,7 +382,7 @@ MKSNAPSHOT_EXTRA_FLAGS = { DTOA_EXTRA_FLAGS = { 'gcc': { 'all': { - 'WARNINGFLAGS': ['-Wno-uninitialized'], + 'WARNINGFLAGS': ['-Werror', '-Wno-uninitialized'], 'CCFLAGS': GCC_DTOA_EXTRA_CCFLAGS } }, diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc index c91f7691b03..82c66364106 100644 --- a/deps/v8/src/heap.cc +++ b/deps/v8/src/heap.cc @@ -563,7 +563,9 @@ void Heap::ReserveSpace( PagedSpace* cell_space = Heap::cell_space(); LargeObjectSpace* lo_space = Heap::lo_space(); bool gc_performed = true; - while (gc_performed) { + int counter = 0; + static const int kThreshold = 20; + while (gc_performed && counter++ < kThreshold) { gc_performed = false; if (!new_space->ReserveSpace(new_space_size)) { Heap::CollectGarbage(NEW_SPACE); @@ -602,6 +604,11 @@ void Heap::ReserveSpace( gc_performed = true; } } + + if (gc_performed) { + // Failed to reserve the space after several attempts. + V8::FatalProcessOutOfMemory("Heap::ReserveSpace"); + } } diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc index 2c21152f1be..4d0e2453546 100644 --- a/deps/v8/src/version.cc +++ b/deps/v8/src/version.cc @@ -35,7 +35,7 @@ #define MAJOR_VERSION 3 #define MINOR_VERSION 6 #define BUILD_NUMBER 6 -#define PATCH_LEVEL 19 +#define PATCH_LEVEL 20 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) #define IS_CANDIDATE_VERSION 0 From 71527e3a55b4a0ce895e62f74d5407317336d64b Mon Sep 17 00:00:00 2001 From: isaacs Date: Thu, 2 Feb 2012 15:37:59 -0800 Subject: [PATCH 10/22] Patches floating on v8 --- deps/v8/SConstruct | 3 +-- deps/v8/tools/gyp/v8.gyp | 7 +++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/deps/v8/SConstruct b/deps/v8/SConstruct index f9c33caae5d..1dcdce4a8ce 100644 --- a/deps/v8/SConstruct +++ b/deps/v8/SConstruct @@ -288,7 +288,6 @@ V8_EXTRA_FLAGS = { 'gcc': { 'all': { 'WARNINGFLAGS': ['-Wall', - '-Werror', '-W', '-Wno-unused-parameter', '-Wnon-virtual-dtor'] @@ -382,7 +381,7 @@ MKSNAPSHOT_EXTRA_FLAGS = { DTOA_EXTRA_FLAGS = { 'gcc': { 'all': { - 'WARNINGFLAGS': ['-Werror', '-Wno-uninitialized'], + 'WARNINGFLAGS': ['-Wno-uninitialized'], 'CCFLAGS': GCC_DTOA_EXTRA_CCFLAGS } }, diff --git a/deps/v8/tools/gyp/v8.gyp b/deps/v8/tools/gyp/v8.gyp index 50144172a04..92d1e5c96a6 100644 --- a/deps/v8/tools/gyp/v8.gyp +++ b/deps/v8/tools/gyp/v8.gyp @@ -641,6 +641,13 @@ ], } ], + ['OS=="solaris"', { + 'sources': [ + '../../src/platform-solaris.cc', + '../../src/platform-posix.cc' + ], + } + ], ['OS=="mac"', { 'sources': [ '../../src/platform-macos.cc', From 5937d02aed663ca0832f2bad09620ee50579695c Mon Sep 17 00:00:00 2001 From: isaacs Date: Thu, 2 Feb 2012 16:56:23 -0800 Subject: [PATCH 11/22] msi: npm bash shim fixes --- tools/msvs/msi/product.wxs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) mode change 100644 => 100755 tools/msvs/msi/product.wxs diff --git a/tools/msvs/msi/product.wxs b/tools/msvs/msi/product.wxs old mode 100644 new mode 100755 index aa07c1e8eaf..889fd37f1d5 --- a/tools/msvs/msi/product.wxs +++ b/tools/msvs/msi/product.wxs @@ -47,7 +47,7 @@ - + @@ -72,6 +72,7 @@ + From 051908e023f87894fa68f5b64d0b99a19a7db01e Mon Sep 17 00:00:00 2001 From: isaacs Date: Thu, 2 Feb 2012 16:04:47 -0800 Subject: [PATCH 12/22] 2012.02.02, Version 0.6.10 (stable) * Update V8 to 3.6.6.20 * Add npm msysgit bash shim to msi installer (isaacs) * buffers: fix intermittent out of bounds error (Ben Noordhuis) * buffers: honor length argument in base64 decoder (Ben Noordhuis) * windows: Fix path.exists regression (Bert Belder) * Make QueryString.parse run faster (Philip Tellis) * http: avoid freeing http-parser objects too early (koichik) * timers: add v0.4 compatibility hack (Ben Noordhuis) * Proper EPERM error code support (Igor Zinkovsky, Brandon Philips) * dgram: Implement udp multicast methods on windows (Bert Belder) --- ChangeLog | 25 ++++++++++++++++++++++++- doc/about/index.html | 2 +- doc/community/index.html | 2 +- doc/index.html | 18 +++++++++--------- doc/logos/index.html | 2 +- doc/template.html | 6 +++--- src/node_version.h | 2 +- 7 files changed, 40 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5f3b69f5a8f..b778f6cb615 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,27 @@ -2012.01.27, Version 0.6.9 (stable) +2012.02.02, Version 0.6.10 (stable) + +* Update V8 to 3.6.6.20 + +* Add npm msysgit bash shim to msi installer (isaacs) + +* buffers: fix intermittent out of bounds error (Ben Noordhuis) + +* buffers: honor length argument in base64 decoder (Ben Noordhuis) + +* windows: Fix path.exists regression (Bert Belder) + +* Make QueryString.parse run faster (Philip Tellis) + +* http: avoid freeing http-parser objects too early (koichik) + +* timers: add v0.4 compatibility hack (Ben Noordhuis) + +* Proper EPERM error code support (Igor Zinkovsky, Brandon Philips) + +* dgram: Implement udp multicast methods on windows (Bert Belder) + + +2012.01.27, Version 0.6.9 (stable), f19e20d33f57c4d2853aaea7d2724d44f3b0012f * dgram: Bring back missing functionality for Unix (Dan VerWeire, Roman Shtylman, Ben Noordhuis) - Note: Windows UDP support not yet complete. diff --git a/doc/about/index.html b/doc/about/index.html index f209769a5bb..e6d3fdb6ff8 100644 --- a/doc/about/index.html +++ b/doc/about/index.html @@ -130,7 +130,7 @@ console.log('Server running at http://127.0.0.1:1337/');
  • -

    Copyright 2010 Joyent, Inc, Node.js is a trademark of Joyent, Inc. View license.

    +

    Copyright 2010 Joyent, Inc, Node.js is a trademark of Joyent, Inc. View license.

    diff --git a/doc/community/index.html b/doc/community/index.html index ef9bac5ae1c..bd15c12678d 100644 --- a/doc/community/index.html +++ b/doc/community/index.html @@ -180,7 +180,7 @@
  • -

    Copyright 2010 Joyent, Inc, Node.js is a trademark of Joyent, Inc. View license.

    +

    Copyright 2010 Joyent, Inc, Node.js is a trademark of Joyent, Inc. View license.

    diff --git a/src/node_version.h b/src/node_version.h index 071fe984bcd..021bad76642 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -29,7 +29,7 @@ #define NODE_MAJOR_VERSION 0 #define NODE_MINOR_VERSION 6 #define NODE_PATCH_VERSION 10 -#define NODE_VERSION_IS_RELEASE 0 +#define NODE_VERSION_IS_RELEASE 1 #ifndef NODE_STRINGIFY #define NODE_STRINGIFY(n) NODE_STRINGIFY_HELPER(n) From 74a2528bd71ced1061aee2ae7f171d7c446a7bfd Mon Sep 17 00:00:00 2001 From: isaacs Date: Thu, 2 Feb 2012 17:19:28 -0800 Subject: [PATCH 13/22] Now working on v0.6.11 --- 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 021bad76642..b1260d78a47 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -28,8 +28,8 @@ #define NODE_MAJOR_VERSION 0 #define NODE_MINOR_VERSION 6 -#define NODE_PATCH_VERSION 10 -#define NODE_VERSION_IS_RELEASE 1 +#define NODE_PATCH_VERSION 11 +#define NODE_VERSION_IS_RELEASE 0 #ifndef NODE_STRINGIFY #define NODE_STRINGIFY(n) NODE_STRINGIFY_HELPER(n) From 9fb088e3ab71ed88a9cbf1f7e6c3bbe30e8d2f1a Mon Sep 17 00:00:00 2001 From: Dave Pacheco Date: Thu, 2 Feb 2012 17:02:09 -0800 Subject: [PATCH 14/22] dtrace: add missing translator Add missing translator for node_dtrace_http_*_request_t types. Fixes #2667. --- src/node.d | 232 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 194 insertions(+), 38 deletions(-) diff --git a/src/node.d b/src/node.d index c666127fffc..fae2378437e 100644 --- a/src/node.d +++ b/src/node.d @@ -64,26 +64,63 @@ translator node_connection_t { &((node_dtrace_connection64_t *)nc)->buffered, sizeof (int32_t)); }; -typedef struct { - uint32_t version; -} node_dtrace_http_request_t; - +/* + * 32-bit and 64-bit structures received from node for HTTP client request + * probe. + */ typedef struct { uint32_t url; uint32_t method; -} node_dtrace_http_request_v0_t; +} node_dtrace_http_client_request_t; + +typedef struct { + uint64_t url; + uint64_t method; +} node_dtrace_http_client_request64_t; + +/* + * The following structures are never used directly, but must exist to bind the + * types specified in the provider to the translators defined here. + * Ultimately, they always get cast to a more specific type inside the + * translator. To add to the confusion, the DTrace compiler does not allow + * declaring two translators with the same destination type if the source types + * are structures with the same size (because libctf says they're compatible, + * so dtrace considers them equivalent). Since we must define translators from + * node_dtrace_http_client_request_t (above), node_dtrace_http_request_t, and + * node_dtrace_http_server_request_t (both below), each of these three structs + * must be declared with a different size. + */ +typedef struct { + uint32_t version; + uint64_t dummy1; +} node_dtrace_http_request_t; + +typedef struct { + uint32_t version; + uint64_t dummy2; + uint64_t dummy3; +} node_dtrace_http_server_request_t; + +/* + * Actual 32-bit and 64-bit, v0 and v1 structures received from node for the + * HTTP server request probe. + */ +typedef struct { + uint32_t url; + uint32_t method; +} node_dtrace_http_server_request_v0_t; typedef struct { uint32_t version; uint32_t url; uint32_t method; uint32_t forwardedFor; -} node_dtrace_http_request_v1_t; +} node_dtrace_http_server_request_v1_t; typedef struct { uint64_t url; uint64_t method; -} node_dtrace_http_request64_v0_t; +} node_dtrace_http_server_request64_v0_t; typedef struct { uint32_t version; @@ -91,8 +128,13 @@ typedef struct { uint64_t url; uint64_t method; uint64_t forwardedFor; -} node_dtrace_http_request64_v1_t; +} node_dtrace_http_server_request64_v1_t; +/* + * In the end, both client and server request probes from both old and new + * binaries translate their arguments to node_http_request_t, which is what the + * user's D script ultimately sees. + */ typedef struct { string url; string method; @@ -100,60 +142,174 @@ typedef struct { } node_http_request_t; /* - * This translator is even filthier than usual owing to our attempts to - * maintain backwards compatibility. Previous versions of node used an - * http_request struct that had fields for "url" and "method". The current - * version also provides a "forwardedFor" field. To distinguish the binary - * representations of these structs, the new version also prepends a "version" - * member (where the old one has a "url" pointer). So each field that we're - * translating below first switches on the value of this "version" field: if - * it's larger than 4096, we know we must be looking at the "url" pointer of - * the older structure version. Otherwise, we must be looking at the new - * version. Besides this, we have the usual switch based on the userland - * process data model. This would all be simpler with macros, but those aren't - * available in delivered D library files since that would make DTrace - * dependent on cpp, which isn't always available. + * The following translators are particularly filthy for reasons of backwards + * compatibility. Stable versions of node prior to 0.6 used a single + * http_request struct with fields for "url" and "method" for both client and + * server probes. 0.6 added a "forwardedFor" field intended for the server + * probe only, and the http_request struct passed by the application was split + * first into client_http_request and server_http_request and the latter was + * again split for v0 (the old struct) and v1. + * + * To distinguish the binary representations of the two versions of these + * structs, the new version prepends a "version" member (where the old one has + * a "url" pointer). Each field that we're translating below first switches on + * the value of this "version" field: if it's larger than 4096, we know we must + * be looking at the "url" pointer of the older structure version. Otherwise, + * we must be looking at the new version. Besides this, we have the usual + * switch based on the userland process data model. This would all be simpler + * with macros, but those aren't available in D library files since we cannot + * rely on cpp being present at runtime. + * + * In retrospect, the versioning bit might have been unnecessary since the type + * of the object passed in should allow DTrace to select which translator to + * use. However, DTrace does sometimes use translators whose source types + * don't quite match, and since we know this versioning logic works, we just + * leave it alone. Each of the translators below is functionally identical + * (except that the client -> client translator doesn't bother translating + * forwardedFor) and should actually work with any version of any of the client + * or server structs transmitted by the application up to this point. */ -translator node_http_request_t { - url = (*(uint32_t *)copyin((uintptr_t)&nd->version, sizeof (uint32_t))) >= 4096 ? + +/* + * Translate from node_dtrace_http_server_request_t (received from node 0.6 and + * later versions) to node_http_request_t. + */ +translator node_http_request_t { + url = (*(uint32_t *)copyin((uintptr_t)(uint32_t *)nd, + sizeof (uint32_t))) >= 4096 ? (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? copyinstr(*(uint32_t *)copyin((uintptr_t) - &((node_dtrace_http_request_v0_t *)nd)->url, + &((node_dtrace_http_server_request_v0_t *)nd)->url, sizeof (uint32_t))) : copyinstr(*(uint64_t *)copyin((uintptr_t) - &((node_dtrace_http_request64_v0_t *)nd)->url, + &((node_dtrace_http_server_request64_v0_t *)nd)->url, sizeof (uint64_t)))) : (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? copyinstr(*(uint32_t *)copyin((uintptr_t) - &((node_dtrace_http_request_v1_t *)nd)->url, + &((node_dtrace_http_server_request_v1_t *)nd)->url, sizeof (uint32_t))) : copyinstr(*(uint64_t *)copyin((uintptr_t) - &((node_dtrace_http_request64_v1_t *)nd)->url, + &((node_dtrace_http_server_request64_v1_t *)nd)->url, sizeof (uint64_t)))); - method = (*(uint32_t *)copyin((uintptr_t)&nd->version, sizeof (uint32_t))) >= 4096 ? + method = (*(uint32_t *)copyin((uintptr_t)(uint32_t *)nd, + sizeof (uint32_t))) >= 4096 ? (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? copyinstr(*(uint32_t *)copyin((uintptr_t) - &((node_dtrace_http_request_v0_t *)nd)->method, + &((node_dtrace_http_server_request_v0_t *)nd)->method, sizeof (uint32_t))) : copyinstr(*(uint64_t *)copyin((uintptr_t) - &((node_dtrace_http_request64_v0_t *)nd)->method, + &((node_dtrace_http_server_request64_v0_t *)nd)->method, sizeof (uint64_t)))) : (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? copyinstr(*(uint32_t *)copyin((uintptr_t) - &((node_dtrace_http_request_v1_t *)nd)->method, + &((node_dtrace_http_server_request_v1_t *)nd)->method, sizeof (uint32_t))) : copyinstr(*(uint64_t *)copyin((uintptr_t) - &((node_dtrace_http_request64_v1_t *)nd)->method, + &((node_dtrace_http_server_request64_v1_t *)nd)->method, sizeof (uint64_t)))); - - forwardedFor = (*(uint32_t *) - copyin((uintptr_t)&nd->version, sizeof (uint32_t))) >= 4096 ? "" : + + forwardedFor = (*(uint32_t *)copyin((uintptr_t)(uint32_t *)nd, + sizeof (uint32_t))) >= 4096 ? "" : (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? copyinstr(*(uint32_t *)copyin((uintptr_t) - &((node_dtrace_http_request_v1_t *)nd)->forwardedFor, + &((node_dtrace_http_server_request_v1_t *)nd)->forwardedFor, sizeof (uint32_t))) : copyinstr(*(uint64_t *)copyin((uintptr_t) - &((node_dtrace_http_request64_v1_t *)nd)->forwardedFor, - sizeof (uint64_t)))); + &((node_dtrace_http_server_request64_v1_t *)nd)-> + forwardedFor, sizeof (uint64_t)))); +}; + +/* + * Translate from node_dtrace_http_client_request_t (received from node 0.6 and + * later versions) to node_http_request_t. + */ +translator node_http_request_t { + url = (*(uint32_t *)copyin((uintptr_t)(uint32_t *)nd, + sizeof (uint32_t))) >= 4096 ? + (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? + copyinstr(*(uint32_t *)copyin((uintptr_t) + &((node_dtrace_http_server_request_v0_t *)nd)->url, + sizeof (uint32_t))) : + copyinstr(*(uint64_t *)copyin((uintptr_t) + &((node_dtrace_http_server_request64_v0_t *)nd)->url, + sizeof (uint64_t)))) : + (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? + copyinstr(*(uint32_t *)copyin((uintptr_t) + &((node_dtrace_http_server_request_v1_t *)nd)->url, + sizeof (uint32_t))) : + copyinstr(*(uint64_t *)copyin((uintptr_t) + &((node_dtrace_http_server_request64_v1_t *)nd)->url, + sizeof (uint64_t)))); + + method = (*(uint32_t *)copyin((uintptr_t)(uint32_t *)nd, + sizeof (uint32_t))) >= 4096 ? + (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? + copyinstr(*(uint32_t *)copyin((uintptr_t) + &((node_dtrace_http_server_request_v0_t *)nd)->method, + sizeof (uint32_t))) : + copyinstr(*(uint64_t *)copyin((uintptr_t) + &((node_dtrace_http_server_request64_v0_t *)nd)->method, + sizeof (uint64_t)))) : + (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? + copyinstr(*(uint32_t *)copyin((uintptr_t) + &((node_dtrace_http_server_request_v1_t *)nd)->method, + sizeof (uint32_t))) : + copyinstr(*(uint64_t *)copyin((uintptr_t) + &((node_dtrace_http_server_request64_v1_t *)nd)->method, + sizeof (uint64_t)))); + + forwardedFor = ""; +}; + +/* + * Translate from node_dtrace_http_request_t (received from versions of node + * prior to 0.6) to node_http_request_t. This is used for both the server and + * client probes since these versions of node didn't distinguish between the + * types used in these probes. + */ +translator node_http_request_t { + url = (*(uint32_t *)copyin((uintptr_t)(uint32_t *)nd, + sizeof (uint32_t))) >= 4096 ? + (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? + copyinstr(*(uint32_t *)copyin((uintptr_t) + &((node_dtrace_http_server_request_v0_t *)nd)->url, + sizeof (uint32_t))) : + copyinstr(*(uint64_t *)copyin((uintptr_t) + &((node_dtrace_http_server_request64_v0_t *)nd)->url, + sizeof (uint64_t)))) : + (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? + copyinstr(*(uint32_t *)copyin((uintptr_t) + &((node_dtrace_http_server_request_v1_t *)nd)->url, + sizeof (uint32_t))) : + copyinstr(*(uint64_t *)copyin((uintptr_t) + &((node_dtrace_http_server_request64_v1_t *)nd)->url, + sizeof (uint64_t)))); + + method = (*(uint32_t *)copyin((uintptr_t)(uint32_t *)nd, + sizeof (uint32_t))) >= 4096 ? + (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? + copyinstr(*(uint32_t *)copyin((uintptr_t) + &((node_dtrace_http_server_request_v0_t *)nd)->method, + sizeof (uint32_t))) : + copyinstr(*(uint64_t *)copyin((uintptr_t) + &((node_dtrace_http_server_request64_v0_t *)nd)->method, + sizeof (uint64_t)))) : + (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? + copyinstr(*(uint32_t *)copyin((uintptr_t) + &((node_dtrace_http_server_request_v1_t *)nd)->method, + sizeof (uint32_t))) : + copyinstr(*(uint64_t *)copyin((uintptr_t) + &((node_dtrace_http_server_request64_v1_t *)nd)->method, + sizeof (uint64_t)))); + + forwardedFor = (*(uint32_t *) copyin((uintptr_t)(uint32_t *)nd, + sizeof (uint32_t))) >= 4096 ? "" : + (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? + copyinstr(*(uint32_t *)copyin((uintptr_t) + &((node_dtrace_http_server_request_v1_t *)nd)->forwardedFor, + sizeof (uint32_t))) : + copyinstr(*(uint64_t *)copyin((uintptr_t) + &((node_dtrace_http_server_request64_v1_t *)nd)-> + forwardedFor, sizeof (uint64_t)))); }; From 68db20656e99da5a179e7139e4f2c3ed9de34d1a Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Fri, 3 Feb 2012 15:37:46 +0100 Subject: [PATCH 15/22] Rename some occurrences of `process_1` back to `process` --- src/node.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/node.cc b/src/node.cc index 96b8373d371..9ac528a85d7 100644 --- a/src/node.cc +++ b/src/node.cc @@ -2429,7 +2429,7 @@ static Handle DebugProcess(const Arguments& args) { HandleScope scope; Handle rv = Undefined(); DWORD pid; - HANDLE process_l = NULL; + HANDLE process = NULL; HANDLE thread = NULL; HANDLE mapping = NULL; char mapping_name[32]; @@ -2442,12 +2442,12 @@ static Handle DebugProcess(const Arguments& args) { pid = (DWORD) args[0]->IntegerValue(); - process_l = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | + process = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, pid); - if (process_l == NULL) { + if (process == NULL) { rv = ThrowException(WinapiErrnoException(GetLastError(), "OpenProcess")); goto out; } @@ -2475,7 +2475,7 @@ static Handle DebugProcess(const Arguments& args) { goto out; } - thread = CreateRemoteThread(process_l, + thread = CreateRemoteThread(process, NULL, 0, *handler, @@ -2496,8 +2496,8 @@ static Handle DebugProcess(const Arguments& args) { } out: - if (process_l != NULL) { - CloseHandle(process_l); + if (process != NULL) { + CloseHandle(process); } if (thread != NULL) { CloseHandle(thread); From 4671e54495a29696ae8e5f9bd17ba4c63f5d1b23 Mon Sep 17 00:00:00 2001 From: Stefan Rusu Date: Fri, 3 Feb 2012 18:27:53 +0200 Subject: [PATCH 16/22] net: destroy socket on DNS error The socket was never destroyed on DNS errors. This broke some clients, including lib/https.js. --- lib/net.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/net.js b/lib/net.js index 85479412b2d..bdd5ba8fadc 100644 --- a/lib/net.js +++ b/lib/net.js @@ -570,6 +570,7 @@ Socket.prototype.connect = function(port /* [host], [cb] */) { // error event to the next tick. process.nextTick(function() { self.emit('error', err); + self.destroy(); }); } else { timers.active(self); From 07a983a6025cf788df2e2371e96924ffe8602e08 Mon Sep 17 00:00:00 2001 From: Stefan Rusu Date: Fri, 3 Feb 2012 18:29:58 +0200 Subject: [PATCH 17/22] test: add tcp and https DNS error tests net-dns-error: specifc test for the net DNS issue. http-dns-error: now it works for HTTPS as well. --- test/simple/test-http-dns-error.js | 5 +--- test/simple/test-net-dns-error.js | 48 ++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 test/simple/test-net-dns-error.js diff --git a/test/simple/test-http-dns-error.js b/test/simple/test-http-dns-error.js index 7abdbcf1346..fc6d6b89e11 100644 --- a/test/simple/test-http-dns-error.js +++ b/test/simple/test-http-dns-error.js @@ -59,10 +59,7 @@ function test(mod) { req.end(); } -// FIXME This doesn't work for https because the tls module won't emit errors -// until a secure channel has been established - and that is never going to -// happen because the host name is invalid. -//test(https); +test(https); test(http); process.on('exit', function() { diff --git a/test/simple/test-net-dns-error.js b/test/simple/test-net-dns-error.js new file mode 100644 index 00000000000..76b51497567 --- /dev/null +++ b/test/simple/test-net-dns-error.js @@ -0,0 +1,48 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var assert = require('assert'); + +var net = require('net'); + +var expected_bad_connections = 1; +var actual_bad_connections = 0; + +var host = '********'; +host += host; +host += host; +host += host; +host += host; +host += host; + +function do_not_call() { + throw new Error('This function should not have been called.'); +} + +var socket = net.connect(42, host, do_not_call); +socket.on('error', function (err) { + assert.equal(err.code, 'ENOTFOUND'); + actual_bad_connections++; +}); + +process.on('exit', function() { + assert.equal(actual_bad_connections, expected_bad_connections); +}); From f64989e63b9cf11c88e46b422de6234fc4699039 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Thu, 2 Feb 2012 00:44:22 -0600 Subject: [PATCH 18/22] fs: fix ReadStream fails to read from existing fd A ReadStream constructed from an existing file descriptor failed to start reading automatically. Avoids a userspace call to ReadStream.prototype._read(). --- lib/fs.js | 1 + test/simple/test-fs-read-stream-fd.js | 44 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 test/simple/test-fs-read-stream-fd.js diff --git a/lib/fs.js b/lib/fs.js index 7b61c8984c8..3603232abf8 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -1050,6 +1050,7 @@ var ReadStream = fs.ReadStream = function(path, options) { } if (this.fd !== null) { + this._read(); return; } diff --git a/test/simple/test-fs-read-stream-fd.js b/test/simple/test-fs-read-stream-fd.js new file mode 100644 index 00000000000..835ed97271d --- /dev/null +++ b/test/simple/test-fs-read-stream-fd.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 fs = require('fs'); +var assert = require('assert'); +var path = require('path'); + +var common = require('../common'); + +var file = path.join(common.tmpDir, '/read_stream_fd_test.txt'); +var input = 'hello world'; +var output = ''; +var fd, stream; + +fs.writeFileSync(file, input); +fd = fs.openSync(file, 'r'); + +stream = fs.createReadStream(null, { fd: fd, encoding: 'utf8' }); +stream.on('data', function(data) { + output += data; +}); + +process.on('exit', function() { + fs.unlinkSync(file); + assert.equal(output, input); +}); From 11d1eca9f3c465045828e3a00b103620c8253258 Mon Sep 17 00:00:00 2001 From: Marcel Laverdet Date: Wed, 10 Aug 2011 16:39:03 -0500 Subject: [PATCH 19/22] Add explicit v8 locker v8 requires a lock of each thread using the vm, but if none is explicitly is created it will implicitly create one for you. This creates issues when trying to build modules which use v8's multi-threading features because there's no lock to unlock. --- src/node.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/node.cc b/src/node.cc index 9ac528a85d7..cb37fef2552 100644 --- a/src/node.cc +++ b/src/node.cc @@ -2633,6 +2633,7 @@ int Start(int argc, char *argv[]) { argv = Init(argc, argv); v8::V8::Initialize(); + v8::Locker locker; v8::HandleScope handle_scope; // Create the one and only Context. From 0f0af55a0aadf3ca1a960de1b6072f6f4175434e Mon Sep 17 00:00:00 2001 From: koichik Date: Fri, 3 Feb 2012 20:09:30 +0900 Subject: [PATCH 20/22] net: fix large file downloads failing Fixes #2678. --- lib/net.js | 2 +- test/simple/test-net-write-slow.js | 60 ++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 test/simple/test-net-write-slow.js diff --git a/lib/net.js b/lib/net.js index bdd5ba8fadc..48129a9c8b4 100644 --- a/lib/net.js +++ b/lib/net.js @@ -481,7 +481,7 @@ function afterWrite(status, handle, req, buffer) { return; } - timers.active(this); + timers.active(self); self._pendingWriteReqs--; diff --git a/test/simple/test-net-write-slow.js b/test/simple/test-net-write-slow.js new file mode 100644 index 00000000000..ddb35c081d4 --- /dev/null +++ b/test/simple/test-net-write-slow.js @@ -0,0 +1,60 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); +var net = require('net'); + +var SIZE = 1E5; +var N = 10; +var received = 0; +var buf = new Buffer(SIZE); +buf.fill(0x61); // 'a' + +var server = net.createServer(function(socket) { + socket.setNoDelay(); + socket.setTimeout(500); + socket.on('timeout', function() { + assert.fail(); + }); + + for (var i = 0; i < N; ++i) { + socket.write(buf); + } + socket.end(); + +}).listen(common.PORT, function() { + var conn = net.connect(common.PORT); + conn.on('data', function(buf) { + received += buf.length; + conn.pause(); + setTimeout(function() { + conn.resume(); + }, 50); + }); + conn.on('end', function() { + server.close(); + }); +}); + +process.on('exit', function() { + assert.equal(received, SIZE * N); +}); From a2cd31cbf110229941cc5af0d69ed35019ef40d1 Mon Sep 17 00:00:00 2001 From: koichik Date: Sun, 5 Feb 2012 19:11:54 +0900 Subject: [PATCH 21/22] doc: add the note about 'data' event Refs #2691. --- doc/api/http.markdown | 22 +++++++++++++++++----- doc/api/net.markdown | 3 +++ doc/api/streams.markdown | 3 +++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/doc/api/http.markdown b/doc/api/http.markdown index dd3765f9849..2669195424d 100644 --- a/doc/api/http.markdown +++ b/doc/api/http.markdown @@ -128,7 +128,8 @@ See [net.Server.close()](net.html#server.close). This object is created internally by a HTTP server -- not by the user -- and passed as the first argument to a `'request'` listener. -This is an `EventEmitter` with the following events: +The request implements the [Readable Stream](streams.html#readable_Stream) +interface. This is an `EventEmitter` with the following events: ### Event: 'data' @@ -141,6 +142,9 @@ argument. The transfer-encoding has been decoded. The body chunk is a string. The body encoding is set with `request.setEncoding()`. +Note that the __data will be lost__ if there is no listener when a +`ServerRequest` emits a `'data'` event. + ### Event: 'end' `function () { }` @@ -245,7 +249,10 @@ authentication details. ## http.ServerResponse This object is created internally by a HTTP server--not by the user. It is -passed as the second parameter to the `'request'` event. It is a `Writable Stream`. +passed as the second parameter to the `'request'` event. + +The response implements the [Writable Stream](streams.html#writable_Stream) +interface. This is an `EventEmitter` with the following events: ### Event: 'close' @@ -575,11 +582,11 @@ event, the entire body will be caught. }, 10); }); -This is a `Writable Stream`. Note: Node does not check whether Content-Length and the length of the body which has been transmitted are equal or not. -This is an `EventEmitter` with the following events: +The request implements the [Writable Stream](streams.html#writable_Stream) +interface. This is an `EventEmitter` with the following events: ### Event 'response' @@ -711,7 +718,9 @@ will be called. This object is created when making a request with `http.request()`. It is passed to the `'response'` event of the request object. -The response implements the `Readable Stream` interface. +The response implements the [Readable Stream](streams.html#readable_Stream) +interface. This is an `EventEmitter` with the following events: + ### Event: 'data' @@ -719,6 +728,9 @@ The response implements the `Readable Stream` interface. Emitted when a piece of the message body is received. +Note that the __data will be lost__ if there is no listener when a +`ClientResponse` emits a `'data'` event. + ### Event: 'end' diff --git a/doc/api/net.markdown b/doc/api/net.markdown index 6b4ef5e38f1..2aa3980c2c0 100644 --- a/doc/api/net.markdown +++ b/doc/api/net.markdown @@ -395,6 +395,9 @@ Emitted when data is received. The argument `data` will be a `Buffer` or (See the [Readable Stream](streams.html#readable_Stream) section for more information.) +Note that the __data will be lost__ if there is no listener when a `Socket` +emits a `'data'` event. + #### Event: 'end' `function () { }` diff --git a/doc/api/streams.markdown b/doc/api/streams.markdown index 4c353212e36..e11f2dade76 100644 --- a/doc/api/streams.markdown +++ b/doc/api/streams.markdown @@ -15,6 +15,9 @@ A `Readable Stream` has the following methods, members, and events. The `'data'` event emits either a `Buffer` (by default) or a string if `setEncoding()` was used. +Note that the __data will be lost__ if there is no listener when a +`Readable Stream` emits a `'data'` event. + ### Event: 'end' `function () { }` From 7543c38dca2b4c64711f5667b82d80ffab3fd6a2 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 5 Feb 2012 23:30:14 +0100 Subject: [PATCH 22/22] Revert "Add explicit v8 locker" This reverts commit 11d1eca9f3c465045828e3a00b103620c8253258. It sporadically (but reproducibly) triggers an assert inside V8: Fatal error in /path/to/node/deps/v8/src/isolate.cc, line 1857 CHECK(CurrentPerIsolateThreadData()->isolate_ == this) failed Needs further investigation. --- src/node.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/node.cc b/src/node.cc index cb37fef2552..9ac528a85d7 100644 --- a/src/node.cc +++ b/src/node.cc @@ -2633,7 +2633,6 @@ int Start(int argc, char *argv[]) { argv = Init(argc, argv); v8::V8::Initialize(); - v8::Locker locker; v8::HandleScope handle_scope; // Create the one and only Context.