Commit 55dee432 authored by Joel Martin's avatar Joel Martin

Remove psuedo-UTF8 encoding.

It's less efficient on average that base64 (150% vs 133%). It's
non-standard (0 shifted to 256 before encoding). And I rarely use it.
parent e8c16989
Short Term: Short Term:
- Timing delta between frames in proxy record log, for playback - Add realtime playback of recordings.
support (for demo and test).
- Playback/demo on website. - Playback/demo on website.
......
...@@ -32,20 +32,6 @@ the proxy to add sequence numbers to every WebSockets frame so that ...@@ -32,20 +32,6 @@ the proxy to add sequence numbers to every WebSockets frame so that
the browser can reorder them. the browser can reorder them.
UTF-8 encoding:
In addition to the base64 encoding of the data, the proxy also
supports UTF-8 encoding of the data (the native WebSockets encoding).
However, in order to not burden the browser too much, the encoding
doesn't use the full UTF-8 value space, but only uses the first 256
values. This actually makes UTF-8 encoding slightly less space
efficient than base64. Also, flash cannot handle byte arrays with 0's
in them properly, so the values are actually 1-256 (rather than 0-255)
and the browser does modulus 256 on the data. For these two reasons,
base64 is the default and is indicated in the GET string by
"base64=1".
Flash security policy: Flash security policy:
The proxy detects flash security policy requests (again by sniffing The proxy detects flash security policy requests (again by sniffing
......
...@@ -45,8 +45,6 @@ load: function(target) { ...@@ -45,8 +45,6 @@ load: function(target) {
html += ' <ul>'; html += ' <ul>';
html += ' <li><input id="VNC_encrypt"'; html += ' <li><input id="VNC_encrypt"';
html += ' type="checkbox"> Encrypt</li>'; html += ' type="checkbox"> Encrypt</li>';
html += ' <li><input id="VNC_base64"';
html += ' type="checkbox" checked> Base64 Encode</li>';
html += ' <li><input id="VNC_true_color"'; html += ' <li><input id="VNC_true_color"';
html += ' type="checkbox" checked> True Color</li>'; html += ' type="checkbox" checked> True Color</li>';
html += ' <li><input id="VNC_cursor"'; html += ' <li><input id="VNC_cursor"';
...@@ -113,7 +111,6 @@ load: function(target) { ...@@ -113,7 +111,6 @@ load: function(target) {
DC.initSetting('port', ''); DC.initSetting('port', '');
DC.initSetting('password', ''); DC.initSetting('password', '');
DC.initSetting('encrypt', false); DC.initSetting('encrypt', false);
DC.initSetting('base64', true);
DC.initSetting('true_color', true); DC.initSetting('true_color', true);
DC.initSetting('cursor', true); DC.initSetting('cursor', true);
...@@ -212,7 +209,6 @@ clickSettingsMenu: function() { ...@@ -212,7 +209,6 @@ clickSettingsMenu: function() {
DC.closeSettingsMenu(); DC.closeSettingsMenu();
} else { } else {
DC.updateSetting('encrypt'); DC.updateSetting('encrypt');
DC.updateSetting('base64');
DC.updateSetting('true_color'); DC.updateSetting('true_color');
if (DC.rfb.get_canvas().get_cursor_uri()) { if (DC.rfb.get_canvas().get_cursor_uri()) {
DC.updateSetting('cursor'); DC.updateSetting('cursor');
...@@ -243,7 +239,6 @@ closeSettingsMenu: function() { ...@@ -243,7 +239,6 @@ closeSettingsMenu: function() {
settingsDisabled: function(disabled) { settingsDisabled: function(disabled) {
var DC = DefaultControls; var DC = DefaultControls;
$('VNC_encrypt').disabled = disabled; $('VNC_encrypt').disabled = disabled;
$('VNC_base64').disabled = disabled;
$('VNC_true_color').disabled = disabled; $('VNC_true_color').disabled = disabled;
if (DC.rfb && DC.rfb.get_canvas().get_cursor_uri()) { if (DC.rfb && DC.rfb.get_canvas().get_cursor_uri()) {
$('VNC_cursor').disabled = disabled; $('VNC_cursor').disabled = disabled;
...@@ -258,7 +253,6 @@ settingsApply: function() { ...@@ -258,7 +253,6 @@ settingsApply: function() {
//Util.Debug(">> settingsApply"); //Util.Debug(">> settingsApply");
var DC = DefaultControls; var DC = DefaultControls;
DC.saveSetting('encrypt'); DC.saveSetting('encrypt');
DC.saveSetting('base64');
DC.saveSetting('true_color'); DC.saveSetting('true_color');
if (DC.rfb.get_canvas().get_cursor_uri()) { if (DC.rfb.get_canvas().get_cursor_uri()) {
DC.saveSetting('cursor'); DC.saveSetting('cursor');
...@@ -361,7 +355,6 @@ connect: function() { ...@@ -361,7 +355,6 @@ connect: function() {
} }
DC.rfb.set_encrypt(DC.getSetting('encrypt')); DC.rfb.set_encrypt(DC.getSetting('encrypt'));
DC.rfb.set_b64encode(DC.getSetting('base64'));
DC.rfb.set_true_color(DC.getSetting('true_color')); DC.rfb.set_true_color(DC.getSetting('true_color'));
DC.rfb.set_local_cursor(DC.getSetting('cursor')); DC.rfb.set_local_cursor(DC.getSetting('cursor'));
......
...@@ -141,8 +141,6 @@ Util.conf_default(conf, that, 'focusContainer', document); ...@@ -141,8 +141,6 @@ Util.conf_default(conf, that, 'focusContainer', document);
Util.conf_default(conf, that, 'encrypt', false, true); Util.conf_default(conf, that, 'encrypt', false, true);
Util.conf_default(conf, that, 'true_color', true, true); Util.conf_default(conf, that, 'true_color', true, true);
// false means UTF-8 on the wire
Util.conf_default(conf, that, 'b64encode', true, true);
Util.conf_default(conf, that, 'local_cursor', true, true); Util.conf_default(conf, that, 'local_cursor', true, true);
// time to wait for connection // time to wait for connection
...@@ -250,12 +248,6 @@ function init_ws() { ...@@ -250,12 +248,6 @@ function init_ws() {
uri = "ws://"; uri = "ws://";
} }
uri += rfb_host + ":" + rfb_port + "/"; uri += rfb_host + ":" + rfb_port + "/";
if (conf.b64encode) {
vars.push("b64encode");
}
if (vars.length > 0) {
uri += "?" + vars.join("&");
}
Util.Info("connecting to " + uri); Util.Info("connecting to " + uri);
ws = new WebSocket(uri); ws = new WebSocket(uri);
...@@ -447,34 +439,15 @@ updateState = function(state, statusMsg) { ...@@ -447,34 +439,15 @@ updateState = function(state, statusMsg) {
}; };
function encode_message(arr) { function encode_message(arr) {
if (conf.b64encode) { /* base64 encode */
/* base64 encode */ SQ = SQ + Base64.encode(arr);
SQ = SQ + Base64.encode(arr);
} else {
/* UTF-8 encode. 0 -> 256 to avoid WebSockets framing */
SQ = SQ + arr.map(function (num) {
if (num === 0) {
return String.fromCharCode(256);
} else {
return String.fromCharCode(num);
}
} ).join('');
}
} }
function decode_message(data) { function decode_message(data) {
var i, length; var i, length;
//Util.Debug(">> decode_message: " + data); //Util.Debug(">> decode_message: " + data);
if (conf.b64encode) { /* base64 decode */
/* base64 decode */ RQ = RQ.concat(Base64.decode(data, 0));
RQ = RQ.concat(Base64.decode(data, 0));
} else {
/* UTF-8 decode. 256 -> 0 to WebSockets framing */
length = data.length;
for (i=0; i < length; i += 1) {
RQ.push(data.charCodeAt(i) % 256);
}
}
//Util.Debug(">> decode_message, RQ: " + RQ); //Util.Debug(">> decode_message, RQ: " + RQ);
} }
......
...@@ -157,10 +157,7 @@ ...@@ -157,10 +157,7 @@
if ($('encrypt').checked) { if ($('encrypt').checked) {
scheme = "wss://"; scheme = "wss://";
} }
var uri = scheme + host + ":" + port + "/?b64encode"; var uri = scheme + host + ":" + port;
//if (RFB.use_seq) {
// uri += "&seq_num";
//}
console.log("connecting to " + uri); console.log("connecting to " + uri);
ws = new WebSocket(uri); ws = new WebSocket(uri);
......
...@@ -68,10 +68,6 @@ ...@@ -68,10 +68,6 @@
scheme = "wss://"; scheme = "wss://";
} }
var uri = scheme + host + ":" + port; var uri = scheme + host + ":" + port;
//var uri = scheme + host + ":" + port + "/?b64encode";
//if (RFB.use_seq) {
// uri += "&seq_num";
//}
console.log("connecting to " + uri); console.log("connecting to " + uri);
ws = new WebSocket(uri); ws = new WebSocket(uri);
......
...@@ -42,7 +42,6 @@ int ssl_initialized = 0; ...@@ -42,7 +42,6 @@ int ssl_initialized = 0;
char *tbuf, *cbuf, *tbuf_tmp, *cbuf_tmp; char *tbuf, *cbuf, *tbuf_tmp, *cbuf_tmp;
unsigned int bufsize, dbufsize; unsigned int bufsize, dbufsize;
settings_t settings; settings_t settings;
client_settings_t client_settings;
void traffic(char * token) { void traffic(char * token) {
fprintf(stdout, "%s", token); fprintf(stdout, "%s", token);
...@@ -189,33 +188,11 @@ int encode(u_char const *src, size_t srclength, char *target, size_t targsize) { ...@@ -189,33 +188,11 @@ int encode(u_char const *src, size_t srclength, char *target, size_t targsize) {
int i, sz = 0, len = 0; int i, sz = 0, len = 0;
unsigned char chr; unsigned char chr;
target[sz++] = '\x00'; target[sz++] = '\x00';
if (client_settings.do_b64encode) { len = __b64_ntop(src, srclength, target+sz, targsize-sz);
len = __b64_ntop(src, srclength, target+sz, targsize-sz); if (len < 0) {
if (len < 0) { return len;
return len;
}
sz += len;
} else {
for (i=0; i < srclength; i++) {
chr = src[i];
if (chr < 128) {
if (chr == 0x00) {
target[sz++] = '\xc4';
target[sz++] = '\x80';
} else {
target[sz++] = chr;
}
} else {
if (chr < 192) {
target[sz++] = '\xc2';
target[sz++] = chr;
} else {
target[sz++] = '\xc3';
target[sz++] = chr - 64;
}
}
}
} }
sz += len;
target[sz++] = '\xff'; target[sz++] = '\xff';
return sz; return sz;
} }
...@@ -233,33 +210,11 @@ int decode(char *src, size_t srclength, u_char *target, size_t targsize) { ...@@ -233,33 +210,11 @@ int decode(char *src, size_t srclength, u_char *target, size_t targsize) {
/* We may have more than one frame */ /* We may have more than one frame */
end = memchr(start, '\xff', srclength); end = memchr(start, '\xff', srclength);
*end = '\x00'; *end = '\x00';
if (client_settings.do_b64encode) { len = __b64_pton(start, target+retlen, targsize-retlen);
len = __b64_pton(start, target+retlen, targsize-retlen); if (len < 0) {
if (len < 0) { return len;
return len;
}
retlen += len;
} else {
for (i=0; i < end-start; i++) {
chr = start[i];
if (chr < 128) {
target[retlen++] = chr;
} else {
i++;
switch (chr) {
case (unsigned char) '\xc2':
target[retlen++] = start[i];
break;
case (unsigned char) '\xc3':
target[retlen++] = start[i] + 64;
break;
case (unsigned char) '\xc4':
target[retlen++] = 0;
break;
}
}
}
} }
retlen += len;
start = end + 2; // Skip '\xff' end and '\x00' start start = end + 2; // Skip '\xff' end and '\x00' start
framecount++; framecount++;
} while (end < (src+srclength-1)); } while (end < (src+srclength-1));
...@@ -375,13 +330,9 @@ ws_ctx_t *do_handshake(int sock) { ...@@ -375,13 +330,9 @@ ws_ctx_t *do_handshake(int sock) {
char handshake[4096], response[4096], trailer[17]; char handshake[4096], response[4096], trailer[17];
char *scheme, *pre; char *scheme, *pre;
headers_t headers; headers_t headers;
char *args_start, *args_end, *arg_idx;
int len, ret; int len, ret;
ws_ctx_t * ws_ctx; ws_ctx_t * ws_ctx;
// Reset settings
client_settings.do_b64encode = 0;
// Peek, but don't read the data // Peek, but don't read the data
len = recv(sock, handshake, 1024, MSG_PEEK); len = recv(sock, handshake, 1024, MSG_PEEK);
handshake[len] = 0; handshake[len] = 0;
...@@ -432,21 +383,6 @@ ws_ctx_t *do_handshake(int sock) { ...@@ -432,21 +383,6 @@ ws_ctx_t *do_handshake(int sock) {
printf(" using protocol version 75\n"); printf(" using protocol version 75\n");
} }
// Parse client settings from the GET path
args_start = strstr(headers.path, "?");
if (args_start) {
if (strstr(args_start, "#")) {
args_end = strstr(args_start, "#");
} else {
args_end = args_start + strlen(args_start);
}
arg_idx = strstr(args_start, "b64encode");
if (arg_idx && arg_idx < args_end) {
printf(" b64encode=1\n");
client_settings.do_b64encode = 1;
}
}
sprintf(response, server_handshake, pre, headers.origin, pre, scheme, sprintf(response, server_handshake, pre, headers.origin, pre, scheme,
headers.host, headers.path, pre, trailer); headers.host, headers.path, pre, trailer);
//printf("response: %s\n", response); //printf("response: %s\n", response);
...@@ -561,15 +497,9 @@ void start_server() { ...@@ -561,15 +497,9 @@ void start_server() {
continue; continue;
} }
/* Calculate dbufsize based on client_settings */ /* base64 is 4 bytes for every 3
if (client_settings.do_b64encode) { * 20 for WS '\x00' / '\xff' and good measure */
/* base64 is 4 bytes for every 3 dbufsize = (bufsize * 3)/4 - 20;
* 20 for WS '\x00' / '\xff' and good measure */
dbufsize = (bufsize * 3)/4 - 20;
} else {
/* UTF-8 encoding is up to 2X larger */
dbufsize = (bufsize/2) - 20;
}
settings.handler(ws_ctx); settings.handler(ws_ctx);
close(csock); close(csock);
......
...@@ -16,10 +16,6 @@ typedef struct { ...@@ -16,10 +16,6 @@ typedef struct {
char *cert; char *cert;
} settings_t; } settings_t;
typedef struct {
int do_b64encode;
} client_settings_t;
typedef struct { typedef struct {
char path[1024+1]; char path[1024+1];
char host[1024+1]; char host[1024+1];
......
...@@ -29,8 +29,6 @@ settings = { ...@@ -29,8 +29,6 @@ settings = {
'ssl_only' : False, 'ssl_only' : False,
'daemon' : True, 'daemon' : True,
'record' : None, } 'record' : None, }
client_settings = {
'b64encode' : False, }
server_handshake = """HTTP/1.1 101 Web Socket Protocol Handshake\r server_handshake = """HTTP/1.1 101 Web Socket Protocol Handshake\r
Upgrade: WebSocket\r Upgrade: WebSocket\r
...@@ -48,27 +46,16 @@ def traffic(token="."): ...@@ -48,27 +46,16 @@ def traffic(token="."):
sys.stdout.flush() sys.stdout.flush()
def encode(buf): def encode(buf):
if client_settings['b64encode']: buf = b64encode(buf)
buf = b64encode(buf)
else:
# Modified UTF-8 encode
buf = buf.decode('latin-1').encode('utf-8').replace("\x00", "\xc4\x80")
return "\x00%s\xff" % buf return "\x00%s\xff" % buf
def decode(buf): def decode(buf):
""" Parse out WebSocket packets. """ """ Parse out WebSocket packets. """
if buf.count('\xff') > 1: if buf.count('\xff') > 1:
if client_settings['b64encode']: return [b64decode(d[1:]) for d in buf.split('\xff')]
return [b64decode(d[1:]) for d in buf.split('\xff')]
else:
# Modified UTF-8 decode
return [d[1:].replace("\xc4\x80", "\x00").decode('utf-8').encode('latin-1') for d in buf.split('\xff')]
else: else:
if client_settings['b64encode']: return [b64decode(buf[1:-1])]
return [b64decode(buf[1:-1])]
else:
return [buf[1:-1].replace("\xc4\x80", "\x00").decode('utf-8').encode('latin-1')]
def parse_handshake(handshake): def parse_handshake(handshake):
ret = {} ret = {}
...@@ -99,9 +86,6 @@ def gen_md5(keys): ...@@ -99,9 +86,6 @@ def gen_md5(keys):
def do_handshake(sock): def do_handshake(sock):
global client_settings
client_settings['b64encode'] = False
# Peek, but don't read the data # Peek, but don't read the data
handshake = sock.recv(1024, socket.MSG_PEEK) handshake = sock.recv(1024, socket.MSG_PEEK)
...@@ -136,14 +120,6 @@ def do_handshake(sock): ...@@ -136,14 +120,6 @@ def do_handshake(sock):
#print "handshake: " + repr(handshake) #print "handshake: " + repr(handshake)
h = parse_handshake(handshake) h = parse_handshake(handshake)
# Parse client settings from the GET path
cvars = parse_qsl(urlsplit(h['path'])[3], True)
for name, val in cvars:
if name not in ['b64encode']: continue
value = val and val or True
client_settings[name] = value
print " %s=%s" % (name, value)
if h.get('key3'): if h.get('key3'):
trailer = gen_md5(h) trailer = gen_md5(h)
pre = "Sec-" pre = "Sec-"
......
...@@ -99,7 +99,6 @@ Connect parameters are provided in query string: ...@@ -99,7 +99,6 @@ Connect parameters are provided in query string:
} }
rfb = new RFB({'encrypt': Util.getQueryVar('encrypt', true), rfb = new RFB({'encrypt': Util.getQueryVar('encrypt', true),
'b64encode': Util.getQueryVar('base64', true),
'true_color': Util.getQueryVar('true_color', true), 'true_color': Util.getQueryVar('true_color', true),
'local_cursor': Util.getQueryVar('cursor', true), 'local_cursor': Util.getQueryVar('cursor', true),
'updateState': updateState}); 'updateState': updateState});
......
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