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:
commit
205b9beb6b
2
AUTHORS
2
AUTHORS
@ -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>
|
||||||
|
|
||||||
|
18
ChangeLog
18
ChangeLog
@ -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
|
||||||
|
8
deps/v8/src/arm/code-stubs-arm.cc
vendored
8
deps/v8/src/arm/code-stubs-arm.cc
vendored
@ -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;
|
||||||
|
4
deps/v8/src/builtins.cc
vendored
4
deps/v8/src/builtins.cc
vendored
@ -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);
|
||||||
|
2
deps/v8/src/runtime.cc
vendored
2
deps/v8/src/runtime.cc
vendored
@ -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();
|
||||||
|
2
deps/v8/src/version.cc
vendored
2
deps/v8/src/version.cc
vendored
@ -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
|
||||||
|
@ -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');
|
||||||
|
@ -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:
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -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');
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
171
lib/tls.js
171
lib/tls.js
@ -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;
|
||||||
|
|
||||||
|
85
lib/url.js
85
lib/url.js
@ -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 = '/';
|
||||||
}
|
}
|
||||||
|
19
src/node.cc
19
src/node.cc
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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), \
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
33
test/message/stack_overflow.js
Normal file
33
test/message/stack_overflow.js
Normal 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');
|
6
test/message/stack_overflow.out
Normal file
6
test/message/stack_overflow.out
Normal 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
|
30
test/message/throw_custom_error.js
Normal file
30
test/message/throw_custom_error.js
Normal 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');
|
6
test/message/throw_custom_error.out
Normal file
6
test/message/throw_custom_error.out
Normal 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
|
30
test/message/throw_non_error.js
Normal file
30
test/message/throw_non_error.js
Normal 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');
|
6
test/message/throw_non_error.out
Normal file
6
test/message/throw_non_error.out
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
before
|
||||||
|
|
||||||
|
node.js:*
|
||||||
|
throw e; // process.nextTick error, or 'error' event on first tick
|
||||||
|
^
|
||||||
|
[object Object]
|
@ -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'), 'あいうえお');
|
||||||
|
@ -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;
|
||||||
});
|
});
|
||||||
|
14
test/simple/test-regress-GH-897.js
Normal file
14
test/simple/test-regress-GH-897.js
Normal 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);
|
||||||
|
});
|
@ -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);
|
||||||
|
100
test/simple/test-stream-pipe-multi.js
Normal file
100
test/simple/test-stream-pipe-multi.js
Normal 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);
|
||||||
|
});
|
@ -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
24
wscript
@ -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
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user