websocket.py has no concept of target/proxy so any target processing
should happen in websockify itself.
Also:
- remove URL parsing imports from websocket.py since they are not
needed with SimpleHTTPRequestHandler doing the parsing.
- read the absolute path of the target_list file on startup since the
--web option will change directories if set.
The --target-list option is used to pass a configuration file on websockify start.
This file contains entries in the form host:port:token, one per line.
When a new connection is open (from noVNC for example), the url should look like:
ws://websockify_host:websockify_port/?token=ABCD
The token is then extracted and checked against the entries in the configuration file.
When the token matches, the connection is proxied to the host:port indicated in the file.
If the configuration file is a folder, then all the entries from files in it are read.
Add the option "-6, --prefer-ipv6". When set, the 'prefer_ipv6' flag in
websocket.py is used so that 'source_addr' is resolved to IPv6 if
available. If 'source_addr' is not set, binds to [::].
- Rename unix socket option to '--unix-target' to be consistent with
'--ssl-target' which is an analogous switch.
- Fix normal socket target mode which was broken after merge.
- Normalize/fix output for SSL, unix socket and wrap command modes.
Try importing from the newest location/name and then fallback if that
fails instead of using python version switches.
Still use version switch for the buffer/bytes to string wrapper
routines since python 2.6 has intermediate support for buffer/bytes
and I want to know if full support (ala python 3.0) is there.
- Use array module for unmasking HyBi when no numpy module is
available.
- Detect client close properly when using python 3.
- Print request URL path is specified.
- --run-once will exit after handling a single WebSocket connection
(but not ater flash policy or normal web requests).
- --timeout TIME will stop listening for new connections after exit
after TIME seconds (the master process shuts down). Existing
WebSocket connections will continue but once all connections are
closed all processes will terminate.
WebSocketServer.socket() is a static method takes a host and port and
an optional connect parameter. If connect is not set then it returns
a socket listening on host and port. If connect is set then
a connection will be made host and port and the socket returned. This
has IPv6 support like the addrinfo method it replaces.
Also, prefer IPv4 resolutions if they are in the list. This can be
overriden to prefer IPv6 resolutions for the same host using the
optional prefer_ipv6 parameter.
- fix addrinfo to accept empty host as localhost
- use correct host variable in addrinfo error message
- accept HyBi 7, 8 and 9. No difference for now.
- send close buffer correctly.
WebSocketServer(..., record='FILE_PREFIX')
The reocrd parameter will turn on recording of all messages sent
to and from the client. The record parameter is a file prefix. The
full file-name will be the prefix with an extension '.HANDLER_ID'
based on the handler ID.
Recording required some restructing of the encode and decode function
to return more information so that the recording functions can record
just the payload data and ignore the WebSockets framing/headers.
Caveats:
- Not all messages recorded as sent to the client were necessarily
received by the client. For example, if several messages are queued
for the client, but the connection is shutdown before the messages
are actually sent, these queued messages will still appear in the
recording.
- If the server is also handling HTTP requests then the handler ID
extensions for the recorded files will be monotonic but not
contiguous because only WebSocket connections are recorded, not HTTP
requests.
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.