summaryrefslogtreecommitdiff
path: root/websockify
diff options
context:
space:
mode:
Diffstat (limited to 'websockify')
-rw-r--r--websockify/auth_plugins.py12
-rw-r--r--websockify/sysloghandler.py2
-rw-r--r--websockify/token_plugins.py71
-rw-r--r--websockify/websocket.py186
-rw-r--r--websockify/websocketproxy.py63
-rw-r--r--websockify/websocketserver.py14
-rw-r--r--websockify/websockifyserver.py91
7 files changed, 221 insertions, 218 deletions
diff --git a/websockify/auth_plugins.py b/websockify/auth_plugins.py
index 2d636c2..36fac52 100644
--- a/websockify/auth_plugins.py
+++ b/websockify/auth_plugins.py
@@ -1,4 +1,4 @@
-class BasePlugin(object):
+class BasePlugin():
def __init__(self, src=None):
self.source = src
@@ -15,7 +15,7 @@ class AuthenticationError(Exception):
if log_msg is None:
log_msg = response_msg
- super(AuthenticationError, self).__init__('%s %s' % (self.code, log_msg))
+ super().__init__('%s %s' % (self.code, log_msg))
class InvalidOriginError(AuthenticationError):
@@ -23,13 +23,13 @@ class InvalidOriginError(AuthenticationError):
self.expected_origin = expected
self.actual_origin = actual
- super(InvalidOriginError, self).__init__(
+ super().__init__(
response_msg='Invalid Origin',
log_msg="Invalid Origin Header: Expected one of "
"%s, got '%s'" % (expected, actual))
-class BasicHTTPAuth(object):
+class BasicHTTPAuth():
"""Verifies Basic Auth headers. Specify src as username:password"""
def __init__(self, src=None):
@@ -76,7 +76,7 @@ class BasicHTTPAuth(object):
raise AuthenticationError(response_code=401,
response_headers={'WWW-Authenticate': 'Basic realm="Websockify"'})
-class ExpectOrigin(object):
+class ExpectOrigin():
def __init__(self, src=None):
if src is None:
self.source = []
@@ -88,7 +88,7 @@ class ExpectOrigin(object):
if origin is None or origin not in self.source:
raise InvalidOriginError(expected=self.source, actual=origin)
-class ClientCertCNAuth(object):
+class ClientCertCNAuth():
"""Verifies client by SSL certificate. Specify src as whitespace separated list of common names."""
def __init__(self, src=None):
diff --git a/websockify/sysloghandler.py b/websockify/sysloghandler.py
index 92ca66f..37ee9dd 100644
--- a/websockify/sysloghandler.py
+++ b/websockify/sysloghandler.py
@@ -44,7 +44,7 @@ class WebsockifySysLogHandler(handlers.SysLogHandler):
self._legacy = True
self._head_fmt = self._legacy_head_fmt
- handlers.SysLogHandler.__init__(self, address, facility, socktype)
+ super().__init__(address, facility, socktype)
def emit(self, record):
diff --git a/websockify/token_plugins.py b/websockify/token_plugins.py
index 1f01e0a..0484023 100644
--- a/websockify/token_plugins.py
+++ b/websockify/token_plugins.py
@@ -1,9 +1,9 @@
-from __future__ import print_function
import os
import sys
+import time
import re
-class BasePlugin(object):
+class BasePlugin():
def __init__(self, src):
self.source = src
@@ -16,7 +16,7 @@ class ReadOnlyTokenFile(BasePlugin):
# token: host:port
# or a directory of such files
def __init__(self, *args, **kwargs):
- super(ReadOnlyTokenFile, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
self._targets = None
def _load_targets(self):
@@ -35,7 +35,7 @@ class ReadOnlyTokenFile(BasePlugin):
tok, target = re.split(':\s', line)
self._targets[tok] = target.strip().rsplit(':', 1)
except ValueError:
- print >>sys.stderr, "Syntax error in %s on line %d" % (self.source, index)
+ print("Syntax error in %s on line %d" % (self.source, index), file=sys.stderr)
index += 1
def lookup(self, token):
@@ -58,7 +58,7 @@ class TokenFile(ReadOnlyTokenFile):
def lookup(self, token):
self._load_targets()
- return super(TokenFile, self).lookup(token)
+ return super().lookup(token)
class BaseTokenAPI(BasePlugin):
@@ -129,6 +129,18 @@ class JWTTokenApi(BasePlugin):
token = jwt.JWT(key=key, jwt=token.claims)
parsed = json.loads(token.claims)
+
+ if 'nbf' in parsed:
+ # Not Before is present, so we need to check it
+ if time.time() < parsed['nbf']:
+ print('Token can not be used yet!', file=sys.stderr)
+ return None
+
+ if 'exp' in parsed:
+ # Expiration time is present, so we need to check it
+ if time.time() > parsed['exp']:
+ print('Token has expired!', file=sys.stderr)
+ return None
return (parsed['host'], parsed['port'])
except Exception as e:
@@ -138,32 +150,63 @@ class JWTTokenApi(BasePlugin):
print("package jwcrypto not found, are you sure you've installed it correctly?", file=sys.stderr)
return None
-class TokenRedis(object):
+class TokenRedis():
+ """
+ The TokenRedis plugin expects the format of the data in a form of json.
+
+ Prepare data with:
+ redis-cli set hello '{"host":"127.0.0.1:5000"}'
+
+ Verify with:
+ redis-cli --raw get hello
+
+ Spawn a test "server" using netcat
+ nc -l 5000 -v
+
+ Note: you have to install also the 'redis' and 'simplejson' modules
+ pip install redis simplejson
+ """
def __init__(self, src):
- self._server, self._port = src.split(":")
+ try:
+ # import those ahead of time so we provide error earlier
+ import redis
+ import simplejson
+ self._server, self._port = src.split(":")
+ print("TokenRedis backend initilized (%s:%s)" %
+ (self._server, self._port), file=sys.stderr)
+ except ValueError:
+ print("The provided --token-source='%s' is not in an expected format <host>:<port>" %
+ src, file=sys.stderr)
+ sys.exit()
+ except ImportError:
+ print("package redis or simplejson not found, are you sure you've installed them correctly?", file=sys.stderr)
+ sys.exit()
def lookup(self, token):
try:
import redis
import simplejson
- except ImportError as e:
+ except ImportError:
print("package redis or simplejson not found, are you sure you've installed them correctly?", file=sys.stderr)
- return None
+ sys.exit()
- client = redis.Redis(host=self._server,port=self._port)
+ print("resolving token '%s'" % token, file=sys.stderr)
+ client = redis.Redis(host=self._server, port=self._port)
stuff = client.get(token)
if stuff is None:
return None
else:
- combo = simplejson.loads(stuff.decode("utf-8"))
+ responseStr = stuff.decode("utf-8")
+ print("response from redis : %s" % responseStr, file=sys.stderr)
+ combo = simplejson.loads(responseStr)
(host, port) = combo["host"].split(':')
- port = port.encode('ascii','ignore')
- return [ host, port ]
+ print("host: %s, port: %s" % (host,port), file=sys.stderr)
+ return [host, port]
class UnixDomainSocketDirectory(BasePlugin):
def __init__(self, *args, **kwargs):
- super(UnixDomainSocketDirectory, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
self._dir_path = os.path.abspath(self.source)
def lookup(self, token):
diff --git a/websockify/websocket.py b/websockify/websocket.py
index c8226cc..f0db3ba 100644
--- a/websockify/websocket.py
+++ b/websockify/websocket.py
@@ -22,6 +22,7 @@ import ssl
import struct
from base64 import b64encode
from hashlib import sha1
+from urllib.parse import urlparse
try:
import numpy
@@ -30,25 +31,10 @@ except ImportError:
warnings.warn("no 'numpy' module, HyBi protocol will be slower")
numpy = None
-# python 3.0 differences
-try:
- from urllib.parse import urlparse
-except ImportError:
- from urlparse import urlparse
-
-# SSLWant*Error is 2.7.9+
-try:
- class WebSocketWantReadError(ssl.SSLWantReadError):
- pass
- class WebSocketWantWriteError(ssl.SSLWantWriteError):
- pass
-except AttributeError:
- class WebSocketWantReadError(OSError):
- def __init__(self):
- OSError.__init__(self, errno.EWOULDBLOCK)
- class WebSocketWantWriteError(OSError):
- def __init__(self):
- OSError.__init__(self, errno.EWOULDBLOCK)
+class WebSocketWantReadError(ssl.SSLWantReadError):
+ pass
+class WebSocketWantWriteError(ssl.SSLWantWriteError):
+ pass
class WebSocket(object):
"""WebSocket protocol socket like class.
@@ -87,11 +73,13 @@ class WebSocket(object):
self._state = "new"
- self._partial_msg = ''.encode("ascii")
+ self._partial_msg = b''
- self._recv_buffer = ''.encode("ascii")
+ self._recv_buffer = b''
self._recv_queue = []
- self._send_buffer = ''.encode("ascii")
+ self._send_buffer = b''
+
+ self._previous_sendmsg = None
self._sent_close = False
self._received_close = False
@@ -164,9 +152,7 @@ class WebSocket(object):
self._key = ''
for i in range(16):
self._key += chr(random.randrange(256))
- if sys.hexversion >= 0x3000000:
- self._key = bytes(self._key, "latin-1")
- self._key = b64encode(self._key).decode("ascii")
+ self._key = b64encode(self._key.encode("latin-1")).decode("ascii")
path = uri.path
if not path:
@@ -196,10 +182,10 @@ class WebSocket(object):
if not self._recv():
raise Exception("Socket closed unexpectedly")
- if self._recv_buffer.find('\r\n\r\n'.encode("ascii")) == -1:
+ if self._recv_buffer.find(b'\r\n\r\n') == -1:
raise WebSocketWantReadError
- (request, self._recv_buffer) = self._recv_buffer.split('\r\n'.encode("ascii"), 1)
+ (request, self._recv_buffer) = self._recv_buffer.split(b'\r\n', 1)
request = request.decode("latin-1")
words = request.split()
@@ -208,7 +194,7 @@ class WebSocket(object):
if words[1] != "101":
raise Exception("WebSocket request denied: %s" % " ".join(words[1:]))
- (headers, self._recv_buffer) = self._recv_buffer.split('\r\n\r\n'.encode("ascii"), 1)
+ (headers, self._recv_buffer) = self._recv_buffer.split(b'\r\n\r\n', 1)
headers = headers.decode('latin-1') + '\r\n'
headers = email.message_from_string(headers)
@@ -254,8 +240,8 @@ class WebSocket(object):
the value "websocket" in such cases.
WebSocketWantWriteError can be raised if the response cannot be
- sent right away. Repeated calls to accept() does not need to
- retain the arguments.
+ sent right away. accept() must be called again once more space
+ is available using the same arguments.
"""
# This is a state machine in order to handle
@@ -419,8 +405,12 @@ class WebSocket(object):
data from other calls, or split it over multiple messages.
WebSocketWantWriteError can be raised if there is insufficient
- space in the underlying socket.
+ space in the underlying socket. send() must be called again
+ once more space is available using the same arguments.
"""
+ if len(bytes) == 0:
+ return 0
+
return self.sendmsg(bytes)
def sendmsg(self, msg):
@@ -431,23 +421,81 @@ class WebSocket(object):
single WebSocket message.
WebSocketWantWriteError can be raised if there is insufficient
- space in the underlying socket.
+ space in the underlying socket. sendmsg() must be called again
+ once more space is available using the same arguments.
"""
- if not self._sent_close:
- # Only called to flush?
- if msg:
- self._sendmsg(0x2, msg)
+ if not isinstance(msg, bytes):
+ raise TypeError
+
+ if self._sent_close:
+ return 0
+
+ if self._previous_sendmsg is not None:
+ if self._previous_sendmsg != msg:
+ raise ValueError
+
+ self._flush()
+ self._previous_sendmsg = None
+
+ return len(msg)
+
+ try:
+ self._sendmsg(0x2, msg)
+ except WebSocketWantWriteError:
+ self._previous_sendmsg = msg
+ raise
- self._flush()
return len(msg)
- def ping(self, data=''.encode('ascii')):
- """Write a ping message to the WebSocket."""
- self._sendmsg(0x9, data)
+ def ping(self, data=b''):
+ """Write a ping message to the WebSocket
+
+ WebSocketWantWriteError can be raised if there is insufficient
+ space in the underlying socket. ping() must be called again once
+ more space is available using the same arguments.
+ """
+ if not isinstance(data, bytes):
+ raise TypeError
+
+ if self._previous_sendmsg is not None:
+ if self._previous_sendmsg != data:
+ raise ValueError
+
+ self._flush()
+ self._previous_sendmsg = None
+
+ return
+
+ try:
+ self._sendmsg(0x9, data)
+ except WebSocketWantWriteError:
+ self._previous_sendmsg = data
+ raise
- def pong(self, data=''.encode('ascii')):
- """Write a pong message to the WebSocket."""
- self._sendmsg(0xA, data)
+ def pong(self, data=b''):
+ """Write a pong message to the WebSocket
+
+ WebSocketWantWriteError can be raised if there is insufficient
+ space in the underlying socket. pong() must be called again once
+ more space is available using the same arguments.
+ """
+ if not isinstance(data, bytes):
+ raise TypeError
+
+ if self._previous_sendmsg is not None:
+ if self._previous_sendmsg != data:
+ raise ValueError
+
+ self._flush()
+ self._previous_sendmsg = None
+
+ return
+
+ try:
+ self._sendmsg(0xA, data)
+ except WebSocketWantWriteError:
+ self._previous_sendmsg = data
+ raise
def shutdown(self, how, code=1000, reason=None):
"""Gracefully terminate the WebSocket connection.
@@ -459,7 +507,9 @@ class WebSocket(object):
ignored.
WebSocketWantWriteError can be raised if there is insufficient
- space in the underlying socket for the close message.
+ space in the underlying socket for the close message. shutdown()
+ must be called again once more space is available using the same
+ arguments.
The how argument is currently ignored.
"""
@@ -476,7 +526,7 @@ class WebSocket(object):
self._sent_close = True
- msg = ''.encode('ascii')
+ msg = b''
if code is not None:
msg += struct.pack(">H", code)
if reason is not None:
@@ -491,7 +541,9 @@ class WebSocket(object):
a close message to the peer.
WebSocketWantWriteError can be raised if there is insufficient
- space in the underlying socket for the close message.
+ space in the underlying socket for the close message. close()
+ must be called again once more space is available using the same
+ arguments.
"""
self.shutdown(socket.SHUT_RDWR, code, reason)
self._close()
@@ -503,16 +555,9 @@ class WebSocket(object):
while True:
try:
data = self.socket.recv(4096)
- except (socket.error, OSError):
- exc = sys.exc_info()[1]
- if hasattr(exc, 'errno'):
- err = exc.errno
- else:
- err = exc[0]
-
- if err == errno.EWOULDBLOCK:
+ except OSError as exc:
+ if exc.errno == errno.EWOULDBLOCK:
raise WebSocketWantReadError
-
raise
if len(data) == 0:
@@ -569,7 +614,7 @@ class WebSocket(object):
if frame["fin"]:
msg = self._partial_msg
- self._partial_msg = ''.decode("ascii")
+ self._partial_msg = b''
return msg
elif frame["opcode"] == 0x1:
self.shutdown(socket.SHUT_RDWR, 1003, "Unsupported: Text frames are not supported")
@@ -644,16 +689,9 @@ class WebSocket(object):
try:
sent = self.socket.send(self._send_buffer)
- except (socket.error, OSError):
- exc = sys.exc_info()[1]
- if hasattr(exc, 'errno'):
- err = exc.errno
- else:
- err = exc[0]
-
- if err == errno.EWOULDBLOCK:
+ except OSError as exc:
+ if exc.errno == errno.EWOULDBLOCK:
raise WebSocketWantWriteError
-
raise
self._send_buffer = self._send_buffer[sent:]
@@ -679,11 +717,9 @@ class WebSocket(object):
def _sendmsg(self, opcode, msg):
# Sends a standard data message
if self.client:
- mask = ''
+ mask = b''
for i in range(4):
- mask += chr(random.randrange(256))
- if sys.hexversion >= 0x3000000:
- mask = bytes(mask, "latin-1")
+ mask += random.randrange(256)
frame = self._encode_hybi(opcode, msg, mask)
else:
frame = self._encode_hybi(opcode, msg)
@@ -705,7 +741,7 @@ class WebSocket(object):
plen = len(buf)
pstart = 0
pend = plen
- b = c = ''.encode('ascii')
+ b = c = b''
if plen >= 4:
dtype=numpy.dtype('<u4')
if sys.byteorder == 'big':
@@ -713,7 +749,7 @@ class WebSocket(object):
mask = numpy.frombuffer(mask, dtype, count=1)
data = numpy.frombuffer(buf, dtype, count=int(plen / 4))
#b = numpy.bitwise_xor(data, mask).data
- b = numpy.bitwise_xor(data, mask).tostring()
+ b = numpy.bitwise_xor(data, mask).tobytes()
if plen % 4:
dtype=numpy.dtype('B')
@@ -722,17 +758,15 @@ class WebSocket(object):
mask = numpy.frombuffer(mask, dtype, count=(plen % 4))
data = numpy.frombuffer(buf, dtype,
offset=plen - (plen % 4), count=(plen % 4))
- c = numpy.bitwise_xor(data, mask).tostring()
+ c = numpy.bitwise_xor(data, mask).tobytes()
return b + c
else:
# Slower fallback
- if sys.hexversion < 0x3000000:
- mask = [ ord(c) for c in mask ]
data = array.array('B')
- data.fromstring(buf)
+ data.frombytes(buf)
for i in range(len(data)):
data[i] ^= mask[i % 4]
- return data.tostring()
+ return data.tobytes()
def _encode_hybi(self, opcode, buf, mask_key=None, fin=True):
""" Encode a HyBi style WebSocket frame.
diff --git a/websockify/websocketproxy.py b/websockify/websocketproxy.py
index d3c7130..09d7882 100644
--- a/websockify/websocketproxy.py
+++ b/websockify/websocketproxy.py
@@ -12,24 +12,13 @@ as taken from http://docs.python.org/dev/library/ssl.html#certificates
'''
import signal, socket, optparse, time, os, sys, subprocess, logging, errno, ssl
-try:
- from socketserver import ThreadingMixIn
-except ImportError:
- from SocketServer import ThreadingMixIn
-
-try:
- from http.server import HTTPServer
-except ImportError:
- from BaseHTTPServer import HTTPServer
+from socketserver import ThreadingMixIn
+from http.server import HTTPServer
import select
from websockify import websockifyserver
from websockify import auth_plugins as auth
-try:
- from urllib.parse import parse_qs, urlparse
-except ImportError:
- from cgi import parse_qs
- from urlparse import urlparse
+from urllib.parse import parse_qs, urlparse
class ProxyRequestHandler(websockifyserver.WebSockifyRequestHandler):
@@ -293,6 +282,7 @@ class WebSocketProxy(websockifyserver.WebSockifyServer):
wsdir = os.path.dirname(sys.argv[0])
rebinder_path = [os.path.join(wsdir, "..", "lib"),
os.path.join(wsdir, "..", "lib", "websockify"),
+ os.path.join(wsdir, ".."),
wsdir]
self.rebinder = None
@@ -318,7 +308,7 @@ class WebSocketProxy(websockifyserver.WebSockifyServer):
"REBIND_OLD_PORT": str(kwargs['listen_port']),
"REBIND_NEW_PORT": str(self.target_port)})
- websockifyserver.WebSockifyServer.__init__(self, RequestHandlerClass, *args, **kwargs)
+ super().__init__(RequestHandlerClass, *args, **kwargs)
def run_wrap_cmd(self):
self.msg("Starting '%s'", " ".join(self.wrap_cmd))
@@ -394,35 +384,15 @@ def _subprocess_setup():
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
-try :
- # First try SSL options for Python 3.4 and above
- SSL_OPTIONS = {
- 'default': ssl.OP_ALL,
- 'tlsv1_1': ssl.PROTOCOL_TLS | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 |
- ssl.OP_NO_TLSv1,
- 'tlsv1_2': ssl.PROTOCOL_TLS | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 |
- ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1,
- 'tlsv1_3': ssl.PROTOCOL_TLS | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 |
- ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_TLSv1_2,
- }
-except AttributeError:
- try:
- # Python 3.3 uses a different scheme for SSL options
- # tlsv1_3 is not supported on older Python versions
- SSL_OPTIONS = {
- 'default': ssl.OP_ALL,
- 'tlsv1_1': ssl.PROTOCOL_TLSv1 | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 |
- ssl.OP_NO_TLSv1,
- 'tlsv1_2': ssl.PROTOCOL_TLSv1 | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 |
- ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1,
- }
- except AttributeError:
- # Python 2.6 does not support TLS v1.2, and uses a different scheme
- # for SSL options
- SSL_OPTIONS = {
- 'default': ssl.PROTOCOL_SSLv23,
- 'tlsv1_1': ssl.PROTOCOL_TLSv1,
- }
+SSL_OPTIONS = {
+ 'default': ssl.OP_ALL,
+ 'tlsv1_1': ssl.PROTOCOL_SSLv23 | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 |
+ ssl.OP_NO_TLSv1,
+ 'tlsv1_2': ssl.PROTOCOL_SSLv23 | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 |
+ ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1,
+ 'tlsv1_3': ssl.PROTOCOL_SSLv23 | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 |
+ ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_TLSv1_2,
+}
def select_ssl_version(version):
"""Returns SSL options for the most secure TSL version available on this
@@ -768,14 +738,13 @@ class LibProxyServer(ThreadingMixIn, HTTPServer):
if web:
os.chdir(web)
- HTTPServer.__init__(self, (listen_host, listen_port),
- RequestHandlerClass)
+ super().__init__((listen_host, listen_port), RequestHandlerClass)
def process_request(self, request, client_address):
"""Override process_request to implement a counter"""
self.handler_id += 1
- ThreadingMixIn.process_request(self, request, client_address)
+ super().process_request(request, client_address)
if __name__ == '__main__':
diff --git a/websockify/websocketserver.py b/websockify/websocketserver.py
index d2e02c9..9088fe9 100644
--- a/websockify/websocketserver.py
+++ b/websockify/websocketserver.py
@@ -8,12 +8,7 @@ Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)
'''
import sys
-
-# python 3.0 differences
-try:
- from http.server import BaseHTTPRequestHandler, HTTPServer
-except ImportError:
- from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
+from http.server import BaseHTTPRequestHandler, HTTPServer
from websockify.websocket import WebSocket, WebSocketWantReadError, WebSocketWantWriteError
@@ -42,12 +37,7 @@ class WebSocketRequestHandlerMixIn:
self._real_do_GET = self.do_GET
self.do_GET = self._websocket_do_GET
try:
- # super() only works for new style classes
- if issubclass(WebSocketRequestHandlerMixIn, object):
- super(WebSocketRequestHandlerMixIn, self).handle_one_request()
- else:
- # Assume handle_one_request() hasn't been overriden
- BaseHTTPRequestHandler.handle_one_request(self)
+ super().handle_one_request()
finally:
self.do_GET = self._real_do_GET
diff --git a/websockify/websockifyserver.py b/websockify/websockifyserver.py
index c801725..0199e42 100644
--- a/websockify/websockifyserver.py
+++ b/websockify/websockifyserver.py
@@ -14,19 +14,7 @@ as taken from http://docs.python.org/dev/library/ssl.html#certificates
import os, sys, time, errno, signal, socket, select, logging
import multiprocessing
-
-# Imports that vary by python version
-
-# python 3.0 differences
-if sys.hexversion > 0x3000000:
- s2b = lambda s: s.encode('latin_1')
-else:
- s2b = lambda s: s # No-op
-
-try:
- from http.server import SimpleHTTPRequestHandler
-except ImportError:
- from SimpleHTTPServer import SimpleHTTPRequestHandler
+from http.server import SimpleHTTPRequestHandler
# Degraded functionality if these imports are missing
for mod, msg in [('ssl', 'TLS/SSL/wss is disabled'),
@@ -46,7 +34,7 @@ from websockify.websocketserver import WebSocketRequestHandlerMixIn
class CompatibleWebSocket(WebSocket):
def select_subprotocol(self, protocols):
- # Handle old websockify clients that still specifiy a sub-protocol
+ # Handle old websockify clients that still specify a sub-protocol
if 'binary' in protocols:
return 'binary'
else:
@@ -96,7 +84,7 @@ class WebSockifyRequestHandler(WebSocketRequestHandlerMixIn, SimpleHTTPRequestHa
if self.logger is None:
self.logger = WebSockifyServer.get_logger()
- SimpleHTTPRequestHandler.__init__(self, req, addr, server)
+ super().__init__(req, addr, server)
def log_message(self, format, *args):
self.logger.info("%s - - [%s] %s" % (self.client_address[0], self.log_date_time_string(), format % args))
@@ -146,20 +134,14 @@ class WebSockifyRequestHandler(WebSocketRequestHandlerMixIn, SimpleHTTPRequestHa
self.rec.write("'{{{0}{{{1}',\n".format(tdelta, bufstr))
self.send_parts.append(buf)
- # Flush any previously queued data
- try:
- self.request.sendmsg('')
- except WebSocketWantWriteError:
- return True
-
while self.send_parts:
# Send pending frames
- buf = self.send_parts.pop(0)
try:
- self.request.sendmsg(buf)
+ self.request.sendmsg(self.send_parts[0])
except WebSocketWantWriteError:
self.print_traffic("<.")
return True
+ self.send_parts.pop(0)
self.print_traffic("<")
return False
@@ -218,7 +200,7 @@ class WebSockifyRequestHandler(WebSocketRequestHandlerMixIn, SimpleHTTPRequestHa
self.validate_connection()
self.auth_connection()
- WebSocketRequestHandlerMixIn.handle_upgrade(self)
+ super().handle_upgrade()
def handle_websocket(self):
# Indicate to server that a Websocket upgrade was done
@@ -270,13 +252,13 @@ class WebSockifyRequestHandler(WebSocketRequestHandlerMixIn, SimpleHTTPRequestHa
if self.only_upgrade:
self.send_error(405, "Method Not Allowed")
else:
- SimpleHTTPRequestHandler.do_GET(self)
+ super().do_GET()
def list_directory(self, path):
if self.file_only:
self.send_error(404, "No such file")
else:
- return SimpleHTTPRequestHandler.list_directory(self, path)
+ return super().list_directory(path)
def new_websocket_client(self):
""" Do something with a WebSockets client connection. """
@@ -297,13 +279,13 @@ class WebSockifyRequestHandler(WebSocketRequestHandlerMixIn, SimpleHTTPRequestHa
if self.only_upgrade:
self.send_error(405, "Method Not Allowed")
else:
- SimpleHTTPRequestHandler.do_HEAD(self)
+ super().do_HEAD()
def finish(self):
if self.rec:
self.rec.write("'EOF'];\n")
self.rec.close()
- SimpleHTTPRequestHandler.finish(self)
+ super().finish()
def handle(self):
# When using run_once, we have a single process, so
@@ -312,14 +294,14 @@ class WebSockifyRequestHandler(WebSocketRequestHandlerMixIn, SimpleHTTPRequestHa
if self.run_once:
self.handle_one_request()
else:
- SimpleHTTPRequestHandler.handle(self)
+ super().handle()
def log_request(self, code='-', size='-'):
if self.verbose:
- SimpleHTTPRequestHandler.log_request(self, code, size)
+ super().log_request(code, size)
-class WebSockifyServer(object):
+class WebSockifyServer():
"""
WebSockets server class.
As an alternative, the standard library SocketServer can be used
@@ -559,7 +541,7 @@ class WebSockifyServer(object):
if not handshake:
raise self.EClose("")
- elif handshake[0] in ("\x16", "\x80", 22, 128):
+ elif handshake[0] in (22, 128):
# SSL wrap the connection
if not ssl:
raise self.EClose("SSL connection but no 'ssl' module")
@@ -568,32 +550,21 @@ class WebSockifyServer(object):
% self.cert)
retsock = None
try:
- if (hasattr(ssl, 'create_default_context')
- and callable(ssl.create_default_context)):
- # create new-style SSL wrapping for extended features
- context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
- if self.ssl_ciphers is not None:
- context.set_ciphers(self.ssl_ciphers)
- context.options = self.ssl_options
- context.load_cert_chain(certfile=self.cert, keyfile=self.key, password=self.key_password)
- if self.verify_client:
- context.verify_mode = ssl.CERT_REQUIRED
- if self.cafile:
- context.load_verify_locations(cafile=self.cafile)
- else:
- context.set_default_verify_paths()
- retsock = context.wrap_socket(
- sock,
- server_side=True)
- else:
- if self.verify_client:
- raise self.EClose("Client certificate verification requested, but this Python is too old.")
- # new-style SSL wrapping is not needed, using to old style
- retsock = ssl.wrap_socket(
- sock,
- server_side=True,
- certfile=self.cert,
- keyfile=self.key)
+ # create new-style SSL wrapping for extended features
+ context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
+ if self.ssl_ciphers is not None:
+ context.set_ciphers(self.ssl_ciphers)
+ context.options = self.ssl_options
+ context.load_cert_chain(certfile=self.cert, keyfile=self.key, password=self.key_password)
+ if self.verify_client:
+ context.verify_mode = ssl.CERT_REQUIRED
+ if self.cafile:
+ context.load_verify_locations(cafile=self.cafile)
+ else:
+ context.set_default_verify_paths()
+ retsock = context.wrap_socket(
+ sock,
+ server_side=True)
except ssl.SSLError:
_, x, _ = sys.exc_info()
if x.args[0] == ssl.SSL_ERROR_EOF:
@@ -729,10 +700,6 @@ class WebSockifyServer(object):
if self.listen_fd != None:
lsock = socket.fromfd(self.listen_fd, socket.AF_INET, socket.SOCK_STREAM)
- if sys.hexversion < 0x3000000:
- # For python 2 we have to wrap the "raw" socket into a socket object,
- # otherwise ssl wrap_socket doesn't work.
- lsock = socket.socket(_sock=lsock)
else:
lsock = self.socket(self.listen_host, self.listen_port, False,
self.prefer_ipv6,