add connect handler that decides wether socket is accepted or not
This commit is contained in:
parent
641a978cbe
commit
1b8dcd0a49
4 changed files with 82 additions and 22 deletions
|
@ -1,3 +1,13 @@
|
||||||
|
const http = require('http');
|
||||||
|
|
||||||
const Wormhole = require('../index');
|
const Wormhole = require('../index');
|
||||||
|
|
||||||
const wormhole = new Wormhole({ urls: [ '/hello' ] });
|
const httpServer = http.createServer();
|
||||||
|
|
||||||
|
const wormhole = new Wormhole({ urls: [ '/hello' ], httpServer });
|
||||||
|
|
||||||
|
wormhole.on('connect', ({ socket, accept, reject }) => {
|
||||||
|
accept();
|
||||||
|
});
|
||||||
|
|
||||||
|
httpServer.listen(8080);
|
67
index.js
67
index.js
|
@ -1,4 +1,4 @@
|
||||||
const http = require('http');
|
const EventEmitter = require('events');
|
||||||
|
|
||||||
const { createLog } = require('./lib/logger');
|
const { createLog } = require('./lib/logger');
|
||||||
const handshake = require('./lib/handshake');
|
const handshake = require('./lib/handshake');
|
||||||
|
@ -7,22 +7,33 @@ const Socket = require('./lib/Socket');
|
||||||
|
|
||||||
const handshakeLog = createLog([ 'Wormhole', 'Handshake' ]);
|
const handshakeLog = createLog([ 'Wormhole', 'Handshake' ]);
|
||||||
|
|
||||||
class Wormhole {
|
class Wormhole extends EventEmitter {
|
||||||
constructor({ urls=[ '/bruh' ], port=8080 }) {
|
constructor({ urls=[ '/bruh' ], httpServer }) {
|
||||||
this._urls = urls;
|
super();
|
||||||
this._port = port;
|
|
||||||
|
|
||||||
this._httpServer = http.createServer((req, res) => {
|
this._urls = urls;
|
||||||
|
this._httpServer = httpServer;
|
||||||
|
|
||||||
|
this._sockets = [];
|
||||||
|
|
||||||
|
this._httpServer.on('request', ((req, res) => {
|
||||||
if (req.method === 'GET' && req.url && this._urls.includes(req.url)) {
|
if (req.method === 'GET' && req.url && this._urls.includes(req.url)) {
|
||||||
handshakeLog(`Got connection request to ${req.url} on port ${this._port}`);
|
handshakeLog(`Got connection request to ${req.url}`);
|
||||||
|
|
||||||
|
let socket = new Socket({ socket: res.socket, initalState: constants.states.CONNECTING });
|
||||||
|
|
||||||
const failConnection = (status=400) => {
|
const failConnection = (status=400) => {
|
||||||
|
socket._setConnectionState(constants.states.CLOSING);
|
||||||
|
|
||||||
res.writeHead(status);
|
res.writeHead(status);
|
||||||
res.end();
|
res.end();
|
||||||
|
|
||||||
|
socket._setConnectionState(constants.states.CLOSED);
|
||||||
|
|
||||||
console.trace();
|
console.trace();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: check origin header
|
||||||
const websocketKey = req.headers['sec-websocket-key'];
|
const websocketKey = req.headers['sec-websocket-key'];
|
||||||
const upgradeHeader = req.headers['upgrade'];
|
const upgradeHeader = req.headers['upgrade'];
|
||||||
const websocketVersion = req.headers['sec-websocket-version'];
|
const websocketVersion = req.headers['sec-websocket-version'];
|
||||||
|
@ -32,26 +43,42 @@ class Wormhole {
|
||||||
|
|
||||||
const websocketAccept = handshake.generateWebsocketAcceptValue(websocketKey);
|
const websocketAccept = handshake.generateWebsocketAcceptValue(websocketKey);
|
||||||
|
|
||||||
handshakeLog(websocketKey, websocketAccept);
|
|
||||||
|
|
||||||
if (websocketAccept) {
|
if (websocketAccept) {
|
||||||
res.writeHead(101, {
|
const accept = () => {
|
||||||
'Upgrade': 'websocket',
|
try {
|
||||||
'Connection': 'Upgrade',
|
socket._setAccepted(true);
|
||||||
'Sec-WebSocket-Accept': websocketAccept
|
} catch(e) {
|
||||||
});
|
throw new Error('Tried to set socket fate (wether it is accept or not) more than once. Check if there are multiple listeners for the "connect" event or if you are somehow calling accept or reject multiple times.');
|
||||||
res.end();
|
}
|
||||||
|
|
||||||
const socket = new Socket({ socket: res.socket, initalState: 'CONNECTED' });
|
res.writeHead(101, {
|
||||||
|
'Upgrade': 'websocket',
|
||||||
|
'Connection': 'Upgrade',
|
||||||
|
'Sec-WebSocket-Accept': websocketAccept
|
||||||
|
});
|
||||||
|
res.end();
|
||||||
|
|
||||||
return true;
|
socket._setConnectionState(constants.states.OPEN);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const reject = (status=403) => {
|
||||||
|
try {
|
||||||
|
socket._setAccepted(false);
|
||||||
|
} catch(e) {
|
||||||
|
throw new Error('Tried to set socket fate (wether it is accept or not) more than once. Check if there are multiple listeners for the "connect" event or if you are somehow calling accept or reject multiple times.');
|
||||||
|
}
|
||||||
|
|
||||||
|
failConnection(status);
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.emit('connect', { socket, accept, reject });
|
||||||
}
|
}
|
||||||
|
|
||||||
return failConnection();
|
return failConnection();
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
|
|
||||||
this._httpServer.listen(port);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,29 @@
|
||||||
|
const constants = require("./constants");
|
||||||
|
|
||||||
class Socket {
|
class Socket {
|
||||||
constructor({ initialState='CONNECTING', socket }) {
|
constructor({ initialState='CONNECTING', socket }) {
|
||||||
this._state = initialState;
|
this._state = initialState;
|
||||||
this._socket = socket;
|
this._socket = socket;
|
||||||
|
this._accepted = false;
|
||||||
|
this._fateDecided = false; // Wether the decision to accept or reject the socket was made
|
||||||
|
|
||||||
this._socket.on('data', (e) => {
|
this._socket.on('data', (e) => {
|
||||||
|
if (this._state !== constants.states.OPEN) return;
|
||||||
|
|
||||||
console.log(e.toString());
|
console.log(e.toString());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Socket.prototype._setConnectionState = function(state) {
|
||||||
|
this._state = state;
|
||||||
|
};
|
||||||
|
|
||||||
|
Socket.prototype._setAccepted = function(state) {
|
||||||
|
if (this._fateDecided) throw new Error('Tried to decide fate (wether socket is accepted or not) more than 1 time');
|
||||||
|
|
||||||
|
this._fateDecided = true;
|
||||||
|
this._accepted = state;
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = Socket;
|
module.exports = Socket;
|
|
@ -1,5 +1,11 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
handshakeGUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
|
handshakeGUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
|
||||||
upgradeHeaderRequirement: 'websocket',
|
upgradeHeaderRequirement: 'websocket',
|
||||||
websocketVersionRequirement: '13'
|
websocketVersionRequirement: '13',
|
||||||
|
states: {
|
||||||
|
CONNECTING: 'CONNECTING',
|
||||||
|
OPEN: 'OPEN',
|
||||||
|
CLOSING: 'CLOSING',
|
||||||
|
CLOSED: 'CLOSED'
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue