From eac2c9fadd72b5fd36c88f3e6021e878c4ffdab9 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Thu, 6 Oct 2011 09:37:09 -0500 Subject: [PATCH] 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. --- websocket.py | 85 +++++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 45 deletions(-) diff --git a/websocket.py b/websocket.py index 106e564..2b3bacc 100644 --- a/websocket.py +++ b/websocket.py @@ -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