66from base64 import b64encode
77from hashlib import sha1
88
9+
910if sys .version_info [0 ] < 3 :
1011 from SocketServer import ThreadingMixIn , TCPServer , StreamRequestHandler
1112else :
@@ -102,6 +103,7 @@ def handler_to_client(self, handler):
102103 return client
103104
104105
106+
105107class WebSocketHandler (StreamRequestHandler ):
106108
107109 def __init__ (self , socket , addr , server ):
@@ -122,13 +124,14 @@ def handle(self):
122124 self .read_next_message ()
123125
124126 def read_next_message (self ):
127+
125128 b1 = self .rfile .read (1 )
126129 b2 = self .rfile .read (1 )
127130 FIN = ord (b1 ) & 0b10000000
128131 OPCODE = ord (b1 ) & 0b00001111
129132 MASKED = ord (b2 ) & 0b10000000
130133 LENGTH = ord (b2 ) & 0b01111111
131-
134+
132135 if not b1 :
133136 print ("Client closed connection." )
134137 self .keep_alive = 0
@@ -191,35 +194,47 @@ def send_text(self, message):
191194 Fragmented(=continuation) messages are not being used since their usage
192195 is needed in very limited cases - when we don't know the payload length.
193196 '''
194-
197+
195198 # 0 = '0x00' = 0b00000000
196199 # 125 = '0x7d' = 0b01111101
197200 # 126 = '0x7e' = 0b01111110
198201 # 127 = '0x7f' = 0b01111111
199202 # 128 = '0x80' = 0b10000000
200203 # 129 = '0x81' = 0b10000001
201- length = len (message )
204+
205+ # assure message is of acceptable format and encode to UTF-8 if needed
206+ encoded_message = None
207+ if isinstance (message , bytes ):
208+ message = try_decode_UTF8 (message ) # this is slower but assures we have UTF-8
209+ if not message :
210+ print ("Can\' t send message, message is not valid UTF-8" )
211+ return False
212+ else :
213+ print ('Can\' t send message, message has to be a string or bytes. Given type is %s' % type (message ))
214+ return False
215+ encoded_message = encode_to_UTF8 (message )
216+ length = len (encoded_message )
202217
203218 # normal payload
204219 if length <= 125 :
205220 #print("sending single frame of size %s", length)
206221 self .request .send (b'\x81 ' )
207222 self .request .send (chr (length ).encode ())
208- self .request .send (unicode ( message , 'UTF-8' ) )
223+ self .request .send (encoded_message )
209224
210225 # extended payload
211226 elif length >= 126 and length <= 65535 :
212227 #print("sending extended frame of size %s", length)
213228 self .request .send (b'\x81 \x7e ' )
214229 self .request .send (struct .pack (">H" , length )) # MUST be 16bits
215- self .request .send (unicode ( message , 'UTF-8' ) )
230+ self .request .send (encoded_message )
216231
217232 # huge extended payload
218233 elif length < 18446744073709551616 :
219234 #print("sending extended frame of size %s", length)
220235 self .request .send (b'\x81 \x7f ' )
221236 self .request .send (struct .pack (">Q" , length )) # MUST be 64bits
222- self .request .send (unicode ( message , 'UTF-8' ) )
237+ self .request .send (encoded_message )
223238
224239 def handshake (self ):
225240 message = self .request .recv (1024 ).decode ().strip ()
@@ -238,15 +253,15 @@ def handshake(self):
238253 self .handshake_done = self .request .send (response .encode ())
239254 self .valid_client = True
240255 self .server ._new_client_ (self )
241-
256+
242257 def make_handshake_response (self , key ):
243258 return \
244259 'HTTP/1.1 101 Switching Protocols\r \n ' \
245260 'Upgrade: websocket\r \n ' \
246261 'Connection: Upgrade\r \n ' \
247262 'Sec-WebSocket-Accept: %s\r \n ' \
248263 '\r \n ' % self .calculate_response_key (key )
249-
264+
250265 def calculate_response_key (self , key ):
251266 GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
252267 hash = sha1 (key .encode () + GUID .encode ())
@@ -257,6 +272,29 @@ def finish(self):
257272 self .server ._client_left_ (self )
258273
259274
275+
276+ def encode_to_UTF8 (data ):
277+ try :
278+ return data .encode ('UTF-8' )
279+ except UnicodeEncodeError as e :
280+ print ("Could not encode data to UTF-8 -- %s" % e )
281+ return False
282+ except Exception as e :
283+ raise (e )
284+ return False
285+
286+
287+
288+ def try_decode_UTF8 (data ):
289+ try :
290+ return data .decode ('utf-8' )
291+ except UnicodeDecodeError :
292+ return False
293+ except Exception as e :
294+ raise (e )
295+
296+
297+
260298# This is only for testing purposes
261299class DummyWebsocketHandler (WebSocketHandler ):
262300 def __init__ (self , * _ ):
0 commit comments