Merge branch 'v0.4'

Conflicts:
	lib/crypto.js
	lib/tls.js
This commit is contained in:
Ryan Dahl 2011-05-20 10:27:39 -07:00
commit 59274e8a33
8 changed files with 248 additions and 40 deletions

View File

@ -483,13 +483,59 @@ Options:
### Event: 'upgrade' ### Event: 'upgrade'
`function (request, socket, head)` `function (response, socket, head)`
Emitted each time a server responds to a request with an upgrade. If this event Emitted each time a server responds to a request with an upgrade. If this
isn't being listened for, clients receiving an upgrade header will have their event isn't being listened for, clients receiving an upgrade header will have
connections closed. their connections closed.
A client server pair that show you how to listen for the `upgrade` event using `http.getAgent`:
var http = require('http');
var net = require('net');
// Create an HTTP server
var srv = http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('okay');
});
srv.on('upgrade', function(req, socket, upgradeHead) {
socket.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n' +
'Upgrade: WebSocket\r\n' +
'Connection: Upgrade\r\n' +
'\r\n\r\n');
socket.ondata = function(data, start, end) {
socket.write(data.toString('utf8', start, end), 'utf8'); // echo back
};
});
// now that server is running
srv.listen(1337, '127.0.0.1', function() {
// make a request
var agent = http.getAgent('127.0.0.1', 1337);
var options = {
agent: agent,
port: 1337,
host: '127.0.0.1',
headers: {
'Connection': 'Upgrade',
'Upgrade': 'websocket'
}
};
var req = http.request(options);
req.end();
agent.on('upgrade', function(res, socket, upgradeHead) {
console.log('got upgraded!');
socket.end();
process.exit(0);
});
});
See the description of the [upgrade event](http.html#event_upgrade_) for `http.Server` for further details.
### Event: 'continue' ### Event: 'continue'

View File

@ -37,7 +37,7 @@ try {
} }
function Credentials(secureProtocol, flags) { function Credentials(secureProtocol, flags, context) {
if (!(this instanceof Credentials)) { if (!(this instanceof Credentials)) {
return new Credentials(secureProtocol); return new Credentials(secureProtocol);
} }
@ -46,6 +46,9 @@ function Credentials(secureProtocol, flags) {
throw new Error('node.js not compiled with openssl crypto support.'); throw new Error('node.js not compiled with openssl crypto support.');
} }
if (context) {
this.context = context;
} else {
this.context = new SecureContext(); this.context = new SecureContext();
if (secureProtocol) { if (secureProtocol) {
@ -53,17 +56,22 @@ function Credentials(secureProtocol, flags) {
} else { } else {
this.context.init(); this.context.init();
} }
}
if(flags) this.context.setOptions(flags); if (flags) this.context.setOptions(flags);
} }
exports.Credentials = Credentials; exports.Credentials = Credentials;
exports.createCredentials = function(options) { exports.createCredentials = function(options, context) {
if (!options) options = {}; if (!options) options = {};
var c = new Credentials(options.secureProtocol, options.secureOptions);
var c = new Credentials(options.secureProtocol,
options.secureOptions,
context);
if (context) return c;
if (options.key) c.context.setKey(options.key); if (options.key) c.context.setKey(options.key);

View File

@ -244,9 +244,23 @@ CryptoStream.prototype._done = function() {
}; };
CryptoStream.prototype.fd = -1; // readyState is deprecated. Don't use it.
CryptoStream.prototype.__defineGetter__('readyState', Object.defineProperty(CryptoStream.prototype, 'readyState', {
net.Socket.prototype.__lookupGetter__('readyState')); get: function() {
if (this._connecting) {
return 'opening';
} else if (this.readable && this.writable) {
return 'open';
} else if (this.readable && !this.writable) {
return 'readOnly';
} else if (!this.readable && this.writable) {
return 'writeOnly';
} else {
return 'closed';
}
}
});
// Move decrypted, clear data out into the application. // Move decrypted, clear data out into the application.
// From the user's perspective this occurs as a 'data' event // From the user's perspective this occurs as a 'data' event
@ -750,9 +764,10 @@ function Server(/* [options], listener */) {
var self = this; var self = this;
// constructor call // Handle option defaults:
net.Server.call(this, function(socket) { this.setOptions(options);
var creds = crypto.createCredentials({
var sharedCreds = crypto.createCredentials({
key: self.key, key: self.key,
cert: self.cert, cert: self.cert,
ca: self.ca, ca: self.ca,
@ -761,7 +776,12 @@ function Server(/* [options], listener */) {
secureOptions: self.secureOptions, secureOptions: self.secureOptions,
crl: self.crl crl: self.crl
}); });
creds.context.setCiphers('RC4-SHA:AES128-SHA:AES256-SHA');
sharedCreds.context.setCiphers('RC4-SHA:AES128-SHA:AES256-SHA');
// constructor call
net.Server.call(this, function(socket) {
var creds = crypto.createCredentials(null, sharedCreds.context);
var pair = new SecurePair(creds, var pair = new SecurePair(creds,
true, true,

View File

@ -702,6 +702,11 @@ Handle<Value> Buffer::ByteLength(const Arguments &args) {
Handle<Value> Buffer::MakeFastBuffer(const Arguments &args) { Handle<Value> Buffer::MakeFastBuffer(const Arguments &args) {
HandleScope scope; HandleScope scope;
if (!Buffer::HasInstance(args[0])) {
return ThrowException(Exception::TypeError(String::New(
"First argument must be a Buffer")));
}
Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject()); Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject());
Local<Object> fast_buffer = args[1]->ToObject();; Local<Object> fast_buffer = args[1]->ToObject();;
uint32_t offset = args[2]->Uint32Value(); uint32_t offset = args[2]->Uint32Value();

View File

@ -168,7 +168,7 @@ int Platform::GetCPUInfo(Local<Array> *cpus) {
*cpus = Array::New(); *cpus = Array::New();
lookup_instance = 0; lookup_instance = 0;
while (ksp = kstat_lookup(kc, "cpu_info", lookup_instance, NULL)){ while (ksp = kstat_lookup(kc, (char *)"cpu_info", lookup_instance, NULL)){
cpuinfo = Object::New(); cpuinfo = Object::New();
if (kstat_read(kc, ksp, NULL) == -1) { if (kstat_read(kc, ksp, NULL) == -1) {
@ -183,9 +183,9 @@ int Platform::GetCPUInfo(Local<Array> *cpus) {
cpuinfo->Set(String::New("error"), String::New(strerror(errno))); cpuinfo->Set(String::New("error"), String::New(strerror(errno)));
(*cpus)->Set(lookup_instance, cpuinfo); (*cpus)->Set(lookup_instance, cpuinfo);
} else { } else {
knp = (kstat_named_t *) kstat_data_lookup(ksp, "clock_MHz"); knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"clock_MHz");
cpuinfo->Set(String::New("speed"), data_named(knp)); cpuinfo->Set(String::New("speed"), data_named(knp));
knp = (kstat_named_t *) kstat_data_lookup(ksp, "brand"); knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"brand");
cpuinfo->Set(String::New("model"), data_named(knp)); cpuinfo->Set(String::New("model"), data_named(knp));
(*cpus)->Set(lookup_instance, cpuinfo); (*cpus)->Set(lookup_instance, cpuinfo);
} }
@ -194,7 +194,7 @@ int Platform::GetCPUInfo(Local<Array> *cpus) {
} }
lookup_instance = 0; lookup_instance = 0;
while (ksp = kstat_lookup(kc, "cpu", lookup_instance, "sys")){ while (ksp = kstat_lookup(kc, (char *)"cpu", lookup_instance, (char *)"sys")){
cpuinfo = (*cpus)->Get(lookup_instance)->ToObject(); cpuinfo = (*cpus)->Get(lookup_instance)->ToObject();
cputimes = Object::New(); cputimes = Object::New();
@ -202,13 +202,13 @@ int Platform::GetCPUInfo(Local<Array> *cpus) {
cputimes->Set(String::New("error"), String::New(strerror(errno))); cputimes->Set(String::New("error"), String::New(strerror(errno)));
cpuinfo->Set(String::New("times"), cpuinfo); cpuinfo->Set(String::New("times"), cpuinfo);
} else { } else {
knp = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_ticks_kernel"); knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"cpu_ticks_kernel");
cputimes->Set(String::New("system"), data_named(knp)); cputimes->Set(String::New("system"), data_named(knp));
knp = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_ticks_user"); knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"cpu_ticks_user");
cputimes->Set(String::New("user"), data_named(knp)); cputimes->Set(String::New("user"), data_named(knp));
knp = (kstat_named_t *) kstat_data_lookup(ksp, "cpu_ticks_idle"); knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"cpu_ticks_idle");
cputimes->Set(String::New("idle"), data_named(knp)); cputimes->Set(String::New("idle"), data_named(knp));
knp = (kstat_named_t *) kstat_data_lookup(ksp, "intr"); knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"intr");
cputimes->Set(String::New("irq"), data_named(knp)); cputimes->Set(String::New("irq"), data_named(knp));
cpuinfo->Set(String::New("times"), cputimes); cpuinfo->Set(String::New("times"), cputimes);
@ -224,12 +224,37 @@ int Platform::GetCPUInfo(Local<Array> *cpus) {
double Platform::GetFreeMemory() { double Platform::GetFreeMemory() {
return 0.0; kstat_ctl_t *kc;
kstat_t *ksp;
kstat_named_t *knp;
double pagesize = static_cast<double>(sysconf(_SC_PAGESIZE));
ulong_t freemem;
if((kc = kstat_open()) == NULL)
throw "could not open kstat";
ksp = kstat_lookup(kc, (char *)"unix", 0, (char *)"system_pages");
if(kstat_read(kc, ksp, NULL) == -1){
throw "could not read kstat";
}
else {
knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"freemem");
freemem = knp->value.ul;
}
kstat_close(kc);
return static_cast<double>(freemem)*pagesize;
} }
double Platform::GetTotalMemory() { double Platform::GetTotalMemory() {
return 0.0; double pagesize = static_cast<double>(sysconf(_SC_PAGESIZE));
double pages = static_cast<double>(sysconf(_SC_PHYS_PAGES));
return pagesize*pages;
} }
double Platform::GetUptimeImpl() { double Platform::GetUptimeImpl() {
@ -243,12 +268,12 @@ double Platform::GetUptimeImpl() {
if ((kc = kstat_open()) == NULL) if ((kc = kstat_open()) == NULL)
throw "could not open kstat"; throw "could not open kstat";
ksp = kstat_lookup(kc, "unix", 0, "system_misc"); ksp = kstat_lookup(kc, (char *)"unix", 0, (char *)"system_misc");
if (kstat_read(kc, ksp, NULL) == -1) { if (kstat_read(kc, ksp, NULL) == -1) {
throw "unable to read kstat"; throw "unable to read kstat";
} else { } else {
knp = (kstat_named_t *) kstat_data_lookup(ksp, "clk_intr"); knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"clk_intr");
clk_intr = knp->value.ul; clk_intr = knp->value.ul;
} }

View File

@ -577,3 +577,9 @@ assert.equal(0xee, b[0]);
assert.equal(0xad, b[1]); assert.equal(0xad, b[1]);
assert.equal(0xbe, b[2]); assert.equal(0xbe, b[2]);
assert.equal(0xef, b[3]); assert.equal(0xef, b[3]);
// This should not segfault the program.
assert.throws(function() {
new Buffer('"pong"', 0, 6, 8031, '127.0.0.1')
});

View File

@ -0,0 +1,93 @@
// 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.
// Verify that the 'upgrade' header causes an 'upgrade' event to be emitted to
// the HTTP client. This test uses a raw TCP server to better control server
// behavior.
var common = require('../common');
var assert = require('assert');
var http = require('http');
var net = require('net');
// Create a TCP server
var srv = net.createServer(function(c) {
var data = '';
c.addListener('data', function(d) {
data += d.toString('utf8');
c.write('HTTP/1.1 101\r\n');
c.write('hello: world\r\n');
c.write('connection: upgrade\r\n');
c.write('upgrade: websocket\r\n');
c.write('\r\n');
c.write('nurtzo');
});
c.addListener('end', function() {
c.end();
});
});
var gotUpgrade = false;
srv.listen(common.PORT, '127.0.0.1', function() {
var agent = http.getAgent({
host: '127.0.0.1',
port: common.PORT
});
assert.ok(agent);
var options = {
port: common.PORT,
host: '127.0.0.1',
headers: {
'upgrade': 'websocket'
}
};
var req = http.request(options);
req.end();
agent.on('upgrade', function(res, socket, upgradeHead) {
// XXX: This test isn't fantastic, as it assumes that the entire response
// from the server will arrive in a single data callback
assert.equal(upgradeHead, 'nurtzo');
console.log(res.headers);
var expectedHeaders = { 'hello': 'world',
'connection': 'upgrade',
'upgrade': 'websocket' };
assert.deepEqual(expectedHeaders, res.headers);
socket.end();
srv.close();
gotUpgrade = true;
});
});
process.addListener('exit', function() {
assert.ok(gotUpgrade);
});

View File

@ -54,6 +54,11 @@ server.listen(common.PORT, function() {
client.on('close', function() { client.on('close', function() {
// readyState is deprecated but we want to make
// sure this isn't triggering an assert in lib/net.js
// See issue #1069.
assert.equal('closed', client.readyState);
assert.equal(buffer, message); assert.equal(buffer, message);
console.log(message); console.log(message);
server.close(); server.close();