|
@@ -1,44 +1,38 @@
|
|
|
-from errors import HandshakeError
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
class Extension(object):
|
|
class Extension(object):
|
|
|
name = ''
|
|
name = ''
|
|
|
rsv1 = False
|
|
rsv1 = False
|
|
|
rsv2 = False
|
|
rsv2 = False
|
|
|
rsv3 = False
|
|
rsv3 = False
|
|
|
opcodes = []
|
|
opcodes = []
|
|
|
- parameters = []
|
|
|
|
|
-
|
|
|
|
|
- def __init__(self, **kwargs):
|
|
|
|
|
- for param in self.parameters:
|
|
|
|
|
- setattr(self, param, None)
|
|
|
|
|
|
|
+ defaults = {}
|
|
|
|
|
+ request = {}
|
|
|
|
|
|
|
|
- for param, value in kwargs.items():
|
|
|
|
|
- if param not in self.parameters:
|
|
|
|
|
- raise HandshakeError('unrecognized parameter "%s"' % param)
|
|
|
|
|
|
|
+ def __init__(self, defaults={}, request={}):
|
|
|
|
|
+ for param in defaults.keys() + request.keys():
|
|
|
|
|
+ if param not in self.defaults:
|
|
|
|
|
+ raise KeyError('unrecognized parameter "%s"' % param)
|
|
|
|
|
|
|
|
- if value is None:
|
|
|
|
|
- value = True
|
|
|
|
|
|
|
+ # Copy dict first to avoid duplicate references to the same object
|
|
|
|
|
+ self.defaults = dict(self.__class__.defaults)
|
|
|
|
|
+ self.defaults.update(defaults)
|
|
|
|
|
|
|
|
- setattr(self, param, value)
|
|
|
|
|
|
|
+ self.request = dict(self.__class__.request)
|
|
|
|
|
+ self.request.update(request)
|
|
|
|
|
|
|
|
def __str__(self, frame):
|
|
def __str__(self, frame):
|
|
|
- if len(self.parameters):
|
|
|
|
|
- params = ' ' + ', '.join(p + '=' + str(getattr(self, p))
|
|
|
|
|
- for p in self.parameters)
|
|
|
|
|
- else:
|
|
|
|
|
- params = ''
|
|
|
|
|
|
|
+ return '<Extension "%s" defaults=%s request=%s>' \
|
|
|
|
|
+ % (self.name, self.defaults, self.request)
|
|
|
|
|
|
|
|
- return '<Extension "%s"%s>' % (self.name, params)
|
|
|
|
|
|
|
+ class Hook:
|
|
|
|
|
+ def __init__(self, **kwargs):
|
|
|
|
|
+ for param, value in kwargs.iteritems():
|
|
|
|
|
+ setattr(self, param, value)
|
|
|
|
|
|
|
|
- def header_params(self, frame):
|
|
|
|
|
- return {}
|
|
|
|
|
|
|
+ def send(self, frame):
|
|
|
|
|
+ return frame
|
|
|
|
|
|
|
|
- def hook_send(self, frame):
|
|
|
|
|
- return frame
|
|
|
|
|
-
|
|
|
|
|
- def hook_receive(self, frame):
|
|
|
|
|
- return frame
|
|
|
|
|
|
|
+ def recv(self, frame):
|
|
|
|
|
+ return frame
|
|
|
|
|
|
|
|
|
|
|
|
|
class DeflateFrame(Extension):
|
|
class DeflateFrame(Extension):
|
|
@@ -57,49 +51,43 @@ class DeflateFrame(Extension):
|
|
|
|
|
|
|
|
name = 'deflate-frame'
|
|
name = 'deflate-frame'
|
|
|
rsv1 = True
|
|
rsv1 = True
|
|
|
- parameters = ['max_window_bits', 'no_context_takeover']
|
|
|
|
|
-
|
|
|
|
|
- # FIXME: is this correct?
|
|
|
|
|
- default_max_window_bits = 32768
|
|
|
|
|
|
|
+ # FIXME: is 32768 (below) correct?
|
|
|
|
|
+ defaults = {'max_window_bits': 32768, 'no_context_takeover': True}
|
|
|
|
|
|
|
|
- def __init__(self, **kwargs):
|
|
|
|
|
- super(DeflateFrame, self).__init__(**kwargs)
|
|
|
|
|
|
|
+ def __init__(self, defaults={}, request={}):
|
|
|
|
|
+ Extension.__init__(self, defaults, request)
|
|
|
|
|
|
|
|
- if self.max_window_bits is None:
|
|
|
|
|
- self.max_window_bits = self.default_max_window_bits
|
|
|
|
|
- elif not isinstance(self.max_window_bits, int):
|
|
|
|
|
- raise HandshakeError('"max_window_bits" must be an integer')
|
|
|
|
|
- elif self.max_window_bits > 32768:
|
|
|
|
|
- raise HandshakeError('"max_window_bits" may not be larger than '
|
|
|
|
|
- '32768')
|
|
|
|
|
|
|
+ mwb = self.defaults['max_window_bits']
|
|
|
|
|
+ cto = self.defaults['no_context_takeover']
|
|
|
|
|
|
|
|
- if self.no_context_takeover is None:
|
|
|
|
|
- self.no_context_takeover = False
|
|
|
|
|
- elif self.no_context_takeover is not True:
|
|
|
|
|
- raise HandshakeError('"no_context_takeover" must have no value')
|
|
|
|
|
|
|
+ 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')
|
|
|
|
|
|
|
|
- def hook_send(self, frame):
|
|
|
|
|
- if not frame.rsv1:
|
|
|
|
|
- frame.rsv1 = True
|
|
|
|
|
- frame.payload = self.deflate(frame.payload)
|
|
|
|
|
|
|
+ if cto is not False and cto is not True:
|
|
|
|
|
+ raise ValueError('"no_context_takeover" must have no value')
|
|
|
|
|
|
|
|
- return frame
|
|
|
|
|
|
|
+ class Hook:
|
|
|
|
|
+ def send(self, frame):
|
|
|
|
|
+ if not frame.rsv1:
|
|
|
|
|
+ frame.rsv1 = True
|
|
|
|
|
+ frame.payload = self.deflate(frame.payload)
|
|
|
|
|
|
|
|
- def hook_recv(self, frame):
|
|
|
|
|
- if frame.rsv1:
|
|
|
|
|
- frame.rsv1 = False
|
|
|
|
|
- frame.payload = self.inflate(frame.payload)
|
|
|
|
|
|
|
+ return frame
|
|
|
|
|
|
|
|
- return frame
|
|
|
|
|
|
|
+ def recv(self, frame):
|
|
|
|
|
+ if frame.rsv1:
|
|
|
|
|
+ frame.rsv1 = False
|
|
|
|
|
+ frame.payload = self.inflate(frame.payload)
|
|
|
|
|
|
|
|
- def header_params(self):
|
|
|
|
|
- raise NotImplementedError # TODO
|
|
|
|
|
|
|
+ return frame
|
|
|
|
|
|
|
|
- def deflate(self, data):
|
|
|
|
|
- raise NotImplementedError # TODO
|
|
|
|
|
|
|
+ def deflate(self, data):
|
|
|
|
|
+ raise NotImplementedError # TODO
|
|
|
|
|
|
|
|
- def inflate(self, data):
|
|
|
|
|
- raise NotImplementedError # TODO
|
|
|
|
|
|
|
+ def inflate(self, data):
|
|
|
|
|
+ raise NotImplementedError # TODO
|
|
|
|
|
|
|
|
|
|
|
|
|
class Multiplex(Extension):
|
|
class Multiplex(Extension):
|
|
@@ -115,21 +103,19 @@ class Multiplex(Extension):
|
|
|
rsv1 = True # FIXME
|
|
rsv1 = True # FIXME
|
|
|
rsv2 = True # FIXME
|
|
rsv2 = True # FIXME
|
|
|
rsv3 = True # FIXME
|
|
rsv3 = True # FIXME
|
|
|
- parameters = ['quota']
|
|
|
|
|
|
|
+ defaults = {'quota': None}
|
|
|
|
|
|
|
|
- def __init__(self, **kwargs):
|
|
|
|
|
- super(Multiplex, self).__init__(**kwargs)
|
|
|
|
|
|
|
+ def __init__(self, defaults={}, request={}):
|
|
|
|
|
+ Extension.__init__(self, defaults, request)
|
|
|
|
|
|
|
|
# TODO: check "quota" value
|
|
# TODO: check "quota" value
|
|
|
|
|
|
|
|
- def hook_send(self, frame):
|
|
|
|
|
- raise NotImplementedError # TODO
|
|
|
|
|
-
|
|
|
|
|
- def hook_recv(self, frame):
|
|
|
|
|
- raise NotImplementedError # TODO
|
|
|
|
|
|
|
+ class Hook:
|
|
|
|
|
+ def send(self, frame):
|
|
|
|
|
+ raise NotImplementedError # TODO
|
|
|
|
|
|
|
|
- def header_params(self):
|
|
|
|
|
- raise NotImplementedError # TODO
|
|
|
|
|
|
|
+ def recv(self, frame):
|
|
|
|
|
+ raise NotImplementedError # TODO
|
|
|
|
|
|
|
|
|
|
|
|
|
def filter_extensions(extensions):
|
|
def filter_extensions(extensions):
|