HyBi fallback when no numpy. Python 3 close fix.

- Use array module for unmasking HyBi when no numpy module is
  available.

- Detect client close properly when using python 3.

- Print request URL path is specified.
This commit is contained in:
Joel Martin 2011-09-29 16:08:28 -05:00
parent 0f8b7580c6
commit 724aa3aca0
1 changed files with 43 additions and 25 deletions

View File

@ -16,7 +16,8 @@ as taken from http://docs.python.org/dev/library/ssl.html#certificates
'''
import os, sys, time, errno, signal, socket, struct, traceback, select
import os, sys, time, errno, signal, socket, traceback, select
import struct, array
from cgi import parse_qsl
from base64 import b64encode, b64decode
@ -28,6 +29,7 @@ if sys.hexversion > 0x3000000:
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
@ -36,6 +38,7 @@ else:
# No-ops
b2s = lambda buf: buf
s2b = lambda s: s
s2a = lambda s: [ord(c) for c in s]
if sys.hexversion >= 0x2060000:
# python >= 2.6
@ -54,7 +57,7 @@ for mod, sup in [('numpy', 'HyBi protocol'),
globals()[mod] = __import__(mod)
except ImportError:
globals()[mod] = None
print("WARNING: no '%s' module, %s support disabled" % (
print("WARNING: no '%s' module, %s decode may be slower" % (
mod, sup))
@ -213,6 +216,38 @@ Sec-WebSocket-Accept: %s\r
os.dup2(os.open(os.devnull, os.O_RDWR), sys.stdout.fileno())
os.dup2(os.open(os.devnull, os.O_RDWR), sys.stderr.fileno())
@staticmethod
def unmask(buf, f):
pstart = f['hlen'] + 4
pend = pstart + f['length']
if numpy:
b = c = s2b('')
if f['length'] >= 4:
mask = numpy.frombuffer(buf, dtype=numpy.dtype('<u4'),
offset=f['hlen'], count=1)
data = numpy.frombuffer(buf, dtype=numpy.dtype('<u4'),
offset=pstart, count=int(f['length'] / 4))
#b = numpy.bitwise_xor(data, mask).data
b = numpy.bitwise_xor(data, mask).tostring()
if f['length'] % 4:
#print("Partial unmask")
mask = numpy.frombuffer(buf, dtype=numpy.dtype('B'),
offset=f['hlen'], count=(f['length'] % 4))
data = numpy.frombuffer(buf, dtype=numpy.dtype('B'),
offset=pend - (f['length'] % 4),
count=(f['length'] % 4))
c = numpy.bitwise_xor(data, mask).tostring()
return b + c
else:
# Slower fallback
data = array.array('B')
mask = s2a(f['mask'])
data.fromstring(buf[pstart:pend])
for i in range(len(data)):
data[i] ^= mask[i % 4]
return data.tostring()
@staticmethod
def encode_hybi(buf, opcode, base64=False):
""" Encode a HyBi style WebSocket frame.
@ -301,24 +336,7 @@ Sec-WebSocket-Accept: %s\r
if has_mask:
# unmask payload
f['mask'] = buf[f['hlen']:f['hlen']+4]
b = c = s2b('')
if f['length'] >= 4:
mask = numpy.frombuffer(buf, dtype=numpy.dtype('<u4'),
offset=f['hlen'], count=1)
data = numpy.frombuffer(buf, dtype=numpy.dtype('<u4'),
offset=f['hlen'] + 4, count=int(f['length'] / 4))
#b = numpy.bitwise_xor(data, mask).data
b = numpy.bitwise_xor(data, mask).tostring()
if f['length'] % 4:
#print("Partial unmask")
mask = numpy.frombuffer(buf, dtype=numpy.dtype('B'),
offset=f['hlen'], count=(f['length'] % 4))
data = numpy.frombuffer(buf, dtype=numpy.dtype('B'),
offset=full_len - (f['length'] % 4),
count=(f['length'] % 4))
c = numpy.bitwise_xor(data, mask).tostring()
f['payload'] = b + c
f['payload'] = WebSocketServer.unmask(buf, f)
else:
print("Unmasked frame: %s" % repr(buf))
f['payload'] = buf[(f['hlen'] + has_mask * 4):full_len]
@ -474,11 +492,11 @@ Sec-WebSocket-Accept: %s\r
break
else:
if buf[0:2] == '\xff\x00':
if buf[0:2] == s2b('\xff\x00'):
closed = "Client sent orderly close frame"
break
elif buf[0:2] == '\x00\xff':
elif buf[0:2] == s2b('\x00\xff'):
buf = buf[2:]
continue # No-op
@ -617,9 +635,6 @@ Sec-WebSocket-Accept: %s\r
if ver:
# HyBi/IETF version of the protocol
if sys.hexversion < 0x2060000 or not numpy:
raise self.EClose("Python >= 2.6 and numpy module is required for HyBi-07 or greater")
# HyBi-07 report version 7
# HyBi-08 - HyBi-12 report version 8
# HyBi-13 reports version 13
@ -675,6 +690,9 @@ Sec-WebSocket-Accept: %s\r
self.msg("%s: %s WebSocket connection" % (address[0], stype))
self.msg("%s: Version %s, base64: '%s'" % (address[0],
self.version, self.base64))
if self.path != '/':
self.msg("%s: Path: '%s'" % (address[0], self.path))
# Send server WebSockets handshake response
#self.msg("sending response [%s]" % response)