Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 409ab09790 | |||
| 61ca9d54d2 | |||
| fa028e4af0 |
@@ -69,4 +69,6 @@ ws://localhost:8080/?target=ws://www.multiplayerpiano.com:443&origin=http://www.
|
|||||||
|
|
||||||
Query parameters may or may not be encoded, but querystring chars (`&` and `=`) must be encoded to escape them.
|
Query parameters may or may not be encoded, but querystring chars (`&` and `=`) must be encoded to escape them.
|
||||||
|
|
||||||
**Note:** If the `target` is missing or invalid, or if an error occurs when connecting to the remote host (such as if it responded with a 403), your connection is simply closed. Ideally, the proxy server would wait for the connection to the target to finish, before responding to the client with the same response of the target; however, I found this much too complicated to set up, so I just kept it simple.
|
## Issues
|
||||||
|
|
||||||
|
If the `target` is missing or invalid, or if an error occurs when connecting to the remote host (such as if it responded with a 403), your connection is simply closed. Ideally, the proxy server would wait for the connection to the target to finish, before responding to the client with the same response of the target; however, I found this much too complicated to set up, so I just kept it simple.
|
||||||
|
|||||||
@@ -1,54 +1,44 @@
|
|||||||
var WebSocket = require('ws');
|
var http = require("http");
|
||||||
var {parse:parseQueryString} = require('query-string');
|
var https = require("https");
|
||||||
var wss = new WebSocket.Server({
|
var server = http.createServer();
|
||||||
port: process.env.OPENSHIFT_NODEJS_PORT || process.env.PORT || 8080
|
server.listen(process.env.OPENSHIFT_NODEJS_PORT || process.env.PORT || 8080);
|
||||||
|
server.on("request", function (req, res) {
|
||||||
|
res.writeHead(400);
|
||||||
|
res.end("Websockets only!");
|
||||||
});
|
});
|
||||||
var conncount = 0;
|
server.on("upgrade", function (req, socket) {
|
||||||
wss.on('connection', function (cws, req){
|
if (req.headers["upgrade"] != "websocket") return socket.end("HTTP/1.1 400 Websocket upgrade only");
|
||||||
var number = conncount++;
|
var xof = req.url.indexOf('?');
|
||||||
console.log(`New connection #${number} from ${req.connection.remoteAddress} with ${req.url}`);
|
if (xof < 0) return socket.end("HTTP/1.1 400 Missing querystring");
|
||||||
cws.on('close', function(){
|
var params = new URLSearchParams(req.url.substring(xof));
|
||||||
console.log(`Closing connection #${number} from ${req.connection.remoteAddress}`);
|
var targetURL = decodeURIComponent(params.get("target"));
|
||||||
});
|
if (!targetURL) return socket.end("HTTP/1.1 400 Target parameter is required");
|
||||||
|
targetURL = new URL(targetURL);
|
||||||
var querystring = req.url.substr(1);
|
if (["https:","wss:"].includes(targetURL.protocol))
|
||||||
if (!querystring) return cws.close();
|
var secure = true;
|
||||||
var params = parseQueryString(querystring);
|
else if (!["http:","ws:"].includes(targetURL.protocol))
|
||||||
var target = params.target;
|
return socket.end("HTTP/1.1 400 Unsupported target protocol");
|
||||||
if (!target) return cws.close();
|
targetURL.protocol = targetURL.protocol.replace("ws", "http");
|
||||||
var headers = {};
|
var targetReq = (secure ? https : http).get(targetURL, {
|
||||||
for (let key in params) if (key != "target") headers[key] = params[key];
|
headers: {
|
||||||
|
"Connection": "Upgrade",
|
||||||
try {
|
"Upgrade": "websocket",
|
||||||
var tws = new WebSocket(target, {headers});
|
"Sec-WebSocket-Version": 13,
|
||||||
} catch(e) {
|
"Sec-WebSocket-Key": require('crypto').randomBytes(16).toString('base64')
|
||||||
console.error(e);
|
|
||||||
cws.close();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// client to target
|
|
||||||
var messageBuffer = [];
|
|
||||||
tws.on('open', function(){
|
|
||||||
for (let message of messageBuffer) tws.send(message);
|
|
||||||
messageBuffer = undefined;
|
|
||||||
});
|
});
|
||||||
cws.on('message', function(message){
|
console.debug("sdfsdfjig");
|
||||||
if (tws.readyState == WebSocket.OPEN) tws.send(message);
|
targetReq.on("response", function(targetRes) {
|
||||||
else if (messageBuffer) messageBuffer.push(message);
|
console.log(req.socket.remoteAddress, targetURL.href, targetRes.statusCode);
|
||||||
|
if (targetRes.statusCode == 101) {
|
||||||
|
targetRes.pipe(socket);
|
||||||
|
socket.pipe(targetRes);
|
||||||
|
} else {
|
||||||
|
socket.end(`HTTP/1.1 502 Unexpected status code from target server: ${targetRes.statusCode}`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
cws.on('close', function(){
|
targetReq.on("error", function(error) {
|
||||||
tws.close();
|
console.log(req.socket.remoteAddress, targetURL.href, error.message);
|
||||||
messageBuffer = undefined;
|
socket.end();
|
||||||
});
|
});
|
||||||
cws.on('error', console.error);
|
|
||||||
|
|
||||||
// target to client
|
|
||||||
tws.on('message', function(message){
|
|
||||||
if (cws.readyState == WebSocket.OPEN) cws.send(message);
|
|
||||||
});
|
|
||||||
tws.on('close', function(){
|
|
||||||
cws.close();
|
|
||||||
});
|
|
||||||
tws.on('error', console.error);
|
|
||||||
});
|
});
|
||||||
Generated
+61
-11
@@ -1,12 +1,64 @@
|
|||||||
{
|
{
|
||||||
|
"name": "websocket-proxy",
|
||||||
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"lockfileVersion": 1,
|
"packages": {
|
||||||
|
"": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async-limiter": {
|
"query-string": "^6.2.0",
|
||||||
"version": "1.0.0",
|
"ws": "^8.3.0"
|
||||||
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
|
}
|
||||||
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
|
|
||||||
},
|
},
|
||||||
|
"node_modules/decode-uri-component": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
|
||||||
|
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/query-string": {
|
||||||
|
"version": "6.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/query-string/-/query-string-6.2.0.tgz",
|
||||||
|
"integrity": "sha512-5wupExkIt8RYL4h/FE+WTg3JHk62e6fFPWtAZA9J5IWK1PfTfKkMS93HBUHcFpeYi9KsY5pFbh+ldvEyaz5MyA==",
|
||||||
|
"dependencies": {
|
||||||
|
"decode-uri-component": "^0.2.0",
|
||||||
|
"strict-uri-encode": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/strict-uri-encode": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ws": {
|
||||||
|
"version": "8.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.3.0.tgz",
|
||||||
|
"integrity": "sha512-Gs5EZtpqZzLvmIM59w4igITU57lrtYVFneaa434VROv4thzJyV6UjIL3D42lslWlI+D4KzLYnxSwtfuiO79sNw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": "^5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
"decode-uri-component": {
|
"decode-uri-component": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
|
||||||
@@ -27,12 +79,10 @@
|
|||||||
"integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
|
"integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
|
||||||
},
|
},
|
||||||
"ws": {
|
"ws": {
|
||||||
"version": "6.0.0",
|
"version": "8.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.3.0.tgz",
|
||||||
"integrity": "sha512-c2UlYcAZp1VS8AORtpq6y4RJIkJ9dQz18W32SpR/qXGfLDZ2jU4y4wKvvZwqbi7U6gxFQTeE+urMbXU/tsDy4w==",
|
"integrity": "sha512-Gs5EZtpqZzLvmIM59w4igITU57lrtYVFneaa434VROv4thzJyV6UjIL3D42lslWlI+D4KzLYnxSwtfuiO79sNw==",
|
||||||
"requires": {
|
"requires": {}
|
||||||
"async-limiter": "~1.0.0"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -4,6 +4,6 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"query-string": "^6.2.0",
|
"query-string": "^6.2.0",
|
||||||
"ws": "^6.0.0"
|
"ws": "^8.3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user