Skip to content

Commit

Permalink
Merge branch 'v0.4'
Browse files Browse the repository at this point in the history
Conflicts:
	lib/crypto.js
	lib/tls.js
  • Loading branch information
ry committed May 20, 2011
2 parents 7ea19d0 + 9c7f89b commit 59274e8
Show file tree
Hide file tree
Showing 8 changed files with 248 additions and 40 deletions.
56 changes: 51 additions & 5 deletions doc/api/http.markdown
Expand Up @@ -483,13 +483,59 @@ Options:

### 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 isn't being listened for, clients receiving an upgrade header will have
their connections closed.

A client server pair that show you how to listen for the `upgrade` event using `http.getAgent`:

Emitted each time a server responds to a request with an upgrade. If this event
isn't being listened for, clients receiving an upgrade header will have their
connections closed.
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'

Expand Down
28 changes: 18 additions & 10 deletions lib/crypto.js
Expand Up @@ -37,7 +37,7 @@ try {
}


function Credentials(secureProtocol, flags) {
function Credentials(secureProtocol, flags, context) {
if (!(this instanceof Credentials)) {
return new Credentials(secureProtocol);
}
Expand All @@ -46,24 +46,32 @@ function Credentials(secureProtocol, flags) {
throw new Error('node.js not compiled with openssl crypto support.');
}

this.context = new SecureContext();

if (secureProtocol) {
this.context.init(secureProtocol);
if (context) {
this.context = context;
} else {
this.context.init();
}
this.context = new SecureContext();

if(flags) this.context.setOptions(flags);
if (secureProtocol) {
this.context.init(secureProtocol);
} else {
this.context.init();
}
}

if (flags) this.context.setOptions(flags);
}

exports.Credentials = Credentials;


exports.createCredentials = function(options) {
exports.createCredentials = function(options, context) {
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);

Expand Down
46 changes: 33 additions & 13 deletions lib/tls.js
Expand Up @@ -244,9 +244,23 @@ CryptoStream.prototype._done = function() {
};


CryptoStream.prototype.fd = -1;
CryptoStream.prototype.__defineGetter__('readyState',
net.Socket.prototype.__lookupGetter__('readyState'));
// readyState is deprecated. Don't use it.
Object.defineProperty(CryptoStream.prototype, '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.
// From the user's perspective this occurs as a 'data' event
Expand Down Expand Up @@ -750,18 +764,24 @@ function Server(/* [options], listener */) {

var self = this;

// Handle option defaults:
this.setOptions(options);

var sharedCreds = crypto.createCredentials({
key: self.key,
cert: self.cert,
ca: self.ca,
ciphers: self.ciphers,
secureProtocol: self.secureProtocol,
secureOptions: self.secureOptions,
crl: self.crl
});

sharedCreds.context.setCiphers('RC4-SHA:AES128-SHA:AES256-SHA');

// constructor call
net.Server.call(this, function(socket) {
var creds = crypto.createCredentials({
key: self.key,
cert: self.cert,
ca: self.ca,
ciphers: self.ciphers,
secureProtocol: self.secureProtocol,
secureOptions: self.secureOptions,
crl: self.crl
});
creds.context.setCiphers('RC4-SHA:AES128-SHA:AES256-SHA');
var creds = crypto.createCredentials(null, sharedCreds.context);

var pair = new SecurePair(creds,
true,
Expand Down
5 changes: 5 additions & 0 deletions src/node_buffer.cc
Expand Up @@ -702,6 +702,11 @@ Handle<Value> Buffer::ByteLength(const Arguments &args) {
Handle<Value> Buffer::MakeFastBuffer(const Arguments &args) {
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());
Local<Object> fast_buffer = args[1]->ToObject();;
uint32_t offset = args[2]->Uint32Value();
Expand Down
49 changes: 37 additions & 12 deletions src/platform_sunos.cc
Expand Up @@ -168,7 +168,7 @@ int Platform::GetCPUInfo(Local<Array> *cpus) {
*cpus = Array::New();

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();

if (kstat_read(kc, ksp, NULL) == -1) {
Expand All @@ -183,9 +183,9 @@ int Platform::GetCPUInfo(Local<Array> *cpus) {
cpuinfo->Set(String::New("error"), String::New(strerror(errno)));
(*cpus)->Set(lookup_instance, cpuinfo);
} 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));
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));
(*cpus)->Set(lookup_instance, cpuinfo);
}
Expand All @@ -194,21 +194,21 @@ int Platform::GetCPUInfo(Local<Array> *cpus) {
}

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();
cputimes = Object::New();

if (kstat_read(kc, ksp, NULL) == -1) {
cputimes->Set(String::New("error"), String::New(strerror(errno)));
cpuinfo->Set(String::New("times"), cpuinfo);
} 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));
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));
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));
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));

cpuinfo->Set(String::New("times"), cputimes);
Expand All @@ -224,12 +224,37 @@ int Platform::GetCPUInfo(Local<Array> *cpus) {


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() {
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() {
Expand All @@ -243,12 +268,12 @@ double Platform::GetUptimeImpl() {
if ((kc = kstat_open()) == NULL)
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) {
throw "unable to read kstat";
} 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;
}

Expand Down
6 changes: 6 additions & 0 deletions test/simple/test-buffer.js
Expand Up @@ -577,3 +577,9 @@ assert.equal(0xee, b[0]);
assert.equal(0xad, b[1]);
assert.equal(0xbe, b[2]);
assert.equal(0xef, b[3]);


// This should not segfault the program.
assert.throws(function() {
new Buffer('"pong"', 0, 6, 8031, '127.0.0.1')
});
93 changes: 93 additions & 0 deletions test/simple/test-http-upgrade-agent.js
@@ -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);
});

0 comments on commit 59274e8

Please sign in to comment.