TLS fixes for WebSocket under MicroPython
This commit is contained in:
24
examples/tls/echo_tls.py
Normal file
24
examples/tls/echo_tls.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import sys
|
||||
from microdot import Microdot, send_file
|
||||
from microdot_websocket import with_websocket
|
||||
from microdot_ssl import create_ssl_context
|
||||
|
||||
app = Microdot()
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index(request):
|
||||
return send_file('index.html')
|
||||
|
||||
|
||||
@app.route('/echo')
|
||||
@with_websocket
|
||||
def echo(request, ws):
|
||||
while True:
|
||||
data = ws.receive()
|
||||
ws.send(data)
|
||||
|
||||
|
||||
ext = 'der' if sys.implementation.name == 'micropython' else 'pem'
|
||||
sslctx = create_ssl_context('cert.' + ext, 'key.' + ext)
|
||||
app.run(port=4443, debug=True, ssl=sslctx)
|
||||
35
examples/tls/index.html
Normal file
35
examples/tls/index.html
Normal file
@@ -0,0 +1,35 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Microdot TLS WebSocket Demo</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Microdot TLS WebSocket Demo</h1>
|
||||
<div id="log"></div>
|
||||
<br>
|
||||
<form id="form">
|
||||
<label for="text">Input: </label>
|
||||
<input type="text" id="text" autofocus>
|
||||
</form>
|
||||
<script>
|
||||
const log = (text, color) => {
|
||||
document.getElementById('log').innerHTML += `<span style="color: ${color}">${text}</span><br>`;
|
||||
};
|
||||
|
||||
const socket = new WebSocket('wss://' + location.host + '/echo');
|
||||
socket.addEventListener('message', ev => {
|
||||
log('<<< ' + ev.data, 'blue');
|
||||
});
|
||||
socket.addEventListener('close', ev => {
|
||||
log('<<< closed');
|
||||
});
|
||||
document.getElementById('form').onsubmit = ev => {
|
||||
ev.preventDefault();
|
||||
const textField = document.getElementById('text');
|
||||
log('>>> ' + textField.value, 'red');
|
||||
socket.send(textField.value);
|
||||
textField.value = '';
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -916,8 +916,11 @@ class Microdot():
|
||||
if exc.errno == errno.ECONNABORTED:
|
||||
break
|
||||
else:
|
||||
raise
|
||||
create_thread(self.handle_request, sock, addr)
|
||||
print_exception(exc)
|
||||
except Exception as exc: # pragma: no cover
|
||||
print_exception(exc)
|
||||
else:
|
||||
create_thread(self.handle_request, sock, addr)
|
||||
|
||||
def shutdown(self):
|
||||
"""Request a server shutdown. The server will then exit its request
|
||||
@@ -953,12 +956,13 @@ class Microdot():
|
||||
stream = sock
|
||||
|
||||
req = None
|
||||
res = None
|
||||
try:
|
||||
req = Request.create(self, stream, addr, sock)
|
||||
res = self.dispatch_request(req)
|
||||
except Exception as exc: # pragma: no cover
|
||||
print_exception(exc)
|
||||
res = self.dispatch_request(req)
|
||||
if res != Response.already_handled: # pragma: no branch
|
||||
if res and res != Response.already_handled: # pragma: no branch
|
||||
res.write(stream)
|
||||
try:
|
||||
stream.close()
|
||||
|
||||
@@ -260,7 +260,7 @@ class TestClient:
|
||||
else WebSocket.BINARY
|
||||
return WebSocket._encode_websocket_frame(opcode, data)
|
||||
|
||||
def recv(self, n):
|
||||
def read(self, n):
|
||||
self.started = True
|
||||
if not self.buffer:
|
||||
self.buffer = self._next()
|
||||
@@ -268,7 +268,7 @@ class TestClient:
|
||||
self.buffer = self.buffer[n:]
|
||||
return data
|
||||
|
||||
def send(self, data):
|
||||
def write(self, data):
|
||||
if self.started:
|
||||
h = WebSocket._parse_frame_header(data[0:2])
|
||||
if h[3] < 0:
|
||||
|
||||
@@ -17,10 +17,10 @@ class WebSocket:
|
||||
|
||||
def handshake(self):
|
||||
response = self._handshake_response()
|
||||
self.request.sock.send(b'HTTP/1.1 101 Switching Protocols\r\n')
|
||||
self.request.sock.send(b'Upgrade: websocket\r\n')
|
||||
self.request.sock.send(b'Connection: Upgrade\r\n')
|
||||
self.request.sock.send(
|
||||
self.request.sock.write(b'HTTP/1.1 101 Switching Protocols\r\n')
|
||||
self.request.sock.write(b'Upgrade: websocket\r\n')
|
||||
self.request.sock.write(b'Connection: Upgrade\r\n')
|
||||
self.request.sock.write(
|
||||
b'Sec-WebSocket-Accept: ' + response + b'\r\n\r\n')
|
||||
|
||||
def receive(self):
|
||||
@@ -36,7 +36,7 @@ class WebSocket:
|
||||
frame = self._encode_websocket_frame(
|
||||
opcode or (self.TEXT if isinstance(data, str) else self.BINARY),
|
||||
data)
|
||||
self.request.sock.send(frame)
|
||||
self.request.sock.write(frame)
|
||||
|
||||
def close(self):
|
||||
if not self.closed: # pragma: no cover
|
||||
@@ -110,16 +110,16 @@ class WebSocket:
|
||||
return frame
|
||||
|
||||
def _read_frame(self):
|
||||
header = self.request.sock.recv(2)
|
||||
header = self.request.sock.read(2)
|
||||
if len(header) != 2: # pragma: no cover
|
||||
raise OSError(32, 'Websocket connection closed')
|
||||
fin, opcode, has_mask, length = self._parse_frame_header(header)
|
||||
if length < 0:
|
||||
length = self.request.sock.recv(-length)
|
||||
length = self.request.sock.read(-length)
|
||||
length = int.from_bytes(length, 'big')
|
||||
if has_mask: # pragma: no cover
|
||||
mask = self.request.sock.recv(4)
|
||||
payload = self.request.sock.recv(length)
|
||||
mask = self.request.sock.read(4)
|
||||
payload = self.request.sock.read(length)
|
||||
if has_mask: # pragma: no cover
|
||||
payload = bytes(x ^ mask[i % 4] for i, x in enumerate(payload))
|
||||
return opcode, payload
|
||||
|
||||
@@ -22,10 +22,10 @@ class WebSocket:
|
||||
|
||||
def handshake(self):
|
||||
response = self._handshake_response()
|
||||
self.request.sock.send(b'HTTP/1.1 101 Switching Protocols\r\n')
|
||||
self.request.sock.send(b'Upgrade: websocket\r\n')
|
||||
self.request.sock.send(b'Connection: Upgrade\r\n')
|
||||
self.request.sock.send(
|
||||
self.request.sock.write(b'HTTP/1.1 101 Switching Protocols\r\n')
|
||||
self.request.sock.write(b'Upgrade: websocket\r\n')
|
||||
self.request.sock.write(b'Connection: Upgrade\r\n')
|
||||
self.request.sock.write(
|
||||
b'Sec-WebSocket-Accept: ' + response + b'\r\n\r\n')
|
||||
|
||||
def receive(self):
|
||||
|
||||
Reference in New Issue
Block a user