Commit 7c99e4fe authored by Taddeüs Kroes's avatar Taddeüs Kroes

Split extension.py into base file and extension implementation files

Also, moved WebkitDeflateFrame to library source instead of tests
parent 91ec1795
......@@ -8,4 +8,6 @@ from frame import Frame, ControlFrame, OPCODE_CONTINUATION, OPCODE_TEXT, \
from connection import Connection
from message import Message, TextMessage, BinaryMessage
from errors import SocketClosed, HandshakeError, PingError, SSLError
from extension import Extension, DeflateFrame
from extension import Extension
from deflate_frame import DeflateFrame, WebkitDeflateFrame
#from multiplex import Multiplex
import zlib
from frame import ControlFrame
from errors import SocketClosed
from extension import Extension
class DeflateFrame(Extension):
"""
This is an implementation of the "deflate-frame" extension, as defined by
http://tools.ietf.org/html/draft-tyoshino-hybi-websocket-perframe-deflate-06.
Supported parameters are:
- max_window_size: maximum size for the LZ77 sliding window.
- no_context_takeover: disallows usage of LZ77 sliding window from
previously built frames for the current frame.
Note that the deflate and inflate hooks modify the RSV1 bit and payload of
existing `Frame` objects.
"""
name = 'deflate-frame'
rsv1 = True
# FIXME: is 32768 (below) correct?
defaults = {'max_window_bits': 15, 'no_context_takeover': False}
def __init__(self, defaults={}, request={}):
Extension.__init__(self, defaults, request)
mwb = self.defaults['max_window_bits']
cto = self.defaults['no_context_takeover']
if not isinstance(mwb, int):
raise ValueError('"max_window_bits" must be an integer')
elif mwb > 32768:
raise ValueError('"max_window_bits" may not be larger than 32768')
if cto is not False and cto is not True:
raise ValueError('"no_context_takeover" must have no value')
class Hook(Extension.Hook):
def __init__(self, extension, **kwargs):
Extension.Hook.__init__(self, extension, **kwargs)
if not self.no_context_takeover:
self.defl = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
zlib.DEFLATED,
-self.max_window_bits)
other_wbits = self.extension.request.get('max_window_bits', 15)
self.dec = zlib.decompressobj(-other_wbits)
def send(self, frame):
if not frame.rsv1 and not isinstance(frame, ControlFrame):
frame.rsv1 = True
frame.payload = self.deflate(frame.payload)
return frame
def recv(self, frame):
if frame.rsv1:
if isinstance(frame, ControlFrame):
raise SocketClosed('received compressed control frame')
frame.rsv1 = False
frame.payload = self.inflate(frame.payload)
return frame
def deflate(self, data):
if self.no_context_takeover:
defl = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
zlib.DEFLATED, -self.max_window_bits)
# FIXME: why the '\x00' below? This was borrowed from
# https://github.com/fancycode/tornado/blob/bc317b6dcf63608ff004ff1f57073be0504b6550/tornado/websocket.py#L91
return defl.compress(data) + defl.flush(zlib.Z_FINISH) + '\x00'
compressed = self.defl.compress(data)
compressed += self.defl.flush(zlib.Z_SYNC_FLUSH)
assert compressed[-4:] == '\x00\x00\xff\xff'
return compressed[:-4]
def inflate(self, data):
data = self.dec.decompress(str(data + '\x00\x00\xff\xff'))
assert not self.dec.unused_data
return data
class WebkitDeflateFrame(DeflateFrame):
name = 'x-webkit-deflate-frame'
import zlib
from frame import ControlFrame
from errors import SocketClosed
class Extension(object):
name = ''
rsv1 = False
......@@ -49,115 +43,6 @@ class Extension(object):
return frame
class DeflateFrame(Extension):
"""
This is an implementation of the "deflate-frame" extension, as defined by
http://tools.ietf.org/html/draft-tyoshino-hybi-websocket-perframe-deflate-06.
Supported parameters are:
- max_window_size: maximum size for the LZ77 sliding window.
- no_context_takeover: disallows usage of LZ77 sliding window from
previously built frames for the current frame.
Note that the deflate and inflate hooks modify the RSV1 bit and payload of
existing `Frame` objects.
"""
name = 'deflate-frame'
rsv1 = True
# FIXME: is 32768 (below) correct?
defaults = {'max_window_bits': 15, 'no_context_takeover': False}
def __init__(self, defaults={}, request={}):
Extension.__init__(self, defaults, request)
mwb = self.defaults['max_window_bits']
cto = self.defaults['no_context_takeover']
if not isinstance(mwb, int):
raise ValueError('"max_window_bits" must be an integer')
elif mwb > 32768:
raise ValueError('"max_window_bits" may not be larger than 32768')
if cto is not False and cto is not True:
raise ValueError('"no_context_takeover" must have no value')
class Hook(Extension.Hook):
def __init__(self, extension, **kwargs):
Extension.Hook.__init__(self, extension, **kwargs)
if not self.no_context_takeover:
self.defl = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
zlib.DEFLATED,
-self.max_window_bits)
other_wbits = self.extension.request.get('max_window_bits', 15)
self.dec = zlib.decompressobj(-other_wbits)
def send(self, frame):
if not frame.rsv1 and not isinstance(frame, ControlFrame):
frame.rsv1 = True
frame.payload = self.deflate(frame.payload)
return frame
def recv(self, frame):
if frame.rsv1:
if isinstance(frame, ControlFrame):
raise SocketClosed('received compressed control frame')
frame.rsv1 = False
frame.payload = self.inflate(frame.payload)
return frame
def deflate(self, data):
if self.no_context_takeover:
defl = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,
zlib.DEFLATED, -self.max_window_bits)
# FIXME: why the '\x00' below? This was borrowed from
# https://github.com/fancycode/tornado/blob/bc317b6dcf63608ff004ff1f57073be0504b6550/tornado/websocket.py#L91
return defl.compress(data) + defl.flush(zlib.Z_FINISH) + '\x00'
compressed = self.defl.compress(data)
compressed += self.defl.flush(zlib.Z_SYNC_FLUSH)
assert compressed[-4:] == '\x00\x00\xff\xff'
return compressed[:-4]
def inflate(self, data):
data = self.dec.decompress(str(data + '\x00\x00\xff\xff'))
assert not self.dec.unused_data
return data
class Multiplex(Extension):
"""
This is an implementation of the "mux" extension, as defined by
http://tools.ietf.org/html/draft-ietf-hybi-websocket-multiplexing-11.
Supported parameters are:
- quota: TODO
"""
name = 'mux'
rsv1 = True # FIXME
rsv2 = True # FIXME
rsv3 = True # FIXME
defaults = {'quota': None}
def __init__(self, defaults={}, request={}):
Extension.__init__(self, defaults, request)
# TODO: check "quota" value
class Hook(Extension.Hook):
def send(self, frame):
raise NotImplementedError # TODO
def recv(self, frame):
raise NotImplementedError # TODO
def filter_extensions(extensions):
"""
Remove extensions that use conflicting rsv bits and/or opcodes, with the
......
from extension import Extension
class Multiplex(Extension):
"""
This is an implementation of the "mux" extension, as defined by
http://tools.ietf.org/html/draft-ietf-hybi-websocket-multiplexing-11.
Supported parameters are:
- quota: TODO
"""
name = 'mux'
rsv1 = True # FIXME
rsv2 = True # FIXME
rsv3 = True # FIXME
defaults = {'quota': None}
def __init__(self, defaults={}, request={}):
Extension.__init__(self, defaults, request)
# TODO: check "quota" value
class Hook(Extension.Hook):
def send(self, frame):
raise NotImplementedError # TODO
def recv(self, frame):
raise NotImplementedError # TODO
......@@ -7,7 +7,7 @@ basepath = abspath(dirname(abspath(__file__)) + '/..')
sys.path.insert(0, basepath)
from server import Server
from extension import DeflateFrame
from deflate_frame import WebkitDeflateFrame
class EchoServer(Server):
......@@ -16,10 +16,6 @@ class EchoServer(Server):
client.send(message)
class WebkitDeflateFrame(DeflateFrame):
name = 'x-webkit-deflate-frame'
if __name__ == '__main__':
deflate = WebkitDeflateFrame()
#deflate = WebkitDeflateFrame(defaults={'no_context_takeover': True})
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment