1313 See the License for the specific language governing permissions and
1414 limitations under the License.
1515"""
16-
17- import urllib2
16+ try :
17+ from urllib .parse import unquote
18+ except :
19+ import urllib2
20+ unquote = urllib2 .unquote
1821from configuration import runtimeInstances , MULTIPLE_INSTANCE , ENABLE_FILE_CACHE , BASE_ADDRESS , HTTP_PORT_NUMBER , WEBSOCKET_PORT_NUMBER , IP_ADDR , UPDATE_INTERVAL
19- from BaseHTTPServer import HTTPServer , BaseHTTPRequestHandler
20- import SocketServer
22+ try :
23+ from http .server import HTTPServer , BaseHTTPRequestHandler
24+ except :
25+ from BaseHTTPServer import HTTPServer , BaseHTTPRequestHandler
26+ try :
27+ import socketserver
28+ except :
29+ import SocketServer as socketserver
2130import webbrowser
2231import struct
32+ import binascii
2333from base64 import b64encode
34+ import hashlib
2435from hashlib import sha1
25- from mimetools import Message
26- from StringIO import StringIO
36+ import sys
37+ try :
38+ import email
39+ Message = email .message_from_string
40+ except :
41+ from mimetools import Message
42+ try :
43+ import io
44+ def StringIO (v ):
45+ v = io .BytesIO (v )
46+ v = b'' .join (v .readlines ()).decode ("utf-8" )
47+ return v
48+ #StringIO = io.BytesIO
49+ except :
50+ from StringIO import StringIO
2751import threading
2852from threading import Timer
2953
3054
3155clients = {}
3256updateTimerStarted = False # to start the update timer only once
3357
58+ pyLessThan3 = sys .version_info < (3 ,)
3459
3560def get_method_by (rootNode , idname ):
3661 if idname .isdigit ():
@@ -74,16 +99,16 @@ def get_method_by_id(rootNode, _id, maxIter=5):
7499
75100
76101class ThreadedWebsocketServer (
77- SocketServer .ThreadingMixIn , SocketServer .TCPServer ):
102+ socketserver .ThreadingMixIn , socketserver .TCPServer ):
78103 allow_reuse_address = True
79104
80105
81- class WebSocketsHandler (SocketServer .StreamRequestHandler ):
82- magic = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
106+ class WebSocketsHandler (socketserver .StreamRequestHandler ):
107+ magic = b '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
83108
84109 def setup (self ):
85110 global clients
86- SocketServer .StreamRequestHandler .setup (self )
111+ socketserver .StreamRequestHandler .setup (self )
87112 print ('websocket connection established' , self .client_address )
88113 self .handshake_done = False
89114
@@ -94,53 +119,61 @@ def handle(self):
94119 self .handshake ()
95120 else :
96121 if not self .read_next_message ():
122+ print ('ending websocket service...' )
97123 break
124+
125+ def bytetonum (self ,b ):
126+ if pyLessThan3 :
127+ b = ord (b )
128+ return b
98129
99130 def read_next_message (self ):
100- try :
101- print ('read_next_message\n ' )
102- length = ord (self .rfile .read (2 )[1 ]) & 127
103- if length == 126 :
104- length = struct .unpack ('>H' , self .rfile .read (2 ))[0 ]
105- elif length == 127 :
106- length = struct .unpack ('>Q' , self .rfile .read (8 ))[0 ]
107- masks = [ord (byte ) for byte in self .rfile .read (4 )]
108- decoded = ''
109- for char in self .rfile .read (length ):
110- decoded += chr (ord (char ) ^ masks [len (decoded ) % 4 ])
111- self .on_message (decoded )
112- return True
113- except :
114- return False
131+ print ('read_next_message\n ' )
132+ length = self .rfile .read (2 )
133+ length = self .bytetonum (length [1 ]) & 127
134+ if length == 126 :
135+ length = struct .unpack ('>H' , self .rfile .read (2 ))[0 ]
136+ elif length == 127 :
137+ length = struct .unpack ('>Q' , self .rfile .read (8 ))[0 ]
138+ masks = [self .bytetonum (byte ) for byte in self .rfile .read (4 )]
139+ decoded = ''
140+ for char in self .rfile .read (length ):
141+ decoded += chr (self .bytetonum (char ) ^ masks [len (decoded ) % 4 ])
142+ self .on_message (decoded )
143+ return True
115144
116145 def send_message (self , message ):
146+ out = bytearray ()
147+ out .append (129 )
117148 print ('send_message\n ' )
118- self .request .send (chr (129 ))
119149 length = len (message )
120150 if length <= 125 :
121- self . request . send ( chr ( length ) )
151+ out . append ( length )
122152 elif length >= 126 and length <= 65535 :
123- self . request . send ( chr ( 126 ) )
124- self . request . send ( struct .pack ('>H' , length ) )
153+ out . append ( 126 )
154+ out = out + struct .pack ('>H' , length )
125155 else :
126- self .request .send (chr (127 ))
127- self .request .send (struct .pack ('>Q' , length ))
128- self .request .send (message )
156+ out .append (127 )
157+ out = out + struct .pack ('>Q' , length )
158+ out = out + message .encode ()
159+ self .request .send (out )
129160
130161 def handshake (self ):
131162 print ('handshake\n ' )
132163 data = self .request .recv (1024 ).strip ()
133- headers = Message (StringIO (data .split ('\r \n ' , 1 )[1 ]))
134- # if headers.get("Upgrade", None) != "websocket":
135- # return
164+ headers = Message (StringIO (data .split (b'\r \n ' , 1 )[1 ]))
136165 print ('Handshaking...' )
137166 key = headers ['Sec-WebSocket-Key' ]
138- digest = b64encode (sha1 (key + self .magic ).hexdigest ().decode ('hex' ))
167+ key = key
168+ digest = hashlib .sha1 ((key .encode ("utf-8" )+ self .magic ))
169+ digest = digest .digest ()
170+ digest = b64encode (digest )
139171 response = 'HTTP/1.1 101 Switching Protocols\r \n '
140172 response += 'Upgrade: websocket\r \n '
141173 response += 'Connection: Upgrade\r \n '
142- response += 'Sec-WebSocket-Accept: %s\r \n \r \n ' % digest
143- self .handshake_done = self .request .send (response )
174+ response += 'Sec-WebSocket-Accept: %s\r \n \r \n ' % digest .decode ("utf-8" )
175+ self .request .sendall (response .encode ("utf-8" ))
176+ self .handshake_done = True
144177
145178 def on_message (self , message ):
146179 # saving the websocket in order to update the client
@@ -243,11 +276,11 @@ def gui_updater(client, leaf):
243276 if leaf .repr_without_children () != client .old_runtime_widgets [__id ]:
244277 #client.old_runtime_widgets[__id] = repr(leaf)
245278 for ws in client .websockets :
246- try :
247- print ('update_widget: ' + __id + ' type: ' + str (type (leaf )))
248- ws .send_message ('update_widget,' + __id + ',' + repr (leaf ))
249- except :
250- print ('exception here, server.py - gui_updater, id2' )
279+ # try:
280+ print ('update_widget: ' + __id + ' type: ' + str (type (leaf )))
281+ ws .send_message ('update_widget,' + __id + ',' + repr (leaf ))
282+ # except:
283+ # print('exception here, server.py - gui_updater, id2')
251284 client .old_runtime_widgets [__id ] = leaf .repr_without_children ()
252285 return True
253286 # widget NOT changed
@@ -371,15 +404,15 @@ def do_POST(self):
371404 self .instance ()
372405 varLen = int (self .headers ['Content-Length' ])
373406 postVars = self .rfile .read (varLen )
374- postVars = str (urllib2 . unquote (postVars ). decode ( 'utf8' ))
407+ postVars = str (unquote (postVars ))
375408 paramDict = parse_parametrs (postVars )
376- function = str (urllib2 . unquote (self .path ). decode ( 'utf8' ))
409+ function = str (unquote (self .path ))
377410 self .process_all (function , paramDict , True )
378411
379412 def do_GET (self ):
380413 """Handler for the GET requests."""
381414 self .instance ()
382- params = str (urllib2 . unquote (self .path ). decode ( 'utf8' ))
415+ params = str (unquote (self .path ))
383416
384417 params = params .split ('?' )
385418 function = params [0 ]
@@ -431,13 +464,13 @@ def process_all(self, function, paramDict, isPost):
431464 self .send_header ('Content-type' , 'text/html' )
432465 self .end_headers ()
433466
434- self .wfile .write (self .client .attachments )
435- self .wfile .write (
467+ self .wfile .write (self .client .attachments . encode ( 'utf-8' ) )
468+ self .wfile .write ((
436469 "<link href='" +
437470 BASE_ADDRESS +
438- "style.css' rel='stylesheet' />" )
471+ "style.css' rel='stylesheet' />" ). encode ( 'utf-8' ))
439472
440- self .wfile .write (repr (self .client .root ))
473+ self .wfile .write (repr (self .client .root ). encode ( 'utf-8' ) )
441474 else :
442475 # here is the function that should return the content type
443476 self .send_response (200 )
@@ -448,13 +481,13 @@ def process_all(self, function, paramDict, isPost):
448481 # if is requested a widget, but not by post, so we suppose is
449482 # requested to show a new page, we attach javascript and style
450483 if (ret [1 ] == 'text/html' and isPost == False ):
451- self .wfile .write (self .client .attachments )
452- self .wfile .write (
484+ self .wfile .write (self .client .attachments . encode ( 'utf-8' ) )
485+ self .wfile .write ((
453486 "<link href='" +
454487 BASE_ADDRESS +
455- "style.css' rel='stylesheet' />" )
488+ "style.css' rel='stylesheet' />" ). encode ( 'utf-8' ))
456489
457- self .wfile .write (ret [0 ])
490+ self .wfile .write (ret [0 ]. encode ( 'utf-8' ) )
458491
459492 else :
460493 self .send_response (200 )
@@ -464,12 +497,12 @@ def process_all(self, function, paramDict, isPost):
464497 self .end_headers ()
465498
466499 f = open ('./' + function , 'r+b' )
467- content = '' .join (f .readlines ())
500+ content = b '' .join (f .readlines ())
468501 f .close ()
469502 self .wfile .write (content )
470503
471504
472- class ThreadedHTTPServer (SocketServer .ThreadingMixIn , HTTPServer ):
505+ class ThreadedHTTPServer (socketserver .ThreadingMixIn , HTTPServer ):
473506
474507 """This class allows to handle requests in separated threads.
475508
0 commit comments