Skip to content

Commit 4c6e7f7

Browse files
author
Paul Sokolovsky
committed
uasyncio.websocket.server: Websocket server implementation for uasyncio.
During development, following questions were posed, and subsequently, answered: Q #1: Should this be in uasyncio package at all? Upstream doesn't have this. Pro: will be easier for people do discover (see e.g. #148) A: uasyncio diverges more and more from asyncio, so if something is convinient for uasyncio, there's no need to look back at asyncio. Q #2: This provides implements 2 ways to create a WS connections: 1) using start_ws_server(); 2) using wrapping existing StreamReader and StreamWriter. History: initial prototype of course used 2). But the idea was "it should be like the official start_server()!!1". But then I though how to integrate it e.g. with Picoweb, and became clear that 2) is the most flixble way. So, 1) is intended to be removed. A: 1) was removed and is not part of the merged version of the patch. Q #3: Uses native websocket module for read path, but has own write path due to micropython/micropython#3396 A: So far, so good. Q #4: Requires #227 due to micropython/micropython#3394 . A: The prerequisite was merged.
1 parent 0c45f9f commit 4c6e7f7

File tree

1 file changed

+63
-0
lines changed
  • uasyncio.websocket.server/uasyncio/websocket

1 file changed

+63
-0
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import uasyncio
2+
import uhashlib, ubinascii
3+
import websocket
4+
5+
6+
def make_respkey(webkey):
7+
d = uhashlib.sha1(webkey)
8+
d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
9+
respkey = d.digest()
10+
respkey = ubinascii.b2a_base64(respkey) #[:-1]
11+
# Return with trailing "\n".
12+
return respkey
13+
14+
15+
class WSWriter:
16+
17+
def __init__(self, reader, writer):
18+
# Reader is passed for symmetry with WSReader() and ignored.
19+
self.s = writer
20+
21+
async def awrite(self, data):
22+
assert len(data) < 126
23+
await self.s.awrite(b"\x81")
24+
await self.s.awrite(bytes([len(data)]))
25+
await self.s.awrite(data)
26+
27+
28+
def WSReader(reader, writer):
29+
30+
webkey = None
31+
while 1:
32+
l = yield from reader.readline()
33+
print(l)
34+
if not l:
35+
raise ValueError()
36+
if l == b"\r\n":
37+
break
38+
if l.startswith(b'Sec-WebSocket-Key'):
39+
webkey = l.split(b":", 1)[1]
40+
webkey = webkey.strip()
41+
42+
if not webkey:
43+
raise ValueError("Not a websocker request")
44+
45+
respkey = make_respkey(webkey)
46+
47+
await writer.awrite(b"""\
48+
HTTP/1.1 101 Switching Protocols\r
49+
Upgrade: websocket\r
50+
Connection: Upgrade\r
51+
Sec-WebSocket-Accept: """)
52+
await writer.awrite(respkey)
53+
# This will lead to "<key>\n\r\n" being written. Not exactly
54+
# "\r\n\r\n", but browsers seem to eat it.
55+
await writer.awrite("\r\n")
56+
#await writer.awrite("\r\n\r\n")
57+
58+
print("Finished webrepl handshake")
59+
60+
ws = websocket.websocket(reader.ios)
61+
rws = uasyncio.StreamReader(reader.ios, ws)
62+
63+
return rws

0 commit comments

Comments
 (0)