Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 264f8fdd7f | |||
| 36cb8f4676 | |||
| 36fcd5784f | |||
| 46450577c2 | |||
| d3ba23fa64 | |||
| 6d27b5d321 | |||
| 888e75a8fb | |||
| b7f255ce0b | |||
| 477947ba96 | |||
| 33e9a21ce4 | |||
| 2d078e8cd8 | |||
| d6d960dbe5 | |||
| 903198a724 | |||
| d3865688c8 | |||
| 5a726c2e4d | |||
| b2fe57c950 |
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "include/web-socket-js-project"]
|
||||||
|
path = include/web-socket-js-project
|
||||||
|
url = https://github.com/gimite/web-socket-js.git
|
||||||
+10
@@ -1,6 +1,16 @@
|
|||||||
Changes
|
Changes
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
0.5.1 - Jun 27, 2013
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
* use upstream einaros/ws (>=0.4.27) with websockify.js
|
||||||
|
* file_only and no_parent security options for WSRequestHandler
|
||||||
|
* Update build of web-socket-js (c0855c6cae)
|
||||||
|
* add include/web-socket-js-project submodule to gimite/web-socket-js
|
||||||
|
for DSFG compliance.
|
||||||
|
* drop Hixie protocol support
|
||||||
|
|
||||||
0.4.1 - Mar 12, 2013
|
0.4.1 - Mar 12, 2013
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -1 +1,2 @@
|
|||||||
include CHANGES.txt websockify include README.md LICENSE.txt
|
include CHANGES.txt README.md LICENSE.txt
|
||||||
|
graft include
|
||||||
|
|||||||
@@ -10,25 +10,17 @@ the target in both directions.
|
|||||||
|
|
||||||
### WebSockets binary data
|
### WebSockets binary data
|
||||||
|
|
||||||
Websockify 0.4.X supports all versions of the WebSockets protocol
|
Starting with websockify 0.5.0, only the HyBi / IETF
|
||||||
(Hixie and HyBi). Starting with websockify 0.5.0, only the HyBi / IETF
|
|
||||||
6455 WebSocket protocol is supported.
|
6455 WebSocket protocol is supported.
|
||||||
|
|
||||||
The older Hixie versions of the protocol only support UTF-8 text
|
Websockify negotiates whether to base64 encode traffic to and from the
|
||||||
payloads. In order to transport binary data over UTF-8 an encoding
|
client via the subprotocol header (Sec-WebSocket-Protocol). The valid
|
||||||
must used to encapsulate the data within UTF-8. With Hixie clients,
|
subprotocol values are 'binary' and 'base64' and if the client sends
|
||||||
Websockify uses base64 to encode all traffic to and from the client.
|
both then the server (the python implementation) will prefer 'binary'.
|
||||||
This does not affect the data between websockify and the server.
|
The 'binary' subprotocol indicates that the data will be sent raw
|
||||||
|
using binary WebSocket frames. Some HyBi clients (such as the Flash
|
||||||
With HyBi clients, websockify negotiates whether to base64 encode
|
fallback and older Chrome and iOS versions) do not support binary data
|
||||||
traffic to and from the client via the subprotocol header
|
which is why the negotiation is necessary.
|
||||||
(Sec-WebSocket-Protocol). The valid subprotocol values are 'binary'
|
|
||||||
and 'base64' and if the client sends both then the server (the python
|
|
||||||
implementation) will prefer 'binary'. The 'binary' subprotocol
|
|
||||||
indicates that the data will be sent raw using binary WebSocket
|
|
||||||
frames. Some HyBi clients (such as the Flash fallback and older Chrome
|
|
||||||
and iOS versions) do not support binary data which is why the
|
|
||||||
negotiation is necessary.
|
|
||||||
|
|
||||||
|
|
||||||
### Encrypted WebSocket connections (wss://)
|
### Encrypted WebSocket connections (wss://)
|
||||||
|
|||||||
+4
-1
@@ -1,4 +1,4 @@
|
|||||||
- Update setup.py and CHANGES.txt and commit
|
- Update setup.py, CHANGES.txt and other/package.json and commit
|
||||||
- Create version tag and tarball from tag
|
- Create version tag and tarball from tag
|
||||||
WVER=0.1.0
|
WVER=0.1.0
|
||||||
git tag v${WVER}
|
git tag v${WVER}
|
||||||
@@ -8,3 +8,6 @@
|
|||||||
python setup.py register
|
python setup.py register
|
||||||
- Upload the source distribution to pypi
|
- Upload the source distribution to pypi
|
||||||
python setup.py sdist upload
|
python setup.py sdist upload
|
||||||
|
- Register with npmjs.org (once)
|
||||||
|
- Upload websockify.js npmjs.org package
|
||||||
|
npm publish other/js
|
||||||
|
|||||||
Submodule
+1
Submodule include/web-socket-js-project added at c0855c6cae
Binary file not shown.
@@ -0,0 +1,7 @@
|
|||||||
|
A JavaScript implementation of the websockify WebSocket-to-TCP bridge/proxy.
|
||||||
|
|
||||||
|
Copyright (C) 2013 - Joel Martin (github.com/kanaka)
|
||||||
|
|
||||||
|
Licensed under LGPL-3.
|
||||||
|
|
||||||
|
See http://github.com/kanaka/websockify for more info.
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"author": "Joel Martin <github@martintribe.org> (http://github.com/kanaka)",
|
||||||
|
"name": "websockify",
|
||||||
|
"description": "websockify is a WebSocket-to-TCP proxy/bridge",
|
||||||
|
"license": "LGPL-3",
|
||||||
|
"version": "0.5.1",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/kanaka/websockify.git"
|
||||||
|
},
|
||||||
|
"files": ["../../docs/LICENSE.LGPL-3"],
|
||||||
|
"bin": {
|
||||||
|
"websockify": "./websockify.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8.9"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ws": ">=0.4.27",
|
||||||
|
"base64": "latest",
|
||||||
|
"optimist": "latest",
|
||||||
|
"policyfile": "latest"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,14 +7,6 @@
|
|||||||
// Known to work with node 0.8.9
|
// Known to work with node 0.8.9
|
||||||
// Requires node modules: ws, optimist and policyfile
|
// Requires node modules: ws, optimist and policyfile
|
||||||
// npm install ws optimist policyfile
|
// npm install ws optimist policyfile
|
||||||
//
|
|
||||||
// NOTE:
|
|
||||||
// This version requires a patched version of einaros/ws that supports
|
|
||||||
// subprotocol negotiation. You can use the patched version like this:
|
|
||||||
//
|
|
||||||
// cd websockify/other
|
|
||||||
// git clone https://github.com/kanaka/ws
|
|
||||||
// npm link ./ws
|
|
||||||
|
|
||||||
|
|
||||||
var argv = require('optimist').argv,
|
var argv = require('optimist').argv,
|
||||||
@@ -37,6 +29,7 @@ var argv = require('optimist').argv,
|
|||||||
// Handle new WebSocket client
|
// Handle new WebSocket client
|
||||||
new_client = function(client) {
|
new_client = function(client) {
|
||||||
var clientAddr = client._socket.remoteAddress, log;
|
var clientAddr = client._socket.remoteAddress, log;
|
||||||
|
console.log(client.upgradeReq.url);
|
||||||
log = function (msg) {
|
log = function (msg) {
|
||||||
console.log(' ' + clientAddr + ': '+ msg);
|
console.log(' ' + clientAddr + ': '+ msg);
|
||||||
};
|
};
|
||||||
@@ -61,6 +54,12 @@ new_client = function(client) {
|
|||||||
});
|
});
|
||||||
target.on('end', function() {
|
target.on('end', function() {
|
||||||
log('target disconnected');
|
log('target disconnected');
|
||||||
|
client.close();
|
||||||
|
});
|
||||||
|
target.on('error', function() {
|
||||||
|
log('target connection error');
|
||||||
|
target.end();
|
||||||
|
client.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('message', function(msg) {
|
client.on('message', function(msg) {
|
||||||
@@ -126,11 +125,9 @@ http_request = function (request, response) {
|
|||||||
|
|
||||||
// Select 'binary' or 'base64' subprotocol, preferring 'binary'
|
// Select 'binary' or 'base64' subprotocol, preferring 'binary'
|
||||||
selectProtocol = function(protocols, callback) {
|
selectProtocol = function(protocols, callback) {
|
||||||
var plist = protocols ? protocols.split(',') : "";
|
if (protocols.indexOf('binary') >= 0) {
|
||||||
var plist = protocols.split(',');
|
|
||||||
if (plist.indexOf('binary') >= 0) {
|
|
||||||
callback(true, 'binary');
|
callback(true, 'binary');
|
||||||
} else if (plist.indexOf('base64') >= 0) {
|
} else if (protocols.indexOf('base64') >= 0) {
|
||||||
callback(true, 'base64');
|
callback(true, 'base64');
|
||||||
} else {
|
} else {
|
||||||
console.log("Client must support 'binary' or 'base64' protocol");
|
console.log("Client must support 'binary' or 'base64' protocol");
|
||||||
+14
-4
@@ -16,6 +16,8 @@ usage() {
|
|||||||
echo " Default: localhost:5900"
|
echo " Default: localhost:5900"
|
||||||
echo " --cert CERT Path to combined cert/key file"
|
echo " --cert CERT Path to combined cert/key file"
|
||||||
echo " Default: self.pem"
|
echo " Default: self.pem"
|
||||||
|
echo " --web WEB Path to web files (e.g. vnc.html)"
|
||||||
|
echo " Default: ./"
|
||||||
exit 2
|
exit 2
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,6 +26,7 @@ HERE="$(cd "$(dirname "$0")" && pwd)"
|
|||||||
PORT="6080"
|
PORT="6080"
|
||||||
VNC_DEST="localhost:5900"
|
VNC_DEST="localhost:5900"
|
||||||
CERT=""
|
CERT=""
|
||||||
|
WEB=""
|
||||||
proxy_pid=""
|
proxy_pid=""
|
||||||
|
|
||||||
die() {
|
die() {
|
||||||
@@ -50,6 +53,7 @@ while [ "$*" ]; do
|
|||||||
--listen) PORT="${OPTARG}"; shift ;;
|
--listen) PORT="${OPTARG}"; shift ;;
|
||||||
--vnc) VNC_DEST="${OPTARG}"; shift ;;
|
--vnc) VNC_DEST="${OPTARG}"; shift ;;
|
||||||
--cert) CERT="${OPTARG}"; shift ;;
|
--cert) CERT="${OPTARG}"; shift ;;
|
||||||
|
--web) WEB="${OPTARG}"; shift ;;
|
||||||
-h|--help) usage ;;
|
-h|--help) usage ;;
|
||||||
-*) usage "Unknown chrooter option: ${param}" ;;
|
-*) usage "Unknown chrooter option: ${param}" ;;
|
||||||
*) break ;;
|
*) break ;;
|
||||||
@@ -60,18 +64,24 @@ done
|
|||||||
which netstat >/dev/null 2>&1 \
|
which netstat >/dev/null 2>&1 \
|
||||||
|| die "Must have netstat installed"
|
|| die "Must have netstat installed"
|
||||||
|
|
||||||
netstat -ltn | grep -qs "${PORT}.*LISTEN" \
|
netstat -ltn | grep -qs "${PORT} .*LISTEN" \
|
||||||
&& die "Port ${PORT} in use. Try --listen PORT"
|
&& die "Port ${PORT} in use. Try --listen PORT"
|
||||||
|
|
||||||
trap "cleanup" TERM QUIT INT EXIT
|
trap "cleanup" TERM QUIT INT EXIT
|
||||||
|
|
||||||
# Find vnc.html
|
# Find vnc.html
|
||||||
if [ -e "$(pwd)/vnc.html" ]; then
|
if [ -n "${WEB}" ]; then
|
||||||
|
if [ ! -e "${WEB}/vnc.html" ]; then
|
||||||
|
die "Could not find ${WEB}/vnc.html"
|
||||||
|
fi
|
||||||
|
elif [ -e "$(pwd)/vnc.html" ]; then
|
||||||
WEB=$(pwd)
|
WEB=$(pwd)
|
||||||
elif [ -e "${HERE}/../vnc.html" ]; then
|
elif [ -e "${HERE}/../vnc.html" ]; then
|
||||||
WEB=${HERE}/../
|
WEB=${HERE}/../
|
||||||
elif [ -e "${HERE}/vnc.html" ]; then
|
elif [ -e "${HERE}/vnc.html" ]; then
|
||||||
WEB=${HERE}
|
WEB=${HERE}
|
||||||
|
elif [ -e "${HERE}/../share/novnc/vnc.html" ]; then
|
||||||
|
WEB=${HERE}/../share/novnc/
|
||||||
else
|
else
|
||||||
die "Could not find vnc.html"
|
die "Could not find vnc.html"
|
||||||
fi
|
fi
|
||||||
@@ -92,7 +102,7 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Starting webserver and WebSockets proxy on port ${PORT}"
|
echo "Starting webserver and WebSockets proxy on port ${PORT}"
|
||||||
${HERE}/wsproxy.py --web ${WEB} ${CERT:+--cert ${CERT}} ${PORT} ${VNC_DEST} &
|
${HERE}/websockify --web ${WEB} ${CERT:+--cert ${CERT}} ${PORT} ${VNC_DEST} &
|
||||||
proxy_pid="$!"
|
proxy_pid="$!"
|
||||||
sleep 1
|
sleep 1
|
||||||
if ! ps -p ${proxy_pid} >/dev/null; then
|
if ! ps -p ${proxy_pid} >/dev/null; then
|
||||||
@@ -101,7 +111,7 @@ if ! ps -p ${proxy_pid} >/dev/null; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "\n\nNavigate to to this URL:\n"
|
echo -e "\n\nNavigate to this URL:\n"
|
||||||
echo -e " http://$(hostname):${PORT}/vnc.html?host=$(hostname)&port=${PORT}\n"
|
echo -e " http://$(hostname):${PORT}/vnc.html?host=$(hostname)&port=${PORT}\n"
|
||||||
echo -e "Press Ctrl-C to exit\n\n"
|
echo -e "Press Ctrl-C to exit\n\n"
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -795,7 +795,7 @@ void start_server() {
|
|||||||
}
|
}
|
||||||
handler_msg("handler exit\n");
|
handler_msg("handler exit\n");
|
||||||
} else {
|
} else {
|
||||||
handler_msg("wsproxy exit\n");
|
handler_msg("websockify exit\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
* REBIND_PORT_NEW environment variables are set then bind on the new
|
* REBIND_PORT_NEW environment variables are set then bind on the new
|
||||||
* port (of localhost) instead of the old port.
|
* port (of localhost) instead of the old port.
|
||||||
*
|
*
|
||||||
* This allows a proxy (such as wsproxy) to run on the old port and translate
|
* This allows a bridge/proxy (such as websockify) to run on the old port and
|
||||||
* traffic to/from the new port.
|
* translate traffic to/from the new port.
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* LD_PRELOAD=./rebind.so \
|
* LD_PRELOAD=./rebind.so \
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
version = '0.4.1'
|
version = '0.5.1'
|
||||||
name = 'websockify'
|
name = 'websockify'
|
||||||
long_description = open("README.md").read() + "\n" + \
|
long_description = open("README.md").read() + "\n" + \
|
||||||
open("CHANGES.txt").read() + "\n"
|
open("CHANGES.txt").read() + "\n"
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ as taken from http://docs.python.org/dev/library/ssl.html#certificates
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
import os, sys, select, optparse
|
import os, sys, select, optparse
|
||||||
sys.path.insert(0,os.path.dirname(__file__) + "/../")
|
sys.path.insert(0,os.path.dirname(__file__) + "/../websockify")
|
||||||
from websocket import WebSocketServer
|
from websocket import WebSocketServer
|
||||||
|
|
||||||
class WebSocketEcho(WebSocketServer):
|
class WebSocketEcho(WebSocketServer):
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ given a sequence number. Any errors are reported and counted.
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
import sys, os, select, random, time, optparse
|
import sys, os, select, random, time, optparse
|
||||||
sys.path.insert(0,os.path.dirname(__file__) + "/../")
|
sys.path.insert(0,os.path.dirname(__file__) + "/../websockify")
|
||||||
from websocket import WebSocketServer
|
from websocket import WebSocketServer
|
||||||
|
|
||||||
class WebSocketLoad(WebSocketServer):
|
class WebSocketLoad(WebSocketServer):
|
||||||
|
|||||||
+3
-5
@@ -6,17 +6,15 @@ Display UTF-8 encoding for 0-255.'''
|
|||||||
import sys, os, socket, ssl, time, traceback
|
import sys, os, socket, ssl, time, traceback
|
||||||
from select import select
|
from select import select
|
||||||
|
|
||||||
sys.path.insert(0,os.path.dirname(__file__) + "/../")
|
sys.path.insert(0,os.path.dirname(__file__) + "/../websockify")
|
||||||
from websocket import WebSocketServer
|
from websocket import WebSocketServer
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
print "val: hixie | hybi_base64 | hybi_binary"
|
print "val: hybi_base64 | hybi_binary"
|
||||||
for c in range(0, 256):
|
for c in range(0, 256):
|
||||||
hixie = WebSocketServer.encode_hixie(chr(c))
|
|
||||||
hybi_base64 = WebSocketServer.encode_hybi(chr(c), opcode=1,
|
hybi_base64 = WebSocketServer.encode_hybi(chr(c), opcode=1,
|
||||||
base64=True)
|
base64=True)
|
||||||
hybi_binary = WebSocketServer.encode_hybi(chr(c), opcode=2,
|
hybi_binary = WebSocketServer.encode_hybi(chr(c), opcode=2,
|
||||||
base64=False)
|
base64=False)
|
||||||
print "%d: %s | %s | %s" % (c, repr(hixie), repr(hybi_base64),
|
print "%d: %s | %s" % (c, repr(hybi_base64), repr(hybi_binary))
|
||||||
repr(hybi_binary))
|
|
||||||
|
|
||||||
|
|||||||
+43
-125
@@ -6,9 +6,9 @@ Copyright 2011 Joel Martin
|
|||||||
Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)
|
Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)
|
||||||
|
|
||||||
Supports following protocol versions:
|
Supports following protocol versions:
|
||||||
- http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75
|
- http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07
|
||||||
- http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
|
|
||||||
- http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10
|
- http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10
|
||||||
|
- http://tools.ietf.org/html/rfc6455
|
||||||
|
|
||||||
You can make a cert/key with openssl using:
|
You can make a cert/key with openssl using:
|
||||||
openssl req -new -x509 -days 365 -nodes -out self.pem -keyout self.pem
|
openssl req -new -x509 -days 365 -nodes -out self.pem -keyout self.pem
|
||||||
@@ -37,8 +37,8 @@ try: from http.server import SimpleHTTPRequestHandler
|
|||||||
except: from SimpleHTTPServer import SimpleHTTPRequestHandler
|
except: from SimpleHTTPServer import SimpleHTTPRequestHandler
|
||||||
|
|
||||||
# python 2.6 differences
|
# python 2.6 differences
|
||||||
try: from hashlib import md5, sha1
|
try: from hashlib import sha1
|
||||||
except: from md5 import md5; from sha import sha as sha1
|
except: from sha import sha as sha1
|
||||||
|
|
||||||
# python 2.5 differences
|
# python 2.5 differences
|
||||||
try:
|
try:
|
||||||
@@ -50,15 +50,15 @@ except:
|
|||||||
return struct.unpack(fmt, slice)
|
return struct.unpack(fmt, slice)
|
||||||
|
|
||||||
# Degraded functionality if these imports are missing
|
# Degraded functionality if these imports are missing
|
||||||
for mod, sup in [('numpy', 'HyBi protocol'), ('ssl', 'TLS/SSL/wss'),
|
for mod, msg in [('numpy', 'HyBi protocol will be slower'),
|
||||||
('multiprocessing', 'Multi-Processing'),
|
('ssl', 'TLS/SSL/wss is disabled'),
|
||||||
('resource', 'daemonizing')]:
|
('multiprocessing', 'Multi-Processing is disabled'),
|
||||||
|
('resource', 'daemonizing is disabled')]:
|
||||||
try:
|
try:
|
||||||
globals()[mod] = __import__(mod)
|
globals()[mod] = __import__(mod)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
globals()[mod] = None
|
globals()[mod] = None
|
||||||
print("WARNING: no '%s' module, %s is slower or disabled" % (
|
print("WARNING: no '%s' module, %s" % (mod, msg))
|
||||||
mod, sup))
|
|
||||||
if multiprocessing and sys.platform == 'win32':
|
if multiprocessing and sys.platform == 'win32':
|
||||||
# make sockets pickle-able/inheritable
|
# make sockets pickle-able/inheritable
|
||||||
import multiprocessing.reduction
|
import multiprocessing.reduction
|
||||||
@@ -72,14 +72,6 @@ class WebSocketServer(object):
|
|||||||
|
|
||||||
buffer_size = 65536
|
buffer_size = 65536
|
||||||
|
|
||||||
|
|
||||||
server_handshake_hixie = """HTTP/1.1 101 Web Socket Protocol Handshake\r
|
|
||||||
Upgrade: WebSocket\r
|
|
||||||
Connection: Upgrade\r
|
|
||||||
%sWebSocket-Origin: %s\r
|
|
||||||
%sWebSocket-Location: %s://%s%s\r
|
|
||||||
"""
|
|
||||||
|
|
||||||
server_handshake_hybi = """HTTP/1.1 101 Switching Protocols\r
|
server_handshake_hybi = """HTTP/1.1 101 Switching Protocols\r
|
||||||
Upgrade: websocket\r
|
Upgrade: websocket\r
|
||||||
Connection: Upgrade\r
|
Connection: Upgrade\r
|
||||||
@@ -100,7 +92,7 @@ Sec-WebSocket-Accept: %s\r
|
|||||||
|
|
||||||
def __init__(self, listen_host='', listen_port=None, source_is_ipv6=False,
|
def __init__(self, listen_host='', listen_port=None, source_is_ipv6=False,
|
||||||
verbose=False, cert='', key='', ssl_only=None,
|
verbose=False, cert='', key='', ssl_only=None,
|
||||||
daemon=False, record='', web='',
|
daemon=False, record='', web='', file_only=False, no_parent=False,
|
||||||
run_once=False, timeout=0, idle_timeout=0):
|
run_once=False, timeout=0, idle_timeout=0):
|
||||||
|
|
||||||
# settings
|
# settings
|
||||||
@@ -118,6 +110,9 @@ Sec-WebSocket-Accept: %s\r
|
|||||||
self.ws_connection = False
|
self.ws_connection = False
|
||||||
self.handler_id = 1
|
self.handler_id = 1
|
||||||
|
|
||||||
|
self.file_only = file_only
|
||||||
|
self.no_parent = no_parent
|
||||||
|
|
||||||
# Make paths settings absolute
|
# Make paths settings absolute
|
||||||
self.cert = os.path.abspath(cert)
|
self.cert = os.path.abspath(cert)
|
||||||
self.key = self.web = self.record = ''
|
self.key = self.web = self.record = ''
|
||||||
@@ -381,33 +376,6 @@ Sec-WebSocket-Accept: %s\r
|
|||||||
|
|
||||||
return f
|
return f
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def encode_hixie(buf):
|
|
||||||
return s2b("\x00" + b2s(b64encode(buf)) + "\xff"), 1, 1
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def decode_hixie(buf):
|
|
||||||
end = buf.find(s2b('\xff'))
|
|
||||||
return {'payload': b64decode(buf[1:end]),
|
|
||||||
'hlen': 1,
|
|
||||||
'masked': False,
|
|
||||||
'length': end - 1,
|
|
||||||
'left': len(buf) - (end + 1)}
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def gen_md5(keys):
|
|
||||||
""" Generate hash value for WebSockets hixie-76. """
|
|
||||||
key1 = keys['Sec-WebSocket-Key1']
|
|
||||||
key2 = keys['Sec-WebSocket-Key2']
|
|
||||||
key3 = keys['key3']
|
|
||||||
spaces1 = key1.count(" ")
|
|
||||||
spaces2 = key2.count(" ")
|
|
||||||
num1 = int("".join([c for c in key1 if c.isdigit()])) / spaces1
|
|
||||||
num2 = int("".join([c for c in key2 if c.isdigit()])) / spaces2
|
|
||||||
|
|
||||||
return b2s(md5(pack('>II8s',
|
|
||||||
int(num1), int(num2), key3)).digest())
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# WebSocketServer logging/output functions
|
# WebSocketServer logging/output functions
|
||||||
@@ -444,16 +412,10 @@ Sec-WebSocket-Accept: %s\r
|
|||||||
|
|
||||||
if bufs:
|
if bufs:
|
||||||
for buf in bufs:
|
for buf in bufs:
|
||||||
if self.version.startswith("hybi"):
|
if self.base64:
|
||||||
if self.base64:
|
encbuf, lenhead, lentail = self.encode_hybi(buf, opcode=1, base64=True)
|
||||||
encbuf, lenhead, lentail = self.encode_hybi(
|
|
||||||
buf, opcode=1, base64=True)
|
|
||||||
else:
|
|
||||||
encbuf, lenhead, lentail = self.encode_hybi(
|
|
||||||
buf, opcode=2, base64=False)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
encbuf, lenhead, lentail = self.encode_hixie(buf)
|
encbuf, lenhead, lentail = self.encode_hybi(buf, opcode=2, base64=False)
|
||||||
|
|
||||||
if self.rec:
|
if self.rec:
|
||||||
self.rec.write("%s,\n" %
|
self.rec.write("%s,\n" %
|
||||||
@@ -498,41 +460,21 @@ Sec-WebSocket-Accept: %s\r
|
|||||||
self.recv_part = None
|
self.recv_part = None
|
||||||
|
|
||||||
while buf:
|
while buf:
|
||||||
if self.version.startswith("hybi"):
|
frame = self.decode_hybi(buf, base64=self.base64)
|
||||||
|
#print("Received buf: %s, frame: %s" % (repr(buf), frame))
|
||||||
frame = self.decode_hybi(buf, base64=self.base64)
|
|
||||||
#print("Received buf: %s, frame: %s" % (repr(buf), frame))
|
|
||||||
|
|
||||||
if frame['payload'] == None:
|
|
||||||
# Incomplete/partial frame
|
|
||||||
self.traffic("}.")
|
|
||||||
if frame['left'] > 0:
|
|
||||||
self.recv_part = buf[-frame['left']:]
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if frame['opcode'] == 0x8: # connection close
|
|
||||||
closed = {'code': frame['close_code'],
|
|
||||||
'reason': frame['close_reason']}
|
|
||||||
break
|
|
||||||
|
|
||||||
|
if frame['payload'] == None:
|
||||||
|
# Incomplete/partial frame
|
||||||
|
self.traffic("}.")
|
||||||
|
if frame['left'] > 0:
|
||||||
|
self.recv_part = buf[-frame['left']:]
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
if buf[0:2] == s2b('\xff\x00'):
|
if frame['opcode'] == 0x8: # connection close
|
||||||
closed = {'code': 1000,
|
closed = {'code': frame['close_code'],
|
||||||
'reason': "Client sent orderly close frame"}
|
'reason': frame['close_reason']}
|
||||||
break
|
break
|
||||||
|
|
||||||
elif buf[0:2] == s2b('\x00\xff'):
|
|
||||||
buf = buf[2:]
|
|
||||||
continue # No-op
|
|
||||||
|
|
||||||
elif buf.count(s2b('\xff')) == 0:
|
|
||||||
# Partial frame
|
|
||||||
self.traffic("}.")
|
|
||||||
self.recv_part = buf
|
|
||||||
break
|
|
||||||
|
|
||||||
frame = self.decode_hixie(buf)
|
|
||||||
|
|
||||||
self.traffic("}")
|
self.traffic("}")
|
||||||
|
|
||||||
if self.rec:
|
if self.rec:
|
||||||
@@ -560,17 +502,9 @@ Sec-WebSocket-Accept: %s\r
|
|||||||
def send_close(self, code=1000, reason=''):
|
def send_close(self, code=1000, reason=''):
|
||||||
""" Send a WebSocket orderly close frame. """
|
""" Send a WebSocket orderly close frame. """
|
||||||
|
|
||||||
if self.version.startswith("hybi"):
|
msg = pack(">H%ds" % len(reason), code, reason)
|
||||||
msg = pack(">H%ds" % len(reason), code, reason)
|
buf, h, t = self.encode_hybi(msg, opcode=0x08, base64=False)
|
||||||
|
self.client.send(buf)
|
||||||
buf, h, t = self.encode_hybi(msg, opcode=0x08, base64=False)
|
|
||||||
self.client.send(buf)
|
|
||||||
|
|
||||||
elif self.version == "hixie-76":
|
|
||||||
buf = s2b('\xff\x00')
|
|
||||||
self.client.send(buf)
|
|
||||||
|
|
||||||
# No orderly close for 75
|
|
||||||
|
|
||||||
def do_websocket_handshake(self, headers, path):
|
def do_websocket_handshake(self, headers, path):
|
||||||
h = self.headers = headers
|
h = self.headers = headers
|
||||||
@@ -612,28 +546,7 @@ Sec-WebSocket-Accept: %s\r
|
|||||||
response += "\r\n"
|
response += "\r\n"
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Hixie version of the protocol (75 or 76)
|
raise self.EClose("Missing Sec-WebSocket-Version header. Hixie protocols not supported.")
|
||||||
|
|
||||||
if h.get('key3'):
|
|
||||||
trailer = self.gen_md5(h)
|
|
||||||
pre = "Sec-"
|
|
||||||
self.version = "hixie-76"
|
|
||||||
else:
|
|
||||||
trailer = ""
|
|
||||||
pre = ""
|
|
||||||
self.version = "hixie-75"
|
|
||||||
|
|
||||||
# We only support base64 in Hixie era
|
|
||||||
self.base64 = True
|
|
||||||
|
|
||||||
response = self.server_handshake_hixie % (pre,
|
|
||||||
h['Origin'], pre, self.scheme, h['Host'], path)
|
|
||||||
|
|
||||||
if 'base64' in protocols:
|
|
||||||
response += "%sWebSocket-Protocol: base64\r\n" % pre
|
|
||||||
else:
|
|
||||||
self.msg("Warning: client does not report 'base64' protocol support")
|
|
||||||
response += "\r\n" + trailer
|
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@@ -710,7 +623,8 @@ Sec-WebSocket-Accept: %s\r
|
|||||||
self.scheme = "ws"
|
self.scheme = "ws"
|
||||||
stype = "Plain non-SSL (ws://)"
|
stype = "Plain non-SSL (ws://)"
|
||||||
|
|
||||||
wsh = WSRequestHandler(retsock, address, not self.web)
|
wsh = WSRequestHandler(retsock, address, not self.web,
|
||||||
|
self.file_only, self.no_parent)
|
||||||
if wsh.last_code == 101:
|
if wsh.last_code == 101:
|
||||||
# Continue on to handle WebSocket upgrade
|
# Continue on to handle WebSocket upgrade
|
||||||
pass
|
pass
|
||||||
@@ -949,19 +863,19 @@ Sec-WebSocket-Accept: %s\r
|
|||||||
|
|
||||||
# HTTP handler with WebSocket upgrade support
|
# HTTP handler with WebSocket upgrade support
|
||||||
class WSRequestHandler(SimpleHTTPRequestHandler):
|
class WSRequestHandler(SimpleHTTPRequestHandler):
|
||||||
def __init__(self, req, addr, only_upgrade=False):
|
def __init__(self, req, addr, only_upgrade=False, file_only=False,
|
||||||
|
no_parent=False):
|
||||||
self.only_upgrade = only_upgrade # only allow upgrades
|
self.only_upgrade = only_upgrade # only allow upgrades
|
||||||
|
self.webroot = os.path.realpath(".")
|
||||||
|
self.file_only = file_only
|
||||||
|
self.no_parent = no_parent
|
||||||
SimpleHTTPRequestHandler.__init__(self, req, addr, object())
|
SimpleHTTPRequestHandler.__init__(self, req, addr, object())
|
||||||
|
|
||||||
def do_GET(self):
|
def do_GET(self):
|
||||||
|
abspath = os.path.realpath("." + (self.path.split('?')[0]))
|
||||||
if (self.headers.get('upgrade') and
|
if (self.headers.get('upgrade') and
|
||||||
self.headers.get('upgrade').lower() == 'websocket'):
|
self.headers.get('upgrade').lower() == 'websocket'):
|
||||||
|
|
||||||
if (self.headers.get('sec-websocket-key1') or
|
|
||||||
self.headers.get('websocket-key1')):
|
|
||||||
# For Hixie-76 read out the key hash
|
|
||||||
self.headers.__setitem__('key3', self.rfile.read(8))
|
|
||||||
|
|
||||||
# Just indicate that an WebSocket upgrade is needed
|
# Just indicate that an WebSocket upgrade is needed
|
||||||
self.last_code = 101
|
self.last_code = 101
|
||||||
self.last_message = "101 Switching Protocols"
|
self.last_message = "101 Switching Protocols"
|
||||||
@@ -969,6 +883,10 @@ class WSRequestHandler(SimpleHTTPRequestHandler):
|
|||||||
# Normal web request responses are disabled
|
# Normal web request responses are disabled
|
||||||
self.last_code = 405
|
self.last_code = 405
|
||||||
self.last_message = "405 Method Not Allowed"
|
self.last_message = "405 Method Not Allowed"
|
||||||
|
elif self.file_only and not os.path.isfile(abspath):
|
||||||
|
self.send_response(404, "No such file")
|
||||||
|
elif self.no_parent and not abspath.startswith(self.webroot):
|
||||||
|
self.send_response(403, "Hidden resources")
|
||||||
else:
|
else:
|
||||||
SimpleHTTPRequestHandler.do_GET(self)
|
SimpleHTTPRequestHandler.do_GET(self)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user