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
|
||||
=======
|
||||
|
||||
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
|
||||
--------------------
|
||||
|
||||
|
||||
+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
|
||||
|
||||
Websockify 0.4.X supports all versions of the WebSockets protocol
|
||||
(Hixie and HyBi). Starting with websockify 0.5.0, only the HyBi / IETF
|
||||
Starting with websockify 0.5.0, only the HyBi / IETF
|
||||
6455 WebSocket protocol is supported.
|
||||
|
||||
The older Hixie versions of the protocol only support UTF-8 text
|
||||
payloads. In order to transport binary data over UTF-8 an encoding
|
||||
must used to encapsulate the data within UTF-8. With Hixie clients,
|
||||
Websockify uses base64 to encode all traffic to and from the client.
|
||||
This does not affect the data between websockify and the server.
|
||||
|
||||
With HyBi clients, websockify negotiates whether to base64 encode
|
||||
traffic to and from the client via the subprotocol header
|
||||
(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.
|
||||
Websockify negotiates whether to base64 encode traffic to and from the
|
||||
client via the subprotocol header (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://)
|
||||
|
||||
+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
|
||||
WVER=0.1.0
|
||||
git tag v${WVER}
|
||||
@@ -8,3 +8,6 @@
|
||||
python setup.py register
|
||||
- Upload the source distribution to pypi
|
||||
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
|
||||
// Requires node modules: ws, optimist and 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,
|
||||
@@ -37,6 +29,7 @@ var argv = require('optimist').argv,
|
||||
// Handle new WebSocket client
|
||||
new_client = function(client) {
|
||||
var clientAddr = client._socket.remoteAddress, log;
|
||||
console.log(client.upgradeReq.url);
|
||||
log = function (msg) {
|
||||
console.log(' ' + clientAddr + ': '+ msg);
|
||||
};
|
||||
@@ -61,6 +54,12 @@ new_client = function(client) {
|
||||
});
|
||||
target.on('end', function() {
|
||||
log('target disconnected');
|
||||
client.close();
|
||||
});
|
||||
target.on('error', function() {
|
||||
log('target connection error');
|
||||
target.end();
|
||||
client.close();
|
||||
});
|
||||
|
||||
client.on('message', function(msg) {
|
||||
@@ -126,11 +125,9 @@ http_request = function (request, response) {
|
||||
|
||||
// Select 'binary' or 'base64' subprotocol, preferring 'binary'
|
||||
selectProtocol = function(protocols, callback) {
|
||||
var plist = protocols ? protocols.split(',') : "";
|
||||
var plist = protocols.split(',');
|
||||
if (plist.indexOf('binary') >= 0) {
|
||||
if (protocols.indexOf('binary') >= 0) {
|
||||
callback(true, 'binary');
|
||||
} else if (plist.indexOf('base64') >= 0) {
|
||||
} else if (protocols.indexOf('base64') >= 0) {
|
||||
callback(true, 'base64');
|
||||
} else {
|
||||
console.log("Client must support 'binary' or 'base64' protocol");
|
||||
+14
-4
@@ -16,6 +16,8 @@ usage() {
|
||||
echo " Default: localhost:5900"
|
||||
echo " --cert CERT Path to combined cert/key file"
|
||||
echo " Default: self.pem"
|
||||
echo " --web WEB Path to web files (e.g. vnc.html)"
|
||||
echo " Default: ./"
|
||||
exit 2
|
||||
}
|
||||
|
||||
@@ -24,6 +26,7 @@ HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
PORT="6080"
|
||||
VNC_DEST="localhost:5900"
|
||||
CERT=""
|
||||
WEB=""
|
||||
proxy_pid=""
|
||||
|
||||
die() {
|
||||
@@ -50,6 +53,7 @@ while [ "$*" ]; do
|
||||
--listen) PORT="${OPTARG}"; shift ;;
|
||||
--vnc) VNC_DEST="${OPTARG}"; shift ;;
|
||||
--cert) CERT="${OPTARG}"; shift ;;
|
||||
--web) WEB="${OPTARG}"; shift ;;
|
||||
-h|--help) usage ;;
|
||||
-*) usage "Unknown chrooter option: ${param}" ;;
|
||||
*) break ;;
|
||||
@@ -60,18 +64,24 @@ done
|
||||
which netstat >/dev/null 2>&1 \
|
||||
|| 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"
|
||||
|
||||
trap "cleanup" TERM QUIT INT EXIT
|
||||
|
||||
# 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)
|
||||
elif [ -e "${HERE}/../vnc.html" ]; then
|
||||
WEB=${HERE}/../
|
||||
elif [ -e "${HERE}/vnc.html" ]; then
|
||||
WEB=${HERE}
|
||||
elif [ -e "${HERE}/../share/novnc/vnc.html" ]; then
|
||||
WEB=${HERE}/../share/novnc/
|
||||
else
|
||||
die "Could not find vnc.html"
|
||||
fi
|
||||
@@ -92,7 +102,7 @@ else
|
||||
fi
|
||||
|
||||
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="$!"
|
||||
sleep 1
|
||||
if ! ps -p ${proxy_pid} >/dev/null; then
|
||||
@@ -101,7 +111,7 @@ if ! ps -p ${proxy_pid} >/dev/null; then
|
||||
exit 1
|
||||
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 "Press Ctrl-C to exit\n\n"
|
||||
|
||||
|
||||
+1
-1
@@ -795,7 +795,7 @@ void start_server() {
|
||||
}
|
||||
handler_msg("handler exit\n");
|
||||
} 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
|
||||
* port (of localhost) instead of the old port.
|
||||
*
|
||||
* This allows a proxy (such as wsproxy) to run on the old port and translate
|
||||
* traffic to/from the new port.
|
||||
* This allows a bridge/proxy (such as websockify) to run on the old port and
|
||||
* translate traffic to/from the new port.
|
||||
*
|
||||
* Usage:
|
||||
* LD_PRELOAD=./rebind.so \
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
version = '0.4.1'
|
||||
version = '0.5.1'
|
||||
name = 'websockify'
|
||||
long_description = open("README.md").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
|
||||
sys.path.insert(0,os.path.dirname(__file__) + "/../")
|
||||
sys.path.insert(0,os.path.dirname(__file__) + "/../websockify")
|
||||
from websocket import 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
|
||||
sys.path.insert(0,os.path.dirname(__file__) + "/../")
|
||||
sys.path.insert(0,os.path.dirname(__file__) + "/../websockify")
|
||||
from websocket import WebSocketServer
|
||||
|
||||
class WebSocketLoad(WebSocketServer):
|
||||
|
||||
+3
-5
@@ -6,17 +6,15 @@ Display UTF-8 encoding for 0-255.'''
|
||||
import sys, os, socket, ssl, time, traceback
|
||||
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
|
||||
|
||||
if __name__ == '__main__':
|
||||
print "val: hixie | hybi_base64 | hybi_binary"
|
||||
print "val: hybi_base64 | hybi_binary"
|
||||
for c in range(0, 256):
|
||||
hixie = WebSocketServer.encode_hixie(chr(c))
|
||||
hybi_base64 = WebSocketServer.encode_hybi(chr(c), opcode=1,
|
||||
base64=True)
|
||||
hybi_binary = WebSocketServer.encode_hybi(chr(c), opcode=2,
|
||||
base64=False)
|
||||
print "%d: %s | %s | %s" % (c, repr(hixie), repr(hybi_base64),
|
||||
repr(hybi_binary))
|
||||
print "%d: %s | %s" % (c, repr(hybi_base64), repr(hybi_binary))
|
||||
|
||||
|
||||
+43
-125
@@ -6,9 +6,9 @@ Copyright 2011 Joel Martin
|
||||
Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)
|
||||
|
||||
Supports following protocol versions:
|
||||
- http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75
|
||||
- http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
|
||||
- http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07
|
||||
- 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:
|
||||
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
|
||||
|
||||
# python 2.6 differences
|
||||
try: from hashlib import md5, sha1
|
||||
except: from md5 import md5; from sha import sha as sha1
|
||||
try: from hashlib import sha1
|
||||
except: from sha import sha as sha1
|
||||
|
||||
# python 2.5 differences
|
||||
try:
|
||||
@@ -50,15 +50,15 @@ except:
|
||||
return struct.unpack(fmt, slice)
|
||||
|
||||
# Degraded functionality if these imports are missing
|
||||
for mod, sup in [('numpy', 'HyBi protocol'), ('ssl', 'TLS/SSL/wss'),
|
||||
('multiprocessing', 'Multi-Processing'),
|
||||
('resource', 'daemonizing')]:
|
||||
for mod, msg in [('numpy', 'HyBi protocol will be slower'),
|
||||
('ssl', 'TLS/SSL/wss is disabled'),
|
||||
('multiprocessing', 'Multi-Processing is disabled'),
|
||||
('resource', 'daemonizing is disabled')]:
|
||||
try:
|
||||
globals()[mod] = __import__(mod)
|
||||
except ImportError:
|
||||
globals()[mod] = None
|
||||
print("WARNING: no '%s' module, %s is slower or disabled" % (
|
||||
mod, sup))
|
||||
print("WARNING: no '%s' module, %s" % (mod, msg))
|
||||
if multiprocessing and sys.platform == 'win32':
|
||||
# make sockets pickle-able/inheritable
|
||||
import multiprocessing.reduction
|
||||
@@ -72,14 +72,6 @@ class WebSocketServer(object):
|
||||
|
||||
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
|
||||
Upgrade: websocket\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,
|
||||
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):
|
||||
|
||||
# settings
|
||||
@@ -118,6 +110,9 @@ Sec-WebSocket-Accept: %s\r
|
||||
self.ws_connection = False
|
||||
self.handler_id = 1
|
||||
|
||||
self.file_only = file_only
|
||||
self.no_parent = no_parent
|
||||
|
||||
# Make paths settings absolute
|
||||
self.cert = os.path.abspath(cert)
|
||||
self.key = self.web = self.record = ''
|
||||
@@ -381,33 +376,6 @@ Sec-WebSocket-Accept: %s\r
|
||||
|
||||
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
|
||||
@@ -444,16 +412,10 @@ Sec-WebSocket-Accept: %s\r
|
||||
|
||||
if bufs:
|
||||
for buf in bufs:
|
||||
if self.version.startswith("hybi"):
|
||||
if self.base64:
|
||||
encbuf, lenhead, lentail = self.encode_hybi(
|
||||
buf, opcode=1, base64=True)
|
||||
else:
|
||||
encbuf, lenhead, lentail = self.encode_hybi(
|
||||
buf, opcode=2, base64=False)
|
||||
|
||||
if self.base64:
|
||||
encbuf, lenhead, lentail = self.encode_hybi(buf, opcode=1, base64=True)
|
||||
else:
|
||||
encbuf, lenhead, lentail = self.encode_hixie(buf)
|
||||
encbuf, lenhead, lentail = self.encode_hybi(buf, opcode=2, base64=False)
|
||||
|
||||
if self.rec:
|
||||
self.rec.write("%s,\n" %
|
||||
@@ -498,41 +460,21 @@ Sec-WebSocket-Accept: %s\r
|
||||
self.recv_part = None
|
||||
|
||||
while buf:
|
||||
if self.version.startswith("hybi"):
|
||||
|
||||
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
|
||||
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 buf[0:2] == s2b('\xff\x00'):
|
||||
closed = {'code': 1000,
|
||||
'reason': "Client sent orderly close frame"}
|
||||
if frame['opcode'] == 0x8: # connection close
|
||||
closed = {'code': frame['close_code'],
|
||||
'reason': frame['close_reason']}
|
||||
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("}")
|
||||
|
||||
if self.rec:
|
||||
@@ -560,17 +502,9 @@ Sec-WebSocket-Accept: %s\r
|
||||
def send_close(self, code=1000, reason=''):
|
||||
""" Send a WebSocket orderly close frame. """
|
||||
|
||||
if self.version.startswith("hybi"):
|
||||
msg = pack(">H%ds" % len(reason), code, reason)
|
||||
|
||||
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
|
||||
msg = pack(">H%ds" % len(reason), code, reason)
|
||||
buf, h, t = self.encode_hybi(msg, opcode=0x08, base64=False)
|
||||
self.client.send(buf)
|
||||
|
||||
def do_websocket_handshake(self, headers, path):
|
||||
h = self.headers = headers
|
||||
@@ -612,28 +546,7 @@ Sec-WebSocket-Accept: %s\r
|
||||
response += "\r\n"
|
||||
|
||||
else:
|
||||
# Hixie version of the protocol (75 or 76)
|
||||
|
||||
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
|
||||
raise self.EClose("Missing Sec-WebSocket-Version header. Hixie protocols not supported.")
|
||||
|
||||
return response
|
||||
|
||||
@@ -710,7 +623,8 @@ Sec-WebSocket-Accept: %s\r
|
||||
self.scheme = "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:
|
||||
# Continue on to handle WebSocket upgrade
|
||||
pass
|
||||
@@ -949,19 +863,19 @@ Sec-WebSocket-Accept: %s\r
|
||||
|
||||
# HTTP handler with WebSocket upgrade support
|
||||
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.webroot = os.path.realpath(".")
|
||||
self.file_only = file_only
|
||||
self.no_parent = no_parent
|
||||
SimpleHTTPRequestHandler.__init__(self, req, addr, object())
|
||||
|
||||
def do_GET(self):
|
||||
abspath = os.path.realpath("." + (self.path.split('?')[0]))
|
||||
if (self.headers.get('upgrade') and
|
||||
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
|
||||
self.last_code = 101
|
||||
self.last_message = "101 Switching Protocols"
|
||||
@@ -969,6 +883,10 @@ class WSRequestHandler(SimpleHTTPRequestHandler):
|
||||
# Normal web request responses are disabled
|
||||
self.last_code = 405
|
||||
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:
|
||||
SimpleHTTPRequestHandler.do_GET(self)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user