mirror of
https://github.com/socketio/socket.io.git
synced 2026-01-11 16:08:24 -05:00
Compare commits
105 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d25c5484c3 | ||
|
|
fea676b90e | ||
|
|
386d2a9c0c | ||
|
|
8b47789414 | ||
|
|
47b06c0fcf | ||
|
|
9823325a1f | ||
|
|
a47d76b990 | ||
|
|
db3ac4b415 | ||
|
|
b9a2804b1a | ||
|
|
b4182a5d42 | ||
|
|
5120a706f2 | ||
|
|
ee078cb124 | ||
|
|
64d8f572aa | ||
|
|
4e1ba9f872 | ||
|
|
5d93af994a | ||
|
|
6e25c802cc | ||
|
|
37690f78d7 | ||
|
|
3cbd00ca70 | ||
|
|
b2a8ed1421 | ||
|
|
0d3313f536 | ||
|
|
3b7224c7e0 | ||
|
|
2030cf1432 | ||
|
|
de9e8dffe1 | ||
|
|
3a3044ebba | ||
|
|
d10b4dd1bd | ||
|
|
12beee2d63 | ||
|
|
875f14d16b | ||
|
|
8ca8990a0c | ||
|
|
c218468f67 | ||
|
|
4164e3bd7e | ||
|
|
46227e7ac9 | ||
|
|
d723d363b2 | ||
|
|
fa1c1b2ada | ||
|
|
d32a848c3f | ||
|
|
48ad0d3d1d | ||
|
|
281a467960 | ||
|
|
1fa74a46a3 | ||
|
|
ca4e3f32a3 | ||
|
|
9dd8134e6a | ||
|
|
180f1c91b9 | ||
|
|
bddf652c25 | ||
|
|
c795e4cf1a | ||
|
|
6afbb34581 | ||
|
|
ac39dbc721 | ||
|
|
a5c5c20438 | ||
|
|
f48b40e134 | ||
|
|
1679fd564c | ||
|
|
bb900d445a | ||
|
|
c6fed55f53 | ||
|
|
6adebc85fc | ||
|
|
7a087bcc94 | ||
|
|
18422183c8 | ||
|
|
aeb904f58b | ||
|
|
9c0b9de7f0 | ||
|
|
81552c11ca | ||
|
|
e1fe76aebe | ||
|
|
8197a0c854 | ||
|
|
2b91f1407f | ||
|
|
3b9715e8e7 | ||
|
|
4e13cfb03e | ||
|
|
39671e81a5 | ||
|
|
ffa8994a23 | ||
|
|
de1afe1317 | ||
|
|
aaad106b90 | ||
|
|
f850ddccd0 | ||
|
|
8d269aae4c | ||
|
|
67b4eb9abd | ||
|
|
fe6dd87443 | ||
|
|
d9aeaa494f | ||
|
|
2024d45383 | ||
|
|
e1884859bc | ||
|
|
0242a2ddf3 | ||
|
|
dbe6d5f740 | ||
|
|
e98fc7bc86 | ||
|
|
9bbf17f31e | ||
|
|
1a5a87af13 | ||
|
|
a4e53a642b | ||
|
|
6f36d8c2ff | ||
|
|
09fb16b443 | ||
|
|
330407cc9d | ||
|
|
2075307f23 | ||
|
|
d7b06edaca | ||
|
|
46fdcf00b3 | ||
|
|
147b9bb941 | ||
|
|
02a3da487c | ||
|
|
087c686ad0 | ||
|
|
16205fc522 | ||
|
|
a232159ce8 | ||
|
|
b9c3255b7c | ||
|
|
d80010dcf0 | ||
|
|
00694a8a98 | ||
|
|
da95094998 | ||
|
|
e7d7582f84 | ||
|
|
df5f23d309 | ||
|
|
e018ba91eb | ||
|
|
c59aa6ff2c | ||
|
|
9431709298 | ||
|
|
a29525e043 | ||
|
|
5312e154b3 | ||
|
|
480b86f382 | ||
|
|
c0e2c3012f | ||
|
|
97b04c4152 | ||
|
|
c8306e207d | ||
|
|
de5c0b3554 | ||
|
|
57a0b24060 |
@@ -1,6 +1,5 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 0.4
|
||||
- 0.6
|
||||
|
||||
notifications:
|
||||
|
||||
114
History.md
114
History.md
@@ -1,4 +1,118 @@
|
||||
|
||||
0.9.17 / 2014-05-22
|
||||
===================
|
||||
|
||||
* use static channels for remote syncing instead of subscribing/unsubscribing 5 channels for every connection
|
||||
* Use destroy buffer size on websocket transport method as well
|
||||
* http-polling : adding 'X-XSS-Protection : 0;' to headers necessary not only to jsonp-polling but http-polling
|
||||
|
||||
0.9.16 / 2013-06-06
|
||||
===================
|
||||
|
||||
* transports: added tests for htmlfile escaping/unescaping
|
||||
|
||||
0.9.15 / 2013-06-06
|
||||
===================
|
||||
|
||||
* transports: added escaping to htmlfile (fixes #1251)
|
||||
|
||||
0.9.14 / 2013-03-29
|
||||
===================
|
||||
|
||||
* manager: fix memory leak with SSL [jpallen]
|
||||
|
||||
0.9.13 / 2012-12-13
|
||||
===================
|
||||
|
||||
* package: fixed `base64id` requirement
|
||||
|
||||
0.9.12 / 2012-12-13
|
||||
===================
|
||||
|
||||
* manager: fix for latest node which is returning a clone with `listeners` [viirya]
|
||||
|
||||
0.9.11 / 2012-11-02
|
||||
===================
|
||||
|
||||
* package: move redis to optionalDependenices [3rd-Eden]
|
||||
* bumped client
|
||||
|
||||
0.9.10 / 2012-08-10
|
||||
===================
|
||||
|
||||
* Don't lowercase log messages
|
||||
* Always set the HTTP response in case an error should be returned to the client
|
||||
* Create or destroy the flash policy server on configuration change
|
||||
* Honour configuration to disable flash policy server
|
||||
* Add express 3.0 instructions on Readme.md
|
||||
* Bump client
|
||||
|
||||
0.9.9 / 2012-08-01
|
||||
==================
|
||||
|
||||
* Fixed sync disconnect xhrs handling
|
||||
* Put license text in its own file (#965)
|
||||
* Add warning to .listen() to ease the migration to Express 3.x
|
||||
* Restored compatibility with node 0.4.x
|
||||
|
||||
0.9.8 / 2012-07-24
|
||||
==================
|
||||
|
||||
* Bumped client.
|
||||
|
||||
0.9.7 / 2012-07-24
|
||||
==================
|
||||
|
||||
* Prevent crash when socket leaves a room twice.
|
||||
* Corrects unsafe usage of for..in
|
||||
* Fix for node 0.8 with `gzip compression` [vadimi]
|
||||
* Update redis to support Node 0.8.x
|
||||
* Made ID generation securely random
|
||||
* Fix Redis Store race condition in manager onOpen unsubscribe callback
|
||||
* Fix for EventEmitters always reusing the same Array instance for listeners
|
||||
|
||||
0.9.6 / 2012-04-17
|
||||
==================
|
||||
|
||||
* Fixed XSS in jsonp-polling.
|
||||
|
||||
0.9.5 / 2012-04-05
|
||||
==================
|
||||
|
||||
* Added test for polling and socket close.
|
||||
* Ensure close upon request close.
|
||||
* Fix disconnection reason being lost for polling transports.
|
||||
* Ensure that polling transports work with Connection: close.
|
||||
* Log disconnection reason.
|
||||
|
||||
0.9.4 / 2012-04-01
|
||||
==================
|
||||
|
||||
* Disconnecting from namespace improvement (#795) [DanielBaulig]
|
||||
* Bumped client with polling reconnection loop (#438)
|
||||
|
||||
0.9.3 / 2012-03-28
|
||||
==================
|
||||
|
||||
* Fix "Syntax error" on FF Web Console with XHR Polling [mikito]
|
||||
|
||||
0.9.2 / 2012-03-13
|
||||
==================
|
||||
|
||||
* More sensible close `timeout default` (fixes disconnect issue)
|
||||
|
||||
0.9.1-1 / 2012-03-02
|
||||
====================
|
||||
|
||||
* Bumped client with NPM dependency fix.
|
||||
|
||||
0.9.1 / 2012-03-02
|
||||
==================
|
||||
|
||||
* Changed heartbeat timeout and interval defaults (60 and 25 seconds)
|
||||
* Make tests work both on 0.4 and 0.6
|
||||
* Updated client (improvements + bug fixes).
|
||||
|
||||
0.9.0 / 2012-02-26
|
||||
==================
|
||||
|
||||
|
||||
22
LICENSE
Normal file
22
LICENSE
Normal file
@@ -0,0 +1,22 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2011 Guillermo Rauch <guillermo@learnboost.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
27
Readme.md
27
Readme.md
@@ -6,7 +6,9 @@ horizontal scalability, automatic JSON encoding/decoding, and more.
|
||||
|
||||
## How to Install
|
||||
|
||||
npm install socket.io
|
||||
```bash
|
||||
npm install socket.io
|
||||
```
|
||||
|
||||
## How to use
|
||||
|
||||
@@ -19,6 +21,25 @@ var io = require('socket.io');
|
||||
Next, attach it to a HTTP/HTTPS server. If you're using the fantastic `express`
|
||||
web framework:
|
||||
|
||||
#### Express 3.x
|
||||
|
||||
```js
|
||||
var app = express()
|
||||
, server = require('http').createServer(app)
|
||||
, io = io.listen(server);
|
||||
|
||||
server.listen(80);
|
||||
|
||||
io.sockets.on('connection', function (socket) {
|
||||
socket.emit('news', { hello: 'world' });
|
||||
socket.on('my other event', function (data) {
|
||||
console.log(data);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
#### Express 2.x
|
||||
|
||||
```js
|
||||
var app = express.createServer()
|
||||
, io = io.listen(app);
|
||||
@@ -102,10 +123,10 @@ io.sockets.on('connection', function (socket) {
|
||||
var socket = io.connect('http://localhost');
|
||||
|
||||
socket.on('connect', function () {
|
||||
socket.emit('set nickname', confirm('What is your nickname?'));
|
||||
socket.emit('set nickname', prompt('What is your nickname?'));
|
||||
socket.on('ready', function () {
|
||||
console.log('Connected !');
|
||||
socket.emit('msg', confirm('What is your message?'));
|
||||
socket.emit('msg', prompt('What is your message?'));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
167
lib/manager.js
167
lib/manager.js
@@ -11,6 +11,7 @@
|
||||
var fs = require('fs')
|
||||
, url = require('url')
|
||||
, tty = require('tty')
|
||||
, crypto = require('crypto')
|
||||
, util = require('./util')
|
||||
, store = require('./store')
|
||||
, client = require('socket.io-client')
|
||||
@@ -44,7 +45,8 @@ var defaultTransports = exports.defaultTransports = [
|
||||
*/
|
||||
|
||||
var parent = module.parent.exports
|
||||
, protocol = parent.protocol;
|
||||
, protocol = parent.protocol
|
||||
, jsonpolling_re = /^\d+$/;
|
||||
|
||||
/**
|
||||
* Manager constructor.
|
||||
@@ -71,9 +73,9 @@ function Manager (server, options) {
|
||||
, blacklist: ['disconnect']
|
||||
, 'log level': 3
|
||||
, 'log colors': tty.isatty(process.stdout.fd)
|
||||
, 'close timeout': 25
|
||||
, 'heartbeat timeout': 15
|
||||
, 'heartbeat interval': 20
|
||||
, 'close timeout': 60
|
||||
, 'heartbeat interval': 25
|
||||
, 'heartbeat timeout': 60
|
||||
, 'polling duration': 20
|
||||
, 'flash policy server': true
|
||||
, 'flash policy port': 10843
|
||||
@@ -91,7 +93,9 @@ function Manager (server, options) {
|
||||
};
|
||||
|
||||
for (var i in options) {
|
||||
this.settings[i] = options[i];
|
||||
if (options.hasOwnProperty(i)) {
|
||||
this.settings[i] = options[i];
|
||||
}
|
||||
}
|
||||
|
||||
var self = this;
|
||||
@@ -108,7 +112,7 @@ function Manager (server, options) {
|
||||
});
|
||||
|
||||
// reset listeners
|
||||
this.oldListeners = server.listeners('request');
|
||||
this.oldListeners = server.listeners('request').splice(0);
|
||||
server.removeAllListeners('request');
|
||||
|
||||
server.on('request', function (req, res) {
|
||||
@@ -128,11 +132,21 @@ function Manager (server, options) {
|
||||
});
|
||||
|
||||
for (var i in transports) {
|
||||
if (transports[i].init) {
|
||||
transports[i].init(this);
|
||||
if (transports.hasOwnProperty(i)) {
|
||||
if (transports[i].init) {
|
||||
transports[i].init(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// forward-compatibility with 1.0
|
||||
var self = this;
|
||||
this.sockets.on('connection', function (conn) {
|
||||
self.emit('connection', conn);
|
||||
});
|
||||
|
||||
this.sequenceNumber = Date.now() | 0;
|
||||
|
||||
this.log.info('socket.io started');
|
||||
};
|
||||
|
||||
@@ -252,7 +266,7 @@ Manager.prototype.disabled = function (key) {
|
||||
Manager.prototype.configure = function (env, fn) {
|
||||
if ('function' == typeof env) {
|
||||
env.call(this);
|
||||
} else if (env == process.env.NODE_ENV) {
|
||||
} else if (env == (process.env.NODE_ENV || 'development')) {
|
||||
fn.call(this);
|
||||
}
|
||||
|
||||
@@ -306,8 +320,46 @@ Manager.prototype.initStore = function () {
|
||||
this.store.subscribe('disconnect', function (id) {
|
||||
self.onDisconnect(id);
|
||||
});
|
||||
};
|
||||
|
||||
// we need to do this in a pub/sub way since the client can POST the message
|
||||
// over a different socket (ie: different Transport instance)
|
||||
|
||||
//use persistent channel for these, don't add and remove 5 channels for every connection
|
||||
//eg. for 10,000 concurrent users this creates 50,000 channels in redis, which kind of slows things down
|
||||
//we only need 5 (extra) total channels at all times
|
||||
this.store.subscribe('message-remote',function (id, packet) {
|
||||
self.onClientMessage(id, packet);
|
||||
});
|
||||
|
||||
this.store.subscribe('disconnect-remote', function (id, reason) {
|
||||
self.onClientDisconnect(id, reason);
|
||||
});
|
||||
|
||||
this.store.subscribe('dispatch-remote', function (id, packet, volatile) {
|
||||
var transport = self.transports[id];
|
||||
if (transport) {
|
||||
transport.onDispatch(packet, volatile);
|
||||
}
|
||||
|
||||
if (!volatile) {
|
||||
self.onClientDispatch(id, packet);
|
||||
}
|
||||
});
|
||||
|
||||
this.store.subscribe('heartbeat-clear', function (id) {
|
||||
var transport = self.transports[id];
|
||||
if (transport) {
|
||||
transport.onHeartbeatClear();
|
||||
}
|
||||
});
|
||||
|
||||
this.store.subscribe('disconnect-force', function (id) {
|
||||
var transport = self.transports[id];
|
||||
if (transport) {
|
||||
transport.onForcedDisconnect();
|
||||
}
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Called when a client handshakes.
|
||||
*
|
||||
@@ -337,13 +389,20 @@ Manager.prototype.onConnect = function (id) {
|
||||
Manager.prototype.onOpen = function (id) {
|
||||
this.open[id] = true;
|
||||
|
||||
// if we were buffering messages for the client, clear them
|
||||
if (this.closed[id]) {
|
||||
var self = this;
|
||||
|
||||
this.store.unsubscribe('dispatch:' + id, function () {
|
||||
delete self.closed[id];
|
||||
});
|
||||
var transport = self.transports[id];
|
||||
if (self.closed[id] && self.closed[id].length && transport) {
|
||||
|
||||
// if we have buffered messages that accumulate between calling
|
||||
// onOpen an this async callback, send them if the transport is
|
||||
// still open, otherwise leave them buffered
|
||||
if (transport.open) {
|
||||
transport.payload(self.closed[id]);
|
||||
self.closed[id] = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clear the current transport
|
||||
@@ -413,7 +472,10 @@ Manager.prototype.onLeave = function (id, room) {
|
||||
if (!this.rooms[room].length) {
|
||||
delete this.rooms[room];
|
||||
}
|
||||
delete this.roomClients[id][room];
|
||||
|
||||
if (this.roomClients[id]) {
|
||||
delete this.roomClients[id][room];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -431,12 +493,6 @@ Manager.prototype.onClose = function (id) {
|
||||
this.closed[id] = [];
|
||||
|
||||
var self = this;
|
||||
|
||||
this.store.subscribe('dispatch:' + id, function (packet, volatile) {
|
||||
if (!volatile) {
|
||||
self.onClientDispatch(id, packet);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -471,8 +527,10 @@ Manager.prototype.onClientMessage = function (id, packet) {
|
||||
|
||||
Manager.prototype.onClientDisconnect = function (id, reason) {
|
||||
for (var name in this.namespaces) {
|
||||
this.namespaces[name].handleDisconnect(id, reason, typeof this.roomClients[id] !== 'undefined' &&
|
||||
typeof this.roomClients[id][name] !== 'undefined');
|
||||
if (this.namespaces.hasOwnProperty(name)) {
|
||||
this.namespaces[name].handleDisconnect(id, reason, typeof this.roomClients[id] !== 'undefined' &&
|
||||
typeof this.roomClients[id][name] !== 'undefined');
|
||||
}
|
||||
}
|
||||
|
||||
this.onDisconnect(id);
|
||||
@@ -484,7 +542,7 @@ Manager.prototype.onClientDisconnect = function (id, reason) {
|
||||
* @param text
|
||||
*/
|
||||
|
||||
Manager.prototype.onDisconnect = function (id, local) {
|
||||
Manager.prototype.onDisconnect = function (id) {
|
||||
delete this.handshaken[id];
|
||||
|
||||
if (this.open[id]) {
|
||||
@@ -506,19 +564,14 @@ Manager.prototype.onDisconnect = function (id, local) {
|
||||
|
||||
if (this.roomClients[id]) {
|
||||
for (var room in this.roomClients[id]) {
|
||||
this.onLeave(id, room);
|
||||
if (this.roomClients[id].hasOwnProperty(room)) {
|
||||
this.onLeave(id, room);
|
||||
}
|
||||
}
|
||||
delete this.roomClients[id]
|
||||
}
|
||||
|
||||
this.store.destroyClient(id, this.get('client store expiration'));
|
||||
|
||||
this.store.unsubscribe('dispatch:' + id);
|
||||
|
||||
if (local) {
|
||||
this.store.unsubscribe('message:' + id);
|
||||
this.store.unsubscribe('disconnect:' + id);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -586,6 +639,7 @@ Manager.prototype.handleUpgrade = function (req, socket, head) {
|
||||
|
||||
req.head = head;
|
||||
this.handleClient(data, req);
|
||||
req.head = null;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -610,12 +664,15 @@ Manager.prototype.handleClient = function (data, req) {
|
||||
, store = this.store
|
||||
, self = this;
|
||||
|
||||
// handle sync disconnect xhrs
|
||||
if (undefined != data.query.disconnect) {
|
||||
if (this.transports[data.id] && this.transports[data.id].open) {
|
||||
this.transports[data.id].onForcedDisconnect();
|
||||
} else {
|
||||
this.store.publish('disconnect-force:' + data.id);
|
||||
this.store.publish('disconnect-force', data.id);
|
||||
}
|
||||
req.res.writeHead(200);
|
||||
req.res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -656,21 +713,15 @@ Manager.prototype.handleClient = function (data, req) {
|
||||
|
||||
// initialize the socket for all namespaces
|
||||
for (var i in this.namespaces) {
|
||||
var socket = this.namespaces[i].socket(data.id, true);
|
||||
if (this.namespaces.hasOwnProperty(i)) {
|
||||
var socket = this.namespaces[i].socket(data.id, true);
|
||||
|
||||
// echo back connect packet and fire connection event
|
||||
if (i === '') {
|
||||
this.namespaces[i].handlePacket(data.id, { type: 'connect' });
|
||||
// echo back connect packet and fire connection event
|
||||
if (i === '') {
|
||||
this.namespaces[i].handlePacket(data.id, { type: 'connect' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.store.subscribe('message:' + data.id, function (packet) {
|
||||
self.onClientMessage(data.id, packet);
|
||||
});
|
||||
|
||||
this.store.subscribe('disconnect:' + data.id, function (reason) {
|
||||
self.onClientDisconnect(data.id, reason);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (transport.open) {
|
||||
@@ -688,8 +739,22 @@ Manager.prototype.handleClient = function (data, req) {
|
||||
*/
|
||||
|
||||
Manager.prototype.generateId = function () {
|
||||
return Math.abs(Math.random() * Math.random() * Date.now() | 0).toString()
|
||||
+ Math.abs(Math.random() * Math.random() * Date.now() | 0).toString();
|
||||
var rand = new Buffer(15); // multiple of 3 for base64
|
||||
if (!rand.writeInt32BE) {
|
||||
return Math.abs(Math.random() * Math.random() * Date.now() | 0).toString()
|
||||
+ Math.abs(Math.random() * Math.random() * Date.now() | 0).toString();
|
||||
}
|
||||
this.sequenceNumber = (this.sequenceNumber + 1) | 0;
|
||||
rand.writeInt32BE(this.sequenceNumber, 11);
|
||||
if (crypto.randomBytes) {
|
||||
crypto.randomBytes(12).copy(rand);
|
||||
} else {
|
||||
// not secure for node 0.4
|
||||
[0, 4, 8].forEach(function(i) {
|
||||
rand.writeInt32BE(Math.random() * Math.pow(2, 32) | 0, i);
|
||||
});
|
||||
}
|
||||
return rand.toString('base64').replace(/\//g, '_').replace(/\+/g, '-');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -706,7 +771,7 @@ Manager.prototype.handleHandshake = function (data, req, res) {
|
||||
};
|
||||
|
||||
function writeErr (status, message) {
|
||||
if (data.query.jsonp) {
|
||||
if (data.query.jsonp && jsonpolling_re.test(data.query.jsonp)) {
|
||||
res.writeHead(200, { 'Content-Type': 'application/javascript' });
|
||||
res.end('io.j[' + data.query.jsonp + '](new Error("' + message + '"));');
|
||||
} else {
|
||||
@@ -745,18 +810,18 @@ Manager.prototype.handleHandshake = function (data, req, res) {
|
||||
, self.transports(data).join(',')
|
||||
].join(':');
|
||||
|
||||
if (data.query.jsonp) {
|
||||
if (data.query.jsonp && jsonpolling_re.test(data.query.jsonp)) {
|
||||
hs = 'io.j[' + data.query.jsonp + '](' + JSON.stringify(hs) + ');';
|
||||
res.writeHead(200, { 'Content-Type': 'application/javascript' });
|
||||
} else {
|
||||
res.writeHead(200, headers);
|
||||
}
|
||||
|
||||
res.end(hs);
|
||||
|
||||
self.onHandshake(id, newData || handshakeData);
|
||||
self.store.publish('handshake', id, newData || handshakeData);
|
||||
|
||||
res.end(hs);
|
||||
|
||||
self.log.info('handshake authorized', id);
|
||||
} else {
|
||||
writeErr(403, 'handshake unauthorized');
|
||||
|
||||
@@ -15,7 +15,7 @@ var client = require('socket.io-client');
|
||||
* Version.
|
||||
*/
|
||||
|
||||
exports.version = '0.9.0';
|
||||
exports.version = '0.9.16';
|
||||
|
||||
/**
|
||||
* Supported protocol version.
|
||||
@@ -39,6 +39,13 @@ exports.clientVersion = client.version;
|
||||
*/
|
||||
|
||||
exports.listen = function (server, options, fn) {
|
||||
if ('function' == typeof server) {
|
||||
console.warn('Socket.IO\'s `listen()` method expects an `http.Server` instance\n'
|
||||
+ 'as its first parameter. Are you migrating from Express 2.x to 3.x?\n'
|
||||
+ 'If so, check out the "Socket.IO compatibility" section at:\n'
|
||||
+ 'https://github.com/visionmedia/express/wiki/Migrating-from-2.x-to-3.x');
|
||||
}
|
||||
|
||||
if ('function' == typeof options) {
|
||||
fn = options;
|
||||
options = {};
|
||||
|
||||
@@ -233,7 +233,7 @@ Socket.prototype.dispatch = function (packet, volatile) {
|
||||
this.manager.onClientDispatch(this.id, packet, volatile);
|
||||
}
|
||||
|
||||
this.manager.store.publish('dispatch:' + this.id, packet, volatile);
|
||||
this.manager.store.publish('dispatch-remote', this.id, packet, volatile);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -291,12 +291,19 @@ Socket.prototype.disconnect = function () {
|
||||
if (!this.disconnected) {
|
||||
this.log.info('booting client');
|
||||
|
||||
if (this.manager.transports[this.id] && this.manager.transports[this.id].open) {
|
||||
this.manager.transports[this.id].onForcedDisconnect();
|
||||
if ('' === this.namespace.name) {
|
||||
if (this.manager.transports[this.id] && this.manager.transports[this.id].open) {
|
||||
this.manager.transports[this.id].onForcedDisconnect();
|
||||
} else {
|
||||
this.manager.onClientDisconnect(this.id);
|
||||
this.manager.store.publish('disconnect-remote', this.id);
|
||||
}
|
||||
} else {
|
||||
this.manager.onClientDisconnect(this.id);
|
||||
this.manager.store.publish('disconnect:' + this.id);
|
||||
this.packet({type: 'disconnect'});
|
||||
this.manager.onLeave(this.id, this.namespace.name);
|
||||
this.$emit('disconnect', 'booted');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
@@ -178,7 +178,7 @@ Static.prototype.gzip = function (data, callback) {
|
||||
buffer.length = 0;
|
||||
});
|
||||
|
||||
gzip.on('exit', function () {
|
||||
gzip.on('close', function () {
|
||||
if (err) return callback(err);
|
||||
|
||||
var size = 0
|
||||
|
||||
@@ -89,20 +89,6 @@ Transport.prototype.onSocketConnect = function () { };
|
||||
Transport.prototype.setHandlers = function () {
|
||||
var self = this;
|
||||
|
||||
// we need to do this in a pub/sub way since the client can POST the message
|
||||
// over a different socket (ie: different Transport instance)
|
||||
this.store.subscribe('heartbeat-clear:' + this.id, function () {
|
||||
self.onHeartbeatClear();
|
||||
});
|
||||
|
||||
this.store.subscribe('disconnect-force:' + this.id, function () {
|
||||
self.onForcedDisconnect();
|
||||
});
|
||||
|
||||
this.store.subscribe('dispatch:' + this.id, function (packet, volatile) {
|
||||
self.onDispatch(packet, volatile);
|
||||
});
|
||||
|
||||
this.bound = {
|
||||
end: this.onSocketEnd.bind(this)
|
||||
, close: this.onSocketClose.bind(this)
|
||||
@@ -126,10 +112,6 @@ Transport.prototype.setHandlers = function () {
|
||||
|
||||
Transport.prototype.clearHandlers = function () {
|
||||
if (this.handlersSet) {
|
||||
this.store.unsubscribe('disconnect-force:' + this.id);
|
||||
this.store.unsubscribe('heartbeat-clear:' + this.id);
|
||||
this.store.unsubscribe('dispatch:' + this.id);
|
||||
|
||||
this.socket.removeListener('end', this.bound.end);
|
||||
this.socket.removeListener('close', this.bound.close);
|
||||
this.socket.removeListener('error', this.bound.error);
|
||||
@@ -350,7 +332,7 @@ Transport.prototype.onMessage = function (packet) {
|
||||
if (current && current.open) {
|
||||
current.onHeartbeatClear();
|
||||
} else {
|
||||
this.store.publish('heartbeat-clear:' + this.id);
|
||||
this.store.publish('heartbeat-clear', this.id);
|
||||
}
|
||||
} else {
|
||||
if ('disconnect' == packet.type && packet.endpoint == '') {
|
||||
@@ -359,7 +341,7 @@ Transport.prototype.onMessage = function (packet) {
|
||||
if (current) {
|
||||
current.onForcedDisconnect();
|
||||
} else {
|
||||
this.store.publish('disconnect-force:' + this.id);
|
||||
this.store.publish('disconnect-force', this.id);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -378,7 +360,7 @@ Transport.prototype.onMessage = function (packet) {
|
||||
current.onDispatch(ack);
|
||||
} else {
|
||||
this.manager.onClientDispatch(this.id, ack);
|
||||
this.store.publish('dispatch:' + this.id, ack);
|
||||
this.store.publish('dispatch-remote', this.id, ack);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,7 +368,7 @@ Transport.prototype.onMessage = function (packet) {
|
||||
if (current) {
|
||||
this.manager.onClientMessage(this.id, packet);
|
||||
} else {
|
||||
this.store.publish('message:' + this.id, packet);
|
||||
this.store.publish('message-remote', this.id, packet);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -455,7 +437,7 @@ Transport.prototype.onClose = function () {
|
||||
|
||||
Transport.prototype.end = function (reason) {
|
||||
if (!this.disconnected) {
|
||||
this.log.info('transport end');
|
||||
this.log.info('transport end (' + reason + ')');
|
||||
|
||||
var local = this.manager.transports[this.id];
|
||||
|
||||
@@ -464,10 +446,10 @@ Transport.prototype.end = function (reason) {
|
||||
this.disconnected = true;
|
||||
|
||||
if (local) {
|
||||
this.manager.onClientDisconnect(this.id, reason, true);
|
||||
} else {
|
||||
this.store.publish('disconnect:' + this.id, reason);
|
||||
this.manager.onClientDisconnect(this.id, reason);
|
||||
}
|
||||
|
||||
this.store.publish('disconnect-remote', this.id, reason);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
@@ -53,9 +52,16 @@ FlashSocket.prototype.name = 'flashsocket';
|
||||
FlashSocket.init = function (manager) {
|
||||
var server;
|
||||
function create () {
|
||||
|
||||
// Drop out immediately if the user has
|
||||
// disabled the flash policy server
|
||||
if (!manager.get('flash policy server')) {
|
||||
return;
|
||||
}
|
||||
|
||||
server = require('policyfile').createServer({
|
||||
log: function(msg){
|
||||
manager.log.info(msg.toLowerCase());
|
||||
manager.log.info(msg);
|
||||
}
|
||||
}, manager.get('origins'));
|
||||
|
||||
@@ -93,6 +99,23 @@ FlashSocket.init = function (manager) {
|
||||
}
|
||||
});
|
||||
|
||||
// create or destroy the server
|
||||
manager.on('set:flash policy server', function (value, key) {
|
||||
var transports = manager.get('transports');
|
||||
if (~transports.indexOf('flashsocket')) {
|
||||
if (server && !value) {
|
||||
// destroy the server
|
||||
try {
|
||||
server.close();
|
||||
}
|
||||
catch (e) { /* ignore exception. could e.g. be that the server isn't started yet */ }
|
||||
}
|
||||
} else if (!server && value) {
|
||||
// create the server
|
||||
create();
|
||||
}
|
||||
});
|
||||
|
||||
// only start the server
|
||||
manager.on('set:transports', function (value, key){
|
||||
if (!server && ~manager.get('transports').indexOf('flashsocket')) {
|
||||
|
||||
@@ -72,7 +72,8 @@ HTMLFile.prototype.handleRequest = function (req) {
|
||||
*/
|
||||
|
||||
HTMLFile.prototype.write = function (data) {
|
||||
data = '<script>_(' + JSON.stringify(data) + ');</script>';
|
||||
// escape all forward slashes. see GH-1251
|
||||
data = '<script>_(' + JSON.stringify(data).replace(/\//g, '\\/') + ');</script>';
|
||||
|
||||
if (this.response.write(data)) {
|
||||
this.drained = true;
|
||||
|
||||
@@ -43,6 +43,18 @@ HTTPPolling.prototype.__proto__ = HTTPTransport.prototype;
|
||||
|
||||
HTTPPolling.prototype.name = 'httppolling';
|
||||
|
||||
/**
|
||||
* Override setHandlers
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
HTTPPolling.prototype.setHandlers = function () {
|
||||
HTTPTransport.prototype.setHandlers.call(this);
|
||||
this.socket.removeListener('end', this.bound.end);
|
||||
this.socket.removeListener('close', this.bound.close);
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes heartbeat timeouts for polling.
|
||||
*/
|
||||
@@ -128,8 +140,8 @@ HTTPPolling.prototype.write = function (data, close) {
|
||||
* @api private
|
||||
*/
|
||||
|
||||
HTTPPolling.prototype.end = function () {
|
||||
HTTPPolling.prototype.end = function (reason) {
|
||||
this.clearPollTimeout();
|
||||
return HTTPTransport.prototype.end.call(this);
|
||||
return HTTPTransport.prototype.end.call(this, reason);
|
||||
};
|
||||
|
||||
|
||||
@@ -42,11 +42,15 @@ HTTPTransport.prototype.__proto__ = Transport.prototype;
|
||||
*/
|
||||
|
||||
HTTPTransport.prototype.handleRequest = function (req) {
|
||||
|
||||
// Always set the response in case an error is returned to the client
|
||||
this.response = req.res;
|
||||
|
||||
if (req.method == 'POST') {
|
||||
var buffer = ''
|
||||
, res = req.res
|
||||
, origin = req.headers.origin
|
||||
, headers = { 'Content-Length': 1 }
|
||||
, headers = { 'Content-Length': 1, 'Content-Type': 'text/plain; charset=UTF-8' }
|
||||
, self = this;
|
||||
|
||||
req.on('data', function (data) {
|
||||
@@ -68,16 +72,16 @@ HTTPTransport.prototype.handleRequest = function (req) {
|
||||
// prevent memory leaks for uncompleted requests
|
||||
req.on('close', function () {
|
||||
buffer = '';
|
||||
self.onClose();
|
||||
});
|
||||
|
||||
if (origin) {
|
||||
// https://developer.mozilla.org/En/HTTP_Access_Control
|
||||
headers['Access-Control-Allow-Origin'] = origin;
|
||||
headers['Access-Control-Allow-Credentials'] = 'true';
|
||||
headers['X-XSS-Protection'] = '0';
|
||||
}
|
||||
} else {
|
||||
this.response = req.res;
|
||||
|
||||
Transport.prototype.handleRequest.call(this, req);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
var HTTPPolling = require('./http-polling');
|
||||
var jsonpolling_re = /^\d+$/
|
||||
|
||||
/**
|
||||
* Export the constructor.
|
||||
@@ -29,7 +30,7 @@ function JSONPPolling (mng, data, req) {
|
||||
this.head = 'io.j[0](';
|
||||
this.foot = ');';
|
||||
|
||||
if (data.query.i) {
|
||||
if (data.query.i && jsonpolling_re.test(data.query.i)) {
|
||||
this.head = 'io.j[' + data.query.i + '](';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
@@ -31,7 +30,7 @@ function WebSocket (mng, data, req) {
|
||||
// parser
|
||||
var self = this;
|
||||
|
||||
this.parser = new Parser();
|
||||
this.parser = new Parser({maxBuffer: mng.get('destroy buffer size')});
|
||||
this.parser.on('data', function (packet) {
|
||||
self.log.debug(self.name + ' received data packet', packet);
|
||||
self.onMessage(parser.decodePacket(packet));
|
||||
@@ -42,6 +41,11 @@ function WebSocket (mng, data, req) {
|
||||
this.parser.on('error', function () {
|
||||
self.end();
|
||||
});
|
||||
this.parser.on('kick', function (reason) {
|
||||
self.log.warn(self.name + ' parser forced user kick: ' + reason);
|
||||
self.onMessage({type: 'disconnect', endpoint: ''});
|
||||
self.end();
|
||||
});
|
||||
|
||||
Transport.call(this, mng, data, req);
|
||||
};
|
||||
@@ -89,11 +93,14 @@ WebSocket.prototype.onSocketConnect = function () {
|
||||
}
|
||||
|
||||
var origin = this.req.headers['origin']
|
||||
, location = ((this.manager.settings['match origin protocol'] ?
|
||||
origin.match(/^https/) : this.socket.encrypted) ?
|
||||
'wss' : 'ws')
|
||||
+ '://' + this.req.headers.host + this.req.url
|
||||
, waitingForNonce = false;
|
||||
, waitingForNonce = false;
|
||||
if(this.manager.settings['match origin protocol']){
|
||||
location = (origin.indexOf('https')>-1 ? 'wss' : 'ws') + '://' + this.req.headers.host + this.req.url;
|
||||
}else if(this.socket.encrypted){
|
||||
location = 'wss://' + this.req.headers.host + this.req.url;
|
||||
}else{
|
||||
location = 'ws://' + this.req.headers.host + this.req.url;
|
||||
}
|
||||
|
||||
if (this.req.headers['sec-websocket-key1']) {
|
||||
// If we don't have the nonce yet, wait for it (HAProxy compatibility).
|
||||
@@ -291,7 +298,9 @@ WebSocket.prototype.doClose = function () {
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function Parser () {
|
||||
function Parser (opts) {
|
||||
this._maxBuffer = (opts && opts.maxBuffer) || 10E7;
|
||||
this._dataLength = 0;
|
||||
this.buffer = '';
|
||||
this.i = 0;
|
||||
};
|
||||
@@ -309,6 +318,13 @@ Parser.prototype.__proto__ = EventEmitter.prototype;
|
||||
*/
|
||||
|
||||
Parser.prototype.add = function (data) {
|
||||
this._dataLength += data.length;
|
||||
if(this._dataLength > this._maxBuffer) {
|
||||
this.buffer = ''; //Clear buffer
|
||||
this.emit('kick', 'max buffer size reached');
|
||||
return;
|
||||
}
|
||||
|
||||
this.buffer += data;
|
||||
this.parse();
|
||||
};
|
||||
|
||||
@@ -35,7 +35,7 @@ function WebSocket (mng, data, req) {
|
||||
var self = this;
|
||||
|
||||
this.manager = mng;
|
||||
this.parser = new Parser();
|
||||
this.parser = new Parser({maxBuffer: mng.get('destroy buffer size')});
|
||||
this.parser.on('data', function (packet) {
|
||||
self.onMessage(parser.decodePacket(packet));
|
||||
});
|
||||
@@ -56,6 +56,11 @@ function WebSocket (mng, data, req) {
|
||||
self.log.warn(self.name + ' parser error: ' + reason);
|
||||
self.end();
|
||||
});
|
||||
this.parser.on('kick', function (reason) {
|
||||
self.log.warn(self.name + ' parser forced user kick: ' + reason);
|
||||
self.onMessage({type: 'disconnect', endpoint: ''});
|
||||
self.end();
|
||||
});
|
||||
|
||||
Transport.call(this, mng, data, req);
|
||||
};
|
||||
@@ -266,7 +271,7 @@ WebSocket.prototype.doClose = function () {
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function Parser () {
|
||||
function Parser (opts) {
|
||||
this.state = {
|
||||
activeFragmentedOperation: null,
|
||||
lastFragment: false,
|
||||
@@ -278,6 +283,8 @@ function Parser () {
|
||||
this.expectBuffer = null;
|
||||
this.expectHandler = null;
|
||||
this.currentMessage = '';
|
||||
this._maxBuffer = (opts && opts.maxBuffer) || 10E7;
|
||||
this._dataLength = 0;
|
||||
|
||||
var self = this;
|
||||
this.opcodeHandlers = {
|
||||
@@ -448,6 +455,15 @@ Parser.prototype.__proto__ = EventEmitter.prototype;
|
||||
*/
|
||||
|
||||
Parser.prototype.add = function(data) {
|
||||
this._dataLength += data.length;
|
||||
if (this._dataLength > this._maxBuffer) {
|
||||
// Clear data
|
||||
this.overflow = null;
|
||||
this.expectBuffer = null;
|
||||
// Kick client
|
||||
this.emit('kick', 'max buffer size reached');
|
||||
return;
|
||||
}
|
||||
if (this.expectBuffer == null) {
|
||||
this.addToOverflow(data);
|
||||
return;
|
||||
@@ -491,6 +507,10 @@ Parser.prototype.addToOverflow = function(data) {
|
||||
*/
|
||||
|
||||
Parser.prototype.expect = function(what, length, handler) {
|
||||
if (length > this._maxBuffer) {
|
||||
this.emit('kick', 'expected input larger than max buffer');
|
||||
return;
|
||||
}
|
||||
this.expectBuffer = new Buffer(length);
|
||||
this.expectOffset = 0;
|
||||
this.expectHandler = handler;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
@@ -35,7 +34,7 @@ function WebSocket (mng, data, req) {
|
||||
var self = this;
|
||||
|
||||
this.manager = mng;
|
||||
this.parser = new Parser();
|
||||
this.parser = new Parser({maxBuffer: mng.get('destroy buffer size')});
|
||||
this.parser.on('data', function (packet) {
|
||||
self.onMessage(parser.decodePacket(packet));
|
||||
});
|
||||
@@ -56,6 +55,11 @@ function WebSocket (mng, data, req) {
|
||||
self.log.warn(self.name + ' parser error: ' + reason);
|
||||
self.end();
|
||||
});
|
||||
this.parser.on('kick', function (reason) {
|
||||
self.log.warn(self.name + ' parser forced user kick: ' + reason);
|
||||
self.onMessage({type: 'disconnect', endpoint: ''});
|
||||
self.end();
|
||||
});
|
||||
|
||||
Transport.call(this, mng, data, req);
|
||||
};
|
||||
@@ -98,7 +102,7 @@ WebSocket.prototype.onSocketConnect = function () {
|
||||
return;
|
||||
}
|
||||
|
||||
var origin = this.req.headers['origin']
|
||||
var origin = this.req.headers['origin'] || ''
|
||||
, location = ((this.manager.settings['match origin protocol'] ?
|
||||
origin.match(/^https/) : this.socket.encrypted) ?
|
||||
'wss' : 'ws')
|
||||
@@ -266,7 +270,7 @@ WebSocket.prototype.doClose = function () {
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function Parser () {
|
||||
function Parser (opts) {
|
||||
this.state = {
|
||||
activeFragmentedOperation: null,
|
||||
lastFragment: false,
|
||||
@@ -278,6 +282,8 @@ function Parser () {
|
||||
this.expectBuffer = null;
|
||||
this.expectHandler = null;
|
||||
this.currentMessage = '';
|
||||
this._maxBuffer = (opts && opts.maxBuffer) || 10E7;
|
||||
this._dataLength = 0;
|
||||
|
||||
var self = this;
|
||||
this.opcodeHandlers = {
|
||||
@@ -448,6 +454,15 @@ Parser.prototype.__proto__ = EventEmitter.prototype;
|
||||
*/
|
||||
|
||||
Parser.prototype.add = function(data) {
|
||||
this._dataLength += data.length;
|
||||
if (this._dataLength > this._maxBuffer) {
|
||||
// Clear data
|
||||
this.overflow = null;
|
||||
this.expectBuffer = null;
|
||||
// Kick client
|
||||
this.emit('kick', 'max buffer size reached');
|
||||
return;
|
||||
}
|
||||
if (this.expectBuffer == null) {
|
||||
this.addToOverflow(data);
|
||||
return;
|
||||
@@ -491,6 +506,10 @@ Parser.prototype.addToOverflow = function(data) {
|
||||
*/
|
||||
|
||||
Parser.prototype.expect = function(what, length, handler) {
|
||||
if (length > this._maxBuffer) {
|
||||
this.emit('kick', 'expected input larger than max buffer');
|
||||
return;
|
||||
}
|
||||
this.expectBuffer = new Buffer(length);
|
||||
this.expectOffset = 0;
|
||||
this.expectHandler = handler;
|
||||
|
||||
11
package.json
11
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "socket.io"
|
||||
, "version": "0.9.0"
|
||||
, "version": "0.9.17"
|
||||
, "description": "Real-time apps made cross-browser & easy with a WebSocket-like API"
|
||||
, "homepage": "http://socket.io"
|
||||
, "keywords": ["websocket", "socket", "realtime", "socket.io", "comet", "ajax"]
|
||||
@@ -16,17 +16,20 @@
|
||||
, "url": "https://github.com/LearnBoost/socket.io.git"
|
||||
}
|
||||
, "dependencies": {
|
||||
"socket.io-client": "0.9.0"
|
||||
"socket.io-client": "0.9.16"
|
||||
, "policyfile": "0.0.4"
|
||||
, "redis": "0.6.7"
|
||||
, "base64id": "0.1.0"
|
||||
}
|
||||
, "devDependencies": {
|
||||
"expresso": "0.9.2"
|
||||
, "should": "0.0.4"
|
||||
, "should": "*"
|
||||
, "benchmark": "0.2.2"
|
||||
, "microtime": "0.1.3-1"
|
||||
, "colors": "0.5.1"
|
||||
}
|
||||
, "optionalDependencies": {
|
||||
"redis": "0.7.3"
|
||||
}
|
||||
, "main": "index"
|
||||
, "engines": { "node": ">= 0.4.0" }
|
||||
, "scripts": {
|
||||
|
||||
@@ -103,7 +103,11 @@ HTTPClient.prototype.end = function () {
|
||||
Object.keys(this.agent.sockets).forEach(function (socket) {
|
||||
for (var i = 0, l = self.agent.sockets[socket].length; i < l; ++i) {
|
||||
if (self.agent.sockets[socket][i]._handle) {
|
||||
self.agent.sockets[socket][i]._handle.socket.end();
|
||||
if (self.agent.sockets[socket][i]._handle.socket) {
|
||||
self.agent.sockets[socket][i]._handle.socket.end();
|
||||
} else {
|
||||
self.agent.sockets[socket][i]._handle.owner.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -282,5 +282,46 @@ module.exports = {
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
'disconnecting from namespace only': function (done) {
|
||||
var cl = client(++ports)
|
||||
, io = create(cl)
|
||||
, ws1
|
||||
, ws2;
|
||||
|
||||
io.of('/foo').on('connection', function (socket) {
|
||||
socket.disconnect();
|
||||
});
|
||||
|
||||
cl.handshake(function (sid) {
|
||||
ws1 = websocket(cl, sid);
|
||||
ws1.on('open', function () {
|
||||
ws1.packet({
|
||||
type: 'connect'
|
||||
, endpoint: '/bar'
|
||||
});
|
||||
cl.handshake(function (sid) {
|
||||
ws2 = websocket(cl, sid);
|
||||
ws2.on('open', function () {
|
||||
ws2.packet({
|
||||
type: 'connect'
|
||||
, endpoint: '/foo'
|
||||
});
|
||||
});
|
||||
ws2.on('message', function (data) {
|
||||
if ('disconnect' === data.type) {
|
||||
cl.end();
|
||||
ws1.finishClose();
|
||||
ws2.finishClose();
|
||||
io.server.close();
|
||||
|
||||
data.endpoint.should.eql('/foo');
|
||||
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -95,7 +95,7 @@ module.exports = {
|
||||
'decoding json packet with message id and ack data': function () {
|
||||
parser.decodePacket('4:1+::{"a":"b"}').should.eql({
|
||||
type: 'json'
|
||||
, id: 1
|
||||
, id: '1'
|
||||
, ack: 'data'
|
||||
, endpoint: ''
|
||||
, data: { a: 'b' }
|
||||
@@ -114,7 +114,7 @@ module.exports = {
|
||||
'decoding an event packet with message id and ack': function () {
|
||||
parser.decodePacket('5:1+::{"name":"tobi"}').should.eql({
|
||||
type: 'event'
|
||||
, id: 1
|
||||
, id: '1'
|
||||
, ack: 'data'
|
||||
, endpoint: ''
|
||||
, name: 'tobi'
|
||||
@@ -143,7 +143,7 @@ module.exports = {
|
||||
'decoding a message packet with id and endpoint': function () {
|
||||
parser.decodePacket('3:5:/tobi').should.eql({
|
||||
type: 'message'
|
||||
, id: 5
|
||||
, id: '5'
|
||||
, ack: true
|
||||
, endpoint: '/tobi'
|
||||
, data: ''
|
||||
@@ -245,7 +245,7 @@ module.exports = {
|
||||
'encoding json packet with message id and ack data': function () {
|
||||
parser.encodePacket({
|
||||
type: 'json'
|
||||
, id: 1
|
||||
, id: '1'
|
||||
, ack: 'data'
|
||||
, endpoint: ''
|
||||
, data: { a: 'b' }
|
||||
@@ -264,7 +264,7 @@ module.exports = {
|
||||
'encoding an event packet with message id and ack': function () {
|
||||
parser.encodePacket({
|
||||
type: 'event'
|
||||
, id: 1
|
||||
, id: '1'
|
||||
, ack: 'data'
|
||||
, endpoint: ''
|
||||
, name: 'tobi'
|
||||
@@ -292,7 +292,7 @@ module.exports = {
|
||||
'encoding a message packet with id and endpoint': function () {
|
||||
parser.encodePacket({
|
||||
type: 'message'
|
||||
, id: 5
|
||||
, id: '5'
|
||||
, ack: true
|
||||
, endpoint: '/tobi'
|
||||
, data: ''
|
||||
|
||||
@@ -452,7 +452,7 @@ module.exports = {
|
||||
|
||||
cl.get('/socket.io/socket.io.js', function (res, data) {
|
||||
res.headers['content-type'].should.eql('application/javascript');
|
||||
res.headers['content-length'].should.eql(13);
|
||||
res.headers['content-length'].should.eql('13');
|
||||
res.headers.etag.should.eql('1.0');
|
||||
|
||||
data.should.eql('custom_client');
|
||||
|
||||
@@ -104,7 +104,7 @@ module.exports = {
|
||||
netConnection(port, function (err, data){
|
||||
should.strictEqual(err, null);
|
||||
|
||||
data.toString().should.include.string('<cross-domain-policy>');
|
||||
data.toString().should.match(/<cross-domain-policy>/);
|
||||
|
||||
this.destroy();
|
||||
io.flashPolicyServer.close();
|
||||
@@ -133,7 +133,7 @@ module.exports = {
|
||||
netConnection(next, function (err, data){
|
||||
should.strictEqual(err, null);
|
||||
|
||||
data.toString().should.include.string('<cross-domain-policy>');
|
||||
data.toString().should.match(/<cross-domain-policy>/);
|
||||
|
||||
this.destroy();
|
||||
io.flashPolicyServer.close();
|
||||
@@ -159,7 +159,7 @@ module.exports = {
|
||||
server.origins.should.not.contain('google.com:80');
|
||||
server.origins.should.contain('foo.bar:80');
|
||||
server.origins.should.contain('socket.io:1337');
|
||||
server.buffer.toString('utf8').should.include.string('socket.io');
|
||||
server.buffer.toString('utf8').should.match(/socket\.io/);
|
||||
|
||||
io.flashPolicyServer.close();
|
||||
done();
|
||||
|
||||
@@ -77,10 +77,14 @@ HTMLFile.prototype.data = function (path, opts, fn) {
|
||||
|
||||
case 2:
|
||||
if (buf.indexOf(foot) != -1) {
|
||||
var data = buf.slice(0, buf.indexOf(foot))
|
||||
, obj = JSON.parse(data);
|
||||
var data = buf.slice(0, buf.indexOf(foot));
|
||||
|
||||
fn(obj === '' ? obj : parser.decodePayload(obj), ++messages);
|
||||
if (false === opts.parse) {
|
||||
fn(data, ++messages);
|
||||
} else {
|
||||
var obj = JSON.parse(data);
|
||||
fn(obj === '' ? obj : parser.decodePayload(obj), ++messages);
|
||||
}
|
||||
|
||||
buf = buf.substr(data.length + foot.length);
|
||||
state = 1;
|
||||
@@ -453,6 +457,78 @@ module.exports = {
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
'test escaping for security': function (done) {
|
||||
var port = ++ports
|
||||
, cl = client(port)
|
||||
, io = create(cl)
|
||||
, messaged = false;
|
||||
|
||||
io.configure(function () {
|
||||
io.set('close timeout', 0);
|
||||
});
|
||||
|
||||
io.sockets.on('connection', function (socket) {
|
||||
socket.emit('</script> woot');
|
||||
|
||||
socket.on('disconnect', function () {
|
||||
io.server.close();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
cl.handshake(function (sid) {
|
||||
cl.data('/socket.io/{protocol}/htmlfile/' + sid, { parse: false }, function (msg, i) {
|
||||
switch (i) {
|
||||
case 2:
|
||||
msg.should.not.include('</script');
|
||||
cl.end();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
'test that unescaping works': function(done){
|
||||
var port = ++ports
|
||||
, cl = client(port)
|
||||
, io = create(cl)
|
||||
, messaged = false;
|
||||
|
||||
io.configure(function () {
|
||||
io.set('close timeout', 0);
|
||||
});
|
||||
|
||||
io.sockets.on('connection', function (socket) {
|
||||
socket.emit('woot </script> <//script>', '</script><script>');
|
||||
|
||||
socket.on('disconnect', function () {
|
||||
io.server.close();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
cl.handshake(function (sid) {
|
||||
cl.data('/socket.io/{protocol}/htmlfile/' + sid, function (msgs, i) {
|
||||
switch (i) {
|
||||
case 1:
|
||||
msgs.should.have.length(1);
|
||||
msgs[0].type.should.eql('connect');
|
||||
msgs[0].endpoint.should.eql('');
|
||||
break;
|
||||
|
||||
case 2:
|
||||
msgs.should.have.length(1);
|
||||
msgs[0].should.eql({
|
||||
type: 'event'
|
||||
, name: 'woot </script> <//script>'
|
||||
, endpoint: ''
|
||||
, args: ['</script><script>']
|
||||
});
|
||||
cl.end();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -257,7 +257,7 @@ module.exports = {
|
||||
, sid;
|
||||
|
||||
io.configure(function () {
|
||||
io.set('close timeout', .05);
|
||||
io.set('close timeout', .1);
|
||||
});
|
||||
|
||||
io.sockets.on('connection', function (socket) {
|
||||
@@ -625,7 +625,7 @@ module.exports = {
|
||||
|
||||
io.configure(function () {
|
||||
io.set('polling duration', .2);
|
||||
io.set('close timeout', .2);
|
||||
io.set('close timeout', .5);
|
||||
});
|
||||
|
||||
io.sockets.on('connection', function (socket) {
|
||||
|
||||
@@ -25,7 +25,7 @@ module.exports = {
|
||||
, ws;
|
||||
|
||||
io.set('transports', ['websocket']);
|
||||
io.sockets.on('connection', function (socket) {
|
||||
io.on('connection', function (socket) {
|
||||
socket.manager.transports[socket.id].name.should.equal('websocket');
|
||||
ws.finishClose();
|
||||
cl.end();
|
||||
|
||||
@@ -289,6 +289,40 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test that connection close does not mean disconnect': function (done) {
|
||||
var cl = client(++ports)
|
||||
, io = create(cl)
|
||||
, sid
|
||||
, end
|
||||
, disconnected = false
|
||||
|
||||
io.configure(function () {
|
||||
io.set('polling duration', .2);
|
||||
io.set('close timeout', .5);
|
||||
});
|
||||
|
||||
io.sockets.on('connection', function (client) {
|
||||
end = function () {
|
||||
cl.end();
|
||||
console.log('ending');
|
||||
client.on('disconnect', function () {
|
||||
disconnected = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
cl.handshake(function (sid) {
|
||||
cl.get('/socket.io/{protocol}/xhr-polling/' + sid);
|
||||
setTimeout(end, 30);
|
||||
setTimeout(function () {
|
||||
console.log('finished');
|
||||
disconnected.should.be.false;
|
||||
io.server.close();
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
},
|
||||
|
||||
'test sending back data': function (done) {
|
||||
var cl = client(++ports)
|
||||
, io = create(cl);
|
||||
@@ -1317,7 +1351,7 @@ module.exports = {
|
||||
msgs.should.have.length(1);
|
||||
msgs[0].should.eql({
|
||||
type: 'ack'
|
||||
, ackId: 1
|
||||
, ackId: '1'
|
||||
, endpoint: ''
|
||||
, args: []
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user