1#!/usr/bin/env python 2 3# Copyright JS Foundation and other contributors, http://js.foundation 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import struct 18 19MAX_BUFFER_SIZE = 128 20WEBSOCKET_BINARY_FRAME = 2 21WEBSOCKET_FIN_BIT = 0x80 22 23class WebSocket(object): 24 def __init__(self, protocol): 25 26 self.data_buffer = b"" 27 self.protocol = protocol 28 29 def __handshake(self): 30 """ Client Handshake Request. """ 31 self.__send_data(b"GET /jerry-debugger HTTP/1.1\r\n" + 32 b"Upgrade: websocket\r\n" + 33 b"Connection: Upgrade\r\n" + 34 b"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n") 35 36 # Expected answer from the handshake. 37 expected = (b"HTTP/1.1 101 Switching Protocols\r\n" + 38 b"Upgrade: websocket\r\n" + 39 b"Connection: Upgrade\r\n" + 40 b"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n") 41 42 len_expected = len(expected) 43 44 while len(self.data_buffer) < len_expected: 45 self.data_buffer += self.protocol.receive_data() 46 47 if self.data_buffer[0:len_expected] != expected: 48 raise Exception("Unexpected handshake") 49 50 if len(self.data_buffer) > len_expected: 51 self.data_buffer = self.data_buffer[len_expected:] 52 else: 53 self.data_buffer = b"" 54 55 def connect(self, config_size): 56 """ WebSockets connection. """ 57 self.protocol.connect() 58 self.data_buffer = b"" 59 self.__handshake() 60 61 # It will return with the Network configurations, which has the following struct: 62 # header [2] - opcode[1], size[1] 63 # configuration [config_size] 64 len_expected = config_size + 2 65 66 while len(self.data_buffer) < len_expected: 67 self.data_buffer += self.protocol.receive_data() 68 69 expected = struct.pack("BB", 70 WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT, 71 config_size) 72 73 if self.data_buffer[0:2] != expected: 74 raise Exception("Unexpected configuration") 75 76 result = self.data_buffer[2:len_expected] 77 self.data_buffer = self.data_buffer[len_expected:] 78 79 return result 80 81 def __send_data(self, data): 82 """ Private function to send data using the given protocol. """ 83 size = len(data) 84 85 while size > 0: 86 bytes_send = self.protocol.send_data(data) 87 if bytes_send < size: 88 data = data[bytes_send:] 89 size -= bytes_send 90 91 def send_message(self, byte_order, packed_data): 92 """ Send message. """ 93 message = struct.pack(byte_order + "BBI", 94 WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT, 95 WEBSOCKET_FIN_BIT + struct.unpack(byte_order + "B", packed_data[0])[0], 96 0) + packed_data[1:] 97 98 self.__send_data(message) 99 100 def close(self): 101 """ Close the WebSockets connection. """ 102 self.protocol.close() 103 104 def get_message(self, blocking): 105 """ Receive message. """ 106 107 # Connection was closed 108 if self.data_buffer is None: 109 return None 110 111 while True: 112 if len(self.data_buffer) >= 2: 113 if ord(self.data_buffer[0]) != WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT: 114 raise Exception("Unexpected data frame") 115 116 size = ord(self.data_buffer[1]) 117 if size == 0 or size >= 126: 118 raise Exception("Unexpected data frame") 119 120 if len(self.data_buffer) >= size + 2: 121 result = self.data_buffer[2:size + 2] 122 self.data_buffer = self.data_buffer[size + 2:] 123 return result 124 125 if not blocking and not self.protocol.ready(): 126 return b'' 127 128 data = self.protocol.receive_data(MAX_BUFFER_SIZE) 129 130 if not data: 131 self.data_buffer = None 132 return None 133 self.data_buffer += data 134