• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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