wip
This commit is contained in:
parent
313a16b2ad
commit
e777d09d87
@ -271,7 +271,6 @@ class ApplicationError(Error):
|
||||
return self.__unicode__().encode('utf8')
|
||||
|
||||
|
||||
@public
|
||||
@error(ApplicationError.NOT_AUTHORIZED)
|
||||
class NotAuthorized(Exception):
|
||||
"""
|
||||
@ -279,7 +278,6 @@ class NotAuthorized(Exception):
|
||||
"""
|
||||
|
||||
|
||||
@public
|
||||
@error(ApplicationError.INVALID_URI)
|
||||
class InvalidUri(Exception):
|
||||
"""
|
||||
@ -287,7 +285,6 @@ class InvalidUri(Exception):
|
||||
"""
|
||||
|
||||
|
||||
@public
|
||||
@error(ApplicationError.INVALID_PAYLOAD)
|
||||
class InvalidPayload(Exception):
|
||||
"""
|
||||
|
@ -33,11 +33,9 @@ __all__ = (
|
||||
'Handler',
|
||||
'Registration',
|
||||
'Endpoint',
|
||||
|
||||
'PublishRequest',
|
||||
'SubscribeRequest',
|
||||
'UnsubscribeRequest',
|
||||
|
||||
'CallRequest',
|
||||
'InvocationRequest',
|
||||
'RegisterRequest',
|
||||
@ -54,6 +52,14 @@ class Publication(object):
|
||||
__slots__ = ('id', 'was_encrypted')
|
||||
|
||||
def __init__(self, publication_id, was_encrypted):
|
||||
"""
|
||||
|
||||
:param publication_id: The publication ID of the published event.
|
||||
:type publication_id: int
|
||||
|
||||
:param was_encrypted: Flag indicating whether the app payload was encrypted.
|
||||
:type was_encrypted: bool
|
||||
"""
|
||||
self.id = publication_id
|
||||
self.was_encrypted = was_encrypted
|
||||
|
||||
@ -70,6 +76,18 @@ class Subscription(object):
|
||||
|
||||
def __init__(self, subscription_id, topic, session, handler):
|
||||
"""
|
||||
|
||||
:param subscription_id: The subscription ID.
|
||||
:type subscription_id: int
|
||||
|
||||
:param topic: The subscription URI or URI pattern.
|
||||
:type topic: str
|
||||
|
||||
:param session: The ApplicationSession this subscription is living on.
|
||||
:type session: instance of ApplicationSession
|
||||
|
||||
:param handler: The user event callback.
|
||||
:type handler: callable
|
||||
"""
|
||||
self.id = subscription_id
|
||||
self.topic = topic
|
||||
@ -79,6 +97,7 @@ class Subscription(object):
|
||||
|
||||
def unsubscribe(self):
|
||||
"""
|
||||
Unsubscribe this subscription.
|
||||
"""
|
||||
if self.active:
|
||||
return self.session._unsubscribe(self)
|
||||
@ -101,8 +120,10 @@ class Handler(object):
|
||||
|
||||
:param fn: The event handler function to be called.
|
||||
:type fn: callable
|
||||
|
||||
:param obj: The (optional) object upon which to call the function.
|
||||
:type obj: obj or None
|
||||
|
||||
:param details_arg: The keyword argument under which event details should be provided.
|
||||
:type details_arg: str or None
|
||||
"""
|
||||
@ -119,6 +140,20 @@ class Registration(object):
|
||||
__slots__ = ('id', 'active', 'session', 'procedure', 'endpoint')
|
||||
|
||||
def __init__(self, session, registration_id, procedure, endpoint):
|
||||
"""
|
||||
|
||||
:param id: The registration ID.
|
||||
:type id: int
|
||||
|
||||
:param active: Flag indicating whether this registration is active.
|
||||
:type active: bool
|
||||
|
||||
:param procedure: The procedure URI or URI pattern.
|
||||
:type procedure: callable
|
||||
|
||||
:param endpoint: The user callback.
|
||||
:type endpoint: callable
|
||||
"""
|
||||
self.id = registration_id
|
||||
self.active = True
|
||||
self.session = session
|
||||
@ -146,8 +181,10 @@ class Endpoint(object):
|
||||
|
||||
:param fn: The endpoint procedure to be called.
|
||||
:type fn: callable
|
||||
|
||||
:param obj: The (optional) object upon which to call the function.
|
||||
:type obj: obj or None
|
||||
|
||||
:param details_arg: The keyword argument under which call details should be provided.
|
||||
:type details_arg: str or None
|
||||
"""
|
||||
@ -169,6 +206,7 @@ class Request(object):
|
||||
|
||||
:param request_id: The WAMP request ID.
|
||||
:type request_id: int
|
||||
|
||||
:param on_reply: The Deferred/Future to be fired when the request returns.
|
||||
:type on_reply: Deferred/Future
|
||||
"""
|
||||
@ -184,6 +222,17 @@ class PublishRequest(Request):
|
||||
__slots__ = ('was_encrypted')
|
||||
|
||||
def __init__(self, request_id, on_reply, was_encrypted):
|
||||
"""
|
||||
|
||||
:param request_id: The WAMP request ID.
|
||||
:type request_id: int
|
||||
|
||||
:param on_reply: The Deferred/Future to be fired when the request returns.
|
||||
:type on_reply: Deferred/Future
|
||||
|
||||
:param was_encrypted: Flag indicating whether the app payload was encrypted.
|
||||
:type was_encrypted: bool
|
||||
"""
|
||||
Request.__init__(self, request_id, on_reply)
|
||||
self.was_encrypted = was_encrypted
|
||||
|
||||
@ -200,10 +249,13 @@ class SubscribeRequest(Request):
|
||||
|
||||
:param request_id: The WAMP request ID.
|
||||
:type request_id: int
|
||||
|
||||
:param topic: The topic URI being subscribed to.
|
||||
:type topic: unicode
|
||||
|
||||
:param on_reply: The Deferred/Future to be fired when the request returns.
|
||||
:type on_reply: Deferred/Future
|
||||
|
||||
:param handler: WAMP call options that are in use for this call.
|
||||
:type handler: callable
|
||||
"""
|
||||
@ -217,7 +269,11 @@ class UnsubscribeRequest(Request):
|
||||
Object representing an outstanding request to unsubscribe a subscription.
|
||||
"""
|
||||
|
||||
__slots__ = ('subscription_id',)
|
||||
|
||||
def __init__(self, request_id, on_reply, subscription_id):
|
||||
"""
|
||||
"""
|
||||
Request.__init__(self, request_id, on_reply)
|
||||
self.subscription_id = subscription_id
|
||||
|
||||
@ -234,8 +290,10 @@ class CallRequest(Request):
|
||||
|
||||
:param request_id: The WAMP request ID.
|
||||
:type request_id: int
|
||||
|
||||
:param on_reply: The Deferred/Future to be fired when the request returns.
|
||||
:type on_reply: Deferred/Future
|
||||
|
||||
:param options: WAMP call options that are in use for this call.
|
||||
:type options: dict
|
||||
"""
|
||||
@ -255,7 +313,11 @@ class RegisterRequest(Request):
|
||||
Object representing an outstanding request to register a procedure.
|
||||
"""
|
||||
|
||||
__slots__ = ('procedure', 'endpoint',)
|
||||
|
||||
def __init__(self, request_id, on_reply, procedure, endpoint):
|
||||
"""
|
||||
"""
|
||||
Request.__init__(self, request_id, on_reply)
|
||||
self.procedure = procedure
|
||||
self.endpoint = endpoint
|
||||
@ -266,6 +328,10 @@ class UnregisterRequest(Request):
|
||||
Object representing an outstanding request to unregister a registration.
|
||||
"""
|
||||
|
||||
__slots__ = ('registration_id',)
|
||||
|
||||
def __init__(self, request_id, on_reply, registration_id):
|
||||
"""
|
||||
"""
|
||||
Request.__init__(self, request_id, on_reply)
|
||||
self.registration_id = registration_id
|
||||
|
@ -136,7 +136,8 @@ class Pattern(object):
|
||||
"""
|
||||
|
||||
:param uri: The URI or URI pattern, e.g. ``"com.myapp.product.<product:int>.update"``.
|
||||
:type uri: unicode
|
||||
:type uri: str
|
||||
|
||||
:param target: The target for this pattern: a procedure endpoint (a callable),
|
||||
an event handler (a callable) or an exception (a class).
|
||||
:type target: callable or obj
|
||||
@ -213,7 +214,7 @@ class Pattern(object):
|
||||
Returns the original URI (pattern) for this pattern.
|
||||
|
||||
:returns: The URI (pattern), e.g. ``"com.myapp.product.<product:int>.update"``.
|
||||
:rtype: unicode
|
||||
:rtype: str
|
||||
"""
|
||||
return self._uri
|
||||
|
||||
@ -229,7 +230,7 @@ class Pattern(object):
|
||||
and return extracted args and kwargs.
|
||||
|
||||
:param uri: The URI to match, e.g. ``"com.myapp.product.123456.update"``.
|
||||
:type uri: unicode
|
||||
:type uri: str
|
||||
|
||||
:returns: A tuple ``(args, kwargs)``
|
||||
:rtype: tuple
|
||||
|
@ -227,6 +227,7 @@ class WampWebSocketFactory(object):
|
||||
:param factory: A callable that produces instances that implement
|
||||
:class:`autobahn.wamp.interfaces.ITransportHandler`
|
||||
:type factory: callable
|
||||
|
||||
:param serializers: A list of WAMP serializers to use (or None for default
|
||||
serializers). Serializers must implement
|
||||
:class:`autobahn.wamp.interfaces.ISerializer`.
|
||||
|
@ -44,22 +44,22 @@ from autobahn.websocket.compress_deflate import \
|
||||
# this must be a list (not tuple), since we dynamically
|
||||
# extend it ..
|
||||
__all__ = [
|
||||
"PerMessageCompressOffer",
|
||||
"PerMessageCompressOfferAccept",
|
||||
"PerMessageCompressResponse",
|
||||
"PerMessageCompressResponseAccept",
|
||||
"PerMessageCompress",
|
||||
"PerMessageDeflateOffer",
|
||||
"PerMessageDeflateOfferAccept",
|
||||
"PerMessageDeflateResponse",
|
||||
"PerMessageDeflateResponseAccept",
|
||||
"PerMessageDeflate",
|
||||
"PERMESSAGE_COMPRESSION_EXTENSION"
|
||||
'PerMessageCompressOffer',
|
||||
'PerMessageCompressOfferAccept',
|
||||
'PerMessageCompressResponse',
|
||||
'PerMessageCompressResponseAccept',
|
||||
'PerMessageCompress',
|
||||
'PerMessageDeflateOffer',
|
||||
'PerMessageDeflateOfferAccept',
|
||||
'PerMessageDeflateResponse',
|
||||
'PerMessageDeflateResponseAccept',
|
||||
'PerMessageDeflate',
|
||||
'PERMESSAGE_COMPRESSION_EXTENSION'
|
||||
]
|
||||
|
||||
# class for "permessage-deflate" is always available
|
||||
#
|
||||
# map of available compression extensions
|
||||
PERMESSAGE_COMPRESSION_EXTENSION = {
|
||||
# class for 'permessage-deflate' is always available
|
||||
PerMessageDeflateMixin.EXTENSION_NAME: {
|
||||
'Offer': PerMessageDeflateOffer,
|
||||
'OfferAccept': PerMessageDeflateOfferAccept,
|
||||
@ -70,8 +70,7 @@ PERMESSAGE_COMPRESSION_EXTENSION = {
|
||||
}
|
||||
|
||||
|
||||
# include "permessage-bzip2" classes if bzip2 is available
|
||||
#
|
||||
# include 'permessage-bzip2' classes if bzip2 is available
|
||||
try:
|
||||
import bz2
|
||||
except ImportError:
|
||||
@ -94,15 +93,14 @@ else:
|
||||
}
|
||||
PERMESSAGE_COMPRESSION_EXTENSION[PerMessageBzip2Mixin.EXTENSION_NAME] = PMCE
|
||||
|
||||
__all__.extend(["PerMessageBzip2Offer",
|
||||
"PerMessageBzip2OfferAccept",
|
||||
"PerMessageBzip2Response",
|
||||
"PerMessageBzip2ResponseAccept",
|
||||
"PerMessageBzip2"])
|
||||
__all__.extend(['PerMessageBzip2Offer',
|
||||
'PerMessageBzip2OfferAccept',
|
||||
'PerMessageBzip2Response',
|
||||
'PerMessageBzip2ResponseAccept',
|
||||
'PerMessageBzip2'])
|
||||
|
||||
|
||||
# include "permessage-snappy" classes if Snappy is available
|
||||
#
|
||||
# include 'permessage-snappy' classes if Snappy is available
|
||||
try:
|
||||
# noinspection PyPackageRequirements
|
||||
import snappy
|
||||
@ -126,8 +124,8 @@ else:
|
||||
}
|
||||
PERMESSAGE_COMPRESSION_EXTENSION[PerMessageSnappyMixin.EXTENSION_NAME] = PMCE
|
||||
|
||||
__all__.extend(["PerMessageSnappyOffer",
|
||||
"PerMessageSnappyOfferAccept",
|
||||
"PerMessageSnappyResponse",
|
||||
"PerMessageSnappyResponseAccept",
|
||||
"PerMessageSnappy"])
|
||||
__all__.extend(['PerMessageSnappyOffer',
|
||||
'PerMessageSnappyOfferAccept',
|
||||
'PerMessageSnappyResponse',
|
||||
'PerMessageSnappyResponseAccept',
|
||||
'PerMessageSnappy'])
|
||||
|
@ -51,13 +51,13 @@ class PerMessageBzip2Mixin(object):
|
||||
|
||||
EXTENSION_NAME = "permessage-bzip2"
|
||||
"""
|
||||
Name of this WebSocket extension.
|
||||
"""
|
||||
Name of this WebSocket extension.
|
||||
"""
|
||||
|
||||
COMPRESS_LEVEL_PERMISSIBLE_VALUES = [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
"""
|
||||
Permissible value for compression level parameter.
|
||||
"""
|
||||
Permissible value for compression level parameter.
|
||||
"""
|
||||
|
||||
|
||||
class PerMessageBzip2Offer(PerMessageCompressOffer, PerMessageBzip2Mixin):
|
||||
@ -77,13 +77,10 @@ class PerMessageBzip2Offer(PerMessageCompressOffer, PerMessageBzip2Mixin):
|
||||
:returns: object -- A new instance of :class:`autobahn.compress.PerMessageBzip2Offer`.
|
||||
"""
|
||||
# extension parameter defaults
|
||||
##
|
||||
acceptMaxCompressLevel = False
|
||||
requestMaxCompressLevel = 0
|
||||
accept_max_compress_level = False
|
||||
request_max_compress_level = 0
|
||||
|
||||
##
|
||||
# verify/parse client ("client-to-server direction") parameters of permessage-bzip2 offer
|
||||
##
|
||||
for p in params:
|
||||
|
||||
if len(params[p]) > 1:
|
||||
@ -96,7 +93,7 @@ class PerMessageBzip2Offer(PerMessageCompressOffer, PerMessageBzip2Mixin):
|
||||
if val is not True:
|
||||
raise Exception("illegal extension parameter value '%s' for parameter '%s' of extension '%s'" % (val, p, cls.EXTENSION_NAME))
|
||||
else:
|
||||
acceptMaxCompressLevel = True
|
||||
accept_max_compress_level = True
|
||||
|
||||
elif p == 'server_max_compress_level':
|
||||
try:
|
||||
@ -106,66 +103,69 @@ class PerMessageBzip2Offer(PerMessageCompressOffer, PerMessageBzip2Mixin):
|
||||
if val not in PerMessageBzip2Mixin.COMPRESS_LEVEL_PERMISSIBLE_VALUES:
|
||||
raise Exception("illegal extension parameter value '%s' for parameter '%s' of extension '%s'" % (val, p, cls.EXTENSION_NAME))
|
||||
else:
|
||||
requestMaxCompressLevel = val
|
||||
request_max_compress_level = val
|
||||
|
||||
else:
|
||||
raise Exception("illegal extension parameter '%s' for extension '%s'" % (p, cls.EXTENSION_NAME))
|
||||
|
||||
offer = cls(acceptMaxCompressLevel,
|
||||
requestMaxCompressLevel)
|
||||
offer = cls(accept_max_compress_level,
|
||||
request_max_compress_level)
|
||||
return offer
|
||||
|
||||
def __init__(self,
|
||||
acceptMaxCompressLevel=True,
|
||||
requestMaxCompressLevel=0):
|
||||
accept_max_compress_level=True,
|
||||
request_max_compress_level=0):
|
||||
"""
|
||||
Constructor.
|
||||
|
||||
:param acceptMaxCompressLevel: Iff true, client accepts "maximum compression level" parameter.
|
||||
:type acceptMaxCompressLevel: bool
|
||||
:param requestMaxCompressLevel: Iff non-zero, client requests given "maximum compression level" - must be 1-9.
|
||||
:type requestMaxCompressLevel: int
|
||||
:param accept_max_compress_level: Iff true, client accepts "maximum compression level" parameter.
|
||||
:type accept_max_compress_level: bool
|
||||
:param request_max_compress_level: Iff non-zero, client requests given "maximum compression level" - must be 1-9.
|
||||
:type request_max_compress_level: int
|
||||
"""
|
||||
if type(acceptMaxCompressLevel) != bool:
|
||||
raise Exception("invalid type %s for acceptMaxCompressLevel" % type(acceptMaxCompressLevel))
|
||||
if type(accept_max_compress_level) != bool:
|
||||
raise Exception("invalid type %s for accept_max_compress_level" % type(accept_max_compress_level))
|
||||
|
||||
self.acceptMaxCompressLevel = acceptMaxCompressLevel
|
||||
self.accept_max_compress_level = accept_max_compress_level
|
||||
|
||||
if requestMaxCompressLevel != 0 and requestMaxCompressLevel not in self.COMPRESS_LEVEL_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for requestMaxCompressLevel - permissible values %s" % (requestMaxCompressLevel, self.COMPRESS_LEVEL_PERMISSIBLE_VALUES))
|
||||
if request_max_compress_level != 0 and request_max_compress_level not in self.COMPRESS_LEVEL_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for request_max_compress_level - permissible values %s" % (request_max_compress_level, self.COMPRESS_LEVEL_PERMISSIBLE_VALUES))
|
||||
|
||||
self.requestMaxCompressLevel = requestMaxCompressLevel
|
||||
self.request_max_compress_level = request_max_compress_level
|
||||
|
||||
def getExtensionString(self):
|
||||
def get_extension_string(self):
|
||||
"""
|
||||
Returns the WebSocket extension configuration string as sent to the server.
|
||||
|
||||
:returns: str -- PMCE configuration string.
|
||||
:returns: PMCE configuration string.
|
||||
:rtype: str
|
||||
"""
|
||||
pmceString = self.EXTENSION_NAME
|
||||
if self.acceptMaxCompressLevel:
|
||||
pmceString += "; client_max_compress_level"
|
||||
if self.requestMaxCompressLevel != 0:
|
||||
pmceString += "; server_max_compress_level=%d" % self.requestMaxCompressLevel
|
||||
return pmceString
|
||||
pmce_string = self.EXTENSION_NAME
|
||||
if self.accept_max_compress_level:
|
||||
pmce_string += "; client_max_compress_level"
|
||||
if self.request_max_compress_level != 0:
|
||||
pmce_string += "; server_max_compress_level=%d" % self.request_max_compress_level
|
||||
return pmce_string
|
||||
|
||||
def __json__(self):
|
||||
"""
|
||||
Returns a JSON serializable object representation.
|
||||
|
||||
:returns: object -- JSON serializable representation.
|
||||
:returns: JSON serializable representation.
|
||||
:rtype: dict
|
||||
"""
|
||||
return {'extension': self.EXTENSION_NAME,
|
||||
'acceptMaxCompressLevel': self.acceptMaxCompressLevel,
|
||||
'requestMaxCompressLevel': self.requestMaxCompressLevel}
|
||||
'accept_max_compress_level': self.accept_max_compress_level,
|
||||
'request_max_compress_level': self.request_max_compress_level}
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
Returns Python object representation that can be eval'ed to reconstruct the object.
|
||||
|
||||
:returns: str -- Python string representation.
|
||||
:returns: Python string representation.
|
||||
:rtype: str
|
||||
"""
|
||||
return "PerMessageBzip2Offer(acceptMaxCompressLevel = %s, requestMaxCompressLevel = %s)" % (self.acceptMaxCompressLevel, self.requestMaxCompressLevel)
|
||||
return "PerMessageBzip2Offer(accept_max_compress_level = %s, request_max_compress_level = %s)" % (self.accept_max_compress_level, self.request_max_compress_level)
|
||||
|
||||
|
||||
class PerMessageBzip2OfferAccept(PerMessageCompressOfferAccept, PerMessageBzip2Mixin):
|
||||
@ -176,71 +176,74 @@ class PerMessageBzip2OfferAccept(PerMessageCompressOfferAccept, PerMessageBzip2M
|
||||
|
||||
def __init__(self,
|
||||
offer,
|
||||
requestMaxCompressLevel=0,
|
||||
compressLevel=None):
|
||||
request_max_compress_level=0,
|
||||
compress_level=None):
|
||||
"""
|
||||
Constructor.
|
||||
|
||||
:param offer: The offer being accepted.
|
||||
:type offer: Instance of :class:`autobahn.compress.PerMessageBzip2Offer`.
|
||||
:param requestMaxCompressLevel: Iff non-zero, server requests given "maximum compression level" - must be 1-9.
|
||||
:type requestMaxCompressLevel: int
|
||||
:param compressLevel: Override server ("server-to-client direction") compress level (this must be compatible with offer).
|
||||
:type compressLevel: int
|
||||
:param request_max_compress_level: Iff non-zero, server requests given "maximum compression level" - must be 1-9.
|
||||
:type request_max_compress_level: int
|
||||
:param compress_level: Override server ("server-to-client direction") compress level (this must be compatible with offer).
|
||||
:type compress_level: int
|
||||
"""
|
||||
if not isinstance(offer, PerMessageBzip2Offer):
|
||||
raise Exception("invalid type %s for offer" % type(offer))
|
||||
|
||||
self.offer = offer
|
||||
|
||||
if requestMaxCompressLevel != 0 and requestMaxCompressLevel not in self.COMPRESS_LEVEL_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for requestMaxCompressLevel - permissible values %s" % (requestMaxCompressLevel, self.COMPRESS_LEVEL_PERMISSIBLE_VALUES))
|
||||
if request_max_compress_level != 0 and request_max_compress_level not in self.COMPRESS_LEVEL_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for request_max_compress_level - permissible values %s" % (request_max_compress_level, self.COMPRESS_LEVEL_PERMISSIBLE_VALUES))
|
||||
|
||||
if requestMaxCompressLevel != 0 and not offer.acceptMaxCompressLevel:
|
||||
raise Exception("invalid value %s for requestMaxCompressLevel - feature unsupported by client" % requestMaxCompressLevel)
|
||||
if request_max_compress_level != 0 and not offer.accept_max_compress_level:
|
||||
raise Exception("invalid value %s for request_max_compress_level - feature unsupported by client" % request_max_compress_level)
|
||||
|
||||
self.requestMaxCompressLevel = requestMaxCompressLevel
|
||||
self.request_max_compress_level = request_max_compress_level
|
||||
|
||||
if compressLevel is not None:
|
||||
if compressLevel not in self.COMPRESS_LEVEL_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for compressLevel - permissible values %s" % (compressLevel, self.COMPRESS_LEVEL_PERMISSIBLE_VALUES))
|
||||
if compress_level is not None:
|
||||
if compress_level not in self.COMPRESS_LEVEL_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for compress_level - permissible values %s" % (compress_level, self.COMPRESS_LEVEL_PERMISSIBLE_VALUES))
|
||||
|
||||
if offer.requestMaxCompressLevel != 0 and compressLevel > offer.requestMaxCompressLevel:
|
||||
raise Exception("invalid value %s for compressLevel - client requested lower maximum value" % compressLevel)
|
||||
if offer.request_max_compress_level != 0 and compress_level > offer.request_max_compress_level:
|
||||
raise Exception("invalid value %s for compress_level - client requested lower maximum value" % compress_level)
|
||||
|
||||
self.compressLevel = compressLevel
|
||||
self.compress_level = compress_level
|
||||
|
||||
def getExtensionString(self):
|
||||
def get_extension_string(self):
|
||||
"""
|
||||
Returns the WebSocket extension configuration string as sent to the server.
|
||||
|
||||
:returns: str -- PMCE configuration string.
|
||||
:returns: PMCE configuration string.
|
||||
:rtype: str
|
||||
"""
|
||||
pmceString = self.EXTENSION_NAME
|
||||
if self.offer.requestMaxCompressLevel != 0:
|
||||
pmceString += "; server_max_compress_level=%d" % self.offer.requestMaxCompressLevel
|
||||
if self.requestMaxCompressLevel != 0:
|
||||
pmceString += "; client_max_compress_level=%d" % self.requestMaxCompressLevel
|
||||
return pmceString
|
||||
pmce_string = self.EXTENSION_NAME
|
||||
if self.offer.request_max_compress_level != 0:
|
||||
pmce_string += "; server_max_compress_level=%d" % self.offer.request_max_compress_level
|
||||
if self.request_max_compress_level != 0:
|
||||
pmce_string += "; client_max_compress_level=%d" % self.request_max_compress_level
|
||||
return pmce_string
|
||||
|
||||
def __json__(self):
|
||||
"""
|
||||
Returns a JSON serializable object representation.
|
||||
|
||||
:returns: object -- JSON serializable representation.
|
||||
:returns: JSON serializable representation.
|
||||
:rtype: dict
|
||||
"""
|
||||
return {'extension': self.EXTENSION_NAME,
|
||||
'offer': self.offer.__json__(),
|
||||
'requestMaxCompressLevel': self.requestMaxCompressLevel,
|
||||
'compressLevel': self.compressLevel}
|
||||
'request_max_compress_level': self.request_max_compress_level,
|
||||
'compress_level': self.compress_level}
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
Returns Python object representation that can be eval'ed to reconstruct the object.
|
||||
|
||||
:returns: str -- Python string representation.
|
||||
:returns: Python string representation.
|
||||
:rtype: str
|
||||
"""
|
||||
return "PerMessageBzip2Accept(offer = %s, requestMaxCompressLevel = %s, compressLevel = %s)" % (self.offer.__repr__(), self.requestMaxCompressLevel, self.compressLevel)
|
||||
return "PerMessageBzip2Accept(offer = %s, request_max_compress_level = %s, compress_level = %s)" % (self.offer.__repr__(), self.request_max_compress_level, self.compress_level)
|
||||
|
||||
|
||||
class PerMessageBzip2Response(PerMessageCompressResponse, PerMessageBzip2Mixin):
|
||||
@ -256,7 +259,8 @@ class PerMessageBzip2Response(PerMessageCompressResponse, PerMessageBzip2Mixin):
|
||||
:param params: Output from :func:`autobahn.websocket.WebSocketProtocol._parseExtensionsHeader`.
|
||||
:type params: list
|
||||
|
||||
:returns: object -- A new instance of :class:`autobahn.compress.PerMessageBzip2Response`.
|
||||
:returns: A new instance of :class:`autobahn.compress.PerMessageBzip2Response`.
|
||||
:rtype: obj
|
||||
"""
|
||||
client_max_compress_level = 0
|
||||
server_max_compress_level = 0
|
||||
@ -305,7 +309,8 @@ class PerMessageBzip2Response(PerMessageCompressResponse, PerMessageBzip2Mixin):
|
||||
"""
|
||||
Returns a JSON serializable object representation.
|
||||
|
||||
:returns: object -- JSON serializable representation.
|
||||
:returns: JSON serializable representation.
|
||||
:rtype: dict
|
||||
"""
|
||||
return {'extension': self.EXTENSION_NAME,
|
||||
'client_max_compress_level': self.client_max_compress_level,
|
||||
@ -315,7 +320,8 @@ class PerMessageBzip2Response(PerMessageCompressResponse, PerMessageBzip2Mixin):
|
||||
"""
|
||||
Returns Python object representation that can be eval'ed to reconstruct the object.
|
||||
|
||||
:returns: str -- Python string representation.
|
||||
:returns: Python string representation.
|
||||
:rtype: str
|
||||
"""
|
||||
return "PerMessageBzip2Response(client_max_compress_level = %s, server_max_compress_level = %s)" % (self.client_max_compress_level, self.server_max_compress_level)
|
||||
|
||||
@ -328,46 +334,47 @@ class PerMessageBzip2ResponseAccept(PerMessageCompressResponseAccept, PerMessage
|
||||
|
||||
def __init__(self,
|
||||
response,
|
||||
compressLevel=None):
|
||||
compress_level=None):
|
||||
"""
|
||||
Constructor.
|
||||
|
||||
:param response: The response being accepted.
|
||||
:type response: Instance of :class:`autobahn.compress.PerMessageBzip2Response`.
|
||||
:param compressLevel: Override client ("client-to-server direction") compress level (this must be compatible with response).
|
||||
:type compressLevel: int
|
||||
:param compress_level: Override client ("client-to-server direction") compress level (this must be compatible with response).
|
||||
:type compress_level: int
|
||||
"""
|
||||
if not isinstance(response, PerMessageBzip2Response):
|
||||
raise Exception("invalid type %s for response" % type(response))
|
||||
|
||||
self.response = response
|
||||
|
||||
if compressLevel is not None:
|
||||
if compressLevel not in self.WINDOW_SIZE_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for compressLevel - permissible values %s" % (compressLevel, self.COMPRESS_LEVEL_PERMISSIBLE_VALUES))
|
||||
if compress_level is not None:
|
||||
if compress_level not in self.COMPRESS_LEVEL_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for compress_level - permissible values %s" % (compress_level, self.COMPRESS_LEVEL_PERMISSIBLE_VALUES))
|
||||
|
||||
if response.client_max_compress_level != 0 and compressLevel > response.client_max_compress_level:
|
||||
raise Exception("invalid value %s for compressLevel - server requested lower maximum value" % compressLevel)
|
||||
if response.client_max_compress_level != 0 and compress_level > response.client_max_compress_level:
|
||||
raise Exception("invalid value %s for compress_level - server requested lower maximum value" % compress_level)
|
||||
|
||||
self.compressLevel = compressLevel
|
||||
self.compress_level = compress_level
|
||||
|
||||
def __json__(self):
|
||||
"""
|
||||
Returns a JSON serializable object representation.
|
||||
|
||||
:returns: object -- JSON serializable representation.
|
||||
:returns: JSON serializable representation.
|
||||
:rtype: dict
|
||||
"""
|
||||
return {'extension': self.EXTENSION_NAME,
|
||||
'response': self.response.__json__(),
|
||||
'compressLevel': self.compressLevel}
|
||||
'compress_level': self.compress_level}
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
Returns Python object representation that can be eval'ed to reconstruct the object.
|
||||
|
||||
:returns: str -- Python string representation.
|
||||
:returns: Python string representation.
|
||||
:rtype: str
|
||||
"""
|
||||
return "PerMessageBzip2ResponseAccept(response = %s, compressLevel = %s)" % (self.response.__repr__(), self.compressLevel)
|
||||
return "PerMessageBzip2ResponseAccept(response = %s, compress_level = %s)" % (self.response.__repr__(), self.compress_level)
|
||||
|
||||
|
||||
class PerMessageBzip2(PerMessageCompress, PerMessageBzip2Mixin):
|
||||
@ -377,24 +384,24 @@ class PerMessageBzip2(PerMessageCompress, PerMessageBzip2Mixin):
|
||||
DEFAULT_COMPRESS_LEVEL = 9
|
||||
|
||||
@classmethod
|
||||
def createFromResponseAccept(cls, isServer, accept):
|
||||
pmce = cls(isServer,
|
||||
def create_from_response_accept(cls, is_server, accept):
|
||||
pmce = cls(is_server,
|
||||
accept.response.server_max_compress_level,
|
||||
accept.compressLevel if accept.compressLevel is not None else accept.response.client_max_compress_level)
|
||||
accept.compress_level if accept.compress_level is not None else accept.response.client_max_compress_level)
|
||||
return pmce
|
||||
|
||||
@classmethod
|
||||
def createFromOfferAccept(cls, isServer, accept):
|
||||
pmce = cls(isServer,
|
||||
accept.compressLevel if accept.compressLevel is not None else accept.offer.requestMaxCompressLevel,
|
||||
accept.requestMaxCompressLevel)
|
||||
def create_from_offer_accept(cls, is_server, accept):
|
||||
pmce = cls(is_server,
|
||||
accept.compress_level if accept.compress_level is not None else accept.offer.request_max_compress_level,
|
||||
accept.request_max_compress_level)
|
||||
return pmce
|
||||
|
||||
def __init__(self,
|
||||
isServer,
|
||||
is_server,
|
||||
server_max_compress_level,
|
||||
client_max_compress_level):
|
||||
self._isServer = isServer
|
||||
self._isServer = is_server
|
||||
self._compressor = None
|
||||
self._decompressor = None
|
||||
|
||||
@ -410,7 +417,7 @@ class PerMessageBzip2(PerMessageCompress, PerMessageBzip2Mixin):
|
||||
def __repr__(self):
|
||||
return "PerMessageBzip2(isServer = %s, server_max_compress_level = %s, client_max_compress_level = %s)" % (self._isServer, self.server_max_compress_level, self.client_max_compress_level)
|
||||
|
||||
def startCompressMessage(self):
|
||||
def start_compress_message(self):
|
||||
if self._isServer:
|
||||
if self._compressor is None:
|
||||
self._compressor = bz2.BZ2Compressor(self.server_max_compress_level)
|
||||
@ -418,10 +425,10 @@ class PerMessageBzip2(PerMessageCompress, PerMessageBzip2Mixin):
|
||||
if self._compressor is None:
|
||||
self._compressor = bz2.BZ2Compressor(self.client_max_compress_level)
|
||||
|
||||
def compressMessageData(self, data):
|
||||
def compress_message_data(self, data):
|
||||
return self._compressor.compress(data)
|
||||
|
||||
def endCompressMessage(self):
|
||||
def end_compress_message(self):
|
||||
data = self._compressor.flush()
|
||||
|
||||
# there seems to be no "flush without close stream", and after
|
||||
@ -430,12 +437,12 @@ class PerMessageBzip2(PerMessageCompress, PerMessageBzip2Mixin):
|
||||
|
||||
return data
|
||||
|
||||
def startDecompressMessage(self):
|
||||
def start_decompress_message(self):
|
||||
if self._decompressor is None:
|
||||
self._decompressor = bz2.BZ2Decompressor()
|
||||
|
||||
def decompressMessageData(self, data):
|
||||
def decompress_message_data(self, data):
|
||||
return self._decompressor.decompress(data)
|
||||
|
||||
def endDecompressMessage(self):
|
||||
def end_decompress_message(self):
|
||||
self._decompressor = None
|
||||
|
@ -28,6 +28,7 @@ from __future__ import absolute_import
|
||||
|
||||
import zlib
|
||||
|
||||
from autobahn.util import public
|
||||
from autobahn.websocket.compress_base import PerMessageCompressOffer, \
|
||||
PerMessageCompressOfferAccept, \
|
||||
PerMessageCompressResponse, \
|
||||
@ -51,22 +52,23 @@ class PerMessageDeflateMixin(object):
|
||||
|
||||
EXTENSION_NAME = "permessage-deflate"
|
||||
"""
|
||||
Name of this WebSocket extension.
|
||||
"""
|
||||
Name of this WebSocket extension.
|
||||
"""
|
||||
|
||||
WINDOW_SIZE_PERMISSIBLE_VALUES = [8, 9, 10, 11, 12, 13, 14, 15]
|
||||
"""
|
||||
Permissible value for window size parameter.
|
||||
Higher values use more memory, but produce smaller output. The default is 15.
|
||||
"""
|
||||
Permissible value for window size parameter.
|
||||
Higher values use more memory, but produce smaller output. The default is 15.
|
||||
"""
|
||||
|
||||
MEM_LEVEL_PERMISSIBLE_VALUES = [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
"""
|
||||
Permissible value for memory level parameter.
|
||||
Higher values use more memory, but are faster and produce smaller output. The default is 8.
|
||||
"""
|
||||
Permissible value for memory level parameter.
|
||||
Higher values use more memory, but are faster and produce smaller output. The default is 8.
|
||||
"""
|
||||
|
||||
|
||||
@public
|
||||
class PerMessageDeflateOffer(PerMessageCompressOffer, PerMessageDeflateMixin):
|
||||
"""
|
||||
Set of extension parameters for `permessage-deflate` WebSocket extension
|
||||
@ -81,15 +83,16 @@ class PerMessageDeflateOffer(PerMessageCompressOffer, PerMessageDeflateMixin):
|
||||
:param params: Output from :func:`autobahn.websocket.WebSocketProtocol._parseExtensionsHeader`.
|
||||
:type params: list
|
||||
|
||||
:returns: object -- A new instance of :class:`autobahn.compress.PerMessageDeflateOffer`.
|
||||
:returns: A new instance of :class:`autobahn.compress.PerMessageDeflateOffer`.
|
||||
:rtype: obj
|
||||
"""
|
||||
|
||||
# extension parameter defaults
|
||||
acceptMaxWindowBits = False
|
||||
acceptNoContextTakeover = True
|
||||
# acceptNoContextTakeover = False # FIXME: this may change in draft
|
||||
requestMaxWindowBits = 0
|
||||
requestNoContextTakeover = False
|
||||
accept_max_window_bits = False
|
||||
accept_no_context_takeover = True
|
||||
# accept_no_context_takeover = False # FIXME: this may change in draft
|
||||
request_max_window_bits = 0
|
||||
request_no_context_takeover = False
|
||||
|
||||
# verify/parse client ("client-to-server direction") parameters of permessage-deflate offer
|
||||
for p in params:
|
||||
@ -100,7 +103,7 @@ class PerMessageDeflateOffer(PerMessageCompressOffer, PerMessageDeflateMixin):
|
||||
val = params[p][0]
|
||||
|
||||
if p == 'client_max_window_bits':
|
||||
##
|
||||
#
|
||||
# see: https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-18
|
||||
# 8.1.2.2. client_max_window_bits
|
||||
|
||||
@ -118,17 +121,17 @@ class PerMessageDeflateOffer(PerMessageCompressOffer, PerMessageDeflateMixin):
|
||||
raise Exception("illegal extension parameter value '%s' for parameter '%s' of extension '%s'" % (val, p, cls.EXTENSION_NAME))
|
||||
else:
|
||||
# FIXME (maybe): possibly forward/process the client hint!
|
||||
# acceptMaxWindowBits = val
|
||||
acceptMaxWindowBits = True
|
||||
# accept_max_window_bits = val
|
||||
accept_max_window_bits = True
|
||||
else:
|
||||
acceptMaxWindowBits = True
|
||||
accept_max_window_bits = True
|
||||
|
||||
elif p == 'client_no_context_takeover':
|
||||
# noinspection PySimplifyBooleanCheck
|
||||
if val is not True:
|
||||
raise Exception("illegal extension parameter value '%s' for parameter '%s' of extension '%s'" % (val, p, cls.EXTENSION_NAME))
|
||||
else:
|
||||
acceptNoContextTakeover = True
|
||||
accept_no_context_takeover = True
|
||||
|
||||
elif p == 'server_max_window_bits':
|
||||
try:
|
||||
@ -139,99 +142,103 @@ class PerMessageDeflateOffer(PerMessageCompressOffer, PerMessageDeflateMixin):
|
||||
if val not in PerMessageDeflateMixin.WINDOW_SIZE_PERMISSIBLE_VALUES:
|
||||
raise Exception("illegal extension parameter value '%s' for parameter '%s' of extension '%s'" % (val, p, cls.EXTENSION_NAME))
|
||||
else:
|
||||
requestMaxWindowBits = val
|
||||
request_max_window_bits = val
|
||||
|
||||
elif p == 'server_no_context_takeover':
|
||||
# noinspection PySimplifyBooleanCheck
|
||||
if val is not True:
|
||||
raise Exception("illegal extension parameter value '%s' for parameter '%s' of extension '%s'" % (val, p, cls.EXTENSION_NAME))
|
||||
else:
|
||||
requestNoContextTakeover = True
|
||||
request_no_context_takeover = True
|
||||
|
||||
else:
|
||||
raise Exception("illegal extension parameter '%s' for extension '%s'" % (p, cls.EXTENSION_NAME))
|
||||
|
||||
offer = cls(acceptNoContextTakeover,
|
||||
acceptMaxWindowBits,
|
||||
requestNoContextTakeover,
|
||||
requestMaxWindowBits)
|
||||
offer = cls(accept_no_context_takeover,
|
||||
accept_max_window_bits,
|
||||
request_no_context_takeover,
|
||||
request_max_window_bits)
|
||||
return offer
|
||||
|
||||
def __init__(self,
|
||||
acceptNoContextTakeover=True,
|
||||
acceptMaxWindowBits=True,
|
||||
requestNoContextTakeover=False,
|
||||
requestMaxWindowBits=0):
|
||||
accept_no_context_takeover=True,
|
||||
accept_max_window_bits=True,
|
||||
request_no_context_takeover=False,
|
||||
request_max_window_bits=0):
|
||||
"""
|
||||
Constructor.
|
||||
|
||||
:param acceptNoContextTakeover: Iff true, client accepts "no context takeover" feature.
|
||||
:type acceptNoContextTakeover: bool
|
||||
:param acceptMaxWindowBits: Iff true, client accepts setting "max window size".
|
||||
:type acceptMaxWindowBits: bool
|
||||
:param requestNoContextTakeover: Iff true, client request "no context takeover" feature.
|
||||
:type requestNoContextTakeover: bool
|
||||
:param requestMaxWindowBits: Iff non-zero, client requests given "max window size" - must be 8-15.
|
||||
:type requestMaxWindowBits: int
|
||||
:param accept_no_context_takeover: When ``True``, the client accepts the "no context takeover" feature.
|
||||
:type accept_no_context_takeover: bool
|
||||
:param accept_max_window_bits: When ``True``, the client accepts setting "max window size".
|
||||
:type accept_max_window_bits: bool
|
||||
:param request_no_context_takeover: When ``True``, the client request the "no context takeover" feature.
|
||||
:type request_no_context_takeover: bool
|
||||
:param request_max_window_bits: When non-zero, the client requests the given "max window size" (must be
|
||||
and integer from the interval ``[8..15]``).
|
||||
:type request_max_window_bits: int
|
||||
"""
|
||||
if type(acceptNoContextTakeover) != bool:
|
||||
raise Exception("invalid type %s for acceptNoContextTakeover" % type(acceptNoContextTakeover))
|
||||
if type(accept_no_context_takeover) != bool:
|
||||
raise Exception("invalid type %s for accept_no_context_takeover" % type(accept_no_context_takeover))
|
||||
|
||||
self.acceptNoContextTakeover = acceptNoContextTakeover
|
||||
self.accept_no_context_takeover = accept_no_context_takeover
|
||||
|
||||
if type(acceptMaxWindowBits) != bool:
|
||||
raise Exception("invalid type %s for acceptMaxWindowBits" % type(acceptMaxWindowBits))
|
||||
if type(accept_max_window_bits) != bool:
|
||||
raise Exception("invalid type %s for accept_max_window_bits" % type(accept_max_window_bits))
|
||||
|
||||
self.acceptMaxWindowBits = acceptMaxWindowBits
|
||||
self.accept_max_window_bits = accept_max_window_bits
|
||||
|
||||
if type(requestNoContextTakeover) != bool:
|
||||
raise Exception("invalid type %s for requestNoContextTakeover" % type(requestNoContextTakeover))
|
||||
if type(request_no_context_takeover) != bool:
|
||||
raise Exception("invalid type %s for request_no_context_takeover" % type(request_no_context_takeover))
|
||||
|
||||
self.requestNoContextTakeover = requestNoContextTakeover
|
||||
self.request_no_context_takeover = request_no_context_takeover
|
||||
|
||||
if requestMaxWindowBits != 0 and requestMaxWindowBits not in self.WINDOW_SIZE_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for requestMaxWindowBits - permissible values %s" % (requestMaxWindowBits, self.WINDOW_SIZE_PERMISSIBLE_VALUES))
|
||||
if request_max_window_bits != 0 and request_max_window_bits not in self.WINDOW_SIZE_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for request_max_window_bits - permissible values %s" % (request_max_window_bits, self.WINDOW_SIZE_PERMISSIBLE_VALUES))
|
||||
|
||||
self.requestMaxWindowBits = requestMaxWindowBits
|
||||
self.request_max_window_bits = request_max_window_bits
|
||||
|
||||
def getExtensionString(self):
|
||||
def get_extension_string(self):
|
||||
"""
|
||||
Returns the WebSocket extension configuration string as sent to the server.
|
||||
|
||||
:returns: str -- PMCE configuration string.
|
||||
:returns: PMCE configuration string.
|
||||
:rtype: str
|
||||
"""
|
||||
pmceString = self.EXTENSION_NAME
|
||||
if self.acceptNoContextTakeover:
|
||||
pmceString += "; client_no_context_takeover"
|
||||
if self.acceptMaxWindowBits:
|
||||
pmceString += "; client_max_window_bits"
|
||||
if self.requestNoContextTakeover:
|
||||
pmceString += "; server_no_context_takeover"
|
||||
if self.requestMaxWindowBits != 0:
|
||||
pmceString += "; server_max_window_bits=%d" % self.requestMaxWindowBits
|
||||
return pmceString
|
||||
pmce_string = self.EXTENSION_NAME
|
||||
if self.accept_no_context_takeover:
|
||||
pmce_string += "; client_no_context_takeover"
|
||||
if self.accept_max_window_bits:
|
||||
pmce_string += "; client_max_window_bits"
|
||||
if self.request_no_context_takeover:
|
||||
pmce_string += "; server_no_context_takeover"
|
||||
if self.request_max_window_bits != 0:
|
||||
pmce_string += "; server_max_window_bits=%d" % self.request_max_window_bits
|
||||
return pmce_string
|
||||
|
||||
def __json__(self):
|
||||
"""
|
||||
Returns a JSON serializable object representation.
|
||||
|
||||
:returns: object -- JSON serializable representation.
|
||||
:returns: JSON serializable representation.
|
||||
:rtype: dict
|
||||
"""
|
||||
return {'extension': self.EXTENSION_NAME,
|
||||
'acceptNoContextTakeover': self.acceptNoContextTakeover,
|
||||
'acceptMaxWindowBits': self.acceptMaxWindowBits,
|
||||
'requestNoContextTakeover': self.requestNoContextTakeover,
|
||||
'requestMaxWindowBits': self.requestMaxWindowBits}
|
||||
'accept_no_context_takeover': self.accept_no_context_takeover,
|
||||
'accept_max_window_bits': self.accept_max_window_bits,
|
||||
'request_no_context_takeover': self.request_no_context_takeover,
|
||||
'request_max_window_bits': self.request_max_window_bits}
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
Returns Python object representation that can be eval'ed to reconstruct the object.
|
||||
|
||||
:returns: str -- Python string representation.
|
||||
:returns: Python string representation.
|
||||
:rtype: str
|
||||
"""
|
||||
return "PerMessageDeflateOffer(acceptNoContextTakeover = %s, acceptMaxWindowBits = %s, requestNoContextTakeover = %s, requestMaxWindowBits = %s)" % (self.acceptNoContextTakeover, self.acceptMaxWindowBits, self.requestNoContextTakeover, self.requestMaxWindowBits)
|
||||
return "PerMessageDeflateOffer(accept_no_context_takeover = %s, accept_max_window_bits = %s, request_no_context_takeover = %s, request_max_window_bits = %s)" % (self.accept_no_context_takeover, self.accept_max_window_bits, self.request_no_context_takeover, self.request_max_window_bits)
|
||||
|
||||
|
||||
@public
|
||||
class PerMessageDeflateOfferAccept(PerMessageCompressOfferAccept, PerMessageDeflateMixin):
|
||||
"""
|
||||
Set of parameters with which to accept an `permessage-deflate` offer
|
||||
@ -240,112 +247,118 @@ class PerMessageDeflateOfferAccept(PerMessageCompressOfferAccept, PerMessageDefl
|
||||
|
||||
def __init__(self,
|
||||
offer,
|
||||
requestNoContextTakeover=False,
|
||||
requestMaxWindowBits=0,
|
||||
noContextTakeover=None,
|
||||
windowBits=None,
|
||||
memLevel=None):
|
||||
request_no_context_takeover=False,
|
||||
request_max_window_bits=0,
|
||||
no_context_takeover=None,
|
||||
window_bits=None,
|
||||
mem_level=None):
|
||||
"""
|
||||
Constructor.
|
||||
|
||||
:param offer: The offer being accepted.
|
||||
:type offer: Instance of :class:`autobahn.compress.PerMessageDeflateOffer`.
|
||||
:param requestNoContextTakeover: Iff true, server request "no context takeover" feature.
|
||||
:type requestNoContextTakeover: bool
|
||||
:param requestMaxCompressLevel: Iff non-zero, server requests given "maximum compression level" - must be 1-9.
|
||||
:type requestMaxCompressLevel: int
|
||||
:param noContextTakeover: Override server ("server-to-client direction") context takeover (this must be compatible with offer).
|
||||
:type noContextTakeover: bool
|
||||
:param windowBits: Override server ("server-to-client direction") window size (this must be compatible with offer).
|
||||
:type windowBits: int
|
||||
:param memLevel: Set server ("server-to-client direction") memory level.
|
||||
:type memLevel: int
|
||||
:param request_no_context_takeover: When ``True``, the server requests the "no context takeover" feature.
|
||||
:type request_no_context_takeover: bool
|
||||
:param request_max_window_bits: When non-zero, the server requests the given "max window size" (must be
|
||||
and integer from the interval ``[8..15]``).
|
||||
:param request_max_window_bits: int
|
||||
:param no_context_takeover: Override server ("server-to-client direction") context takeover (this must
|
||||
be compatible with the offer).
|
||||
:type no_context_takeover: bool
|
||||
:param window_bits: Override server ("server-to-client direction") window size (this must be
|
||||
compatible with the offer).
|
||||
:type window_bits: int
|
||||
:param mem_level: Set server ("server-to-client direction") memory level.
|
||||
:type mem_level: int
|
||||
"""
|
||||
if not isinstance(offer, PerMessageDeflateOffer):
|
||||
raise Exception("invalid type %s for offer" % type(offer))
|
||||
|
||||
self.offer = offer
|
||||
|
||||
if type(requestNoContextTakeover) != bool:
|
||||
raise Exception("invalid type %s for requestNoContextTakeover" % type(requestNoContextTakeover))
|
||||
if type(request_no_context_takeover) != bool:
|
||||
raise Exception("invalid type %s for request_no_context_takeover" % type(request_no_context_takeover))
|
||||
|
||||
if requestNoContextTakeover and not offer.acceptNoContextTakeover:
|
||||
raise Exception("invalid value %s for requestNoContextTakeover - feature unsupported by client" % requestNoContextTakeover)
|
||||
if request_no_context_takeover and not offer.accept_no_context_takeover:
|
||||
raise Exception("invalid value %s for request_no_context_takeover - feature unsupported by client" % request_no_context_takeover)
|
||||
|
||||
self.requestNoContextTakeover = requestNoContextTakeover
|
||||
self.request_no_context_takeover = request_no_context_takeover
|
||||
|
||||
if requestMaxWindowBits != 0 and requestMaxWindowBits not in self.WINDOW_SIZE_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for requestMaxWindowBits - permissible values %s" % (requestMaxWindowBits, self.WINDOW_SIZE_PERMISSIBLE_VALUES))
|
||||
if request_max_window_bits != 0 and request_max_window_bits not in self.WINDOW_SIZE_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for request_max_window_bits - permissible values %s" % (request_max_window_bits, self.WINDOW_SIZE_PERMISSIBLE_VALUES))
|
||||
|
||||
if requestMaxWindowBits != 0 and not offer.acceptMaxWindowBits:
|
||||
raise Exception("invalid value %s for requestMaxWindowBits - feature unsupported by client" % requestMaxWindowBits)
|
||||
if request_max_window_bits != 0 and not offer.accept_max_window_bits:
|
||||
raise Exception("invalid value %s for request_max_window_bits - feature unsupported by client" % request_max_window_bits)
|
||||
|
||||
self.requestMaxWindowBits = requestMaxWindowBits
|
||||
self.request_max_window_bits = request_max_window_bits
|
||||
|
||||
if noContextTakeover is not None:
|
||||
if type(noContextTakeover) != bool:
|
||||
raise Exception("invalid type %s for noContextTakeover" % type(noContextTakeover))
|
||||
if no_context_takeover is not None:
|
||||
if type(no_context_takeover) != bool:
|
||||
raise Exception("invalid type %s for no_context_takeover" % type(no_context_takeover))
|
||||
|
||||
if offer.requestNoContextTakeover and not noContextTakeover:
|
||||
raise Exception("invalid value %s for noContextTakeover - client requested feature" % noContextTakeover)
|
||||
if offer.request_no_context_takeover and not no_context_takeover:
|
||||
raise Exception("invalid value %s for no_context_takeover - client requested feature" % no_context_takeover)
|
||||
|
||||
self.noContextTakeover = noContextTakeover
|
||||
self.no_context_takeover = no_context_takeover
|
||||
|
||||
if windowBits is not None:
|
||||
if windowBits not in self.WINDOW_SIZE_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for windowBits - permissible values %s" % (windowBits, self.WINDOW_SIZE_PERMISSIBLE_VALUES))
|
||||
if window_bits is not None:
|
||||
if window_bits not in self.WINDOW_SIZE_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for window_bits - permissible values %s" % (window_bits, self.WINDOW_SIZE_PERMISSIBLE_VALUES))
|
||||
|
||||
if offer.requestMaxWindowBits != 0 and windowBits > offer.requestMaxWindowBits:
|
||||
raise Exception("invalid value %s for windowBits - client requested lower maximum value" % windowBits)
|
||||
if offer.request_max_window_bits != 0 and window_bits > offer.request_max_window_bits:
|
||||
raise Exception("invalid value %s for window_bits - client requested lower maximum value" % window_bits)
|
||||
|
||||
self.windowBits = windowBits
|
||||
self.window_bits = window_bits
|
||||
|
||||
if memLevel is not None:
|
||||
if memLevel not in self.MEM_LEVEL_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for memLevel - permissible values %s" % (memLevel, self.MEM_LEVEL_PERMISSIBLE_VALUES))
|
||||
if mem_level is not None:
|
||||
if mem_level not in self.MEM_LEVEL_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for mem_level - permissible values %s" % (mem_level, self.MEM_LEVEL_PERMISSIBLE_VALUES))
|
||||
|
||||
self.memLevel = memLevel
|
||||
self.mem_level = mem_level
|
||||
|
||||
def getExtensionString(self):
|
||||
def get_extension_string(self):
|
||||
"""
|
||||
Returns the WebSocket extension configuration string as sent to the server.
|
||||
|
||||
:returns: str -- PMCE configuration string.
|
||||
:returns: PMCE configuration string.
|
||||
:rtype: str
|
||||
"""
|
||||
pmceString = self.EXTENSION_NAME
|
||||
if self.offer.requestNoContextTakeover:
|
||||
pmceString += "; server_no_context_takeover"
|
||||
if self.offer.requestMaxWindowBits != 0:
|
||||
pmceString += "; server_max_window_bits=%d" % self.offer.requestMaxWindowBits
|
||||
if self.requestNoContextTakeover:
|
||||
pmceString += "; client_no_context_takeover"
|
||||
if self.requestMaxWindowBits != 0:
|
||||
pmceString += "; client_max_window_bits=%d" % self.requestMaxWindowBits
|
||||
return pmceString
|
||||
pmce_string = self.EXTENSION_NAME
|
||||
if self.offer.request_no_context_takeover:
|
||||
pmce_string += "; server_no_context_takeover"
|
||||
if self.offer.request_max_window_bits != 0:
|
||||
pmce_string += "; server_max_window_bits=%d" % self.offer.request_max_window_bits
|
||||
if self.request_no_context_takeover:
|
||||
pmce_string += "; client_no_context_takeover"
|
||||
if self.request_max_window_bits != 0:
|
||||
pmce_string += "; client_max_window_bits=%d" % self.request_max_window_bits
|
||||
return pmce_string
|
||||
|
||||
def __json__(self):
|
||||
"""
|
||||
Returns a JSON serializable object representation.
|
||||
|
||||
:returns: object -- JSON serializable representation.
|
||||
:returns: JSON serializable representation.
|
||||
:rtype: dict
|
||||
"""
|
||||
return {'extension': self.EXTENSION_NAME,
|
||||
'offer': self.offer.__json__(),
|
||||
'requestNoContextTakeover': self.requestNoContextTakeover,
|
||||
'requestMaxWindowBits': self.requestMaxWindowBits,
|
||||
'noContextTakeover': self.noContextTakeover,
|
||||
'windowBits': self.windowBits,
|
||||
'memLevel': self.memLevel}
|
||||
'request_no_context_takeover': self.request_no_context_takeover,
|
||||
'request_max_window_bits': self.request_max_window_bits,
|
||||
'no_context_takeover': self.no_context_takeover,
|
||||
'window_bits': self.window_bits,
|
||||
'mem_level': self.mem_level}
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
Returns Python object representation that can be eval'ed to reconstruct the object.
|
||||
|
||||
:returns: str -- Python string representation.
|
||||
:returns: Python string representation.
|
||||
:rtype: str
|
||||
"""
|
||||
return "PerMessageDeflateOfferAccept(offer = %s, requestNoContextTakeover = %s, requestMaxWindowBits = %s, noContextTakeover = %s, windowBits = %s, memLevel = %s)" % (self.offer.__repr__(), self.requestNoContextTakeover, self.requestMaxWindowBits, self.noContextTakeover, self.windowBits, self.memLevel)
|
||||
return "PerMessageDeflateOfferAccept(offer = %s, request_no_context_takeover = %s, request_max_window_bits = %s, no_context_takeover = %s, window_bits = %s, mem_level = %s)" % (self.offer.__repr__(), self.request_no_context_takeover, self.request_max_window_bits, self.no_context_takeover, self.window_bits, self.mem_level)
|
||||
|
||||
|
||||
@public
|
||||
class PerMessageDeflateResponse(PerMessageCompressResponse, PerMessageDeflateMixin):
|
||||
"""
|
||||
Set of parameters for `permessage-deflate` responded by server.
|
||||
@ -359,7 +372,8 @@ class PerMessageDeflateResponse(PerMessageCompressResponse, PerMessageDeflateMix
|
||||
:param params: Output from :func:`autobahn.websocket.WebSocketProtocol._parseExtensionsHeader`.
|
||||
:type params: list
|
||||
|
||||
:returns: object -- A new instance of :class:`autobahn.compress.PerMessageDeflateResponse`.
|
||||
:returns: A new instance of :class:`autobahn.compress.PerMessageDeflateResponse`.
|
||||
:rtype: obj
|
||||
"""
|
||||
client_max_window_bits = 0
|
||||
client_no_context_takeover = False
|
||||
@ -423,6 +437,17 @@ class PerMessageDeflateResponse(PerMessageCompressResponse, PerMessageDeflateMix
|
||||
client_no_context_takeover,
|
||||
server_max_window_bits,
|
||||
server_no_context_takeover):
|
||||
"""
|
||||
|
||||
:param client_max_window_bits: FIXME
|
||||
:type client_max_window_bits: int
|
||||
:param client_no_context_takeover: FIXME
|
||||
:type client_no_context_takeover: bool
|
||||
:param server_max_window_bits: FIXME
|
||||
:type server_max_window_bits: int
|
||||
:param server_no_context_takeover: FIXME
|
||||
:type server_no_context_takeover: bool
|
||||
"""
|
||||
self.client_max_window_bits = client_max_window_bits
|
||||
self.client_no_context_takeover = client_no_context_takeover
|
||||
self.server_max_window_bits = server_max_window_bits
|
||||
@ -432,7 +457,8 @@ class PerMessageDeflateResponse(PerMessageCompressResponse, PerMessageDeflateMix
|
||||
"""
|
||||
Returns a JSON serializable object representation.
|
||||
|
||||
:returns: object -- JSON serializable representation.
|
||||
:returns: JSON serializable representation.
|
||||
:rtype: dict
|
||||
"""
|
||||
return {'extension': self.EXTENSION_NAME,
|
||||
'client_max_window_bits': self.client_max_window_bits,
|
||||
@ -444,11 +470,13 @@ class PerMessageDeflateResponse(PerMessageCompressResponse, PerMessageDeflateMix
|
||||
"""
|
||||
Returns Python object representation that can be eval'ed to reconstruct the object.
|
||||
|
||||
:returns: str -- Python string representation.
|
||||
:returns: Python string representation.
|
||||
:rtype: str
|
||||
"""
|
||||
return "PerMessageDeflateResponse(client_max_window_bits = %s, client_no_context_takeover = %s, server_max_window_bits = %s, server_no_context_takeover = %s)" % (self.client_max_window_bits, self.client_no_context_takeover, self.server_max_window_bits, self.server_no_context_takeover)
|
||||
|
||||
|
||||
@public
|
||||
class PerMessageDeflateResponseAccept(PerMessageCompressResponseAccept, PerMessageDeflateMixin):
|
||||
"""
|
||||
Set of parameters with which to accept an `permessage-deflate` response
|
||||
@ -457,69 +485,70 @@ class PerMessageDeflateResponseAccept(PerMessageCompressResponseAccept, PerMessa
|
||||
|
||||
def __init__(self,
|
||||
response,
|
||||
noContextTakeover=None,
|
||||
windowBits=None,
|
||||
memLevel=None):
|
||||
no_context_takeover=None,
|
||||
window_bits=None,
|
||||
mem_level=None):
|
||||
"""
|
||||
Constructor.
|
||||
|
||||
:param response: The response being accepted.
|
||||
:type response: Instance of :class:`autobahn.compress.PerMessageDeflateResponse`.
|
||||
:param noContextTakeover: Override client ("client-to-server direction") context takeover (this must be compatible with response).
|
||||
:type noContextTakeover: bool
|
||||
:param windowBits: Override client ("client-to-server direction") window size (this must be compatible with response).
|
||||
:type windowBits: int
|
||||
:param memLevel: Set client ("client-to-server direction") memory level.
|
||||
:type memLevel: int
|
||||
:param no_context_takeover: Override client ("client-to-server direction") context takeover (this must be compatible with response).
|
||||
:type no_context_takeover: bool
|
||||
:param window_bits: Override client ("client-to-server direction") window size (this must be compatible with response).
|
||||
:type window_bits: int
|
||||
:param mem_level: Set client ("client-to-server direction") memory level.
|
||||
:type mem_level: int
|
||||
"""
|
||||
if not isinstance(response, PerMessageDeflateResponse):
|
||||
raise Exception("invalid type %s for response" % type(response))
|
||||
|
||||
self.response = response
|
||||
|
||||
if noContextTakeover is not None:
|
||||
if type(noContextTakeover) != bool:
|
||||
raise Exception("invalid type %s for noContextTakeover" % type(noContextTakeover))
|
||||
if no_context_takeover is not None:
|
||||
if type(no_context_takeover) != bool:
|
||||
raise Exception("invalid type %s for no_context_takeover" % type(no_context_takeover))
|
||||
|
||||
if response.client_no_context_takeover and not noContextTakeover:
|
||||
raise Exception("invalid value %s for noContextTakeover - server requested feature" % noContextTakeover)
|
||||
if response.client_no_context_takeover and not no_context_takeover:
|
||||
raise Exception("invalid value %s for no_context_takeover - server requested feature" % no_context_takeover)
|
||||
|
||||
self.noContextTakeover = noContextTakeover
|
||||
self.no_context_takeover = no_context_takeover
|
||||
|
||||
if windowBits is not None:
|
||||
if windowBits not in self.WINDOW_SIZE_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for windowBits - permissible values %s" % (windowBits, self.WINDOW_SIZE_PERMISSIBLE_VALUES))
|
||||
if window_bits is not None:
|
||||
if window_bits not in self.WINDOW_SIZE_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for window_bits - permissible values %s" % (window_bits, self.WINDOW_SIZE_PERMISSIBLE_VALUES))
|
||||
|
||||
if response.client_max_window_bits != 0 and windowBits > response.client_max_window_bits:
|
||||
raise Exception("invalid value %s for windowBits - server requested lower maximum value" % windowBits)
|
||||
if response.client_max_window_bits != 0 and window_bits > response.client_max_window_bits:
|
||||
raise Exception("invalid value %s for window_bits - server requested lower maximum value" % window_bits)
|
||||
|
||||
self.windowBits = windowBits
|
||||
self.window_bits = window_bits
|
||||
|
||||
if memLevel is not None:
|
||||
if memLevel not in self.MEM_LEVEL_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for memLevel - permissible values %s" % (memLevel, self.MEM_LEVEL_PERMISSIBLE_VALUES))
|
||||
if mem_level is not None:
|
||||
if mem_level not in self.MEM_LEVEL_PERMISSIBLE_VALUES:
|
||||
raise Exception("invalid value %s for mem_level - permissible values %s" % (mem_level, self.MEM_LEVEL_PERMISSIBLE_VALUES))
|
||||
|
||||
self.memLevel = memLevel
|
||||
self.mem_level = mem_level
|
||||
|
||||
def __json__(self):
|
||||
"""
|
||||
Returns a JSON serializable object representation.
|
||||
|
||||
:returns: object -- JSON serializable representation.
|
||||
:returns: JSON serializable representation.
|
||||
:rtype: dict
|
||||
"""
|
||||
return {'extension': self.EXTENSION_NAME,
|
||||
'response': self.response.__json__(),
|
||||
'noContextTakeover': self.noContextTakeover,
|
||||
'windowBits': self.windowBits,
|
||||
'memLevel': self.memLevel}
|
||||
'no_context_takeover': self.no_context_takeover,
|
||||
'window_bits': self.window_bits,
|
||||
'mem_level': self.mem_level}
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
Returns Python object representation that can be eval'ed to reconstruct the object.
|
||||
|
||||
:returns: str -- Python string representation.
|
||||
:returns: Python string representation.
|
||||
:rtype: str
|
||||
"""
|
||||
return "PerMessageDeflateResponseAccept(response = %s, noContextTakeover = %s, windowBits = %s, memLevel = %s)" % (self.response.__repr__(), self.noContextTakeover, self.windowBits, self.memLevel)
|
||||
return "PerMessageDeflateResponseAccept(response = %s, no_context_takeover = %s, window_bits = %s, mem_level = %s)" % (self.response.__repr__(), self.no_context_takeover, self.window_bits, self.mem_level)
|
||||
|
||||
|
||||
# noinspection PyArgumentList
|
||||
@ -531,35 +560,35 @@ class PerMessageDeflate(PerMessageCompress, PerMessageDeflateMixin):
|
||||
DEFAULT_MEM_LEVEL = 8
|
||||
|
||||
@classmethod
|
||||
def createFromResponseAccept(cls, isServer, accept):
|
||||
def create_from_response_accept(cls, is_server, accept):
|
||||
# accept: instance of PerMessageDeflateResponseAccept
|
||||
pmce = cls(isServer,
|
||||
pmce = cls(is_server,
|
||||
accept.response.server_no_context_takeover,
|
||||
accept.noContextTakeover if accept.noContextTakeover is not None else accept.response.client_no_context_takeover,
|
||||
accept.no_context_takeover if accept.no_context_takeover is not None else accept.response.client_no_context_takeover,
|
||||
accept.response.server_max_window_bits,
|
||||
accept.windowBits if accept.windowBits is not None else accept.response.client_max_window_bits,
|
||||
accept.window_bits if accept.window_bits is not None else accept.response.client_max_window_bits,
|
||||
accept.memLevel)
|
||||
return pmce
|
||||
|
||||
@classmethod
|
||||
def createFromOfferAccept(cls, isServer, accept):
|
||||
def create_from_offer_accept(cls, is_server, accept):
|
||||
# accept: instance of PerMessageDeflateOfferAccept
|
||||
pmce = cls(isServer,
|
||||
accept.noContextTakeover if accept.noContextTakeover is not None else accept.offer.requestNoContextTakeover,
|
||||
accept.requestNoContextTakeover,
|
||||
accept.windowBits if accept.windowBits is not None else accept.offer.requestMaxWindowBits,
|
||||
pmce = cls(is_server,
|
||||
accept.no_context_takeover if accept.no_context_takeover is not None else accept.offer.request_no_context_takeover,
|
||||
accept.request_no_context_takeover,
|
||||
accept.window_bits if accept.window_bits is not None else accept.offer.requestMaxWindowBits,
|
||||
accept.requestMaxWindowBits,
|
||||
accept.memLevel)
|
||||
return pmce
|
||||
|
||||
def __init__(self,
|
||||
isServer,
|
||||
is_server,
|
||||
server_no_context_takeover,
|
||||
client_no_context_takeover,
|
||||
server_max_window_bits,
|
||||
client_max_window_bits,
|
||||
mem_level):
|
||||
self._isServer = isServer
|
||||
self._is_server = is_server
|
||||
|
||||
self.server_no_context_takeover = server_no_context_takeover
|
||||
self.client_no_context_takeover = client_no_context_takeover
|
||||
@ -574,7 +603,7 @@ class PerMessageDeflate(PerMessageCompress, PerMessageDeflateMixin):
|
||||
|
||||
def __json__(self):
|
||||
return {'extension': self.EXTENSION_NAME,
|
||||
'isServer': self._isServer,
|
||||
'is_server': self._is_server,
|
||||
'server_no_context_takeover': self.server_no_context_takeover,
|
||||
'client_no_context_takeover': self.client_no_context_takeover,
|
||||
'server_max_window_bits': self.server_max_window_bits,
|
||||
@ -582,38 +611,38 @@ class PerMessageDeflate(PerMessageCompress, PerMessageDeflateMixin):
|
||||
'mem_level': self.mem_level}
|
||||
|
||||
def __repr__(self):
|
||||
return "PerMessageDeflate(isServer = %s, server_no_context_takeover = %s, client_no_context_takeover = %s, server_max_window_bits = %s, client_max_window_bits = %s, mem_level = %s)" % (self._isServer, self.server_no_context_takeover, self.client_no_context_takeover, self.server_max_window_bits, self.client_max_window_bits, self.mem_level)
|
||||
return "PerMessageDeflate(is_server = %s, server_no_context_takeover = %s, client_no_context_takeover = %s, server_max_window_bits = %s, client_max_window_bits = %s, mem_level = %s)" % (self._is_server, self.server_no_context_takeover, self.client_no_context_takeover, self.server_max_window_bits, self.client_max_window_bits, self.mem_level)
|
||||
|
||||
def startCompressMessage(self):
|
||||
def start_compress_message(self):
|
||||
# compressobj([level[, method[, wbits[, memlevel[, strategy]]]]])
|
||||
# http://bugs.python.org/issue19278
|
||||
# http://hg.python.org/cpython/rev/c54c8e71b79a
|
||||
if self._isServer:
|
||||
if self._is_server:
|
||||
if self._compressor is None or self.server_no_context_takeover:
|
||||
self._compressor = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -self.server_max_window_bits, self.mem_level)
|
||||
else:
|
||||
if self._compressor is None or self.client_no_context_takeover:
|
||||
self._compressor = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -self.client_max_window_bits, self.mem_level)
|
||||
|
||||
def compressMessageData(self, data):
|
||||
def compress_message_data(self, data):
|
||||
return self._compressor.compress(data)
|
||||
|
||||
def endCompressMessage(self):
|
||||
def end_compress_message(self):
|
||||
data = self._compressor.flush(zlib.Z_SYNC_FLUSH)
|
||||
return data[:-4]
|
||||
|
||||
def startDecompressMessage(self):
|
||||
if self._isServer:
|
||||
def start_decompress_message(self):
|
||||
if self._is_server:
|
||||
if self._decompressor is None or self.client_no_context_takeover:
|
||||
self._decompressor = zlib.decompressobj(-self.client_max_window_bits)
|
||||
else:
|
||||
if self._decompressor is None or self.server_no_context_takeover:
|
||||
self._decompressor = zlib.decompressobj(-self.server_max_window_bits)
|
||||
|
||||
def decompressMessageData(self, data):
|
||||
def decompress_message_data(self, data):
|
||||
return self._decompressor.decompress(data)
|
||||
|
||||
def endDecompressMessage(self):
|
||||
def end_decompress_message(self):
|
||||
# Eat stripped LEN and NLEN field of a non-compressed block added
|
||||
# for Z_SYNC_FLUSH.
|
||||
self._decompressor.decompress(b'\x00\x00\xff\xff')
|
||||
|
@ -51,8 +51,8 @@ class PerMessageSnappyMixin(object):
|
||||
|
||||
EXTENSION_NAME = "permessage-snappy"
|
||||
"""
|
||||
Name of this WebSocket extension.
|
||||
"""
|
||||
Name of this WebSocket extension.
|
||||
"""
|
||||
|
||||
|
||||
class PerMessageSnappyOffer(PerMessageCompressOffer, PerMessageSnappyMixin):
|
||||
@ -69,16 +69,14 @@ class PerMessageSnappyOffer(PerMessageCompressOffer, PerMessageSnappyMixin):
|
||||
:param params: Output from :func:`autobahn.websocket.WebSocketProtocol._parseExtensionsHeader`.
|
||||
:type params: list
|
||||
|
||||
:returns: object -- A new instance of :class:`autobahn.compress.PerMessageSnappyOffer`.
|
||||
:returns: A new instance of :class:`autobahn.compress.PerMessageSnappyOffer`.
|
||||
:rtype: obj
|
||||
"""
|
||||
# extension parameter defaults
|
||||
##
|
||||
acceptNoContextTakeover = False
|
||||
requestNoContextTakeover = False
|
||||
accept_no_context_takeover = False
|
||||
request_no_context_takeover = False
|
||||
|
||||
##
|
||||
# verify/parse client ("client-to-server direction") parameters of permessage-snappy offer
|
||||
##
|
||||
for p in params:
|
||||
|
||||
if len(params[p]) > 1:
|
||||
@ -91,73 +89,75 @@ class PerMessageSnappyOffer(PerMessageCompressOffer, PerMessageSnappyMixin):
|
||||
if val is not True:
|
||||
raise Exception("illegal extension parameter value '%s' for parameter '%s' of extension '%s'" % (val, p, cls.EXTENSION_NAME))
|
||||
else:
|
||||
acceptNoContextTakeover = True
|
||||
accept_no_context_takeover = True
|
||||
|
||||
elif p == 'server_no_context_takeover':
|
||||
# noinspection PySimplifyBooleanCheck
|
||||
if val is not True:
|
||||
raise Exception("illegal extension parameter value '%s' for parameter '%s' of extension '%s'" % (val, p, cls.EXTENSION_NAME))
|
||||
else:
|
||||
requestNoContextTakeover = True
|
||||
request_no_context_takeover = True
|
||||
|
||||
else:
|
||||
raise Exception("illegal extension parameter '%s' for extension '%s'" % (p, cls.EXTENSION_NAME))
|
||||
|
||||
offer = cls(acceptNoContextTakeover,
|
||||
requestNoContextTakeover)
|
||||
offer = cls(accept_no_context_takeover,
|
||||
request_no_context_takeover)
|
||||
return offer
|
||||
|
||||
def __init__(self,
|
||||
acceptNoContextTakeover=True,
|
||||
requestNoContextTakeover=False):
|
||||
accept_no_context_takeover=True,
|
||||
request_no_context_takeover=False):
|
||||
"""
|
||||
Constructor.
|
||||
|
||||
:param acceptNoContextTakeover: Iff true, client accepts "no context takeover" feature.
|
||||
:type acceptNoContextTakeover: bool
|
||||
:param requestNoContextTakeover: Iff true, client request "no context takeover" feature.
|
||||
:type requestNoContextTakeover: bool
|
||||
:param accept_no_context_takeover: Iff true, client accepts "no context takeover" feature.
|
||||
:type accept_no_context_takeover: bool
|
||||
:param request_no_context_takeover: Iff true, client request "no context takeover" feature.
|
||||
:type request_no_context_takeover: bool
|
||||
"""
|
||||
if type(acceptNoContextTakeover) != bool:
|
||||
raise Exception("invalid type %s for acceptNoContextTakeover" % type(acceptNoContextTakeover))
|
||||
if type(accept_no_context_takeover) != bool:
|
||||
raise Exception("invalid type %s for accept_no_context_takeover" % type(accept_no_context_takeover))
|
||||
|
||||
self.acceptNoContextTakeover = acceptNoContextTakeover
|
||||
self.accept_no_context_takeover = accept_no_context_takeover
|
||||
|
||||
if type(requestNoContextTakeover) != bool:
|
||||
raise Exception("invalid type %s for requestNoContextTakeover" % type(requestNoContextTakeover))
|
||||
if type(request_no_context_takeover) != bool:
|
||||
raise Exception("invalid type %s for request_no_context_takeover" % type(request_no_context_takeover))
|
||||
|
||||
self.requestNoContextTakeover = requestNoContextTakeover
|
||||
self.request_no_context_takeover = request_no_context_takeover
|
||||
|
||||
def getExtensionString(self):
|
||||
def get_extension_string(self):
|
||||
"""
|
||||
Returns the WebSocket extension configuration string as sent to the server.
|
||||
|
||||
:returns: str -- PMCE configuration string.
|
||||
:returns: PMCE configuration string.
|
||||
:rtype: str
|
||||
"""
|
||||
pmceString = self.EXTENSION_NAME
|
||||
if self.acceptNoContextTakeover:
|
||||
pmceString += "; client_no_context_takeover"
|
||||
if self.requestNoContextTakeover:
|
||||
pmceString += "; server_no_context_takeover"
|
||||
return pmceString
|
||||
pmce_string = self.EXTENSION_NAME
|
||||
if self.accept_no_context_takeover:
|
||||
pmce_string += "; client_no_context_takeover"
|
||||
if self.request_no_context_takeover:
|
||||
pmce_string += "; server_no_context_takeover"
|
||||
return pmce_string
|
||||
|
||||
def __json__(self):
|
||||
"""
|
||||
Returns a JSON serializable object representation.
|
||||
|
||||
:returns: object -- JSON serializable representation.
|
||||
:returns: JSON serializable representation.
|
||||
:rtype: dict
|
||||
"""
|
||||
return {'extension': self.EXTENSION_NAME,
|
||||
'acceptNoContextTakeover': self.acceptNoContextTakeover,
|
||||
'requestNoContextTakeover': self.requestNoContextTakeover}
|
||||
'accept_no_context_takeover': self.accept_no_context_takeover,
|
||||
'request_no_context_takeover': self.request_no_context_takeover}
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
Returns Python object representation that can be eval'ed to reconstruct the object.
|
||||
|
||||
:returns: str -- Python string representation.
|
||||
:returns: Python string representation.
|
||||
:rtype: str
|
||||
"""
|
||||
return "PerMessageSnappyOffer(acceptNoContextTakeover = %s, requestNoContextTakeover = %s)" % (self.acceptNoContextTakeover, self.requestNoContextTakeover)
|
||||
return "PerMessageSnappyOffer(accept_no_context_takeover = %s, request_no_context_takeover = %s)" % (self.accept_no_context_takeover, self.request_no_context_takeover)
|
||||
|
||||
|
||||
class PerMessageSnappyOfferAccept(PerMessageCompressOfferAccept, PerMessageSnappyMixin):
|
||||
@ -168,71 +168,73 @@ class PerMessageSnappyOfferAccept(PerMessageCompressOfferAccept, PerMessageSnapp
|
||||
|
||||
def __init__(self,
|
||||
offer,
|
||||
requestNoContextTakeover=False,
|
||||
noContextTakeover=None):
|
||||
request_no_context_takeover=False,
|
||||
no_context_takeover=None):
|
||||
"""
|
||||
Constructor.
|
||||
|
||||
:param offer: The offer being accepted.
|
||||
:type offer: Instance of :class:`autobahn.compress.PerMessageSnappyOffer`.
|
||||
:param requestNoContextTakeover: Iff true, server request "no context takeover" feature.
|
||||
:type requestNoContextTakeover: bool
|
||||
:param noContextTakeover: Override server ("server-to-client direction") context takeover (this must be compatible with offer).
|
||||
:type noContextTakeover: bool
|
||||
:param request_no_context_takeover: Iff true, server request "no context takeover" feature.
|
||||
:type request_no_context_takeover: bool
|
||||
:param no_context_takeover: Override server ("server-to-client direction") context takeover (this must be compatible with offer).
|
||||
:type no_context_takeover: bool
|
||||
"""
|
||||
if not isinstance(offer, PerMessageSnappyOffer):
|
||||
raise Exception("invalid type %s for offer" % type(offer))
|
||||
|
||||
self.offer = offer
|
||||
|
||||
if type(requestNoContextTakeover) != bool:
|
||||
raise Exception("invalid type %s for requestNoContextTakeover" % type(requestNoContextTakeover))
|
||||
if type(request_no_context_takeover) != bool:
|
||||
raise Exception("invalid type %s for request_no_context_takeover" % type(request_no_context_takeover))
|
||||
|
||||
if requestNoContextTakeover and not offer.acceptNoContextTakeover:
|
||||
raise Exception("invalid value %s for requestNoContextTakeover - feature unsupported by client" % requestNoContextTakeover)
|
||||
if request_no_context_takeover and not offer.accept_no_context_takeover:
|
||||
raise Exception("invalid value %s for request_no_context_takeover - feature unsupported by client" % request_no_context_takeover)
|
||||
|
||||
self.requestNoContextTakeover = requestNoContextTakeover
|
||||
self.request_no_context_takeover = request_no_context_takeover
|
||||
|
||||
if noContextTakeover is not None:
|
||||
if type(noContextTakeover) != bool:
|
||||
raise Exception("invalid type %s for noContextTakeover" % type(noContextTakeover))
|
||||
if no_context_takeover is not None:
|
||||
if type(no_context_takeover) != bool:
|
||||
raise Exception("invalid type %s for no_context_takeover" % type(no_context_takeover))
|
||||
|
||||
if offer.requestNoContextTakeover and not noContextTakeover:
|
||||
raise Exception("invalid value %s for noContextTakeover - client requested feature" % noContextTakeover)
|
||||
if offer.request_no_context_takeover and not no_context_takeover:
|
||||
raise Exception("invalid value %s for no_context_takeover - client requested feature" % no_context_takeover)
|
||||
|
||||
self.noContextTakeover = noContextTakeover
|
||||
self.no_context_takeover = no_context_takeover
|
||||
|
||||
def getExtensionString(self):
|
||||
def get_extension_string(self):
|
||||
"""
|
||||
Returns the WebSocket extension configuration string as sent to the server.
|
||||
|
||||
:returns: str -- PMCE configuration string.
|
||||
:returns: PMCE configuration string.
|
||||
:rtype: str
|
||||
"""
|
||||
pmceString = self.EXTENSION_NAME
|
||||
if self.offer.requestNoContextTakeover:
|
||||
pmceString += "; server_no_context_takeover"
|
||||
if self.requestNoContextTakeover:
|
||||
pmceString += "; client_no_context_takeover"
|
||||
return pmceString
|
||||
pmce_string = self.EXTENSION_NAME
|
||||
if self.offer.request_no_context_takeover:
|
||||
pmce_string += "; server_no_context_takeover"
|
||||
if self.request_no_context_takeover:
|
||||
pmce_string += "; client_no_context_takeover"
|
||||
return pmce_string
|
||||
|
||||
def __json__(self):
|
||||
"""
|
||||
Returns a JSON serializable object representation.
|
||||
|
||||
:returns: object -- JSON serializable representation.
|
||||
:returns: JSON serializable representation.
|
||||
:rtype: dict
|
||||
"""
|
||||
return {'extension': self.EXTENSION_NAME,
|
||||
'offer': self.offer.__json__(),
|
||||
'requestNoContextTakeover': self.requestNoContextTakeover,
|
||||
'noContextTakeover': self.noContextTakeover}
|
||||
'request_no_context_takeover': self.request_no_context_takeover,
|
||||
'no_context_takeover': self.no_context_takeover}
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
Returns Python object representation that can be eval'ed to reconstruct the object.
|
||||
|
||||
:returns: str -- Python string representation.
|
||||
:returns: Python string representation.
|
||||
:rtype: str
|
||||
"""
|
||||
return "PerMessageSnappyAccept(offer = %s, requestNoContextTakeover = %s, noContextTakeover = %s)" % (self.offer.__repr__(), self.requestNoContextTakeover, self.noContextTakeover)
|
||||
return "PerMessageSnappyAccept(offer = %s, request_no_context_takeover = %s, no_context_takeover = %s)" % (self.offer.__repr__(), self.request_no_context_takeover, self.no_context_takeover)
|
||||
|
||||
|
||||
class PerMessageSnappyResponse(PerMessageCompressResponse, PerMessageSnappyMixin):
|
||||
@ -248,7 +250,8 @@ class PerMessageSnappyResponse(PerMessageCompressResponse, PerMessageSnappyMixin
|
||||
:param params: Output from :func:`autobahn.websocket.WebSocketProtocol._parseExtensionsHeader`.
|
||||
:type params: list
|
||||
|
||||
:returns: object -- A new instance of :class:`autobahn.compress.PerMessageSnappyResponse`.
|
||||
:returns: A new instance of :class:`autobahn.compress.PerMessageSnappyResponse`.
|
||||
:rtype: obj
|
||||
"""
|
||||
client_no_context_takeover = False
|
||||
server_no_context_takeover = False
|
||||
@ -291,7 +294,8 @@ class PerMessageSnappyResponse(PerMessageCompressResponse, PerMessageSnappyMixin
|
||||
"""
|
||||
Returns a JSON serializable object representation.
|
||||
|
||||
:returns: object -- JSON serializable representation.
|
||||
:returns: JSON serializable representation.
|
||||
:rtype: dict
|
||||
"""
|
||||
return {'extension': self.EXTENSION_NAME,
|
||||
'client_no_context_takeover': self.client_no_context_takeover,
|
||||
@ -301,7 +305,8 @@ class PerMessageSnappyResponse(PerMessageCompressResponse, PerMessageSnappyMixin
|
||||
"""
|
||||
Returns Python object representation that can be eval'ed to reconstruct the object.
|
||||
|
||||
:returns: str -- Python string representation.
|
||||
:returns: Python string representation.
|
||||
:rtype: str
|
||||
"""
|
||||
return "PerMessageSnappyResponse(client_no_context_takeover = %s, server_no_context_takeover = %s)" % (self.client_no_context_takeover, self.server_no_context_takeover)
|
||||
|
||||
@ -314,46 +319,47 @@ class PerMessageSnappyResponseAccept(PerMessageCompressResponseAccept, PerMessag
|
||||
|
||||
def __init__(self,
|
||||
response,
|
||||
noContextTakeover=None):
|
||||
no_context_takeover=None):
|
||||
"""
|
||||
Constructor.
|
||||
|
||||
:param response: The response being accepted.
|
||||
:type response: Instance of :class:`autobahn.compress.PerMessageSnappyResponse`.
|
||||
:param noContextTakeover: Override client ("client-to-server direction") context takeover (this must be compatible with response).
|
||||
:type noContextTakeover: bool
|
||||
:param no_context_takeover: Override client ("client-to-server direction") context takeover (this must be compatible with response).
|
||||
:type no_context_takeover: bool
|
||||
"""
|
||||
if not isinstance(response, PerMessageSnappyResponse):
|
||||
raise Exception("invalid type %s for response" % type(response))
|
||||
|
||||
self.response = response
|
||||
|
||||
if noContextTakeover is not None:
|
||||
if type(noContextTakeover) != bool:
|
||||
raise Exception("invalid type %s for noContextTakeover" % type(noContextTakeover))
|
||||
if no_context_takeover is not None:
|
||||
if type(no_context_takeover) != bool:
|
||||
raise Exception("invalid type %s for no_context_takeover" % type(no_context_takeover))
|
||||
|
||||
if response.client_no_context_takeover and not noContextTakeover:
|
||||
raise Exception("invalid value %s for noContextTakeover - server requested feature" % noContextTakeover)
|
||||
if response.client_no_context_takeover and not no_context_takeover:
|
||||
raise Exception("invalid value %s for no_context_takeover - server requested feature" % no_context_takeover)
|
||||
|
||||
self.noContextTakeover = noContextTakeover
|
||||
self.no_context_takeover = no_context_takeover
|
||||
|
||||
def __json__(self):
|
||||
"""
|
||||
Returns a JSON serializable object representation.
|
||||
|
||||
:returns: object -- JSON serializable representation.
|
||||
:returns: JSON serializable representation.
|
||||
:rtype: dict
|
||||
"""
|
||||
return {'extension': self.EXTENSION_NAME,
|
||||
'response': self.response.__json__(),
|
||||
'noContextTakeover': self.noContextTakeover}
|
||||
'no_context_takeover': self.no_context_takeover}
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
Returns Python object representation that can be eval'ed to reconstruct the object.
|
||||
|
||||
:returns: str -- Python string representation.
|
||||
:returns: Python string representation.
|
||||
:rtype: str
|
||||
"""
|
||||
return "PerMessageSnappyResponseAccept(response = %s, noContextTakeover = %s)" % (self.response.__repr__(), self.noContextTakeover)
|
||||
return "PerMessageSnappyResponseAccept(response = %s, no_context_takeover = %s)" % (self.response.__repr__(), self.no_context_takeover)
|
||||
|
||||
|
||||
class PerMessageSnappy(PerMessageCompress, PerMessageSnappyMixin):
|
||||
@ -362,24 +368,24 @@ class PerMessageSnappy(PerMessageCompress, PerMessageSnappyMixin):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def createFromResponseAccept(cls, isServer, accept):
|
||||
pmce = cls(isServer,
|
||||
def create_from_response_accept(cls, is_server, accept):
|
||||
pmce = cls(is_server,
|
||||
accept.response.server_no_context_takeover,
|
||||
accept.noContextTakeover if accept.noContextTakeover is not None else accept.response.client_no_context_takeover)
|
||||
accept.no_context_takeover if accept.no_context_takeover is not None else accept.response.client_no_context_takeover)
|
||||
return pmce
|
||||
|
||||
@classmethod
|
||||
def createFromOfferAccept(cls, isServer, accept):
|
||||
pmce = cls(isServer,
|
||||
accept.noContextTakeover if accept.noContextTakeover is not None else accept.offer.requestNoContextTakeover,
|
||||
accept.requestNoContextTakeover)
|
||||
def create_from_offer_accept(cls, is_server, accept):
|
||||
pmce = cls(is_server,
|
||||
accept.no_context_takeover if accept.no_context_takeover is not None else accept.offer.request_no_context_takeover,
|
||||
accept.request_no_context_takeover)
|
||||
return pmce
|
||||
|
||||
def __init__(self,
|
||||
isServer,
|
||||
is_server,
|
||||
server_no_context_takeover,
|
||||
client_no_context_takeover):
|
||||
self._isServer = isServer
|
||||
self._is_server = is_server
|
||||
self.server_no_context_takeover = server_no_context_takeover
|
||||
self.client_no_context_takeover = client_no_context_takeover
|
||||
|
||||
@ -392,32 +398,32 @@ class PerMessageSnappy(PerMessageCompress, PerMessageSnappyMixin):
|
||||
'client_no_context_takeover': self.client_no_context_takeover}
|
||||
|
||||
def __repr__(self):
|
||||
return "PerMessageSnappy(isServer = %s, server_no_context_takeover = %s, client_no_context_takeover = %s)" % (self._isServer, self.server_no_context_takeover, self.client_no_context_takeover)
|
||||
return "PerMessageSnappy(is_server = %s, server_no_context_takeover = %s, client_no_context_takeover = %s)" % (self._is_server, self.server_no_context_takeover, self.client_no_context_takeover)
|
||||
|
||||
def startCompressMessage(self):
|
||||
if self._isServer:
|
||||
def start_compress_message(self):
|
||||
if self._is_server:
|
||||
if self._compressor is None or self.server_no_context_takeover:
|
||||
self._compressor = snappy.StreamCompressor()
|
||||
else:
|
||||
if self._compressor is None or self.client_no_context_takeover:
|
||||
self._compressor = snappy.StreamCompressor()
|
||||
|
||||
def compressMessageData(self, data):
|
||||
def compress_message_data(self, data):
|
||||
return self._compressor.add_chunk(data)
|
||||
|
||||
def endCompressMessage(self):
|
||||
def end_compress_message(self):
|
||||
return ""
|
||||
|
||||
def startDecompressMessage(self):
|
||||
if self._isServer:
|
||||
def start_decompress_message(self):
|
||||
if self._is_server:
|
||||
if self._decompressor is None or self.client_no_context_takeover:
|
||||
self._decompressor = snappy.StreamDecompressor()
|
||||
else:
|
||||
if self._decompressor is None or self.server_no_context_takeover:
|
||||
self._decompressor = snappy.StreamDecompressor()
|
||||
|
||||
def decompressMessageData(self, data):
|
||||
def decompress_message_data(self, data):
|
||||
return self._decompressor.decompress(data)
|
||||
|
||||
def endDecompressMessage(self):
|
||||
def end_decompress_message(self):
|
||||
pass
|
||||
|
@ -51,7 +51,7 @@ from autobahn.websocket.types import ConnectionRequest, ConnectionResponse, Conn
|
||||
from autobahn.util import Stopwatch, newid, wildcards2patterns, encode_truncate
|
||||
from autobahn.util import _LazyHexFormatter
|
||||
from autobahn.websocket.utf8validator import Utf8Validator
|
||||
from autobahn.websocket.xormasker import XorMaskerNull, createXorMasker
|
||||
from autobahn.websocket.xormasker import XorMaskerNull, create_xor_masker
|
||||
from autobahn.websocket.compress import PERMESSAGE_COMPRESSION_EXTENSION
|
||||
from autobahn.websocket.util import parse_url
|
||||
|
||||
@ -1483,7 +1483,7 @@ class WebSocketProtocol(object):
|
||||
i += 4
|
||||
|
||||
if frame_masked and frame_payload_len > 0 and self.applyMask:
|
||||
self.current_frame_masker = createXorMasker(frame_mask, frame_payload_len)
|
||||
self.current_frame_masker = create_xor_masker(frame_mask, frame_payload_len)
|
||||
else:
|
||||
self.current_frame_masker = XorMaskerNull()
|
||||
|
||||
@ -1575,7 +1575,7 @@ class WebSocketProtocol(object):
|
||||
#
|
||||
if self._perMessageCompress is not None and self.current_frame.rsv == 4:
|
||||
self._isMessageCompressed = True
|
||||
self._perMessageCompress.startDecompressMessage()
|
||||
self._perMessageCompress.start_decompress_message()
|
||||
else:
|
||||
self._isMessageCompressed = False
|
||||
|
||||
@ -1616,7 +1616,7 @@ class WebSocketProtocol(object):
|
||||
octets=_LazyHexFormatter(payload),
|
||||
)
|
||||
|
||||
payload = self._perMessageCompress.decompressMessageData(payload)
|
||||
payload = self._perMessageCompress.decompress_message_data(payload)
|
||||
uncompressedLen = len(payload)
|
||||
else:
|
||||
l = len(payload)
|
||||
@ -1658,7 +1658,7 @@ class WebSocketProtocol(object):
|
||||
# handle end of compressed message
|
||||
#
|
||||
if self._isMessageCompressed:
|
||||
self._perMessageCompress.endDecompressMessage()
|
||||
self._perMessageCompress.end_decompress_message()
|
||||
|
||||
# verify UTF8 has actually ended
|
||||
#
|
||||
@ -1802,7 +1802,7 @@ class WebSocketProtocol(object):
|
||||
# mask frame payload
|
||||
#
|
||||
if l > 0 and self.applyMask:
|
||||
masker = createXorMasker(mask, l)
|
||||
masker = create_xor_masker(mask, l)
|
||||
plm = masker.process(pl)
|
||||
else:
|
||||
plm = pl
|
||||
@ -1978,7 +1978,7 @@ class WebSocketProtocol(object):
|
||||
#
|
||||
if self._perMessageCompress is not None and not doNotCompress:
|
||||
self.send_compressed = True
|
||||
self._perMessageCompress.startCompressMessage()
|
||||
self._perMessageCompress.start_compress_message()
|
||||
else:
|
||||
self.send_compressed = False
|
||||
|
||||
@ -2019,7 +2019,7 @@ class WebSocketProtocol(object):
|
||||
# payload masker
|
||||
#
|
||||
if self.send_message_frame_mask and length > 0 and self.applyMask:
|
||||
self.send_message_frame_masker = createXorMasker(self.send_message_frame_mask, length)
|
||||
self.send_message_frame_masker = create_xor_masker(self.send_message_frame_mask, length)
|
||||
else:
|
||||
self.send_message_frame_masker = XorMaskerNull()
|
||||
|
||||
@ -2128,7 +2128,7 @@ class WebSocketProtocol(object):
|
||||
# raise Exception("WebSocketProtocol.endMessage invalid in current sending state [%d]" % self.send_state)
|
||||
|
||||
if self.send_compressed:
|
||||
payload = self._perMessageCompress.endCompressMessage()
|
||||
payload = self._perMessageCompress.end_compress_message()
|
||||
self.trafficStats.outgoingOctetsWebSocketLevel += len(payload)
|
||||
else:
|
||||
# send continuation frame with empty payload and FIN set to end message
|
||||
@ -2146,7 +2146,7 @@ class WebSocketProtocol(object):
|
||||
|
||||
if self.send_compressed:
|
||||
self.trafficStats.outgoingOctetsAppLevel += len(payload)
|
||||
payload = self._perMessageCompress.compressMessageData(payload)
|
||||
payload = self._perMessageCompress.compress_message_data(payload)
|
||||
|
||||
self.beginMessageFrame(len(payload))
|
||||
self.sendMessageFrameData(payload, sync)
|
||||
@ -2182,12 +2182,12 @@ class WebSocketProtocol(object):
|
||||
if self._perMessageCompress is not None and not doNotCompress:
|
||||
sendCompressed = True
|
||||
|
||||
self._perMessageCompress.startCompressMessage()
|
||||
self._perMessageCompress.start_compress_message()
|
||||
|
||||
self.trafficStats.outgoingOctetsAppLevel += len(payload)
|
||||
|
||||
payload1 = self._perMessageCompress.compressMessageData(payload)
|
||||
payload2 = self._perMessageCompress.endCompressMessage()
|
||||
payload1 = self._perMessageCompress.compress_message_data(payload)
|
||||
payload2 = self._perMessageCompress.end_compress_message()
|
||||
payload = b''.join([payload1, payload2])
|
||||
|
||||
self.trafficStats.outgoingOctetsWebSocketLevel += len(payload)
|
||||
@ -2318,7 +2318,7 @@ class PreparedMessage(object):
|
||||
if l == 0:
|
||||
plm = payload
|
||||
else:
|
||||
plm = createXorMasker(mask, l).process(payload)
|
||||
plm = create_xor_masker(mask, l).process(payload)
|
||||
else:
|
||||
b1 = 0
|
||||
mask = b''
|
||||
@ -2886,9 +2886,9 @@ class WebSocketServerProtocol(WebSocketProtocol):
|
||||
accept = self.perMessageCompressionAccept(pmceOffers)
|
||||
if accept is not None:
|
||||
PMCE = PERMESSAGE_COMPRESSION_EXTENSION[accept.EXTENSION_NAME]
|
||||
self._perMessageCompress = PMCE['PMCE'].createFromOfferAccept(self.factory.isServer, accept)
|
||||
self._perMessageCompress = PMCE['PMCE'].create_from_offer_accept(self.factory.isServer, accept)
|
||||
self.websocket_extensions_in_use.append(self._perMessageCompress)
|
||||
extensionResponse.append(accept.getExtensionString())
|
||||
extensionResponse.append(accept.get_extension_string())
|
||||
else:
|
||||
self.log.debug(
|
||||
"client request permessage-compress extension, but we did "
|
||||
@ -3571,7 +3571,7 @@ class WebSocketClientProtocol(WebSocketProtocol):
|
||||
# permessage-compress offers
|
||||
#
|
||||
for offer in self.perMessageCompressionOffers:
|
||||
extensions.append(offer.getExtensionString())
|
||||
extensions.append(offer.get_extension_string())
|
||||
|
||||
if len(extensions) > 0:
|
||||
request += "Sec-WebSocket-Extensions: %s\x0d\x0a" % ', '.join(extensions)
|
||||
@ -3728,7 +3728,7 @@ class WebSocketClientProtocol(WebSocketProtocol):
|
||||
if accept is None:
|
||||
return self.failHandshake("WebSocket permessage-compress extension response from server denied by client")
|
||||
|
||||
self._perMessageCompress = PMCE['PMCE'].createFromResponseAccept(self.factory.isServer, accept)
|
||||
self._perMessageCompress = PMCE['PMCE'].create_from_response_accept(self.factory.isServer, accept)
|
||||
|
||||
self.websocket_extensions_in_use.append(self._perMessageCompress)
|
||||
|
||||
|
@ -54,17 +54,15 @@ UTF8_REJECT = 1
|
||||
|
||||
|
||||
# use Cython implementation of UTF8 validator if available
|
||||
#
|
||||
try:
|
||||
from wsaccel.utf8validator import Utf8Validator
|
||||
|
||||
except ImportError:
|
||||
#
|
||||
|
||||
# Fallback to pure Python implementation - also for PyPy.
|
||||
#
|
||||
# Do NOT touch this code unless you know what you are doing!
|
||||
# https://github.com/oberstet/scratchbox/tree/master/python/utf8
|
||||
#
|
||||
|
||||
import six
|
||||
|
||||
@ -83,7 +81,16 @@ except ImportError:
|
||||
Bjoern Hoehrmann (http://bjoern.hoehrmann.de/utf-8/decoder/dfa/).
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
'_codepoint',
|
||||
'_state',
|
||||
'_index',
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
self._codepoint = None
|
||||
self._state = None
|
||||
self._index = None
|
||||
self.reset()
|
||||
|
||||
def decode(self, b):
|
||||
@ -98,20 +105,20 @@ except ImportError:
|
||||
Returns some other positive integer when more octets need to be eaten.
|
||||
"""
|
||||
tt = UTF8VALIDATOR_DFA_S[b]
|
||||
if self.state != UTF8_ACCEPT:
|
||||
self.codepoint = (b & 0x3f) | (self.codepoint << 6)
|
||||
if self._state != UTF8_ACCEPT:
|
||||
self._codepoint = (b & 0x3f) | (self._codepoint << 6)
|
||||
else:
|
||||
self.codepoint = (0xff >> tt) & b
|
||||
self.state = UTF8VALIDATOR_DFA_S[256 + self.state * 16 + tt]
|
||||
return self.state
|
||||
self._codepoint = (0xff >> tt) & b
|
||||
self._state = UTF8VALIDATOR_DFA_S[256 + self._state * 16 + tt]
|
||||
return self._state
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset validator to start new incremental UTF-8 decode/validation.
|
||||
"""
|
||||
self.state = UTF8_ACCEPT # the empty string is valid UTF8
|
||||
self.codepoint = 0
|
||||
self.i = 0
|
||||
self._state = UTF8_ACCEPT # the empty string is valid UTF8
|
||||
self._codepoint = 0
|
||||
self._index = 0
|
||||
|
||||
def validate(self, ba):
|
||||
"""
|
||||
@ -132,18 +139,18 @@ except ImportError:
|
||||
#
|
||||
l = len(ba)
|
||||
i = 0
|
||||
state = self.state
|
||||
state = self._state
|
||||
while i < l:
|
||||
# optimized version of decode(), since we are not interested in actual code points
|
||||
state = UTF8VALIDATOR_DFA_S[256 + (state << 4) + UTF8VALIDATOR_DFA_S[ba[i]]]
|
||||
if state == UTF8_REJECT:
|
||||
self.state = state
|
||||
self.i += i
|
||||
return False, False, i, self.i
|
||||
self._state = state
|
||||
self._index += i
|
||||
return False, False, i, self._index
|
||||
i += 1
|
||||
self.state = state
|
||||
self.i += l
|
||||
return True, state == UTF8_ACCEPT, l, self.i
|
||||
self._state = state
|
||||
self._index += l
|
||||
return True, state == UTF8_ACCEPT, l, self._index
|
||||
|
||||
else:
|
||||
|
||||
@ -158,7 +165,16 @@ except ImportError:
|
||||
Bjoern Hoehrmann (http://bjoern.hoehrmann.de/utf-8/decoder/dfa/).
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
'_codepoint',
|
||||
'_state',
|
||||
'_index',
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
self._codepoint = None
|
||||
self._state = None
|
||||
self._index = None
|
||||
self.reset()
|
||||
|
||||
def decode(self, b):
|
||||
@ -173,20 +189,20 @@ except ImportError:
|
||||
Returns some other positive integer when more octets need to be eaten.
|
||||
"""
|
||||
tt = ord(UTF8VALIDATOR_DFA_S[b])
|
||||
if self.state != UTF8_ACCEPT:
|
||||
self.codepoint = (b & 0x3f) | (self.codepoint << 6)
|
||||
if self._state != UTF8_ACCEPT:
|
||||
self._codepoint = (b & 0x3f) | (self._codepoint << 6)
|
||||
else:
|
||||
self.codepoint = (0xff >> tt) & b
|
||||
self.state = ord(UTF8VALIDATOR_DFA_S[256 + self.state * 16 + tt])
|
||||
return self.state
|
||||
self._codepoint = (0xff >> tt) & b
|
||||
self._state = ord(UTF8VALIDATOR_DFA_S[256 + self._state * 16 + tt])
|
||||
return self._state
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset validator to start new incremental UTF-8 decode/validation.
|
||||
"""
|
||||
self.state = UTF8_ACCEPT # the empty string is valid UTF8
|
||||
self.codepoint = 0
|
||||
self.i = 0
|
||||
self._state = UTF8_ACCEPT # the empty string is valid UTF8
|
||||
self._codepoint = 0
|
||||
self._index = 0
|
||||
|
||||
def validate(self, ba):
|
||||
"""
|
||||
@ -207,15 +223,15 @@ except ImportError:
|
||||
#
|
||||
l = len(ba)
|
||||
i = 0
|
||||
state = self.state
|
||||
state = self._state
|
||||
while i < l:
|
||||
# optimized version of decode(), since we are not interested in actual code points
|
||||
state = ord(UTF8VALIDATOR_DFA_S[256 + (state << 4) + ord(UTF8VALIDATOR_DFA_S[ord(ba[i])])])
|
||||
if state == UTF8_REJECT:
|
||||
self.state = state
|
||||
self.i += i
|
||||
return False, False, i, self.i
|
||||
self._state = state
|
||||
self._index += i
|
||||
return False, False, i, self._index
|
||||
i += 1
|
||||
self.state = state
|
||||
self.i += l
|
||||
return True, state == UTF8_ACCEPT, l, self.i
|
||||
self._state = state
|
||||
self._index += l
|
||||
return True, state == UTF8_ACCEPT, l, self._index
|
||||
|
@ -26,17 +26,21 @@
|
||||
|
||||
import six
|
||||
|
||||
|
||||
# use Cython implementation of XorMasker validator if available
|
||||
##
|
||||
try:
|
||||
from wsaccel.xormask import XorMaskerNull, createXorMasker
|
||||
# use Cython implementation of XorMasker validator if available
|
||||
|
||||
from wsaccel.xormask import XorMaskerNull
|
||||
# noinspection PyUnresolvedReferences
|
||||
from wsaccel.xormask import createXorMasker
|
||||
create_xor_masker = createXorMasker
|
||||
|
||||
except ImportError:
|
||||
# fallback to pure Python implementation
|
||||
|
||||
# fallback to pure Python implementation (this is faster on PyPy than above!)
|
||||
|
||||
# http://stackoverflow.com/questions/15014310/python3-xrange-lack-hurts
|
||||
try:
|
||||
# noinspection PyUnresolvedReferences
|
||||
xrange
|
||||
except NameError:
|
||||
# Python 3
|
||||
@ -47,39 +51,43 @@ except ImportError:
|
||||
|
||||
class XorMaskerNull(object):
|
||||
|
||||
__slots__ = ('_ptr',)
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
def __init__(self, mask=None):
|
||||
self.ptr = 0
|
||||
self._ptr = 0
|
||||
|
||||
def pointer(self):
|
||||
return self.ptr
|
||||
return self._ptr
|
||||
|
||||
def reset(self):
|
||||
self.ptr = 0
|
||||
self._ptr = 0
|
||||
|
||||
def process(self, data):
|
||||
self.ptr += len(data)
|
||||
self._ptr += len(data)
|
||||
return data
|
||||
|
||||
class XorMaskerSimple(object):
|
||||
|
||||
__slots__ = ('_ptr', '_msk')
|
||||
|
||||
def __init__(self, mask):
|
||||
assert len(mask) == 4
|
||||
self.ptr = 0
|
||||
self.msk = array('B', mask)
|
||||
self._ptr = 0
|
||||
self._msk = array('B', mask)
|
||||
|
||||
def pointer(self):
|
||||
return self.ptr
|
||||
return self._ptr
|
||||
|
||||
def reset(self):
|
||||
self.ptr = 0
|
||||
self._ptr = 0
|
||||
|
||||
def process(self, data):
|
||||
dlen = len(data)
|
||||
payload = array('B', data)
|
||||
for k in xrange(dlen):
|
||||
payload[k] ^= self.msk[self.ptr & 3]
|
||||
self.ptr += 1
|
||||
payload[k] ^= self._msk[self._ptr & 3]
|
||||
self._ptr += 1
|
||||
if six.PY3:
|
||||
return payload.tobytes()
|
||||
else:
|
||||
@ -87,42 +95,44 @@ except ImportError:
|
||||
|
||||
class XorMaskerShifted1(object):
|
||||
|
||||
__slots__ = ('_ptr', '_mskarray')
|
||||
|
||||
def __init__(self, mask):
|
||||
assert len(mask) == 4
|
||||
self.ptr = 0
|
||||
self.mskarray = [array('B'), array('B'), array('B'), array('B')]
|
||||
self._ptr = 0
|
||||
self._mskarray = [array('B'), array('B'), array('B'), array('B')]
|
||||
if six.PY3:
|
||||
for j in xrange(4):
|
||||
self.mskarray[0].append(mask[j & 3])
|
||||
self.mskarray[1].append(mask[(j + 1) & 3])
|
||||
self.mskarray[2].append(mask[(j + 2) & 3])
|
||||
self.mskarray[3].append(mask[(j + 3) & 3])
|
||||
self._mskarray[0].append(mask[j & 3])
|
||||
self._mskarray[1].append(mask[(j + 1) & 3])
|
||||
self._mskarray[2].append(mask[(j + 2) & 3])
|
||||
self._mskarray[3].append(mask[(j + 3) & 3])
|
||||
else:
|
||||
for j in xrange(4):
|
||||
self.mskarray[0].append(ord(mask[j & 3]))
|
||||
self.mskarray[1].append(ord(mask[(j + 1) & 3]))
|
||||
self.mskarray[2].append(ord(mask[(j + 2) & 3]))
|
||||
self.mskarray[3].append(ord(mask[(j + 3) & 3]))
|
||||
self._mskarray[0].append(ord(mask[j & 3]))
|
||||
self._mskarray[1].append(ord(mask[(j + 1) & 3]))
|
||||
self._mskarray[2].append(ord(mask[(j + 2) & 3]))
|
||||
self._mskarray[3].append(ord(mask[(j + 3) & 3]))
|
||||
|
||||
def pointer(self):
|
||||
return self.ptr
|
||||
return self._ptr
|
||||
|
||||
def reset(self):
|
||||
self.ptr = 0
|
||||
self._ptr = 0
|
||||
|
||||
def process(self, data):
|
||||
dlen = len(data)
|
||||
payload = array('B', data)
|
||||
msk = self.mskarray[self.ptr & 3]
|
||||
msk = self._mskarray[self._ptr & 3]
|
||||
for k in xrange(dlen):
|
||||
payload[k] ^= msk[k & 3]
|
||||
self.ptr += dlen
|
||||
self._ptr += dlen
|
||||
if six.PY3:
|
||||
return payload.tobytes()
|
||||
else:
|
||||
return payload.tostring()
|
||||
|
||||
def createXorMasker(mask, length=None):
|
||||
def create_xor_masker(mask, length=None):
|
||||
if length is None or length < 128:
|
||||
return XorMaskerSimple(mask)
|
||||
else:
|
||||
|
Loading…
Reference in New Issue
Block a user