From 8c3a757ffc7d77d367dd348eee97187564d5fb2f Mon Sep 17 00:00:00 2001 From: Jeremy Martin Date: Wed, 28 Dec 2011 15:14:30 -0500 Subject: [PATCH 01/11] docs: tiny typo in http.markdown --- doc/api/http.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/http.markdown b/doc/api/http.markdown index 8dd9935a1e..57f13a48ad 100644 --- a/doc/api/http.markdown +++ b/doc/api/http.markdown @@ -647,7 +647,7 @@ A client server pair that show you how to listen for the `upgrade` event using ` ### Event: 'continue' -`function ()` +`function () { }` Emitted when the server sends a '100 Continue' HTTP response, usually because the request contained 'Expect: 100-continue'. This is an instruction that From 744ed46970ad2acd25b7e8539578b856ec35383a Mon Sep 17 00:00:00 2001 From: Damon Oehlman Date: Thu, 29 Dec 2011 12:15:49 +1000 Subject: [PATCH 02/11] repl: fix repl.start not passing the `ignoreUndefined` arg to the REPLServer constructor --- lib/repl.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/repl.js b/lib/repl.js index 3a5ac4346e..7cfbf0e878 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -247,8 +247,8 @@ exports.REPLServer = REPLServer; // prompt is a string to print on each line for the prompt, // source is a stream to use for I/O, defaulting to stdin/stdout. -exports.start = function(prompt, source, eval, useGlobal) { - var repl = new REPLServer(prompt, source, eval, useGlobal); +exports.start = function(prompt, source, eval, useGlobal, ignoreUndefined) { + var repl = new REPLServer(prompt, source, eval, useGlobal, ignoreUndefined); if (!exports.repl) exports.repl = repl; return repl; }; From 3f5bb15f353d607783a5937972bc990fcd67892a Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 29 Dec 2011 14:57:53 +0100 Subject: [PATCH 03/11] dgram: fix memory leak in error path --- src/udp_wrap.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index cd4c58ecab..741e4ed460 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -365,6 +365,7 @@ void UDPWrap::OnRecv(uv_udp_t* handle, if (nread == -1) { SetErrno(uv_last_error(uv_default_loop())); + ReleaseMemory(buf.base, NULL); } else { Local rinfo = Object::New(); From 432a2e4d397908965cfbdc44eb8a10c7fb840701 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 29 Dec 2011 13:36:13 -0800 Subject: [PATCH 04/11] Add test for #2438 Unfortunately valgrind must be used to see the bad read. It would be nice if we could improve this test to cause a segfault. --- test/simple/test-http-parser-bad-ref.js | 72 +++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 test/simple/test-http-parser-bad-ref.js diff --git a/test/simple/test-http-parser-bad-ref.js b/test/simple/test-http-parser-bad-ref.js new file mode 100644 index 0000000000..b8fd5b2917 --- /dev/null +++ b/test/simple/test-http-parser-bad-ref.js @@ -0,0 +1,72 @@ +// Run this program with valgrind or efence with --expose_gc to expose the +// problem. + +// Flags: --expose_gc + +var assert = require('assert'); +var HTTPParser = process.binding('http_parser').HTTPParser; + +var headersComplete = 0; +var messagesComplete = 0; + +function flushPool() { + new Buffer(Buffer.poolSize - 1); + gc(); +} + +function demoBug(part1, part2) { + var parser = new HTTPParser('REQUEST'); + + parser.headers = []; + parser.url = ''; + + parser.onHeaders = function(headers, url) { + parser.headers = parser.headers.concat(headers); + parser.url += url; + }; + + parser.onHeadersComplete = function(info) { + headersComplete++; + console.log("url", info.url); + }; + + parser.onBody = function(b, start, len) { }; + + parser.onMessageComplete = function() { + messagesComplete++; + }; + + + // We use a function to eliminate references to the Buffer b + // We want b to be GCed. The parser will hold a bad reference to it. + (function() { + var b = Buffer(part1); + flushPool(); + + console.log("parse the first part of the message"); + parser.execute(b, 0, b.length); + })(); + + flushPool(); + + (function() { + var b = Buffer(part2); + + console.log("parse the second part of the message"); + parser.execute(b, 0, b.length); + parser.finish(); + })(); +} + + +demoBug('POST /1', '/22 HTTP/1.1\r\n' + + 'Content-Type: text/plain\r\n' + + 'Content-Length: 4\r\n\r\n' + + 'pong'); + + +process.on('exit', function() { + assert.equal(1, headersComplete); + assert.equal(1, messagesComplete); + console.log("done!"); +}); From 8b2abed03df9bc16b37d1ac21bfc68b36dfa9f47 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 30 Dec 2011 02:03:08 +0100 Subject: [PATCH 05/11] bench: add /echo endpoint to http_simple Copies the POST request data verbatim into the response body. --- benchmark/http_simple.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/benchmark/http_simple.js b/benchmark/http_simple.js index 4b550283b8..74ba4d7768 100644 --- a/benchmark/http_simple.js +++ b/benchmark/http_simple.js @@ -54,6 +54,12 @@ var server = http.createServer(function (req, res) { } else if (command == "fixed") { body = fixed; + } else if (command == "echo") { + res.writeHead(200, { "Content-Type": "text/plain", + "Transfer-Encoding": "chunked" }); + req.pipe(res); + return; + } else { status = 404; body = "not found\n"; From 539598b11f34344c4e17afcb56b04a257f4fa3b2 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 31 Dec 2011 03:16:04 +0100 Subject: [PATCH 06/11] test: don't create temp files in fixtures dir --- test/simple/test-fs-watch.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/simple/test-fs-watch.js b/test/simple/test-fs-watch.js index 989c6352f3..678d4e048c 100644 --- a/test/simple/test-fs-watch.js +++ b/test/simple/test-fs-watch.js @@ -30,8 +30,7 @@ var watchSeenOne = 0; var watchSeenTwo = 0; var watchSeenThree = 0; -var startDir = process.cwd(); -var testDir = common.fixturesDir; +var testDir = common.tmpDir; var filenameOne = 'watch.txt'; var filepathOne = path.join(testDir, filenameOne); @@ -46,15 +45,16 @@ var filepathThree = path.join(testsubdir, filenameThree); process.on('exit', function() { - fs.unlinkSync(filepathOne); - fs.unlinkSync(filepathTwoAbs); - fs.unlinkSync(filepathThree); - fs.rmdirSync(testsubdir); assert.ok(watchSeenOne > 0); assert.ok(watchSeenTwo > 0); assert.ok(watchSeenThree > 0); }); +// Clean up stale files (if any) from previous run. +try { fs.unlinkSync(filepathOne); } catch (e) { } +try { fs.unlinkSync(filepathTwoAbs); } catch (e) { } +try { fs.unlinkSync(filepathThree); } catch (e) { } +try { fs.rmdirSync(testsubdir); } catch (e) { } fs.writeFileSync(filepathOne, 'hello'); From 8e57398b2032ca62712c3d846d22d4c04820bace Mon Sep 17 00:00:00 2001 From: isaacs Date: Mon, 7 Nov 2011 16:10:21 -0800 Subject: [PATCH 07/11] Fix #2034 repl message for .clear when useGlobal=true --- lib/repl.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/repl.js b/lib/repl.js index 7cfbf0e878..08697ab72e 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -712,12 +712,20 @@ function defineDefaultCommands(repl) { } }); + var clearMessage; + if (repl.useGlobal) { + clearMessage = 'Alias for .break'; + } else { + clearMessage = 'Break, and also clear the local context'; + } repl.defineCommand('clear', { - help: 'Break, and also clear the local context', + help: clearMessage, action: function() { - this.outputStream.write('Clearing context...\n'); this.bufferedCommand = ''; - this.resetContext(true); + if (!this.useGlobal) { + this.outputStream.write('Clearing context...\n'); + this.resetContext(true); + } this.displayPrompt(); } }); From c2fb062f60a596db3e03b3b34cb5b4d0c54d9553 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 1 Jan 2012 23:36:03 +0100 Subject: [PATCH 08/11] docs: fix typo on community page --- doc/community/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/community/index.html b/doc/community/index.html index 9c427624b5..dec8b58b90 100644 --- a/doc/community/index.html +++ b/doc/community/index.html @@ -73,7 +73,7 @@ should be reported to https://github.com/joyent/node/issues. Fixes to the code are welcome! Please see our contirbuting + href="https://github.com/joyent/node/wiki/Contributing">contributing guidelines for information on how to submit a patch.

@@ -159,4 +159,4 @@ } catch(err) {} - \ No newline at end of file + From 41f2725639dd10378cb0a5a57fe29157d7b926e9 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 2 Jan 2012 10:43:10 +0100 Subject: [PATCH 09/11] uv: upgrade to 38fc6ad --- deps/uv/LICENSE | 2 + deps/uv/include/uv-private/uv-win.h | 2 +- deps/uv/src/unix/kqueue.c | 2 + deps/uv/src/unix/linux.c | 2 + deps/uv/src/unix/sunos.c | 2 + deps/uv/src/win/fs-event.c | 145 ++++++++++++++++++++++------ deps/uv/src/win/fs.c | 8 +- deps/uv/test/test-fs-event.c | 20 +++- deps/uv/test/test-fs.c | 68 +++++++++++++ deps/uv/test/test-list.h | 4 + 10 files changed, 223 insertions(+), 32 deletions(-) diff --git a/deps/uv/LICENSE b/deps/uv/LICENSE index f7df47f71c..f62d7f1991 100644 --- a/deps/uv/LICENSE +++ b/deps/uv/LICENSE @@ -33,6 +33,8 @@ The externally maintained libraries used by libuv are: - ngx_queue.h (from Nginx), copyright Igor Sysoev. Two clause BSD license. + - c-ares, copyright Daniel Stenberg and others. MIT licensed. + - libev, located at ev/ is copyright Marc Alexander Lehmann, and dual-licensed under the MIT license and GPL2. diff --git a/deps/uv/include/uv-private/uv-win.h b/deps/uv/include/uv-private/uv-win.h index 7c1818cbc9..ea770132dd 100644 --- a/deps/uv/include/uv-private/uv-win.h +++ b/deps/uv/include/uv-private/uv-win.h @@ -414,7 +414,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); uv_fs_event_cb cb; \ wchar_t* filew; \ wchar_t* short_filew; \ - int is_path_dir; \ + wchar_t* dirw; \ char* buffer; int uv_utf16_to_utf8(const wchar_t* utf16Buffer, size_t utf16Size, diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index 551bce0a62..58a6816d8a 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -43,10 +43,12 @@ static void uv__fs_event_start(uv_fs_event_t* handle) { handle->fd, EV_LIBUV_KQUEUE_HACK); ev_io_start(handle->loop->ev, &handle->event_watcher); + ev_unref(handle->loop->ev); } static void uv__fs_event_stop(uv_fs_event_t* handle) { + ev_ref(handle->loop->ev); ev_io_stop(handle->loop->ev, &handle->event_watcher); } diff --git a/deps/uv/src/unix/linux.c b/deps/uv/src/unix/linux.c index 965de0173b..3ed6565316 100644 --- a/deps/uv/src/unix/linux.c +++ b/deps/uv/src/unix/linux.c @@ -283,12 +283,14 @@ int uv_fs_event_init(uv_loop_t* loop, ev_io_init(&handle->read_watcher, uv__inotify_read, fd, EV_READ); ev_io_start(loop->ev, &handle->read_watcher); + ev_unref(loop->ev); return 0; } void uv__fs_event_destroy(uv_fs_event_t* handle) { + ev_ref(handle->loop->ev); ev_io_stop(handle->loop->ev, &handle->read_watcher); uv__close(handle->fd); handle->fd = -1; diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index cf9f162a26..dbdad3ce7b 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/src/unix/sunos.c @@ -166,12 +166,14 @@ int uv_fs_event_init(uv_loop_t* loop, ev_io_init(&handle->event_watcher, uv__fs_event_read, portfd, EV_READ); ev_io_start(loop->ev, &handle->event_watcher); + ev_unref(loop->ev); return 0; } void uv__fs_event_destroy(uv_fs_event_t* handle) { + ev_ref(handle->loop->ev); ev_io_stop(handle->loop->ev, &handle->event_watcher); uv__close(handle->fd); handle->fd = -1; diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index b2f6583a40..5a25e9d647 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/src/win/fs-event.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "uv.h" #include "internal.h" @@ -36,12 +37,12 @@ static void uv_fs_event_init_handle(uv_loop_t* loop, uv_fs_event_t* handle, handle->loop = loop; handle->flags = 0; handle->cb = cb; - handle->is_path_dir = 0; handle->dir_handle = INVALID_HANDLE_VALUE; handle->buffer = NULL; handle->req_pending = 0; handle->filew = NULL; handle->short_filew = NULL; + handle->dirw = NULL; uv_req_init(loop, (uv_req_t*)&handle->req); handle->req.type = UV_FS_EVENT_REQ; @@ -134,9 +135,9 @@ static int uv_split_path(const wchar_t* filename, wchar_t** dir, int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle, const char* filename, uv_fs_event_cb cb, int flags) { - int name_size; + int name_size, is_path_dir; DWORD attr, last_error; - wchar_t* dir = NULL, *dir_to_watch, *filenamew; + wchar_t* dir = NULL, *dir_to_watch, *filenamew = NULL; wchar_t short_path[MAX_PATH]; /* We don't support any flags yet. */ @@ -164,10 +165,11 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle, goto error; } - handle->is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0; + is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0; - if (handle->is_path_dir) { + if (is_path_dir) { /* filename is a directory, so that's the directory that we will watch. */ + handle->dirw = filenamew; dir_to_watch = filenamew; } else { /* @@ -192,6 +194,8 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle, } dir_to_watch = dir; + free(filenamew); + filenamew = NULL; } handle->dir_handle = CreateFileW(dir_to_watch, @@ -268,6 +272,8 @@ error: handle->short_filew = NULL; } + free(filenamew); + if (handle->dir_handle != INVALID_HANDLE_VALUE) { CloseHandle(handle->dir_handle); handle->dir_handle = INVALID_HANDLE_VALUE; @@ -286,8 +292,9 @@ error: void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, uv_fs_event_t* handle) { FILE_NOTIFY_INFORMATION* file_info; + int sizew, size, result; char* filename = NULL; - int utf8size; + wchar_t* filenamew, *long_filenamew = NULL; DWORD offset = 0; assert(req->type == UV_FS_EVENT_REQ); @@ -300,39 +307,114 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, if (req->overlapped.InternalHigh > 0) { do { file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset); + assert(!filename); + assert(!long_filenamew); /* * Fire the event only if we were asked to watch a directory, * or if the filename filter matches. */ - if (handle->is_path_dir || + if (handle->dirw || _wcsnicmp(handle->filew, file_info->FileName, file_info->FileNameLength / sizeof(wchar_t)) == 0 || _wcsnicmp(handle->short_filew, file_info->FileName, file_info->FileNameLength / sizeof(wchar_t)) == 0) { - - /* Convert the filename to utf8. */ - utf8size = uv_utf16_to_utf8(file_info->FileName, - file_info->FileNameLength / - sizeof(wchar_t), - NULL, - 0); - if (utf8size) { - filename = (char*)malloc(utf8size + 1); - if (!filename) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); - } - utf8size = uv_utf16_to_utf8(file_info->FileName, - file_info->FileNameLength / - sizeof(wchar_t), - filename, - utf8size); - if (utf8size) { - filename[utf8size] = '\0'; + if (handle->dirw) { + /* + * We attempt to convert the file name to its long form for + * events that still point to valid files on disk. + * For removed and renamed events, we do not provide the file name. + */ + if (file_info->Action != FILE_ACTION_REMOVED && + file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) { + /* Construct a full path to the file. */ + size = wcslen(handle->dirw) + + file_info->FileNameLength / sizeof(wchar_t) + 2; + + filenamew = (wchar_t*)malloc(size * sizeof(wchar_t)); + if (!filenamew) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + _snwprintf(filenamew, size, L"%s\\%s", handle->dirw, + file_info->FileName); + + filenamew[size - 1] = L'\0'; + + /* Convert to long name. */ + size = GetLongPathNameW(filenamew, NULL, 0); + + if (size) { + long_filenamew = (wchar_t*)malloc(size * sizeof(wchar_t)); + if (!long_filenamew) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + size = GetLongPathNameW(filenamew, long_filenamew, size); + if (size) { + long_filenamew[size] = '\0'; + } else { + free(long_filenamew); + long_filenamew = NULL; + } + } + + free(filenamew); + + if (long_filenamew) { + /* Get the file name out of the long path. */ + result = uv_split_path(long_filenamew, NULL, &filenamew); + free(long_filenamew); + + if (result == 0) { + long_filenamew = filenamew; + sizew = -1; + } else { + long_filenamew = NULL; + } + } + + /* + * If we couldn't get the long name - just use the name + * provided by ReadDirectoryChangesW. + */ + if (!long_filenamew) { + filenamew = file_info->FileName; + sizew = file_info->FileNameLength / sizeof(wchar_t); + } } else { - free(filename); - filename = NULL; + /* Removed or renamed callbacks don't provide filename. */ + filenamew = NULL; + } + } else { + /* We already have the long name of the file, so just use it. */ + filenamew = handle->filew; + sizew = -1; + } + + if (filenamew) { + /* Convert the filename to utf8. */ + size = uv_utf16_to_utf8(filenamew, + sizew, + NULL, + 0); + if (size) { + filename = (char*)malloc(size + 1); + if (!filename) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + size = uv_utf16_to_utf8(filenamew, + sizew, + filename, + size); + if (size) { + filename[size] = '\0'; + } else { + free(filename); + filename = NULL; + } } } @@ -351,6 +433,8 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, free(filename); filename = NULL; + free(long_filenamew); + long_filenamew = NULL; } offset = file_info->NextEntryOffset; @@ -411,6 +495,11 @@ void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) { handle->filename = NULL; } + if (handle->dirw) { + free(handle->dirw); + handle->dirw = NULL; + } + if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 2037ddd6b7..78ccffab6b 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -542,8 +542,12 @@ void fs__fstat(uv_fs_t* req, uv_file file) { void fs__rename(uv_fs_t* req, const wchar_t* path, const wchar_t* new_path) { - int result = _wrename(path, new_path); - SET_REQ_RESULT(req, result); + if (!MoveFileExW(path, new_path, MOVEFILE_REPLACE_EXISTING)) { + SET_REQ_RESULT_WIN32_ERROR(req, GetLastError()); + return; + } + + SET_REQ_RESULT(req, 0); } diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c index 59bdebc032..8b52f67ff3 100644 --- a/deps/uv/test/test-fs-event.c +++ b/deps/uv/test/test-fs-event.c @@ -282,7 +282,7 @@ static void timer_cb(uv_timer_t* handle, int status) { ASSERT(status == 0); r = uv_fs_event_init(handle->loop, &fs_event, ".", fs_event_fail, 0); - ASSERT(r != -1); + ASSERT(r == 0); uv_close((uv_handle_t*)&fs_event, close_cb); uv_close((uv_handle_t*)handle, close_cb); @@ -308,3 +308,21 @@ TEST_IMPL(fs_event_immediate_close) { return 0; } + + +TEST_IMPL(fs_event_unref) { + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + r = uv_fs_event_init(loop, &fs_event, ".", fs_event_fail, 0); + ASSERT(r == 0); + + uv_unref(loop); + + r = uv_run(loop); + ASSERT(r == 0); + + return 0; +} diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 34f891c177..763af8a78d 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -1476,3 +1476,71 @@ TEST_IMPL(fs_file_open_append) { return 0; } + + +TEST_IMPL(fs_rename_to_existing_file) { + int r; + + /* Setup. */ + unlink("test_file"); + unlink("test_file2"); + + loop = uv_default_loop(); + + r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT, + S_IWRITE | S_IREAD, NULL); + ASSERT(r != -1); + ASSERT(open_req1.result != -1); + uv_fs_req_cleanup(&open_req1); + + r = uv_fs_write(loop, &write_req, open_req1.result, test_buf, + sizeof(test_buf), -1, NULL); + ASSERT(r != -1); + ASSERT(write_req.result != -1); + uv_fs_req_cleanup(&write_req); + + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r != -1); + ASSERT(close_req.result != -1); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_open(loop, &open_req1, "test_file2", O_WRONLY | O_CREAT, + S_IWRITE | S_IREAD, NULL); + ASSERT(r != -1); + ASSERT(open_req1.result != -1); + uv_fs_req_cleanup(&open_req1); + + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r != -1); + ASSERT(close_req.result != -1); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_rename(loop, &rename_req, "test_file", "test_file2", NULL); + ASSERT(r != -1); + ASSERT(rename_req.result != -1); + uv_fs_req_cleanup(&rename_req); + + r = uv_fs_open(loop, &open_req1, "test_file2", O_RDONLY, 0, NULL); + ASSERT(r != -1); + ASSERT(open_req1.result != -1); + uv_fs_req_cleanup(&open_req1); + + memset(buf, 0, sizeof(buf)); + r = uv_fs_read(loop, &read_req, open_req1.result, buf, sizeof(buf), -1, + NULL); + ASSERT(r != -1); + ASSERT(read_req.result != -1); + ASSERT(strcmp(buf, test_buf) == 0); + uv_fs_req_cleanup(&read_req); + + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r != -1); + ASSERT(close_req.result != -1); + uv_fs_req_cleanup(&close_req); + + /* Cleanup */ + unlink("test_file"); + unlink("test_file2"); + + return 0; +} \ No newline at end of file diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index dec5105349..f6b58a693f 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -112,9 +112,11 @@ TEST_DECLARE (fs_event_watch_file) TEST_DECLARE (fs_event_watch_file_current_dir) TEST_DECLARE (fs_event_no_callback_on_close) TEST_DECLARE (fs_event_immediate_close) +TEST_DECLARE (fs_event_unref) TEST_DECLARE (fs_readdir_empty_dir) TEST_DECLARE (fs_readdir_file) TEST_DECLARE (fs_open_dir) +TEST_DECLARE (fs_rename_to_existing_file) TEST_DECLARE (threadpool_queue_work_simple) TEST_DECLARE (counters_init) #ifdef _WIN32 @@ -267,9 +269,11 @@ TASK_LIST_START TEST_ENTRY (fs_event_watch_file_current_dir) TEST_ENTRY (fs_event_no_callback_on_close) TEST_ENTRY (fs_event_immediate_close) + TEST_ENTRY (fs_event_unref) TEST_ENTRY (fs_readdir_empty_dir) TEST_ENTRY (fs_readdir_file) TEST_ENTRY (fs_open_dir) + TEST_ENTRY (fs_rename_to_existing_file) TEST_ENTRY (threadpool_queue_work_simple) TEST_ENTRY (counters_init) From 884f689efecee487788d0b2d1289018735f2841c Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 2 Jan 2012 10:48:33 +0100 Subject: [PATCH 10/11] test: add #2293 regression test Creating a file event watcher with fs.watch({persistent:false}) should not block the event loop. --- test/simple/test-fs-watch.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/simple/test-fs-watch.js b/test/simple/test-fs-watch.js index 678d4e048c..21fe3102e1 100644 --- a/test/simple/test-fs-watch.js +++ b/test/simple/test-fs-watch.js @@ -141,3 +141,9 @@ setTimeout(function() { var fd = fs.openSync(filepathThree, 'w'); fs.closeSync(fd); }, 1000); + +// https://github.com/joyent/node/issues/2293 - non-persistent watcher should +// not block the event loop +fs.watch(__filename, {persistent: false}, function() { + assert(0); +}); From 6f8839d2ac362ced42235a34a023af5e2c656501 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 2 Jan 2012 12:02:05 +0100 Subject: [PATCH 11/11] crypto: add SecureContext.clearOptions() method SecureContext.setOptions() is backed by SSL_CTX_set_options() which, contrary to what the name suggests, is additive: it doesn't set options, it adds them to the already active options. Hence the need for SecureContext.clearOptions(), which lets you unset active options. --- src/node_crypto.cc | 27 +++++++++++++++------------ src/node_crypto.h | 1 + 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 9f73df35ca..f3bff2ed04 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -166,6 +166,7 @@ void SecureContext::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(t, "addRootCerts", SecureContext::AddRootCerts); NODE_SET_PROTOTYPE_METHOD(t, "setCiphers", SecureContext::SetCiphers); NODE_SET_PROTOTYPE_METHOD(t, "setOptions", SecureContext::SetOptions); + NODE_SET_PROTOTYPE_METHOD(t, "clearOptions", SecureContext::ClearOptions); NODE_SET_PROTOTYPE_METHOD(t, "setSessionIdContext", SecureContext::SetSessionIdContext); NODE_SET_PROTOTYPE_METHOD(t, "close", SecureContext::Close); @@ -540,21 +541,23 @@ Handle SecureContext::SetCiphers(const Arguments& args) { return True(); } -Handle SecureContext::SetOptions(const Arguments& args) { - HandleScope scope; - - SecureContext *sc = ObjectWrap::Unwrap(args.Holder()); - - if (args.Length() != 1 || !args[0]->IsUint32()) { - return ThrowException(Exception::TypeError(String::New("Bad parameter"))); +#define X(name, fn) \ + Handle name(const Arguments& args) { \ + HandleScope scope; \ + SecureContext *sc = ObjectWrap::Unwrap(args.Holder()); \ + if (args.Length() != 1 || !args[0]->IsInt32()) { \ + return ThrowException( \ + Exception::TypeError(String::New("Bad parameter"))); \ + } \ + fn(sc->ctx_, args[0]->Int32Value()); \ + return True(); \ } - unsigned int opts = args[0]->Uint32Value(); - - SSL_CTX_set_options(sc->ctx_, opts); +// can't use templates, SSL_CTX_set_options and SSL_CTX_clear_options are macros +X(SecureContext::SetOptions, SSL_CTX_set_options) +X(SecureContext::ClearOptions, SSL_CTX_clear_options) - return True(); -} +#undef X Handle SecureContext::SetSessionIdContext(const Arguments& args) { HandleScope scope; diff --git a/src/node_crypto.h b/src/node_crypto.h index 4cde964da4..58168e3df1 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -66,6 +66,7 @@ class SecureContext : ObjectWrap { static v8::Handle AddRootCerts(const v8::Arguments& args); static v8::Handle SetCiphers(const v8::Arguments& args); static v8::Handle SetOptions(const v8::Arguments& args); + static v8::Handle ClearOptions(const v8::Arguments& args); static v8::Handle SetSessionIdContext(const v8::Arguments& args); static v8::Handle Close(const v8::Arguments& args);