Files
telemetry-backend/venv/lib/python2.7/site-packages/engineio/payload.py
2017-07-20 18:02:16 +02:00

85 lines
3.8 KiB
Python

import six
from . import packet
class Payload(object):
"""Engine.IO payload."""
def __init__(self, packets=None, encoded_payload=None):
self.packets = packets or []
if encoded_payload is not None:
self.decode(encoded_payload)
def encode(self, b64=False):
"""Encode the payload for transmission."""
encoded_payload = b''
for pkt in self.packets:
encoded_packet = pkt.encode(b64=b64)
packet_len = len(encoded_packet)
if b64:
encoded_payload += str(packet_len).encode('utf-8') + b':' + \
encoded_packet
else:
binary_len = b''
while packet_len != 0:
binary_len = six.int2byte(packet_len % 10) + binary_len
packet_len = int(packet_len / 10)
if not pkt.binary:
encoded_payload += b'\0'
else:
encoded_payload += b'\1'
encoded_payload += binary_len + b'\xff' + encoded_packet
return encoded_payload
def decode(self, encoded_payload):
"""Decode a transmitted payload."""
fixed_double_encode = False
self.packets = []
while encoded_payload:
if six.byte2int(encoded_payload[0:1]) <= 1:
packet_len = 0
i = 1
while six.byte2int(encoded_payload[i:i + 1]) != 255:
packet_len = packet_len * 10 + six.byte2int(
encoded_payload[i:i + 1])
i += 1
self.packets.append(packet.Packet(
encoded_packet=encoded_payload[i + 1:i + 1 + packet_len]))
else:
i = encoded_payload.find(b':')
if i == -1:
raise ValueError('invalid payload')
# the packet_len below is given in utf-8 characters, but we
# receive the payload as bytes, so down below this length is
# adjusted to reflect byte length
packet_len = int(encoded_payload[0:i])
if not fixed_double_encode:
# the engine.io javascript client sends text payloads with
# a double UTF-8 encoding. Here we try to fix that mess and
# restore the original packet
try:
# first we remove one UTF-8 encoding layer
fixed_payload = encoded_payload.decode(
'utf-8').encode('raw_unicode_escape')
# then we make sure the result can be decoded a second
# time (this will raise an exception if not)
fixed_payload.decode('utf-8')
# if a second utf-8 decode worked, then this appears to
# be a double encoded packet, so here we keep the
# packet after a single decode, since the packet class
# will perform a decode as well, and in this case it is
# not necessary to adjust the packet length
encoded_payload = fixed_payload
except:
# if we couldn't apply a double utf-8 decode then
# the packet must have been correct, so we just adjust
# the packet length to be in bytes and not utf-8
# characters and keep going
packet_len += len(encoded_payload) - len(fixed_payload)
fixed_double_encode = True
pkt = encoded_payload[i + 1: i + 1 + packet_len]
self.packets.append(packet.Packet(encoded_packet=pkt))
encoded_payload = encoded_payload[i + 1 + packet_len:]