Skip to content

Commit d04e206

Browse files
committed
Update server.py
Now python3.x compatible!
1 parent 969c1f5 commit d04e206

File tree

1 file changed

+89
-56
lines changed

1 file changed

+89
-56
lines changed

server.py

Lines changed: 89 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,49 @@
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
1821
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
2130
import webbrowser
2231
import struct
32+
import binascii
2333
from base64 import b64encode
34+
import hashlib
2435
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
2751
import threading
2852
from threading import Timer
2953

3054

3155
clients = {}
3256
updateTimerStarted = False # to start the update timer only once
3357

58+
pyLessThan3 = sys.version_info < (3,)
3459

3560
def get_method_by(rootNode, idname):
3661
if idname.isdigit():
@@ -74,16 +99,16 @@ def get_method_by_id(rootNode, _id, maxIter=5):
7499

75100

76101
class 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

Comments
 (0)