Browse Source

Merge remote-tracking branch 'ry/v0.10'

Conflicts:
	src/node_version.h
v0.11.0-release
isaacs 12 years ago
parent
commit
5917828622
  1. 2
      AUTHORS
  2. 33
      ChangeLog
  3. 13
      deps/npm/lib/search.js
  4. 2
      deps/uv/src/win/pipe.c
  5. 3
      deps/uv/src/win/tcp.c
  6. 8
      doc/api/events.markdown
  7. 23
      doc/api/fs.markdown
  8. 4
      doc/api/path.markdown
  9. 11
      doc/api/process.markdown
  10. 487
      doc/blog/release/v0.10.0.md
  11. 51
      lib/_stream_readable.js
  12. 1
      lib/events.js
  13. 34
      lib/fs.js
  14. 27
      lib/http.js
  15. 2
      lib/timers.js
  16. 6
      src/handle_wrap.cc
  17. 6
      src/handle_wrap.h
  18. 4
      src/node.js
  19. 2
      src/stream_wrap.cc
  20. 42
      test/simple/test-domain-nested-throw.js
  21. 42
      test/simple/test-event-emitter-no-error-provided-to-error-event.js
  22. 11
      test/simple/test-fs-readfile-error.js
  23. 1
      test/simple/test-http-allow-req-after-204-res.js
  24. 1
      test/simple/test-http-client-response-domain.js
  25. 1
      test/simple/test-http-contentLength0.js
  26. 1
      test/simple/test-http-head-request.js
  27. 1
      test/simple/test-http-head-response-has-no-body-end.js
  28. 1
      test/simple/test-http-head-response-has-no-body.js
  29. 1
      test/simple/test-http-legacy.js
  30. 1
      test/simple/test-http-max-headers-count.js
  31. 1
      test/simple/test-http-pipe-fs.js
  32. 86
      test/simple/test-http-set-timeout-server.js
  33. 1
      test/simple/test-http-should-keep-alive.js
  34. 1
      test/simple/test-http.js
  35. 3
      test/simple/test-https-client-reject.js
  36. 62
      test/simple/test-regress-GH-4948.js
  37. 86
      test/simple/test-stream-pipe-after-end.js
  38. 15
      test/simple/test-stream2-unpipe-leak.js
  39. 64
      test/simple/test-timers-this.js
  40. 14
      tools/msvs/msi/product.wxs
  41. 4
      tools/msvs/nodevars.bat

2
AUTHORS

@ -426,3 +426,5 @@ Aaron Cannon <cannona@fireantproductions.com>
Xidorn Quan <quanxunzhen@gmail.com> Xidorn Quan <quanxunzhen@gmail.com>
Paolo Fragomeni <paolo@async.ly> Paolo Fragomeni <paolo@async.ly>
Scott Blomquist <github@scott.blomqui.st> Scott Blomquist <github@scott.blomqui.st>
Henry Chin <hheennrryy@gmail.com>
Julian Gruber <julian@juliangruber.com>

33
ChangeLog

@ -1,4 +1,35 @@
2013.03.06, Version 0.9.12 (Unstable) 2013.03.11, Version 0.10.0 (Stable)
* npm: Upgrade to 1.2.14
* core: Append filename properly in dlopen on windows (isaacs)
* zlib: Manage flush flags appropriately (isaacs)
* domains: Handle errors thrown in nested error handlers (isaacs)
* buffer: Strip high bits when converting to ascii (Ben Noordhuis)
* win/msi: Enable modify and repair (Bert Belder)
* win/msi: Add feature selection for various node parts (Bert Belder)
* win/msi: use consistent registry key paths (Bert Belder)
* child_process: support sending dgram socket (Andreas Madsen)
* fs: Raise EISDIR on Windows when calling fs.read/write on a dir (isaacs)
* unix: fix strict aliasing warnings, macro-ify functions (Ben Noordhuis)
* unix: honor UV_THREADPOOL_SIZE environment var (Ben Noordhuis)
* win/tty: fix typo in color attributes enumeration (Bert Belder)
* win/tty: don't touch insert mode or quick edit mode (Bert Belder)
2013.03.06, Version 0.9.12 (Unstable), 0debf5a82934da805592b6496756cdf27c993abc
* stream: Allow strings in Readable.push/unshift (isaacs) * stream: Allow strings in Readable.push/unshift (isaacs)

13
deps/npm/lib/search.js

@ -86,6 +86,7 @@ function stripData (data) {
}) })
, url: !Object.keys(data.versions || {}).length ? data.url : null , url: !Object.keys(data.versions || {}).length ? data.url : null
, keywords: data.keywords || [] , keywords: data.keywords || []
, version: Object.keys(data.versions)[0] || []
, time: data.time , time: data.time
&& data.time.modified && data.time.modified
&& (new Date(data.time.modified).toISOString() && (new Date(data.time.modified).toISOString()
@ -142,18 +143,19 @@ function prettify (data, args) {
var longest = [] var longest = []
, spaces , spaces
, maxLen = npm.config.get("description") , maxLen = npm.config.get("description")
? [20, 60, 20, 20, Infinity] ? [20, 60, 20, 20, 10, Infinity]
: [20, 20, 20, Infinity] : [20, 20, 20, 10, Infinity]
, headings = npm.config.get("description") , headings = npm.config.get("description")
? ["NAME", "DESCRIPTION", "AUTHOR", "DATE", "KEYWORDS"] ? ["NAME", "DESCRIPTION", "AUTHOR", "DATE", "VERSION", "KEYWORDS"]
: ["NAME", "AUTHOR", "DATE", "KEYWORDS"] : ["NAME", "AUTHOR", "DATE", "VERSION", "KEYWORDS"]
, lines , lines
, searchsort = (npm.config.get("searchsort") || "NAME").toLowerCase() , searchsort = (npm.config.get("searchsort") || "NAME").toLowerCase()
, sortFields = { name: 0 , sortFields = { name: 0
, description: 1 , description: 1
, author: 2 , author: 2
, date: 3 , date: 3
, keywords: 4 } , version: 4
, keywords: 5 }
, searchRev = searchsort.charAt(0) === "-" , searchRev = searchsort.charAt(0) === "-"
, sortField = sortFields[searchsort.replace(/^\-+/, "")] , sortField = sortFields[searchsort.replace(/^\-+/, "")]
@ -171,6 +173,7 @@ function prettify (data, args) {
, data.description || "" , data.description || ""
, data.maintainers.join(" ") , data.maintainers.join(" ")
, data.time , data.time
, data.version || ""
, (data.keywords || []).join(" ") , (data.keywords || []).join(" ")
] ]
l.forEach(function (s, i) { l.forEach(function (s, i) {

2
deps/uv/src/win/pipe.c

@ -915,7 +915,7 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
} else { } else {
memset(&req->overlapped, 0, sizeof(req->overlapped)); memset(&req->overlapped, 0, sizeof(req->overlapped));
if (handle->flags & UV_HANDLE_EMULATE_IOCP) { if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
req->overlapped.hEvent = (HANDLE) ((DWORD) req->event_handle | 1); req->overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1);
} }
/* Do 0-read */ /* Do 0-read */

3
deps/uv/src/win/tcp.c

@ -113,7 +113,8 @@ static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle,
non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv4; non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv4;
} }
if (pSetFileCompletionNotificationModes && !non_ifs_lsp) { if (pSetFileCompletionNotificationModes &&
!(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) {
if (pSetFileCompletionNotificationModes((HANDLE) socket, if (pSetFileCompletionNotificationModes((HANDLE) socket,
FILE_SKIP_SET_EVENT_ON_HANDLE | FILE_SKIP_SET_EVENT_ON_HANDLE |
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {

8
doc/api/events.markdown

@ -99,3 +99,11 @@ Return the number of listeners for a given event.
* `listener` {Function} The event handler function * `listener` {Function} The event handler function
This event is emitted any time someone adds a new listener. This event is emitted any time someone adds a new listener.
### Event: 'removeListener'
* `event` {String} The event name
* `listener` {Function} The event handler function
This event is emitted any time someone removes a listener.

23
doc/api/fs.markdown

@ -63,26 +63,11 @@ Relative path to filename can be used, remember however that this path will be
relative to `process.cwd()`. relative to `process.cwd()`.
Most fs functions let you omit the callback argument. If you do, a default Most fs functions let you omit the callback argument. If you do, a default
callback is used that rethrows errors. To get a trace to the original call callback is used that ignores errors, but prints a deprecation
site, set the NODE_DEBUG environment variable: warning.
$ cat script.js **IMPORTANT**: Omitting the callback is deprecated. v0.12 will throw the
function bad() { errors as exceptions.
require('fs').readFile('/');
}
bad();
$ env NODE_DEBUG=fs node script.js
fs.js:66
throw err;
^
Error: EISDIR, read
at rethrow (fs.js:61:21)
at maybeCallback (fs.js:79:42)
at Object.fs.readFile (fs.js:153:18)
at bad (/path/to/script.js:2:17)
at Object.<anonymous> (/path/to/script.js:5:1)
<etc.>
## fs.rename(oldPath, newPath, [callback]) ## fs.rename(oldPath, newPath, [callback])

4
doc/api/path.markdown

@ -25,7 +25,9 @@ Example:
## path.join([path1], [path2], [...]) ## path.join([path1], [path2], [...])
Join all arguments together and normalize the resulting path. Join all arguments together and normalize the resulting path.
Non-string arguments are ignored.
Arguments must be strings. In v0.8, non-string arguments were
silently ignored. In v0.10 and up, an exception is thrown.
Example: Example:

11
doc/api/process.markdown

@ -379,10 +379,21 @@ The PID of the process.
console.log('This process is pid ' + process.pid); console.log('This process is pid ' + process.pid);
## process.title ## process.title
Getter/setter to set what is displayed in 'ps'. Getter/setter to set what is displayed in 'ps'.
When used as a setter, the maximum length is platform-specific and probably
short.
On Linux and OS X, it's limited to the size of the binary name plus the
length of the command line arguments because it overwrites the argv memory.
v0.8 allowed for longer process title strings by also overwriting the environ
memory but that was potentially insecure/confusing in some (rather obscure)
cases.
## process.arch ## process.arch

487
doc/blog/release/v0.10.0.md

@ -0,0 +1,487 @@
title: Node v0.10.0 (Stable)
category: release
version: 0.10.0
date: 2013-03-11T16:00:00.000Z
slug: node-v0-10-0-stable
author: Isaac Z. Schlueter
I am pleased to announce a new stable version of Node.
This branch brings significant improvements to many areas, with a
focus on API polish, ease of use, and backwards compatibility.
For a very brief overview of the relevant API changes since v0.8,
please see [the API changes wiki
page](https://github.com/joyent/node/wiki/Api-changes-between-v0.8-and-v0.10).
## Streams2
In a [previous post](http://blog.nodejs.org/2012/12/20/streams2/), we
introduced the
"[Streams2](http://blog.nodejs.org/2012/12/20/streams2/)" API changes.
If you haven't reviewed the changes, please go read that now (at least
the tl;dr section).
The changes to the stream interface have been a long time in the
making. Even from the earliest days of Node, we've all sort of known
that this whole "data events come right away" and "pause() is
advisory" stuff was unnecessarily awful. In v0.10, we finally bit the
bullet and committed to making drastic changes in order to make these
things better.
More importantly, all streams in Node-core are built using the same
set of easily-extended base classes, so their behavior is much more
consistent, and it's easier than ever to create streaming interfaces
in your own userland programs.
In fact, the Streams2 API was developed while using it for modules in
the npm registry. At the time of this writing, [37 published Node
modules](https://npmjs.org/browse/depended/readable-stream) already
are using the
[readable-stream](https://npmjs.org/package/readable-stream) library
as a dependency. The readable-stream npm package allows you to use
the new Stream interface in your legacy v0.8 codebase.
## Domains and Error Handling
The `domain` module has been elevated from "Experimental" to
"Unstable" status. It's been given more of a first-class treatment
internally, making it easier to handle some of the edge cases that we
found using Domains for error handling in v0.8. Specifically, domain
error handler no longer relies on `process.on('uncaughtException')`
being raised, and the C++ code in Node is domain-aware.
If you're not already using Domains to catch errors in your programs,
and you've found yourself wishing that you could get better debugging
information when errors are thrown (especially in the midst of lots of
requests and asynchronous calls), then definitely check it out.
## Faster process.nextTick
In v0.8 (and before), the `process.nextTick()` function scheduled its
callback using a spinner on the event loop. This *usually* caused the
callback to be fired before any other I/O. However, it was not
guaranteed.
As a result, a lot of programs (including some parts of Node's
internals) began using `process.nextTick` as a "do later, but before
any actual I/O is performed" interface. Since it usually works that
way, it seemed fine.
However, under load, it's possible for a server to have a lot of I/O
scheduled, to the point where the `nextTick` gets preempted for
something else. This led to some odd errors and race conditions,
which could not be fixed without changing the semantics of nextTick.
So, that's what we did. In v0.10, `nextTick` handlers are run right
after each call from C++ into JavaScript. That means that, if your
JavaScript code calls `process.nextTick`, then the callback will fire
as soon as the code runs to completion, but *before* going back to
the event loop. The race is over, and all is good.
However, there are programs out in the wild that use recursive calls
to `process.nextTick` to avoid pre-empting the I/O event loop for
long-running jobs. In order to avoid breaking horribly right away,
Node will now print a deprecation warning, and ask you to use
`setImmediate` for these kinds of tasks instead.
## Latency and Idle Garbage Collection
One of the toughest things to get right in a garbage collected
language is garbage collection. In order to try to avoid excessive
memory usage, Node used to try to tell V8 to collect some garbage
whenever the event loop was idle.
However, knowing exactly when to do this is extremely difficult.
There are different degrees of "idleness", and if you get it wrong,
you can easily end up spending massive amounts of time collecting
garbage when you'd least expect. In practice, disabling the
`IdleNotification` call yields better performance without any
excessive memory usage, because V8 is pretty good at knowing when it's
the best time to run GC.
So, in v0.10, we just ripped that feature out. (According to another
point of view, we fixed the bug that it was ever there in the first
place.) As a result, latency is much more predictable and stable.
You won't see a difference in the benchmarks as a result of this, but
you'll probably find that your app's response times are more reliable.
## Performance and Benchmarks
When the Streams2 feature first landed in master, it disrupted a lot
of things. We focused first on correctness rather than speed, and as
a result of that, we got a correct implementation that was
significantly slower.
We have a consistent rule in Node, that it cannot be allowed to get
slower for our main use cases. It took a lot of work, but over the
last few months, we've managed to get v0.10 to an appropriate level of
performance, without sacrificing the API goals that we had in mind.
Benchmarks are complicated beasts. Until this release, we've gotten
by with a pretty ad-hoc approach to running benchmarks. However, as
we started actually having to track down regressions, the need for a
more comprehensive approach was obvious.
Work is underway to figure out the optimum way to get statistically
significant benchmark results in an automated way. As it is, we're
still seeing significant jitter in some of the data, so take the red
and green colors with a grain of salt.
The benchmarks below were run on an Apple 13-inch, Late 2011 MacBook
Pro with a 2.8 GHz Intel Core i7 processor, 8GB of 1333MHz DDR3 RAM,
running OS X Lion 10.7.5 (11G63b). The numbers are slightly different
on Linux and SmartOS, but the conclusions are the same. The [raw data
is available](http://nodejs.org/benchmarks-v0.10-vs-v0.8/), as well.
## Benchmarks: http
Node is for websites, and websites run over HTTP, so this is the one
that people usually care the most about:
<pre style="background-color:#333;color:#eee;font-size:12px">
http/cluster.js type=bytes length=4: <span style="background-color:#0f0;color:#000">v0.10: 16843</span> v0.8: 16202 ................. <span style="background-color:#0f0;color:#000">3.96%</span>
http/cluster.js type=bytes length=1024: <span style="background-color:#0f0;color:#000">v0.10: 15505</span> v0.8: 15065 .............. <span style="background-color:#0f0;color:#000">2.92%</span>
http/cluster.js type=bytes length=102400: v0.10: 1555.2 <span style="background-color:#f00;color:#fff">v0.8: 1566.3</span> ......... <span style="background-color:#f00;color:#fff">-0.71%</span>
http/cluster.js type=buffer length=4: <span style="background-color:#0f0;color:#000">v0.10: 15308</span> v0.8: 14763 ................ <span style="background-color:#0f0;color:#000">3.69%</span>
http/cluster.js type=buffer length=1024: <span style="background-color:#0f0;color:#000">v0.10: 15039</span> v0.8: 14830 ............. <span style="background-color:#0f0;color:#000">1.41%</span>
http/cluster.js type=buffer length=102400: <span style="background-color:#0f0;color:#000">v0.10: 7584.6</span> v0.8: 7433.6 ......... <span style="background-color:#0f0;color:#000">2.03%</span>
http/simple.js type=bytes length=4: <span style="background-color:#0f0;color:#000">v0.10: 12343</span> v0.8: 11761 .................. <span style="background-color:#0f0;color:#000">4.95%</span>
http/simple.js type=bytes length=1024: <span style="background-color:#0f0;color:#000">v0.10: 11051</span> v0.8: 10287 ............... <span style="background-color:#0f0;color:#000">7.43%</span>
http/simple.js type=bytes length=102400: v0.10: 853.19 <span style="background-color:#f00;color:#fff">v0.8: 892.75</span> .......... <span style="background-color:#f00;color:#fff">-4.43%</span>
http/simple.js type=buffer length=4: <span style="background-color:#0f0;color:#000">v0.10: 11316</span> v0.8: 10728 ................. <span style="background-color:#0f0;color:#000">5.48%</span>
http/simple.js type=buffer length=1024: <span style="background-color:#0f0;color:#000">v0.10: 11199</span> v0.8: 10429 .............. <span style="background-color:#0f0;color:#000">7.38%</span>
http/simple.js type=buffer length=102400: <span style="background-color:#0f0;color:#000">v0.10: 4942.1</span> v0.8: 4822.9 .......... <span style="background-color:#0f0;color:#000">2.47%</span>
</pre>
What we see here is that, overall, HTTP is faster. It's just slightly
slower (1-5%) when sending extremely large string messages (ie
`type=bytes` rather than `type=buffer`). But otherwise, things are
about the same, or slightly faster.
## Benchmarks: fs
The fs.ReadStream throughput is massively improved, and less affected
by the chunk size argument:
<pre style="background-color:#333;color:#eee;font-size:12px">
fs/read-stream buf size=1024: <span style="background-color:#0f0;color:#000">v0.10</span>: 1106.6 v0.8: 60.597 ................... <span style="background-color:#0f0;color:#000">1726.12%</span>
fs/read-stream buf size=4096: <span style="background-color:#0f0;color:#000">v0.10</span>: 1107.9 v0.8: 235.51 .................... <span style="background-color:#0f0;color:#000">370.44%</span>
fs/read-stream buf size=65535: <span style="background-color:#0f0;color:#000">v0.10</span>: 1108.2 v0.8: 966.84 .................... <span style="background-color:#0f0;color:#000">14.62%</span>
fs/read-stream buf size=1048576: <span style="background-color:#0f0;color:#000">v0.10</span>: 1103.3 v0.8: 959.66 .................. <span style="background-color:#0f0;color:#000">14.97%</span>
fs/read-stream asc size=1024: <span style="background-color:#0f0;color:#000">v0.10</span>: 1081.5 v0.8: 62.218 ................... <span style="background-color:#0f0;color:#000">1638.21%</span>
fs/read-stream asc size=4096: <span style="background-color:#0f0;color:#000">v0.10</span>: 1082.3 v0.8: 174.78 .................... <span style="background-color:#0f0;color:#000">519.21%</span>
fs/read-stream asc size=65535: <span style="background-color:#0f0;color:#000">v0.10</span>: 1083.9 v0.8: 627.91 .................... <span style="background-color:#0f0;color:#000">72.62%</span>
fs/read-stream asc size=1048576: <span style="background-color:#0f0;color:#000">v0.10</span>: 1083.2 v0.8: 627.49 .................. <span style="background-color:#0f0;color:#000">72.62%</span>
fs/read-stream utf size=1024: <span style="background-color:#0f0;color:#000">v0.10</span>: 46.553 v0.8: 16.944 .................... <span style="background-color:#0f0;color:#000">174.74%</span>
fs/read-stream utf size=4096: <span style="background-color:#0f0;color:#000">v0.10</span>: 46.585 v0.8: 32.933 ..................... <span style="background-color:#0f0;color:#000">41.45%</span>
fs/read-stream utf size=65535: <span style="background-color:#0f0;color:#000">v0.10</span>: 46.57 v0.8: 45.832 ...................... <span style="background-color:#0f0;color:#000">1.61%</span>
fs/read-stream utf size=1048576: <span style="background-color:#0f0;color:#000">v0.10</span>: 46.576 v0.8: 45.884 ................... <span style="background-color:#0f0;color:#000">1.51%</span>
</pre>
The fs.WriteStream throughput increases considerably, for most
workloads. As the size of the chunk goes up, the speed is limited by
the underlying system and the cost of string conversion, so v0.8 and
v0.10 converge. But for smaller chunk sizes (like you'd be more
likely to see in real applications), v0.10 is a significant
improvement.
<pre style="background-color:#333;color:#eee;font-size:12px">
fs/write-stream buf size=2: <span style="background-color:#0f0;color:#000">v0.10</span>: 0.12434 v0.8: 0.10097 ..................... <span style="background-color:#0f0;color:#000">23.15%</span>
fs/write-stream buf size=1024: <span style="background-color:#0f0;color:#000">v0.10</span>: 59.926 v0.8: 49.822 .................... <span style="background-color:#0f0;color:#000">20.28%</span>
fs/write-stream buf size=65535: <span style="background-color:#0f0;color:#000">v0.10</span>: 180.41 v0.8: 179.26 .................... <span style="background-color:#0f0;color:#000">0.64%</span>
fs/write-stream buf size=1048576: <span style="background-color:#0f0;color:#000">v0.10</span>: 181.49 v0.8: 176.73 .................. <span style="background-color:#0f0;color:#000">2.70%</span>
fs/write-stream asc size=2: <span style="background-color:#0f0;color:#000">v0.10</span>: 0.11133 v0.8: 0.08123 ..................... <span style="background-color:#0f0;color:#000">37.06%</span>
fs/write-stream asc size=1024: <span style="background-color:#0f0;color:#000">v0.10</span>: 53.023 v0.8: 36.708 .................... <span style="background-color:#0f0;color:#000">44.45%</span>
fs/write-stream asc size=65535: <span style="background-color:#0f0;color:#000">v0.10</span>: 178.54 v0.8: 174.36 .................... <span style="background-color:#0f0;color:#000">2.39%</span>
fs/write-stream asc size=1048576: <span style="background-color:#0f0;color:#000">v0.10</span>: 185.27 v0.8: 183.65 .................. <span style="background-color:#0f0;color:#000">0.88%</span>
fs/write-stream utf size=2: <span style="background-color:#0f0;color:#000">v0.10</span>: 0.11165 v0.8: 0.080079 .................... <span style="background-color:#0f0;color:#000">39.43%</span>
fs/write-stream utf size=1024: <span style="background-color:#0f0;color:#000">v0.10</span>: 45.166 v0.8: 32.636 .................... <span style="background-color:#0f0;color:#000">38.39%</span>
fs/write-stream utf size=65535: <span style="background-color:#0f0;color:#000">v0.10</span>: 176.1 v0.8: 175.34 ..................... <span style="background-color:#0f0;color:#000">0.43%</span>
fs/write-stream utf size=1048576: v0.10: 182.3 <span style="background-color:#f00;color:#fff">v0.8</span>: 182.82 .................. <span style="background-color:#f00;color:#fff">-0.28%</span>
</pre>
## Benchmark: tls
We switched to a newer version of OpenSSL, and the CryptoStream
implementation was significantly changed to support the Stream2
interface.
The throughput of TLS connections is massively improved:
<pre style="background-color:#333;color:#eee;font-size:12px">
tls/throughput.js dur=5 type=buf size=2: <span style="background-color:#0f0;color:#000">v0.10: 0.90836</span> v0.8: 0.32381 ....... <span style="background-color:#0f0;color:#000">180.52%</span>
tls/throughput.js dur=5 type=buf size=1024: <span style="background-color:#0f0;color:#000">v0.10: 222.84</span> v0.8: 116.75 ....... <span style="background-color:#0f0;color:#000">90.87%</span>
tls/throughput.js dur=5 type=buf size=1048576: <span style="background-color:#0f0;color:#000">v0.10: 403.17</span> v0.8: 360.42 .... <span style="background-color:#0f0;color:#000">11.86%</span>
tls/throughput.js dur=5 type=asc size=2: <span style="background-color:#0f0;color:#000">v0.10: 0.78323</span> v0.8: 0.28761 ....... <span style="background-color:#0f0;color:#000">172.32%</span>
tls/throughput.js dur=5 type=asc size=1024: <span style="background-color:#0f0;color:#000">v0.10: 199.7</span> v0.8: 102.46 ........ <span style="background-color:#0f0;color:#000">94.91%</span>
tls/throughput.js dur=5 type=asc size=1048576: <span style="background-color:#0f0;color:#000">v0.10: 375.85</span> v0.8: 317.81 .... <span style="background-color:#0f0;color:#000">18.26%</span>
tls/throughput.js dur=5 type=utf size=2: <span style="background-color:#0f0;color:#000">v0.10: 0.78503</span> v0.8: 0.28834 ....... <span style="background-color:#0f0;color:#000">172.26%</span>
tls/throughput.js dur=5 type=utf size=1024: <span style="background-color:#0f0;color:#000">v0.10: 182.43</span> v0.8: 100.3 ........ <span style="background-color:#0f0;color:#000">81.88%</span>
tls/throughput.js dur=5 type=utf size=1048576: <span style="background-color:#0f0;color:#000">v0.10: 333.05</span> v0.8: 301.57 .... <span style="background-color:#0f0;color:#000">10.44%</span>
</pre>
However, the speed at which we can make connections is somewhat
reduced:
<pre style="background-color:#333;color:#eee;font-size:12px">
tls/tls-connect.js concurrency=1 dur=5: v0.10: 433.05 <span style="background-color:#f00;color:#fff">v0.8: 560.43</span> .......... <span style="background-color:#f00;color:#fff">-22.73%</span>
tls/tls-connect.js concurrency=10 dur=5: v0.10: 438.38 <span style="background-color:#f00;color:#fff">v0.8: 577.93</span> ......... <span style="background-color:#f00;color:#fff">-24.15%</span>
</pre>
At this point, it seems like the connection speed is related to the
new version of OpenSSL, but we'll be tracking that further.
TLS still has more room for improvement, but this throughput increase
is a huge step.
## Benchmark: net
The net throughput tests tell an interesting story. When sending
ascii messages, they're much faster.
<pre style="background-color:#333;color:#eee;font-size:12px">
net/net-c2s.js len=102400 type=asc dur=5: <span style="background-color:#0f0;color:#000">v0.10: 3.6551</span> v0.8: 2.0478 ......... <span style="background-color:#0f0;color:#000">78.49%</span>
net/net-c2s.js len=16777216 type=asc dur=5: <span style="background-color:#0f0;color:#000">v0.10: 3.2428</span> v0.8: 2.0503 ....... <span style="background-color:#0f0;color:#000">58.16%</span>
net/net-pipe.js len=102400 type=asc dur=5: <span style="background-color:#0f0;color:#000">v0.10: 4.4638</span> v0.8: 3.0798 ........ <span style="background-color:#0f0;color:#000">44.94%</span>
net/net-pipe.js len=16777216 type=asc dur=5: <span style="background-color:#0f0;color:#000">v0.10: 3.9449</span> v0.8: 2.8906 ...... <span style="background-color:#0f0;color:#000">36.48%</span>
net/net-s2c.js len=102400 type=asc dur=5: <span style="background-color:#0f0;color:#000">v0.10: 3.6306</span> v0.8: 2.0415 ......... <span style="background-color:#0f0;color:#000">77.84%</span>
net/net-s2c.js len=16777216 type=asc dur=5: <span style="background-color:#0f0;color:#000">v0.10: 3.2271</span> v0.8: 2.0636 ....... <span style="background-color:#0f0;color:#000">56.38%</span>
</pre>
When sending Buffer messages, they're just slightly slower. (This
difference is less than the typical variability of the test, but they
were run 20 times and outliers were factored out for this post.)
<pre style="background-color:#333;color:#eee;font-size:12px">
net/net-c2s.js len=102400 type=buf dur=5: v0.10: 5.5597 <span style="background-color:#f00;color:#fff">v0.8: 5.6967</span> ......... <span style="background-color:#f00;color:#fff">-2.40%</span>
net/net-c2s.js len=16777216 type=buf dur=5: v0.10: 6.1843 <span style="background-color:#f00;color:#fff">v0.8: 6.4595</span> ....... <span style="background-color:#f00;color:#fff">-4.26%</span>
net/net-pipe.js len=102400 type=buf dur=5: v0.10: 5.6898 <span style="background-color:#f00;color:#fff">v0.8: 5.986</span> ......... <span style="background-color:#f00;color:#fff">-4.95%</span>
net/net-pipe.js len=16777216 type=buf dur=5: <span style="background-color:#0f0;color:#000">v0.10: 5.9643</span> v0.8: 5.9251 ....... <span style="background-color:#0f0;color:#000">0.66%</span>
net/net-s2c.js len=102400 type=buf dur=5: v0.10: 5.473 <span style="background-color:#f00;color:#fff">v0.8: 5.6492</span> .......... <span style="background-color:#f00;color:#fff">-3.12%</span>
net/net-s2c.js len=16777216 type=buf dur=5: v0.10: 6.1986 <span style="background-color:#f00;color:#fff">v0.8: 6.3236</span> ....... <span style="background-color:#f00;color:#fff">-1.98%</span>
</pre>
When sending utf-8 messages, they're a bit slower than that:
<pre style="background-color:#333;color:#eee;font-size:12px">
net/net-c2s.js len=102400 type=utf dur=5: v0.10: 2.2671 <span style="background-color:#f00;color:#fff">v0.8: 2.4606</span> ......... <span style="background-color:#f00;color:#fff">-7.87%</span>
net/net-c2s.js len=16777216 type=utf dur=5: v0.10: 1.7434 <span style="background-color:#f00;color:#fff">v0.8: 1.8771</span> ....... <span style="background-color:#f00;color:#fff">-7.12%</span>
net/net-pipe.js len=102400 type=utf dur=5: v0.10: 3.1679 <span style="background-color:#f00;color:#fff">v0.8: 3.5401</span> ....... <span style="background-color:#f00;color:#fff">-10.51%</span>
net/net-pipe.js len=16777216 type=utf dur=5: v0.10: 2.5615 <span style="background-color:#f00;color:#fff">v0.8: 2.7002</span> ...... <span style="background-color:#f00;color:#fff">-5.14%</span>
net/net-s2c.js len=102400 type=utf dur=5: v0.10: 2.2495 <span style="background-color:#f00;color:#fff">v0.8: 2.4578</span> ......... <span style="background-color:#f00;color:#fff">-8.48%</span>
net/net-s2c.js len=16777216 type=utf dur=5: v0.10: 1.7733 <span style="background-color:#f00;color:#fff">v0.8: 1.8975</span> ....... <span style="background-color:#f00;color:#fff">-6.55%</span>
</pre>
You might suspect that this is a result of the new Streams
implementation. However, running the same benchmarks without using
any of the code in Node's `lib/` folder, just calling into the C++
bindings directly, yields consistently similar results.
This slight regression comes along with significant improvements in
everything that sits on *top* of TCP (that is, TLS and HTTP).
Keep an eye out for more work in this area. Fast is never fast
enough!
## Continuous Integration
To support a higher degree of stability, and hopefully catch issues
sooner, we have a Jenkins instance running every commit through the
test suite, on each operating system we support. You can watch the
action at [the Node Jenkins web portal](http://jenkins.nodejs.org/).
Coming soon, we'll have automatically generated nightly builds every
day, and eventually, the entire release process will be automated.
While we're pretty rigorous about running tests and benchmarks, it's
easy for things to slip by, and our ad-hoc methods are not cutting it
any longer. This promises a much lower incidence of the sort of
regressions that delayed the release of v0.10 for several months.
## Growing Out
A year ago, we said that the innovation in the Node universe would be
happening in userland modules. Now, we've finally taken that to its
logical conclusion, and moved our iteration on **core** modules into
userland as well. Things like `readable-stream` and `tlsnappy` allow
us to get much more user-testing, experimentation, and contributions
to a feature.
The userland module can live on as a compatibility layer so that
libraries can use the new features, even if they need to support older
versions of Node. This is a remarkably effective way to do node-core
development. Future developments will continue to be iterated in
userland modules.
## Growing Up <a name="enterprise"></a>
The question comes up pretty often whether Node is "ready for prime
time" yet. I usually answer that it depends on your requirements for
"prime time", but Node has been powering some high profile sites, and
the options for "real" companies using Node for The Business are
better than ever.
It would be out of scope to try to provide an exhaustive list of all
the companies using Node, and all of the options for support and
training. However, here are a few resources that are quickly
expanding to fill the "Enterprise Node" space.
For those looking for commercial support,
[StrongLoop](http://strongloop.com/) (Ben Noordhuis & Bert Belder's
company) has released a distribution containing node v0.10 that they
will support on Windows, Mac, Red Hat/Fedora, Debian/Ubuntu and
multiple cloud platforms. You can [download their Node distribution
here](http://strongloop.com/products#downloads).
[The Node Firm](http://thenodefirm.com) is a worldwide network of key
Node contributors and community members that help organizations
succeed with Node. Through corporate training, consulting,
architectural guidance, and [ongoing consulting
subscriptions](http://thenodefirm.com/nodejs-consulting-subscriptions),
they have helped Skype, Qualcomm, and others quickly and effectively
embrace Node.
Node would not be what it is without [npm](https://npmjs.org/), and
npm would not be what it is without the registry of published modules.
However, relying on the public registry is problematic for many
enterprise use-cases. [Iris npm](https://www.irisnpm.com/) is a fully
managed private npm registry, from [Iris
Couch](http://www.iriscouch.com), the team that runs the public npm
registry in production.
[Joyent](http://joyent.com), the company you probably know as the
custodian of the Node project, provides high performance cloud
infrastructure specializing in real-time web and mobile applications.
Joyent uses Node extensively throughout their stack, and provides
impressive [post-mortem debugging and real-time performance analysis
tools](http://dtrace.org/blogs/dap/2012/05/31/debugging-node-js-in-production-fluent-slides/)
for Node.js applications. They are also my employer, so I'd probably
have to get a "real" job if they weren't sponsoring Node :)
## Next Up: v0.12
The focus of Node v0.12 will be to make HTTP better. Node's current
HTTP implementation is pretty good, and clearly sufficient to do a lot
of interesting things with. However:
1. The codebase is a mess. We share a lot of code between the Client
and Server implementations, but do so in a way that makes it
unnecessarily painful to read the code or fix bugs. It will be
split up so that client and server are clearly separated, and have
cleaner interfaces.
2. The socket pooling behavior is confusing and weird. We will be
adding configurable socket pooling as a standalone utility. This
will allow us to implement KeepAlive behavior in a more reasonable
manner, as well as providing something that you can use in your own
programs.
There is some experimentation going on in the
[tlsnappy](https://github.com/indutny/tlsnappy) module, which may make
its way back into the core TLS implementation and speed things up
considerably.
## 1.0
After 0.12, the next major stable release will be 1.0. At that point,
very little will change in terms of the day-to-day operation of the
project, but it will mark a significant milestone in terms of our
stability and willingness to add new features. However, we've already
gotten strict about maintaining backwards compatibility, so this won't
really be so much of a shift.
New versions will still come out, especially to pull in new versions
of our dependencies, and bugs will continue to be fixed. There's been
talk of pinning our release cycles to V8, and automating the release
process in some interesting ways.
The goal of Node has always been to eventually be "finished" with the
core program. Of course, that's a rather lofty goal, perhaps even
impossible. But as we take Node to more places, and use it in more
ways, we're getting closer to the day when the relevant innovation
happens outside of the core Node program.
Stability in the platform enables growth on top of it.
And now, the traditional release notes:
## 2013.03.11, Version 0.10.0 (Stable)
* npm: Upgrade to 1.2.14
* core: Append filename properly in dlopen on windows (isaacs)
* zlib: Manage flush flags appropriately (isaacs)
* domains: Handle errors thrown in nested error handlers (isaacs)
* buffer: Strip high bits when converting to ascii (Ben Noordhuis)
* win/msi: Enable modify and repair (Bert Belder)
* win/msi: Add feature selection for various Node parts (Bert Belder)
* win/msi: use consistent registry key paths (Bert Belder)
* child_process: support sending dgram socket (Andreas Madsen)
* fs: Raise EISDIR on Windows when calling fs.read/write on a dir (isaacs)
* unix: fix strict aliasing warnings, macro-ify functions (Ben Noordhuis)
* unix: honor UV_THREADPOOL_SIZE environment var (Ben Noordhuis)
* win/tty: fix typo in color attributes enumeration (Bert Belder)
* win/tty: don't touch insert mode or quick edit mode (Bert Belder)
Source Code: http://nodejs.org/dist/v0.10.0/node-v0.10.0.tar.gz
Macintosh Installer (Universal): http://nodejs.org/dist/v0.10.0/node-v0.10.0.pkg
Windows Installer: http://nodejs.org/dist/v0.10.0/node-v0.10.0-x86.msi
Windows x64 Installer: http://nodejs.org/dist/v0.10.0/x64/node-v0.10.0-x64.msi
Windows x64 Files: http://nodejs.org/dist/v0.10.0/x64/
Linux 32-bit Binary: http://nodejs.org/dist/v0.10.0/node-v0.10.0-linux-x86.tar.gz
Linux 64-bit Binary: http://nodejs.org/dist/v0.10.0/node-v0.10.0-linux-x64.tar.gz
Solaris 32-bit Binary: http://nodejs.org/dist/v0.10.0/node-v0.10.0-sunos-x86.tar.gz
Solaris 64-bit Binary: http://nodejs.org/dist/v0.10.0/node-v0.10.0-sunos-x64.tar.gz
Other release files: http://nodejs.org/dist/v0.10.0/
Website: http://nodejs.org/docs/v0.10.0/
Documentation: http://nodejs.org/docs/v0.10.0/api/
Shasums:
```
b9e9bca99cdb5563cad3d3f04baa262e317b827c node-v0.10.0-darwin-x64.tar.gz
0227c9bc3df5b62267b9d4e3b0a92b3a70732229 node-v0.10.0-darwin-x86.tar.gz
9f5f7350d6f889ea8e794516ecfea651e8e53d24 node-v0.10.0-linux-x64.tar.gz
cc5f1cd6a2f2530bc400e761144bbaf8fcb66cc4 node-v0.10.0-linux-x86.tar.gz
42c14b7eab398976b1ac0a8e6e96989059616af5 node-v0.10.0-sunos-x64.tar.gz
ddcadbac66d1acea48aa6c5462d0a0d7308ea823 node-v0.10.0-sunos-x86.tar.gz
70eacf2cca7abec79fac4ca502e8d99590a2108a node-v0.10.0-x86.msi
c48c269b9b0f0a95e6e9234d4597d1c8a1c45c5a node-v0.10.0.pkg
7321266347dc1c47ed2186e7d61752795ce8a0ef node-v0.10.0.tar.gz
f8c6f55469551243ea461f023cc57c024f57fef2 node.exe
253ae79e411fcfddcf28861559ececb4b335db64 node.exp
acb8febb5ea714c065f201ced5423b0838fdf1b6 node.lib
0fdad1400036dd26d720070f783d3beeb3bb9c0a node.pdb
abcaf8ef606655a05e73ee5d06715ffd022aad22 x64/node-v0.10.0-x64.msi
e5d0c235629b26430b6e07c07ee2c7dcda82f35e x64/node.exe
43b3fb3a6aaf6a04f578ee607a9455c1e23acf08 x64/node.exp
87dd6eb6c8127a1af0dcca639961441fc303d75a x64/node.lib
50aca715777fa42b854e6cfc56b6199a54aabd3c x64/node.pdb
```

51
lib/_stream_readable.js

@ -49,6 +49,12 @@ function ReadableState(options, stream) {
this.endEmitted = false; this.endEmitted = false;
this.reading = false; this.reading = false;
// In streams that never have any data, and do push(null) right away,
// the consumer can miss the 'end' event if they do some I/O before
// consuming the stream. So, we don't emit('end') until some reading
// happens.
this.calledRead = false;
// a flag to be able to tell if the onwrite cb is called immediately, // a flag to be able to tell if the onwrite cb is called immediately,
// or on a later tick. We set this to true at first, becuase any // or on a later tick. We set this to true at first, becuase any
// actions that shouldn't happen until "later" should generally also // actions that shouldn't happen until "later" should generally also
@ -218,6 +224,7 @@ function howMuchToRead(n, state) {
// you can override either this method, or the async _read(n) below. // you can override either this method, or the async _read(n) below.
Readable.prototype.read = function(n) { Readable.prototype.read = function(n) {
var state = this._readableState; var state = this._readableState;
state.calledRead = true;
var nOrig = n; var nOrig = n;
if (typeof n !== 'number' || n > 0) if (typeof n !== 'number' || n > 0)
@ -386,17 +393,23 @@ function maybeReadMore(stream, state) {
if (!state.readingMore) { if (!state.readingMore) {
state.readingMore = true; state.readingMore = true;
process.nextTick(function() { process.nextTick(function() {
state.readingMore = false;
maybeReadMore_(stream, state); maybeReadMore_(stream, state);
}); });
} }
} }
function maybeReadMore_(stream, state) { function maybeReadMore_(stream, state) {
if (!state.reading && !state.flowing && !state.ended && var len = state.length;
state.length < state.highWaterMark) { while (!state.reading && !state.flowing && !state.ended &&
state.length < state.highWaterMark) {
stream.read(0); stream.read(0);
if (len === state.length)
// didn't get any data, stop spinning.
break;
else
len = state.length;
} }
state.readingMore = false;
} }
// abstract method. to be overridden in specific implementation classes. // abstract method. to be overridden in specific implementation classes.
@ -424,13 +437,15 @@ Readable.prototype.pipe = function(dest, pipeOpts) {
} }
state.pipesCount += 1; state.pipesCount += 1;
if ((!pipeOpts || pipeOpts.end !== false) && var doEnd = (!pipeOpts || pipeOpts.end !== false) &&
dest !== process.stdout && dest !== process.stdout &&
dest !== process.stderr) { dest !== process.stderr;
src.once('end', onend);
} else { var endFn = doEnd ? onend : cleanup;
src.once('end', cleanup); if (state.endEmitted)
} process.nextTick(endFn);
else
src.once('end', endFn);
dest.on('unpipe', onunpipe); dest.on('unpipe', onunpipe);
function onunpipe(readable) { function onunpipe(readable) {
@ -847,12 +862,12 @@ function endReadable(stream) {
if (state.length > 0) if (state.length > 0)
throw new Error('endReadable called on non-empty stream'); throw new Error('endReadable called on non-empty stream');
if (state.endEmitted) if (!state.endEmitted && state.calledRead) {
return; state.ended = true;
state.ended = true; state.endEmitted = true;
state.endEmitted = true; process.nextTick(function() {
process.nextTick(function() { stream.readable = false;
stream.readable = false; stream.emit('end');
stream.emit('end'); });
}); }
} }

1
lib/events.js

@ -63,6 +63,7 @@ EventEmitter.prototype.emit = function(type) {
!this._events.error.length)) { !this._events.error.length)) {
er = arguments[1]; er = arguments[1];
if (this.domain) { if (this.domain) {
if (!er) er = new TypeError('Uncaught, unspecified "error" event.');
er.domainEmitter = this; er.domainEmitter = this;
er.domain = this.domain; er.domain = this.domain;
er.domainThrown = false; er.domainThrown = false;

34
lib/fs.js

@ -59,22 +59,36 @@ var DEBUG = process.env.NODE_DEBUG && /fs/.test(process.env.NODE_DEBUG);
function rethrow() { function rethrow() {
// Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and // Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and
// is fairly slow to generate. // is fairly slow to generate.
var callback;
if (DEBUG) { if (DEBUG) {
var backtrace = new Error; var backtrace = new Error;
return function(err) { callback = debugCallback;
if (err) { } else
backtrace.message = err.message; callback = missingCallback;
err = backtrace;
throw err; return callback;
}
}; function debugCallback(err) {
if (err) {
backtrace.message = err.message;
err = backtrace;
missingCallback(err);
}
} }
return function(err) { function missingCallback(err) {
if (err) { if (err) {
throw err; // Forgot a callback but don't know where? Use NODE_DEBUG=fs if (process.throwDeprecation)
throw err; // Forgot a callback but don't know where? Use NODE_DEBUG=fs
else if (!process.noDeprecation) {
var msg = 'fs: missing callback ' + (err.stack || err.message);
if (process.traceDeprecation)
console.trace(msg);
else
console.error(msg);
}
} }
}; }
} }
function maybeCallback(cb) { function maybeCallback(cb) {

27
lib/http.js

@ -416,13 +416,13 @@ IncomingMessage.prototype._addHeaderLine = function(field, value) {
// Call this instead of resume() if we want to just // Call this instead of resume() if we want to just
// dump all the data to /dev/null // dump all the data to /dev/null
IncomingMessage.prototype._dump = function() { IncomingMessage.prototype._dump = function() {
if (this._dumped) if (!this._dumped) {
return; this._dumped = true;
if (this.socket.parser) this.socket.parser.incoming = null;
this._dumped = true; this.push(null);
this.socket.parser.incoming = null; readStart(this.socket);
this.push(null); this.read();
readStart(this.socket); }
}; };
@ -445,6 +445,9 @@ function OutgoingMessage() {
this.finished = false; this.finished = false;
this._hangupClose = false; this._hangupClose = false;
this.socket = null;
this.connection = null;
} }
util.inherits(OutgoingMessage, Stream); util.inherits(OutgoingMessage, Stream);
@ -455,7 +458,12 @@ exports.OutgoingMessage = OutgoingMessage;
OutgoingMessage.prototype.setTimeout = function(msecs, callback) { OutgoingMessage.prototype.setTimeout = function(msecs, callback) {
if (callback) if (callback)
this.on('timeout', callback); this.on('timeout', callback);
this.socket.setTimeout(msecs); if (!this.socket) {
this.once('socket', function(socket) {
socket.setTimeout(msecs);
});
} else
this.socket.setTimeout(msecs);
}; };
@ -1056,6 +1064,7 @@ ServerResponse.prototype.assignSocket = function(socket) {
socket.on('close', onServerResponseClose); socket.on('close', onServerResponseClose);
this.socket = socket; this.socket = socket;
this.connection = socket; this.connection = socket;
this.emit('socket', socket);
this._flush(); this._flush();
}; };
@ -1864,7 +1873,7 @@ function connectionListener(socket) {
socket.setTimeout(self.timeout); socket.setTimeout(self.timeout);
socket.on('timeout', function() { socket.on('timeout', function() {
var req = socket.parser && socket.parser.incoming; var req = socket.parser && socket.parser.incoming;
var reqTimeout = req && req.emit('timeout', socket); var reqTimeout = req && !req.complete && req.emit('timeout', socket);
var res = socket._httpMessage; var res = socket._httpMessage;
var resTimeout = res && res.emit('timeout', socket); var resTimeout = res && res.emit('timeout', socket);
var serverTimeout = self.emit('timeout', socket); var serverTimeout = self.emit('timeout', socket);

2
lib/timers.js

@ -324,7 +324,7 @@ exports.setImmediate = function(callback) {
args = Array.prototype.slice.call(arguments, 1); args = Array.prototype.slice.call(arguments, 1);
immediate._onImmediate = function() { immediate._onImmediate = function() {
callback.apply(null, args); callback.apply(immediate, args);
}; };
} }

6
src/handle_wrap.cc

@ -23,12 +23,6 @@
#include "ngx-queue.h" #include "ngx-queue.h"
#include "handle_wrap.h" #include "handle_wrap.h"
#define UNWRAP_NO_ABORT(type) \
assert(!args.Holder().IsEmpty()); \
assert(args.Holder()->InternalFieldCount() > 0); \
type* wrap = static_cast<type*>( \
args.Holder()->GetPointerFromInternalField(0));
namespace node { namespace node {
using v8::Arguments; using v8::Arguments;

6
src/handle_wrap.h

@ -46,6 +46,12 @@ namespace node {
// js/c++ boundary crossing. At the javascript layer that should all be // js/c++ boundary crossing. At the javascript layer that should all be
// taken care of. // taken care of.
#define UNWRAP_NO_ABORT(type) \
assert(!args.Holder().IsEmpty()); \
assert(args.Holder()->InternalFieldCount() > 0); \
type* wrap = static_cast<type*>( \
args.Holder()->GetPointerFromInternalField(0));
class HandleWrap { class HandleWrap {
public: public:
static void Initialize(v8::Handle<v8::Object> target); static void Initialize(v8::Handle<v8::Object> target);

4
src/node.js

@ -258,7 +258,9 @@
// The domain error handler threw! oh no! // The domain error handler threw! oh no!
// See if another domain can catch THIS error, // See if another domain can catch THIS error,
// or else crash on the original one. // or else crash on the original one.
domainStack.pop(); // If the user already exited it, then don't double-exit.
if (domain === domainModule.active)
domainStack.pop();
if (domainStack.length) { if (domainStack.length) {
var parentDomain = domainStack[domainStack.length - 1]; var parentDomain = domainStack[domainStack.length - 1];
process.domain = domainModule.active = parentDomain; process.domain = domainModule.active = parentDomain;

2
src/stream_wrap.cc

@ -122,7 +122,7 @@ Handle<Value> StreamWrap::GetFD(Local<String>, const AccessorInfo& args) {
return v8::Null(); return v8::Null();
#else #else
HandleScope scope; HandleScope scope;
UNWRAP(StreamWrap) UNWRAP_NO_ABORT(StreamWrap)
int fd = -1; int fd = -1;
if (wrap != NULL && wrap->stream_ != NULL) fd = wrap->stream_->io_watcher.fd; if (wrap != NULL && wrap->stream_ != NULL) fd = wrap->stream_->io_watcher.fd;
return scope.Close(Integer::New(fd)); return scope.Close(Integer::New(fd));

42
test/simple/test-domain-nested-throw.js

@ -24,6 +24,34 @@ var assert = require('assert');
var domain = require('domain'); var domain = require('domain');
var dispose;
switch (process.argv[2]) {
case 'true':
dispose = true;
break;
case 'false':
dispose = false;
break;
default:
parent();
return;
}
function parent() {
var node = process.execPath;
var spawn = require('child_process').spawn;
var opt = { stdio: 'inherit' };
var child = spawn(node, [__filename, 'true'], opt);
child.on('exit', function(c) {
assert(!c);
child = spawn(node, [__filename, 'false'], opt);
child.on('exit', function(c) {
assert(!c);
console.log('ok');
});
});
}
var gotDomain1Error = false; var gotDomain1Error = false;
var gotDomain2Error = false; var gotDomain2Error = false;
@ -44,8 +72,11 @@ function inner(throw1, throw2) {
var domain1 = domain.createDomain(); var domain1 = domain.createDomain();
domain1.on('error', function (err) { domain1.on('error', function (err) {
console.error('domain 1 error'); if (gotDomain1Error) {
if (gotDomain1Error) process.exit(1); console.error('got domain 1 twice');
process.exit(1);
}
if (dispose) domain1.dispose();
gotDomain1Error = true; gotDomain1Error = true;
throw2(); throw2();
}); });
@ -59,7 +90,10 @@ function outer() {
var domain2 = domain.createDomain(); var domain2 = domain.createDomain();
domain2.on('error', function (err) { domain2.on('error', function (err) {
console.error('domain 2 error'); if (gotDomain2Error) {
console.error('got domain 2 twice');
process.exit(1);
}
gotDomain2Error = true; gotDomain2Error = true;
}); });
@ -73,7 +107,7 @@ process.on('exit', function() {
assert(gotDomain2Error); assert(gotDomain2Error);
assert(threw1); assert(threw1);
assert(threw2); assert(threw2);
console.log('ok'); console.log('ok', dispose);
}); });
outer(); outer();

42
test/simple/test-event-emitter-no-error-provided-to-error-event.js

@ -0,0 +1,42 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var events = require('events');
var domain = require('domain');
var errorCatched = false;
var e = new events.EventEmitter();
var d = domain.create();
d.add(e);
d.on('error', function (er) {
assert(er instanceof TypeError, 'type error created');
errorCatched = true;
});
e.emit('error');
process.on('exit', function () {
assert(errorCatched, 'error got catched');
});

11
test/simple/test-fs-readfile-error.js

@ -28,7 +28,7 @@ var callbacks = 0;
function test(env, cb) { function test(env, cb) {
var filename = path.join(common.fixturesDir, 'test-fs-readfile-error.js'); var filename = path.join(common.fixturesDir, 'test-fs-readfile-error.js');
var execPath = process.execPath + ' ' + filename; var execPath = process.execPath + ' --throw-deprecation ' + filename;
var options = { env: env || {} }; var options = { env: env || {} };
exec(execPath, options, function(err, stdout, stderr) { exec(execPath, options, function(err, stdout, stderr) {
assert(err); assert(err);
@ -53,3 +53,12 @@ test({ NODE_DEBUG: 'fs' }, function(data) {
process.on('exit', function() { process.on('exit', function() {
assert.equal(callbacks, 2); assert.equal(callbacks, 2);
}); });
(function() {
console.error('the warnings are normal here.');
// just make sure that this doesn't crash the process.
var fs = require('fs');
fs.readFile(__dirname);
fs.readdir(__filename);
fs.unlink('gee-i-sure-hope-this-file-isnt-important-or-existing');
})();

1
test/simple/test-http-allow-req-after-204-res.js

@ -58,6 +58,7 @@ function nextRequest() {
//process.nextTick(nextRequest); //process.nextTick(nextRequest);
} }
}); });
response.resume();
}); });
request.end(); request.end();
} }

1
test/simple/test-http-client-response-domain.js

@ -60,6 +60,7 @@ function test() {
res.on('end', function() { res.on('end', function() {
res.emit('error', new Error('should be caught by domain')); res.emit('error', new Error('should be caught by domain'));
}); });
res.resume();
}); });
req.end(); req.end();
} }

1
test/simple/test-http-contentLength0.js

@ -36,6 +36,7 @@ s.listen(common.PORT, function() {
var request = http.request({ port: common.PORT }, function(response) { var request = http.request({ port: common.PORT }, function(response) {
console.log('STATUS: ' + response.statusCode); console.log('STATUS: ' + response.statusCode);
s.close(); s.close();
response.resume();
}); });
request.end(); request.end();

1
test/simple/test-http-head-request.js

@ -47,6 +47,7 @@ server.listen(common.PORT, function() {
common.error('response end'); common.error('response end');
gotEnd = true; gotEnd = true;
}); });
response.resume();
}); });
request.end(); request.end();
}); });

1
test/simple/test-http-head-response-has-no-body-end.js

@ -51,6 +51,7 @@ server.on('listening', function() {
server.close(); server.close();
responseComplete = true; responseComplete = true;
}); });
res.resume();
}); });
common.error('req'); common.error('req');
req.end(); req.end();

1
test/simple/test-http-head-response-has-no-body.js

@ -48,6 +48,7 @@ server.on('listening', function() {
server.close(); server.close();
responseComplete = true; responseComplete = true;
}); });
res.resume();
}); });
common.error('req'); common.error('req');
req.end(); req.end();

1
test/simple/test-http-legacy.js

@ -61,6 +61,7 @@ var server = http.createServer(function(req, res) {
res.end(); res.end();
responses_sent += 1; responses_sent += 1;
}); });
req.resume();
//assert.equal('127.0.0.1', res.connection.remoteAddress); //assert.equal('127.0.0.1', res.connection.remoteAddress);
}); });

1
test/simple/test-http-max-headers-count.js

@ -75,6 +75,7 @@ server.listen(common.PORT, function() {
server.close(); server.close();
} }
}); });
res.resume();
}); });
req.maxHeadersCount = max; req.maxHeadersCount = max;
req.end(); req.end();

1
test/simple/test-http-pipe-fs.js

@ -54,6 +54,7 @@ var server = http.createServer(function(req, res) {
server.close(); server.close();
} }
}); });
res.resume();
}); });
req.on('socket', function(s) { req.on('socket', function(s) {
common.debug('req' + i + ' start'); common.debug('req' + i + ' start');

86
test/simple/test-http-set-timeout-server.js

@ -22,6 +22,7 @@
var common = require('../common.js'); var common = require('../common.js');
var assert = require('assert'); var assert = require('assert');
var http = require('http'); var http = require('http');
var net = require('net');
var tests = []; var tests = [];
@ -73,7 +74,10 @@ test(function serverRequestTimeout(cb) {
}); });
}); });
server.listen(common.PORT); server.listen(common.PORT);
http.get({ port: common.PORT }).on('error', function() {}); var req = http.request({ port: common.PORT, method: 'POST' });
req.on('error', function() {});
req.write('Hello');
// req is in progress
}); });
test(function serverResponseTimeout(cb) { test(function serverResponseTimeout(cb) {
@ -93,3 +97,83 @@ test(function serverResponseTimeout(cb) {
server.listen(common.PORT); server.listen(common.PORT);
http.get({ port: common.PORT }).on('error', function() {}); http.get({ port: common.PORT }).on('error', function() {});
}); });
test(function serverRequestNotTimeoutAfterEnd(cb) {
var caughtTimeoutOnRequest = false;
var caughtTimeoutOnResponse = false;
process.on('exit', function() {
assert(!caughtTimeoutOnRequest);
assert(caughtTimeoutOnResponse);
});
var server = http.createServer(function(req, res) {
// just do nothing, we should get a timeout event.
req.setTimeout(50, function(socket) {
caughtTimeoutOnRequest = true;
});
res.on('timeout', function(socket) {
caughtTimeoutOnResponse = true;
});
});
server.on('timeout', function(socket) {
socket.destroy();
server.close();
cb();
});
server.listen(common.PORT);
http.get({ port: common.PORT }).on('error', function() {});
});
test(function serverResponseTimeoutWithPipeline(cb) {
var caughtTimeout = '';
process.on('exit', function() {
assert.equal(caughtTimeout, '/2');
});
var server = http.createServer(function(req, res) {
res.setTimeout(50, function() {
caughtTimeout += req.url;
});
if (req.url === '/1') res.end();
});
server.on('timeout', function(socket) {
socket.destroy();
server.close();
cb();
});
server.listen(common.PORT);
var c = net.connect({ port: common.PORT, allowHalfOpen: true }, function() {
c.write('GET /1 HTTP/1.1\r\nHost: localhost\r\n\r\n');
c.write('GET /2 HTTP/1.1\r\nHost: localhost\r\n\r\n');
c.write('GET /3 HTTP/1.1\r\nHost: localhost\r\n\r\n');
});
});
test(function idleTimeout(cb) {
var caughtTimeoutOnRequest = false;
var caughtTimeoutOnResponse = false;
var caughtTimeoutOnServer = false;
process.on('exit', function() {
assert(!caughtTimeoutOnRequest);
assert(!caughtTimeoutOnResponse);
assert(caughtTimeoutOnServer);
});
var server = http.createServer(function(req, res) {
req.on('timeout', function(socket) {
caughtTimeoutOnRequest = true;
});
res.on('timeout', function(socket) {
caughtTimeoutOnResponse = true;
});
res.end();
});
server.setTimeout(50, function(socket) {
caughtTimeoutOnServer = true;
socket.destroy();
server.close();
cb();
});
server.listen(common.PORT);
var c = net.connect({ port: common.PORT, allowHalfOpen: true }, function() {
c.write('GET /1 HTTP/1.1\r\nHost: localhost\r\n\r\n');
// Keep-Alive
});
});

1
test/simple/test-http-should-keep-alive.js

@ -59,6 +59,7 @@ var server = net.createServer(function(socket) {
} else { } else {
server.close(); server.close();
} }
res.resume();
}); });
} }

1
test/simple/test-http.js

@ -58,6 +58,7 @@ var server = http.Server(function(req, res) {
res.end(); res.end();
responses_sent += 1; responses_sent += 1;
}); });
req.resume();
//assert.equal('127.0.0.1', res.connection.remoteAddress); //assert.equal('127.0.0.1', res.connection.remoteAddress);
}); });

3
test/simple/test-https-client-reject.js

@ -41,6 +41,7 @@ var server = https.createServer(options, function(req, res) {
++reqCount; ++reqCount;
res.writeHead(200); res.writeHead(200);
res.end(); res.end();
req.resume();
}).listen(common.PORT, function() { }).listen(common.PORT, function() {
unauthorized(); unauthorized();
}); });
@ -51,6 +52,7 @@ function unauthorized() {
rejectUnauthorized: false rejectUnauthorized: false
}, function(res) { }, function(res) {
assert(!req.socket.authorized); assert(!req.socket.authorized);
res.resume();
rejectUnauthorized(); rejectUnauthorized();
}); });
req.on('error', function(err) { req.on('error', function(err) {
@ -80,6 +82,7 @@ function authorized() {
}; };
options.agent = new https.Agent(options); options.agent = new https.Agent(options);
var req = https.request(options, function(res) { var req = https.request(options, function(res) {
res.resume();
assert(req.socket.authorized); assert(req.socket.authorized);
server.close(); server.close();
}); });

62
test/simple/test-regress-GH-4948.js

@ -0,0 +1,62 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// https://github.com/joyent/node/issues/4948
var common = require('../common');
var http = require('http');
var reqCount = 0;
var server = http.createServer(function(serverReq, serverRes){
if (reqCount) {
serverRes.end();
server.close();
return;
}
reqCount = 1;
// normally the use case would be to call an external site
// does not require connecting locally or to itself to fail
var r = http.request({hostname: 'localhost', port: common.PORT}, function(res) {
// required, just needs to be in the client response somewhere
serverRes.end();
// required for test to fail
res.on('data', function(data) { });
});
r.on('error', function(e) {});
r.end();
serverRes.write('some data');
}).listen(common.PORT);
// simulate a client request that closes early
var net = require('net');
var sock = new net.Socket();
sock.connect(common.PORT, 'localhost');
sock.on('connect', function() {
sock.write('GET / HTTP/1.1\r\n\r\n');
sock.end();
});

86
test/simple/test-stream-pipe-after-end.js

@ -0,0 +1,86 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var common = require('../common');
var assert = require('assert');
var Readable = require('_stream_readable');
var Writable = require('_stream_writable');
var util = require('util');
util.inherits(TestReadable, Readable);
function TestReadable(opt) {
if (!(this instanceof TestReadable))
return new TestReadable(opt);
Readable.call(this, opt);
this._ended = false;
}
TestReadable.prototype._read = function(n) {
if (this._ended)
this.emit('error', new Error('_read called twice'));
this._ended = true;
this.push(null);
};
util.inherits(TestWritable, Writable);
function TestWritable(opt) {
if (!(this instanceof TestWritable))
return new TestWritable(opt);
Writable.call(this, opt);
this._written = [];
}
TestWritable.prototype._write = function(chunk, encoding, cb) {
this._written.push(chunk);
cb();
};
// this one should not emit 'end' until we read() from it later.
var ender = new TestReadable();
var enderEnded = false;
// what happens when you pipe() a Readable that's already ended?
var piper = new TestReadable();
// pushes EOF null, and length=0, so this will trigger 'end'
piper.read();
setTimeout(function() {
ender.on('end', function() {
enderEnded = true;
});
assert(!enderEnded);
var c = ender.read();
assert.equal(c, null);
var w = new TestWritable();
var writableFinished = false;
w.on('finish', function() {
writableFinished = true;
});
piper.pipe(w);
process.on('exit', function() {
assert(enderEnded);
assert(writableFinished);
console.log('ok');
});
});

15
test/simple/test-stream2-unpipe-leak.js

@ -24,6 +24,8 @@ var common = require('../common.js');
var assert = require('assert'); var assert = require('assert');
var stream = require('stream'); var stream = require('stream');
var chunk = new Buffer('hallo');
var util = require('util'); var util = require('util');
function TestWriter() { function TestWriter() {
@ -37,13 +39,15 @@ TestWriter.prototype._write = function(buffer, encoding, callback) {
var dest = new TestWriter(); var dest = new TestWriter();
// Set this high so that we'd trigger a nextTick warning
// and/or RangeError if we do maybeReadMore wrong.
function TestReader() { function TestReader() {
stream.Readable.call(this); stream.Readable.call(this, { highWaterMark: 0x10000 });
} }
util.inherits(TestReader, stream.Readable); util.inherits(TestReader, stream.Readable);
TestReader.prototype._read = function(size) { TestReader.prototype._read = function(size) {
this.push(new Buffer('hallo')); this.push(chunk);
}; };
var src = new TestReader(); var src = new TestReader();
@ -61,3 +65,10 @@ assert.equal(dest.listeners('drain').length, 0);
assert.equal(dest.listeners('error').length, 0); assert.equal(dest.listeners('error').length, 0);
assert.equal(dest.listeners('close').length, 0); assert.equal(dest.listeners('close').length, 0);
assert.equal(dest.listeners('finish').length, 0); assert.equal(dest.listeners('finish').length, 0);
console.error(src._readableState);
process.on('exit', function() {
assert(src._readableState.length >= src._readableState.highWaterMark);
src._readableState.buffer.length = 0;
console.error(src._readableState);
});

64
test/simple/test-timers-this.js

@ -0,0 +1,64 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var assert = require('assert');
var immediateThis, intervalThis, timeoutThis,
immediateArgsThis, intervalArgsThis, timeoutArgsThis;
var immediateHandler = setImmediate(function () {
immediateThis = this;
});
var immediateArgsHandler = setImmediate(function () {
immediateArgsThis = this;
}, "args ...");
var intervalHandler = setInterval(function () {
clearInterval(intervalHandler);
intervalThis = this;
});
var intervalArgsHandler = setInterval(function () {
clearInterval(intervalArgsHandler);
intervalArgsThis = this;
}, 0, "args ...");
var timeoutHandler = setTimeout(function () {
timeoutThis = this;
});
var timeoutArgsHandler = setTimeout(function () {
timeoutArgsThis = this;
}, 0, "args ...");
process.once('exit', function () {
assert.strictEqual(immediateThis, immediateHandler);
assert.strictEqual(immediateArgsThis, immediateArgsHandler);
assert.strictEqual(intervalThis, intervalHandler);
assert.strictEqual(intervalArgsThis, intervalArgsHandler);
assert.strictEqual(timeoutThis, timeoutHandler);
assert.strictEqual(timeoutArgsThis, timeoutArgsHandler);
});

14
tools/msvs/msi/product.wxs

@ -65,8 +65,8 @@
<Feature Id="npm" <Feature Id="npm"
Level="1" Level="1"
Title="NPM package manager" Title="npm package manager"
Description="Install NPM, the recommended package manager for Node.js."> Description="Install npm, the recommended package manager for Node.js.">
<ComponentRef Id="NpmCmdScript"/> <ComponentRef Id="NpmCmdScript"/>
<ComponentRef Id="NpmBashScript"/> <ComponentRef Id="NpmBashScript"/>
<ComponentRef Id="NpmConfigurationFile"/> <ComponentRef Id="NpmConfigurationFile"/>
@ -83,18 +83,18 @@
<Feature Id="EnvironmentPath" <Feature Id="EnvironmentPath"
Level="1" Level="1"
Title="Add to PATH" Title="Add to PATH"
Description="Add Node, NPM, and modules that were globally installed by NPM to the PATH environment variable."> Description="Add Node, npm, and modules that were globally installed by npm to the PATH environment variable.">
<Feature Id="EnvironmentPathNode" <Feature Id="EnvironmentPathNode"
Level="1" Level="1"
Title="Node and NPM" Title="Node and npm"
Description="Add Node and NPM (if installed) to the PATH environment variable."> Description="Add Node and npm (if installed) to the PATH environment variable.">
<ComponentRef Id="EnvironmentPathNode"/> <ComponentRef Id="EnvironmentPathNode"/>
</Feature> </Feature>
<Feature Id="EnvironmentPathNpmModules" <Feature Id="EnvironmentPathNpmModules"
Level="1" Level="1"
Title="NPM modules" Title="npm modules"
Description="Add modules that are installed globablly by NPM to the PATH environment variable. This option works for the current user only; other users need to update their PATH manually."> Description="Add modules that are installed globally by npm to the PATH environment variable. This option works for the current user only; other users need to update their PATH manually.">
<ComponentRef Id="EnvironmentPathNpmModules"/> <ComponentRef Id="EnvironmentPathNpmModules"/>
</Feature> </Feature>
</Feature> </Feature>

4
tools/msvs/nodevars.bat

@ -1,6 +1,6 @@
@echo off @echo off
rem Ensure this Node.js and NPM are first in the PATH rem Ensure this Node.js and npm are first in the PATH
set PATH=%APPDATA%\npm;%~dp0;%PATH% set PATH=%APPDATA%\npm;%~dp0;%PATH%
setlocal enabledelayedexpansion setlocal enabledelayedexpansion
@ -12,7 +12,7 @@ for /F "usebackq delims=" %%v in (`%print_version%`) do set version=%%v
rem Print message. rem Print message.
if exist npm.cmd ( if exist npm.cmd (
echo Your environment has been set up for using Node.js !version! and NPM. echo Your environment has been set up for using Node.js !version! and npm.
) else ( ) else (
echo Your environment has been set up for using Node.js !version!. echo Your environment has been set up for using Node.js !version!.
) )

Loading…
Cancel
Save