Also add a wsencoding test client/server program to test send a set of values between client and server and vice-versa to test encodings. Not turned on by default. Add support for encode/decode of UTF-8 in the proxy. This leverages the browser for decoding the WebSocket stream directly instead of doing base64 decode in the browser itself. Unfortunately, in Chrome this has negligible impact (round-trip time is increased slightly likely due to extra python processing). In firefox, due to the use of the flash WebSocket emulator the performance is even worse. This is because it's really annoying to get the flash WebSocket emulator to properly decode a UTF-8 bytestream. The problem is that the readUTFBytes and readMultiByte methods of an ActionScript ByteArray don't treat 0x00 correctly. They return a string that ends at the first 0x00, but the index into the ByteArray has been advanced by however much you requested. This is very silly for two reasons: ActionScript (and Javascript) strings can contain 0x00 (they are not null terminated) and second, UTF-8 can legitimately contain 0x00 values. Since UTF-8 is not constant width there isn't a great way to determine if those methods in fact did encounter a 0x00 or they just read the number of bytes requested. Doing manual decoding using readUTFByte one character at a time slows things down quite a bit. And to top it all off, those methods don't support the alternate UTF-8 encoding for 0x00 ("\xc0\x80"). They also just treat that encoding as the end of string too. So to get around this, for now I'm encoding zero as 256 ("\xc4\x80") and then doing mod 256 in Javascript. Still doesn't result in much benefit in firefox. But, it's an interesting approach that could use some more exploration so I'm leaving in the code in both places. |
||
---|---|---|
docs | ||
include | ||
tests | ||
.gitignore | ||
LICENSE.LGPL-3 | ||
LICENSE.txt | ||
README.md | ||
vnc.html | ||
vnc.js | ||
web.py | ||
websocket.py | ||
wsproxy.py |
README.md
noVNC: HTML5 VNC Client
Description
noVNC is a VNC client implemented using HTML5 technologies, specifically Canvas and WebSocket (supports 'wss://' encryption).
For browsers that do not have builtin WebSocket support, the project includes web-socket-js, a WebSocket emulator using Adobe Flash (http://github.com/gimite/web-socket-js).
In addition, as3crypto has been added to web-socket-js to implement WebSocket SSL/TLS encryption, i.e. the "wss://" URI scheme. (http://github.com/lyokato/as3crypto_patched).
Requirements
Until there is VNC server support for WebSocket connections, you need to use a WebSocket to TCP socket proxy. There is a python proxy included ('wsproxy'). One advantage of using the proxy is that it has builtin support for SSL/TLS encryption (i.e. "wss://").
There a few reasons why a proxy is required:
-
WebSocket is not a pure socket protocol. There is an initial HTTP like handshake to allow easy hand-off by web servers and allow some origin policy exchange. Also, each WebSocket frame begins with 0 ('\x00') and ends with 255 ('\xff').
-
Javascript itself does not have the ability to handle pure byte strings (Unicode encoding messes with it) even though you can read them with WebSocket. The python proxy encodes the data so that the Javascript client can base64 decode the data into an array.
-
When using the web-socket-js as a fallback, WebSocket 'onmessage' events may arrive out of order. In order to compensate for this the client asks the proxy (using the initial query string) to add sequence numbers to each packet.
To encrypt the traffic using the WebSocket 'wss://' URI scheme you need to generate a certificate for the proxy to load. You can generate a self-signed certificate using openssl. The common name should be the hostname of the server where the proxy will be running:
`openssl req -new -x509 -days 365 -nodes -out self.pem -keyout self.pem`
Usage
-
run a VNC server.
vncserver :1
-
run the python proxy:
./wsproxy.py [listen_port] [vnc_host] [vnc_port]
./wsproxy.py 8787 localhost 5901
-
run the mini python web server to serve the directory:
./web.py PORT
./web.py 8080
-
Point your web browser at http://localhost:8080/vnc.html (or whatever port you used above to run the web server).
-
Specify the host and port where the proxy is running and the password that the vnc server is using (if any). Hit the Connect button and enjoy!
Integration
The client is designed to be easily integrated with existing web structure and style.
At a minimum you must include the script and call the RFB.load() function which takes a parameter that is the ID of the DOM element to fill. For example:
<body>
<div id='vnc'>Loading</div>
</body>
<script src='vnc.js'></script>
<script> windows.onload = function () { RFB.load('vnc'); }</script>
The file include/plain.css
has a list of stylable elements.