@@ -342,14 +342,14 @@ function chunkInvalid(state, chunk) {


function onEofChunk(stream, state) {
state.ended = true;
if (state.decoder) {
if (state.decoder && !state.ended) {
var chunk = state.decoder.end();
if (chunk && chunk.length) {
state.buffer.push(chunk);
state.length += state.objectMode ? 1 : chunk.length;
}
}
state.ended = true;

// if we've ended and we have some data left, then emit
// 'readable' now to make sure it gets picked up.
@@ -733,12 +733,12 @@ Readable.prototype.wrap = function(stream) {

var self = this;
stream.on('end', function() {
state.ended = true;
if (state.decoder) {
if (state.decoder && !state.ended) {
var chunk = state.decoder.end();
if (chunk && chunk.length)
self.push(chunk);
}
state.ended = true;

self.push(null);
});
@@ -777,10 +777,12 @@ Readable.prototype.wrap = function(stream) {
// underlying stream.
self._read = function(n) {
if (paused) {
stream.resume();
paused = false;
stream.resume();
}
};

return self;
};


@@ -150,15 +150,33 @@ exports.createCredentials = function(options, context) {
};


function LazyTransform(options) {
this._options = options;
}
util.inherits(LazyTransform, stream.Transform);

['read', 'write', 'end'].forEach(function(action, i, actions) {
LazyTransform.prototype[action] = function() {
stream.Transform.call(this, this._options);

actions.forEach(function(action) {
this[action] = stream.Transform.prototype[action];
}, this);

return this[action].apply(this, arguments);
};
});


exports.createHash = exports.Hash = Hash;
function Hash(algorithm, options) {
if (!(this instanceof Hash))
return new Hash(algorithm);
this._binding = new binding.Hash(algorithm);
stream.Transform.call(this, options);
LazyTransform.call(this, options);
}

util.inherits(Hash, stream.Transform);
util.inherits(Hash, LazyTransform);

Hash.prototype._transform = function(chunk, encoding, callback) {
this._binding.update(chunk, encoding);
@@ -194,10 +212,10 @@ function Hmac(hmac, key, options) {
return new Hmac(hmac, key);
this._binding = new binding.Hmac();
this._binding.init(hmac, toBuf(key));
stream.Transform.call(this, options);
LazyTransform.call(this, options);
}

util.inherits(Hmac, stream.Transform);
util.inherits(Hmac, LazyTransform);

Hmac.prototype.update = Hash.prototype.update;
Hmac.prototype.digest = Hash.prototype.digest;
@@ -221,10 +239,10 @@ function Cipher(cipher, password, options) {
this._binding.init(cipher, toBuf(password));
this._decoder = null;

stream.Transform.call(this, options);
LazyTransform.call(this, options);
}

util.inherits(Cipher, stream.Transform);
util.inherits(Cipher, LazyTransform);

Cipher.prototype._transform = function(chunk, encoding, callback) {
this.push(this._binding.update(chunk, encoding));
@@ -280,10 +298,10 @@ function Cipheriv(cipher, key, iv, options) {
this._binding.initiv(cipher, toBuf(key), toBuf(iv));
this._decoder = null;

stream.Transform.call(this, options);
LazyTransform.call(this, options);
}

util.inherits(Cipheriv, stream.Transform);
util.inherits(Cipheriv, LazyTransform);

Cipheriv.prototype._transform = Cipher.prototype._transform;
Cipheriv.prototype._flush = Cipher.prototype._flush;
@@ -302,10 +320,10 @@ function Decipher(cipher, password, options) {
this._binding.init(cipher, toBuf(password));
this._decoder = null;

stream.Transform.call(this, options);
LazyTransform.call(this, options);
}

util.inherits(Decipher, stream.Transform);
util.inherits(Decipher, LazyTransform);

Decipher.prototype._transform = Cipher.prototype._transform;
Decipher.prototype._flush = Cipher.prototype._flush;
@@ -325,10 +343,10 @@ function Decipheriv(cipher, key, iv, options) {
this._binding.initiv(cipher, toBuf(key), toBuf(iv));
this._decoder = null;

stream.Transform.call(this, options);
LazyTransform.call(this, options);
}

util.inherits(Decipheriv, stream.Transform);
util.inherits(Decipheriv, LazyTransform);

Decipheriv.prototype._transform = Cipher.prototype._transform;
Decipheriv.prototype._flush = Cipher.prototype._flush;
@@ -950,7 +950,7 @@ fs.writeFileSync = function(path, data, options) {
assertEncoding(options.encoding);

var flag = options.flag || 'w';
var fd = fs.openSync(path, flag);
var fd = fs.openSync(path, flag, options.mode);
if (!Buffer.isBuffer(data)) {
data = new Buffer('' + data, options.encoding || 'utf8');
}
@@ -855,6 +855,14 @@ OutgoingMessage.prototype.end = function(data, encoding) {
this.connection.writable &&
this.connection._httpMessage === this;

// The benefits of the hot-path optimization below start to fall
// off when the buffer size gets up near 128KB, because the cost
// of the copy is more than the cost of the extra write() call.
// Switch to the write/end method at that point. Heuristics and
// magic numbers are awful, but slow http responses are worse.
if (hot && Buffer.isBuffer(data) && data.length > 120 * 1024)
hot = false;

if (hot) {
// Hot path. They're doing
// res.writeHead();
@@ -42,6 +42,15 @@ function createTCP() {
}


function createHandle(fd) {
var tty = process.binding('tty_wrap');
var type = tty.guessHandleType(fd);
if (type === 'PIPE') return createPipe();
if (type === 'TCP') return createTCP();
throw new TypeError('Unsupported fd type: ' + type);
}


var debug;
if (process.env.NODE_DEBUG && /net/.test(process.env.NODE_DEBUG)) {
var pid = process.pid;
@@ -144,7 +153,7 @@ function Socket(options) {
if (options.handle) {
this._handle = options.handle; // private
} else if (typeof options.fd !== 'undefined') {
this._handle = createPipe();
this._handle = createHandle(options.fd);
this._handle.open(options.fd);
this.readable = options.readable !== false;
this.writable = options.writable !== false;
@@ -930,25 +939,18 @@ var createServerHandle = exports._createServerHandle =
var handle;

if (typeof fd === 'number' && fd >= 0) {
var tty_wrap = process.binding('tty_wrap');
var type = tty_wrap.guessHandleType(fd);
switch (type) {
case 'PIPE':
debug('listen pipe fd=' + fd);
// create a PipeWrap
handle = createPipe();
handle.open(fd);
handle.readable = true;
handle.writable = true;
break;

default:
// Not a fd we can listen on. This will trigger an error.
debug('listen invalid fd=' + fd + ' type=' + type);
process._errno = 'EINVAL'; // hack, callers expect that errno is set
handle = null;
break;
try {
handle = createHandle(fd);
}
catch (e) {
// Not a fd we can listen on. This will trigger an error.
debug('listen invalid fd=' + fd + ': ' + e.message);
process._errno = 'EINVAL'; // hack, callers expect that errno is set
return null;
}
handle.open(fd);
handle.readable = true;
handle.writable = true;
return handle;

} else if (port == -1 && addressType == -1) {
@@ -645,15 +645,18 @@ Object.defineProperty(CryptoStream.prototype, 'readyState', {
function CleartextStream(pair, options) {
CryptoStream.call(this, pair, options);

// This is a fake kludge to support how the http impl sits
// on top of net Sockets
var self = this;
this._handle = {
readStop: function() {
self._reading = false;
},
readStart: function() {
if (self._reading) return;
if (self._reading && self._readableState.length > 0) return;
self._reading = true;
self.read(0);
if (self._opposite.readable) self._opposite.read(0);
}
};
}
@@ -906,30 +909,25 @@ SecurePair.prototype.destroy = function() {


SecurePair.prototype.error = function() {
var err = this.ssl.error;
this.ssl.error = null;

if (!this._secureEstablished) {
var error = this.ssl.error;
if (!error) {
error = new Error('socket hang up');
error.code = 'ECONNRESET';
if (!err) {
err = new Error('socket hang up');
err.code = 'ECONNRESET';
}
this.destroy();
this.emit('error', error);
return error;
this.emit('error', err);
} else if (this._isServer &&
this._rejectUnauthorized &&
/peer did not return a certificate/.test(err.message)) {
// Not really an error.
this.destroy();
} else {
var err = this.ssl.error;
this.ssl.error = null;

if (this._isServer &&
this._rejectUnauthorized &&
/peer did not return a certificate/.test(err.message)) {
// Not really an error.
this.destroy();
} else {
this.cleartext.emit('error', err);
}

return err;
this.cleartext.emit('error', err);
}
return err;
};

// TODO: support anonymous (nocert) and PSK
@@ -901,9 +901,11 @@ Handle<Value> FromConstructorTemplate(Persistent<FunctionTemplate> t,

Handle<Value>
MakeDomainCallback(const Handle<Object> object,
const Handle<Function> callback,
int argc,
Handle<Value> argv[]) {
const Handle<Function> callback,
int argc,
Handle<Value> argv[]) {
// TODO Hook for long stack traces to be made here.

// lazy load _tickDomainCallback
if (process_tickDomainCallback.IsEmpty()) {
Local<Value> cb_v = process->Get(String::New("_tickDomainCallback"));
@@ -980,20 +982,11 @@ MakeDomainCallback(const Handle<Object> object,

Handle<Value>
MakeCallback(const Handle<Object> object,
const Handle<String> symbol,
const Handle<Function> callback,
int argc,
Handle<Value> argv[]) {
HandleScope scope(node_isolate);

Local<Function> callback = object->Get(symbol).As<Function>();
Local<Value> domain = object->Get(domain_symbol);

// TODO Hook for long stack traces to be made here.

// has domain, off with you
if (!domain->IsNull() && !domain->IsUndefined())
return scope.Close(MakeDomainCallback(object, callback, argc, argv));

// lazy load no domain next tick callbacks
if (process_tickCallback.IsEmpty()) {
Local<Value> cb_v = process->Get(String::New("_tickCallback"));
@@ -1017,7 +1010,7 @@ MakeCallback(const Handle<Object> object,
if (tick_infobox.length == 0) {
tick_infobox.index = 0;
tick_infobox.depth = 0;
return scope.Close(ret);
return ret;
}

// process nextTicks after call
@@ -1028,7 +1021,24 @@ MakeCallback(const Handle<Object> object,
return Undefined(node_isolate);
}

return scope.Close(ret);
return ret;
}


Handle<Value>
MakeCallback(const Handle<Object> object,
const Handle<String> symbol,
int argc,
Handle<Value> argv[]) {
HandleScope scope(node_isolate);

Local<Function> callback = object->Get(symbol).As<Function>();
Local<Value> domain = object->Get(domain_symbol);

// has domain, off with you
if (!domain->IsNull() && !domain->IsUndefined())
return scope.Close(MakeDomainCallback(object, callback, argc, argv));
return scope.Close(MakeCallback(object, callback, argc, argv));
}


@@ -569,6 +569,7 @@
break;

case 'PIPE':
case 'TCP':
var net = NativeModule.require('net');
stream = new net.Socket({
fd: fd,
@@ -654,6 +655,7 @@
break;

case 'PIPE':
case 'TCP':
var net = NativeModule.require('net');
stdin = new net.Socket({
fd: fd,
@@ -731,10 +733,6 @@
};

startup.processSignalHandlers = function() {
// Not supported on Windows.
if (process.platform === 'win32')
return;

// Load events module in order to access prototype elements on process like
// process.addListener.
var signalWraps = {};
@@ -104,6 +104,7 @@ void TCPWrap::Initialize(Handle<Object> target) {
NODE_SET_PROTOTYPE_METHOD(t, "writeUtf8String", StreamWrap::WriteUtf8String);
NODE_SET_PROTOTYPE_METHOD(t, "writeUcs2String", StreamWrap::WriteUcs2String);

NODE_SET_PROTOTYPE_METHOD(t, "open", Open);
NODE_SET_PROTOTYPE_METHOD(t, "bind", Bind);
NODE_SET_PROTOTYPE_METHOD(t, "listen", Listen);
NODE_SET_PROTOTYPE_METHOD(t, "connect", Connect);
@@ -256,6 +257,15 @@ Handle<Value> TCPWrap::SetSimultaneousAccepts(const Arguments& args) {
#endif


Handle<Value> TCPWrap::Open(const Arguments& args) {
HandleScope scope;
UNWRAP(TCPWrap)
int fd = args[0]->IntegerValue();
uv_tcp_open(&wrap->handle_, fd);
return Null();
}


Handle<Value> TCPWrap::Bind(const Arguments& args) {
HandleScope scope(node_isolate);

@@ -105,9 +105,15 @@ Handle<Value> TTYWrap::GuessHandleType(const Arguments& args) {
uv_handle_type t = uv_guess_handle(fd);

switch (t) {
case UV_TCP:
return scope.Close(String::New("TCP"));

case UV_TTY:
return scope.Close(String::New("TTY"));

case UV_UDP:
return scope.Close(String::New("UDP"));

case UV_NAMED_PIPE:
return scope.Close(String::New("PIPE"));

@@ -0,0 +1,98 @@
// 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 path = require('path');
var fs = require('fs');
var isWindows = process.platform === 'win32';
var openCount = 0;
var mode;
var content;

// Need to hijack fs.open/close to make sure that things
// get closed once they're opened.
fs._openSync = fs.openSync;
fs.openSync = openSync;
fs._closeSync = fs.closeSync;
fs.closeSync = closeSync;

// Reset the umask for testing
var mask = process.umask(0000);

// On Windows chmod is only able to manipulate read-only bit. Test if creating
// the file in read-only mode works.
if (isWindows) {
mode = 0444;
} else {
mode = 0755;
}

// Test writeFileSync
var file1 = path.join(common.tmpDir, 'testWriteFileSync.txt');
removeFile(file1);

fs.writeFileSync(file1, '123', {mode: mode});

content = fs.readFileSync(file1, {encoding: 'utf8'});
assert.equal('123', content);

assert.equal(mode, fs.statSync(file1).mode & 0777);

removeFile(file1);

// Test appendFileSync
var file2 = path.join(common.tmpDir, 'testAppendFileSync.txt');
removeFile(file2);

fs.appendFileSync(file2, 'abc', {mode: mode});

content = fs.readFileSync(file2, {encoding: 'utf8'});
assert.equal('abc', content);

assert.equal(mode, fs.statSync(file2).mode & mode);

removeFile(file2);

// Verify that all opened files were closed.
assert.equal(0, openCount);

// Removes a file if it exists.
function removeFile(file) {
try {
if (isWindows)
fs.chmodSync(file, 0666);
fs.unlinkSync(file);
} catch (err) {
if (err && err.code !== 'ENOENT')
throw err;
}
}

function openSync() {
openCount++;
return fs._openSync.apply(fs, arguments);
}

function closeSync() {
openCount--;
return fs._closeSync.apply(fs, arguments);
}
@@ -0,0 +1,94 @@
// 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 EE = require('events').EventEmitter;

var old = new EE;
var r = new Readable({ highWaterMark: 10 });
assert.equal(r, r.wrap(old));

var ended = false;
r.on('end', function() {
ended = true;
});

var pauses = 0;
var resumes = 0;

old.pause = function() {
pauses++;
old.emit('pause');
flowing = false;
};

old.resume = function() {
resumes++;
old.emit('resume');
flow();
};

var flowing;
var chunks = 10;
var oldEnded = false;
function flow() {
flowing = true;
while (flowing && chunks-- > 0) {
old.emit('data', new Buffer('xxxxxxxxxx'));
}
if (chunks <= 0) {
oldEnded = true;
old.emit('end');
}
}

var w = new Writable({ highWaterMark: 20 });
var written = [];
w._write = function(chunk, encoding, cb) {
written.push(chunk.toString());
setTimeout(cb);
};

var finished = false;
w.on('finish', function() {
finished = true;
});


var expect = new Array(11).join('xxxxxxxxxx');

r.pipe(w);

flow();

process.on('exit', function() {
assert.equal(pauses, 10);
assert.equal(resumes, 9);
assert(ended);
assert(finished);
assert(oldEnded);
assert.equal(written.join(''), expect);
console.log('ok');
});
@@ -74,11 +74,15 @@ TestReader.prototype._read = function(n) {
setTimeout(function() {

if (this.pos >= this.len) {
// double push(null) to test eos handling
this.push(null);
return this.push(null);
}

n = Math.min(n, this.len - this.pos);
if (n <= 0) {
// double push(null) to test eos handling
this.push(null);
return this.push(null);
}

@@ -118,9 +122,6 @@ test('setEncoding utf8', function(t) {
t.same(out, expect);
t.end();
});

// just kick it off.
tr.emit('readable');
});


@@ -160,9 +161,6 @@ test('setEncoding hex', function(t) {
t.same(out, expect);
t.end();
});

// just kick it off.
tr.emit('readable');
});

test('setEncoding hex with read(13)', function(t) {
@@ -199,9 +197,38 @@ test('setEncoding hex with read(13)', function(t) {
t.same(out, expect);
t.end();
});
});

// just kick it off.
tr.emit('readable');
test('setEncoding base64', function(t) {
var tr = new TestReader(100);
tr.setEncoding('base64');
var out = [];
var expect =
[ 'YWFhYWFhYW',
'FhYWFhYWFh',
'YWFhYWFhYW',
'FhYWFhYWFh',
'YWFhYWFhYW',
'FhYWFhYWFh',
'YWFhYWFhYW',
'FhYWFhYWFh',
'YWFhYWFhYW',
'FhYWFhYWFh',
'YWFhYWFhYW',
'FhYWFhYWFh',
'YWFhYWFhYW',
'FhYQ==' ];

tr.on('readable', function flow() {
var chunk;
while (null !== (chunk = tr.read(10)))
out.push(chunk);
});

tr.on('end', function() {
t.same(out, expect);
t.end();
});
});

test('encoding: utf8', function(t) {
@@ -229,9 +256,6 @@ test('encoding: utf8', function(t) {
t.same(out, expect);
t.end();
});

// just kick it off.
tr.emit('readable');
});


@@ -270,9 +294,6 @@ test('encoding: hex', function(t) {
t.same(out, expect);
t.end();
});

// just kick it off.
tr.emit('readable');
});

test('encoding: hex with read(13)', function(t) {
@@ -306,7 +327,35 @@ test('encoding: hex with read(13)', function(t) {
t.same(out, expect);
t.end();
});
});

test('encoding: base64', function(t) {
var tr = new TestReader(100, { encoding: 'base64' });
var out = [];
var expect =
[ 'YWFhYWFhYW',
'FhYWFhYWFh',
'YWFhYWFhYW',
'FhYWFhYWFh',
'YWFhYWFhYW',
'FhYWFhYWFh',
'YWFhYWFhYW',
'FhYWFhYWFh',
'YWFhYWFhYW',
'FhYWFhYWFh',
'YWFhYWFhYW',
'FhYWFhYWFh',
'YWFhYWFhYW',
'FhYQ==' ];

tr.on('readable', function flow() {
var chunk;
while (null !== (chunk = tr.read(10)))
out.push(chunk);
});

// just kick it off.
tr.emit('readable');
tr.on('end', function() {
t.same(out, expect);
t.end();
});
});
@@ -119,7 +119,6 @@ def npm_files(action):
assert(0) # unhandled action type

def files(action):
action(['doc/node.1'], 'share/man/man1/')
action(['out/Release/node'], 'bin/node')

# install unconditionally, checking if the platform supports dtrace doesn't