Merge branch 'v0.4'

Conflicts:
	lib/tls.js
	lib/url.js
	src/node_version.h
	test/simple/test-buffer.js
	test/simple/test-url.js
This commit is contained in:
isaacs 2011-05-07 20:38:32 -07:00
commit 205b9beb6b
33 changed files with 667 additions and 243 deletions

View File

@ -170,4 +170,6 @@ Arnout Kazemier <info@3rd-Eden.com>
George Stagas <gstagas@gmail.com> George Stagas <gstagas@gmail.com>
Scott McWhirter <scott.mcwhirter@joyent.com> Scott McWhirter <scott.mcwhirter@joyent.com>
Jakub Lekstan <jakub.lekstan@dreamlab.pl> Jakub Lekstan <jakub.lekstan@dreamlab.pl>
Tim Baumann <tim@timbaumann.info>
Robert Mustacchi <rm@joyent.com>

View File

@ -1,3 +1,21 @@
2011.04.22, Version 0.4.7 (stable)
* Don't emit error on ECONNRESET from read() #670
* Fix: Multiple pipes to the same stream were broken #929
(Felix Geisendörfer)
* URL parsing/formatting corrections #954 (isaacs)
* make it possible to do repl.start('', stream) (Wade Simmons)
* Add os.loadavg for SunOS (Robert Mustacchi)
* Fix timeouts with floating point numbers #897 (Jorge Chamorro Bieling)
* Improve docs.
2011.04.13, Version 0.4.6 (stable) 2011.04.13, Version 0.4.6 (stable)
* Don't error on ENOTCONN from shutdown() #670 * Don't error on ENOTCONN from shutdown() #670

View File

@ -3425,6 +3425,8 @@ void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
// Save the left value on the stack. // Save the left value on the stack.
__ Push(r5, r4); __ Push(r5, r4);
Label pop_and_call_runtime;
// Allocate a heap number to store the result. // Allocate a heap number to store the result.
heap_number_result = r5; heap_number_result = r5;
GenerateHeapResultAllocation(masm, GenerateHeapResultAllocation(masm,
@ -3432,7 +3434,7 @@ void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
heap_number_map, heap_number_map,
scratch1, scratch1,
scratch2, scratch2,
&call_runtime); &pop_and_call_runtime);
// Load the left value from the value saved on the stack. // Load the left value from the value saved on the stack.
__ Pop(r1, r0); __ Pop(r1, r0);
@ -3440,6 +3442,10 @@ void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
// Call the C function to handle the double operation. // Call the C function to handle the double operation.
FloatingPointHelper::CallCCodeForDoubleOperation( FloatingPointHelper::CallCCodeForDoubleOperation(
masm, op_, heap_number_result, scratch1); masm, op_, heap_number_result, scratch1);
__ bind(&pop_and_call_runtime);
__ Drop(2);
__ b(&call_runtime);
} }
break; break;

View File

@ -818,8 +818,8 @@ BUILTIN(ArraySplice) {
const int delta = actual_delete_count - item_count; const int delta = actual_delete_count - item_count;
if (actual_start > 0) { if (actual_start > 0) {
Object** start = elms->data_start(); AssertNoAllocation no_gc;
memmove(start + delta, start, actual_start * kPointerSize); MoveElements(&no_gc, elms, delta, elms, 0, actual_start);
} }
elms = LeftTrimFixedArray(elms, delta); elms = LeftTrimFixedArray(elms, delta);

View File

@ -2625,7 +2625,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
end = RegExpImpl::GetCapture(match_info_array, 1); end = RegExpImpl::GetCapture(match_info_array, 1);
} }
int length = subject->length(); int length = subject_handle->length();
int new_length = length - (end - start); int new_length = length - (end - start);
if (new_length == 0) { if (new_length == 0) {
return Heap::empty_string(); return Heap::empty_string();

View File

@ -35,7 +35,7 @@
#define MAJOR_VERSION 3 #define MAJOR_VERSION 3
#define MINOR_VERSION 1 #define MINOR_VERSION 1
#define BUILD_NUMBER 8 #define BUILD_NUMBER 8
#define PATCH_LEVEL 10 #define PATCH_LEVEL 14
#define CANDIDATE_VERSION false #define CANDIDATE_VERSION false
// Define SONAME to have the SCons build the put a specific SONAME into the // Define SONAME to have the SCons build the put a specific SONAME into the

View File

@ -88,7 +88,7 @@ sent to the server on that socket.
If a client connection emits an 'error' event - it will forwarded here. If a client connection emits an 'error' event - it will forwarded here.
### http.createServer(requestListener) ### http.createServer([requestListener])
Returns a new web server object. Returns a new web server object.
@ -397,6 +397,10 @@ Example:
}); });
}); });
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// write data to request body // write data to request body
req.write('data\n'); req.write('data\n');
req.write('data\n'); req.write('data\n');

View File

@ -4,7 +4,15 @@ HTTPS is the HTTP protocol over TLS/SSL. In Node this is implemented as a
separate module. separate module.
## https.Server ## https.Server
## https.createServer
This class is a subclass of `tls.Server` and emits events same as
`http.Server`. See `http.Server` for more information.
## https.createServer(options, [requestListener])
Returns a new HTTPS web server object. The `options` is similer to
`tls.createServer()`. The `requestListener` is a function which is
automatically added to the `'request'` event.
Example: Example:

View File

@ -33,7 +33,7 @@ Example of using `vm.runInThisContext` and `eval` to run the same code:
`eval` does have access to the local scope, so `localVar` is changed. `eval` does have access to the local scope, so `localVar` is changed.
In case of syntax error in `code`, `vm.runInThisContext` emits the syntax error to stderr In case of syntax error in `code`, `vm.runInThisContext` emits the syntax error to stderr
and throws.an exception. and throws an exception.
### vm.runInNewContext(code, [sandbox], [filename]) ### vm.runInNewContext(code, [sandbox], [filename])
@ -62,7 +62,7 @@ Note that running untrusted code is a tricky business requiring great care. To
global variable leakage, `vm.runInNewContext` is quite useful, but safely running untrusted code global variable leakage, `vm.runInNewContext` is quite useful, but safely running untrusted code
requires a separate process. requires a separate process.
In case of syntax error in `code`, `vm.runInThisContext` emits the syntax error to stderr In case of syntax error in `code`, `vm.runInNewContext` emits the syntax error to stderr
and throws an exception. and throws an exception.

View File

@ -24,9 +24,9 @@
<div id="toc"> <div id="toc">
<ol> <ol>
<li><a href="#download">Download</a></li> <li><a href="#download">Download</a></li>
<li><a href="https://github.com/joyent/node/raw/master/ChangeLog">ChangeLog</a></li> <li><a href="https://github.com/joyent/node/raw/v0.4/ChangeLog">ChangeLog</a></li>
<li><a href="#about">About</a></li> <li><a href="#about">About</a></li>
<li><a href="http://nodejs.org/docs/v0.4.6/api">v0.4.6 docs</a></li> <li><a href="http://nodejs.org/docs/v0.4.7/api">v0.4.7 docs</a></li>
<br/> <br/>
<li><a href="https://github.com/joyent/node/wiki">Wiki</a></li> <li><a href="https://github.com/joyent/node/wiki">Wiki</a></li>
<li><a href="http://blog.nodejs.org/">Blog</a></li> <li><a href="http://blog.nodejs.org/">Blog</a></li>
@ -55,8 +55,8 @@ var http = require('http');
http.createServer(function (req, res) { http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'}); res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n'); res.end('Hello World\n');
}).listen(8124, "127.0.0.1"); }).listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:8124/'); console.log('Server running at http://127.0.0.1:1337/');
</pre> </pre>
<p> <p>
@ -66,10 +66,10 @@ console.log('Server running at http://127.0.0.1:8124/');
</p> </p>
<pre class="sh_none"> <pre class="sh_none">
% node example.js % node example.js
Server running at http://127.0.0.1:8124/</pre> Server running at http://127.0.0.1:1337/</pre>
<p> <p>
Here is an example of a simple TCP server which listens on port 8124 Here is an example of a simple TCP server which listens on port 1337
and echoes whatever you send it: and echoes whatever you send it:
</p> </p>
@ -79,9 +79,9 @@ var net = require('net');
var server = net.createServer(function (socket) { var server = net.createServer(function (socket) {
socket.write("Echo server\r\n"); socket.write("Echo server\r\n");
socket.pipe(socket); socket.pipe(socket);
}) });
server.listen(8124, "127.0.0.1"); server.listen(1337, "127.0.0.1");
</pre> </pre>
<p> <p>
@ -107,9 +107,9 @@ server.listen(8124, "127.0.0.1");
</p> </p>
<p> <p>
2011.04.13 2011.04.22
<a href="http://nodejs.org/dist/node-v0.4.6.tar.gz">node-v0.4.6.tar.gz</a> <a href="http://nodejs.org/dist/node-v0.4.7.tar.gz">node-v0.4.7.tar.gz</a>
(<a href="http://nodejs.org/docs/v0.4.6/api/index.html">Documentation</a>) (<a href="http://nodejs.org/docs/v0.4.7/api/index.html">Documentation</a>)
</p> </p>
<p>Historical: <a href="http://nodejs.org/dist">versions</a>, <a href="http://nodejs.org/docs">docs</a></p> <p>Historical: <a href="http://nodejs.org/dist">versions</a>, <a href="http://nodejs.org/docs">docs</a></p>

View File

@ -291,7 +291,10 @@ Client.prototype.reqEval = function(expression, cb) {
var frame = bt.frames[self.currentFrame]; var frame = bt.frames[self.currentFrame];
var evalFrames = frame.scopes.map(function(s) { var evalFrames = frame.scopes.map(function(s) {
return bt.frames[s.index].index; if (!s) return;
var x = bt.frames[s.index];
if (!x) return;
return x.index;
}); });
self._reqFramesEval(expression, evalFrames, cb); self._reqFramesEval(expression, evalFrames, cb);
@ -1043,20 +1046,17 @@ Interface.prototype.trySpawn = function(cb) {
this.pause(); this.pause();
setTimeout(function() {
process.stdout.write('connecting...');
var client = self.client = new Client(); var client = self.client = new Client();
client.connect(exports.port); var connectionAttempts = 0;
client.once('ready', function() { client.once('ready', function() {
process.stdout.write('ok\r\n'); process.stdout.write(' ok\r\n');
// since we did debug-brk, we're hitting a break point immediately // since we did debug-brk, we're hitting a break point immediately
// continue before anything else. // continue before anything else.
client.reqContinue(function() { client.reqContinue(function() {
if (cb) cb(); if (cb) cb();
}); });
});
client.on('close', function() { client.on('close', function() {
console.log('\nprogram terminated'); console.log('\nprogram terminated');
@ -1064,6 +1064,7 @@ Interface.prototype.trySpawn = function(cb) {
self.killChild(); self.killChild();
if (!self.quitting) self.term.prompt(); if (!self.quitting) self.term.prompt();
}); });
});
client.on('unhandledResponse', function(res) { client.on('unhandledResponse', function(res) {
console.log('\r\nunhandled res:'); console.log('\r\nunhandled res:');
@ -1074,7 +1075,26 @@ Interface.prototype.trySpawn = function(cb) {
client.on('break', function(res) { client.on('break', function(res) {
self.handleBreak(res.body); self.handleBreak(res.body);
}); });
}, 100);
client.on('error', connectError);
function connectError() {
// If it's failed to connect 4 times then don't catch the next error
if (connectionAttempts >= 4) {
client.removeListener('error', connectError);
}
setTimeout(attemptConnect, 50);
}
function attemptConnect() {
++connectionAttempts;
process.stdout.write('.');
client.connect(exports.port);
}
setTimeout(function() {
process.stdout.write('connecting..');
attemptConnect();
}, 50);
}; };

View File

@ -139,7 +139,7 @@ SlowBuffer.prototype.write = function(string, offset, encoding) {
case 'ucs2': case 'ucs2':
case 'ucs-2': case 'ucs-2':
return this.ucs2Write(start, end); return this.ucs2Write(string, offset);
default: default:
throw new Error('Unknown encoding'); throw new Error('Unknown encoding');

View File

@ -1196,13 +1196,12 @@ Agent.prototype._establishNewConnection = function() {
req = self.queue.shift(); req = self.queue.shift();
assert(req._queue === self.queue); assert(req._queue === self.queue);
req._queue = null; req._queue = null;
} else {
// No requests on queue? Where is the request
assert(0);
} }
if (req) {
req.emit('error', err); req.emit('error', err);
req._hadError = true; // hacky req._hadError = true; // hacky
}
// clean up so that agent can handle new requests // clean up so that agent can handle new requests
parser.finish(); parser.finish();

View File

@ -80,7 +80,7 @@ function REPLServer(prompt, stream) {
process.stdin.resume(); process.stdin.resume();
} }
self.prompt = prompt || '> '; self.prompt = (prompt != undefined ? prompt : '> ');
function complete(text) { function complete(text) {
return self.complete(text); return self.complete(text);
@ -92,7 +92,7 @@ function REPLServer(prompt, stream) {
this.commands = {}; this.commands = {};
defineDefaultCommands(this); defineDefaultCommands(this);
if (rli.enabled && !disableColors) { if (rli.enabled && !disableColors && exports.writer === util.inspect) {
// Turn on ANSI coloring. // Turn on ANSI coloring.
exports.writer = function(obj, showHidden, depth) { exports.writer = function(obj, showHidden, depth) {
return util.inspect(obj, showHidden, depth, true); return util.inspect(obj, showHidden, depth, true);
@ -181,8 +181,8 @@ function REPLServer(prompt, stream) {
// It could also be an error from JSON.parse // It could also be an error from JSON.parse
} else if (e && } else if (e &&
e.stack && e.stack &&
e.stack.match('Unexpected token ILLEGAL') && e.stack.match(/^SyntaxError: Unexpected token .*\n/) &&
e.stack.match(/Object.parse \(native\)/)) { e.stack.match(/\n at Object.parse \(native\)\n/)) {
throw e; throw e;
} }
} }

View File

@ -28,13 +28,9 @@ function Stream() {
util.inherits(Stream, events.EventEmitter); util.inherits(Stream, events.EventEmitter);
exports.Stream = Stream; exports.Stream = Stream;
var pipes = [];
Stream.prototype.pipe = function(dest, options) { Stream.prototype.pipe = function(dest, options) {
var source = this; var source = this;
pipes.push(dest);
function ondata(chunk) { function ondata(chunk) {
if (dest.writable) { if (dest.writable) {
if (false === dest.write(chunk)) source.pause(); if (false === dest.write(chunk)) source.pause();
@ -49,31 +45,66 @@ Stream.prototype.pipe = function(dest, options) {
dest.on('drain', ondrain); dest.on('drain', ondrain);
/* // If the 'end' option is not supplied, dest.end() will be called when
* If the 'end' option is not supplied, dest.end() will be called when // source gets the 'end' or 'close' events. Only dest.end() once, and
* source gets the 'end' event. // only when all sources have ended.
*/
if (!options || options.end !== false) { if (!options || options.end !== false) {
function onend() { dest._pipeCount = dest._pipeCount || 0;
var index = pipes.indexOf(dest); dest._pipeCount++;
pipes.splice(index, 1);
if (pipes.indexOf(dest) > -1) { source.on('end', onend);
source.on('close', onclose);
}
var didOnEnd = false;
function onend() {
if (didOnEnd) return;
didOnEnd = true;
dest._pipeCount--;
// remove the listeners
cleanup();
if (dest._pipeCount > 0) {
// waiting for other incoming streams to end.
return; return;
} }
dest.end(); dest.end();
} }
source.on('end', onend);
source.on('close', onend); function onclose() {
if (didOnEnd) return;
didOnEnd = true;
dest._pipeCount--;
// remove the listeners
cleanup();
if (dest._pipeCount > 0) {
// waiting for other incoming streams to end.
return;
} }
/* dest.destroy();
* Questionable: }
*/
// don't leave dangling pipes when there are errors.
function onerror(er) {
cleanup();
if (this.listeners('error').length === 1) {
throw er; // Unhandled stream error in pipe.
}
}
source.on('error', onerror);
dest.on('error', onerror);
// guarantee that source streams can be paused and resumed, even
// if the only effect is to proxy the event back up the pipe chain.
if (!source.pause) { if (!source.pause) {
source.pause = function() { source.pause = function() {
source.emit('pause'); source.emit('pause');
@ -86,27 +117,32 @@ Stream.prototype.pipe = function(dest, options) {
}; };
} }
var onpause = function() { function onpause() {
source.pause(); source.pause();
} }
dest.on('pause', onpause); dest.on('pause', onpause);
var onresume = function() { function onresume() {
if (source.readable) source.resume(); if (source.readable) source.resume();
}; }
dest.on('resume', onresume); dest.on('resume', onresume);
var cleanup = function () { // remove all the event listeners that were added.
function cleanup() {
source.removeListener('data', ondata); source.removeListener('data', ondata);
dest.removeListener('drain', ondrain); dest.removeListener('drain', ondrain);
source.removeListener('end', onend); source.removeListener('end', onend);
source.removeListener('close', onend); source.removeListener('close', onclose);
dest.removeListener('pause', onpause); dest.removeListener('pause', onpause);
dest.removeListener('resume', onresume); dest.removeListener('resume', onresume);
source.removeListener('error', onerror);
dest.removeListener('error', onerror);
source.removeListener('end', cleanup); source.removeListener('end', cleanup);
source.removeListener('close', cleanup); source.removeListener('close', cleanup);

View File

@ -79,7 +79,7 @@ function CryptoStream(pair) {
this.readable = this.writable = true; this.readable = this.writable = true;
this._writeState = true; this._paused = false;
this._pending = []; this._pending = [];
this._pendingCallbacks = []; this._pendingCallbacks = [];
this._pendingBytes = 0; this._pendingBytes = 0;
@ -118,11 +118,10 @@ CryptoStream.prototype.write = function(data /* , encoding, cb */) {
this._pending.push(data); this._pending.push(data);
this._pendingCallbacks.push(cb); this._pendingCallbacks.push(cb);
this._pendingBytes += data.length; this._pendingBytes += data.length;
this.pair._writeCalled = true; this.pair._writeCalled = true;
this.pair._cycle(); this.pair.cycle();
return this._pendingBytes < 128 * 1024; return this._pendingBytes < 128 * 1024;
}; };
@ -130,14 +129,14 @@ CryptoStream.prototype.write = function(data /* , encoding, cb */) {
CryptoStream.prototype.pause = function() { CryptoStream.prototype.pause = function() {
debug('paused ' + (this == this.pair.cleartext ? 'cleartext' : 'encrypted')); debug('paused ' + (this == this.pair.cleartext ? 'cleartext' : 'encrypted'));
this._writeState = false; this._paused = true;
}; };
CryptoStream.prototype.resume = function() { CryptoStream.prototype.resume = function() {
debug('resume ' + (this == this.pair.cleartext ? 'cleartext' : 'encrypted')); debug('resume ' + (this == this.pair.cleartext ? 'cleartext' : 'encrypted'));
this._writeState = true; this._paused = false;
this.pair._cycle(); this.pair.cycle();
}; };
@ -175,8 +174,8 @@ function parseCertString(s) {
CryptoStream.prototype.getPeerCertificate = function() { CryptoStream.prototype.getPeerCertificate = function() {
if (this.pair._ssl) { if (this.pair.ssl) {
var c = this.pair._ssl.getPeerCertificate(); var c = this.pair.ssl.getPeerCertificate();
if (c) { if (c) {
if (c.issuer) c.issuer = parseCertString(c.issuer); if (c.issuer) c.issuer = parseCertString(c.issuer);
@ -190,8 +189,8 @@ CryptoStream.prototype.getPeerCertificate = function() {
CryptoStream.prototype.getCipher = function(err) { CryptoStream.prototype.getCipher = function(err) {
if (this.pair._ssl) { if (this.pair.ssl) {
return this.pair._ssl.getCurrentCipher(); return this.pair.ssl.getCurrentCipher();
} else { } else {
return null; return null;
} }
@ -199,8 +198,8 @@ CryptoStream.prototype.getCipher = function(err) {
CryptoStream.prototype.end = function(d) { CryptoStream.prototype.end = function(d) {
if (this.writable) { if (this.pair._doneFlag) return;
if (this.pair._done) return; if (!this.writable) return;
if (d) { if (d) {
this.write(d); this.write(d);
@ -214,8 +213,7 @@ CryptoStream.prototype.end = function(d) {
this.writable = false; this.writable = false;
this.pair._cycle(); this.pair.cycle();
}
}; };
@ -229,8 +227,8 @@ CryptoStream.prototype.destroySoon = function(err) {
CryptoStream.prototype.destroy = function(err) { CryptoStream.prototype.destroy = function(err) {
if (this.pair._done) return; if (this.pair._doneFlag) return;
this.pair._destroy(); this.pair.destroy();
}; };
@ -239,9 +237,9 @@ CryptoStream.prototype._done = function() {
if (this.pair.cleartext._doneFlag && if (this.pair.cleartext._doneFlag &&
this.pair.encrypted._doneFlag && this.pair.encrypted._doneFlag &&
!this.pair._done) { !this.pair._doneFlag) {
// If both streams are done: // If both streams are done:
this.pair._destroy(); this.pair.destroy();
} }
}; };
@ -269,7 +267,7 @@ CryptoStream.prototype._push = function() {
return; return;
} }
while (this._writeState == true) { while (!this._paused) {
var bytesRead = 0; var bytesRead = 0;
var chunkBytes = 0; var chunkBytes = 0;
var pool = new Buffer(16 * 4096); // alloc every time? var pool = new Buffer(16 * 4096); // alloc every time?
@ -277,18 +275,18 @@ CryptoStream.prototype._push = function() {
do { do {
chunkBytes = this._pusher(pool, bytesRead, pool.length - bytesRead); chunkBytes = this._pusher(pool, bytesRead, pool.length - bytesRead);
if (this.pair._ssl && this.pair._ssl.error) { if (this.pair.ssl && this.pair.ssl.error) {
this.pair._error(); this.pair.error();
return; return;
} }
this.pair._maybeInitFinished(); this.pair.maybeInitFinished();
if (chunkBytes >= 0) { if (chunkBytes >= 0) {
bytesRead += chunkBytes; bytesRead += chunkBytes;
} }
} while ((chunkBytes > 0) && (bytesRead < pool.length)); } while (chunkBytes > 0 && bytesRead < pool.length);
assert(bytesRead >= 0); assert(bytesRead >= 0);
@ -341,7 +339,7 @@ CryptoStream.prototype._pull = function() {
assert(havePending || this._pendingBytes == 0); assert(havePending || this._pendingBytes == 0);
while (this._pending.length > 0) { while (this._pending.length > 0) {
if (!this.pair._ssl) break; if (!this.pair.ssl) break;
var tmp = this._pending.shift(); var tmp = this._pending.shift();
var cb = this._pendingCallbacks.shift(); var cb = this._pendingCallbacks.shift();
@ -358,7 +356,7 @@ CryptoStream.prototype._pull = function() {
assert(this === this.pair.cleartext); assert(this === this.pair.cleartext);
debug('end cleartext'); debug('end cleartext');
this.pair._ssl.shutdown(); this.pair.ssl.shutdown();
// TODO check if we get EAGAIN From shutdown, would have to do it // TODO check if we get EAGAIN From shutdown, would have to do it
// again. should unshift END_OF_FILE back onto pending and wait for // again. should unshift END_OF_FILE back onto pending and wait for
@ -366,7 +364,7 @@ CryptoStream.prototype._pull = function() {
this.pair.encrypted._destroyAfterPush = true; this.pair.encrypted._destroyAfterPush = true;
} }
this.pair._cycle(); this.pair.cycle();
this._done() this._done()
return; return;
} }
@ -375,12 +373,12 @@ CryptoStream.prototype._pull = function() {
var rv = this._puller(tmp); var rv = this._puller(tmp);
if (this.pair._ssl && this.pair._ssl.error) { if (this.pair.ssl && this.pair.ssl.error) {
this.pair._error(); this.pair.error();
return; return;
} }
this.pair._maybeInitFinished(); this.pair.maybeInitFinished();
if (rv === 0 || rv < 0) { if (rv === 0 || rv < 0) {
this._pending.unshift(tmp); this._pending.unshift(tmp);
@ -412,8 +410,8 @@ util.inherits(CleartextStream, CryptoStream);
CleartextStream.prototype._internallyPendingBytes = function() { CleartextStream.prototype._internallyPendingBytes = function() {
if (this.pair._ssl) { if (this.pair.ssl) {
return this.pair._ssl.clearPending(); return this.pair.ssl.clearPending();
} else { } else {
return 0; return 0;
} }
@ -422,14 +420,14 @@ CleartextStream.prototype._internallyPendingBytes = function() {
CleartextStream.prototype._puller = function(b) { CleartextStream.prototype._puller = function(b) {
debug('clearIn ' + b.length + ' bytes'); debug('clearIn ' + b.length + ' bytes');
return this.pair._ssl.clearIn(b, 0, b.length); return this.pair.ssl.clearIn(b, 0, b.length);
}; };
CleartextStream.prototype._pusher = function(pool, offset, length) { CleartextStream.prototype._pusher = function(pool, offset, length) {
debug('reading from clearOut'); debug('reading from clearOut');
if (!this.pair._ssl) return -1; if (!this.pair.ssl) return -1;
return this.pair._ssl.clearOut(pool, offset, length); return this.pair.ssl.clearOut(pool, offset, length);
}; };
@ -440,8 +438,8 @@ util.inherits(EncryptedStream, CryptoStream);
EncryptedStream.prototype._internallyPendingBytes = function() { EncryptedStream.prototype._internallyPendingBytes = function() {
if (this.pair._ssl) { if (this.pair.ssl) {
return this.pair._ssl.encPending(); return this.pair.ssl.encPending();
} else { } else {
return 0; return 0;
} }
@ -450,14 +448,14 @@ EncryptedStream.prototype._internallyPendingBytes = function() {
EncryptedStream.prototype._puller = function(b) { EncryptedStream.prototype._puller = function(b) {
debug('writing from encIn'); debug('writing from encIn');
return this.pair._ssl.encIn(b, 0, b.length); return this.pair.ssl.encIn(b, 0, b.length);
}; };
EncryptedStream.prototype._pusher = function(pool, offset, length) { EncryptedStream.prototype._pusher = function(pool, offset, length) {
debug('reading from encOut'); debug('reading from encOut');
if (!this.pair._ssl) return -1; if (!this.pair.ssl) return -1;
return this.pair._ssl.encOut(pool, offset, length); return this.pair.ssl.encOut(pool, offset, length);
}; };
@ -483,9 +481,7 @@ function SecurePair(credentials, isServer, requestCert, rejectUnauthorized,
this._isServer = isServer ? true : false; this._isServer = isServer ? true : false;
this._encWriteState = true; this._encWriteState = true;
this._clearWriteState = true; this._clearWriteState = true;
this._done = false; this._doneFlag = false;
var crypto = require('crypto');
if (!credentials) { if (!credentials) {
this.credentials = crypto.createCredentials(); this.credentials = crypto.createCredentials();
@ -503,13 +499,13 @@ function SecurePair(credentials, isServer, requestCert, rejectUnauthorized,
this._rejectUnauthorized = rejectUnauthorized ? true : false; this._rejectUnauthorized = rejectUnauthorized ? true : false;
this._requestCert = requestCert ? true : false; this._requestCert = requestCert ? true : false;
this._ssl = new Connection(this.credentials.context, this.ssl = new Connection(this.credentials.context,
this._isServer ? true : false, this._isServer ? true : false,
this._requestCert, this._requestCert,
this._rejectUnauthorized); this._rejectUnauthorized);
if (NPN_ENABLED && NPNProtocols) { if (NPN_ENABLED && NPNProtocols) {
this._ssl.setNPNProtocols(NPNProtocols); this.ssl.setNPNProtocols(NPNProtocols);
this.npnProtocol = null; this.npnProtocol = null;
} }
@ -520,8 +516,8 @@ function SecurePair(credentials, isServer, requestCert, rejectUnauthorized,
this.encrypted = new EncryptedStream(this); this.encrypted = new EncryptedStream(this);
process.nextTick(function() { process.nextTick(function() {
self._ssl.start(); self.ssl.start();
self._cycle(); self.cycle();
}); });
} }
@ -569,63 +565,57 @@ exports.createSecurePair = function(credentials,
* Because it is also called everywhere, we also check if the connection has * Because it is also called everywhere, we also check if the connection has
* completed negotiation and emit 'secure' from here if it has. * completed negotiation and emit 'secure' from here if it has.
*/ */
SecurePair.prototype._cycle = function(depth) { SecurePair.prototype.cycle = function(depth) {
depth = depth ? depth : 0; if (this._doneFlag) return;
if (this._done) {
return;
}
if(depth == 0) this._writeCalled = false; depth = depth ? depth : 0;
if (depth == 0) this._writeCalled = false;
var established = this._secureEstablished; var established = this._secureEstablished;
if (!this._cycleEncryptedPullLock) { if (!this.cycleEncryptedPullLock) {
this._cycleEncryptedPullLock = true; this.cycleEncryptedPullLock = true;
debug("encrypted._pull"); debug("encrypted._pull");
this.encrypted._pull(); this.encrypted._pull();
this._cycleEncryptedPullLock = false; this.cycleEncryptedPullLock = false;
} }
if (!this._cycleCleartextPullLock) { if (!this.cycleCleartextPullLock) {
this._cycleCleartextPullLock = true; this.cycleCleartextPullLock = true;
debug("cleartext._pull"); debug("cleartext._pull");
this.cleartext._pull(); this.cleartext._pull();
this._cycleCleartextPullLock = false; this.cycleCleartextPullLock = false;
} }
if (!this._cycleCleartextPushLock) { if (!this.cycleCleartextPushLock) {
this._cycleCleartextPushLock = true; this.cycleCleartextPushLock = true;
debug("cleartext._push"); debug("cleartext._push");
this.cleartext._push(); this.cleartext._push();
this._cycleCleartextPushLock = false; this.cycleCleartextPushLock = false;
} }
if (!this._cycleEncryptedPushLock) { if (!this.cycleEncryptedPushLock) {
this._cycleEncryptedPushLock = true; this.cycleEncryptedPushLock = true;
debug("encrypted._push"); debug("encrypted._push");
this.encrypted._push(); this.encrypted._push();
this._cycleEncryptedPushLock = false; this.cycleEncryptedPushLock = false;
}
if (this._done) {
return;
} }
if ((!established && this._secureEstablished) || if ((!established && this._secureEstablished) ||
(depth == 0 && this._writeCalled)) { (depth == 0 && this._writeCalled)) {
// If we were not established but now we are, let's cycle again. // If we were not established but now we are, let's cycle again.
// Or if there is some data to write... // Or if there is some data to write...
this._cycle(depth + 1); this.cycle(depth + 1);
} }
}; };
SecurePair.prototype._maybeInitFinished = function() { SecurePair.prototype.maybeInitFinished = function() {
if (this._ssl && !this._secureEstablished && this._ssl.isInitFinished()) { if (this.ssl && !this._secureEstablished && this.ssl.isInitFinished()) {
if (NPN_ENABLED) { if (NPN_ENABLED) {
this.npnProtocol = this._ssl.getNegotiatedProtocol(); this.npnProtocol = this.ssl.getNegotiatedProtocol();
} }
this._secureEstablished = true; this._secureEstablished = true;
debug('secure established'); debug('secure established');
this.emit('secure'); this.emit('secure');
@ -633,45 +623,38 @@ SecurePair.prototype._maybeInitFinished = function() {
}; };
SecurePair.prototype._destroy = function() { SecurePair.prototype.destroy = function() {
var self = this; var self = this;
if (!this._done) { if (!this._doneFlag) {
this._done = true; this._doneFlag = true;
this._ssl.error = null; this.ssl.error = null;
this._ssl.close(); this.ssl.close();
this._ssl = null; this.ssl = null;
self.encrypted.writable = self.encrypted.readable = false; self.encrypted.writable = self.encrypted.readable = false;
self.cleartext.writable = self.cleartext.readable = false; self.cleartext.writable = self.cleartext.readable = false;
process.nextTick(function() { process.nextTick(function() {
self.encrypted.emit('end');
if (self.encrypted.onend) self.encrypted.onend();
self.encrypted.emit('close'); self.encrypted.emit('close');
self.cleartext.emit('end');
if (self.cleartext.onend) self.cleartext.onend();
self.cleartext.emit('close'); self.cleartext.emit('close');
}); });
} }
this._cycle();
}; };
SecurePair.prototype._error = function() { SecurePair.prototype.error = function() {
if (!this._secureEstablished) { if (!this._secureEstablished) {
this._destroy(); this.destroy();
} else { } else {
var err = this._ssl.error; var err = this.ssl.error;
this._ssl.error = null; this.ssl.error = null;
if (this._isServer && if (this._isServer &&
this._rejectUnauthorized && this._rejectUnauthorized &&
/peer did not return a certificate/.test(err.message)) { /peer did not return a certificate/.test(err.message)) {
// Not really an error. // Not really an error.
this._destroy(); this.destroy();
} else { } else {
this.cleartext.emit('error', err); this.cleartext.emit('error', err);
} }
@ -796,13 +779,13 @@ function Server(/* [options], listener */) {
cleartext._controlReleased = true; cleartext._controlReleased = true;
self.emit('secureConnection', pair.cleartext, pair.encrypted); self.emit('secureConnection', pair.cleartext, pair.encrypted);
} else { } else {
var verifyError = pair._ssl.verifyError(); var verifyError = pair.ssl.verifyError();
if (verifyError) { if (verifyError) {
pair.cleartext.authorizationError = verifyError; pair.cleartext.authorizationError = verifyError;
if (self.rejectUnauthorized) { if (self.rejectUnauthorized) {
socket.destroy(); socket.destroy();
pair._destroy(); pair.destroy();
} else { } else {
cleartext._controlReleased = true; cleartext._controlReleased = true;
self.emit('secureConnection', pair.cleartext, pair.encrypted); self.emit('secureConnection', pair.cleartext, pair.encrypted);
@ -904,7 +887,7 @@ exports.connect = function(port /* host, options, cb */) {
socket.connect(port, host); socket.connect(port, host);
pair.on('secure', function() { pair.on('secure', function() {
var verifyError = pair._ssl.verifyError(); var verifyError = pair.ssl.verifyError();
cleartext.npnProtocol = pair.npnProtocol; cleartext.npnProtocol = pair.npnProtocol;

View File

@ -24,25 +24,40 @@ exports.resolve = urlResolve;
exports.resolveObject = urlResolveObject; exports.resolveObject = urlResolveObject;
exports.format = urlFormat; exports.format = urlFormat;
// Reference: RFC 3986, RFC 1808, RFC 2396
// define these here so at least they only have to be // define these here so at least they only have to be
// compiled once on the first module load. // compiled once on the first module load.
var protocolPattern = /^([a-z0-9]+:)/i, var protocolPattern = /^([a-z0-9]+:)/i,
portPattern = /:[0-9]+$/, portPattern = /:[0-9]+$/,
delims = ['<', '>', '"', '\'', '`', /\s/], // RFC 2396: characters reserved for delimiting URLs.
delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'],
// RFC 2396: characters not allowed for various reasons.
unwise = ['{', '}', '|', '\\', '^', '~', '[', ']', '`'].concat(delims), unwise = ['{', '}', '|', '\\', '^', '~', '[', ']', '`'].concat(delims),
nonHostChars = ['/', '?', ';', '#'].concat(unwise), // Allowed by RFCs, but cause of XSS attacks. Always escape these.
autoEscape = ['\''],
// Characters that are never ever allowed in a hostname.
// Note that any invalid chars are also handled, but these
// are the ones that are *expected* to be seen, so we fast-path
// them.
nonHostChars = ['%', '/', '?', ';', '#']
.concat(unwise).concat(autoEscape),
hostnameMaxLen = 255, hostnameMaxLen = 255,
hostnamePartPattern = /^[a-z0-9][a-z0-9A-Z-]{0,62}$/, hostnamePartPattern = /^[a-zA-Z0-9][a-z0-9A-Z-]{0,62}$/,
hostnamePartStart = /^([a-zA-Z0-9][a-z0-9A-Z-]{0,62})(.*)$/,
// protocols that can allow "unsafe" and "unwise" chars.
unsafeProtocol = { unsafeProtocol = {
'javascript': true, 'javascript': true,
'javascript:': true 'javascript:': true
}, },
// protocols that never have a hostname.
hostlessProtocol = { hostlessProtocol = {
'javascript': true, 'javascript': true,
'javascript:': true, 'javascript:': true,
'file': true, 'file': true,
'file:': true 'file:': true
}, },
// protocols that always have a path component.
pathedProtocol = { pathedProtocol = {
'http': true, 'http': true,
'https': true, 'https': true,
@ -54,6 +69,7 @@ var protocolPattern = /^([a-z0-9]+:)/i,
'gopher:': true, 'gopher:': true,
'file:': true 'file:': true
}, },
// protocols that always contain a // bit.
slashedProtocol = { slashedProtocol = {
'http': true, 'http': true,
'https': true, 'https': true,
@ -71,17 +87,23 @@ var protocolPattern = /^([a-z0-9]+:)/i,
function urlParse(url, parseQueryString, slashesDenoteHost) { function urlParse(url, parseQueryString, slashesDenoteHost) {
if (url && typeof(url) === 'object' && url.href) return url; if (url && typeof(url) === 'object' && url.href) return url;
var out = { href: '' }, var out = {},
rest = url; rest = url;
var proto = protocolPattern.exec(rest), // cut off any delimiters.
lowerProto = proto; // This is to support parse stuff like "<http://foo.com>"
for (var i = 0, l = rest.length; i < l; i++) {
if (delims.indexOf(rest.charAt(i)) === -1) break;
}
if (i !== 0) rest = rest.substr(i);
var proto = protocolPattern.exec(rest);
if (proto) { if (proto) {
proto = proto[0]; proto = proto[0];
lowerProto = proto.toLowerCase(); var lowerProto = proto.toLowerCase();
out.protocol = lowerProto; out.protocol = lowerProto;
rest = rest.substr(proto.length); rest = rest.substr(proto.length);
out.href += lowerProto;
} }
// figure out if it's got a host // figure out if it's got a host
@ -90,15 +112,14 @@ function urlParse(url, parseQueryString, slashesDenoteHost) {
// how the browser resolves relative URLs. // how the browser resolves relative URLs.
if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) { if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) {
var slashes = rest.substr(0, 2) === '//'; var slashes = rest.substr(0, 2) === '//';
if (slashes && !(lowerProto && hostlessProtocol[lowerProto])) { if (slashes && !(proto && hostlessProtocol[proto])) {
rest = rest.substr(2); rest = rest.substr(2);
out.slashes = true; out.slashes = true;
out.href += '//';
} }
} }
if (!hostlessProtocol[lowerProto] && if (!hostlessProtocol[proto] &&
(slashes || (lowerProto && !slashedProtocol[lowerProto]))) { (slashes || (proto && !slashedProtocol[proto]))) {
// there's a hostname. // there's a hostname.
// the first instance of /, ?, ;, or # ends the host. // the first instance of /, ?, ;, or # ends the host.
// don't enforce full RFC correctness, just be unstupid about it. // don't enforce full RFC correctness, just be unstupid about it.
@ -123,9 +144,10 @@ function urlParse(url, parseQueryString, slashesDenoteHost) {
var key = keys[i]; var key = keys[i];
out[key] = p[key]; out[key] = p[key];
} }
// we've indicated that there is a hostname, // we've indicated that there is a hostname,
// so even if it's empty, it has to be present. // so even if it's empty, it has to be present.
out.hostname = (out.hostname) ? out.hostname.toLowerCase() : ''; out.hostname = out.hostname || '';
// validate a little. // validate a little.
if (out.hostname.length > hostnameMaxLen) { if (out.hostname.length > hostnameMaxLen) {
@ -134,19 +156,49 @@ function urlParse(url, parseQueryString, slashesDenoteHost) {
var hostparts = out.hostname.split(/\./); var hostparts = out.hostname.split(/\./);
for (var i = 0, l = hostparts.length; i < l; i++) { for (var i = 0, l = hostparts.length; i < l; i++) {
var part = hostparts[i]; var part = hostparts[i];
if (!part) continue;
if (!part.match(hostnamePartPattern)) { if (!part.match(hostnamePartPattern)) {
out.hostname = ''; var validParts = hostparts.slice(0, i);
var notHost = hostparts.slice(i + 1);
var bit = part.match(hostnamePartStart);
if (bit) {
validParts.push(bit[1]);
notHost.unshift(bit[2]);
}
if (notHost.length) {
rest = '/' + notHost.join('.') + rest
}
out.hostname = validParts.join('.');
break; break;
} }
} }
} }
out.host = ((out.auth)?out.auth +'@':'') + (out.hostname||'') + ((out.port)?':'+out.port:''); // hostnames are always lower case.
out.hostname = out.hostname.toLowerCase();
out.host = ((out.auth) ? out.auth + '@' : '') +
(out.hostname || '') +
((out.port) ? ':' + out.port : '');
out.href += out.host; out.href += out.host;
} }
// now rest is set to the post-host stuff. // now rest is set to the post-host stuff.
// chop off any delim chars. // chop off any delim chars.
if (!unsafeProtocol[lowerProto]) { if (!unsafeProtocol[lowerProto]) {
// First, make 100% sure that any "autoEscape" chars get
// escaped, even if encodeURIComponent doesn't think they
// need to be.
for (var i = 0, l = autoEscape.length; i < l; i++) {
var ae = autoEscape[i];
var esc = encodeURIComponent(ae);
if (esc === ae) {
esc = escape(ae);
}
rest = rest.split(ae).join(esc);
}
// Now make sure that delims never appear in a url.
var chop = rest.length; var chop = rest.length;
for (var i = 0, l = delims.length; i < l; i++) { for (var i = 0, l = delims.length; i < l; i++) {
var c = rest.indexOf(delims[i]); var c = rest.indexOf(delims[i]);
@ -155,7 +207,6 @@ function urlParse(url, parseQueryString, slashesDenoteHost) {
} }
} }
rest = rest.substr(0, chop); rest = rest.substr(0, chop);
out.href += rest;
} }
@ -180,7 +231,7 @@ function urlParse(url, parseQueryString, slashesDenoteHost) {
out.query = {}; out.query = {};
} }
if (rest) out.pathname = rest; if (rest) out.pathname = rest;
if (slashedProtocol[lowerProto] && if (slashedProtocol[proto] &&
out.hostname && !out.pathname) { out.hostname && !out.pathname) {
out.pathname = '/'; out.pathname = '/';
} }

View File

@ -1278,13 +1278,24 @@ static void ReportException(TryCatch &try_catch, bool show_line) {
String::Utf8Value trace(try_catch.StackTrace()); String::Utf8Value trace(try_catch.StackTrace());
if (trace.length() > 0) { // range errors have a trace member set to undefined
if (trace.length() > 0 && !try_catch.StackTrace()->IsUndefined()) {
fprintf(stderr, "%s\n", *trace); fprintf(stderr, "%s\n", *trace);
} else { } else {
// this really only happens for RangeErrors, since they're the only // this really only happens for RangeErrors, since they're the only
// kind that won't have all this info in the trace. // kind that won't have all this info in the trace, or when non-Error
// objects are thrown manually.
Local<Value> er = try_catch.Exception(); Local<Value> er = try_catch.Exception();
String::Utf8Value msg(!er->IsObject() ? er->ToString() bool isErrorObject = er->IsObject() &&
!(er->ToObject()->Get(String::New("message"))->IsUndefined()) &&
!(er->ToObject()->Get(String::New("name"))->IsUndefined());
if (isErrorObject) {
String::Utf8Value name(er->ToObject()->Get(String::New("name")));
fprintf(stderr, "%s: ", *name);
}
String::Utf8Value msg(!isErrorObject ? er->ToString()
: er->ToObject()->Get(String::New("message"))->ToString()); : er->ToObject()->Get(String::New("message"))->ToString());
fprintf(stderr, "%s\n", *msg); fprintf(stderr, "%s\n", *msg);
} }
@ -2251,7 +2262,7 @@ static void EnableDebug(bool wait_connect) {
assert(r); assert(r);
// Print out some information. // Print out some information.
fprintf(stderr, "debugger listening on port %d\r\n", debug_port); fprintf(stderr, "debugger listening on port %d", debug_port);
} }

View File

@ -48,7 +48,7 @@ void EmitExit(v8::Handle<v8::Object> process);
/* Converts a unixtime to V8 Date */ /* Converts a unixtime to V8 Date */
#define NODE_UNIXTIME_V8(t) v8::Date::New(1000*static_cast<double>(t)) #define NODE_UNIXTIME_V8(t) v8::Date::New(1000*static_cast<double>(t))
#define NODE_V8_UNIXTIME(v) (static_cast<double>((v)->IntegerValue())/1000.0); #define NODE_V8_UNIXTIME(v) (static_cast<double>((v)->NumberValue())/1000.0);
#define NODE_DEFINE_CONSTANT(target, constant) \ #define NODE_DEFINE_CONSTANT(target, constant) \
(target)->Set(v8::String::NewSymbol(#constant), \ (target)->Set(v8::String::NewSymbol(#constant), \

View File

@ -31,6 +31,7 @@
#include <errno.h> #include <errno.h>
#include <inttypes.h> #include <inttypes.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/loadavg.h>
#if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64) #if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64)
#define PROCFS_FILE_OFFSET_BITS_HACK 1 #define PROCFS_FILE_OFFSET_BITS_HACK 1
@ -250,6 +251,14 @@ double Platform::GetUptimeImpl() {
} }
int Platform::GetLoadAvg(Local<Array> *loads) { int Platform::GetLoadAvg(Local<Array> *loads) {
HandleScope scope;
double loadavg[3];
(void) getloadavg(loadavg, 3);
(*loads)->Set(0, Number::New(loadavg[LOADAVG_1MIN]));
(*loads)->Set(1, Number::New(loadavg[LOADAVG_5MIN]));
(*loads)->Set(2, Number::New(loadavg[LOADAVG_15MIN]));
return 0; return 0;
} }

View File

@ -0,0 +1,33 @@
// 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');
common.error('before');
// stack overflow
function stackOverflow() {
stackOverflow();
}
stackOverflow();
common.error('after');

View File

@ -0,0 +1,6 @@
before
node.js:*
throw e; // process.nextTick error, or 'error' event on first tick
^
RangeError: Maximum call stack size exceeded

View File

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

View File

@ -0,0 +1,6 @@
before
node.js:*
throw e; // process.nextTick error, or 'error' event on first tick
^
MyCustomError: This is a custom message

View File

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

View File

@ -0,0 +1,6 @@
before
node.js:*
throw e; // process.nextTick error, or 'error' event on first tick
^
[object Object]

View File

@ -540,6 +540,7 @@ console.log(z.length)
assert.equal(2, z.length); assert.equal(2, z.length);
assert.equal(0x66, z[0]); assert.equal(0x66, z[0]);
assert.equal(0x6f, z[1]); assert.equal(0x6f, z[1]);
assert.equal(0, Buffer('hello').slice(0, 0).length) assert.equal(0, Buffer('hello').slice(0, 0).length)
b = new Buffer(50); b = new Buffer(50);
@ -557,3 +558,7 @@ b.fill(1, 16, 32);
for (var i = 0; i < 16; i++) assert.equal(0, b[i]); for (var i = 0; i < 16; i++) assert.equal(0, b[i]);
for (; i < 32; i++) assert.equal(1, b[i]); for (; i < 32; i++) assert.equal(1, b[i]);
for (; i < b.length; i++) assert.equal(0, b[i]); for (; i < b.length; i++) assert.equal(0, b[i]);
var b = new SlowBuffer(10);
b.write('あいうえお', 'ucs2');
assert.equal(b.toString('ucs2'), 'あいうえお');

View File

@ -83,7 +83,7 @@ server.listen(common.PORT, function() {
bodyBuffer += s; bodyBuffer += s;
}); });
res.on('end', function() { res.on('close', function() {
console.log('5) Client got "end" event.'); console.log('5) Client got "end" event.');
gotEnd = true; gotEnd = true;
}); });

View File

@ -0,0 +1,14 @@
var common = require('../common');
var assert = require('assert');
var t = Date.now();
var diff;
setTimeout(function () {
diff = Date.now() - t;
console.error(diff);
}, 0.1);
process.on('exit', function() {
assert.ok(diff < 100);
});

View File

@ -36,6 +36,10 @@ Writable.prototype.end = function () {
this.endCalls++; this.endCalls++;
} }
Writable.prototype.destroy = function () {
this.endCalls++;
}
function Readable () { function Readable () {
this.readable = true; this.readable = true;
stream.Stream.call(this); stream.Stream.call(this);

View File

@ -0,0 +1,100 @@
// Test that having a bunch of streams piping in parallel
// doesn't break anything.
var common = require("../common");
var assert = require("assert");
var Stream = require("stream").Stream;
var rr = [];
var ww = [];
var cnt = 100;
var chunks = 1000;
var chunkSize = 250;
var data = new Buffer(chunkSize);
var wclosed = 0;
var rclosed = 0;
function FakeStream() {
Stream.apply(this);
this.wait = false;
this.writable = true;
this.readable = true;
}
FakeStream.prototype = Object.create(Stream.prototype);
FakeStream.prototype.write = function(chunk) {
console.error(this.ID, "write", this.wait)
if (this.wait) {
process.nextTick(this.emit.bind(this, "drain"));
}
this.wait = !this.wait;
return this.wait;
};
FakeStream.prototype.end = function() {
this.emit("end");
process.nextTick(this.close.bind(this));
};
// noop - closes happen automatically on end.
FakeStream.prototype.close = function() {
this.emit("close");
};
// expect all streams to close properly.
process.on("exit", function() {
assert.equal(cnt, wclosed, "writable streams closed");
assert.equal(cnt, rclosed, "readable streams closed");
});
for (var i = 0; i < chunkSize; i ++) {
chunkSize[i] = i % 256;
}
for (var i = 0; i < cnt; i++) {
var r = new FakeStream();
r.on("close", function() {
console.error(this.ID, "read close");
rclosed++;
});
rr.push(r);
var w = new FakeStream();
w.on("close", function() {
console.error(this.ID, "write close");
wclosed++;
});
ww.push(w);
r.ID = w.ID = i;
r.pipe(w);
}
// now start passing through data
// simulate a relatively fast async stream.
rr.forEach(function (r) {
var cnt = chunks;
var paused = false;
r.on("pause", function() {
paused = true;
});
r.on("resume", function() {
paused = false;
step();
});
function step() {
r.emit("data", data);
if (--cnt === 0) {
r.end();
return;
}
if (paused) return;
process.nextTick(step);
}
process.nextTick(step);
});

View File

@ -63,7 +63,67 @@ var parseTests = {
'host': 'USER:PW@www.example.com', 'host': 'USER:PW@www.example.com',
'hostname': 'www.example.com', 'hostname': 'www.example.com',
'pathname': '/' 'pathname': '/'
},
'http://x.com/path?that\'s#all, folks' : {
'href': 'http://x.com/path?that%27s#all,',
'protocol': 'http:',
'host': 'x.com',
'hostname': 'x.com',
'search': '?that%27s',
'query': 'that%27s',
'pathname': '/path',
'hash': '#all,'
},
'HTTP://X.COM/Y' : {
'href': 'http://x.com/Y',
'protocol': 'http:',
'host': 'x.com',
'hostname': 'x.com',
'pathname': '/Y',
},
// an unexpected invalid char in the hostname.
'HtTp://x.y.cOm*a/b/c?d=e#f g<h>i' : {
'href': 'http://x.y.com/*a/b/c?d=e#f',
'protocol': 'http:',
'host': 'x.y.com',
'hostname': 'x.y.com',
'pathname': '/*a/b/c',
'search': '?d=e',
'query': 'd=e',
'hash': '#f'
},
// make sure that we don't accidentally lcast the path parts.
'HtTp://x.y.cOm*A/b/c?d=e#f g<h>i' : {
'href': 'http://x.y.com/*A/b/c?d=e#f',
'protocol': 'http:',
'host': 'x.y.com',
'hostname': 'x.y.com',
'pathname': '/*A/b/c',
'search': '?d=e',
'query': 'd=e',
'hash': '#f'
},
'http://x...y...#p': {
'href': 'http://x...y.../#p',
'protocol': 'http:',
'host': 'x...y...',
'hostname': 'x...y...',
'hash': '#p',
'pathname': '/'
},
'http://x/p/"quoted"': {
'href': 'http://x/p/',
'protocol':'http:',
'host': 'x',
'hostname': 'x',
'pathname': '/p/'
},
'<http://goo.corn/bread> Is a URL!': {
'href': 'http://goo.corn/bread',
'protocol': 'http:',
'host': 'goo.corn',
'hostname': 'goo.corn',
'pathname': '/bread'
}, },
'http://www.narwhaljs.org/blog/categories?id=news' : { 'http://www.narwhaljs.org/blog/categories?id=news' : {
'href': 'http://www.narwhaljs.org/blog/categories?id=news', 'href': 'http://www.narwhaljs.org/blog/categories?id=news',
@ -91,7 +151,8 @@ var parseTests = {
'query': '??&hl=en&src=api&x=2&y=2&z=3&s=', 'query': '??&hl=en&src=api&x=2&y=2&z=3&s=',
'pathname': '/vt/lyrs=m@114' 'pathname': '/vt/lyrs=m@114'
}, },
'http://user:pass@mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=' : { 'http://user:pass@mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=':
{
'href': 'http://user:pass@mt0.google.com/vt/lyrs=m@114???' + 'href': 'http://user:pass@mt0.google.com/vt/lyrs=m@114???' +
'&hl=en&src=api&x=2&y=2&z=3&s=', '&hl=en&src=api&x=2&y=2&z=3&s=',
'protocol': 'http:', 'protocol': 'http:',
@ -191,7 +252,7 @@ for (var u in parseTests) {
actual = url.format(parseTests[u]); actual = url.format(parseTests[u]);
assert.equal(expected, actual, assert.equal(expected, actual,
'format(' + u + ') == ' + expected + '\nactual:' + actual); 'format(' + u + ') == ' + u + '\nactual:' + actual);
} }
var parseTestsWithQueryString = { var parseTestsWithQueryString = {
@ -204,7 +265,7 @@ var parseTestsWithQueryString = {
}, },
'pathname': '/foo/bar' 'pathname': '/foo/bar'
}, },
'http://example.com/' : { 'http://example.com' : {
'href': 'http://example.com/', 'href': 'http://example.com/',
'protocol': 'http:', 'protocol': 'http:',
'slashes': true, 'slashes': true,

24
wscript
View File

@ -143,13 +143,6 @@ def set_options(opt):
, dest='openssl_libpath' , dest='openssl_libpath'
) )
opt.add_option( '--oprofile'
, action='store_true'
, default=False
, help="add oprofile support"
, dest='use_oprofile'
)
opt.add_option( '--gdb' opt.add_option( '--gdb'
, action='store_true' , action='store_true'
, default=False , default=False
@ -252,12 +245,8 @@ def configure(conf):
conf.env["USE_SHARED_CARES"] = o.shared_cares or o.shared_cares_includes or o.shared_cares_libpath conf.env["USE_SHARED_CARES"] = o.shared_cares or o.shared_cares_includes or o.shared_cares_libpath
conf.env["USE_SHARED_LIBEV"] = o.shared_libev or o.shared_libev_includes or o.shared_libev_libpath conf.env["USE_SHARED_LIBEV"] = o.shared_libev or o.shared_libev_includes or o.shared_libev_libpath
conf.env["USE_OPROFILE"] = o.use_oprofile
conf.env["USE_GDBJIT"] = o.use_gdbjit conf.env["USE_GDBJIT"] = o.use_gdbjit
if o.use_oprofile:
conf.check(lib=['bfd', 'opagent'], uselib_store="OPROFILE")
conf.check(lib='dl', uselib_store='DL') conf.check(lib='dl', uselib_store='DL')
if not sys.platform.startswith("sunos") and not sys.platform.startswith("cygwin") and not sys.platform.startswith("win32"): if not sys.platform.startswith("sunos") and not sys.platform.startswith("cygwin") and not sys.platform.startswith("win32"):
conf.env.append_value("CCFLAGS", "-rdynamic") conf.env.append_value("CCFLAGS", "-rdynamic")
@ -552,7 +541,6 @@ def configure(conf):
# Configure default variant # Configure default variant
conf.setenv('default') conf.setenv('default')
conf.env.append_value('CPPFLAGS', '-DNDEBUG')
default_compile_flags = ['-g', '-O3'] default_compile_flags = ['-g', '-O3']
conf.env.append_value('CCFLAGS', default_compile_flags) conf.env.append_value('CCFLAGS', default_compile_flags)
conf.env.append_value('CXXFLAGS', default_compile_flags) conf.env.append_value('CXXFLAGS', default_compile_flags)
@ -587,12 +575,7 @@ def v8_cmd(bld, variant):
else: else:
snapshot = "" snapshot = ""
if bld.env["USE_OPROFILE"]: cmd_R = sys.executable + ' "%s" -j %d -C "%s" -Y "%s" visibility=default mode=%s %s toolchain=%s library=static %s'
profile = "prof=oprofile"
else:
profile = ""
cmd_R = sys.executable + ' "%s" -j %d -C "%s" -Y "%s" visibility=default mode=%s %s toolchain=%s library=static %s %s'
cmd = cmd_R % ( scons cmd = cmd_R % ( scons
, Options.options.jobs , Options.options.jobs
@ -602,7 +585,6 @@ def v8_cmd(bld, variant):
, arch , arch
, toolchain , toolchain
, snapshot , snapshot
, profile
) )
if bld.env["USE_GDBJIT"]: if bld.env["USE_GDBJIT"]:
@ -753,7 +735,7 @@ def build(bld):
native_cc_debug = native_cc.clone("debug") native_cc_debug = native_cc.clone("debug")
native_cc_debug.rule = javascript_in_c_debug native_cc_debug.rule = javascript_in_c_debug
native_cc.rule = javascript_in_c native_cc.rule = javascript_in_c_debug
if bld.env["USE_DTRACE"]: if bld.env["USE_DTRACE"]:
dtrace = bld.new_task_gen( dtrace = bld.new_task_gen(
@ -892,7 +874,7 @@ def build(bld):
, 'CPPFLAGS' : " ".join(program.env["CPPFLAGS"]).replace('"', '\\"') , 'CPPFLAGS' : " ".join(program.env["CPPFLAGS"]).replace('"', '\\"')
, 'LIBFLAGS' : " ".join(program.env["LIBFLAGS"]).replace('"', '\\"') , 'LIBFLAGS' : " ".join(program.env["LIBFLAGS"]).replace('"', '\\"')
, 'PREFIX' : safe_path(program.env["PREFIX"]) , 'PREFIX' : safe_path(program.env["PREFIX"])
, 'VERSION' : '0.4.6' # FIXME should not be hard-coded, see NODE_VERSION_STRING in src/node_version. , 'VERSION' : '0.4.7' # FIXME should not be hard-coded, see NODE_VERSION_STRING in src/node_version.
} }
return x return x