Skip to content

Instantly share code, notes, and snippets.

@lerouxb
Last active October 22, 2020 13:26
Show Gist options
  • Save lerouxb/429979e342dfbfd5e75db7f02c84e04e to your computer and use it in GitHub Desktop.
Save lerouxb/429979e342dfbfd5e75db7f02c84e04e to your computer and use it in GitHub Desktop.
Http and websocket proxy that allows you to mess with websocket connections
'use strict';
const proxy = require('./lib/proxy')({ host: 'localhost', port: 8006 });
proxy.listen(8015);
'use strict';
const internals = {};
internals.log = function (...params) {
console.log(new Date(), ...params);
};
exports.listening = function (port) {
internals.log(`Listening to port ${port}`);
};
exports.disconnecting = function () {
internals.log('Disconnecting');
};
exports.alreadyDisconnected = function () {
internals.log('Already disconnected');
};
exports.connecting = function () {
internals.log('Connecting');
};
exports.alreadyConnected = function () {
internals.log('Already connected');
};
exports.disconnectingSocket = function (socket) {
internals.log('Disconnecting a socket');
};
exports.delayingConnection = function (req, socket, head) {
internals.log('Delaying a connection until we allow connections again');
};
exports.delayedConnection = function (req, socket, head) {
internals.log('Allowing a waiting connection to connect');
};
exports.open = function (socket) {
internals.log('Adding socket');
};
exports.close = function (res, socket, head) {
internals.log('Removing socket');
};
exports.proxyReq = function (proxyReq, req, res, options) {
// TODO: not actualy working
//internals.log('RAW Request', JSON.stringify(proxyReq.headers, true, 2));
};
exports.proxyRes = function (proxyRes, req, res) {
//internals.log('RAW Response', JSON.stringify(proxyRes.headers, true, 2));
};
exports.proxyReqWs = function (proxyReq, req, socket, options, head) {
//internals.log('RAW WS Request', JSON.stringify(proxyReq.headers, true, 2));
};
'use strict';
const _ = require('lodash');
const Http = require('http');
const HttpProxy = require('http-proxy');
const Logger = require('./logger');
const internals = {};
module.exports = function (target) {
const sockets = [];
let allowConnections = false;
const waiting = [];
const logger = Logger; // just alias to a local var for now. might become Logger() or new Logger();
const proxy = new HttpProxy.createProxyServer({ target });
const proxyServer = Http.createServer(function (req, res) {
const { method, url } = req;
if (method === 'POST') {
if (url === '/disconnect-sockets') {
if (allowConnections) {
logger.disconnecting();
allowConnections = false;
while (sockets.length) {
const socket = sockets.shift();
logger.disconnectingSocket(socket);
socket.destroy();
}
}
else {
logger.alreadyDisconnected();
}
return internals.ok(res);
}
if (url === '/reconnect-sockets') {
if (allowConnections) {
logger.alreadyConnected();
}
else {
logger.connecting();
allowConnections = true;
while (waiting.length) {
const params = waiting.shift();
logger.delayedConnection(...params);
proxy.ws(...params);
}
}
return internals.ok(res);
}
}
// proxy everything that is not an internally handled route
proxy.web(req, res);
});
proxyServer.on('upgrade', function (...params) {
if (allowConnections) {
proxy.ws(...params);
}
else {
// we'll respond once we reconnect again
logger.delayingConnection(params);
waiting.push(params);
}
});
proxy.on('open', function (socket) {
logger.open(socket)
sockets.push(socket);
});
proxy.on('close', function (res, socket, head) {
logger.close(res, socket, head);
const index = sockets.indexOf(socket);
if (index !== -1) {
sockets.splice(index, 1);
}
});
proxy.on('error', function (err, req, res) { // res could be a socket? could have a 4th url param?
if (res.writeHead) { // crude check to make sure res is not a socket
res.writeHead(500, {
'Content-Type': 'text/plain'
});
res.end('Something went wrong. And we are reporting a custom error message.');
}
});
proxy.on('proxyReq', logger.proxyReq);
proxy.on('proxyRes', logger.proxyRes);
proxy.on('proxyReqWs', logger.proxyReqWs);
const api = {
listen: _.once((port) => {
proxyServer.listen(port);
Logger.listening(port);
allowConnections = true;
})
};
return api;
};
internals.ok = function (res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('okay');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment