frame.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import struct
  2. from os import urandom
  3. from exceptions import SocketClosed
  4. OPCODE_CONTINUATION = 0x0
  5. OPCODE_TEXT = 0x1
  6. OPCODE_BINARY = 0x2
  7. OPCODE_CLOSE = 0x8
  8. OPCODE_PING = 0x9
  9. OPCODE_PONG = 0xA
  10. class Frame(object):
  11. """
  12. A Frame instance represents a web socket data frame as defined in RFC 6455.
  13. To encoding a frame for sending it over a socket, use Frame.pack(). To
  14. receive and decode a frame from a socket, use receive_frame() (or,
  15. preferably, receive_fragments()).
  16. """
  17. def __init__(self, opcode, payload, masking_key='', final=True, rsv1=False,
  18. rsv2=False, rsv3=False):
  19. """
  20. Create a new frame.
  21. `opcode' is one of the constants as defined above.
  22. `payload' is a string of bytes containing the data sendt in the frame.
  23. `final` is a boolean indicating whether this frame is the last in a
  24. chain of fragments.
  25. `rsv1', `rsv2' and `rsv3' are booleans indicating bit values for RSV1,
  26. RVS2 and RSV3, which are only non-zero if defined so by extensions.
  27. """
  28. if len(masking_key) not in (0, 4):
  29. raise ValueError('invalid masking key "%s"' % masking_key)
  30. self.final = final
  31. self.rsv1 = rsv1
  32. self.rsv2 = rsv2
  33. self.rsv3 = rsv3
  34. self.opcode = opcode
  35. self.masking_key = masking_key
  36. self.payload = payload
  37. def pack(self):
  38. """
  39. Pack the frame into a string according to the following scheme:
  40. +-+-+-+-+-------+-+-------------+-------------------------------+
  41. |F|R|R|R| opcode|M| Payload len | Extended payload length |
  42. |I|S|S|S| (4) |A| (7) | (16/64) |
  43. |N|V|V|V| |S| | (if payload len==126/127) |
  44. | |1|2|3| |K| | |
  45. +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
  46. | Extended payload length continued, if payload len == 127 |
  47. + - - - - - - - - - - - - - - - +-------------------------------+
  48. | |Masking-key, if MASK set to 1 |
  49. +-------------------------------+-------------------------------+
  50. | Masking-key (continued) | Payload Data |
  51. +-------------------------------- - - - - - - - - - - - - - - - +
  52. : Payload Data continued ... :
  53. + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
  54. | Payload Data continued ... |
  55. +---------------------------------------------------------------+
  56. """
  57. header = struct.pack('!B', (self.fin << 7) | (self.rsv1 << 6) |
  58. (self.rsv2 << 5) | (self.rsv3 << 4) | self.opcode)
  59. mask = bool(self.masking_key) << 7
  60. payload_len = len(self.payload)
  61. if payload_len <= 125:
  62. header += struct.pack('!B', mask | payload_len)
  63. elif payload_len < (1 << 16):
  64. header += struct.pack('!BH', mask | 126, payload_len)
  65. elif payload_len < (1 << 63):
  66. header += struct.pack('!BQ', mask | 127, payload_len)
  67. else:
  68. raise Exception('the payload length is too damn high!')
  69. if mask:
  70. return header + self.masking_key + self.mask_payload()
  71. return header + self.payload
  72. def mask_payload(self):
  73. return mask(self.masking_key, self.payload)
  74. def fragment(self, fragment_size, mask=False):
  75. frames = []
  76. for start in range(0, len(self.payload), fragment_size):
  77. payload = self.payload[start:start + fragment_size]
  78. key = urandom(4) if mask else ''
  79. frames.append(Frame(OPCODE_CONTINUATION, payload, key, False))
  80. frames[0].opcode = self.opcode
  81. frames[-1].final = True
  82. return frames
  83. def __str__(self):
  84. return '<Frame opcode=0x%X len=%d>' % (self.opcode, len(self.payload))
  85. def receive_fragments(sock):
  86. """
  87. Receive a sequence of frames that belong together:
  88. - An initial frame with non-zero opcode
  89. - Zero or more frames with opcode = 0 and final = False
  90. - A final frame with opcode = 0 and final = True
  91. The first and last frame may be the same frame, having a non-zero opcode
  92. and final = True. Thus, this function returns a list of at least a single
  93. frame.
  94. """
  95. fragments = [receive_frame(sock)]
  96. while not fragments[-1].final:
  97. fragments.append(receive_frame(sock))
  98. return fragments
  99. def receive_frame(sock):
  100. """
  101. Receive a single frame on the given socket.
  102. """
  103. b1, b2 = struct.unpack('!BB', recvn(sock, 2))
  104. final = bool(b1 & 0x80)
  105. rsv1 = bool(b1 & 0x40)
  106. rsv2 = bool(b1 & 0x20)
  107. rsv3 = bool(b1 & 0x10)
  108. opcode = b1 & 0x0F
  109. mask = bool(b2 & 0x80)
  110. payload_len = b2 & 0x7F
  111. if payload_len == 126:
  112. payload_len = struct.unpack('!H', recvn(sock, 2))
  113. elif payload_len == 127:
  114. payload_len = struct.unpack('!Q', recvn(sock, 8))
  115. if mask:
  116. masking_key = recvn(sock, 4)
  117. payload = mask(masking_key, recvn(sock, payload_len))
  118. else:
  119. masking_key = ''
  120. payload = recvn(sock, payload_len)
  121. return Frame(opcode, payload, masking_key=masking_key, final=final,
  122. rsv1=rsv1, rsv2=rsv2, rsv3=rsv3)
  123. def recvn(sock, n):
  124. """
  125. Keep receiving data from `sock' until exactly `n' bytes have been read.
  126. """
  127. data = ''
  128. while len(data) < n:
  129. received = sock.recv(n - len(data))
  130. if not len(received):
  131. raise SocketClosed()
  132. data += received
  133. return data
  134. def mask(key, original):
  135. """
  136. Mask an octet string using the given masking key.
  137. The following masking algorithm is used, as defined in RFC 6455:
  138. for each octet:
  139. j = i MOD 4
  140. transformed-octet-i = original-octet-i XOR masking-key-octet-j
  141. """
  142. if len(key) != 4:
  143. raise ValueError('invalid masking key "%s"' % key)
  144. key = map(ord, key)
  145. masked = bytearray(original)
  146. for i in xrange(len(masked)):
  147. masked[i] ^= key[i % 4]
  148. return masked