Use detection rather than python version checking.

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.
This commit is contained in:
Joel Martin 2011-10-06 09:37:09 -05:00
parent 1658649d0c
commit eac2c9fadd
1 changed files with 40 additions and 45 deletions

View File

@ -17,60 +17,54 @@ as taken from http://docs.python.org/dev/library/ssl.html#certificates
'''
import os, sys, time, errno, signal, socket, traceback, select
import array
import array, struct
from cgi import parse_qsl
from base64 import b64encode, b64decode
# Imports that vary by python version
# python 3.0 differences
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')
s2b = lambda s: s.encode('latin_1')
s2a = lambda s: s
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]
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
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
# python 2.6 differences
try: from hashlib import md5, sha1
except: from md5 import md5; from sha import sha as sha1
if sys.hexversion >= 0x2050000:
# python >= 2.5
import struct
else:
# python < 2.5
import struct
# unpack_from was introduced in python 2.5
def _unpack_from(fmt, buf, offset=0):
# 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)
struct.unpack_from = _unpack_from
# 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:
globals()[mod] = __import__(mod)
except ImportError:
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))
if multiprocessing and sys.platform == 'win32':
# make sockets pickle-able/inheritable
import multiprocessing.reduction
class WebSocketServer(object):
@ -277,11 +271,11 @@ Sec-WebSocket-Accept: %s\r
b1 = 0x80 | (opcode & 0x0f) # FIN + opcode
payload_len = len(buf)
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:
header = struct.pack('>BBH', b1, 126, payload_len)
header = pack('>BBH', b1, 126, payload_len)
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))
@ -318,7 +312,7 @@ Sec-WebSocket-Accept: %s\r
if blen < f['hlen']:
return f # Incomplete frame header
b1, b2 = struct.unpack_from(">BB", buf)
b1, b2 = unpack_from(">BB", buf)
f['opcode'] = b1 & 0x0f
f['fin'] = (b1 & 0x80) >> 7
has_mask = (b2 & 0x80) >> 7
@ -329,12 +323,12 @@ Sec-WebSocket-Accept: %s\r
f['hlen'] = 4
if blen < f['hlen']:
return f # Incomplete frame header
(f['length'],) = struct.unpack_from('>xxH', buf)
(f['length'],) = unpack_from('>xxH', buf)
elif f['length'] == 127:
f['hlen'] = 10
if blen < f['hlen']:
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']
@ -363,7 +357,7 @@ Sec-WebSocket-Accept: %s\r
if f['opcode'] == 0x08:
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:
f['close_reason'] = f['payload'][2:]
@ -393,7 +387,7 @@ Sec-WebSocket-Accept: %s\r
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(struct.pack('>II8s',
return b2s(md5(pack('>II8s',
int(num1), int(num2), key3)).digest())
#
@ -544,7 +538,7 @@ Sec-WebSocket-Accept: %s\r
if self.version.startswith("hybi"):
msg = s2b('')
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)
self.client.send(buf)
@ -803,7 +797,7 @@ Sec-WebSocket-Accept: %s\r
# Allow override of SIGINT
signal.signal(signal.SIGINT, self.do_SIGINT)
if not Process:
if not multiprocessing:
# os.fork() (python 2.4) child reaper
signal.signal(signal.SIGCHLD, self.fallback_SIGCHLD)
@ -849,9 +843,10 @@ Sec-WebSocket-Accept: %s\r
self.msg('%s: exiting due to --run-once'
% address[0])
break
elif Process:
elif multiprocessing:
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))
p.start()
# child will not return