From 5e409c2f1aa94b76f42e58001f7fcd0959a958aa Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 19 May 2011 12:13:48 -0700 Subject: [PATCH 1/8] makeFastBuffer should not segfault but rather throw on non-buffer --- src/node_buffer.cc | 5 +++++ test/simple/test-buffer.js | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 75bac2a2808..33870c3757a 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -679,6 +679,11 @@ Handle Buffer::ByteLength(const Arguments &args) { Handle 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(args[0]->ToObject()); Local fast_buffer = args[1]->ToObject();; uint32_t offset = args[2]->Uint32Value(); diff --git a/test/simple/test-buffer.js b/test/simple/test-buffer.js index 1aa4611010d..ae67d09d6ed 100644 --- a/test/simple/test-buffer.js +++ b/test/simple/test-buffer.js @@ -520,3 +520,7 @@ 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. +new Buffer('"pong"', 0, 6, 8031, '127.0.0.1') From 6461af1baa4ed1f9b1f521a9e7dda33b3b946eb5 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Thu, 19 May 2011 12:41:17 -0700 Subject: [PATCH 2/8] Fix buffer test --- test/simple/test-buffer.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/simple/test-buffer.js b/test/simple/test-buffer.js index ae67d09d6ed..ad062e6264a 100644 --- a/test/simple/test-buffer.js +++ b/test/simple/test-buffer.js @@ -523,4 +523,6 @@ assert.equal(0xef, b[3]); // This should not segfault the program. -new Buffer('"pong"', 0, 6, 8031, '127.0.0.1') +assert.throws(function() { + new Buffer('"pong"', 0, 6, 8031, '127.0.0.1') +}); From 21724ecaec63aad529a1ce2f0eebd82e52d399e3 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Fri, 20 May 2011 02:42:13 +0700 Subject: [PATCH 3/8] Share SSL context between server connections Fixes #1073. --- lib/crypto.js | 24 +++++++++++++++--------- lib/tls.js | 23 +++++++++++++++-------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/lib/crypto.js b/lib/crypto.js index c95103f3dfb..2a9225ae160 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -36,7 +36,7 @@ try { } -function Credentials(secureProtocol) { +function Credentials(secureProtocol, context) { if (!(this instanceof Credentials)) { return new Credentials(secureProtocol); } @@ -45,22 +45,28 @@ function Credentials(secureProtocol) { 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; + this.reuseContext = true; } else { - this.context.init(); - } + this.context = new SecureContext(); + if (secureProtocol) { + this.context.init(secureProtocol); + } else { + this.context.init(); + } + } } exports.Credentials = Credentials; -exports.createCredentials = function(options) { +exports.createCredentials = function(options, context) { if (!options) options = {}; - var c = new Credentials(options.secureProtocol); + var c = new Credentials(options.secureProtocol, context); + + if (context) return c; if (options.key) c.context.setKey(options.key); diff --git a/lib/tls.js b/lib/tls.js index 295c95a6308..781f4c53922 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -713,16 +713,23 @@ 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, + 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, - secureProtocol: self.secureProtocol, - 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, From 5d9dc1c6d5babaf033f40d90c13e87563c7f5de5 Mon Sep 17 00:00:00 2001 From: Alexandre Marangone Date: Thu, 19 May 2011 21:15:12 +0200 Subject: [PATCH 4/8] Adding os.totalmem() and os.freemem() for SunOS --- src/platform_sunos.cc | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/platform_sunos.cc b/src/platform_sunos.cc index 99488f1f0e4..66fb8b8daaa 100644 --- a/src/platform_sunos.cc +++ b/src/platform_sunos.cc @@ -216,12 +216,37 @@ int Platform::GetCPUInfo(Local *cpus) { double Platform::GetFreeMemory() { - return 0.0; + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *knp; + + double pagesize = static_cast(sysconf(_SC_PAGESIZE)); + ulong_t freemem; + + if((kc = kstat_open()) == NULL) + throw "could not open kstat"; + + ksp = kstat_lookup(kc, "unix", 0, "system_pages"); + + if(kstat_read(kc, ksp, NULL) == -1){ + throw "could not read kstat"; + } + else { + knp = (kstat_named_t *) kstat_data_lookup(ksp, "freemem"); + freemem = knp->value.ul; + } + + kstat_close(kc); + + return static_cast(freemem)*pagesize; } double Platform::GetTotalMemory() { - return 0.0; + double pagesize = static_cast(sysconf(_SC_PAGESIZE)); + double pages = static_cast(sysconf(_SC_PHYS_PAGES)); + + return pagesize*pages; } double Platform::GetUptime() { From 6c28fcf661f1233bb17bf63c5df1fe8920b5cedc Mon Sep 17 00:00:00 2001 From: Alexandre Marangone Date: Thu, 19 May 2011 21:20:08 +0200 Subject: [PATCH 5/8] (char *) casting for all strings args to kstat function to avoid warnings Fixes #1071. --- src/platform_sunos.cc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/platform_sunos.cc b/src/platform_sunos.cc index 66fb8b8daaa..aba2b2b975d 100644 --- a/src/platform_sunos.cc +++ b/src/platform_sunos.cc @@ -160,7 +160,7 @@ int Platform::GetCPUInfo(Local *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) { @@ -175,9 +175,9 @@ int Platform::GetCPUInfo(Local *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); } @@ -186,7 +186,7 @@ int Platform::GetCPUInfo(Local *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(); @@ -194,13 +194,13 @@ int Platform::GetCPUInfo(Local *cpus) { 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); @@ -226,13 +226,13 @@ double Platform::GetFreeMemory() { if((kc = kstat_open()) == NULL) throw "could not open kstat"; - ksp = kstat_lookup(kc, "unix", 0, "system_pages"); + 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, "freemem"); + knp = (kstat_named_t *) kstat_data_lookup(ksp, (char *)"freemem"); freemem = knp->value.ul; } @@ -260,12 +260,12 @@ double Platform::GetUptime() { 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; } From 8a0ac5b422ed3726b4aec090cd702c5e20c88a18 Mon Sep 17 00:00:00 2001 From: David Trejo Date: Thu, 19 May 2011 16:50:12 -0700 Subject: [PATCH 6/8] Add test for agent upgrade and example in docs --- doc/api/http.markdown | 56 ++++++++++++++-- test/simple/test-http-upgrade-agent.js | 90 ++++++++++++++++++++++++++ 2 files changed, 141 insertions(+), 5 deletions(-) create mode 100644 test/simple/test-http-upgrade-agent.js diff --git a/doc/api/http.markdown b/doc/api/http.markdown index f8da15106d8..4dadec75541 100644 --- a/doc/api/http.markdown +++ b/doc/api/http.markdown @@ -476,13 +476,59 @@ agent. The `http.getAgent()` function allows you to access the agents. ### 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. +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`: + + 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' diff --git a/test/simple/test-http-upgrade-agent.js b/test/simple/test-http-upgrade-agent.js new file mode 100644 index 00000000000..fd8c62622d4 --- /dev/null +++ b/test/simple/test-http-upgrade-agent.js @@ -0,0 +1,90 @@ +// 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('127.0.0.1', 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); +}); From 2de0611b43f1587c511de65ef50c647e77e28abb Mon Sep 17 00:00:00 2001 From: Brian White Date: Thu, 19 May 2011 15:09:10 -0700 Subject: [PATCH 7/8] Remove unused variable Fixes #1077 --- lib/crypto.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/crypto.js b/lib/crypto.js index 2a9225ae160..25aceaff4c6 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -47,7 +47,6 @@ function Credentials(secureProtocol, context) { if (context) { this.context = context; - this.reuseContext = true; } else { this.context = new SecureContext(); From 9c7f89bf56abd37a796fea621ad2e47dd33d2b82 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Fri, 20 May 2011 10:08:08 -0700 Subject: [PATCH 8/8] CryptoStream.prototype.readyState shoudn't reference fd Fixes #1069 --- lib/tls.js | 20 +++++++++++++++++--- test/simple/test-tls-set-encoding.js | 5 +++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/lib/tls.js b/lib/tls.js index 781f4c53922..291c31cedcf 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -216,9 +216,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 diff --git a/test/simple/test-tls-set-encoding.js b/test/simple/test-tls-set-encoding.js index 6634110fee6..2956eec0e28 100644 --- a/test/simple/test-tls-set-encoding.js +++ b/test/simple/test-tls-set-encoding.js @@ -54,6 +54,11 @@ server.listen(common.PORT, 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); console.log(message); server.close();