1425bb815Sopenharmony_ci#!/usr/bin/env python 2425bb815Sopenharmony_ci 3425bb815Sopenharmony_ci# Copyright JS Foundation and other contributors, http://js.foundation 4425bb815Sopenharmony_ci# 5425bb815Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License"); 6425bb815Sopenharmony_ci# you may not use this file except in compliance with the License. 7425bb815Sopenharmony_ci# You may obtain a copy of the License at 8425bb815Sopenharmony_ci# 9425bb815Sopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0 10425bb815Sopenharmony_ci# 11425bb815Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software 12425bb815Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS 13425bb815Sopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14425bb815Sopenharmony_ci# See the License for the specific language governing permissions and 15425bb815Sopenharmony_ci# limitations under the License. 16425bb815Sopenharmony_ci 17425bb815Sopenharmony_ciimport struct 18425bb815Sopenharmony_ci 19425bb815Sopenharmony_ciMAX_BUFFER_SIZE = 128 20425bb815Sopenharmony_ciWEBSOCKET_BINARY_FRAME = 2 21425bb815Sopenharmony_ciWEBSOCKET_FIN_BIT = 0x80 22425bb815Sopenharmony_ci 23425bb815Sopenharmony_ciclass WebSocket(object): 24425bb815Sopenharmony_ci def __init__(self, protocol): 25425bb815Sopenharmony_ci 26425bb815Sopenharmony_ci self.data_buffer = b"" 27425bb815Sopenharmony_ci self.protocol = protocol 28425bb815Sopenharmony_ci 29425bb815Sopenharmony_ci def __handshake(self): 30425bb815Sopenharmony_ci """ Client Handshake Request. """ 31425bb815Sopenharmony_ci self.__send_data(b"GET /jerry-debugger HTTP/1.1\r\n" + 32425bb815Sopenharmony_ci b"Upgrade: websocket\r\n" + 33425bb815Sopenharmony_ci b"Connection: Upgrade\r\n" + 34425bb815Sopenharmony_ci b"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n") 35425bb815Sopenharmony_ci 36425bb815Sopenharmony_ci # Expected answer from the handshake. 37425bb815Sopenharmony_ci expected = (b"HTTP/1.1 101 Switching Protocols\r\n" + 38425bb815Sopenharmony_ci b"Upgrade: websocket\r\n" + 39425bb815Sopenharmony_ci b"Connection: Upgrade\r\n" + 40425bb815Sopenharmony_ci b"Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n") 41425bb815Sopenharmony_ci 42425bb815Sopenharmony_ci len_expected = len(expected) 43425bb815Sopenharmony_ci 44425bb815Sopenharmony_ci while len(self.data_buffer) < len_expected: 45425bb815Sopenharmony_ci self.data_buffer += self.protocol.receive_data() 46425bb815Sopenharmony_ci 47425bb815Sopenharmony_ci if self.data_buffer[0:len_expected] != expected: 48425bb815Sopenharmony_ci raise Exception("Unexpected handshake") 49425bb815Sopenharmony_ci 50425bb815Sopenharmony_ci if len(self.data_buffer) > len_expected: 51425bb815Sopenharmony_ci self.data_buffer = self.data_buffer[len_expected:] 52425bb815Sopenharmony_ci else: 53425bb815Sopenharmony_ci self.data_buffer = b"" 54425bb815Sopenharmony_ci 55425bb815Sopenharmony_ci def connect(self, config_size): 56425bb815Sopenharmony_ci """ WebSockets connection. """ 57425bb815Sopenharmony_ci self.protocol.connect() 58425bb815Sopenharmony_ci self.data_buffer = b"" 59425bb815Sopenharmony_ci self.__handshake() 60425bb815Sopenharmony_ci 61425bb815Sopenharmony_ci # It will return with the Network configurations, which has the following struct: 62425bb815Sopenharmony_ci # header [2] - opcode[1], size[1] 63425bb815Sopenharmony_ci # configuration [config_size] 64425bb815Sopenharmony_ci len_expected = config_size + 2 65425bb815Sopenharmony_ci 66425bb815Sopenharmony_ci while len(self.data_buffer) < len_expected: 67425bb815Sopenharmony_ci self.data_buffer += self.protocol.receive_data() 68425bb815Sopenharmony_ci 69425bb815Sopenharmony_ci expected = struct.pack("BB", 70425bb815Sopenharmony_ci WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT, 71425bb815Sopenharmony_ci config_size) 72425bb815Sopenharmony_ci 73425bb815Sopenharmony_ci if self.data_buffer[0:2] != expected: 74425bb815Sopenharmony_ci raise Exception("Unexpected configuration") 75425bb815Sopenharmony_ci 76425bb815Sopenharmony_ci result = self.data_buffer[2:len_expected] 77425bb815Sopenharmony_ci self.data_buffer = self.data_buffer[len_expected:] 78425bb815Sopenharmony_ci 79425bb815Sopenharmony_ci return result 80425bb815Sopenharmony_ci 81425bb815Sopenharmony_ci def __send_data(self, data): 82425bb815Sopenharmony_ci """ Private function to send data using the given protocol. """ 83425bb815Sopenharmony_ci size = len(data) 84425bb815Sopenharmony_ci 85425bb815Sopenharmony_ci while size > 0: 86425bb815Sopenharmony_ci bytes_send = self.protocol.send_data(data) 87425bb815Sopenharmony_ci if bytes_send < size: 88425bb815Sopenharmony_ci data = data[bytes_send:] 89425bb815Sopenharmony_ci size -= bytes_send 90425bb815Sopenharmony_ci 91425bb815Sopenharmony_ci def send_message(self, byte_order, packed_data): 92425bb815Sopenharmony_ci """ Send message. """ 93425bb815Sopenharmony_ci message = struct.pack(byte_order + "BBI", 94425bb815Sopenharmony_ci WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT, 95425bb815Sopenharmony_ci WEBSOCKET_FIN_BIT + struct.unpack(byte_order + "B", packed_data[0])[0], 96425bb815Sopenharmony_ci 0) + packed_data[1:] 97425bb815Sopenharmony_ci 98425bb815Sopenharmony_ci self.__send_data(message) 99425bb815Sopenharmony_ci 100425bb815Sopenharmony_ci def close(self): 101425bb815Sopenharmony_ci """ Close the WebSockets connection. """ 102425bb815Sopenharmony_ci self.protocol.close() 103425bb815Sopenharmony_ci 104425bb815Sopenharmony_ci def get_message(self, blocking): 105425bb815Sopenharmony_ci """ Receive message. """ 106425bb815Sopenharmony_ci 107425bb815Sopenharmony_ci # Connection was closed 108425bb815Sopenharmony_ci if self.data_buffer is None: 109425bb815Sopenharmony_ci return None 110425bb815Sopenharmony_ci 111425bb815Sopenharmony_ci while True: 112425bb815Sopenharmony_ci if len(self.data_buffer) >= 2: 113425bb815Sopenharmony_ci if ord(self.data_buffer[0]) != WEBSOCKET_BINARY_FRAME | WEBSOCKET_FIN_BIT: 114425bb815Sopenharmony_ci raise Exception("Unexpected data frame") 115425bb815Sopenharmony_ci 116425bb815Sopenharmony_ci size = ord(self.data_buffer[1]) 117425bb815Sopenharmony_ci if size == 0 or size >= 126: 118425bb815Sopenharmony_ci raise Exception("Unexpected data frame") 119425bb815Sopenharmony_ci 120425bb815Sopenharmony_ci if len(self.data_buffer) >= size + 2: 121425bb815Sopenharmony_ci result = self.data_buffer[2:size + 2] 122425bb815Sopenharmony_ci self.data_buffer = self.data_buffer[size + 2:] 123425bb815Sopenharmony_ci return result 124425bb815Sopenharmony_ci 125425bb815Sopenharmony_ci if not blocking and not self.protocol.ready(): 126425bb815Sopenharmony_ci return b'' 127425bb815Sopenharmony_ci 128425bb815Sopenharmony_ci data = self.protocol.receive_data(MAX_BUFFER_SIZE) 129425bb815Sopenharmony_ci 130425bb815Sopenharmony_ci if not data: 131425bb815Sopenharmony_ci self.data_buffer = None 132425bb815Sopenharmony_ci return None 133425bb815Sopenharmony_ci self.data_buffer += data 134