|
@@ -17,48 +17,54 @@ as taken from http://docs.python.org/dev/library/ssl.html#certificates
|
|
'''
|
|
'''
|
|
|
|
|
|
import os, sys, time, errno, signal, socket, traceback, select
|
|
import os, sys, time, errno, signal, socket, traceback, select
|
|
-import struct, array
|
|
|
|
|
|
+import array, struct
|
|
from cgi import parse_qsl
|
|
from cgi import parse_qsl
|
|
from base64 import b64encode, b64decode
|
|
from base64 import b64encode, b64decode
|
|
|
|
|
|
# Imports that vary by python version
|
|
# Imports that vary by python version
|
|
|
|
+
|
|
|
|
+# python 3.0 differences
|
|
if sys.hexversion > 0x3000000:
|
|
if sys.hexversion > 0x3000000:
|
|
- # python >= 3.0
|
|
|
|
- from io import StringIO
|
|
|
|
- from http.server import SimpleHTTPRequestHandler
|
|
|
|
- from urllib.parse import urlsplit
|
|
|
|
b2s = lambda buf: buf.decode('latin_1')
|
|
b2s = lambda buf: buf.decode('latin_1')
|
|
s2b = lambda s: s.encode('latin_1')
|
|
s2b = lambda s: s.encode('latin_1')
|
|
s2a = lambda s: s
|
|
s2a = lambda s: s
|
|
else:
|
|
else:
|
|
- # python 2.X
|
|
|
|
- from cStringIO import StringIO
|
|
|
|
- from SimpleHTTPServer import SimpleHTTPRequestHandler
|
|
|
|
- from urlparse import urlsplit
|
|
|
|
- # No-ops
|
|
|
|
- b2s = lambda buf: buf
|
|
|
|
- s2b = lambda s: s
|
|
|
|
|
|
+ b2s = lambda buf: buf # No-op
|
|
|
|
+ s2b = lambda s: s # No-op
|
|
s2a = lambda s: [ord(c) for c in s]
|
|
s2a = lambda s: [ord(c) for c in s]
|
|
-
|
|
|
|
-if sys.hexversion >= 0x2060000:
|
|
|
|
- # python >= 2.6
|
|
|
|
- from multiprocessing import Process
|
|
|
|
- from hashlib import md5, sha1
|
|
|
|
-else:
|
|
|
|
- # python < 2.6
|
|
|
|
- Process = None
|
|
|
|
- from md5 import md5
|
|
|
|
- from sha import sha as sha1
|
|
|
|
|
|
+try: from io import StringIO
|
|
|
|
+except: from cStringIO import StringIO
|
|
|
|
+try: from http.server import SimpleHTTPRequestHandler
|
|
|
|
+except: from SimpleHTTPServer import SimpleHTTPRequestHandler
|
|
|
|
+try: from urllib.parse import urlsplit
|
|
|
|
+except: from urlparse import urlsplit
|
|
|
|
+
|
|
|
|
+# python 2.6 differences
|
|
|
|
+try: from hashlib import md5, sha1
|
|
|
|
+except: from md5 import md5; from sha import sha as sha1
|
|
|
|
+
|
|
|
|
+# python 2.5 differences
|
|
|
|
+try:
|
|
|
|
+ from struct import pack, unpack_from
|
|
|
|
+except:
|
|
|
|
+ from struct import pack
|
|
|
|
+ def unpack_from(fmt, buf, offset=0):
|
|
|
|
+ slice = buffer(buf, offset, struct.calcsize(fmt))
|
|
|
|
+ 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'), ('resource', 'daemonizing')]:
|
|
|
|
|
|
+for mod, sup in [('numpy', 'HyBi protocol'), ('ssl', 'TLS/SSL/wss'),
|
|
|
|
+ ('multiprocessing', 'Multi-Processing'),
|
|
|
|
+ ('resource', 'daemonizing')]:
|
|
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 decode may be slower" % (
|
|
|
|
|
|
+ print("WARNING: no '%s' module, %s is slower or disabled" % (
|
|
mod, sup))
|
|
mod, sup))
|
|
|
|
+if multiprocessing and sys.platform == 'win32':
|
|
|
|
+ # make sockets pickle-able/inheritable
|
|
|
|
+ import multiprocessing.reduction
|
|
|
|
|
|
|
|
|
|
class WebSocketServer(object):
|
|
class WebSocketServer(object):
|
|
@@ -265,11 +271,11 @@ Sec-WebSocket-Accept: %s\r
|
|
b1 = 0x80 | (opcode & 0x0f) # FIN + opcode
|
|
b1 = 0x80 | (opcode & 0x0f) # FIN + opcode
|
|
payload_len = len(buf)
|
|
payload_len = len(buf)
|
|
if payload_len <= 125:
|
|
if payload_len <= 125:
|
|
- header = struct.pack('>BB', b1, payload_len)
|
|
|
|
|
|
+ header = pack('>BB', b1, payload_len)
|
|
elif payload_len > 125 and payload_len < 65536:
|
|
elif payload_len > 125 and payload_len < 65536:
|
|
- header = struct.pack('>BBH', b1, 126, payload_len)
|
|
|
|
|
|
+ header = pack('>BBH', b1, 126, payload_len)
|
|
elif payload_len >= 65536:
|
|
elif payload_len >= 65536:
|
|
- header = struct.pack('>BBQ', b1, 127, payload_len)
|
|
|
|
|
|
+ header = pack('>BBQ', b1, 127, payload_len)
|
|
|
|
|
|
#print("Encoded: %s" % repr(header + buf))
|
|
#print("Encoded: %s" % repr(header + buf))
|
|
|
|
|
|
@@ -306,7 +312,7 @@ Sec-WebSocket-Accept: %s\r
|
|
if blen < f['hlen']:
|
|
if blen < f['hlen']:
|
|
return f # Incomplete frame header
|
|
return f # Incomplete frame header
|
|
|
|
|
|
- b1, b2 = struct.unpack_from(">BB", buf)
|
|
|
|
|
|
+ b1, b2 = unpack_from(">BB", buf)
|
|
f['opcode'] = b1 & 0x0f
|
|
f['opcode'] = b1 & 0x0f
|
|
f['fin'] = (b1 & 0x80) >> 7
|
|
f['fin'] = (b1 & 0x80) >> 7
|
|
has_mask = (b2 & 0x80) >> 7
|
|
has_mask = (b2 & 0x80) >> 7
|
|
@@ -317,12 +323,12 @@ Sec-WebSocket-Accept: %s\r
|
|
f['hlen'] = 4
|
|
f['hlen'] = 4
|
|
if blen < f['hlen']:
|
|
if blen < f['hlen']:
|
|
return f # Incomplete frame header
|
|
return f # Incomplete frame header
|
|
- (f['length'],) = struct.unpack_from('>xxH', buf)
|
|
|
|
|
|
+ (f['length'],) = unpack_from('>xxH', buf)
|
|
elif f['length'] == 127:
|
|
elif f['length'] == 127:
|
|
f['hlen'] = 10
|
|
f['hlen'] = 10
|
|
if blen < f['hlen']:
|
|
if blen < f['hlen']:
|
|
return f # Incomplete frame header
|
|
return f # Incomplete frame header
|
|
- (f['length'],) = struct.unpack_from('>xxQ', buf)
|
|
|
|
|
|
+ (f['length'],) = unpack_from('>xxQ', buf)
|
|
|
|
|
|
full_len = f['hlen'] + has_mask * 4 + f['length']
|
|
full_len = f['hlen'] + has_mask * 4 + f['length']
|
|
|
|
|
|
@@ -351,7 +357,7 @@ Sec-WebSocket-Accept: %s\r
|
|
|
|
|
|
if f['opcode'] == 0x08:
|
|
if f['opcode'] == 0x08:
|
|
if f['length'] >= 2:
|
|
if f['length'] >= 2:
|
|
- f['close_code'] = struct.unpack_from(">H", f['payload'])
|
|
|
|
|
|
+ f['close_code'] = unpack_from(">H", f['payload'])
|
|
if f['length'] > 3:
|
|
if f['length'] > 3:
|
|
f['close_reason'] = f['payload'][2:]
|
|
f['close_reason'] = f['payload'][2:]
|
|
|
|
|
|
@@ -381,7 +387,7 @@ Sec-WebSocket-Accept: %s\r
|
|
num1 = int("".join([c for c in key1 if c.isdigit()])) / spaces1
|
|
num1 = int("".join([c for c in key1 if c.isdigit()])) / spaces1
|
|
num2 = int("".join([c for c in key2 if c.isdigit()])) / spaces2
|
|
num2 = int("".join([c for c in key2 if c.isdigit()])) / spaces2
|
|
|
|
|
|
- return b2s(md5(struct.pack('>II8s',
|
|
|
|
|
|
+ return b2s(md5(pack('>II8s',
|
|
int(num1), int(num2), key3)).digest())
|
|
int(num1), int(num2), key3)).digest())
|
|
|
|
|
|
#
|
|
#
|
|
@@ -532,7 +538,7 @@ Sec-WebSocket-Accept: %s\r
|
|
if self.version.startswith("hybi"):
|
|
if self.version.startswith("hybi"):
|
|
msg = s2b('')
|
|
msg = s2b('')
|
|
if code != None:
|
|
if code != None:
|
|
- msg = struct.pack(">H%ds" % (len(reason)), code)
|
|
|
|
|
|
+ msg = pack(">H%ds" % (len(reason)), code)
|
|
|
|
|
|
buf, h, t = self.encode_hybi(msg, opcode=0x08, base64=False)
|
|
buf, h, t = self.encode_hybi(msg, opcode=0x08, base64=False)
|
|
self.client.send(buf)
|
|
self.client.send(buf)
|
|
@@ -791,7 +797,7 @@ Sec-WebSocket-Accept: %s\r
|
|
|
|
|
|
# Allow override of SIGINT
|
|
# Allow override of SIGINT
|
|
signal.signal(signal.SIGINT, self.do_SIGINT)
|
|
signal.signal(signal.SIGINT, self.do_SIGINT)
|
|
- if not Process:
|
|
|
|
|
|
+ if not multiprocessing:
|
|
# os.fork() (python 2.4) child reaper
|
|
# os.fork() (python 2.4) child reaper
|
|
signal.signal(signal.SIGCHLD, self.fallback_SIGCHLD)
|
|
signal.signal(signal.SIGCHLD, self.fallback_SIGCHLD)
|
|
|
|
|
|
@@ -837,9 +843,10 @@ Sec-WebSocket-Accept: %s\r
|
|
self.msg('%s: exiting due to --run-once'
|
|
self.msg('%s: exiting due to --run-once'
|
|
% address[0])
|
|
% address[0])
|
|
break
|
|
break
|
|
- elif Process:
|
|
|
|
|
|
+ elif multiprocessing:
|
|
self.vmsg('%s: new handler Process' % address[0])
|
|
self.vmsg('%s: new handler Process' % address[0])
|
|
- p = Process(target=self.top_new_client,
|
|
|
|
|
|
+ p = multiprocessing.Process(
|
|
|
|
+ target=self.top_new_client,
|
|
args=(startsock, address))
|
|
args=(startsock, address))
|
|
p.start()
|
|
p.start()
|
|
# child will not return
|
|
# child will not return
|