@@ -434,6 +434,8 @@ See also: `child_process.exec()` and `child_process.fork()`
* `options` {Object}
* `cwd` {String} Current working directory of the child process
* `stdio` {Array|String} Child's stdio configuration. (See above)
Only stdin is configurable, anything else will lead to unpredictable
results.
* `customFds` {Array} **Deprecated** File descriptors for the child to use
for stdio. (See above)
* `env` {Object} Environment key-value pairs
@@ -159,7 +159,7 @@ associated with each `REPLServer`. For example:
var repl = require("repl"),
msg = "message";

repl.start().context.m = msg;
repl.start("> ").context.m = msg;

Things in the `context` object appear as local within the REPL:

@@ -0,0 +1,134 @@
category: npm
title: Peer Dependencies
date: 2013-02-08T00:00:00Z
author: Domenic Denicola
slug: peer-dependencies

<i>Reposted from [Domenic's
blog](http://domenic.me/2013/02/08/peer-dependencies/) with
permission. Thanks!</i>

npm is awesome as a package manager. In particular, it handles sub-dependencies very well: if my package depends on
`request` version 2 and `some-other-library`, but `some-other-library` depends on `request` version 1, the resulting
dependency graph looks like:

```text
├── request@2.12.0
└─┬ some-other-library@1.2.3
└── request@1.9.9
```

This is, generally, great: now `some-other-library` has its own copy of `request` v1 that it can use, while not
interfering with my package's v2 copy. Everyone's code works!

## The Problem: Plugins

There's one use case where this falls down, however: *plugins*. A plugin package is meant to be used with another "host"
package, even though it does not always directly *use* the host package. There are many examples of this pattern in the
Node.js package ecosystem already:

- Grunt [plugins](http://gruntjs.com/#plugins-all)
- Chai [plugins](http://chaijs.com/plugins)
- Levelup [plugins](https://npmjs.org/package/level-hooks)
- Express [middleware](http://expressjs.com/api.html#middleware)
- Winston [transports](https://github.com/flatiron/winston/blob/master/docs/transports.md)

Even if you're not familiar with any of those use cases, surely you recall "jQuery plugins" from back when you were a
client-side developer: little `<script>`s you would drop into your page that would attach things to `jQuery.prototype`
for your later convenience.

In essence, plugins are designed to be used with host packages. But more importantly, they're designed to be used with
*particular versions* of host packages. For example, versions 1.x and 2.x of my `chai-as-promised` plugin work with
`chai` version 0.5, whereas versions 3.x work with `chai` 1.x. Or, in the faster-paced and less-semver–friendly world of
Grunt plugins, version 0.3.1 of `grunt-contrib-stylus` works with `grunt` 0.4.0rc4, but breaks when used with `grunt`
0.4.0rc5 due to removed APIs.

As a package manager, a large part of npm's job when installing your dependencies is managing their versions. But its
usual model, with a `"dependencies"` hash in `package.json`, clearly falls down for plugins. Most plugins never actually
depend on their host package, i.e. grunt plugins never do `require("grunt")`, so even if plugins did put down their host
package as a dependency, the downloaded copy would never be used. So we'd be back to square one, with your application
possibly plugging in the plugin to a host package that it's incompatible with.

Even for plugins that do have such direct dependencies, probably due to the host package supplying utility APIs,
specifying the dependency in the plugin's `package.json` would result in a dependency tree with multiple copies of the
host package—not what you want. For example, let's pretend that `winston-mail` 0.2.3 specified `"winston": "0.5.x"` in
its `"dependencies"` hash, since that's the latest version it was tested against. As an app developer, you want the
latest and greatest stuff, so you look up the latest versions of `winston` and of `winston-mail`, putting them in your
`package.json` as

```json
{
"dependencies": {
"winston": "0.6.2",
"winston-mail": "0.2.3"
}
}
```

But now, running `npm install` results in the unexpected dependency graph of

```text
├── winston@0.6.2
└─┬ winston-mail@0.2.3
└── winston@0.5.11
```

I'll leave the subtle failures that come from the plugin using a different Winston API than the main application to
your imagination.

## The Solution: Peer Dependencies

What we need is a way of expressing these "dependencies" between plugins and their host package. Some way of saying, "I
only work when plugged in to version 1.2.x of my host package, so if you install me, be sure that it's alongside a
compatible host." We call this relationship a *peer dependency*.

The peer dependency idea has been kicked around for [literally](https://github.com/isaacs/npm/issues/930)
[years](https://github.com/isaacs/npm/issues/1400). After
[volunteering](https://github.com/isaacs/npm/issues/1400#issuecomment-5932027) to get this done "over the weekend" nine
months ago, I finally found a free weekend, and now peer dependencies are in npm!

Specifically, they were introduced in a rudimentary form in npm 1.2.0, and refined over the next few releases into
something I'm actually happy with. Today Isaac packaged up npm 1.2.10 into
[Node.js 0.8.19](http://blog.nodejs.org/2013/02/06/node-v0-8-19-stable/), so if you've installed the latest version of
Node, you should be ready to use peer dependencies!

As proof, I present you the results of trying to install [`jitsu`](https://npmjs.org/package/jitsu) 0.11.6 with npm
1.2.10:

```text
npm ERR! peerinvalid The package flatiron does not satisfy its siblings' peerDependencies requirements!
npm ERR! peerinvalid Peer flatiron-cli-config@0.1.3 wants flatiron@~0.1.9
npm ERR! peerinvalid Peer flatiron-cli-users@0.1.4 wants flatiron@~0.3.0
```

As you can see, `jitsu` depends on two Flatiron-related packages, which themselves peer-depend on conflicting versions
of Flatiron. Good thing npm was around to help us figure out this conflict, so it could be fixed in version 0.11.7!

## Using Peer Dependencies

Peer dependencies are pretty simple to use. When writing a plugin, figure out what version of the host package you
peer-depend on, and add it to your `package.json`:

```json
{
"name": "chai-as-promised",
"peerDependencies": {
"chai": "1.x"
}
}
```

Now, when installing `chai-as-promised`, the `chai` package will come along with it. And if later you try to install
another Chai plugin that only works with 0.x versions of Chai, you'll get an error. Nice!

One piece of advice: peer dependency requirements, unlike those for regular dependencies, *should be lenient*. You
should not lock your peer dependencies down to specific patch versions. It would be really annoying if one Chai plugin
peer-depended on Chai 1.4.1, while another depended on Chai 1.5.0, simply because the authors were lazy and didn't spend
the time figuring out the actual minimum version of Chai they are compatible with.

The best way to determine what your peer dependency requirements should be is to actually follow
[semver](http://semver.org/). Assume that only changes in the host package's major version will break your plugin. Thus,
if you've worked with every 1.x version of the host package, use `"~1.0"` or `"1.x"` to express this. If you depend on
features introduced in 1.5.2, use `">= 1.5.2 < 2"`.

Now go forth, and peer depend!
@@ -0,0 +1,62 @@
title: Node v0.8.20 (Stable)
slug: node-v0-8-20-stable
category: release
date: Fri Feb 15 11:21:42 PST 2013
version: 0.8.20

2013.02.15, Version 0.8.20 (Stable)

* npm: Upgrade to v1.2.11

* http: Do not let Agent hand out destroyed sockets (isaacs)

* http: Raise hangup error on destroyed socket write (isaacs)

* http: protect against response splitting attacks (Bert Belder)


Source Code: http://nodejs.org/dist/v0.8.20/node-v0.8.20.tar.gz

Macintosh Installer (Universal): http://nodejs.org/dist/v0.8.20/node-v0.8.20.pkg

Windows Installer: http://nodejs.org/dist/v0.8.20/node-v0.8.20-x86.msi

Windows x64 Installer: http://nodejs.org/dist/v0.8.20/x64/node-v0.8.20-x64.msi

Windows x64 Files: http://nodejs.org/dist/v0.8.20/x64/

Linux 32-bit Binary: http://nodejs.org/dist/v0.8.20/node-v0.8.20-linux-x86.tar.gz

Linux 64-bit Binary: http://nodejs.org/dist/v0.8.20/node-v0.8.20-linux-x64.tar.gz

Solaris 32-bit Binary: http://nodejs.org/dist/v0.8.20/node-v0.8.20-sunos-x86.tar.gz

Solaris 64-bit Binary: http://nodejs.org/dist/v0.8.20/node-v0.8.20-sunos-x64.tar.gz

Other release files: http://nodejs.org/dist/v0.8.20/

Website: http://nodejs.org/docs/v0.8.20/

Documentation: http://nodejs.org/docs/v0.8.20/api/

Shasums:
```
2b87bf077022b8fa1cbcec10ea3866574fed2b75 node-v0.8.20-darwin-x64.tar.gz
42023ffbdbf36ef69250bd750f112e684eb97008 node-v0.8.20-darwin-x86.tar.gz
93480cbc67f2c757879228434bce1fd765db7df8 node-v0.8.20-linux-x64.tar.gz
7fedae5ce4b366d5dcaa7f2e770b3ff739648a51 node-v0.8.20-linux-x86.tar.gz
fd66ea1bfbe5c8fe8df5ba8cc79cd3fab6e753ac node-v0.8.20-sunos-x64.tar.gz
ca6ad9aa92330358f6201191347451ab42fe12cf node-v0.8.20-sunos-x86.tar.gz
200ff5e5083df2a6bb4552e673d81b498e9812f0 node-v0.8.20-x86.msi
54440b1f525da0126b434440ee6433c2b96959ae node-v0.8.20.pkg
b780f58f0e3bc43d2380d4a935f2b45350783b37 node-v0.8.20.tar.gz
8e13b125c3572a1cb46364b3241405cdf7af1a82 node.exe
f67ea64d6686207dbacb9bb8feacce3ac8899ec8 node.exp
c338212caf48d945e8e8049c2a0c30e38e8730d6 node.lib
019b24c60cdb03f9d8209290e7af90e8565999e7 node.pdb
67fff498c5271033073a3ca9fc01178b5f5c309a x64/node-v0.8.20-x64.msi
6ecab177a47ff5c74397799b329c2359b40c7d1f x64/node.exe
bcd51345c05a28be5db3553fc578aa3dd52fc97e x64/node.exp
825f2ba0bb9d7bd170adef89009b84ee147754e5 x64/node.lib
50c4cc483cc4b675966c7ec524afacb59ff99164 x64/node.pdb
```
@@ -0,0 +1,78 @@
date: Thu Feb 7 10:32:17 PST 2013
title: Node v0.9.9 (Unstable)
version: 0.9.9
category: release
slug: node-v0-9-9-unstable

2013.02.07, Version 0.9.9 (Unstable)

* tls: port CryptoStream to streams2 (Fedor Indutny)

* typed arrays: only share ArrayBuffer backing store (Ben Noordhuis)

* stream: make Writable#end() accept a callback function (Nathan Rajlich)

* buffer: optimize 'hex' handling (Ben Noordhuis)

* dns, cares: don't filter NOTIMP, REFUSED, SERVFAIL (Ben Noordhuis)

* readline: treat bare \r as a line ending (isaacs)

* readline: make \r\n emit one 'line' event (Ben Noordhuis)

* cluster: support datagram sockets (Bert Belder)

* stream: Correct Transform class backpressure (isaacs)

* addon: Pass module object to NODE_MODULE init function (isaacs, Rod Vagg)

* buffer: slow buffer copy compatibility fix (Trevor Norris)

* Add bytesWritten to tls.CryptoStream (Andy Burke)


Source Code: http://nodejs.org/dist/v0.9.9/node-v0.9.9.tar.gz

Macintosh Installer (Universal): http://nodejs.org/dist/v0.9.9/node-v0.9.9.pkg

Windows Installer: http://nodejs.org/dist/v0.9.9/node-v0.9.9-x86.msi

Windows x64 Installer: http://nodejs.org/dist/v0.9.9/x64/node-v0.9.9-x64.msi

Windows x64 Files: http://nodejs.org/dist/v0.9.9/x64/

Linux 32-bit Binary: http://nodejs.org/dist/v0.9.9/node-v0.9.9-linux-x86.tar.gz

Linux 64-bit Binary: http://nodejs.org/dist/v0.9.9/node-v0.9.9-linux-x64.tar.gz

Solaris 32-bit Binary: http://nodejs.org/dist/v0.9.9/node-v0.9.9-sunos-x86.tar.gz

Solaris 64-bit Binary: http://nodejs.org/dist/v0.9.9/node-v0.9.9-sunos-x64.tar.gz

Other release files: http://nodejs.org/dist/v0.9.9/

Website: http://nodejs.org/docs/v0.9.9/

Documentation: http://nodejs.org/docs/v0.9.9/api/

Shasums:
```
643c26c2fc0c9ddeee99d346af86a022e6b470bc node-v0.9.9-darwin-x64.tar.gz
f3ffeb08ceab15fd24a33c8d1974be952177b623 node-v0.9.9-darwin-x86.tar.gz
63d6ce5e4333a0cd203753a3153998076baa23a7 node-v0.9.9-linux-x64.tar.gz
f1008b823b6010bd3ed3fd4f422eac3af5bd61da node-v0.9.9-linux-x86.tar.gz
679b09328f1a0c3225286a891bb5b4de131777d6 node-v0.9.9-sunos-x64.tar.gz
4253f2e976a05ee6ea6ecc3b583e942b812d0b86 node-v0.9.9-sunos-x86.tar.gz
0436ee0e57d12d5fc53914f9157521427d016629 node-v0.9.9-x86.msi
8a98bc39e9c99a1a1dad6f38a47f56eeb9ad6ecd node-v0.9.9.pkg
af1deb80c79f256b319a727f8593740ff99cdbc8 node-v0.9.9.tar.gz
ab3db4d6ffab88bb1babdddd96ca8d2c6caf4625 node.exe
56f5a3c72992463435f6649b31da81fd679e91ae node.exp
e77f0097ce66317fc255b8e1642eaa675c190267 node.lib
5ff7b6d7f1001383b4bd97e1315c67e7b223477d node.pdb
5b4dcf545eace51a4cae58e9c42b73604f6eb0f9 x64/node-v0.9.9-x64.msi
43fd59cf0df5bdf21690a43a68a8f16160e28ec6 x64/node.exe
b4845d2318dd5b1030eeca02703d7f19ebf2ef15 x64/node.exp
2726441e5ff354bc51a841fa9a5a193d39831ac0 x64/node.lib
df9083c37cf13109326df30df01e9692238ac381 x64/node.pdb
```
@@ -474,7 +474,8 @@ OutgoingMessage.prototype._writeRaw = function(data, encoding) {

if (this.connection &&
this.connection._httpMessage === this &&
this.connection.writable) {
this.connection.writable &&
!this.connection.destroyed) {
// There might be pending data in the this.output buffer.
while (this.output.length) {
if (!this.connection.writable) {
@@ -488,7 +489,16 @@ OutgoingMessage.prototype._writeRaw = function(data, encoding) {

// Directly write to socket.
return this.connection.write(data, encoding);
} else if (this.connection && this.connection.destroyed) {
// The socket was destroyed. If we're still trying to write to it,
// then something bad happened.
// If we've already raised an error on this message, then just ignore.
if (!this._hadError) {
this.emit('error', createHangUpError());
this._hadError = true;
}
} else {
// buffer, as long as we're not destroyed.
this._buffer(data, encoding);
return false;
}
@@ -1142,7 +1152,8 @@ function Agent(options) {
name += ':' + localAddress;
}

if (self.requests[name] && self.requests[name].length) {
if (!socket.destroyed &&
self.requests[name] && self.requests[name].length) {
self.requests[name].shift().onSocket(socket);
if (self.requests[name].length === 0) {
// don't leak
@@ -1418,8 +1429,17 @@ function socketCloseListener() {
// receive a response. The error needs to
// fire on the request.
req.emit('error', createHangUpError());
req._hadError = true;
}

// Too bad. That output wasn't getting written.
// This is pretty terrible that it doesn't raise an error.
// Fixed better in v0.10
if (req.output)
req.output.length = 0;
if (req.outputEncodings)
req.outputEncodings.length = 0;

if (parser) {
parser.finish();
freeParser(parser, req);
File renamed without changes.
@@ -0,0 +1,106 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var common = require('../common');
var assert = require('assert');
var http = require('http');

var server = http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(common.PORT);

var agent = new http.Agent({maxSockets: 1});

agent.on('free', function(socket, host, port) {
console.log('freeing socket. destroyed? ', socket.destroyed);
});

var requestOptions = {
agent: agent,
host: 'localhost',
port: common.PORT,
path: '/'
};

var request1 = http.get(requestOptions, function(response) {
// assert request2 is queued in the agent
var key = 'localhost:' + common.PORT;
assert(agent.requests[key].length === 1);
console.log('got response1');
request1.socket.on('close', function() {
console.log('request1 socket closed');
});
response.pipe(process.stdout);
response.on('end', function() {
console.log('response1 done');
/////////////////////////////////
//
// THE IMPORTANT PART
//
// It is possible for the socket to get destroyed and other work
// to run before the 'close' event fires because it happens on
// nextTick. This example is contrived because it destroys the
// socket manually at just the right time, but at Voxer we have
// seen cases where the socket is destroyed by non-user code
// then handed out again by an agent *before* the 'close' event
// is triggered.
request1.socket.destroy();

process.nextTick(function() {
// assert request2 was removed from the queue
assert(!agent.requests[key]);
console.log("waiting for request2.onSocket's nextTick");
process.nextTick(function() {
// assert that the same socket was not assigned to request2,
// since it was destroyed.
assert(request1.socket !== request2.socket);
assert(!request2.socket.destroyed, 'the socket is destroyed');
});
});
});
});

var request2 = http.get(requestOptions, function(response) {
assert(!request2.socket.destroyed);
assert(request1.socket.destroyed);
// assert not reusing the same socket, since it was destroyed.
assert(request1.socket !== request2.socket);
console.log('got response2');
var gotClose = false;
var gotResponseEnd = false;
request2.socket.on('close', function() {
console.log('request2 socket closed');
gotClose = true;
done();
});
response.pipe(process.stdout);
response.on('end', function() {
console.log('response2 done');
gotResponseEnd = true;
done();
});

function done() {
if (gotResponseEnd && gotClose)
server.close();
}
});
@@ -0,0 +1,131 @@
// 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');

// Fix the memory explosion that happens when writing to a http request
// where the server has destroyed the socket on us between a successful
// first request, and a subsequent request that reuses the socket.
//
// This test should not be ported to v0.10 and higher, because the
// problem is fixed by not ignoring ECONNRESET in the first place.

var http = require('http');
var net = require('net');
var server = http.createServer(function(req, res) {
// simulate a server that is in the process of crashing or something
// it only crashes after the first request, but before the second,
// which reuses the connection.
res.end('hallo wereld\n', function() {
setTimeout(function() {
req.connection.destroy();
}, 100);
});
});

var gotFirstResponse = false;
var gotFirstData = false;
var gotFirstEnd = false;
server.listen(common.PORT, function() {

var gotFirstResponse = false;
var first = http.request({
port: common.PORT,
path: '/'
});
first.on('response', function(res) {
gotFirstResponse = true;
res.on('data', function(chunk) {
gotFirstData = true;
});
res.on('end', function() {
gotFirstEnd = true;
})
});
first.end();
second();

function second() {
var sec = http.request({
port: common.PORT,
path: '/',
method: 'POST'
});

var timer = setTimeout(write, 200);
var writes = 0;
var sawFalseWrite;

var gotError = false;
sec.on('error', function(er) {
assert.equal(gotError, false);
gotError = true;
assert(er.code === 'ECONNRESET');
clearTimeout(timer);
test();
});

function write() {
if (++writes === 64) {
clearTimeout(timer);
sec.end();
test();
} else {
timer = setTimeout(write);
var writeRet = sec.write(new Buffer('hello'));

// Once we find out that the connection is destroyed, every
// write() returns false
if (sawFalseWrite)
assert.equal(writeRet, false);
else
sawFalseWrite = writeRet === false;
}
}

assert.equal(first.connection, sec.connection,
'should reuse connection');

sec.on('response', function(res) {
res.on('data', function(chunk) {
console.error('second saw data: ' + chunk);
});
res.on('end', function() {
console.error('second saw end');
});
});

function test() {
server.close();
assert(sec.connection.destroyed);
if (sec.output.length || sec.outputEncodings.length)
console.error('bad happened', sec.output, sec.outputEncodings);
assert.equal(sec.output.length, 0);
assert.equal(sec.outputEncodings, 0);
assert(gotError);
assert(gotFirstResponse);
assert(gotFirstData);
assert(gotFirstEnd);
console.log('ok');
}
}
});
@@ -27,7 +27,6 @@ var testIndex = 0,
responses = 0;

var server = http.createServer(function(req, res) {
console.error('request', testIndex);
switch (testIndex++) {
case 0:
res.writeHead(200, { test: 'foo \r\ninvalid: bar' });
@@ -42,7 +41,6 @@ var server = http.createServer(function(req, res) {
res.writeHead(200, { test: 'foo \n\n\ninvalid: bar' });
break;
case 4:
console.error('send request, then close');
res.writeHead(200, { test: 'foo \r\n \r\n \r\ninvalid: bar' });
server.close();
break;
@@ -51,6 +49,7 @@ var server = http.createServer(function(req, res) {
}
res.end('Hi mars!');
});

server.listen(common.PORT, function() {
for (var i = 0; i < 5; i++) {
var req = http.get({ port: common.PORT, path: '/' }, function(res) {