summaryrefslogtreecommitdiff
path: root/node_modules/socket.io/support
diff options
context:
space:
mode:
authorJules Laplace <jules@okfoc.us>2012-09-24 16:22:07 -0400
committerJules Laplace <jules@okfoc.us>2012-09-24 16:22:07 -0400
commit686106d544ecc3b6ffd4db2b665d3bc879a58d8c (patch)
treea5b5e50237cef70e12f0745371896e96f5f6d578 /node_modules/socket.io/support
ok
Diffstat (limited to 'node_modules/socket.io/support')
-rw-r--r--node_modules/socket.io/support/node-websocket-client/LICENSE27
-rw-r--r--node_modules/socket.io/support/node-websocket-client/Makefile22
-rw-r--r--node_modules/socket.io/support/node-websocket-client/README.md41
-rw-r--r--node_modules/socket.io/support/node-websocket-client/examples/client-unix.js12
-rw-r--r--node_modules/socket.io/support/node-websocket-client/examples/client.js10
-rw-r--r--node_modules/socket.io/support/node-websocket-client/examples/server-unix.js13
-rw-r--r--node_modules/socket.io/support/node-websocket-client/lib/websocket.js617
-rw-r--r--node_modules/socket.io/support/node-websocket-client/package.json22
-rw-r--r--node_modules/socket.io/support/node-websocket-client/test/test-basic.js68
-rw-r--r--node_modules/socket.io/support/node-websocket-client/test/test-client-close.js43
-rw-r--r--node_modules/socket.io/support/node-websocket-client/test/test-readonly-attrs.js43
-rw-r--r--node_modules/socket.io/support/node-websocket-client/test/test-ready-state.js26
-rw-r--r--node_modules/socket.io/support/node-websocket-client/test/test-server-close.js41
-rw-r--r--node_modules/socket.io/support/node-websocket-client/test/test-unix-send-fd.js63
-rw-r--r--node_modules/socket.io/support/node-websocket-client/test/test-unix-sockets.js46
15 files changed, 1094 insertions, 0 deletions
diff --git a/node_modules/socket.io/support/node-websocket-client/LICENSE b/node_modules/socket.io/support/node-websocket-client/LICENSE
new file mode 100644
index 0000000..f3c2eae
--- /dev/null
+++ b/node_modules/socket.io/support/node-websocket-client/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2010, Peter Griess <pg@std.in>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of node-websocket-client nor the names of its
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/node_modules/socket.io/support/node-websocket-client/Makefile b/node_modules/socket.io/support/node-websocket-client/Makefile
new file mode 100644
index 0000000..e7c849a
--- /dev/null
+++ b/node_modules/socket.io/support/node-websocket-client/Makefile
@@ -0,0 +1,22 @@
+# This makefile exists to help run tests.
+#
+# If TEST_UNIX is a non-empty value, runs tests for UNIX sockets. This
+# functionality is not in node-websocket-server at the moment.
+
+.PHONY: test
+
+all: test test-unix
+
+test:
+ for f in `ls -1 test/test-*.js | grep -v unix` ; do \
+ echo $$f ; \
+ node $$f ; \
+ done
+
+test-unix:
+ if [[ -n "$$TEST_UNIX" ]] ; then \
+ for f in `ls -1 test/test-*.js | grep unix` ; do \
+ echo $$f ; \
+ node $$f ; \
+ done \
+ fi
diff --git a/node_modules/socket.io/support/node-websocket-client/README.md b/node_modules/socket.io/support/node-websocket-client/README.md
new file mode 100644
index 0000000..8823a5c
--- /dev/null
+++ b/node_modules/socket.io/support/node-websocket-client/README.md
@@ -0,0 +1,41 @@
+A prototype [Web Socket](http://www.whatwg.org/specs/web-socket-protocol/)
+client implementation for [node.js](http://nodejs.org).
+
+Tested with
+[miksago/node-websocket-server](http://github.com/miksago/node-websocket-server)
+v1.2.00.
+
+Requires [nodejs](http://nodejs.org) 0.1.98 or later.
+
+## Installation
+
+Install this using `npm` as follows
+
+ npm install websocket-client
+
+... or just dump `lib/websocket.js` in your `$NODE_PATH`.
+
+## Usage
+
+ var sys = require('sys');
+ var WebSocket = require('websocket').WebSocket;
+
+ var ws = new WebSocket('ws://localhost:8000/biff', 'borf');
+ ws.addListener('data', function(buf) {
+ sys.debug('Got data: ' + sys.inspect(buf));
+ });
+ ws.onmessage = function(m) {
+ sys.debug('Got message: ' + m);
+ }
+
+## API
+
+This supports the `send()` and `onmessage()` APIs. The `WebSocket` object will
+also emit `data` events that are node `Buffer` objects, in case you want to
+work with something lower-level than strings.
+
+## Transports
+
+Multiple transports are supported, indicated by the scheme provided to the
+`WebSocket` constructor. `ws://` is a standard TCP-based Web Socket;
+`ws+unix://` allows connection to a UNIX socket at the given path.
diff --git a/node_modules/socket.io/support/node-websocket-client/examples/client-unix.js b/node_modules/socket.io/support/node-websocket-client/examples/client-unix.js
new file mode 100644
index 0000000..3bb23ba
--- /dev/null
+++ b/node_modules/socket.io/support/node-websocket-client/examples/client-unix.js
@@ -0,0 +1,12 @@
+var sys = require('sys');
+var WebSocket = require('../lib/websocket').WebSocket;
+
+var ws = new WebSocket('ws+unix://' + process.argv[2], 'boffo');
+
+ws.addListener('message', function(d) {
+ sys.debug('Received message: ' + d.toString('utf8'));
+});
+
+ws.addListener('open', function() {
+ ws.send('This is a message', 1);
+});
diff --git a/node_modules/socket.io/support/node-websocket-client/examples/client.js b/node_modules/socket.io/support/node-websocket-client/examples/client.js
new file mode 100644
index 0000000..259bf6e
--- /dev/null
+++ b/node_modules/socket.io/support/node-websocket-client/examples/client.js
@@ -0,0 +1,10 @@
+var sys = require('sys');
+var WebSocket = require('../lib/websocket').WebSocket;
+
+var ws = new WebSocket('ws://localhost:8000/biff', 'borf');
+ws.addListener('data', function(buf) {
+ sys.debug('Got data: ' + sys.inspect(buf));
+});
+ws.onmessage = function(m) {
+ sys.debug('Got message: ' + m);
+}
diff --git a/node_modules/socket.io/support/node-websocket-client/examples/server-unix.js b/node_modules/socket.io/support/node-websocket-client/examples/server-unix.js
new file mode 100644
index 0000000..912be0e
--- /dev/null
+++ b/node_modules/socket.io/support/node-websocket-client/examples/server-unix.js
@@ -0,0 +1,13 @@
+var sys = require('sys');
+var ws = require('websocket-server/ws');
+
+var srv = ws.createServer({ debug : true});
+srv.addListener('connection', function(s) {
+ sys.debug('Got a connection!');
+
+ s._req.socket.addListener('fd', function(fd) {
+ sys.debug('Got an fd: ' + fd);
+ });
+});
+
+srv.listen(process.argv[2]);
diff --git a/node_modules/socket.io/support/node-websocket-client/lib/websocket.js b/node_modules/socket.io/support/node-websocket-client/lib/websocket.js
new file mode 100644
index 0000000..4f7f734
--- /dev/null
+++ b/node_modules/socket.io/support/node-websocket-client/lib/websocket.js
@@ -0,0 +1,617 @@
+var assert = require('assert');
+var buffer = require('buffer');
+var crypto = require('crypto');
+var events = require('events');
+var http = require('http');
+var net = require('net');
+var urllib = require('url');
+var sys = require('util');
+
+var FRAME_NO = 0;
+var FRAME_LO = 1;
+var FRAME_HI = 2;
+
+// Values for readyState as per the W3C spec
+var CONNECTING = 0;
+var OPEN = 1;
+var CLOSING = 2;
+var CLOSED = 3;
+
+var debugLevel = parseInt(process.env.NODE_DEBUG, 16);
+var debug = (debugLevel & 0x4) ?
+ function() { sys.error.apply(this, arguments); } :
+ function() { };
+
+// Generate a Sec-WebSocket-* value
+var createSecretKey = function() {
+ // How many spaces will we be inserting?
+ var numSpaces = 1 + Math.floor(Math.random() * 12);
+ assert.ok(1 <= numSpaces && numSpaces <= 12);
+
+ // What is the numerical value of our key?
+ var keyVal = (Math.floor(
+ Math.random() * (4294967295 / numSpaces)
+ ) * numSpaces);
+
+ // Our string starts with a string representation of our key
+ var s = keyVal.toString();
+
+ // Insert 'numChars' worth of noise in the character ranges
+ // [0x21, 0x2f] (14 characters) and [0x3a, 0x7e] (68 characters)
+ var numChars = 1 + Math.floor(Math.random() * 12);
+ assert.ok(1 <= numChars && numChars <= 12);
+
+ for (var i = 0; i < numChars; i++) {
+ var pos = Math.floor(Math.random() * s.length + 1);
+
+ var c = Math.floor(Math.random() * (14 + 68));
+ c = (c <= 14) ?
+ String.fromCharCode(c + 0x21) :
+ String.fromCharCode((c - 14) + 0x3a);
+
+ s = s.substring(0, pos) + c + s.substring(pos, s.length);
+ }
+
+ // We shoudln't have any spaces in our value until we insert them
+ assert.equal(s.indexOf(' '), -1);
+
+ // Insert 'numSpaces' worth of spaces
+ for (var i = 0; i < numSpaces; i++) {
+ var pos = Math.floor(Math.random() * (s.length - 1)) + 1;
+ s = s.substring(0, pos) + ' ' + s.substring(pos, s.length);
+ }
+
+ assert.notEqual(s.charAt(0), ' ');
+ assert.notEqual(s.charAt(s.length), ' ');
+
+ return s;
+};
+
+// Generate a challenge sequence
+var createChallenge = function() {
+ var c = '';
+ for (var i = 0; i < 8; i++) {
+ c += String.fromCharCode(Math.floor(Math.random() * 255));
+ }
+
+ return c;
+};
+
+// Get the value of a secret key string
+//
+// This strips non-digit values and divides the result by the number of
+// spaces found.
+var secretKeyValue = function(sk) {
+ var ns = 0;
+ var v = 0;
+
+ for (var i = 0; i < sk.length; i++) {
+ var cc = sk.charCodeAt(i);
+
+ if (cc == 0x20) {
+ ns++;
+ } else if (0x30 <= cc && cc <= 0x39) {
+ v = v * 10 + cc - 0x30;
+ }
+ }
+
+ return Math.floor(v / ns);
+}
+
+// Get the to-be-hashed value of a secret key string
+//
+// This takes the result of secretKeyValue() and encodes it in a big-endian
+// byte string
+var secretKeyHashValue = function(sk) {
+ var skv = secretKeyValue(sk);
+
+ var hv = '';
+ hv += String.fromCharCode((skv >> 24) & 0xff);
+ hv += String.fromCharCode((skv >> 16) & 0xff);
+ hv += String.fromCharCode((skv >> 8) & 0xff);
+ hv += String.fromCharCode((skv >> 0) & 0xff);
+
+ return hv;
+};
+
+// Compute the secret key signature based on two secret key strings and some
+// handshaking data.
+var computeSecretKeySignature = function(s1, s2, hs) {
+ assert.equal(hs.length, 8);
+
+ var hash = crypto.createHash('md5');
+
+ hash.update(secretKeyHashValue(s1));
+ hash.update(secretKeyHashValue(s2));
+ hash.update(hs);
+
+ return hash.digest('binary');
+};
+
+// Return a hex representation of the given binary string; used for debugging
+var str2hex = function(str) {
+ var hexChars = [
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f'
+ ];
+
+ var out = '';
+ for (var i = 0; i < str.length; i++) {
+ var c = str.charCodeAt(i);
+ out += hexChars[(c & 0xf0) >>> 4];
+ out += hexChars[c & 0x0f];
+ out += ' ';
+ }
+
+ return out.trim();
+};
+
+// Get the scheme for a URL, undefined if none is found
+var getUrlScheme = function(url) {
+ var i = url.indexOf(':');
+ if (i == -1) {
+ return undefined;
+ }
+
+ return url.substring(0, i);
+};
+
+// Set a constant on the given object
+var setConstant = function(obj, name, value) {
+ Object.defineProperty(obj, name, {
+ get : function() {
+ return value;
+ }
+ });
+};
+
+// WebSocket object
+//
+// This is intended to conform (mostly) to http://dev.w3.org/html5/websockets/
+//
+// N.B. Arguments are parsed in the anonymous function at the bottom of the
+// constructor.
+var WebSocket = function(url, proto, opts) {
+ events.EventEmitter.call(this);
+
+ // Retain a reference to our object
+ var self = this;
+
+ // State of our end of the connection
+ var readyState = CONNECTING;
+
+ // Whether or not the server has sent a close handshake
+ var serverClosed = false;
+
+ // Our underlying net.Stream instance
+ var stream = undefined;
+
+ opts = opts || {
+ origin : 'http://www.example.com'
+ };
+
+ // Frame parsing functions
+ //
+ // These read data from the given buffer starting at the given offset,
+ // looking for the end of the current frame. If found, the current frame is
+ // emitted and the function returns. Only a single frame is processed at a
+ // time.
+ //
+ // The number of bytes read to complete a frame is returned, which the
+ // caller is to use to advance along its buffer. If 0 is returned, no
+ // completed frame bytes were found, and the caller should probably enqueue
+ // the buffer as a continuation of the current message. If a complete frame
+ // is read, the function is responsible for resting 'frameType'.
+
+ // Framing data
+ var frameType = FRAME_NO;
+ var bufs = [];
+ var bufsBytes = 0;
+
+ // Frame-parsing functions
+ var frameFuncs = [
+ // FRAME_NO
+ function(buf, off) {
+ if (buf[off] & 0x80) {
+ frameType = FRAME_HI;
+ } else {
+ frameType = FRAME_LO;
+ }
+
+ return 1;
+ },
+
+ // FRAME_LO
+ function(buf, off) {
+ debug('frame_lo(' + sys.inspect(buf) + ', ' + off + ')');
+
+ // Find the first instance of 0xff, our terminating byte
+ for (var i = off; i < buf.length && buf[i] != 0xff; i++)
+ ;
+
+ // We didn't find a terminating byte
+ if (i >= buf.length) {
+ return 0;
+ }
+
+ // We found a terminating byte; collect all bytes into a single buffer
+ // and emit it
+ var mb = null;
+ if (bufs.length == 0) {
+ mb = buf.slice(off, i);
+ } else {
+ mb = new buffer.Buffer(bufsBytes + i);
+
+ var mbOff = 0;
+ bufs.forEach(function(b) {
+ b.copy(mb, mbOff, 0, b.length);
+ mbOff += b.length;
+ });
+
+ assert.equal(mbOff, bufsBytes);
+
+ // Don't call Buffer.copy() if we're coping 0 bytes. Rather
+ // than being a no-op, this will trigger a range violation on
+ // the destination.
+ if (i > 0) {
+ buf.copy(mb, mbOff, off, i);
+ }
+
+ // We consumed all of the buffers that we'd been saving; clear
+ // things out
+ bufs = [];
+ bufsBytes = 0;
+ }
+
+ process.nextTick(function() {
+ var b = mb;
+ return function() {
+ var m = b.toString('utf8');
+
+ self.emit('data', b);
+ self.emit('message', m); // wss compat
+
+ if (self.onmessage) {
+ self.onmessage({data: m});
+ }
+ };
+ }());
+
+ frameType = FRAME_NO;
+ return i - off + 1;
+ },
+
+ // FRAME_HI
+ function(buf, off) {
+ debug('frame_hi(' + sys.inspect(buf) + ', ' + off + ')');
+
+ if (buf[off] !== 0) {
+ throw new Error('High-byte framing not supported.');
+ }
+
+ serverClosed = true;
+ return 1;
+ }
+ ];
+
+ // Handle data coming from our socket
+ var dataListener = function(buf) {
+ if (buf.length <= 0 || serverClosed) {
+ return;
+ }
+
+ debug('dataListener(' + sys.inspect(buf) + ')');
+
+ var off = 0;
+ var consumed = 0;
+
+ do {
+ if (frameType < 0 || frameFuncs.length <= frameType) {
+ throw new Error('Unexpected frame type: ' + frameType);
+ }
+
+ assert.equal(bufs.length === 0, bufsBytes === 0);
+ assert.ok(off < buf.length);
+
+ consumed = frameFuncs[frameType](buf, off);
+ off += consumed;
+ } while (!serverClosed && consumed > 0 && off < buf.length);
+
+ if (serverClosed) {
+ serverCloseHandler();
+ }
+
+ if (consumed == 0) {
+ bufs.push(buf.slice(off, buf.length));
+ bufsBytes += buf.length - off;
+ }
+ };
+
+ // Handle incoming file descriptors
+ var fdListener = function(fd) {
+ self.emit('fd', fd);
+ };
+
+ // Handle errors from any source (HTTP client, stream, etc)
+ var errorListener = function(e) {
+ process.nextTick(function() {
+ self.emit('wserror', e);
+
+ if (self.onerror) {
+ self.onerror(e);
+ }
+ });
+ };
+
+ // Finish the closing process; destroy the socket and tell the application
+ // that we've closed.
+ var finishClose = self.finishClose = function() {
+ readyState = CLOSED;
+ if (stream) {
+ stream.end();
+ stream.destroy();
+ stream = undefined;
+ }
+
+ process.nextTick(function() {
+ self.emit('close');
+ if (self.onclose) {
+ self.onclose();
+ }
+ });
+ };
+
+ // Send a close frame to the server
+ var sendClose = function() {
+ assert.equal(OPEN, readyState);
+
+ readyState = CLOSING;
+ stream.write('\xff\x00', 'binary');
+ };
+
+ // Handle a close packet sent from the server
+ var serverCloseHandler = function() {
+ assert.ok(serverClosed);
+ assert.ok(readyState === OPEN || readyState === CLOSING);
+
+ bufs = [];
+ bufsBytes = 0;
+
+ // Handle state transitions asynchronously so that we don't change
+ // readyState before the application has had a chance to process data
+ // events which are already in the delivery pipeline. For example, a
+ // 'data' event could be delivered with a readyState of CLOSING if we
+ // received both frames in the same packet.
+ process.nextTick(function() {
+ if (readyState === OPEN) {
+ sendClose();
+ }
+
+ finishClose();
+ });
+ };
+
+ // External API
+ self.close = function(timeout) {
+ if (readyState === CONNECTING) {
+ // If we're still in the process of connecting, the server is not
+ // in a position to understand our close frame. Just nuke the
+ // connection and call it a day.
+ finishClose();
+ } else if (readyState === OPEN) {
+ sendClose();
+
+ if (timeout) {
+ setTimeout(finishClose, timeout * 1000);
+ }
+ }
+ };
+
+ self.send = function(str, fd) {
+ if (readyState != OPEN) {
+ return;
+ }
+
+ stream.write('\x00', 'binary');
+ stream.write(str, 'utf8', fd);
+ stream.write('\xff', 'binary');
+ };
+
+ // wss compat
+ self.write = self.send;
+
+ setConstant(self, 'url', url);
+
+ Object.defineProperty(self, 'readyState', {
+ get : function() {
+ return readyState;
+ }
+ });
+
+ // Connect and perform handshaking with the server
+ (function() {
+ // Parse constructor arguments
+ if (!url) {
+ throw new Error('Url and must be specified.');
+ }
+
+ // Secrets used for handshaking
+ var key1 = createSecretKey();
+ var key2 = createSecretKey();
+ var challenge = createChallenge();
+
+ debug(
+ 'key1=\'' + str2hex(key1) + '\'; ' +
+ 'key2=\'' + str2hex(key2) + '\'; ' +
+ 'challenge=\'' + str2hex(challenge) + '\''
+ );
+
+ var httpHeaders = {
+ 'Connection' : 'Upgrade',
+ 'Upgrade' : 'WebSocket',
+ 'Sec-WebSocket-Key1' : key1,
+ 'Sec-WebSocket-Key2' : key2
+ };
+ if (opts.origin) {
+ httpHeaders['Origin'] = opts.origin;
+ }
+ if (proto) {
+ httpHeaders['Sec-WebSocket-Protocol'] = proto;
+ }
+
+ var httpPath = '/';
+
+ // Create the HTTP client that we'll use for handshaking. We'll cannabalize
+ // its socket via the 'upgrade' event and leave it to rot.
+ //
+ // N.B. The ws+unix:// scheme makes use of the implementation detail
+ // that http.Client passes its constructor arguments through,
+ // un-inspected to net.Stream.connect(). The latter accepts a
+ // string as its first argument to connect to a UNIX socket.
+ var opt = {};
+ var agent = null;
+ switch (getUrlScheme(url)) {
+ case 'ws':
+ var u = urllib.parse(url);
+ agent = new http.Agent({
+ host: u.hostname,
+ port: u.port || 80
+ });
+ opt.agent = agent;
+ opt.host = u.hostname;
+ opt.port = u.port || 80;
+ opt.path = (u.pathname || '/') + (u.search || '');
+ opt.headers = httpHeaders;
+ break;
+
+ case 'ws+unix':
+ var sockPath = url.substring('ws+unix://'.length, url.length);
+ var u = urllib.parse(url);
+ agent = new http.Agent({
+ host: 'localhost',
+ port: sockPath
+ });
+ opt.agent = agent;
+ opt.host = 'localhost';
+ opt.path = sockPath;
+ opt.headers = httpHeaders;
+ break;
+
+ default:
+ throw new Error('Invalid URL scheme \'' + urlScheme + '\' specified.');
+ }
+
+ var httpReq = http.request(opt, function() { });
+ var upgradeHandler = (function() {
+ var data = undefined;
+
+ return function(req, s, head) {
+ req.socket.setNoDelay(true);
+ stream = s;
+
+ if (readyState == CLOSED) {
+ stream.end();
+ stream.destroy();
+ stream = undefined;
+ return;
+ }
+
+ stream.on('data', function(d) {
+ if (d.length <= 0) {
+ return;
+ }
+
+ if (!data) {
+ data = d;
+ } else {
+ var data2 = new buffer.Buffer(data.length + d.length);
+
+ data.copy(data2, 0, 0, data.length);
+ d.copy(data2, data.length, 0, d.length);
+
+ data = data2;
+ }
+
+ if (data.length >= 16) {
+ var expected = computeSecretKeySignature(key1, key2, challenge);
+ var actual = data.slice(0, 16).toString('binary');
+
+ // Handshaking fails; we're donezo
+ if (actual != expected) {
+ debug(
+ 'expected=\'' + str2hex(expected) + '\'; ' +
+ 'actual=\'' + str2hex(actual) + '\''
+ );
+
+ process.nextTick(function() {
+ // N.B. Emit 'wserror' here, as 'error' is a reserved word in the
+ // EventEmitter world, and gets thrown.
+ self.emit(
+ 'wserror',
+ new Error('Invalid handshake from server:' +
+ 'expected \'' + str2hex(expected) + '\', ' +
+ 'actual \'' + str2hex(actual) + '\''
+ )
+ );
+
+ if (self.onerror) {
+ self.onerror();
+ }
+
+ finishClose();
+ });
+ }
+
+ // Un-register our data handler and add the one to be used
+ // for the normal, non-handshaking case. If we have extra
+ // data left over, manually fire off the handler on
+ // whatever remains.
+ //
+ // XXX: This is lame. We should only remove the listeners
+ // that we added.
+ httpReq.removeAllListeners('upgrade');
+ stream.removeAllListeners('data');
+ stream.on('data', dataListener);
+
+ readyState = OPEN;
+
+ process.nextTick(function() {
+ self.emit('open');
+
+ if (self.onopen) {
+ self.onopen();
+ }
+ });
+
+ // Consume any leftover data
+ if (data.length > 16) {
+ stream.emit('data', data.slice(16, data.length));
+ }
+ }
+ });
+ stream.on('fd', fdListener);
+ stream.on('error', errorListener);
+ stream.on('close', function() {
+ errorListener(new Error('Stream closed unexpectedly.'));
+ });
+
+ stream.emit('data', head);
+ };
+ })();
+ agent.on('upgrade', upgradeHandler); // node v0.4
+ httpReq.on('upgrade', upgradeHandler); // node v0.5+
+
+ httpReq.write(challenge, 'binary');
+ httpReq.end();
+ })();
+};
+sys.inherits(WebSocket, events.EventEmitter);
+exports.WebSocket = WebSocket;
+
+// Add some constants to the WebSocket object
+setConstant(WebSocket.prototype, 'CONNECTING', CONNECTING);
+setConstant(WebSocket.prototype, 'OPEN', OPEN);
+setConstant(WebSocket.prototype, 'CLOSING', CLOSING);
+setConstant(WebSocket.prototype, 'CLOSED', CLOSED);
+
+// vim:ts=4 sw=4 et
diff --git a/node_modules/socket.io/support/node-websocket-client/package.json b/node_modules/socket.io/support/node-websocket-client/package.json
new file mode 100644
index 0000000..c6e221f
--- /dev/null
+++ b/node_modules/socket.io/support/node-websocket-client/package.json
@@ -0,0 +1,22 @@
+{
+ "name" : "websocket-client",
+ "version" : "1.0.0",
+ "description" : "An HTML5 Web Sockets client",
+ "author" : "Peter Griess <pg@std.in>",
+ "engines" : {
+ "node" : ">=0.1.98"
+ },
+ "repositories" : [
+ {
+ "type" : "git",
+ "url" : "http://github.com/pgriess/node-websocket-client.git"
+ }
+ ],
+ "licenses" : [
+ {
+ "type" : "BSD",
+ "url" : "http://github.com/pgriess/node-websocket-client/blob/master/LICENSE"
+ }
+ ],
+ "main" : "./lib/websocket"
+}
diff --git a/node_modules/socket.io/support/node-websocket-client/test/test-basic.js b/node_modules/socket.io/support/node-websocket-client/test/test-basic.js
new file mode 100644
index 0000000..f010424
--- /dev/null
+++ b/node_modules/socket.io/support/node-websocket-client/test/test-basic.js
@@ -0,0 +1,68 @@
+// Verify that we can connect to a WebSocket server, exchange messages, and
+// shut down cleanly.
+
+var assert = require('assert');
+var WebSocket = require('../lib/websocket').WebSocket;
+var WebSocketServer = require('websocket-server/ws/server').Server;
+
+var PORT = 1024 + Math.floor(Math.random() * 4096);
+var C_MSG = 'Client test: ' + (Math.random() * 100);
+var S_MSG = 'Server test: ' + (Math.random() * 100);
+
+var serverGotConnection = false;
+var clientGotOpen = false;
+var clientGotData = false;
+var clientGotMessage = false;
+var serverGotMessage = false;
+var serverGotClose = false;
+var clientGotClose = false;
+
+var wss = new WebSocketServer();
+wss.listen(PORT, 'localhost');
+wss.on('connection', function(c) {
+ serverGotConnection = true;
+
+ c.on('message', function(m) {
+ assert.equal(m, C_MSG);
+ serverGotMessage = true;
+
+ c.close();
+ });
+
+ c.on('close', function() {
+ serverGotClose = true;
+ wss.close();
+ });
+
+ c.write(S_MSG);
+});
+
+var ws = new WebSocket('ws://localhost:' + PORT + '/', 'biff');
+ws.on('open', function() {
+ clientGotOpen = true;
+});
+ws.on('data', function(buf) {
+ assert.equal(typeof buf, 'object');
+ assert.equal(buf.toString('utf8'), S_MSG);
+
+ clientGotData = true;
+
+ ws.send(C_MSG);
+});
+ws.onmessage = function(m) {
+ assert.deepEqual(m, {data : S_MSG});
+ clientGotMessage = true;
+};
+ws.onclose = function() {
+ clientGotClose = true;
+};
+
+process.on('exit', function() {
+ assert.ok(serverGotConnection);
+ assert.ok(clientGotOpen);
+ assert.ok(clientGotData);
+ assert.ok(clientGotMessage);
+ assert.ok(serverGotMessage);
+ assert.ok(serverGotClose);
+ assert.ok(clientGotClose);
+});
diff --git a/node_modules/socket.io/support/node-websocket-client/test/test-client-close.js b/node_modules/socket.io/support/node-websocket-client/test/test-client-close.js
new file mode 100644
index 0000000..76fb81f
--- /dev/null
+++ b/node_modules/socket.io/support/node-websocket-client/test/test-client-close.js
@@ -0,0 +1,43 @@
+// Verify that a connection can be closed gracefully from the client.
+
+var assert = require('assert');
+var WebSocket = require('../lib/websocket').WebSocket;
+var WebSocketServer = require('websocket-server/ws/server').Server;
+
+var PORT = 1024 + Math.floor(Math.random() * 4096);
+var C_MSG = 'Client test: ' + (Math.random() * 100);
+
+var serverGotClientMessage = false;
+var clientGotServerClose = false;
+var serverGotClientClose = false;
+
+var wss = new WebSocketServer();
+wss.listen(PORT, 'localhost');
+wss.on('connection', function(c) {
+ c.on('message', function(m) {
+ assert.equal(m, C_MSG);
+ serverGotClientMessage = true;
+ });
+ c.on('close', function() {
+ serverGotClientClose = true;
+ wss.close();
+ });
+});
+
+var ws = new WebSocket('ws://localhost:' + PORT);
+ws.onopen = function() {
+ ws.send(C_MSG);
+
+ // XXX: Add a timeout here
+ ws.close(5);
+};
+ws.onclose = function() {
+ assert.equal(ws.CLOSED, ws.readyState);
+ clientGotServerClose = true;
+};
+
+process.on('exit', function() {
+ assert.ok(serverGotClientMessage);
+ assert.ok(clientGotServerClose);
+ assert.ok(serverGotClientClose);
+});
diff --git a/node_modules/socket.io/support/node-websocket-client/test/test-readonly-attrs.js b/node_modules/socket.io/support/node-websocket-client/test/test-readonly-attrs.js
new file mode 100644
index 0000000..de896b3
--- /dev/null
+++ b/node_modules/socket.io/support/node-websocket-client/test/test-readonly-attrs.js
@@ -0,0 +1,43 @@
+// Verify that some attributes of a WebSocket object are read-only.
+
+var assert = require('assert');
+var sys = require('sys');
+var WebSocket = require('../lib/websocket').WebSocket;
+var WebSocketServer = require('websocket-server/ws/server').Server;
+
+var PORT = 1024 + Math.floor(Math.random() * 4096);
+
+var wss = new WebSocketServer();
+wss.listen(PORT, 'localhost');
+wss.on('connection', function(c) {
+ c.close();
+ wss.close();
+});
+var ws = new WebSocket('ws://localhost:' + PORT + '/', 'biff');
+ws.on('open', function() {
+ assert.equal(ws.CONNECTING, 0);
+ try {
+ ws.CONNECTING = 13;
+ assert.equal(
+ ws.CONNECTING, 0,
+ 'Should not have been able to set read-only CONNECTING attribute'
+ );
+ } catch (e) {
+ assert.equal(e.type, 'no_setter_in_callback');
+ }
+
+ assert.equal(ws.OPEN, 1);
+ assert.equal(ws.CLOSING, 2);
+ assert.equal(ws.CLOSED, 3);
+
+ assert.equal(ws.url, 'ws://localhost:' + PORT + '/');
+ try {
+ ws.url = 'foobar';
+ assert.equal(
+ ws.url, 'ws://localhost:' + PORT + '/',
+ 'Should not have been able to set read-only url attribute'
+ );
+ } catch (e) {
+ assert.equal(e.type, 'no_setter_in_callback');
+ }
+});
diff --git a/node_modules/socket.io/support/node-websocket-client/test/test-ready-state.js b/node_modules/socket.io/support/node-websocket-client/test/test-ready-state.js
new file mode 100644
index 0000000..8fcbd4c
--- /dev/null
+++ b/node_modules/socket.io/support/node-websocket-client/test/test-ready-state.js
@@ -0,0 +1,26 @@
+// Verify that readyState transitions are implemented correctly
+
+var assert = require('assert');
+var WebSocket = require('../lib/websocket').WebSocket;
+var WebSocketServer = require('websocket-server/ws/server').Server;
+
+var PORT = 1024 + Math.floor(Math.random() * 4096);
+
+var wss = new WebSocketServer();
+wss.listen(PORT, 'localhost');
+wss.on('connection', function(c) {
+ c.close();
+});
+
+var ws = new WebSocket('ws://localhost:' + PORT);
+assert.equal(ws.readyState, ws.CONNECTING);
+ws.onopen = function() {
+ assert.equal(ws.readyState, ws.OPEN);
+
+ ws.close();
+ assert.ok(ws.readyState == ws.CLOSING);
+};
+ws.onclose = function() {
+ assert.equal(ws.readyState, ws.CLOSED);
+ wss.close();
+};
diff --git a/node_modules/socket.io/support/node-websocket-client/test/test-server-close.js b/node_modules/socket.io/support/node-websocket-client/test/test-server-close.js
new file mode 100644
index 0000000..a286429
--- /dev/null
+++ b/node_modules/socket.io/support/node-websocket-client/test/test-server-close.js
@@ -0,0 +1,41 @@
+// Verify that a connection can be closed gracefully from the server.
+
+var assert = require('assert');
+var WebSocket = require('../lib/websocket').WebSocket;
+var WebSocketServer = require('websocket-server/ws/server').Server;
+
+var PORT = 1024 + Math.floor(Math.random() * 4096);
+var S_MSG = 'Server test: ' + (Math.random() * 100);
+
+var clientGotServerMessage = false;
+var clientGotServerClose = false;
+var serverGotClientClose = false;
+
+var wss = new WebSocketServer();
+wss.listen(PORT, 'localhost');
+wss.on('connection', function(c) {
+ c.on('close', function() {
+ serverGotClientClose = true;
+ wss.close();
+ });
+
+ c.write(S_MSG);
+ c.close();
+});
+
+var ws = new WebSocket('ws://localhost:' + PORT);
+ws.onmessage = function(m) {
+ assert.deepEqual(m, {data: S_MSG});
+
+ clientGotServerMessage = true;
+};
+ws.onclose = function() {
+ assert.equal(ws.CLOSED, ws.readyState);
+ clientGotServerClose = true;
+};
+
+process.on('exit', function() {
+ assert.ok(clientGotServerMessage);
+ assert.ok(clientGotServerClose);
+ assert.ok(serverGotClientClose);
+});
diff --git a/node_modules/socket.io/support/node-websocket-client/test/test-unix-send-fd.js b/node_modules/socket.io/support/node-websocket-client/test/test-unix-send-fd.js
new file mode 100644
index 0000000..8f1c28d
--- /dev/null
+++ b/node_modules/socket.io/support/node-websocket-client/test/test-unix-send-fd.js
@@ -0,0 +1,63 @@
+// Verify that both sides of the WS connection can both send and receive file
+// descriptors.
+
+var assert = require('assert');
+var fs = require('fs');
+var path = require('path');
+var sys = require('sys');
+var WebSocket = require('../lib/websocket').WebSocket;
+var WebSocketServer = require('websocket-server/ws/server').Server;
+
+var PATH = path.join(__dirname, 'sock.' + process.pid);
+var C_MSG = 'Client test: ' + (Math.random() * 100);
+var S_MSG = 'Server test: ' + (Math.random() * 100);
+
+var clientReceivedData = false;
+var clientReceivedFD = false;
+var serverReceivedData = false;
+var serverReceivedFD = false;
+
+var wss = new WebSocketServer();
+wss.on('listening', function() {
+ var ws = new WebSocket('ws+unix://' + PATH);
+ ws.on('data', function(d) {
+ assert.equal(d.toString('utf8'), S_MSG);
+
+ clientReceivedData = true;
+
+ ws.send(C_MSG, 1);
+ ws.close();
+ });
+ ws.on('fd', function(fd) {
+ assert.ok(fd >= 0);
+
+ clientReceivedFD = true;
+ });
+});
+wss.on('connection', function(c) {
+ c.write(S_MSG, 0);
+ c._req.socket.on('fd', function(fd) {
+ assert.ok(fd >= 0);
+
+ serverReceivedFD = true;
+ });
+ c.on('message', function(d) {
+ assert.equal(d, C_MSG);
+
+ serverReceivedData = true;
+
+ wss.close();
+ });
+});
+wss.listen(PATH);
+
+process.on('exit', function() {
+ assert.ok(clientReceivedFD);
+ assert.ok(clientReceivedData);
+ assert.ok(serverReceivedFD);
+ assert.ok(serverReceivedData);
+
+ try {
+ fs.unlinkSync(PATH);
+ } catch (e) { }
+});
diff --git a/node_modules/socket.io/support/node-websocket-client/test/test-unix-sockets.js b/node_modules/socket.io/support/node-websocket-client/test/test-unix-sockets.js
new file mode 100644
index 0000000..5cbf094
--- /dev/null
+++ b/node_modules/socket.io/support/node-websocket-client/test/test-unix-sockets.js
@@ -0,0 +1,46 @@
+// Verify that we can connect to a server over UNIX domain sockets.
+
+var assert = require('assert');
+var fs = require('fs');
+var path = require('path');
+var sys = require('sys');
+var WebSocket = require('../lib/websocket').WebSocket;
+var WebSocketServer = require('websocket-server/ws/server').Server;
+
+var PATH = path.join(__dirname, 'sock.' + process.pid);
+var S_MSG = 'Server test: ' + (Math.random() * 100);
+
+var serverGotConnection = false;
+var clientGotOpen = false;
+var clientGotData = false;
+
+var wss = new WebSocketServer();
+wss.on('listening', function() {
+ var ws = new WebSocket('ws+unix://' + PATH);
+ ws.on('open', function() {
+ clientGotOpen = true;
+
+ ws.close();
+ });
+ ws.on('data', function(d) {
+ assert.equal(d.toString('utf8'), S_MSG);
+ clientGotData = true;
+ });
+});
+wss.on('connection', function(c) {
+ serverGotConnection = true;
+
+ c.write(S_MSG);
+ wss.close();
+});
+wss.listen(PATH);
+
+process.on('exit', function() {
+ assert.ok(serverGotConnection);
+ assert.ok(clientGotOpen);
+ assert.ok(clientGotData);
+
+ try {
+ fs.unlinkSync(PATH);
+ } catch(e) { }
+});