Last active
October 22, 2020 13:26
-
-
Save lerouxb/429979e342dfbfd5e75db7f02c84e04e to your computer and use it in GitHub Desktop.
Http and websocket proxy that allows you to mess with websocket connections
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
const proxy = require('./lib/proxy')({ host: 'localhost', port: 8006 }); | |
proxy.listen(8015); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'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)); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'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