Comparing version 0.2.9 to 0.3.0
@@ -0,1 +1,11 @@ | ||
v0.3.0 - Dec 8th 2011 | ||
====================== | ||
* Node.js v0.4.x compatibility. | ||
* Code cleanups and efficiency improvements. | ||
* WebSocket server added, although this will still mainly be a client library. | ||
* WebSocket server certified to pass the Autobahn test suite. | ||
* Protocol improvements and corrections - such as handling (redundant) masks for empty fragments. | ||
* 'wscat' command line utility added, which can act as either client or server. | ||
v0.2.6 - Dec 3rd 2011 | ||
@@ -2,0 +12,0 @@ ====================== |
module.exports = require('./lib/WebSocket'); | ||
module.exports.Server = require('./lib/WebSocketServer'); | ||
module.exports.Sender = require('./lib/Sender'); | ||
module.exports.Receiver = require('./lib/Receiver'); |
@@ -66,6 +66,3 @@ /*! | ||
var firstLength = data[1] & 0x7f; | ||
if (firstLength == 0) { | ||
opcodes['1'].finish(null, null); | ||
} | ||
else if (firstLength < 126) { | ||
if (firstLength < 126) { | ||
opcodes['1'].getData(firstLength); | ||
@@ -123,6 +120,3 @@ } | ||
var firstLength = data[1] & 0x7f; | ||
if (firstLength == 0) { | ||
opcodes['2'].finish(null, null); | ||
} | ||
else if (firstLength < 126) { | ||
if (firstLength < 126) { | ||
opcodes['2'].getData(firstLength); | ||
@@ -181,6 +175,3 @@ } | ||
var firstLength = data[1] & 0x7f; | ||
if (firstLength == 0) { | ||
opcodes['8'].finish(null, null); | ||
} | ||
else if (firstLength < 126) { | ||
if (firstLength < 126) { | ||
opcodes['8'].getData(firstLength); | ||
@@ -241,6 +232,3 @@ } | ||
var firstLength = data[1] & 0x7f; | ||
if (firstLength == 0) { | ||
opcodes['9'].finish(null, null); | ||
} | ||
else if (firstLength < 126) { | ||
if (firstLength < 126) { | ||
opcodes['9'].getData(firstLength); | ||
@@ -282,6 +270,3 @@ } | ||
var firstLength = data[1] & 0x7f; | ||
if (firstLength == 0) { | ||
opcodes['10'].finish(null, null); | ||
} | ||
else if (firstLength < 126) { | ||
if (firstLength < 126) { | ||
opcodes['10'].getData(firstLength); | ||
@@ -371,2 +356,6 @@ } | ||
Receiver.prototype.expect = function(length, handler) { | ||
if (length == 0) { | ||
handler(null); | ||
return; | ||
} | ||
this.expectBuffer = this.allocateFromPool(length); | ||
@@ -481,3 +470,3 @@ this.expectOffset = 0; | ||
Receiver.prototype.unmask = function (mask, buf, binary) { | ||
if (mask != null) { | ||
if (mask != null && buf != null) { | ||
for (var i = 0, ll = buf.length; i < ll; i++) { | ||
@@ -484,0 +473,0 @@ buf[i] ^= mask[i % 4]; |
@@ -52,3 +52,3 @@ /*! | ||
Sender.prototype.close = function(code, data, options) { | ||
Sender.prototype.close = function(code, data, mask) { | ||
if (typeof code !== 'undefined') { | ||
@@ -62,4 +62,9 @@ if (typeof code !== 'number' || | ||
if (dataBuffer.length > 2) dataBuffer.write(data, 2); | ||
var buf = this.frameData(0x8, dataBuffer, true, true); // always masked | ||
this._socket.write(buf, 'binary'); | ||
var buf = this.frameData(0x8, dataBuffer, true, mask); | ||
try { | ||
this._socket.write(buf, 'binary'); | ||
} | ||
catch (e) { | ||
this.emit('error', e); | ||
} | ||
} | ||
@@ -76,3 +81,8 @@ | ||
var buf = this.frameData(0x9, data || '', true, mask); | ||
this._socket.write(buf, 'binary'); | ||
try { | ||
this._socket.write(buf, 'binary'); | ||
} | ||
catch (e) { | ||
this.emit('error', e); | ||
} | ||
} | ||
@@ -89,3 +99,8 @@ | ||
var buf = this.frameData(0xa, data || '', true, mask); | ||
this._socket.write(buf, 'binary'); | ||
try { | ||
this._socket.write(buf, 'binary'); | ||
} | ||
catch (e) { | ||
this.emit('error', e); | ||
} | ||
} | ||
@@ -108,3 +123,9 @@ | ||
if (finalFragment) this.firstFragment = true | ||
this._socket.write(buf, 'binary', cb); | ||
try { | ||
this._socket.write(buf, 'binary', cb); | ||
} | ||
catch (e) { | ||
if (typeof cb == 'function') cb(e); | ||
else this.emit('error', e); | ||
} | ||
} | ||
@@ -111,0 +132,0 @@ |
@@ -28,110 +28,94 @@ /*! | ||
function WebSocket(address, options) { | ||
var serverUrl = url.parse(address); | ||
if (!serverUrl.host) throw new Error('invalid url'); | ||
if (Object.prototype.toString.call(address) == '[object Array]') { | ||
/** | ||
* Act as server client | ||
*/ | ||
options = options || {}; | ||
options.origin = options.origin || null; | ||
options.protocolVersion = options.protocolVersion || protocolVersion; | ||
if (options.protocolVersion != 8 && options.protocolVersion != 13) { | ||
throw new Error('unsupported protocol version'); | ||
this._state = 'connecting'; | ||
this._isServer = true; | ||
var self = this; | ||
process.nextTick(function() { | ||
upgrade.apply(self, address); | ||
}); | ||
} | ||
else { | ||
/** | ||
* Act as regular client | ||
*/ | ||
this._isServer = false; | ||
var key = new Buffer(options.protocolVersion + '-' + Date.now()).toString('base64'); | ||
var shasum = crypto.createHash('sha1'); | ||
shasum.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'); | ||
var expectedServerKey = shasum.digest('base64'); | ||
var serverUrl = url.parse(address); | ||
if (!serverUrl.host) throw new Error('invalid url'); | ||
// node<=v0.4.x compatibility | ||
var isNodeV4 = false; | ||
var agent; | ||
if (/^v0\.4/.test(process.version)) { | ||
isNodeV4 = true; | ||
agent = new http.Agent({ | ||
host: serverUrl.hostname, | ||
port: serverUrl.port || 80 | ||
}); | ||
} | ||
options = options || {}; | ||
options.origin = options.origin || null; | ||
options.protocolVersion = options.protocolVersion || protocolVersion; | ||
if (options.protocolVersion != 8 && options.protocolVersion != 13) { | ||
throw new Error('unsupported protocol version'); | ||
} | ||
var requestOptions = { | ||
port: serverUrl.port || 80, | ||
host: serverUrl.hostname, | ||
headers: { | ||
'Connection': 'Upgrade', | ||
'Upgrade': 'websocket', | ||
'Sec-WebSocket-Version': options.protocolVersion, | ||
'Sec-WebSocket-Key': key | ||
var key = new Buffer(options.protocolVersion + '-' + Date.now()).toString('base64'); | ||
var shasum = crypto.createHash('sha1'); | ||
shasum.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'); | ||
var expectedServerKey = shasum.digest('base64'); | ||
// node<=v0.4.x compatibility | ||
var isNodeV4 = false; | ||
var agent; | ||
if (/^v0\.4/.test(process.version)) { | ||
isNodeV4 = true; | ||
agent = new http.Agent({ | ||
host: serverUrl.hostname, | ||
port: serverUrl.port || 80 | ||
}); | ||
} | ||
}; | ||
if (isNodeV4) { | ||
requestOptions.path = (serverUrl.pathname || '/') + (serverUrl.search || ''); | ||
requestOptions.agent = agent; | ||
} | ||
else requestOptions.path = serverUrl.path || '/'; | ||
if (options.origin) { | ||
if (options.protocolVersion < 13) requestOptions.headers['Sec-WebSocket-Origin'] = options.origin; | ||
else requestOptions.headers['Origin'] = options.origin; | ||
} | ||
var req = http.request(requestOptions); | ||
var self = this; | ||
(isNodeV4 ? agent : req).on('upgrade', function(res, socket, upgradeHead) { | ||
if (self._state == 'disconnected') { | ||
// client disconnected before server accepted connection | ||
self.emit('close'); | ||
socket.end(); | ||
return; | ||
var requestOptions = { | ||
port: serverUrl.port || 80, | ||
host: serverUrl.hostname, | ||
headers: { | ||
'Connection': 'Upgrade', | ||
'Upgrade': 'websocket', | ||
'Sec-WebSocket-Version': options.protocolVersion, | ||
'Sec-WebSocket-Key': key | ||
} | ||
}; | ||
if (isNodeV4) { | ||
requestOptions.path = (serverUrl.pathname || '/') + (serverUrl.search || ''); | ||
requestOptions.agent = agent; | ||
} | ||
var serverKey = res.headers['sec-websocket-accept']; | ||
if (typeof serverKey == 'undefined' || serverKey !== expectedServerKey) { | ||
self.emit('error', 'invalid server key'); | ||
socket.end(); | ||
return; | ||
else requestOptions.path = serverUrl.path || '/'; | ||
if (options.origin) { | ||
if (options.protocolVersion < 13) requestOptions.headers['Sec-WebSocket-Origin'] = options.origin; | ||
else requestOptions.headers['Origin'] = options.origin; | ||
} | ||
self._socket = socket; | ||
socket.setTimeout(0); | ||
socket.setNoDelay(true); | ||
socket.on('close', function() { | ||
if (self._state == 'disconnected') return; | ||
self._state = 'disconnected'; | ||
self.emit('close', self._closeCode || 1000, self._closeMessage || ''); | ||
var req = http.request(requestOptions); | ||
var self = this; | ||
(isNodeV4 ? agent : req).on('error', function(error) { | ||
self.emit('error', error); | ||
}); | ||
(isNodeV4 ? agent : req).on('upgrade', function(res, socket, upgradeHead) { | ||
if (self._state == 'disconnected') { | ||
// client disconnected before server accepted connection | ||
self.emit('close'); | ||
socket.end(); | ||
return; | ||
} | ||
var serverKey = res.headers['sec-websocket-accept']; | ||
if (typeof serverKey == 'undefined' || serverKey !== expectedServerKey) { | ||
self.emit('error', 'invalid server key'); | ||
socket.end(); | ||
return; | ||
} | ||
var receiver = new Receiver(); | ||
socket.on('data', function (data) { | ||
receiver.add(data); | ||
upgrade.call(self, res, socket, upgradeHead); | ||
}); | ||
receiver.on('text', function (data, flags) { | ||
flags = flags || {}; | ||
self.emit('message', data, flags); | ||
}); | ||
receiver.on('binary', function (data, flags) { | ||
flags = flags || {}; | ||
flags.binary = true; | ||
self.emit('message', data, flags); | ||
}); | ||
receiver.on('ping', function(data, flags) { | ||
flags = flags || {}; | ||
self.pong(data, {mask: true, binary: flags.binary === true}); | ||
self.emit('ping', data, flags); | ||
}); | ||
receiver.on('close', function(code, data, flags) { | ||
flags = flags || {}; | ||
self.close(code, data, {mask: true}); | ||
}); | ||
receiver.on('error', function(reason, errorCode) { | ||
// close the connection when the receiver reports a HyBi error code | ||
if (typeof errorCode !== 'undefined') { | ||
self.close(errorCode, '', {mask: true}); | ||
} | ||
self.emit('error', reason, errorCode); | ||
}); | ||
self._sender = new Sender(socket); | ||
self._state = 'connected'; | ||
self.emit('open'); | ||
req.end(); | ||
this._state = 'connecting'; | ||
} | ||
if (upgradeHead && upgradeHead.length > 0) receiver.add(upgradeHead); | ||
}); | ||
this._socket = null; | ||
var realEmit = this.emit; | ||
@@ -142,6 +126,2 @@ this.emit = function(event) { | ||
} | ||
req.end(); | ||
this._socket = null; | ||
this._state = 'connecting'; | ||
} | ||
@@ -159,7 +139,11 @@ | ||
* @param {Object} data to be sent to the server | ||
* @param {Object} Members - mask: boolean, binary: boolean | ||
* @api public | ||
*/ | ||
WebSocket.prototype.close = function(code, data, options) { | ||
WebSocket.prototype.close = function(code, data) { | ||
if (this._state == 'closing') return; | ||
if (this._state == 'connecting') { | ||
this._state = 'disconnected'; | ||
return; | ||
} | ||
if (this._state != 'connected') throw new Error('not connected'); | ||
@@ -170,3 +154,4 @@ try { | ||
this._closeMessage = data; | ||
this._sender.close(code, data, options); | ||
var mask = !this._isServer; | ||
this._sender.close(code, data, mask); | ||
this.terminate(); | ||
@@ -189,8 +174,5 @@ } | ||
if (this._state != 'connected') throw new Error('not connected'); | ||
try { | ||
this._sender.ping(data, options); | ||
} | ||
catch (e) { | ||
this.emit('error', e); | ||
} | ||
options = options || {}; | ||
if (typeof options.mask == 'undefined') options.mask = !this._isServer; | ||
this._sender.ping(data, options); | ||
} | ||
@@ -208,8 +190,5 @@ | ||
if (this._state != 'connected') throw new Error('not connected'); | ||
try { | ||
this._sender.pong(data, options); | ||
} | ||
catch (e) { | ||
this.emit('error', e); | ||
} | ||
options = options || {}; | ||
if (typeof options.mask == 'undefined') options.mask = !this._isServer; | ||
this._sender.pong(data, options); | ||
} | ||
@@ -239,2 +218,3 @@ | ||
options.fin = true; | ||
if (typeof options.mask == 'undefined') options.mask = !this._isServer; | ||
if (data instanceof fs.ReadStream) { | ||
@@ -252,8 +232,3 @@ startQueue(this); | ||
else { | ||
try { | ||
this._sender.send(data, options, cb); | ||
} | ||
catch (e) { | ||
this.emit('error', e); | ||
} | ||
this._sender.send(data, options, cb); | ||
} | ||
@@ -282,2 +257,4 @@ } | ||
if (typeof cb != 'function') throw new Error('callback must be provided'); | ||
options = options || {}; | ||
if (typeof options.mask == 'undefined') options.mask = !this._isServer; | ||
startQueue(this); | ||
@@ -324,2 +301,53 @@ var self = this; | ||
function upgrade(res, socket, upgradeHead) { | ||
this._socket = socket; | ||
socket.setTimeout(0); | ||
socket.setNoDelay(true); | ||
var self = this; | ||
socket.on('close', function() { | ||
if (self._state == 'disconnected') return; | ||
self._state = 'disconnected'; | ||
self.emit('close', self._closeCode || 1000, self._closeMessage || ''); | ||
}); | ||
var receiver = new Receiver(); | ||
socket.on('data', function (data) { | ||
receiver.add(data); | ||
}); | ||
receiver.on('text', function (data, flags) { | ||
flags = flags || {}; | ||
self.emit('message', data, flags); | ||
}); | ||
receiver.on('binary', function (data, flags) { | ||
flags = flags || {}; | ||
flags.binary = true; | ||
self.emit('message', data, flags); | ||
}); | ||
receiver.on('ping', function(data, flags) { | ||
flags = flags || {}; | ||
self.pong(data, {mask: !self._isServer, binary: flags.binary === true}); | ||
self.emit('ping', data, flags); | ||
}); | ||
receiver.on('close', function(code, data, flags) { | ||
flags = flags || {}; | ||
self.close(code, data, {mask: !self._isServer}); | ||
}); | ||
receiver.on('error', function(reason, errorCode) { | ||
// close the connection when the receiver reports a HyBi error code | ||
if (typeof errorCode !== 'undefined') { | ||
self.close(errorCode, '', {mask: !self._isServer}); | ||
} | ||
self.emit('error', reason, errorCode); | ||
}); | ||
this._sender = new Sender(socket); | ||
this._sender.on('error', function(error) { | ||
self.emit('error', e); | ||
}); | ||
this._state = 'connected'; | ||
this.emit('open'); | ||
if (upgradeHead && upgradeHead.length > 0) receiver.add(upgradeHead); | ||
} | ||
function startQueue(instance) { | ||
@@ -326,0 +354,0 @@ instance._queue = instance._queue || []; |
@@ -5,3 +5,3 @@ { | ||
"description": "simple and very fast websocket protocol client for node.js", | ||
"version": "0.2.9", | ||
"version": "0.3.0", | ||
"repository": { | ||
@@ -19,3 +19,3 @@ "type": "git", | ||
"engines": { | ||
"node": ">0.4.0" | ||
"node": ">=0.4.0" | ||
}, | ||
@@ -22,0 +22,0 @@ "dependencies": { |
@@ -24,3 +24,6 @@ var http = require('http') | ||
var srv = new Server(webServer); | ||
webServer.on('upgrade', (handler || validServer).bind(null, srv)); | ||
webServer.on('upgrade', function(req, socket) { | ||
webServer._socket = socket; | ||
(handler || validServer)(srv, req, socket); | ||
}); | ||
webServer.listen(port, '127.0.0.1', function() { cb(srv); }); | ||
@@ -165,2 +168,3 @@ } | ||
this.webServer.close(); | ||
if (this._socket) this._socket.end(); | ||
} |
@@ -26,57 +26,13 @@ var assert = require('assert') | ||
describe('WebSocket', function() { | ||
it('throws exception for invalid url', function(done) { | ||
try { | ||
var ws = new WebSocket('echo.websocket.org'); | ||
} | ||
catch (e) { | ||
done(); | ||
} | ||
}) | ||
it('text data can be sent and received', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.send('hi'); | ||
}); | ||
ws.on('message', function(message, flags) { | ||
assert.equal('hi', message); | ||
ws.terminate(); | ||
srv.close(); | ||
describe('#ctor', function() { | ||
it('throws exception for invalid url', function(done) { | ||
try { | ||
var ws = new WebSocket('echo.websocket.org'); | ||
} | ||
catch (e) { | ||
done(); | ||
}); | ||
}); | ||
} | ||
}) | ||
}) | ||
it('binary data can be sent and received as array', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var array = new Float32Array(5); | ||
for (var i = 0; i < array.length; ++i) array[i] = i / 2; | ||
ws.on('open', function() { | ||
ws.send(array, {binary: true}); | ||
}); | ||
ws.on('message', function(message, flags) { | ||
assert.ok(flags.binary); | ||
assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(message)))); | ||
ws.terminate(); | ||
srv.close(); | ||
done(); | ||
}); | ||
}); | ||
}) | ||
it('binary data can be sent and received as buffer', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var buf = new Buffer('foobar'); | ||
ws.on('open', function() { | ||
ws.send(buf, {binary: true}); | ||
}); | ||
ws.on('message', function(message, flags) { | ||
assert.ok(flags.binary); | ||
assert.ok(areArraysEqual(buf, message)); | ||
ws.terminate(); | ||
srv.close(); | ||
done(); | ||
}); | ||
}); | ||
}) | ||
it('can disconnect before connection is established', function(done) { | ||
@@ -90,2 +46,3 @@ server.createServer(++port, function(srv) { | ||
ws.on('close', function() { | ||
srv.close(); | ||
done(); | ||
@@ -95,25 +52,11 @@ }); | ||
}) | ||
it('send before connect should fail', function(done) { | ||
it('can close before connection is established', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
try { | ||
ws.send('hi'); | ||
} | ||
catch (e) { | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}) | ||
it('send without data should fail', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.close(1001); | ||
ws.on('open', function() { | ||
ws.send(); | ||
assert.fail('connect shouldnt be raised here'); | ||
}); | ||
srv.on('message', function(message, flags) { | ||
assert.equal(false, flags.masked); | ||
assert.equal('', message); | ||
ws.on('close', function() { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
@@ -123,14 +66,2 @@ }); | ||
}) | ||
it('ping before connect should fail', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
try { | ||
ws.ping(); | ||
} | ||
catch (e) { | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}) | ||
it('invalid server key is denied', function(done) { | ||
@@ -149,3 +80,2 @@ server.createServer(++port, server.handlers.invalidKey, function(srv) { | ||
ws.on('close', function() { | ||
srv.close(); | ||
done(); | ||
@@ -155,744 +85,847 @@ }); | ||
}) | ||
it('send calls optional callback when flushed', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.send('hi', function() { | ||
describe('#ping', function() { | ||
it('before connect should fail', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('error', function() {}); | ||
try { | ||
ws.ping(); | ||
} | ||
catch (e) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}) | ||
it('without message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.ping(); | ||
}); | ||
srv.on('ping', function(message) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}) | ||
it('send with unencoded message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.send('hi'); | ||
}) | ||
it('with message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.ping('hi'); | ||
}); | ||
srv.on('ping', function(message) { | ||
assert.equal('hi', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
}); | ||
srv.on('message', function(message, flags) { | ||
assert.equal(false, flags.masked); | ||
assert.equal('hi', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}) | ||
it('with encoded message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.ping('hi', {mask: true}); | ||
}); | ||
srv.on('ping', function(message, flags) { | ||
assert.ok(flags.masked); | ||
assert.equal('hi', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}) | ||
}) | ||
it('send with encoded message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.send('hi', {mask: true}); | ||
describe('#pong', function() { | ||
it('without message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.pong(); | ||
}); | ||
srv.on('pong', function(message) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
}); | ||
srv.on('message', function(message, flags) { | ||
assert.ok(flags.masked); | ||
assert.equal('hi', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}) | ||
it('with message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.pong('hi'); | ||
}); | ||
srv.on('pong', function(message) { | ||
assert.equal('hi', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}) | ||
it('send with unencoded binary message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var array = new Float32Array(5); | ||
for (var i = 0; i < array.length; ++i) array[i] = i / 2; | ||
ws.on('open', function() { | ||
ws.send(array, {binary: true}); | ||
}) | ||
it('with encoded message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.pong('hi', {mask: true}); | ||
}); | ||
srv.on('pong', function(message, flags) { | ||
assert.ok(flags.masked); | ||
assert.equal('hi', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
}); | ||
srv.on('message', function(message, flags) { | ||
assert.ok(flags.binary); | ||
assert.equal(false, flags.masked); | ||
assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(message)))); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
}); | ||
}) | ||
}) | ||
it('send with encoded binary message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var array = new Float32Array(5); | ||
for (var i = 0; i < array.length; ++i) array[i] = i / 2; | ||
ws.on('open', function() { | ||
ws.send(array, {mask: true, binary: true}); | ||
describe('#send', function() { | ||
it('very long binary data can be sent and received (with echoing server)', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var array = new Float32Array(5 * 1024 * 1024); | ||
for (var i = 0; i < array.length; ++i) array[i] = i / 5; | ||
ws.on('open', function() { | ||
ws.send(array, {binary: true}); | ||
}); | ||
ws.on('message', function(message, flags) { | ||
assert.ok(flags.binary); | ||
assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(message)))); | ||
ws.terminate(); | ||
srv.close(); | ||
done(); | ||
}); | ||
}); | ||
srv.on('message', function(message, flags) { | ||
assert.ok(flags.binary); | ||
assert.ok(flags.masked); | ||
assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(message)))); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}) | ||
it('can send and receive text data', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.send('hi'); | ||
}); | ||
ws.on('message', function(message, flags) { | ||
assert.equal('hi', message); | ||
ws.terminate(); | ||
srv.close(); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}) | ||
it('send with binary stream will send fragmented data', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var callbackFired = false; | ||
ws.on('open', function() { | ||
var fileStream = fs.createReadStream('test/fixtures/textfile'); | ||
fileStream.bufferSize = 100; | ||
ws.send(fileStream, {binary: true}, function(error) { | ||
assert.equal(null, error); | ||
callbackFired = true; | ||
}) | ||
it('send and receive binary data as an array', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var array = new Float32Array(5); | ||
for (var i = 0; i < array.length; ++i) array[i] = i / 2; | ||
ws.on('open', function() { | ||
ws.send(array, {binary: true}); | ||
}); | ||
ws.on('message', function(message, flags) { | ||
assert.ok(flags.binary); | ||
assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(message)))); | ||
ws.terminate(); | ||
srv.close(); | ||
done(); | ||
}); | ||
}); | ||
srv.on('message', function(data, flags) { | ||
assert.ok(flags.binary); | ||
assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile'), data)); | ||
ws.terminate(); | ||
}); | ||
ws.on('close', function() { | ||
assert.ok(callbackFired); | ||
srv.close(); | ||
done(); | ||
}); | ||
}); | ||
}) | ||
it('send with text stream will send fragmented data', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var callbackFired = false; | ||
ws.on('open', function() { | ||
var fileStream = fs.createReadStream('test/fixtures/textfile'); | ||
fileStream.setEncoding('utf8'); | ||
fileStream.bufferSize = 100; | ||
ws.send(fileStream, {binary: false}, function(error) { | ||
assert.equal(null, error); | ||
callbackFired = true; | ||
}) | ||
it('binary data can be sent and received as buffer', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var buf = new Buffer('foobar'); | ||
ws.on('open', function() { | ||
ws.send(buf, {binary: true}); | ||
}); | ||
ws.on('message', function(message, flags) { | ||
assert.ok(flags.binary); | ||
assert.ok(areArraysEqual(buf, message)); | ||
ws.terminate(); | ||
srv.close(); | ||
done(); | ||
}); | ||
}); | ||
srv.on('message', function(data, flags) { | ||
assert.ok(!flags.binary); | ||
assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); | ||
ws.terminate(); | ||
}); | ||
ws.on('close', function() { | ||
assert.ok(callbackFired); | ||
srv.close(); | ||
done(); | ||
}); | ||
}); | ||
}) | ||
it('stream before connect should fail', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
try { | ||
ws.stream(function() {}); | ||
} | ||
catch (e) { | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}) | ||
it('stream without callback should fail', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var payload = 'HelloWorld'; | ||
ws.on('open', function() { | ||
}) | ||
it('before connect should fail', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('error', function() {}); | ||
try { | ||
ws.stream(); | ||
ws.send('hi'); | ||
} | ||
catch (e) { | ||
ws.terminate(); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
done(); | ||
} | ||
}); | ||
}); | ||
}) | ||
it('ping without message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.ping(); | ||
}) | ||
it('without data should fail', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.send(); | ||
}); | ||
srv.on('message', function(message, flags) { | ||
assert.equal(false, flags.masked); | ||
assert.equal('', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
}); | ||
srv.on('ping', function(message) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}) | ||
it('calls optional callback when flushed', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.send('hi', function() { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}) | ||
it('ping with message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.ping('hi'); | ||
}) | ||
it('with unencoded message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.send('hi'); | ||
}); | ||
srv.on('message', function(message, flags) { | ||
assert.equal(false, flags.masked); | ||
assert.equal('hi', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
}); | ||
srv.on('ping', function(message) { | ||
assert.equal('hi', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}) | ||
it('with encoded message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.send('hi', {mask: true}); | ||
}); | ||
srv.on('message', function(message, flags) { | ||
assert.ok(flags.masked); | ||
assert.equal('hi', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}) | ||
it('ping with encoded message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.ping('hi', {mask: true}); | ||
}) | ||
it('with unencoded binary message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var array = new Float32Array(5); | ||
for (var i = 0; i < array.length; ++i) array[i] = i / 2; | ||
ws.on('open', function() { | ||
ws.send(array, {binary: true}); | ||
}); | ||
srv.on('message', function(message, flags) { | ||
assert.ok(flags.binary); | ||
assert.equal(false, flags.masked); | ||
assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(message)))); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
}); | ||
srv.on('ping', function(message, flags) { | ||
assert.ok(flags.masked); | ||
assert.equal('hi', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}) | ||
it('with encoded binary message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var array = new Float32Array(5); | ||
for (var i = 0; i < array.length; ++i) array[i] = i / 2; | ||
ws.on('open', function() { | ||
ws.send(array, {mask: true, binary: true}); | ||
}); | ||
srv.on('message', function(message, flags) { | ||
assert.ok(flags.binary); | ||
assert.ok(flags.masked); | ||
assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(message)))); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}) | ||
it('pong without message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.pong(); | ||
}) | ||
it('with binary stream will send fragmented data', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var callbackFired = false; | ||
ws.on('open', function() { | ||
var fileStream = fs.createReadStream('test/fixtures/textfile'); | ||
fileStream.bufferSize = 100; | ||
ws.send(fileStream, {binary: true}, function(error) { | ||
assert.equal(null, error); | ||
callbackFired = true; | ||
}); | ||
}); | ||
srv.on('message', function(data, flags) { | ||
assert.ok(flags.binary); | ||
assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile'), data)); | ||
ws.terminate(); | ||
}); | ||
ws.on('close', function() { | ||
assert.ok(callbackFired); | ||
srv.close(); | ||
done(); | ||
}); | ||
}); | ||
srv.on('pong', function(message) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}) | ||
it('with text stream will send fragmented data', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var callbackFired = false; | ||
ws.on('open', function() { | ||
var fileStream = fs.createReadStream('test/fixtures/textfile'); | ||
fileStream.setEncoding('utf8'); | ||
fileStream.bufferSize = 100; | ||
ws.send(fileStream, {binary: false}, function(error) { | ||
assert.equal(null, error); | ||
callbackFired = true; | ||
}); | ||
}); | ||
srv.on('message', function(data, flags) { | ||
assert.ok(!flags.binary); | ||
assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); | ||
ws.terminate(); | ||
}); | ||
ws.on('close', function() { | ||
assert.ok(callbackFired); | ||
srv.close(); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}) | ||
it('pong with message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.pong('hi'); | ||
}) | ||
it('will cause intermittent send to be delayed in order', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
var fileStream = fs.createReadStream('test/fixtures/textfile'); | ||
fileStream.setEncoding('utf8'); | ||
fileStream.bufferSize = 100; | ||
ws.send(fileStream); | ||
ws.send('foobar'); | ||
ws.send('baz'); | ||
}); | ||
var receivedIndex = 0; | ||
srv.on('message', function(data, flags) { | ||
++receivedIndex; | ||
if (receivedIndex == 1) { | ||
assert.ok(!flags.binary); | ||
assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); | ||
} | ||
else if (receivedIndex == 2) { | ||
assert.ok(!flags.binary); | ||
assert.equal('foobar', data); | ||
} | ||
else { | ||
assert.ok(!flags.binary); | ||
assert.equal('baz', data); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}); | ||
srv.on('pong', function(message) { | ||
assert.equal('hi', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}) | ||
it('will cause intermittent stream to be delayed in order', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
var fileStream = fs.createReadStream('test/fixtures/textfile'); | ||
fileStream.setEncoding('utf8'); | ||
fileStream.bufferSize = 100; | ||
ws.send(fileStream); | ||
var i = 0; | ||
ws.stream(function(error, send) { | ||
assert.ok(!error); | ||
if (++i == 1) send('foo'); | ||
else send('bar', true); | ||
}); | ||
}); | ||
var receivedIndex = 0; | ||
srv.on('message', function(data, flags) { | ||
++receivedIndex; | ||
if (receivedIndex == 1) { | ||
assert.ok(!flags.binary); | ||
assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); | ||
} | ||
else if (receivedIndex == 2) { | ||
assert.ok(!flags.binary); | ||
assert.equal('foobar', data); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}); | ||
}); | ||
}) | ||
it('pong with encoded message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.pong('hi', {mask: true}); | ||
}) | ||
it('will cause intermittent ping to be delivered', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
var fileStream = fs.createReadStream('test/fixtures/textfile'); | ||
fileStream.setEncoding('utf8'); | ||
fileStream.bufferSize = 100; | ||
ws.send(fileStream); | ||
ws.ping('foobar'); | ||
}); | ||
var receivedIndex = 0; | ||
srv.on('message', function(data, flags) { | ||
assert.ok(!flags.binary); | ||
assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); | ||
if (++receivedIndex == 2) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
srv.on('ping', function(data) { | ||
assert.equal('foobar', data); | ||
if (++receivedIndex == 2) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}); | ||
srv.on('pong', function(message, flags) { | ||
assert.ok(flags.masked); | ||
assert.equal('hi', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}) | ||
it('will cause intermittent pong to be delivered', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
var fileStream = fs.createReadStream('test/fixtures/textfile'); | ||
fileStream.setEncoding('utf8'); | ||
fileStream.bufferSize = 100; | ||
ws.send(fileStream); | ||
ws.pong('foobar'); | ||
}); | ||
var receivedIndex = 0; | ||
srv.on('message', function(data, flags) { | ||
assert.ok(!flags.binary); | ||
assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); | ||
if (++receivedIndex == 2) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
srv.on('pong', function(data) { | ||
assert.equal('foobar', data); | ||
if (++receivedIndex == 2) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}); | ||
}); | ||
}) | ||
it('close without invalid first argument throws exception', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
try { | ||
ws.close('error'); | ||
} | ||
catch (e) { | ||
}) | ||
it('will cause intermittent close to be delivered', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
var fileStream = fs.createReadStream('test/fixtures/textfile'); | ||
fileStream.setEncoding('utf8'); | ||
fileStream.bufferSize = 100; | ||
ws.send(fileStream); | ||
ws.close(1000, 'foobar'); | ||
}); | ||
ws.on('close', function() { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
ws.on('error', function() { /* That's quite alright -- a send was attempted after close */ }); | ||
srv.on('message', function(data, flags) { | ||
assert.ok(!flags.binary); | ||
assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); | ||
}); | ||
srv.on('close', function(code, data) { | ||
assert.equal(1000, code); | ||
assert.equal('foobar', data); | ||
}); | ||
}); | ||
}); | ||
}) | ||
}) | ||
it('close without reserved error code 1004 throws exception', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
describe('#stream', function() { | ||
it('very long binary data can be streamed', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var buffer = new Buffer(10 * 1024); | ||
for (var i = 0; i < buffer.length; ++i) buffer[i] = i % 0xff; | ||
ws.on('open', function() { | ||
var i = 0; | ||
var blockSize = 800; | ||
var bufLen = buffer.length; | ||
ws.stream({binary: true}, function(error, send) { | ||
assert.ok(!error); | ||
var start = i * blockSize; | ||
var toSend = Math.min(blockSize, bufLen - (i * blockSize)); | ||
var end = start + toSend; | ||
var isFinal = toSend < blockSize; | ||
send(buffer.slice(start, end), isFinal); | ||
i += 1; | ||
}); | ||
}); | ||
srv.on('message', function(data, flags) { | ||
assert.ok(flags.binary); | ||
assert.ok(areArraysEqual(buffer, data)); | ||
ws.terminate(); | ||
srv.close(); | ||
done(); | ||
}); | ||
}); | ||
}) | ||
it('stream before connect should fail', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('error', function() {}); | ||
try { | ||
ws.close(1004); | ||
ws.stream(function() {}); | ||
} | ||
catch (e) { | ||
ws.terminate(); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}); | ||
}) | ||
it('close without message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.close(1000); | ||
}) | ||
it('stream without callback should fail', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var payload = 'HelloWorld'; | ||
ws.on('open', function() { | ||
try { | ||
ws.stream(); | ||
} | ||
catch (e) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}); | ||
srv.on('close', function(code, message, flags) { | ||
assert.equal('', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
}); | ||
}) | ||
it('close with message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.close(1000, 'some reason'); | ||
}); | ||
srv.on('close', function(code, message, flags) { | ||
assert.ok(flags.masked); | ||
assert.equal('some reason', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
}); | ||
}) | ||
it('close with encoded message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.close(1000, 'some reason', {mask: true}); | ||
}); | ||
srv.on('close', function(code, message, flags) { | ||
assert.ok(flags.masked); | ||
assert.equal('some reason', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
}); | ||
}) | ||
it('close ends connection to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var connectedOnce = false; | ||
ws.on('open', function() { | ||
connectedOnce = true; | ||
ws.close(1000, 'some reason', {mask: true}); | ||
}); | ||
ws.on('close', function() { | ||
assert.ok(connectedOnce); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
}); | ||
}) | ||
it('very long binary data can be sent and received (with echoing server)', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var array = new Float32Array(5 * 1024 * 1024); | ||
for (var i = 0; i < array.length; ++i) array[i] = i / 5; | ||
ws.on('open', function() { | ||
ws.send(array, {binary: true}); | ||
}); | ||
ws.on('message', function(message, flags) { | ||
assert.ok(flags.binary); | ||
assert.ok(areArraysEqual(array, new Float32Array(getArrayBuffer(message)))); | ||
ws.terminate(); | ||
srv.close(); | ||
done(); | ||
}); | ||
}); | ||
}) | ||
it('very long binary data can be streamed', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var buffer = new Buffer(10 * 1024); | ||
for (var i = 0; i < buffer.length; ++i) buffer[i] = i % 0xff; | ||
ws.on('open', function() { | ||
var i = 0; | ||
var blockSize = 800; | ||
var bufLen = buffer.length; | ||
ws.stream({binary: true}, function(error, send) { | ||
assert.ok(!error); | ||
var start = i * blockSize; | ||
var toSend = Math.min(blockSize, bufLen - (i * blockSize)); | ||
var end = start + toSend; | ||
var isFinal = toSend < blockSize; | ||
send(buffer.slice(start, end), isFinal); | ||
i += 1; | ||
}) | ||
it('will cause intermittent send to be delayed in order', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var payload = 'HelloWorld'; | ||
ws.on('open', function() { | ||
var i = 0; | ||
ws.stream(function(error, send) { | ||
assert.ok(!error); | ||
if (++i == 1) { | ||
send(payload.substr(0, 5)); | ||
ws.send('foobar'); | ||
ws.send('baz'); | ||
} | ||
else { | ||
send(payload.substr(5, 5), true); | ||
} | ||
}); | ||
}); | ||
}); | ||
srv.on('message', function(data, flags) { | ||
assert.ok(flags.binary); | ||
assert.ok(areArraysEqual(buffer, data)); | ||
ws.terminate(); | ||
srv.close(); | ||
done(); | ||
}); | ||
}); | ||
}) | ||
it('streaming data will cause intermittent send to be delayed in order', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var payload = 'HelloWorld'; | ||
ws.on('open', function() { | ||
var i = 0; | ||
ws.stream(function(error, send) { | ||
assert.ok(!error); | ||
if (++i == 1) { | ||
send(payload.substr(0, 5)); | ||
ws.send('foobar'); | ||
ws.send('baz'); | ||
var receivedIndex = 0; | ||
srv.on('message', function(data, flags) { | ||
++receivedIndex; | ||
if (receivedIndex == 1) { | ||
assert.ok(!flags.binary); | ||
assert.equal(payload, data); | ||
} | ||
else if (receivedIndex == 2) { | ||
assert.ok(!flags.binary); | ||
assert.equal('foobar', data); | ||
} | ||
else { | ||
send(payload.substr(5, 5), true); | ||
assert.ok(!flags.binary); | ||
assert.equal('baz', data); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}); | ||
var receivedIndex = 0; | ||
srv.on('message', function(data, flags) { | ||
++receivedIndex; | ||
if (receivedIndex == 1) { | ||
}) | ||
it('will cause intermittent stream to be delayed in order', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var payload = 'HelloWorld'; | ||
ws.on('open', function() { | ||
var i = 0; | ||
ws.stream(function(error, send) { | ||
assert.ok(!error); | ||
if (++i == 1) { | ||
send(payload.substr(0, 5)); | ||
var i2 = 0; | ||
ws.stream(function(error, send) { | ||
assert.ok(!error); | ||
if (++i2 == 1) send('foo'); | ||
else send('bar', true); | ||
}); | ||
ws.send('baz'); | ||
} | ||
else send(payload.substr(5, 5), true); | ||
}); | ||
}); | ||
var receivedIndex = 0; | ||
srv.on('message', function(data, flags) { | ||
++receivedIndex; | ||
if (receivedIndex == 1) { | ||
assert.ok(!flags.binary); | ||
assert.equal(payload, data); | ||
} | ||
else if (receivedIndex == 2) { | ||
assert.ok(!flags.binary); | ||
assert.equal('foobar', data); | ||
} | ||
else if (receivedIndex == 3){ | ||
assert.ok(!flags.binary); | ||
assert.equal('baz', data); | ||
setTimeout(function() { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}, 1000); | ||
} | ||
else throw new Error('more messages than we actually sent just arrived'); | ||
}); | ||
}); | ||
}) | ||
it('will cause intermittent ping to be delivered', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var payload = 'HelloWorld'; | ||
ws.on('open', function() { | ||
var i = 0; | ||
ws.stream(function(error, send) { | ||
assert.ok(!error); | ||
if (++i == 1) { | ||
send(payload.substr(0, 5)); | ||
ws.ping('foobar'); | ||
} | ||
else { | ||
send(payload.substr(5, 5), true); | ||
} | ||
}); | ||
}); | ||
var receivedIndex = 0; | ||
srv.on('message', function(data, flags) { | ||
assert.ok(!flags.binary); | ||
assert.equal(payload, data); | ||
} | ||
else if (receivedIndex == 2) { | ||
assert.ok(!flags.binary); | ||
if (++receivedIndex == 2) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
srv.on('ping', function(data) { | ||
assert.equal('foobar', data); | ||
} | ||
else { | ||
assert.ok(!flags.binary); | ||
assert.equal('baz', data); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}); | ||
}) | ||
it('streaming data will cause intermittent stream to be delayed in order', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var payload = 'HelloWorld'; | ||
ws.on('open', function() { | ||
var i = 0; | ||
ws.stream(function(error, send) { | ||
assert.ok(!error); | ||
if (++i == 1) { | ||
send(payload.substr(0, 5)); | ||
var i2 = 0; | ||
ws.stream(function(error, send) { | ||
assert.ok(!error); | ||
if (++i2 == 1) send('foo'); | ||
else send('bar', true); | ||
}); | ||
ws.send('baz'); | ||
if (++receivedIndex == 2) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
else send(payload.substr(5, 5), true); | ||
}); | ||
}); | ||
var receivedIndex = 0; | ||
srv.on('message', function(data, flags) { | ||
++receivedIndex; | ||
if (receivedIndex == 1) { | ||
}) | ||
it('will cause intermittent pong to be delivered', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var payload = 'HelloWorld'; | ||
ws.on('open', function() { | ||
var i = 0; | ||
ws.stream(function(error, send) { | ||
assert.ok(!error); | ||
if (++i == 1) { | ||
send(payload.substr(0, 5)); | ||
ws.pong('foobar'); | ||
} | ||
else { | ||
send(payload.substr(5, 5), true); | ||
} | ||
}); | ||
}); | ||
var receivedIndex = 0; | ||
srv.on('message', function(data, flags) { | ||
assert.ok(!flags.binary); | ||
assert.equal(payload, data); | ||
} | ||
else if (receivedIndex == 2) { | ||
assert.ok(!flags.binary); | ||
if (++receivedIndex == 2) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
srv.on('pong', function(data) { | ||
assert.equal('foobar', data); | ||
} | ||
else if (receivedIndex == 3){ | ||
assert.ok(!flags.binary); | ||
assert.equal('baz', data); | ||
setTimeout(function() { | ||
if (++receivedIndex == 2) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}, 1000); | ||
} | ||
else throw new Error('more messages than we actually sent just arrived'); | ||
done(); | ||
} | ||
}); | ||
}); | ||
}); | ||
}) | ||
it('sending stream will cause intermittent send to be delayed in order', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
var fileStream = fs.createReadStream('test/fixtures/textfile'); | ||
fileStream.setEncoding('utf8'); | ||
fileStream.bufferSize = 100; | ||
ws.send(fileStream); | ||
ws.send('foobar'); | ||
ws.send('baz'); | ||
}); | ||
var receivedIndex = 0; | ||
srv.on('message', function(data, flags) { | ||
++receivedIndex; | ||
if (receivedIndex == 1) { | ||
assert.ok(!flags.binary); | ||
assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); | ||
} | ||
else if (receivedIndex == 2) { | ||
assert.ok(!flags.binary); | ||
assert.equal('foobar', data); | ||
} | ||
else { | ||
assert.ok(!flags.binary); | ||
assert.equal('baz', data); | ||
}) | ||
it('will cause intermittent close to be delivered', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var payload = 'HelloWorld'; | ||
var errorGiven = false; | ||
ws.on('open', function() { | ||
var i = 0; | ||
ws.stream(function(error, send) { | ||
if (++i == 1) { | ||
send(payload.substr(0, 5)); | ||
ws.close(1000, 'foobar'); | ||
} | ||
else if(i == 2) { | ||
send(payload.substr(5, 5), true); | ||
} | ||
else if (i == 3) { | ||
assert.ok(error); | ||
errorGiven = true; | ||
} | ||
}); | ||
}); | ||
ws.on('close', function() { | ||
assert.ok(errorGiven); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}); | ||
}) | ||
it('sending stream will cause intermittent stream to be delayed in order', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
var fileStream = fs.createReadStream('test/fixtures/textfile'); | ||
fileStream.setEncoding('utf8'); | ||
fileStream.bufferSize = 100; | ||
ws.send(fileStream); | ||
var i = 0; | ||
ws.stream(function(error, send) { | ||
assert.ok(!error); | ||
if (++i == 1) send('foo'); | ||
else send('bar', true); | ||
done(); | ||
}); | ||
}); | ||
var receivedIndex = 0; | ||
srv.on('message', function(data, flags) { | ||
++receivedIndex; | ||
if (receivedIndex == 1) { | ||
srv.on('message', function(data, flags) { | ||
assert.ok(!flags.binary); | ||
assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); | ||
} | ||
else if (receivedIndex == 2) { | ||
assert.ok(!flags.binary); | ||
assert.equal(payload, data); | ||
}); | ||
srv.on('close', function(code, data) { | ||
assert.equal(1000, code); | ||
assert.equal('foobar', data); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}); | ||
}); | ||
}) | ||
}) | ||
it('streaming data will cause intermittent ping to be delivered', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var payload = 'HelloWorld'; | ||
ws.on('open', function() { | ||
var i = 0; | ||
ws.stream(function(error, send) { | ||
assert.ok(!error); | ||
if (++i == 1) { | ||
send(payload.substr(0, 5)); | ||
ws.ping('foobar'); | ||
describe('#close', function() { | ||
it('will raise error callback, if any, if called during send stream', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var errorGiven = false; | ||
ws.on('open', function() { | ||
var fileStream = fs.createReadStream('test/fixtures/textfile'); | ||
fileStream.setEncoding('utf8'); | ||
fileStream.bufferSize = 100; | ||
ws.send(fileStream, function(error) { | ||
errorGiven = error != null; | ||
}); | ||
ws.close(1000, 'foobar'); | ||
}); | ||
ws.on('close', function() { | ||
setTimeout(function() { | ||
assert.ok(errorGiven); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}, 1000); | ||
}); | ||
}); | ||
}) | ||
it('without invalid first argument throws exception', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
try { | ||
ws.close('error'); | ||
} | ||
else { | ||
send(payload.substr(5, 5), true); | ||
catch (e) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}); | ||
var receivedIndex = 0; | ||
srv.on('message', function(data, flags) { | ||
assert.ok(!flags.binary); | ||
assert.equal(payload, data); | ||
if (++receivedIndex == 2) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
srv.on('ping', function(data) { | ||
assert.equal('foobar', data); | ||
if (++receivedIndex == 2) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}); | ||
}) | ||
it('sending stream will cause intermittent ping to be delivered', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
var fileStream = fs.createReadStream('test/fixtures/textfile'); | ||
fileStream.setEncoding('utf8'); | ||
fileStream.bufferSize = 100; | ||
ws.send(fileStream); | ||
ws.ping('foobar'); | ||
}); | ||
var receivedIndex = 0; | ||
srv.on('message', function(data, flags) { | ||
assert.ok(!flags.binary); | ||
assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); | ||
if (++receivedIndex == 2) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
srv.on('ping', function(data) { | ||
assert.equal('foobar', data); | ||
if (++receivedIndex == 2) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}); | ||
}) | ||
it('streaming data will cause intermittent pong to be delivered', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var payload = 'HelloWorld'; | ||
ws.on('open', function() { | ||
var i = 0; | ||
ws.stream(function(error, send) { | ||
assert.ok(!error); | ||
if (++i == 1) { | ||
send(payload.substr(0, 5)); | ||
ws.pong('foobar'); | ||
}) | ||
it('without reserved error code 1004 throws exception', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
try { | ||
ws.close(1004); | ||
} | ||
else { | ||
send(payload.substr(5, 5), true); | ||
catch (e) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}); | ||
var receivedIndex = 0; | ||
srv.on('message', function(data, flags) { | ||
assert.ok(!flags.binary); | ||
assert.equal(payload, data); | ||
if (++receivedIndex == 2) { | ||
}) | ||
it('without message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.close(1000); | ||
}); | ||
srv.on('close', function(code, message, flags) { | ||
assert.equal('', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
done(); | ||
}); | ||
}); | ||
srv.on('pong', function(data) { | ||
assert.equal('foobar', data); | ||
if (++receivedIndex == 2) { | ||
}) | ||
it('with message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.close(1000, 'some reason'); | ||
}); | ||
srv.on('close', function(code, message, flags) { | ||
assert.ok(flags.masked); | ||
assert.equal('some reason', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}) | ||
it('sending stream will cause intermittent pong to be delivered', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
var fileStream = fs.createReadStream('test/fixtures/textfile'); | ||
fileStream.setEncoding('utf8'); | ||
fileStream.bufferSize = 100; | ||
ws.send(fileStream); | ||
ws.pong('foobar'); | ||
}); | ||
var receivedIndex = 0; | ||
srv.on('message', function(data, flags) { | ||
assert.ok(!flags.binary); | ||
assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); | ||
if (++receivedIndex == 2) { | ||
}) | ||
it('with encoded message is successfully transmitted to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
ws.close(1000, 'some reason', {mask: true}); | ||
}); | ||
srv.on('close', function(code, message, flags) { | ||
assert.ok(flags.masked); | ||
assert.equal('some reason', message); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
srv.on('pong', function(data) { | ||
assert.equal('foobar', data); | ||
if (++receivedIndex == 2) { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
} | ||
}); | ||
}); | ||
}) | ||
it('streaming data will cause intermittent close to be delivered', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var payload = 'HelloWorld'; | ||
var errorGiven = false; | ||
ws.on('open', function() { | ||
var i = 0; | ||
ws.stream(function(error, send) { | ||
if (++i == 1) { | ||
send(payload.substr(0, 5)); | ||
ws.close(1000, 'foobar'); | ||
} | ||
else if(i == 2) { | ||
send(payload.substr(5, 5), true); | ||
} | ||
else if (i == 3) { | ||
assert.ok(error); | ||
errorGiven = true; | ||
} | ||
done(); | ||
}); | ||
}); | ||
ws.on('close', function() { | ||
assert.ok(errorGiven); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
srv.on('message', function(data, flags) { | ||
assert.ok(!flags.binary); | ||
assert.equal(payload, data); | ||
}); | ||
srv.on('close', function(code, data) { | ||
assert.equal(1000, code); | ||
assert.equal('foobar', data); | ||
}); | ||
}); | ||
}) | ||
it('sending stream will cause intermittent close to be delivered', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
ws.on('open', function() { | ||
var fileStream = fs.createReadStream('test/fixtures/textfile'); | ||
fileStream.setEncoding('utf8'); | ||
fileStream.bufferSize = 100; | ||
ws.send(fileStream); | ||
ws.close(1000, 'foobar'); | ||
}); | ||
ws.on('close', function() { | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}); | ||
ws.on('error', function() { /* That's quite alright -- a send was attempted after close */ }); | ||
srv.on('message', function(data, flags) { | ||
assert.ok(!flags.binary); | ||
assert.ok(areArraysEqual(fs.readFileSync('test/fixtures/textfile', 'utf8'), data)); | ||
}); | ||
srv.on('close', function(code, data) { | ||
assert.equal(1000, code); | ||
assert.equal('foobar', data); | ||
}); | ||
}); | ||
}) | ||
it('close during send stream causes error callback if given', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var errorGiven = false; | ||
ws.on('open', function() { | ||
var fileStream = fs.createReadStream('test/fixtures/textfile'); | ||
fileStream.setEncoding('utf8'); | ||
fileStream.bufferSize = 100; | ||
ws.send(fileStream, function(error) { | ||
errorGiven = error != null; | ||
}) | ||
it('ends connection to the server', function(done) { | ||
server.createServer(++port, function(srv) { | ||
var ws = new WebSocket('ws://localhost:' + port); | ||
var connectedOnce = false; | ||
ws.on('open', function() { | ||
connectedOnce = true; | ||
ws.close(1000, 'some reason', {mask: true}); | ||
}); | ||
ws.close(1000, 'foobar'); | ||
}); | ||
ws.on('close', function() { | ||
setTimeout(function() { | ||
assert.ok(errorGiven); | ||
ws.on('close', function() { | ||
assert.ok(connectedOnce); | ||
srv.close(); | ||
ws.terminate(); | ||
done(); | ||
}, 1000); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}) | ||
}) | ||
}) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
108194
27
2830
3
3