parsers.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import json
  2. from collections import namedtuple
  3. from .symmetries import (
  4. decode_string, encode_string, get_byte, get_character, parse_url)
  5. EngineIOSession = namedtuple('EngineIOSession', [
  6. 'id', 'ping_interval', 'ping_timeout', 'transport_upgrades'])
  7. SocketIOData = namedtuple('SocketIOData', ['path', 'ack_id', 'args'])
  8. def parse_host(host, port, resource):
  9. if not host.startswith('http'):
  10. host = 'http://' + host
  11. url_pack = parse_url(host)
  12. is_secure = url_pack.scheme == 'https'
  13. port = port or url_pack.port or (443 if is_secure else 80)
  14. url = '%s:%d%s/%s' % (url_pack.hostname, port, url_pack.path, resource)
  15. return is_secure, url
  16. def parse_engineIO_session(engineIO_packet_data):
  17. d = json.loads(decode_string(engineIO_packet_data))
  18. return EngineIOSession(
  19. id=d['sid'],
  20. ping_interval=d['pingInterval'] / float(1000),
  21. ping_timeout=d['pingTimeout'] / float(1000),
  22. transport_upgrades=d['upgrades'])
  23. def encode_engineIO_content(engineIO_packets):
  24. content = bytearray()
  25. for packet_type, packet_data in engineIO_packets:
  26. packet_text = format_packet_text(packet_type, packet_data)
  27. content.extend(_make_packet_prefix(packet_text) + packet_text)
  28. return content
  29. def decode_engineIO_content(content):
  30. content_index = 0
  31. content_length = len(content)
  32. while content_index < content_length:
  33. try:
  34. content_index, packet_length = _read_packet_length(
  35. content, content_index)
  36. except IndexError:
  37. break
  38. content_index, packet_text = _read_packet_text(
  39. content, content_index, packet_length)
  40. engineIO_packet_type, engineIO_packet_data = parse_packet_text(
  41. packet_text)
  42. yield engineIO_packet_type, engineIO_packet_data
  43. def format_socketIO_packet_data(path=None, ack_id=None, args=None):
  44. socketIO_packet_data = json.dumps(args, ensure_ascii=False) if args else ''
  45. if ack_id is not None:
  46. socketIO_packet_data = str(ack_id) + socketIO_packet_data
  47. if path:
  48. socketIO_packet_data = path + ',' + socketIO_packet_data
  49. return socketIO_packet_data
  50. def parse_socketIO_packet_data(socketIO_packet_data):
  51. # fix decoding if server doesn't use UTF-8 (decode_string will try UTF-8 and latin-1)
  52. try:
  53. data = decode_string(socketIO_packet_data)
  54. except Exception as ex:
  55. print("Error on decoding data:")
  56. print(socketIO_packet_data)
  57. data = ""
  58. if data.startswith('/'):
  59. try:
  60. path, data = data.split(',', 1)
  61. except ValueError:
  62. path = data
  63. data = ''
  64. else:
  65. path = ''
  66. try:
  67. ack_id_string, data = data.split('[', 1)
  68. data = '[' + data
  69. ack_id = int(ack_id_string)
  70. except (ValueError, IndexError):
  71. ack_id = None
  72. try:
  73. args = json.loads(data)
  74. except ValueError:
  75. args = []
  76. return SocketIOData(path=path, ack_id=ack_id, args=args)
  77. def format_packet_text(packet_type, packet_data):
  78. return encode_string(str(packet_type) + packet_data)
  79. def parse_packet_text(packet_text):
  80. packet_type = int(get_character(packet_text, 0))
  81. packet_data = packet_text[1:]
  82. return packet_type, packet_data
  83. def get_namespace_path(socketIO_packet_data):
  84. if not socketIO_packet_data.startswith(b'/'):
  85. return ''
  86. # Loop incrementally in case there is binary data
  87. parts = []
  88. for i in range(len(socketIO_packet_data)):
  89. character = get_character(socketIO_packet_data, i)
  90. if ',' == character:
  91. break
  92. parts.append(character)
  93. return ''.join(parts)
  94. def _make_packet_prefix(packet):
  95. length_string = str(len(packet))
  96. header_digits = bytearray([0])
  97. for i in range(len(length_string)):
  98. header_digits.append(ord(length_string[i]) - 48)
  99. header_digits.append(255)
  100. return header_digits
  101. def _read_packet_length(content, content_index):
  102. while get_byte(content, content_index) != 0:
  103. content_index += 1
  104. content_index += 1
  105. packet_length_string = ''
  106. byte = get_byte(content, content_index)
  107. while byte != 255:
  108. packet_length_string += str(byte)
  109. content_index += 1
  110. byte = get_byte(content, content_index)
  111. return content_index, int(packet_length_string)
  112. def _read_packet_text(content, content_index, packet_length):
  113. while get_byte(content, content_index) == 255:
  114. content_index += 1
  115. packet_text = content[content_index:content_index + packet_length]
  116. return content_index + packet_length, packet_text