Commit 1ee2d93e authored by Joel Martin's avatar Joel Martin

wsproxy.js: Fix multi-frame decoding.

- Also, discovered node.js bug in base64 decoding. Added test case and
  filed https://github.com/ry/node/issues/issue/402
parent fd758dd3
// The following results in 'hello [MANGLED]'
//
// Filed as https://github.com/ry/node/issues/issue/402
var sys = require("sys"),
buf = new Buffer(1024), len,
str1 = "aGVsbG8g", // 'hello '
str2 = "d29ybGQ=", // 'world'
len = buf.write(str1, 0, 'base64');
len += buf.write(str2, len, 'base64');
sys.log("decoded result: " + buf.toString('binary', 0, len));
...@@ -42,11 +42,23 @@ function encode(buf) { ...@@ -42,11 +42,23 @@ function encode(buf) {
String.fromCharCode(255); String.fromCharCode(255);
} }
function decode(data) {
function decode(str) { var i, len = 0, strs, retstrs = [],
var buf = new Buffer(str.length); buf = new Buffer(data.length),
len = buf.write(str.substring(1, str.length-1), 0, 'base64'); str = data.toString('binary', 1, data.length-1);
return buf.toString('binary', 0, len);
if (str.indexOf('\xff') > -1) {
// We've gotten multiple frames at once
strs = str.split('\xff\x00')
for (i = 0; i < strs.length; i++) {
len = buf.write(strs[i], 0, 'base64');
retstrs.push(buf.toString('binary', 0, len));
}
return retstrs.join("");
} else {
len = buf.write(str, 0, 'base64');
return buf.toString('binary', 0, len);
}
} }
...@@ -54,6 +66,14 @@ var server = net.createServer(function (client) { ...@@ -54,6 +66,14 @@ var server = net.createServer(function (client) {
var handshake = "", headers = {}, header, var handshake = "", headers = {}, header,
version, path, k1, k2, k3, target = null; version, path, k1, k2, k3, target = null;
function cleanup() {
client.end();
if (target) {
target.end();
target = null;
}
}
function do_handshake(data) { function do_handshake(data) {
var i, idx, dlen = data.length, lines, location, rheaders, var i, idx, dlen = data.length, lines, location, rheaders,
sec_hdr; sec_hdr;
...@@ -88,8 +108,8 @@ var server = net.createServer(function (client) { ...@@ -88,8 +108,8 @@ var server = net.createServer(function (client) {
client.end(); client.end();
return; return;
} }
header = lines[i].substring(0, idx).toLowerCase(); header = lines[i].slice(0, idx).toLowerCase();
headers[header] = lines[i].substring(idx+2); headers[header] = lines[i].slice(idx+2);
} }
//console.dir(headers); //console.dir(headers);
//sys.log("k3: " + k3 + ", k3.length: " + k3.length); //sys.log("k3: " + k3 + ", k3.length: " + k3.length);
...@@ -130,7 +150,7 @@ var server = net.createServer(function (client) { ...@@ -130,7 +150,7 @@ var server = net.createServer(function (client) {
// Switch listener to normal data path // Switch listener to normal data path
client.on('data', client_data); client.on('data', client_data);
client.setEncoding('utf8'); //client.setEncoding('utf8');
client.removeListener('data', do_handshake); client.removeListener('data', do_handshake);
// Do not delay writes // Do not delay writes
client.setNoDelay(true); client.setNoDelay(true);
...@@ -150,26 +170,26 @@ var server = net.createServer(function (client) { ...@@ -150,26 +170,26 @@ var server = net.createServer(function (client) {
target.on('data', target_data); target.on('data', target_data);
target.on('end', function () { target.on('end', function () {
sys.log("received target end"); sys.log("received target end");
client.end(); cleanup();
if (target) { });
target.end(); target.on('error', function (exc) {
target = null; sys.log("received target error: " + exc);
} cleanup();
}); });
} }
function client_data(data) { function client_data(data) {
var ret;
//sys.log("received client data: " + data); //sys.log("received client data: " + data);
//sys.log(" decoded: " + decode(data)); //sys.log(" decoded: " + decode(data));
try { try {
target.write(decode(data), 'binary'); ret = target.write(decode(data), 'binary');
if (! ret) {
sys.log("target write returned false");
}
} catch(e) { } catch(e) {
sys.log("fatal error writing to target"); sys.log("fatal error writing to target");
client.end(); cleanup();
if (target) {
target.end();
target = null;
}
} }
} }
...@@ -180,9 +200,7 @@ var server = net.createServer(function (client) { ...@@ -180,9 +200,7 @@ var server = net.createServer(function (client) {
client.write(encode(data), 'binary'); client.write(encode(data), 'binary');
} catch(e) { } catch(e) {
sys.log("fatal error writing to client"); sys.log("fatal error writing to client");
client.end(); cleanup();
target.end();
target = null;
} }
} }
...@@ -192,11 +210,11 @@ var server = net.createServer(function (client) { ...@@ -192,11 +210,11 @@ var server = net.createServer(function (client) {
client.on('data', do_handshake); client.on('data', do_handshake);
client.on('end', function () { client.on('end', function () {
sys.log("recieved client end"); sys.log("recieved client end");
client.end(); cleanup();
if (target) { });
target.end(); client.on('error', function (exc) {
target = null; sys.log("recieved client error: " + exc);
} cleanup();
}); });
}); });
...@@ -208,8 +226,8 @@ try { ...@@ -208,8 +226,8 @@ try {
var idx; var idx;
idx = source_arg.indexOf(":"); idx = source_arg.indexOf(":");
if (idx >= 0) { if (idx >= 0) {
source_host = source_arg.substring(0, idx); source_host = source_arg.slice(0, idx);
source_port = parseInt(source_arg.substring(idx+1), 10); source_port = parseInt(source_arg.slice(idx+1), 10);
} else { } else {
source_host = ""; source_host = "";
source_port = parseInt(source_arg, 10); source_port = parseInt(source_arg, 10);
...@@ -219,8 +237,8 @@ try { ...@@ -219,8 +237,8 @@ try {
if (idx < 0) { if (idx < 0) {
throw("target must be host:port"); throw("target must be host:port");
} }
target_host = target_arg.substring(0, idx); target_host = target_arg.slice(0, idx);
target_port = parseInt(target_arg.substring(idx+1), 10); target_port = parseInt(target_arg.slice(idx+1), 10);
if (isNaN(source_port) || isNaN(target_port)) { if (isNaN(source_port) || isNaN(target_port)) {
throw("illegal port"); throw("illegal port");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment