mirror of
https://github.com/socketio/socket.io.git
synced 2026-01-11 16:08:24 -05:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d49cafd03 | ||
|
|
77ca2dcbda | ||
|
|
7e4aa4fa64 | ||
|
|
b46e480f65 | ||
|
|
5e92dd8663 | ||
|
|
f981d3f050 | ||
|
|
f57505fee7 | ||
|
|
f8f1b132a1 | ||
|
|
f7f83bc09f | ||
|
|
b8ded0d725 | ||
|
|
086ccd2708 | ||
|
|
864857cb6f | ||
|
|
e5a7e422f9 | ||
|
|
f5b75151bd | ||
|
|
0523b655da | ||
|
|
d9415a38e4 | ||
|
|
ca82c09bf2 | ||
|
|
b9aaa1607c | ||
|
|
d1304c5d82 | ||
|
|
bd479a9cd6 | ||
|
|
a116d7765a | ||
|
|
1c6620d564 | ||
|
|
dba462e6da | ||
|
|
19c4422361 | ||
|
|
8242dd01ef | ||
|
|
17960ed038 | ||
|
|
d9996f0470 | ||
|
|
24d06d76dd | ||
|
|
4e4bbf918e | ||
|
|
b49f5c82f2 | ||
|
|
5bd67195de | ||
|
|
73fe547956 | ||
|
|
973e6cc982 | ||
|
|
136fe960b7 |
26
History.md
26
History.md
@@ -1,4 +1,30 @@
|
||||
|
||||
1.3.1 / 2015-01-19
|
||||
==================
|
||||
|
||||
* no change on this release
|
||||
* package: bump `engine.io`
|
||||
|
||||
1.3.0 / 2015-01-19
|
||||
==================
|
||||
|
||||
* package: bump `engine.io`
|
||||
* add test for reconnection after server restarts [rase-]
|
||||
* update license with up-to-date year range [fay-jai]
|
||||
* fix leaving unknown rooms [defunctzombie]
|
||||
* allow null origins when allowed origins is a function [drewblaisdell]
|
||||
* fix tests on node 0.11
|
||||
* package: fix `npm test` to run on windows
|
||||
* package: bump `debug` v2.1.0 [coderaiser]
|
||||
* added tests for volatile [rase-]
|
||||
|
||||
1.2.1 / 2014-11-21
|
||||
==================
|
||||
|
||||
* fix protocol violations and improve error handling (GH-1880)
|
||||
* package: bump `engine.io` for websocket leak fix [3rd-Eden]
|
||||
* style tweaks
|
||||
|
||||
1.2.0 / 2014-10-27
|
||||
==================
|
||||
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2014 Automattic <dev@cloudup.com>
|
||||
Copyright (c) 2014-2015 Automattic <dev@cloudup.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# socket.io
|
||||
|
||||
[](http://travis-ci.org/Automattic/socket.io)
|
||||
[](http://badge.fury.io/js/socket.io)
|
||||

|
||||

|
||||

|
||||
|
||||
## How to use
|
||||
|
||||
@@ -274,7 +274,7 @@ server.listen(3000);
|
||||
|
||||
### Socket#conn:Socket
|
||||
|
||||
A reference to the underyling `Client` transport connection (engine.io
|
||||
A reference to the underlying `Client` transport connection (engine.io
|
||||
`Socket` object).
|
||||
|
||||
### Socket#request:Request
|
||||
|
||||
@@ -42,9 +42,12 @@ function Client(server, conn){
|
||||
Client.prototype.setup = function(){
|
||||
this.onclose = this.onclose.bind(this);
|
||||
this.ondata = this.ondata.bind(this);
|
||||
this.onerror = this.onerror.bind(this);
|
||||
this.ondecoded = this.ondecoded.bind(this);
|
||||
|
||||
this.decoder.on('decoded', this.ondecoded);
|
||||
this.conn.on('data', this.ondata);
|
||||
this.conn.on('error', this.onerror);
|
||||
this.conn.on('close', this.onclose);
|
||||
};
|
||||
|
||||
@@ -167,7 +170,12 @@ Client.prototype.packet = function(packet, preEncoded, volatile){
|
||||
*/
|
||||
|
||||
Client.prototype.ondata = function(data){
|
||||
this.decoder.add(data);
|
||||
// try/catch is needed for protocol violations (GH-1880)
|
||||
try {
|
||||
this.decoder.add(data);
|
||||
} catch(e) {
|
||||
this.onerror(e);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -189,6 +197,20 @@ Client.prototype.ondecoded = function(packet) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles an error.
|
||||
*
|
||||
* @param {Objcet} error object
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Client.prototype.onerror = function(err){
|
||||
this.sockets.forEach(function(socket){
|
||||
socket.onerror(err);
|
||||
});
|
||||
this.onclose('client error');
|
||||
};
|
||||
|
||||
/**
|
||||
* Called upon transport close.
|
||||
*
|
||||
@@ -219,6 +241,7 @@ Client.prototype.onclose = function(reason){
|
||||
|
||||
Client.prototype.destroy = function(){
|
||||
this.conn.removeListener('data', this.ondata);
|
||||
this.conn.removeListener('error', this.onerror);
|
||||
this.conn.removeListener('close', this.onclose);
|
||||
this.decoder.removeListener('decoded', this.ondecoded);
|
||||
};
|
||||
|
||||
@@ -62,7 +62,7 @@ Server.prototype.checkRequest = function(req, fn) {
|
||||
var origin = req.headers.origin || req.headers.referer;
|
||||
|
||||
// file:// URLs produce a null Origin which can't be authorized via echo-back
|
||||
if ('null' == origin) origin = '*';
|
||||
if ('null' == origin || null == origin) origin = '*';
|
||||
|
||||
if (!!origin && typeof(this._origins) == 'function') return this._origins(origin, fn);
|
||||
if (this._origins.indexOf('*:*') !== -1) return fn(null, true);
|
||||
@@ -194,7 +194,7 @@ Server.prototype.origins = function(v){
|
||||
Server.prototype.listen =
|
||||
Server.prototype.attach = function(srv, opts){
|
||||
if ('function' == typeof srv) {
|
||||
var msg = 'You are trying to attach socket.io to an express' +
|
||||
var msg = 'You are trying to attach socket.io to an express ' +
|
||||
'request handler function. Please pass a http.Server instance.';
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
@@ -242,7 +242,10 @@ Socket.prototype.leave = function(room, fn){
|
||||
this.adapter.del(this.id, room, function(err){
|
||||
if (err) return fn && fn(err);
|
||||
debug('left room %s', room);
|
||||
self.rooms.splice(self.rooms.indexOf(room), 1);
|
||||
var idx = self.rooms.indexOf(room);
|
||||
if (idx >= 0) {
|
||||
self.rooms.splice(idx, 1);
|
||||
}
|
||||
fn && fn(null);
|
||||
});
|
||||
return this;
|
||||
@@ -380,10 +383,21 @@ Socket.prototype.ondisconnect = function(){
|
||||
this.onclose('client namespace disconnect');
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles a client error.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Socket.prototype.onerror = function(err){
|
||||
this.emit('error', err);
|
||||
};
|
||||
|
||||
/**
|
||||
* Called upon closing. Called by `Client`.
|
||||
*
|
||||
* @param {String} reason
|
||||
* @param {Error} optional error object
|
||||
* @api private
|
||||
*/
|
||||
|
||||
|
||||
10
package.json
10
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "socket.io",
|
||||
"version": "1.2.0",
|
||||
"version": "1.3.1",
|
||||
"description": "node.js realtime framework server",
|
||||
"keywords": [
|
||||
"realtime",
|
||||
@@ -16,15 +16,15 @@
|
||||
"url": "git://github.com/Automattic/socket.io"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "make test"
|
||||
"test": "mocha --reporter dot --slow 200ms --bail"
|
||||
},
|
||||
"dependencies": {
|
||||
"engine.io": "1.4.2",
|
||||
"engine.io": "1.5.1",
|
||||
"socket.io-parser": "2.2.2",
|
||||
"socket.io-client": "1.2.0",
|
||||
"socket.io-client": "1.3.1",
|
||||
"socket.io-adapter": "0.3.1",
|
||||
"has-binary-data": "0.1.3",
|
||||
"debug": "0.7.4"
|
||||
"debug": "2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "1.16.2",
|
||||
|
||||
@@ -7,7 +7,7 @@ var ioc = require('socket.io-client');
|
||||
var request = require('supertest');
|
||||
var expect = require('expect.js');
|
||||
|
||||
// creates a socket.io client for the given server
|
||||
// Creates a socket.io client for the given server
|
||||
function client(srv, nsp, opts){
|
||||
if ('object' == typeof nsp) {
|
||||
opts = nsp;
|
||||
@@ -15,7 +15,7 @@ function client(srv, nsp, opts){
|
||||
}
|
||||
var addr = srv.address();
|
||||
if (!addr) addr = srv.listen().address();
|
||||
var url = 'ws://' + addr.address + ':' + addr.port + (nsp || '');
|
||||
var url = 'ws://localhost:' + addr.port + (nsp || '');
|
||||
return ioc(url, opts);
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ describe('socket.io', function(){
|
||||
expect(s.handshake.time.split(' ').length > 0); // Is "multipart" string representation
|
||||
|
||||
// Address, xdomain, secure, issued and url set
|
||||
expect(s.handshake.address).to.be('127.0.0.1');
|
||||
expect(s.handshake.address).to.contain('127.0.0.1');
|
||||
expect(s.handshake.xdomain).to.be.a('boolean');
|
||||
expect(s.handshake.secure).to.be.a('boolean');
|
||||
expect(s.handshake.issued).to.be.a('number');
|
||||
@@ -273,8 +273,9 @@ describe('socket.io', function(){
|
||||
|
||||
it('should allow request when origin defined as function and same is supplied', function(done) {
|
||||
var sockets = io({ origins: function(origin,callback){
|
||||
if(origin == 'http://foo.example')
|
||||
if (origin == 'http://foo.example') {
|
||||
return callback(null, true);
|
||||
}
|
||||
return callback(null, false);
|
||||
} }).listen('54016');
|
||||
request.get('http://localhost:54016/socket.io/default/')
|
||||
@@ -288,8 +289,9 @@ describe('socket.io', function(){
|
||||
|
||||
it('should allow request when origin defined as function and different is supplied', function(done) {
|
||||
var sockets = io({ origins: function(origin,callback){
|
||||
if(origin == 'http://foo.example')
|
||||
if (origin == 'http://foo.example') {
|
||||
return callback(null, true);
|
||||
}
|
||||
return callback(null, false);
|
||||
} }).listen('54017');
|
||||
request.get('http://localhost:54017/socket.io/default/')
|
||||
@@ -300,6 +302,21 @@ describe('socket.io', function(){
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow request when origin defined as function and no origin is supplied', function(done) {
|
||||
var sockets = io({ origins: function(origin,callback){
|
||||
if (origin == '*') {
|
||||
return callback(null, true);
|
||||
}
|
||||
return callback(null, false);
|
||||
} }).listen('54021');
|
||||
request.get('http://localhost:54021/socket.io/default/')
|
||||
.query({ transport: 'polling' })
|
||||
.end(function (err, res) {
|
||||
expect(res.status).to.be(200);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('close', function(){
|
||||
@@ -445,7 +462,7 @@ describe('socket.io', function(){
|
||||
var c1 = client(srv, '/');
|
||||
var c2 = client(srv, '/abc');
|
||||
});
|
||||
|
||||
|
||||
it('should be equivalent for "" and "/" on client', function(done){
|
||||
var srv = http();
|
||||
var sio = io(srv);
|
||||
@@ -454,7 +471,7 @@ describe('socket.io', function(){
|
||||
});
|
||||
var c1 = client(srv, '');
|
||||
});
|
||||
|
||||
|
||||
it('should work with `of` and many sockets', function(done){
|
||||
var srv = http();
|
||||
var sio = io(srv);
|
||||
@@ -637,6 +654,39 @@ describe('socket.io', function(){
|
||||
});
|
||||
});
|
||||
|
||||
it('should error with null messages', function(done){
|
||||
var srv = http();
|
||||
var sio = io(srv);
|
||||
srv.listen(function(){
|
||||
var socket = client(srv);
|
||||
sio.on('connection', function(s){
|
||||
s.on('message', function(a){
|
||||
expect(a).to.be(null);
|
||||
done();
|
||||
});
|
||||
socket.send(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle transport null messages', function(done){
|
||||
var srv = http();
|
||||
var sio = io(srv);
|
||||
srv.listen(function(){
|
||||
var socket = client(srv);
|
||||
sio.on('connection', function(s){
|
||||
s.on('error', function(err){
|
||||
expect(err).to.be.an(Error);
|
||||
s.on('disconnect', function(reason){
|
||||
expect(reason).to.be('client error');
|
||||
done();
|
||||
});
|
||||
});
|
||||
s.client.ondata(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should emit events', function(done){
|
||||
var srv = http();
|
||||
var sio = io(srv);
|
||||
@@ -765,6 +815,208 @@ describe('socket.io', function(){
|
||||
});
|
||||
});
|
||||
|
||||
it('should not emit volatile event after regular event (polling)', function(done) {
|
||||
var srv = http();
|
||||
var sio = io(srv, { transports: ['polling'] });
|
||||
|
||||
var counter = 0;
|
||||
srv.listen(function(){
|
||||
sio.on('connection', function(s){
|
||||
s.emit('ev', 'data');
|
||||
s.volatile.emit('ev', 'data');
|
||||
});
|
||||
|
||||
var socket = client(srv, { transports: ['polling'] });
|
||||
socket.on('ev', function() {
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
expect(counter).to.be(1);
|
||||
done();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
it('should not emit volatile event after regular event (ws)', function(done) {
|
||||
var srv = http();
|
||||
var sio = io(srv, { transports: ['websocket'] });
|
||||
|
||||
var counter = 0;
|
||||
srv.listen(function(){
|
||||
sio.on('connection', function(s){
|
||||
s.emit('ev', 'data');
|
||||
s.volatile.emit('ev', 'data');
|
||||
});
|
||||
|
||||
var socket = client(srv, { transports: ['websocket'] });
|
||||
socket.on('ev', function() {
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
expect(counter).to.be(1);
|
||||
done();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
it('should emit volatile event (polling)', function(done) {
|
||||
var srv = http();
|
||||
var sio = io(srv, { transports: ['polling'] });
|
||||
|
||||
var counter = 0;
|
||||
srv.listen(function(){
|
||||
sio.on('connection', function(s){
|
||||
// Wait to make sure there are no packets being sent for opening the connection
|
||||
setTimeout(function() {
|
||||
s.volatile.emit('ev', 'data');
|
||||
}, 20);
|
||||
});
|
||||
|
||||
var socket = client(srv, { transports: ['polling'] });
|
||||
socket.on('ev', function() {
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
expect(counter).to.be(1);
|
||||
done();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
it('should emit volatile event (ws)', function(done) {
|
||||
var srv = http();
|
||||
var sio = io(srv, { transports: ['websocket'] });
|
||||
|
||||
var counter = 0;
|
||||
srv.listen(function(){
|
||||
sio.on('connection', function(s){
|
||||
// Wait to make sure there are no packets being sent for opening the connection
|
||||
setTimeout(function() {
|
||||
s.volatile.emit('ev', 'data');
|
||||
}, 20);
|
||||
});
|
||||
|
||||
var socket = client(srv, { transports: ['websocket'] });
|
||||
socket.on('ev', function() {
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
expect(counter).to.be(1);
|
||||
done();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
it('should emit only one consecutive volatile event (polling)', function(done) {
|
||||
var srv = http();
|
||||
var sio = io(srv, { transports: ['polling'] });
|
||||
|
||||
var counter = 0;
|
||||
srv.listen(function(){
|
||||
sio.on('connection', function(s){
|
||||
// Wait to make sure there are no packets being sent for opening the connection
|
||||
setTimeout(function() {
|
||||
s.volatile.emit('ev', 'data');
|
||||
s.volatile.emit('ev', 'data');
|
||||
}, 20);
|
||||
});
|
||||
|
||||
var socket = client(srv, { transports: ['polling'] });
|
||||
socket.on('ev', function() {
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
expect(counter).to.be(1);
|
||||
done();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
it('should emit only one consecutive volatile event (ws)', function(done) {
|
||||
var srv = http();
|
||||
var sio = io(srv, { transports: ['websocket'] });
|
||||
|
||||
var counter = 0;
|
||||
srv.listen(function(){
|
||||
sio.on('connection', function(s){
|
||||
// Wait to make sure there are no packets being sent for opening the connection
|
||||
setTimeout(function() {
|
||||
s.volatile.emit('ev', 'data');
|
||||
s.volatile.emit('ev', 'data');
|
||||
}, 20);
|
||||
});
|
||||
|
||||
var socket = client(srv, { transports: ['websocket'] });
|
||||
socket.on('ev', function() {
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
expect(counter).to.be(1);
|
||||
done();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
it('should emit regular events after trying a failed volatile event (polling)', function(done) {
|
||||
var srv = http();
|
||||
var sio = io(srv, { transports: ['polling'] });
|
||||
|
||||
var counter = 0;
|
||||
srv.listen(function(){
|
||||
sio.on('connection', function(s){
|
||||
// Wait to make sure there are no packets being sent for opening the connection
|
||||
setTimeout(function() {
|
||||
s.emit('ev', 'data');
|
||||
s.volatile.emit('ev', 'data');
|
||||
s.emit('ev', 'data');
|
||||
}, 20);
|
||||
});
|
||||
|
||||
var socket = client(srv, { transports: ['polling'] });
|
||||
socket.on('ev', function() {
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
expect(counter).to.be(2);
|
||||
done();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
it('should emit regular events after trying a failed volatile event (ws)', function(done) {
|
||||
var srv = http();
|
||||
var sio = io(srv, { transports: ['websocket'] });
|
||||
|
||||
var counter = 0;
|
||||
srv.listen(function(){
|
||||
sio.on('connection', function(s){
|
||||
// Wait to make sure there are no packets being sent for opening the connection
|
||||
setTimeout(function() {
|
||||
s.emit('ev', 'data');
|
||||
s.volatile.emit('ev', 'data');
|
||||
s.emit('ev', 'data');
|
||||
}, 20);
|
||||
});
|
||||
|
||||
var socket = client(srv, { transports: ['websocket'] });
|
||||
socket.on('ev', function() {
|
||||
counter++;
|
||||
});
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
expect(counter).to.be(2);
|
||||
done();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
it('should emit message events through `send`', function(done){
|
||||
var srv = http();
|
||||
var sio = io(srv);
|
||||
@@ -987,7 +1239,7 @@ describe('socket.io', function(){
|
||||
var sio = io(srv);
|
||||
srv.listen(function() {
|
||||
var addr = srv.listen().address();
|
||||
var url = 'ws://' + addr.address + ':' + addr.port + '?key1=1&key2=2';
|
||||
var url = 'ws://localhost:' + addr.port + '?key1=1&key2=2';
|
||||
var socket = ioc(url);
|
||||
sio.on('connection', function(s) {
|
||||
var parsed = require('url').parse(s.request.url);
|
||||
@@ -1000,7 +1252,7 @@ describe('socket.io', function(){
|
||||
});
|
||||
|
||||
it('should handle very large json', function(done){
|
||||
this.timeout();
|
||||
this.timeout(30000);
|
||||
var srv = http();
|
||||
var sio = io(srv);
|
||||
var received = 0;
|
||||
@@ -1051,6 +1303,32 @@ describe('socket.io', function(){
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to emit after server close and restart', function(done){
|
||||
var srv = http();
|
||||
var sio = io(srv);
|
||||
|
||||
sio.on('connection', function(socket){
|
||||
socket.on('ev', function(data){
|
||||
expect(data).to.be('payload');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
srv.listen(function(){
|
||||
var port = srv.address().port;
|
||||
var clientSocket = client(srv, { reconnectionAttempts: 10, reconnectionDelay: 100 });
|
||||
clientSocket.once('connect', function(){
|
||||
srv.close(function(){
|
||||
srv.listen(port, function(){
|
||||
clientSocket.on('reconnect', function(){
|
||||
clientSocket.emit('ev', 'payload');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('messaging many', function(){
|
||||
@@ -1350,6 +1628,30 @@ describe('socket.io', function(){
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should properly cleanup left rooms', function(done){
|
||||
var srv = http();
|
||||
var sio = io(srv);
|
||||
|
||||
srv.listen(function(){
|
||||
var socket = client(srv);
|
||||
sio.on('connection', function(s){
|
||||
s.join('a', function(){
|
||||
expect(s.rooms).to.eql([s.id, 'a']);
|
||||
s.join('b', function(){
|
||||
expect(s.rooms).to.eql([s.id, 'a', 'b']);
|
||||
s.leave('unknown', function(){
|
||||
expect(s.rooms).to.eql([s.id, 'a', 'b']);
|
||||
s.leaveAll();
|
||||
expect(s.rooms).to.eql([]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('middleware', function(done){
|
||||
|
||||
Reference in New Issue
Block a user