Compare commits

...

48 Commits

Author SHA1 Message Date
Damien Arrachequesne
ed74dee3b0 Release 0.9.18 2017-05-07 07:54:20 +02:00
John Chadwick
9ad1fd2771 Remove process.EventEmitter usage for Node 7.x
process.EventEmitter has been deprecated and removed from Node.
2017-05-07 07:50:00 +02:00
Guillermo Rauch
d25c5484c3 Release 0.9.17 2014-05-22 11:03:55 -07:00
Guillermo Rauch
fea676b90e Merge pull request #1371 from surespot/channelfix
Use static channels for node syncing.
2014-05-22 10:49:53 -07:00
Adam Patacchiola
386d2a9c0c don't call non existant transport onDisconnect 2013-12-13 10:02:20 -07:00
Adam Patacchiola
8b47789414 use static channels for remote syncing instead of subscribing/unsubscribing 5 channels for every connection 2013-12-13 07:22:43 -07:00
Guillermo Rauch
47b06c0fcf Merge pull request #1333 from yujiosaka/0.9
http-polling : adding 'X-XSS-Protection : 0;' to headers necessary not o...
2013-12-09 08:17:42 -08:00
Guillermo Rauch
9823325a1f Merge pull request #1346 from DeadAlready/0.9-security-fix
Use destroy buffer size on websocket transport method as well
2013-11-15 04:01:16 -08:00
Karl Düüna
a47d76b990 Use destroy buffer size on websocket transport method as well 2013-11-15 10:31:00 +02:00
yujiosaka
db3ac4b415 http-polling : adding 'X-XSS-Protection : 0;' to headers necessary not only to jsonp-polling but http-polling 2013-10-24 14:53:19 +09:00
Guillermo Rauch
b9a2804b1a Merge pull request #1323 from tico8/0.9-bug
Memory leak : If a lot of connections continue being disconnected, a memory will leak.
2013-10-09 08:32:44 -07:00
tico8
b4182a5d42 Memory leak : If a lot of connections continue being disconnected, a memory will leak. 2013-10-09 01:06:02 +09:00
Guillermo Rauch
5120a706f2 Release 0.9.16 2013-06-06 08:39:48 -07:00
Guillermo Rauch
ee078cb124 transports: added tests for htmlfile escaping/unescaping 2013-06-06 08:38:57 -07:00
Guillermo Rauch
64d8f572aa Release 0.9.15 2013-06-06 08:22:29 -07:00
Guillermo Rauch
4e1ba9f872 transports: escaping (fixes #1251) 2013-06-06 08:17:40 -07:00
Guillermo Rauch
5d93af994a Release 0.9.14 2013-03-29 14:15:52 -07:00
Guillermo Rauch
6e25c802cc manager: fix memory leak with SSL 2013-03-29 14:14:42 -07:00
Guillermo Rauch
37690f78d7 Release 0.9.13 2012-12-13 15:15:38 -03:00
Guillermo Rauch
3cbd00ca70 package: fixed base64id requirement 2012-12-13 15:15:15 -03:00
Guillermo Rauch
b2a8ed1421 Release 0.9.12 2012-12-13 08:19:16 -03:00
Guillermo Rauch
0d3313f536 manager: fix for latest node which is returning a clone with listeners [viirya] 2012-12-13 08:18:42 -03:00
Guillermo Rauch
3b7224c7e0 Release 0.9.11 2012-11-02 08:03:15 -07:00
Guillermo Rauch
2030cf1432 package: move redis to optionalDependenices [3rd-Eden] 2012-11-02 08:01:24 -07:00
Guillermo Rauch
de9e8dffe1 Release 0.9.10 2012-08-10 13:34:50 -07:00
Guillermo Rauch
3a3044ebba Merge pull request #972 from Coreh/express-3.x-readme
Add express 3.0 instructions on Readme.md
2012-08-10 10:17:55 -07:00
Guillermo Rauch
d10b4dd1bd Merge pull request #985 from GICodeWarrior/log-case-fix
Don't lowercase log messages
2012-08-08 18:03:57 -07:00
Rusty Burchfield
12beee2d63 Don't lowercase log messages
Lowercasing log messages is unnecessary.  It makes some messages difficult to
read, and others difficult to search for.
2012-08-08 11:32:57 -07:00
Guillermo Rauch
875f14d16b Revert "Fix infinite recursion in Websocket parsers."
This reverts commit c218468f67.
2012-08-07 13:18:41 -07:00
Guillermo Rauch
8ca8990a0c Merge pull request #983 from GICodeWarrior/parser-recursion
Fix infinite recursion in Websocket parsers.
2012-08-06 13:16:37 -07:00
Rusty Burchfield
c218468f67 Fix infinite recursion in Websocket parsers.
If a client is feeding messages faster than server can handle them, infinite
recursion occurs.  Basically, the "overflow" data gets added to the parser and
it immediately parses a new message.

The fix pushes the processing of the next message (in this edge case) onto the
event queue.  This prevents the stack from recursing indefinitely.  This also
prevents a fast client from starving other clients.
2012-08-06 13:03:51 -07:00
Guillermo Rauch
4164e3bd7e Merge pull request #981 from doozr/honour-flash-settings
Honour flash settings
2012-08-06 08:59:17 -07:00
Guillermo Rauch
46227e7ac9 Merge pull request #980 from doozr/jsonp-error-crash
Always set the HTTP response in case an error should be returned to the client
2012-08-06 08:58:57 -07:00
Craig Andrews
d723d363b2 Always set the HTTP response in case an error should be returned to the client 2012-08-06 14:16:06 +01:00
Craig Andrews
fa1c1b2ada Create or destroy the flash policy server on configuration change 2012-08-06 14:14:15 +01:00
Craig Andrews
d32a848c3f Honour configuration to disable flash policy server 2012-08-06 14:14:14 +01:00
Guillermo Rauch
48ad0d3d1d Release 0.9.9 2012-08-01 15:14:02 -07:00
Guillermo Rauch
281a467960 manager: added response to sync disconnect xhrs 2012-08-01 15:08:06 -07:00
Guillermo Rauch
1fa74a46a3 Revert "Fix disconnectSync getting ignored"
This reverts commit f48b40e134.
2012-08-01 11:58:28 -07:00
Guillermo Rauch
ca4e3f32a3 Merge pull request #975 from huancz/master
fix issue #961 - restore compatibility with earlier node releases (up to 0.4.x)
2012-07-31 08:34:22 -07:00
Guillermo Rauch
9dd8134e6a Merge pull request #970 from renier/master
Codebase needs a license file (#965)
2012-07-31 08:32:07 -07:00
Renier Morales
180f1c91b9 Put license text in its own file (#965) 2012-07-31 11:07:21 -04:00
Marco Aurélio
bddf652c25 Add express 3.0 instructions on Readme.md 2012-07-30 15:53:47 -03:00
Guillermo Rauch
c795e4cf1a Merge pull request #971 from Coreh/express-3.x-warn
Add warning to .listen() to ease the migration to Express 3.x
2012-07-30 11:49:53 -07:00
Marco Aurélio
6afbb34581 Add warning to .listen() to ease the migration to Express 3.x 2012-07-30 15:43:00 -03:00
Guillermo Rauch
ac39dbc721 Merge pull request #964 from crickeys/xhr_polling_disconnectSync
Fix disconnectSync getting ignored
2012-07-27 10:06:03 -07:00
Petr Běhan
a5c5c20438 restore compatibility with node 0.4.x 2012-07-27 15:38:57 +02:00
Brian Gruber
f48b40e134 Fix disconnectSync getting ignored
If using xhr-polling and a browser closes a tab or window, the
disconnectSync in the socket.io-client method is called which sends an
XHR request to the server indicating a disconnect. This line would cause
that to be ignored and so the server would have to wait for a timeout to
mark them as disconnect. This was possibly because it was sent from a
different tcp socket than the current connection.
2012-07-26 21:19:00 -05:00
18 changed files with 366 additions and 91 deletions

View File

@@ -1,4 +1,65 @@
0.9.18 / 2017-05-07
===================
* Remove process.EventEmitter usage for Node 7.x
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
==================

22
LICENSE Normal file
View 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.

View File

@@ -21,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);

View File

@@ -39,7 +39,7 @@ var Client = irc.Client = function(host, port) {
this.user = null;
this.real = null;
}
sys.inherits(Client, process.EventEmitter);
sys.inherits(Client, require('events'));
Client.prototype.connect = function(nick, user, real) {
var connection = tcp.createConnection(this.port, this.host);

View File

@@ -21,7 +21,7 @@ var fs = require('fs')
, MemoryStore = require('./stores/memory')
, SocketNamespace = require('./namespace')
, Static = require('./static')
, EventEmitter = process.EventEmitter;
, EventEmitter = require('events');
/**
* Export the constructor.
@@ -113,6 +113,7 @@ function Manager (server, options) {
// reset listeners
this.oldListeners = server.listeners('request').splice(0);
server.removeAllListeners('request');
server.on('request', function (req, res) {
self.handleRequest(req, res);
@@ -319,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.
*
@@ -353,19 +392,17 @@ Manager.prototype.onOpen = function (id) {
if (this.closed[id]) {
var self = this;
this.store.unsubscribe('dispatch:' + id, function () {
var transport = self.transports[id];
if (self.closed[id] && self.closed[id].length && transport) {
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] = [];
}
// 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
@@ -456,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);
}
});
};
/**
@@ -511,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]) {
@@ -541,13 +572,6 @@ Manager.prototype.onDisconnect = function (id, local) {
}
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);
}
};
/**
@@ -615,6 +639,7 @@ Manager.prototype.handleUpgrade = function (req, socket, head) {
req.head = head;
this.handleClient(data, req);
req.head = null;
};
/**
@@ -639,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;
}
@@ -694,14 +722,6 @@ Manager.prototype.handleClient = function (data, req) {
}
}
}
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) {
@@ -720,6 +740,10 @@ Manager.prototype.handleClient = function (data, req) {
Manager.prototype.generateId = function () {
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) {
@@ -793,11 +817,11 @@ Manager.prototype.handleHandshake = function (data, req, res) {
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');

View File

@@ -3,7 +3,7 @@
*/
var Socket = require('./socket')
, EventEmitter = process.EventEmitter
, EventEmitter = require('events')
, parser = require('./parser')
, util = require('./util');

View File

@@ -15,7 +15,7 @@ var client = require('socket.io-client');
* Version.
*/
exports.version = '0.9.8';
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 = {};

View File

@@ -11,7 +11,7 @@
var parser = require('./parser')
, util = require('./util')
, EventEmitter = process.EventEmitter
, EventEmitter = require('events')
/**
* Export the constructor.
@@ -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);
}
};
@@ -296,7 +296,7 @@ Socket.prototype.disconnect = function () {
this.manager.transports[this.id].onForcedDisconnect();
} else {
this.manager.onClientDisconnect(this.id);
this.manager.store.publish('disconnect:' + this.id);
this.manager.store.publish('disconnect-remote', this.id);
}
} else {
this.packet({type: 'disconnect'});

View File

@@ -15,7 +15,7 @@ exports = module.exports = Store;
* Module dependencies.
*/
var EventEmitter = process.EventEmitter;
var EventEmitter = require('events');
/**
* Store interface

View File

@@ -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);
}
}
};
@@ -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);
}
};

View File

@@ -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')) {

View File

@@ -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;

View File

@@ -42,6 +42,10 @@ 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
@@ -75,10 +79,9 @@ HTTPTransport.prototype.handleRequest = function (req) {
// 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);
}
};

View File

@@ -9,7 +9,7 @@
*/
var Transport = require('../../transport')
, EventEmitter = process.EventEmitter
, EventEmitter = require('events')
, crypto = require('crypto')
, parser = require('../../parser');
@@ -30,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));
@@ -41,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);
};
@@ -293,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;
};
@@ -311,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();
};

View File

@@ -10,7 +10,7 @@
*/
var Transport = require('../../transport')
, EventEmitter = process.EventEmitter
, EventEmitter = require('events')
, crypto = require('crypto')
, url = require('url')
, parser = require('../../parser')
@@ -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;

View File

@@ -9,7 +9,7 @@
*/
var Transport = require('../../transport')
, EventEmitter = process.EventEmitter
, EventEmitter = require('events')
, crypto = require('crypto')
, url = require('url')
, parser = require('../../parser')
@@ -34,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));
});
@@ -55,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);
};
@@ -265,7 +270,7 @@ WebSocket.prototype.doClose = function () {
* @api public
*/
function Parser () {
function Parser (opts) {
this.state = {
activeFragmentedOperation: null,
lastFragment: false,
@@ -277,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 = {
@@ -447,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;
@@ -490,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;

View File

@@ -1,6 +1,6 @@
{
"name": "socket.io"
, "version": "0.9.8"
, "version": "0.9.18"
, "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.8"
"socket.io-client": "0.9.16"
, "policyfile": "0.0.4"
, "redis": "0.7.2"
, "base64id": "0.1.0"
}
, "devDependencies": {
"expresso": "0.9.2"
, "should": "*"
, "benchmark": "0.2.2"
, "microtime": "0.1.3-1"
, "microtime": "2.1.3"
, "colors": "0.5.1"
}
, "optionalDependencies": {
"redis": "0.7.3"
}
, "main": "index"
, "engines": { "node": ">= 0.4.0" }
, "scripts": {

View File

@@ -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();
}
});
});
}
};