13
13
See the License for the specific language governing permissions and
14
14
limitations under the License.
15
15
"""
16
-
17
- import urllib2
16
+ try :
17
+ from urllib .parse import unquote
18
+ except :
19
+ import urllib2
20
+ unquote = urllib2 .unquote
18
21
from 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
21
30
import webbrowser
22
31
import struct
32
+ import binascii
23
33
from base64 import b64encode
34
+ import hashlib
24
35
from 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
27
51
import threading
28
52
from threading import Timer
29
53
30
54
31
55
clients = {}
32
56
updateTimerStarted = False # to start the update timer only once
33
57
58
+ pyLessThan3 = sys .version_info < (3 ,)
34
59
35
60
def get_method_by (rootNode , idname ):
36
61
if idname .isdigit ():
@@ -74,16 +99,16 @@ def get_method_by_id(rootNode, _id, maxIter=5):
74
99
75
100
76
101
class ThreadedWebsocketServer (
77
- SocketServer .ThreadingMixIn , SocketServer .TCPServer ):
102
+ socketserver .ThreadingMixIn , socketserver .TCPServer ):
78
103
allow_reuse_address = True
79
104
80
105
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'
83
108
84
109
def setup (self ):
85
110
global clients
86
- SocketServer .StreamRequestHandler .setup (self )
111
+ socketserver .StreamRequestHandler .setup (self )
87
112
print ('websocket connection established' , self .client_address )
88
113
self .handshake_done = False
89
114
@@ -94,53 +119,61 @@ def handle(self):
94
119
self .handshake ()
95
120
else :
96
121
if not self .read_next_message ():
122
+ print ('ending websocket service...' )
97
123
break
124
+
125
+ def bytetonum (self ,b ):
126
+ if pyLessThan3 :
127
+ b = ord (b )
128
+ return b
98
129
99
130
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
115
144
116
145
def send_message (self , message ):
146
+ out = bytearray ()
147
+ out .append (129 )
117
148
print ('send_message\n ' )
118
- self .request .send (chr (129 ))
119
149
length = len (message )
120
150
if length <= 125 :
121
- self . request . send ( chr ( length ) )
151
+ out . append ( length )
122
152
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 )
125
155
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 )
129
160
130
161
def handshake (self ):
131
162
print ('handshake\n ' )
132
163
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 ]))
136
165
print ('Handshaking...' )
137
166
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 )
139
171
response = 'HTTP/1.1 101 Switching Protocols\r \n '
140
172
response += 'Upgrade: websocket\r \n '
141
173
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
144
177
145
178
def on_message (self , message ):
146
179
# saving the websocket in order to update the client
@@ -243,11 +276,11 @@ def gui_updater(client, leaf):
243
276
if leaf .repr_without_children () != client .old_runtime_widgets [__id ]:
244
277
#client.old_runtime_widgets[__id] = repr(leaf)
245
278
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')
251
284
client .old_runtime_widgets [__id ] = leaf .repr_without_children ()
252
285
return True
253
286
# widget NOT changed
@@ -371,15 +404,15 @@ def do_POST(self):
371
404
self .instance ()
372
405
varLen = int (self .headers ['Content-Length' ])
373
406
postVars = self .rfile .read (varLen )
374
- postVars = str (urllib2 . unquote (postVars ). decode ( 'utf8' ))
407
+ postVars = str (unquote (postVars ))
375
408
paramDict = parse_parametrs (postVars )
376
- function = str (urllib2 . unquote (self .path ). decode ( 'utf8' ))
409
+ function = str (unquote (self .path ))
377
410
self .process_all (function , paramDict , True )
378
411
379
412
def do_GET (self ):
380
413
"""Handler for the GET requests."""
381
414
self .instance ()
382
- params = str (urllib2 . unquote (self .path ). decode ( 'utf8' ))
415
+ params = str (unquote (self .path ))
383
416
384
417
params = params .split ('?' )
385
418
function = params [0 ]
@@ -431,13 +464,13 @@ def process_all(self, function, paramDict, isPost):
431
464
self .send_header ('Content-type' , 'text/html' )
432
465
self .end_headers ()
433
466
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 ((
436
469
"<link href='" +
437
470
BASE_ADDRESS +
438
- "style.css' rel='stylesheet' />" )
471
+ "style.css' rel='stylesheet' />" ). encode ( 'utf-8' ))
439
472
440
- self .wfile .write (repr (self .client .root ))
473
+ self .wfile .write (repr (self .client .root ). encode ( 'utf-8' ) )
441
474
else :
442
475
# here is the function that should return the content type
443
476
self .send_response (200 )
@@ -448,13 +481,13 @@ def process_all(self, function, paramDict, isPost):
448
481
# if is requested a widget, but not by post, so we suppose is
449
482
# requested to show a new page, we attach javascript and style
450
483
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 ((
453
486
"<link href='" +
454
487
BASE_ADDRESS +
455
- "style.css' rel='stylesheet' />" )
488
+ "style.css' rel='stylesheet' />" ). encode ( 'utf-8' ))
456
489
457
- self .wfile .write (ret [0 ])
490
+ self .wfile .write (ret [0 ]. encode ( 'utf-8' ) )
458
491
459
492
else :
460
493
self .send_response (200 )
@@ -464,12 +497,12 @@ def process_all(self, function, paramDict, isPost):
464
497
self .end_headers ()
465
498
466
499
f = open ('./' + function , 'r+b' )
467
- content = '' .join (f .readlines ())
500
+ content = b '' .join (f .readlines ())
468
501
f .close ()
469
502
self .wfile .write (content )
470
503
471
504
472
- class ThreadedHTTPServer (SocketServer .ThreadingMixIn , HTTPServer ):
505
+ class ThreadedHTTPServer (socketserver .ThreadingMixIn , HTTPServer ):
473
506
474
507
"""This class allows to handle requests in separated threads.
475
508
0 commit comments