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, \ ...@@ -8,4 +8,6 @@ from frame import Frame, ControlFrame, OPCODE_CONTINUATION, OPCODE_TEXT, \
from connection import Connection from connection import Connection
from message import Message, TextMessage, BinaryMessage from message import Message, TextMessage, BinaryMessage
from errors import SocketClosed, HandshakeError, PingError, SSLError 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): class Extension(object):
name = '' name = ''
rsv1 = False rsv1 = False
...@@ -49,115 +43,6 @@ class Extension(object): ...@@ -49,115 +43,6 @@ class Extension(object):
return frame 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): def filter_extensions(extensions):
""" """
Remove extensions that use conflicting rsv bits and/or opcodes, with the 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__)) + '/..') ...@@ -7,7 +7,7 @@ basepath = abspath(dirname(abspath(__file__)) + '/..')
sys.path.insert(0, basepath) sys.path.insert(0, basepath)
from server import Server from server import Server
from extension import DeflateFrame from deflate_frame import WebkitDeflateFrame
class EchoServer(Server): class EchoServer(Server):
...@@ -16,10 +16,6 @@ class EchoServer(Server): ...@@ -16,10 +16,6 @@ class EchoServer(Server):
client.send(message) client.send(message)
class WebkitDeflateFrame(DeflateFrame):
name = 'x-webkit-deflate-frame'
if __name__ == '__main__': if __name__ == '__main__':
deflate = WebkitDeflateFrame() deflate = WebkitDeflateFrame()
#deflate = WebkitDeflateFrame(defaults={'no_context_takeover': True}) #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