mirror of
https://github.com/socketio/socket.io.git
synced 2026-01-14 17:37:56 -05:00
Compare commits
16 Commits
socket.io@
...
2.5.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88b2cdb6ab | ||
|
|
d30630ba10 | ||
|
|
f927ba29ef | ||
|
|
baa6804440 | ||
|
|
f223178eb6 | ||
|
|
226cc16165 | ||
|
|
05e1278cfa | ||
|
|
22d4bdf00d | ||
|
|
dfded53593 | ||
|
|
e6b869738c | ||
|
|
a169050947 | ||
|
|
873fdc55ed | ||
|
|
f78a575f66 | ||
|
|
d33a619905 | ||
|
|
3951a79359 | ||
|
|
6fa026fc94 |
24
.github/workflows/ci.yml
vendored
Normal file
24
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test-node:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [10.x, 12.x, 14.x]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
- run: npm ci
|
||||||
|
- run: npm test
|
||||||
|
env:
|
||||||
|
CI: true
|
||||||
12
.travis.yml
12
.travis.yml
@@ -1,12 +0,0 @@
|
|||||||
language: node_js
|
|
||||||
sudo: false
|
|
||||||
node_js:
|
|
||||||
- '8'
|
|
||||||
- '10'
|
|
||||||
notifications:
|
|
||||||
irc: "irc.freenode.org#socket.io"
|
|
||||||
git:
|
|
||||||
depth: 1
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- node_modules
|
|
||||||
36
CHANGELOG.md
Normal file
36
CHANGELOG.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
## [2.5.1](https://github.com/socketio/socket.io/compare/2.5.0...2.5.1) (2024-06-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add a noop handler for the error event ([d30630b](https://github.com/socketio/socket.io/commit/d30630ba10562bf987f4d2b42440fc41a828119c))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [2.5.0](https://github.com/socketio/socket.io/compare/2.4.1...2.5.0) (2022-06-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix race condition in dynamic namespaces ([05e1278](https://github.com/socketio/socket.io/commit/05e1278cfa99f3ecf3f8f0531ffe57d850e9a05b))
|
||||||
|
* ignore packet received after disconnection ([22d4bdf](https://github.com/socketio/socket.io/commit/22d4bdf00d1a03885dc0171125faddfaef730066))
|
||||||
|
* only set 'connected' to true after middleware execution ([226cc16](https://github.com/socketio/socket.io/commit/226cc16165f9fe60f16ff4d295fb91c8971cde35))
|
||||||
|
* prevent the socket from joining a room after disconnection ([f223178](https://github.com/socketio/socket.io/commit/f223178eb655a7713303b21a78f9ef9e161d6458))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.4.1](https://github.com/socketio/socket.io/compare/2.4.0...2.4.1) (2021-01-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Reverts
|
||||||
|
|
||||||
|
* fix(security): do not allow all origins by default ([a169050](https://github.com/socketio/socket.io/commit/a1690509470e9dd5559cec4e60908ca6c23e9ba0))
|
||||||
|
|
||||||
|
|
||||||
|
# [2.4.0](https://github.com/socketio/socket.io/compare/2.3.0...2.4.0) (2021-01-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **security:** do not allow all origins by default ([f78a575](https://github.com/socketio/socket.io/commit/f78a575f66ab693c3ea96ea88429ddb1a44c86c7))
|
||||||
|
* properly overwrite the query sent in the handshake ([d33a619](https://github.com/socketio/socket.io/commit/d33a619905a4905c153d4fec337c74da5b533a9e))
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
# socket.io
|
# socket.io
|
||||||
|
|
||||||
[](#backers) [](#sponsors)
|
[](#backers) [](#sponsors)
|
||||||
[](https://travis-ci.org/socketio/socket.io)
|
[](https://github.com/socketio/socket.io/actions)
|
||||||
[](https://david-dm.org/socketio/socket.io)
|
[](https://david-dm.org/socketio/socket.io)
|
||||||
[](https://david-dm.org/socketio/socket.io#info=devDependencies)
|
[](https://david-dm.org/socketio/socket.io#info=devDependencies)
|
||||||
[](https://www.npmjs.com/package/socket.io)
|
[](https://www.npmjs.com/package/socket.io)
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ Client.prototype.connect = function(name, query){
|
|||||||
|
|
||||||
this.server.checkNamespace(name, query, (dynamicNsp) => {
|
this.server.checkNamespace(name, query, (dynamicNsp) => {
|
||||||
if (dynamicNsp) {
|
if (dynamicNsp) {
|
||||||
debug('dynamic namespace %s was created', dynamicNsp.name);
|
|
||||||
this.doConnect(name, query);
|
this.doConnect(name, query);
|
||||||
} else {
|
} else {
|
||||||
debug('creation of namespace %s was denied', name);
|
debug('creation of namespace %s was denied', name);
|
||||||
|
|||||||
14
lib/index.js
14
lib/index.js
@@ -182,11 +182,17 @@ Server.prototype.checkNamespace = function(name, query, fn){
|
|||||||
return fn(false);
|
return fn(false);
|
||||||
}
|
}
|
||||||
nextFn.value(name, query, (err, allow) => {
|
nextFn.value(name, query, (err, allow) => {
|
||||||
if (err || !allow) {
|
if (err || !allow) {
|
||||||
run();
|
return run();
|
||||||
} else {
|
|
||||||
fn(this.parentNsps.get(nextFn.value).createChild(name));
|
|
||||||
}
|
}
|
||||||
|
if (this.nsps[name]) {
|
||||||
|
// the namespace was created in the meantime
|
||||||
|
debug("dynamic namespace %s already exists", name);
|
||||||
|
return fn(this.nsps[name]);
|
||||||
|
}
|
||||||
|
const namespace = this.parentNsps.get(nextFn.value).createChild(name);
|
||||||
|
debug("dynamic namespace %s was created", name);
|
||||||
|
fn(namespace);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -163,25 +163,31 @@ Namespace.prototype.add = function(client, query, fn){
|
|||||||
var self = this;
|
var self = this;
|
||||||
this.run(socket, function(err){
|
this.run(socket, function(err){
|
||||||
process.nextTick(function(){
|
process.nextTick(function(){
|
||||||
if ('open' == client.conn.readyState) {
|
if ("open" !== client.conn.readyState) {
|
||||||
if (err) return socket.error(err.data || err.message);
|
debug("next called after client was closed - ignoring socket");
|
||||||
|
socket._cleanup();
|
||||||
// track socket
|
return;
|
||||||
self.sockets[socket.id] = socket;
|
|
||||||
|
|
||||||
// it's paramount that the internal `onconnect` logic
|
|
||||||
// fires before user-set events to prevent state order
|
|
||||||
// violations (such as a disconnection before the connection
|
|
||||||
// logic is complete)
|
|
||||||
socket.onconnect();
|
|
||||||
if (fn) fn();
|
|
||||||
|
|
||||||
// fire user-set events
|
|
||||||
self.emit('connect', socket);
|
|
||||||
self.emit('connection', socket);
|
|
||||||
} else {
|
|
||||||
debug('next called after client was closed - ignoring socket');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
debug("middleware error, sending CONNECT_ERROR packet to the client");
|
||||||
|
socket._cleanup();
|
||||||
|
return socket.error(err.data || err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// track socket
|
||||||
|
self.sockets[socket.id] = socket;
|
||||||
|
|
||||||
|
// it's paramount that the internal `onconnect` logic
|
||||||
|
// fires before user-set events to prevent state order
|
||||||
|
// violations (such as a disconnection before the connection
|
||||||
|
// logic is complete)
|
||||||
|
socket.onconnect();
|
||||||
|
if (fn) fn();
|
||||||
|
|
||||||
|
// fire user-set events
|
||||||
|
self.emit('connect', socket);
|
||||||
|
self.emit('connection', socket);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return socket;
|
return socket;
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ var flags = [
|
|||||||
|
|
||||||
var emit = Emitter.prototype.emit;
|
var emit = Emitter.prototype.emit;
|
||||||
|
|
||||||
|
function noop() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface to a `Client` for a given `Namespace`.
|
* Interface to a `Client` for a given `Namespace`.
|
||||||
*
|
*
|
||||||
@@ -66,12 +68,15 @@ function Socket(nsp, client, query){
|
|||||||
this.conn = client.conn;
|
this.conn = client.conn;
|
||||||
this.rooms = {};
|
this.rooms = {};
|
||||||
this.acks = {};
|
this.acks = {};
|
||||||
this.connected = true;
|
this.connected = false;
|
||||||
this.disconnected = false;
|
this.disconnected = true;
|
||||||
this.handshake = this.buildHandshake(query);
|
this.handshake = this.buildHandshake(query);
|
||||||
this.fns = [];
|
this.fns = [];
|
||||||
this.flags = {};
|
this.flags = {};
|
||||||
this._rooms = [];
|
this._rooms = [];
|
||||||
|
|
||||||
|
// prevents crash when the socket receives an "error" event without listener
|
||||||
|
this.on('error', noop);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -116,7 +121,7 @@ Socket.prototype.buildHandshake = function(query){
|
|||||||
function buildQuery(){
|
function buildQuery(){
|
||||||
var requestQuery = url.parse(self.request.url, true).query;
|
var requestQuery = url.parse(self.request.url, true).query;
|
||||||
//if socket-specific query exist, replace query strings in requestQuery
|
//if socket-specific query exist, replace query strings in requestQuery
|
||||||
return Object.assign({}, query, requestQuery);
|
return Object.assign({}, requestQuery, query);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
headers: this.request.headers,
|
headers: this.request.headers,
|
||||||
@@ -300,6 +305,8 @@ Socket.prototype.leaveAll = function(){
|
|||||||
|
|
||||||
Socket.prototype.onconnect = function(){
|
Socket.prototype.onconnect = function(){
|
||||||
debug('socket connected - writing packet');
|
debug('socket connected - writing packet');
|
||||||
|
this.connected = true;
|
||||||
|
this.disconnected = false;
|
||||||
this.nsp.connected[this.id] = this;
|
this.nsp.connected[this.id] = this;
|
||||||
this.join(this.id);
|
this.join(this.id);
|
||||||
var skip = this.nsp.name === '/' && this.nsp.fns.length === 0;
|
var skip = this.nsp.name === '/' && this.nsp.fns.length === 0;
|
||||||
@@ -425,12 +432,7 @@ Socket.prototype.ondisconnect = function(){
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Socket.prototype.onerror = function(err){
|
Socket.prototype.onerror = function(err){
|
||||||
if (this.listeners('error').length) {
|
this.emit('error', err);
|
||||||
this.emit('error', err);
|
|
||||||
} else {
|
|
||||||
console.error('Missing error handler on `socket`.');
|
|
||||||
console.error(err.stack);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -445,7 +447,7 @@ Socket.prototype.onclose = function(reason){
|
|||||||
if (!this.connected) return this;
|
if (!this.connected) return this;
|
||||||
debug('closing socket - reason %s', reason);
|
debug('closing socket - reason %s', reason);
|
||||||
this.emit('disconnecting', reason);
|
this.emit('disconnecting', reason);
|
||||||
this.leaveAll();
|
this._cleanup();
|
||||||
this.nsp.remove(this);
|
this.nsp.remove(this);
|
||||||
this.client.remove(this);
|
this.client.remove(this);
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
@@ -525,7 +527,11 @@ Socket.prototype.dispatch = function(event){
|
|||||||
if (err) {
|
if (err) {
|
||||||
return self.error(err.data || err.message);
|
return self.error(err.data || err.message);
|
||||||
}
|
}
|
||||||
emit.apply(self, event);
|
if (self.connected) {
|
||||||
|
emit.apply(self, event);
|
||||||
|
} else {
|
||||||
|
debug("ignore packet received after disconnection");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.run(event, dispatchSocket);
|
this.run(event, dispatchSocket);
|
||||||
@@ -570,3 +576,8 @@ Socket.prototype.run = function(event, fn){
|
|||||||
|
|
||||||
run(0);
|
run(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Socket.prototype._cleanup = function () {
|
||||||
|
this.leaveAll();
|
||||||
|
this.join = function noop() {};
|
||||||
|
}
|
||||||
|
|||||||
3352
package-lock.json
generated
Normal file
3352
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "socket.io",
|
"name": "socket.io",
|
||||||
"version": "2.3.0",
|
"version": "2.5.1",
|
||||||
"description": "node.js realtime framework server",
|
"description": "node.js realtime framework server",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"realtime",
|
"realtime",
|
||||||
@@ -25,10 +25,10 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"debug": "~4.1.0",
|
"debug": "~4.1.0",
|
||||||
"engine.io": "~3.4.0",
|
"engine.io": "~3.6.0",
|
||||||
"has-binary2": "~1.0.2",
|
"has-binary2": "~1.0.2",
|
||||||
"socket.io-adapter": "~1.1.0",
|
"socket.io-adapter": "~1.1.0",
|
||||||
"socket.io-client": "2.3.0",
|
"socket.io-client": "2.5.0",
|
||||||
"socket.io-parser": "~3.4.0"
|
"socket.io-parser": "~3.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -945,6 +945,42 @@ describe('socket.io', function(){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should handle race conditions with dynamic namespaces (#4136)", (done) => {
|
||||||
|
const srv = http();
|
||||||
|
const sio = io(srv);
|
||||||
|
const counters = {
|
||||||
|
connected: 0,
|
||||||
|
created: 0,
|
||||||
|
events: 0,
|
||||||
|
};
|
||||||
|
const buffer = [];
|
||||||
|
srv.listen(() => {
|
||||||
|
const handler = () => {
|
||||||
|
if (++counters.events === 2) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
sio
|
||||||
|
.of((name, query, next) => {
|
||||||
|
buffer.push(next);
|
||||||
|
if (buffer.length === 2) {
|
||||||
|
buffer.forEach((next) => next(null, true));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on("connection", (socket) => {
|
||||||
|
if (++counters.connected === 2) {
|
||||||
|
sio.of("/dynamic-101").emit("message");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let one = client(srv, "/dynamic-101");
|
||||||
|
let two = client(srv, "/dynamic-101");
|
||||||
|
one.on("message", handler);
|
||||||
|
two.on("message", handler);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1621,8 +1657,25 @@ describe('socket.io', function(){
|
|||||||
expect(s.handshake.query.key2).to.be('&=bb');
|
expect(s.handshake.query.key2).to.be('&=bb');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should see the query options sent in the Socket.IO handshake (specific to the given socket)', (done) => {
|
||||||
|
const srv = http();
|
||||||
|
const sio = io(srv);
|
||||||
|
const socket = client(srv, '/namespace',{ query: { key1: 'a', key2: 'b' }}); // manager-specific query option
|
||||||
|
socket.query = { key2: 'c' }; // socket-specific query option
|
||||||
|
|
||||||
|
const success = () => {
|
||||||
|
sio.close();
|
||||||
|
socket.close();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
|
||||||
|
sio.of('/namespace').on('connection', (s) => {
|
||||||
|
expect(s.handshake.query.key1).to.be('a'); // in the query params
|
||||||
|
expect(s.handshake.query.key2).to.be('c'); // in the Socket.IO handshake
|
||||||
|
success();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle very large json', function(done){
|
it('should handle very large json', function(done){
|
||||||
@@ -1805,7 +1858,7 @@ describe('socket.io', function(){
|
|||||||
it('should not crash when messing with Object prototype (and other globals)', function(done){
|
it('should not crash when messing with Object prototype (and other globals)', function(done){
|
||||||
Object.prototype.foo = 'bar';
|
Object.prototype.foo = 'bar';
|
||||||
global.File = '';
|
global.File = '';
|
||||||
global.Blob = [];
|
// global.Blob = [];
|
||||||
var srv = http();
|
var srv = http();
|
||||||
var sio = io(srv);
|
var sio = io(srv);
|
||||||
srv.listen(function(){
|
srv.listen(function(){
|
||||||
@@ -1821,6 +1874,70 @@ describe('socket.io', function(){
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should ignore a packet received after disconnection", (done) => {
|
||||||
|
const srv = http();
|
||||||
|
const sio = io(srv);
|
||||||
|
|
||||||
|
srv.listen(() => {
|
||||||
|
const clientSocket = client(srv);
|
||||||
|
|
||||||
|
const success = () => {
|
||||||
|
clientSocket.close();
|
||||||
|
sio.close();
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
|
||||||
|
sio.on("connection", (socket) => {
|
||||||
|
socket.on("test", () => {
|
||||||
|
done(new Error("should not happen"));
|
||||||
|
});
|
||||||
|
socket.on("disconnect", success);
|
||||||
|
});
|
||||||
|
|
||||||
|
clientSocket.on("connect", () => {
|
||||||
|
clientSocket.emit("test", Buffer.alloc(10));
|
||||||
|
clientSocket.disconnect();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should leave all rooms joined after a middleware failure", (done) => {
|
||||||
|
const srv = http().listen(0);
|
||||||
|
const sio = io(srv);
|
||||||
|
const clientSocket = client(srv, "/");
|
||||||
|
|
||||||
|
sio.use((socket, next) => {
|
||||||
|
socket.join("room1");
|
||||||
|
next(new Error("nope"));
|
||||||
|
});
|
||||||
|
|
||||||
|
clientSocket.on("error", () => {
|
||||||
|
expect(sio.of("/").adapter.rooms).to.eql(0);
|
||||||
|
|
||||||
|
clientSocket.disconnect();
|
||||||
|
sio.close();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not join rooms after disconnection", (done) => {
|
||||||
|
const srv = http().listen(0);
|
||||||
|
const sio = io(srv);
|
||||||
|
const clientSocket = client(srv, "/");
|
||||||
|
|
||||||
|
sio.on("connection", (socket) => {
|
||||||
|
socket.disconnect();
|
||||||
|
socket.join("room1");
|
||||||
|
});
|
||||||
|
|
||||||
|
clientSocket.on("disconnect", () => {
|
||||||
|
expect(sio.of("/").adapter.rooms).to.eql(0);
|
||||||
|
|
||||||
|
sio.close();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should always trigger the callback (if provided) when joining a room', function(done){
|
it('should always trigger the callback (if provided) when joining a room', function(done){
|
||||||
var srv = http();
|
var srv = http();
|
||||||
var sio = io(srv);
|
var sio = io(srv);
|
||||||
@@ -2362,6 +2479,25 @@ describe('socket.io', function(){
|
|||||||
if (++count === 2) done();
|
if (++count === 2) done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should only set `connected` to true after the middleware execution", (done) => {
|
||||||
|
const httpServer = http();
|
||||||
|
const sio = io(httpServer);
|
||||||
|
|
||||||
|
const clientSocket = client(httpServer, "/");
|
||||||
|
|
||||||
|
sio.use((socket, next) => {
|
||||||
|
expect(socket.connected).to.be(false);
|
||||||
|
expect(socket.disconnected).to.be(true);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
sio.on("connection", (socket) => {
|
||||||
|
expect(socket.connected).to.be(true);
|
||||||
|
expect(socket.disconnected).to.be(false);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('socket middleware', function(done){
|
describe('socket middleware', function(done){
|
||||||
|
|||||||
Reference in New Issue
Block a user