Socket
Socket
Sign inDemoInstall

engine.io

Package Overview
Dependencies
76
Maintainers
1
Versions
147
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.2.2 to 0.3.0

11

History.md
0.3.0 / 2012-10-04
==================
* socket: `writeBuffer` now gets sliced, and is recoverable after `close` [afshinm]
* server: expect ping from client and send interval with handshake [cadorn]
* polling-jsonp: prevent client breakage with utf8 whitespace
* socket: fix `flush` and `drain` events
* socket: add `send` callback [afshinm]
* transport: avoid unhandled error events for stale transports
* README: documentation improvements [EugenDueck]
0.2.2 / 2012-08-26

@@ -3,0 +14,0 @@ ==================

3

lib/parser.js

@@ -1,2 +0,1 @@

/**

@@ -6,2 +5,2 @@ * Exposes the client parser to avoid code repetition.

module.exports = require('engine.io-client').parser;
module.exports = require('engine.io-client/lib/parser');

@@ -10,2 +10,3 @@

, crypto = require('crypto')
, base64id = require('base64id')
, transports = require('./transports')

@@ -115,18 +116,2 @@ , EventEmitter = require('events').EventEmitter

/**
* Generates an id.
*
* @api private
*/
Server.prototype.id = function(){
var rand = new Buffer(15);
this.sequenceNumber = (this.sequenceNumber + 1) | 0;
rand.writeInt32BE(this.sequenceNumber, 11);
crypto.randomBytes(12).copy(rand);
var id = rand.toString('base64').replace(/\//g, '_').replace(/\+/g, '-');
if (this.clients[id]) return this.id();
return id;
};
/**
* Closes all clients.

@@ -183,3 +168,3 @@ *

Server.prototype.handshake = function(transport, req){
var id = this.id();
var id = base64id.generateId();

@@ -186,0 +171,0 @@ debug('handshaking client "%d"', id);

@@ -26,2 +26,3 @@ /**

this.writeBuffer = [];
this.packetsFn = [];

@@ -62,2 +63,3 @@ this.setTransport(transport);

, upgrades: this.getAvailableUpgrades()
, pingInterval: this.server.pingInterval
, pingTimeout: this.server.pingTimeout

@@ -67,3 +69,3 @@ }));

this.emit('open');
this.ping();
this.setPingTimeout();
};

@@ -81,6 +83,8 @@

switch (packet.type) {
case 'pong':
debug('got pong');
case 'ping':
debug('got ping');
this.sendPacket('pong');
this.emit('heartbeat');
this.ping();
this.setPingTimeout();
break;

@@ -107,3 +111,3 @@

/**
* Pings a client.
* Sets and resets ping timeout timer based on client pings.
*

@@ -113,14 +117,8 @@ * @api private

Socket.prototype.ping = function () {
clearTimeout(this.pingIntervalTimer);
Socket.prototype.setPingTimeout = function () {
var self = this;
this.pingIntervalTimer = setTimeout(function () {
debug('writing ping packet - expected pong in %sms', self.server.pingTimeout);
self.sendPacket('ping');
clearTimeout(self.pingTimeoutTimer);
self.pingTimeoutTimer = setTimeout(function () {
self.onClose('ping timeout');
}, self.server.pingTimeout);
}, this.server.pingInterval);
clearTimeout(self.pingTimeoutTimer);
self.pingTimeoutTimer = setTimeout(function () {
self.onClose('ping timeout');
}, self.server.pingInterval + self.server.pingTimeout);
};

@@ -141,2 +139,4 @@

this.transport.once('close', this.onClose.bind(this, 'transport close'));
//this function will manage packet events (also message callbacks)
this.setupSendCallback();
};

@@ -183,3 +183,3 @@

self.setTransport(transport);
self.ping();
self.setPingTimeout();
self.flush();

@@ -218,2 +218,3 @@ clearTimeout(upgradeTimeout);

if ('closed' != this.readyState) {
this.packetsFn = [];
this.clearTransport();

@@ -226,5 +227,26 @@ this.readyState = 'closed';

/**
* Setup and manage send callback
*
* @api private
*/
Socket.prototype.setupSendCallback = function () {
var self = this;
//the message was sent successfully, execute the callback
this.transport.on('drain', function() {
if (self.packetsFn.length > 0) {
var seqFn = self.packetsFn.splice(0,1)[0];
if ('function' == typeof seqFn) {
debug('executing send callback');
seqFn(self.transport);
}
}
});
};
/**
* Sends a message packet.
*
* @param {String} message
* @param {Function} callback
* @return {Socket} for chaining

@@ -234,4 +256,4 @@ * @api public

Socket.prototype.send = function (data) {
this.sendPacket('message', data);
Socket.prototype.send = function (data, callback) {
this.sendPacket('message', data, callback);
return this;

@@ -248,6 +270,10 @@ };

Socket.prototype.sendPacket = function (type, data) {
Socket.prototype.sendPacket = function (type, data, callback) {
if ('closing' != this.readyState) {
debug('sending packet "%s" (%s)', type, data);
this.writeBuffer.push({ type: type, data: data });
//add send callback to object
if (callback) {
this.packetsFn.push(callback);
}
this.flush();

@@ -254,0 +280,0 @@ }

@@ -57,4 +57,11 @@

JSONP.prototype.doWrite = function (data) {
data = this.head + JSON.stringify(data) + this.foot;
// we must output valid javascript, not valid json
// see: http://timelessrepo.com/json-isnt-a-javascript-subset
var js = JSON.stringify(data)
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029');
// prepare response
data = this.head + js + this.foot;
// explicit UTF-8 is required for pages not served under utf

@@ -61,0 +68,0 @@ var headers = {

{
"name": "engine.io"
, "version": "0.2.2"
, "version": "0.3.0"
, "description": "The realtime engine behind Socket.IO. Provides the foundation of a bidirectional connection between client and server"

@@ -8,8 +8,10 @@ , "main": "./lib/engine.io"

, "contributors": [
{ "name": "Eugen Dueck", "web": "https://github.com/EugenDueck" }
{ "name": "Eugen Dueck", "web": "https://github.com/EugenDueck" },
{ "name": "Afshin Mehrabani", "web": "https://github.com/afshinm" }
]
, "dependencies": {
"debug": "0.6.0"
, "engine.io-client": "0.2.2"
, "engine.io-client": "0.3.0"
, "ws": "~0.4.21"
, "base64id": "0.1.0"
}

@@ -16,0 +18,0 @@ , "devDependencies": {

@@ -61,3 +61,3 @@ # Engine.IO: the realtime engine

<script>
var socket = new eio.Socket({ host: 'localhost', port: 80 });
var socket = new eio.Socket('ws://localhost/');
socket.on('open', function () {

@@ -137,7 +137,5 @@ socket.on('message', function (data) { });

- **Options**
- `path` (`String`) default prefix path (`/engine.io`)
- `resource` (`String`): name of resource for this server (`default`).
Setting a resource allows you to initialize multiple engine.io
endpoints on the same host without them interfering, and without
changing the `path` directly.
endpoints on the same host without them interfering.
- `policyFile` (`Boolean`): whether to handle policy file requests (`true`)

@@ -253,2 +251,3 @@ - `destroyUpgrade` (`Boolean`): destroy unhandled upgrade requests (`true`)

- `String`: a string or any object implementing `toString()`, with outgoing data
- `Function`: optional, a callback executed when the message gets flushed out by the transport
- **Returns** `Socket` for chaining

@@ -269,2 +268,14 @@ - `close`

## Debug / logging
Engine.IO is powered by [debug](http://github.com/visionmedia/debug).
In order to see all the debug output, run your app with the env variable
`DEBUG` including the desired scope.
To see the output from all of Engine.IO's debugging scopes you can use:
```
DEBUG=engine* node myapp
```
## Transports

@@ -271,0 +282,0 @@

/**
* Instrument.
*/
var fs = require('fs');
if (process.env.DEBUG) {
require.extensions['.js'] = function(mod, filename){
var js = fs.readFileSync(filename, 'utf8');
// Profiling support
js = js.replace(/^ *\/\/ *(start|end): *([^\n]+)/gm, function(_, type, expr){
switch (type) {
case 'start': return 'console.time(' + expr + ');';
case 'end': return 'console.timeEnd(' + expr + ');';
}
});
// Debugging
js = js.replace(/^ *\/\/ *debug: *([^\n,]+) *([^\n]+)?/gm, function(_, fmt, args){
fmt = fmt.replace(/"/g, '\\"');
return 'console.error(" client\033[90m ' + fmt + '\033[0m"' + (args || '') + ');';
});
js = js.replace(/^ *\/\/ *assert: ([^,]+) *, *([^\n]+)/gm, function(_, expr, msg){
return 'if (!(' + expr + ')) console.error(" client assert\033[31m %s. (%s)\033[0m", ' + msg + ', "' + expr + '");';
});
mod._compile(js, filename);
};
}
/**
* Expose `eio` global.
*/
eio = require('../index');
global.eio = require('../index');

@@ -44,3 +12,3 @@ /**

eioc = require('engine.io-client');
global.eioc = require('engine.io-client');

@@ -51,3 +19,3 @@ /**

request = require('superagent');
global.request = require('superagent');

@@ -58,3 +26,3 @@ /**

expect = require('expect.js');
global.expect = require('expect.js');

@@ -65,3 +33,3 @@ /**

listen = function (opts, fn) {
global.listen = function (opts, fn) {
if ('function' == typeof opts) {

@@ -72,3 +40,3 @@ fn = opts;

var e = eio.listen(null, opts, function () {
var e = global.eio.listen(null, opts, function () {
fn(e.httpServer.address().port);

@@ -78,3 +46,3 @@ });

return e;
}
};

@@ -81,0 +49,0 @@ /**

@@ -0,1 +1,2 @@

/*global eio,listen,request,expect*/

@@ -7,3 +8,3 @@ /**

var net = require('net')
, http = require('http')
, http = require('http');

@@ -10,0 +11,0 @@ /**

@@ -0,1 +1,2 @@

/*global eio,eioc,listen,request,expect*/

@@ -8,3 +9,3 @@ /**

, parser = eio.parser
, WebSocket = require('ws')
, WebSocket = require('ws');

@@ -21,3 +22,3 @@ /**

request.get('http://localhost:%d/engine.io/default/'.s(port))
.send({ transport: 'tobi' }) // no tobi transport - outrageous
.query({ transport: 'tobi' }) // no tobi transport - outrageous
.end(function (res) {

@@ -34,3 +35,3 @@ expect(res.status).to.be(500);

request.get('http://localhost:%d/engine.io/default/'.s(port))
.send({ transport: 'constructor' })
.query({ transport: 'constructor' })
.end(function (res) {

@@ -46,3 +47,3 @@ expect(res.status).to.be(500);

request.get('http://localhost:%d/engine.io/default/'.s(port))
.send({ transport: 'polling', sid: 'test' })
.query({ transport: 'polling', sid: 'test' })
.end(function (res) {

@@ -60,3 +61,3 @@ expect(res.status).to.be(500);

request.get('http://localhost:%d/engine.io/default/'.s(port))
.send({ transport: 'polling' })
.query({ transport: 'polling' })
.end(function (res) {

@@ -74,3 +75,3 @@ // hack-obtain sid

request.get('http://localhost:%d/engine.io/default/'.s(port))
.send({ transport: 'polling' })
.query({ transport: 'polling' })
.end(function (res) {

@@ -87,3 +88,3 @@ var sid = res.text.match(/"sid":"([^"]+)"/)[1];

request.get('http://localhost:%d/engine.io/default/'.s(port))
.send({ transport: 'polling' })
.query({ transport: 'polling' })
.end(function (res) {

@@ -219,3 +220,3 @@ expect(res.headers['set-cookie']).to.be(undefined);

it('should trigger on server if the client does not pong', function (done) {
var opts = { allowUpgrades: false, pingInterval: 5, pingTimeout: 5 }
var opts = { allowUpgrades: false, pingInterval: 5, pingTimeout: 5 };
var engine = listen(opts, function (port) {

@@ -234,3 +235,3 @@ var socket = new eioc.Socket('http://localhost:%d'.s(port));

it('should trigger on client if server does not meet ping timeout', function (done) {
var opts = { allowUpgrades: false, pingTimeout: 10 };
var opts = { allowUpgrades: false, pingInterval: 5, pingTimeout: 5 };
var engine = listen(opts, function (port) {

@@ -253,3 +254,3 @@ var socket = new eioc.Socket('ws://localhost:%d'.s(port));

var socket = new eioc.Socket('ws://localhost:%d'.s(port))
, total = 2
, total = 2;

@@ -276,3 +277,3 @@ function onClose (reason, err) {

var socket = new eioc.Socket('ws://localhost:%d'.s(port))
, total = 2
, total = 2;

@@ -302,3 +303,3 @@ engine.on('connection', function (conn) {

var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] })
, total = 2
, total = 2;

@@ -327,3 +328,3 @@ engine.on('connection', function (conn) {

var socket = new eioc.Socket('ws://localhost:%d'.s(port))
, total = 2
, total = 2;

@@ -354,3 +355,3 @@ engine.on('connection', function (conn) {

var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] })
, total = 2
, total = 2;

@@ -390,7 +391,7 @@ engine.on('connection', function (conn) {

it('should trigger if a poll request is ongoing and the underlying'
+ ' socket closes, as in a browser tab close', function (done) {
it('should trigger if a poll request is ongoing and the underlying' +
' socket closes, as in a browser tab close', function (done) {
var engine = listen({ allowUpgrades: false }, function (port) {
var socket = new eioc.Socket('ws://localhost:%d'.s(port))
, serverSocket
, serverSocket;

@@ -436,3 +437,3 @@ engine.on('connection', function(socket){

return oldRequest.apply(this, arguments);
}
};

@@ -446,3 +447,3 @@ engine.on('connection', function(socket){

var socket = new eioc.Socket('ws://localhost:%d'.s(port))
var socket = new eioc.Socket('ws://localhost:%d'.s(port));
socket.on('open', function(){

@@ -458,2 +459,108 @@ socket.send('test');

});
it('should not trigger early with connection `ping timeout` after post handshake timeout', function (done) {
// First timeout should trigger after `pingInterval + pingTimeout`, not just `pingTimeout`.
var opts = { allowUpgrades: false, pingInterval: 300, pingTimeout: 100 };
var engine = listen(opts, function (port) {
var socket = new eioc.Socket('ws://localhost:%d'.s(port));
var clientCloseReason = null;
socket.on('handshake', function() {
socket.onPacket = function(){};
});
socket.on('open', function () {
socket.on('close', function (reason) {
clientCloseReason = reason;
});
});
setTimeout(function() {
expect(clientCloseReason).to.be(null);
done();
}, 200);
});
});
it('should not trigger early with connection `ping timeout` after post ping timeout', function (done) {
// Ping timeout should trigger after `pingInterval + pingTimeout`, not just `pingTimeout`.
var opts = { allowUpgrades: false, pingInterval: 300, pingTimeout: 100 };
var engine = listen(opts, function (port) {
var socket = new eioc.Socket('ws://localhost:%d'.s(port));
var clientCloseReason = null;
engine.on('connection', function(conn){
conn.on('heartbeat', function() {
conn.onPacket = function(){};
});
});
socket.on('open', function () {
socket.on('close', function (reason) {
clientCloseReason = reason;
});
});
setTimeout(function() {
expect(clientCloseReason).to.be(null);
done();
}, 300);
});
});
it('should trigger early with connection `transport close` after missing pong', function (done) {
// Ping timeout should trigger after `pingInterval + pingTimeout`, not just `pingTimeout`.
var opts = { allowUpgrades: false, pingInterval: 300, pingTimeout: 100 };
var engine = listen(opts, function (port) {
var socket = new eioc.Socket('ws://localhost:%d'.s(port));
var clientCloseReason = null;
socket.on('open', function () {
socket.on('close', function (reason) {
clientCloseReason = reason;
});
});
engine.on('connection', function(conn){
conn.on('heartbeat', function() {
setTimeout(function() {
conn.close();
}, 20);
setTimeout(function() {
expect(clientCloseReason).to.be("transport close");
done();
}, 150);
});
});
});
});
it('should trigger with connection `ping timeout` after `pingInterval + pingTimeout`', function (done) {
var opts = { allowUpgrades: false, pingInterval: 30, pingTimeout: 10 };
var engine = listen(opts, function (port) {
var socket = new eioc.Socket('ws://localhost:%d'.s(port));
var clientCloseReason = null;
socket.on('open', function () {
socket.on('close', function (reason) {
clientCloseReason = reason;
});
});
engine.on('connection', function(conn){
conn.once('heartbeat', function() {
setTimeout(function() {
socket.onPacket = function(){};
expect(clientCloseReason).to.be(null);
}, 15);
setTimeout(function() {
expect(clientCloseReason).to.be(null);
}, 35);
setTimeout(function() {
expect(clientCloseReason).to.be("ping timeout");
done();
}, 50);
});
});
});
});
});

@@ -481,3 +588,3 @@

, expected = ['a', 'b', 'c']
, i = 0
, i = 0;

@@ -556,3 +663,4 @@ engine.on('connection', function (conn) {

, expected = ['a', 'b', 'c']
, i = 0
, i = 0;
engine.on('connection', function (conn) {

@@ -574,2 +682,3 @@ conn.send('a');

});
socket.on('open', function () {

@@ -616,2 +725,146 @@ socket.on('message', function (msg) {

describe('send', function() {
describe('callback', function() {
it('should execute when message sent (polling)', function (done) {
var engine = listen({ allowUpgrades: false }, function (port) {
var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['polling'] });
var i = 0;
var j = 0;
engine.on('connection', function (conn) {
conn.send('a', function (transport) {
i++;
});
});
socket.on('open', function () {
socket.on('message', function (msg) {
j++;
});
});
setTimeout(function() {
expect(i).to.be(j);
done();
}, 10);
});
});
it('should execute when message sent (websocket)', function (done) {
var engine = listen({ allowUpgrades: false }, function (port) {
var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['websocket'] });
var i = 0;
var j = 0;
engine.on('connection', function (conn) {
conn.send('a', function (transport) {
i++;
});
});
socket.on('open', function () {
socket.on('message', function (msg) {
j++;
});
});
setTimeout(function () {
expect(i).to.be(j);
done();
}, 10);
});
});
it('should execute once for each send', function (done) {
var engine = listen(function (port) {
var socket = new eioc.Socket('ws://localhost:%d'.s(port));
var i = 0;
var ic = 0;
var j = 0;
var jc = 0;
engine.on('connection', function (conn) {
conn.send('b', function (transport) {
jc++;
});
conn.send('a', function (transport) {
ic++;
});
});
socket.on('open', function () {
socket.on('message', function (msg) {
if (msg == 'a') {
i++;
} else if (msg == 'b') {
j++;
}
});
});
setTimeout(function () {
expect(i).to.be(ic);
expect(j).to.be(jc);
done();
}, 100);
});
});
it('should execute in multipart packet', function (done) {
var engine = listen(function (port) {
var socket = new eioc.Socket('ws://localhost:%d'.s(port));
var i = 0;
var j = 0;
engine.on('connection', function (conn) {
conn.send('b', function (transport) {
i++;
});
conn.send('a', function (transport) {
i++;
});
});
socket.on('open', function () {
socket.on('message', function (msg) {
j++;
});
});
setTimeout(function () {
expect(i).to.be(j);
done();
}, 200);
});
});
it('should clean callback references when socket gets closed with pending callbacks', function (done) {
var engine = listen({ allowUpgrades: false }, function (port) {
var socket = new eioc.Socket('ws://localhost:%d'.s(port), { transports: ['polling'] });
engine.on('connection', function (conn) {
socket.transport.on('pollComplete', function () {
conn.send('a', function (transport) {
done(new Error('Test invalidation'));
});
if (!conn.writeBuffer.length) {
done(new Error('Test invalidation'));
}
// force to close the socket when we have one or more packet(s) in buffer
socket.close();
});
conn.on('close', function (reason) {
expect(conn.packetsFn).to.be.empty();
done();
});
});
});
});
});
});
describe('upgrade', function () {

@@ -618,0 +871,0 @@ it('should upgrade', function (done) {

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc