|
- import six
-
- from . import packet
-
- from six.moves import urllib
-
-
- 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, jsonp_index=None):
- """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
- if jsonp_index is not None:
- encoded_payload = b'___eio[' + \
- str(jsonp_index).encode() + \
- b']("' + \
- encoded_payload.replace(b'"', b'\\"') + \
- b'");'
- return encoded_payload
-
- def decode(self, encoded_payload):
- """Decode a transmitted payload."""
- self.packets = []
- while encoded_payload:
- # JSONP POST payload starts with 'd='
- if encoded_payload.startswith(b'd='):
- encoded_payload = urllib.parse.parse_qs(
- encoded_payload)[b'd'][0]
-
- 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')
-
- # extracting the packet out of the payload is extremely
- # inefficient, because the payload needs to be treated as
- # binary, but the non-binary packets have to be parsed as
- # unicode. Luckily this complication only applies to long
- # polling, as the websocket transport sends packets
- # individually wrapped.
- packet_len = int(encoded_payload[0:i])
- pkt = encoded_payload.decode('utf-8', errors='ignore')[
- i + 1: i + 1 + packet_len].encode('utf-8')
- self.packets.append(packet.Packet(encoded_packet=pkt))
-
- # the engine.io protocol sends the packet length in
- # utf-8 characters, but we need it in bytes to be able to
- # jump to the next packet in the payload
- packet_len = len(pkt)
- encoded_payload = encoded_payload[i + 1 + packet_len:]
|