aboutsummaryrefslogtreecommitdiff
path: root/third_party/websockify/tests
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/websockify/tests')
-rwxr-xr-xthird_party/websockify/tests/b64_vs_utf8.py29
-rw-r--r--third_party/websockify/tests/base64.html91
-rw-r--r--third_party/websockify/tests/base64.js12
-rw-r--r--third_party/websockify/tests/echo.html148
-rwxr-xr-xthird_party/websockify/tests/echo.py75
-rwxr-xr-xthird_party/websockify/tests/echo.rb62
l---------third_party/websockify/tests/include1
-rw-r--r--third_party/websockify/tests/latency.html290
l---------third_party/websockify/tests/latency.py1
-rw-r--r--third_party/websockify/tests/load.html250
-rwxr-xr-xthird_party/websockify/tests/load.py167
-rw-r--r--third_party/websockify/tests/plain_echo.html168
-rw-r--r--third_party/websockify/tests/simple.html68
-rwxr-xr-xthird_party/websockify/tests/utf8-list.py22
14 files changed, 1384 insertions, 0 deletions
diff --git a/third_party/websockify/tests/b64_vs_utf8.py b/third_party/websockify/tests/b64_vs_utf8.py
new file mode 100755
index 00000000..9af7b621
--- /dev/null
+++ b/third_party/websockify/tests/b64_vs_utf8.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+from base64 import b64encode, b64decode
+from codecs import (utf_8_encode, utf_8_decode,
+ latin_1_encode, latin_1_decode)
+import random, time
+
+buf_len = 10000
+iterations = 10000
+
+print "Generating random input buffer"
+r = random.Random()
+buf = "".join([chr(r.randint(0, 255)) for i in range(buf_len)])
+
+tests = {'UTF8 encode': lambda: utf_8_encode(unicode(buf, 'latin-1'))[0],
+ 'B64 encode': lambda: b64encode(buf)}
+utf8_buf = tests['UTF8 encode']()
+b64_buf = tests['B64 encode']()
+tests.update({'UTF8 decode': lambda: latin_1_encode(utf_8_decode(utf8_buf)[0])[0],
+ 'B64 decode': lambda: b64decode(b64_buf)})
+
+print "Running tests"
+for test in 'UTF8 encode', 'B64 encode', 'UTF8 decode', 'B64 decode':
+ start = time.time()
+ for i in range(iterations):
+ res_buf = tests[test]()
+ print "%s took %s seconds (result size %s)" % (
+ test, (time.time() - start), len(res_buf))
+
diff --git a/third_party/websockify/tests/base64.html b/third_party/websockify/tests/base64.html
new file mode 100644
index 00000000..24ad80b5
--- /dev/null
+++ b/third_party/websockify/tests/base64.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>Native Base64 Tests</title>
+ <script src="include/util.js"></script>
+ <script src="include/webutil.js"></script>
+ <script src="include/base64.js"></script>
+ </head>
+ <body>
+ <h1>Native Base64 Tests</h1>
+
+ <br>
+ Messages:<br>
+ <textarea id="debug" style="font-size: 9px;" cols=80 rows=25></textarea>
+
+ <br>
+ </body>
+
+<script>
+ function debug(str) {
+ console.log(str);
+ cell = $D('debug');
+ cell.innerHTML += str + "\n";
+ cell.scrollTop = cell.scrollHeight;
+ }
+
+ function assertRun(code, result) {
+ try {
+ var actual = eval(code);
+ } catch (exc) {
+ debug("FAIL: '" + code + "' threw an exception");
+ fail += 1;
+ return false;
+ }
+ if (actual !== result) {
+ debug("FAIL: '" + code + "' returned '" + actual + "', expected '" + result + "'");
+ fail += 1;
+ return false;
+ }
+ debug("PASS: '" + code + "' returned expected '" + result +"'");
+ pass += 1;
+ return true;
+ }
+
+ function Base64_decode(data) {
+ var arr = Base64.decode (data);
+ return arr.map(function (num) {
+ return String.fromCharCode(num); } ).join('');
+
+ }
+
+ window.onload = function() {
+ var str;
+ debug('onload');
+ fail = 0;
+ pass = 0;
+ assertRun('window.btoa("hello world")', 'aGVsbG8gd29ybGQ=');
+ assertRun('window.btoa("a")', 'YQ==');
+ assertRun('window.btoa("ab")', 'YWI=');
+ assertRun('window.btoa("abc")', 'YWJj');
+ assertRun('window.btoa("abcd")', 'YWJjZA==');
+ assertRun('window.btoa("abcde")', 'YWJjZGU=');
+ assertRun('window.btoa("abcdef")', 'YWJjZGVm');
+ assertRun('window.btoa("abcdefg")', 'YWJjZGVmZw==');
+ assertRun('window.btoa("abcdefgh")', 'YWJjZGVmZ2g=');
+
+ assertRun('window.atob("aGVsbG8gd29ybGQ=")', 'hello world');
+ assertRun('Base64_decode("aGVsbG8gd29ybGQ=")', 'hello world');
+ assertRun('window.atob("YQ==")', 'a');
+ assertRun('Base64_decode("YQ==")', 'a');
+ assertRun('window.atob("YWI=")', 'ab');
+ assertRun('Base64_decode("YWI=")', 'ab');
+ assertRun('window.atob("YWJj")', 'abc');
+ assertRun('Base64_decode("YWJj")', 'abc');
+ assertRun('window.atob("YWJjZA==")', 'abcd');
+ assertRun('Base64_decode("YWJjZA==")', 'abcd');
+ assertRun('window.atob("YWJjZGU=")', 'abcde');
+ assertRun('Base64_decode("YWJjZGU=")', 'abcde');
+ assertRun('window.atob("YWJjZGVm")', 'abcdef');
+ assertRun('Base64_decode("YWJjZGVm")', 'abcdef');
+
+ assertRun('typeof window.btoa', 'function');
+ assertRun('window.btoa("")', '');
+ assertRun('window.btoa(null)', '');
+ assertRun('window.atob(window.btoa(window))', window.toString()); // "[object DOMWindow]"
+ assertRun('window.btoa("\\u0080\\u0081")', 'gIE=');
+
+ debug("Tests failed: " + fail);
+ debug("Tests passed: " + pass);
+ }
+</script>
diff --git a/third_party/websockify/tests/base64.js b/third_party/websockify/tests/base64.js
new file mode 100644
index 00000000..6ade00a3
--- /dev/null
+++ b/third_party/websockify/tests/base64.js
@@ -0,0 +1,12 @@
+// 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));
diff --git a/third_party/websockify/tests/echo.html b/third_party/websockify/tests/echo.html
new file mode 100644
index 00000000..cc8b642f
--- /dev/null
+++ b/third_party/websockify/tests/echo.html
@@ -0,0 +1,148 @@
+<html>
+
+ <head>
+ <title>WebSockets Echo Test</title>
+ <script src="include/util.js"></script>
+ <script src="include/webutil.js"></script>
+ <script src="include/base64.js"></script>
+ <script src="include/websock.js"></script>
+ <!-- Uncomment to activate firebug lite -->
+ <!--
+ <script type='text/javascript'
+ src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
+ -->
+
+
+ </head>
+
+ <body>
+
+ Host: <input id='host' style='width:100'>&nbsp;
+ Port: <input id='port' style='width:50'>&nbsp;
+ Encrypt: <input id='encrypt' type='checkbox'>&nbsp;
+ <input id='connectButton' type='button' value='Start' style='width:100px'
+ onclick="connect();">&nbsp;
+
+
+ <br>
+ Log:<br>
+ <textarea id="messages" style="font-size: 9;" cols=80 rows=25></textarea>
+ </body>
+
+
+ <script>
+ var ws, host = null, port = null,
+ msg_cnt = 0, send_cnt = 1, echoDelay = 500,
+ echo_ref;
+
+ function message(str) {
+ console.log(str);
+ cell = $D('messages');
+ cell.innerHTML += msg_cnt + ": " + str + "\n";
+ cell.scrollTop = cell.scrollHeight;
+ msg_cnt++;
+ }
+
+ Array.prototype.pushStr = function (str) {
+ var n = str.length;
+ for (var i=0; i < n; i++) {
+ this.push(str.charCodeAt(i));
+ }
+ }
+
+ function send_msg() {
+ var str = "Message #" + send_cnt;
+ ws.send_string(str);
+ message("Sent message: '" + str + "'");
+ send_cnt++;
+ }
+
+ function update_stats() {
+ $D('sent').innerHTML = sent;
+ $D('received').innerHTML = received;
+ $D('errors').innerHTML = errors;
+ }
+
+ function connect() {
+ var host = $D('host').value,
+ port = $D('port').value,
+ scheme = "ws://", uri;
+
+ console.log(">> connect");
+ if ((!host) || (!port)) {
+ console.log("must set host and port");
+ return;
+ }
+
+ if (ws) {
+ ws.close();
+ }
+
+ if ($D('encrypt').checked) {
+ scheme = "wss://";
+ }
+ uri = scheme + host + ":" + port;
+ message("connecting to " + uri);
+
+ ws = new Websock();
+ ws.open(uri);
+
+ ws.on('message', function(e) {
+ //console.log(">> WebSockets.onmessage");
+ var str = ws.rQshiftStr();
+
+ message("Received message '" + str + "'");
+ //console.log("<< WebSockets.onmessage");
+ });
+ ws.on('open', function(e) {
+ console.log(">> WebSockets.onopen");
+ echo_ref = setInterval(send_msg, echoDelay);
+ console.log("<< WebSockets.onopen");
+ });
+ ws.on('close', function(e) {
+ console.log(">> WebSockets.onclose");
+ if (echo_ref) {
+ clearInterval(echo_ref);
+ echo_ref = null;
+ }
+ console.log("<< WebSockets.onclose");
+ });
+ ws.on('error', function(e) {
+ console.log(">> WebSockets.onerror");
+ if (echo_ref) {
+ clearInterval(echo_ref);
+ echo_ref = null;
+ }
+ console.log("<< WebSockets.onerror");
+ });
+
+ $D('connectButton').value = "Stop";
+ $D('connectButton').onclick = disconnect;
+ console.log("<< connect");
+ }
+
+ function disconnect() {
+ console.log(">> disconnect");
+ if (ws) {
+ ws.close();
+ }
+
+ if (echo_ref) {
+ clearInterval(echo_ref);
+ }
+
+ $D('connectButton').value = "Start";
+ $D('connectButton').onclick = connect;
+ console.log("<< disconnect");
+ }
+
+
+ window.onload = function() {
+ console.log("onload");
+ var url = document.location.href;
+ $D('host').value = (url.match(/host=([^&#]*)/) || ['',window.location.hostname])[1];
+ $D('port').value = (url.match(/port=([^&#]*)/) || ['',window.location.port])[1];
+ }
+ </script>
+
+</html>
diff --git a/third_party/websockify/tests/echo.py b/third_party/websockify/tests/echo.py
new file mode 100755
index 00000000..878c31ae
--- /dev/null
+++ b/third_party/websockify/tests/echo.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+
+'''
+A WebSocket server that echos back whatever it receives from the client.
+Copyright 2010 Joel Martin
+Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)
+
+You can make a cert/key with openssl using:
+openssl req -new -x509 -days 365 -nodes -out self.pem -keyout self.pem
+as taken from http://docs.python.org/dev/library/ssl.html#certificates
+'''
+
+import os, sys, select, optparse
+sys.path.insert(0,os.path.dirname(__file__) + "/../")
+from websocket import WebSocketServer
+
+class WebSocketEcho(WebSocketServer):
+ """
+ WebSockets server that echos back whatever is received from the
+ client. """
+ buffer_size = 8096
+
+ def new_client(self):
+ """
+ Echo back whatever is received.
+ """
+
+ cqueue = []
+ c_pend = 0
+ cpartial = ""
+ rlist = [self.client]
+
+ while True:
+ wlist = []
+
+ if cqueue or c_pend: wlist.append(self.client)
+ ins, outs, excepts = select.select(rlist, wlist, [], 1)
+ if excepts: raise Exception("Socket exception")
+
+ if self.client in outs:
+ # Send queued target data to the client
+ c_pend = self.send_frames(cqueue)
+ cqueue = []
+
+ if self.client in ins:
+ # Receive client data, decode it, and send it back
+ frames, closed = self.recv_frames()
+ cqueue.extend(frames)
+
+ if closed:
+ self.send_close()
+ raise self.EClose(closed)
+
+if __name__ == '__main__':
+ parser = optparse.OptionParser(usage="%prog [options] listen_port")
+ parser.add_option("--verbose", "-v", action="store_true",
+ help="verbose messages and per frame traffic")
+ parser.add_option("--cert", default="self.pem",
+ help="SSL certificate file")
+ parser.add_option("--key", default=None,
+ help="SSL key file (if separate from cert)")
+ parser.add_option("--ssl-only", action="store_true",
+ help="disallow non-encrypted connections")
+ (opts, args) = parser.parse_args()
+
+ try:
+ if len(args) != 1: raise
+ opts.listen_port = int(args[0])
+ except:
+ parser.error("Invalid arguments")
+
+ opts.web = "."
+ server = WebSocketEcho(**opts.__dict__)
+ server.start_server()
+
diff --git a/third_party/websockify/tests/echo.rb b/third_party/websockify/tests/echo.rb
new file mode 100755
index 00000000..ea34db5d
--- /dev/null
+++ b/third_party/websockify/tests/echo.rb
@@ -0,0 +1,62 @@
+#!/usr/bin/env ruby
+
+# A WebSocket server that echos back whatever it receives from the client.
+# Copyright 2011 Joel Martin
+# Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)
+
+require 'socket'
+$: << "other"
+$: << "../other"
+require 'websocket'
+
+class WebSocketEcho < WebSocketServer
+
+ # Echo back whatever is received
+ def new_client(client)
+
+ cqueue = []
+ c_pend = 0
+ rlist = [client]
+
+ loop do
+ wlist = []
+
+ if cqueue.length > 0 or c_pend
+ wlist << client
+ end
+
+ ins, outs, excepts = IO.select(rlist, wlist, nil, 1)
+ if excepts.length > 0
+ raise Exception, "Socket exception"
+ end
+
+ if outs.include?(client)
+ # Send queued data to the client
+ c_pend = send_frames(cqueue)
+ cqueue = []
+ end
+
+ if ins.include?(client)
+ # Receive client data, decode it, and send it back
+ frames, closed = recv_frames
+ cqueue += frames
+
+ if closed
+ raise EClose, closed
+ end
+ end
+
+ end # loop
+ end
+end
+
+port = ARGV[0].to_i
+puts "Starting server on port #{port}"
+
+server = WebSocketEcho.new('listen_port' => port, 'verbose' => true)
+server.start
+server.join
+
+puts "Server has been terminated"
+
+# vim: sw=2
diff --git a/third_party/websockify/tests/include b/third_party/websockify/tests/include
new file mode 120000
index 00000000..f5030fe8
--- /dev/null
+++ b/third_party/websockify/tests/include
@@ -0,0 +1 @@
+../include \ No newline at end of file
diff --git a/third_party/websockify/tests/latency.html b/third_party/websockify/tests/latency.html
new file mode 100644
index 00000000..74538a48
--- /dev/null
+++ b/third_party/websockify/tests/latency.html
@@ -0,0 +1,290 @@
+<html>
+
+ <head>
+ <title>WebSockets Latency Test</title>
+ <script src="include/base64.js"></script>
+ <script src="include/util.js"></script>
+ <script src="include/webutil.js"></script>
+ <script src="include/websock.js"></script>
+ <!-- Uncomment to activate firebug lite -->
+ <!--
+ <script type='text/javascript'
+ src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
+ -->
+
+
+ </head>
+
+ <body>
+
+ Host: <input id='host' style='width:100'>&nbsp;
+ Port: <input id='port' style='width:50'>&nbsp;
+ Encrypt: <input id='encrypt' type='checkbox'>
+ <br>
+ Payload Size: <input id='payload_size' style='width:50'>&nbsp;
+ Send Delay (ms): <input id='sendDelay' style='width:50' value="10">&nbsp;
+ <input id='connectButton' type='button' value='Start' style='width:100px'
+ onclick="connect();">&nbsp;
+
+ <br><br>
+ <table border=1>
+ <tr>
+ <th align="right">Packets sent:</th>
+ <td align="right"><div id='sent'></div></td>
+ </tr><tr>
+ <th align="right">Packets Received:</th>
+ <td align="right"><div id='received'></div></td>
+ </tr><tr>
+ <th align="right">Average Latency:</th>
+ <td align="right"><div id='laverage'></div></td>
+ </tr><tr>
+ <th align="right">40 Frame Running Average Latency:</th>
+ <td align="right"><div id='lrunning'></div></td>
+ </tr><tr>
+ <th align="right">Minimum Latency:</th>
+ <td align="right"><div id='lmin'></div></td>
+ </tr><tr>
+ <th align="right">Maximum Latency:</th>
+ <td align="right"><div id='lmax'></div></td>
+ </tr>
+ </table>
+
+ <br>
+ Messages:<br>
+ <textarea id="messages" style="font-size: 9;" cols=80 rows=10></textarea>
+ </body>
+
+
+ <script>
+
+ var host = null, port = null, sendDelay = 0, actualSendDelay,
+ ws = null, send_ref = null,
+ sent, received, latencies, ltotal, laverage, lrunning, lmin, lmax,
+ run_length = 40,
+ payload_size = 2000, payload,
+ msg_cnt = 0, recv_seq = 0, send_seq = 0;
+
+ Array.prototype.pushStr = function (str) {
+ var n = str.length;
+ for (var i=0; i < n; i++) {
+ this.push(str.charCodeAt(i));
+ }
+ }
+
+
+ function message(str) {
+ console.log(str);
+ cell = $D('messages');
+ msg_cnt++;
+ cell.innerHTML += msg_cnt + ": " + str + "\n";
+ cell.scrollTop = cell.scrollHeight;
+ }
+
+
+ function add (x,y) {
+ return parseInt(x,10)+parseInt(y,10);
+ }
+
+ function recvMsg(data) {
+ //console.log(">> check_respond");
+ var i, now, arr, first, last, arr, latency;
+
+ now = (new Date()).getTime(); // Early as possible
+
+ arr = ws.rQshiftBytes(ws.rQlen());
+ first = String.fromCharCode(arr.shift());
+ last = String.fromCharCode(arr.pop());
+
+ if (first != "^") {
+ message("Error: packet missing start char '^'");
+ disconnect();
+ return;
+ }
+ if (last != "$") {
+ message("Error: packet missing end char '$'");
+ disconnect();
+ return;
+ }
+ arr = arr.map(function(num) {
+ return String.fromCharCode(num);
+ } ).join('').split(':');
+ seq = arr[0];
+ timestamp = parseInt(arr[1],10);
+ rpayload = arr[2];
+
+ if (seq != recv_seq) {
+ message("Error: expected seq " + recv_seq + " but got " + seq);
+ disconnect();
+ return;
+ }
+ recv_seq++;
+ if (payload !== rpayload) {
+ message("Payload corrupt");
+ disconnect();
+ return;
+ }
+
+ received++;
+
+ latency = now - timestamp;
+ latencies.push(latency);
+ if (latencies.length > run_length) {
+ latencies.shift();
+ }
+ ltotal += latency;
+ laverage = ltotal / received;
+ lrunning = 0;
+ for (var i=0; i < latencies.length; i++) {
+ lrunning += latencies[i];
+ }
+ lrunning = lrunning / latencies.length;
+
+ if (latency < lmin) {
+ lmin = latency;
+ }
+ if (latency > lmax) {
+ lmax = latency;
+ }
+
+ showStats();
+ //console.log("<< check_respond");
+ }
+
+ function sendMsg() {
+ var arr = [];
+ if (! ws.flush() ) {
+ message("WebSocket not ready, backing off");
+ actualSendDelay = actualSendDelay * 2;
+ send_ref = setTimeout(sendMsg, actualSendDelay);
+ return false;
+ } else {
+ // Scale the delay down to the requested minimum
+ if (actualSendDelay > sendDelay) {
+ message("WebSocket ready, increasing presure");
+ actualSendDelay = Math.max(actualSendDelay / 2, sendDelay);
+ }
+ }
+
+ timestamp = (new Date()).getTime();
+ arr.pushStr("^" + send_seq + ":" + timestamp + ":" + payload + "$");
+ send_seq ++;
+ ws.send(arr);
+ sent++;
+
+ showStats();
+ send_ref = setTimeout(sendMsg, actualSendDelay);
+ }
+
+ function showStats() {
+ $D('sent').innerHTML = sent;
+ $D('received').innerHTML = received;
+ $D('laverage').innerHTML = laverage.toFixed(2);
+ $D('lrunning').innerHTML = lrunning.toFixed(2);
+ $D('lmin').innerHTML = lmin.toFixed(2);
+ $D('lmax').innerHTML = lmax.toFixed(2);
+ }
+
+ function init_ws() {
+ console.log(">> init_ws");
+ var scheme = "ws://";
+ if ($D('encrypt').checked) {
+ scheme = "wss://";
+ }
+ var uri = scheme + host + ":" + port;
+ console.log("connecting to " + uri);
+ ws = new Websock();
+ ws.maxBufferedAmount = 5000;
+ ws.open(uri);
+
+ ws.on('message', function() {
+ recvMsg();
+ });
+ ws.on('open', function() {
+ send_ref = setTimeout(sendMsg, sendDelay);
+ });
+ ws.on('close', function(e) {
+ disconnect();
+ });
+ ws.on('error', function(e) {
+ message("Websock error: " + e);
+ disconnect();
+ });
+
+ console.log("<< init_ws");
+ }
+
+ function connect() {
+ console.log(">> connect");
+ host = $D('host').value;
+ port = $D('port').value;
+ payload_size = parseInt($D('payload_size').value, 10);
+ sendDelay = parseInt($D('sendDelay').value, 10);
+
+ if ((!host) || (!port)) {
+ console.log("must set host and port");
+ return;
+ }
+
+ if (ws) {
+ ws.close();
+ }
+ init_ws();
+
+ // Populate payload data
+ var numlist = []
+ for (var i=0; i < payload_size; i++) {
+ numlist.push( Math.floor(Math.random()*10) );
+ }
+ payload = numlist.join('');
+
+ // Initialize stats
+ sent = 0;
+ received = 0;
+ latencies = [];
+ ltotal = 0;
+ laverage = 0;
+ lrunning = 0;
+ lmin = 999999999;
+ lmax = 0;
+ actualSendDelay = sendDelay;
+
+ $D('connectButton').value = "Stop";
+ $D('connectButton').onclick = disconnect;
+ console.log("<< connect");
+ }
+
+ function disconnect() {
+ console.log(">> disconnect");
+ if (ws) {
+ ws.close();
+ }
+
+ if (send_ref) {
+ clearInterval(send_ref);
+ send_ref = null;
+ }
+ showStats(); // Final numbers
+ recv_seq = 0;
+ send_seq = 0;
+
+ $D('connectButton').value = "Start";
+ $D('connectButton').onclick = connect;
+ console.log("<< disconnect");
+ }
+
+
+ window.onload = function() {
+ console.log("onload");
+ if (Websock_native) {
+ message("Using native WebSockets");
+ } else {
+ message("initializing web-socket-js flash bridge");
+ }
+ var url = document.location.href;
+ $D('host').value = (url.match(/host=([^&#]*)/) || ['',window.location.hostname])[1];
+ $D('port').value = (url.match(/port=([^&#]*)/) || ['',window.location.port])[1];
+ $D('payload_size').value = payload_size;
+ }
+ </script>
+
+</html>
diff --git a/third_party/websockify/tests/latency.py b/third_party/websockify/tests/latency.py
new file mode 120000
index 00000000..3ae4d964
--- /dev/null
+++ b/third_party/websockify/tests/latency.py
@@ -0,0 +1 @@
+echo.py \ No newline at end of file
diff --git a/third_party/websockify/tests/load.html b/third_party/websockify/tests/load.html
new file mode 100644
index 00000000..af165dca
--- /dev/null
+++ b/third_party/websockify/tests/load.html
@@ -0,0 +1,250 @@
+<html>
+
+ <head>
+ <title>WebSockets Load Test</title>
+ <script src="include/util.js"></script>
+ <script src="include/webutil.js"></script>
+ <script src="include/base64.js"></script>
+ <script src="include/websock.js"></script>
+ <!-- Uncomment to activate firebug lite -->
+ <!--
+ <script type='text/javascript'
+ src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
+ -->
+
+
+ </head>
+
+ <body>
+
+ Host: <input id='host' style='width:100'>&nbsp;
+ Port: <input id='port' style='width:50'>&nbsp;
+ Encrypt: <input id='encrypt' type='checkbox'>&nbsp;
+ Send Delay (ms): <input id='sendDelay' style='width:50' value="100">&nbsp;
+ <input id='connectButton' type='button' value='Start' style='width:100px'
+ onclick="connect();">&nbsp;
+
+ <br><br>
+ <table border=1>
+ <tr>
+ <th align="right">Packets sent:</th>
+ <td align="right"><div id='sent'>0</div></td>
+ </tr><tr>
+ <th align="right">Good Packets Received:</th>
+ <td align="right"><div id='received'>0</div></td>
+ </tr><tr>
+ <th align="right">Errors (Bad Packets Received:)</th>
+ <td align="right"><div id='errors'>0</div></td>
+ </tr>
+ </table>
+
+ <br>
+ Errors:<br>
+ <textarea id="error" style="font-size: 9;" cols=80 rows=25></textarea>
+ </body>
+
+
+ <script>
+
+ function error(str) {
+ console.error(str);
+ cell = $D('error');
+ cell.innerHTML += errors + ": " + str + "\n";
+ cell.scrollTop = cell.scrollHeight;
+ }
+
+ var host = null, port = null, sendDelay = 0;
+ var ws = null, update_ref = null, send_ref = null;
+ var sent = 0, received = 0, errors = 0;
+ var max_send = 2000;
+ var recv_seq = 0, send_seq = 0;
+
+ Array.prototype.pushStr = function (str) {
+ var n = str.length;
+ for (var i=0; i < n; i++) {
+ this.push(str.charCodeAt(i));
+ }
+ }
+
+
+
+ function add (x,y) {
+ return parseInt(x,10)+parseInt(y,10);
+ }
+
+ function check_respond(data) {
+ //console.log(">> check_respond");
+ var first, last, str, length, chksum, nums, arr;
+ first = String.fromCharCode(data.shift());
+ last = String.fromCharCode(data.pop());
+
+ if (first != "^") {
+ errors++;
+ error("Packet missing start char '^'");
+ return;
+ }
+ if (last != "$") {
+ errors++;
+ error("Packet missing end char '$'");
+ return;
+ }
+ arr = data.map(function(num) {
+ return String.fromCharCode(num);
+ } ).join('').split(':');
+ seq = arr[0];
+ length = arr[1];
+ chksum = arr[2];
+ nums = arr[3];
+
+ //console.log(" length:" + length + " chksum:" + chksum + " nums:" + nums);
+ if (seq != recv_seq) {
+ errors++;
+ error("Expected seq " + recv_seq + " but got " + seq);
+ recv_seq = parseInt(seq,10) + 1; // Back on track
+ return;
+ }
+ recv_seq++;
+ if (nums.length != length) {
+ errors++;
+ error("Expected length " + length + " but got " + nums.length);
+ return;
+ }
+ //real_chksum = nums.reduce(add);
+ real_chksum = 0;
+ for (var i=0; i < nums.length; i++) {
+ real_chksum += parseInt(nums.charAt(i), 10);
+ }
+ if (real_chksum != chksum) {
+ errors++
+ error("Expected chksum " + chksum + " but real chksum is " + real_chksum);
+ return;
+ }
+ received++;
+ //console.log(" Packet checks out: length:" + length + " chksum:" + chksum);
+ //console.log("<< check_respond");
+ }
+
+ function send() {
+ var length = Math.floor(Math.random()*(max_send-9)) + 10; // 10 - max_send
+ var numlist = [], arr = [];
+ for (var i=0; i < length; i++) {
+ numlist.push( Math.floor(Math.random()*10) );
+ }
+ //chksum = numlist.reduce(add);
+ chksum = 0;
+ for (var i=0; i < numlist.length; i++) {
+ chksum += parseInt(numlist[i], 10);
+ }
+ var nums = numlist.join('');
+ arr.pushStr("^" + send_seq + ":" + length + ":" + chksum + ":" + nums + "$")
+ send_seq ++;
+ ws.send(arr);
+ sent++;
+ }
+
+ function update_stats() {
+ $D('sent').innerHTML = sent;
+ $D('received').innerHTML = received;
+ $D('errors').innerHTML = errors;
+ }
+
+ function init_ws() {
+ console.log(">> init_ws");
+ var scheme = "ws://";
+ if ($D('encrypt').checked) {
+ scheme = "wss://";
+ }
+ var uri = scheme + host + ":" + port;
+ console.log("connecting to " + uri);
+ ws = new Websock();
+ ws.open(uri);
+
+ ws.on('message', function() {
+ //console.log(">> WebSockets.onmessage");
+ arr = ws.rQshiftBytes(ws.rQlen());
+ check_respond(arr);
+ //console.log("<< WebSockets.onmessage");
+ });
+ ws.on('open', function() {
+ console.log(">> WebSockets.onopen");
+ send_ref = setInterval(send, sendDelay);
+ console.log("<< WebSockets.onopen");
+ });
+ ws.on('close', function(e) {
+ console.log(">> WebSockets.onclose");
+ clearInterval(send_ref);
+ console.log("<< WebSockets.onclose");
+ });
+ ws.on('error', fun