Ticket #2: https://github.com/kanaka/websockify/issues/2 - win32
support. The 'resource' module is not available under Windows. We only
use it for daemonizing so make it optional and disable daemonizing
support on Windows for now.
Also, refactor how the optional imports to turn them into data instead
of code and iterate through them.
Add early warnings to indicate when modules are missing and
functionality is disabled.
Multiprocessing:
- Switch to using multiprocessing module for python >= 2.6. For python
2.4 continue to use the os.fork() method.
- Move the new_client creation into top_new_client method to enable
multiprocessing refactor.
- Only do SIGCHLD handling for os.fork/python 2.4. When doing our own
SIGCHLD handling under python 3.0, we can run into a python futex
hang when reloading a web page rapidly. Multiprocessing does it's
own child reaping so we only need it with os.fork().
Python 3.0:
- Modify imports to reflect new locations: StringIO from io,
SimpleHTTPRequestHandler from http.server, urlsplit from
urllib.parse.
- Convert all print statements to print() calls. This also means no
comma parameter idiom and only using string formatting.
- Define b2s (bytes-to-string) and s2b (string-to-bytes) which are
no-ops on python versions prior to python 3. In python 3 these do
the conversion between string and bytes.
- Use compatible try/except method. Exception variable must be
extracted using sys.exc_info() rather than as part of the except
statement.
Python 2.4:
- Now degrades more gracefully if ssl module is not found. It will
still run, but will refuse SSL connections.
- Doesn't support HyBi-07 version due to numpy and struct.unpack_from
requirement.
Instead of doing crazy things with file-descriptors in
SplitHTTPHandler, WSRequestHandler detects a WebSockets upgrade and
returns 101 as the 'last_code'. In addition to avoiding funkiness with
file-descriptors, this allows use of the already parsed headers and
removal of the parse_handshake routine.
This also makes it easier to explore adding python 3.X support
(https://github.com/kanaka/websockify/issues/1) since the
file-descriptor/string splitting is very difficult to integrate with
python 3.X.
- Add initial IETF-07 (HyBi-07) protocol version support. This version
still uses base64 encoding since the API for binary support is not
yet finalized.
- Move socket send and recieve functions into the WebSocketServer
class instead of having the sub-class do this. This simplifies
sub-classes somewhat. The send_frame routine now returns the number
of frames that were unable to be sent. If this value is non-zero
then the sub-class should call again when the socket is ready until
the pending frames count is 0.
- Do traffic reporting in the main class instead.
- When the client is HyBi style (i.e. IETF-07) then use the
sub-protocol header to select whether to do base64 encoding or
simply send the frame data raw (binary). Update include/websock.js
to send a 'base64' protocol selector. Once the API support binary,
then the client will need to detect this and set the protocol to
'binary'.
Wait 3 seconds for the client to send something. If no data is
available within 3 seconds then close the connection. It's probably
a non-WebSockets client that is waiting for the server to say
something first.
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.