8000 webrepl: Allow the page to run from the device (over HTTP). · micropython/micropython@d13cf4c · GitHub
[go: up one dir, main page]

Skip to content

Commit d13cf4c

Browse files
committed
webrepl: Allow the page to run from the device (over HTTP).
The device will respond to a non-WS request with a simple page that loads websocket_content.js from a static host (http or https). However, even if the resources are https, the page is still http and therefore allows requesting to a WS (not WSS) websocket on the device. Removed unused client_handshake from websocket_helper, and then merges the remainder of this file (server_handshake) into webrepl.py (to reduce firmware size). Also added the respond-as-HTTP handling to server_handshake. The default HTTP response is a simple page that sets the base URL and then loads webrepl_content.js which document.write's the actual HTML. Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
1 parent 93a17b9 commit d13cf4c

File tree

4 files changed

+100
-99
lines changed

4 files changed

+100
-99
lines changed

extmod/webrepl/manifest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
freeze(".", ("webrepl.py", "webrepl_setup.py", "websocket_helper.py"))
1+
freeze(".", ("webrepl.py", "webrepl_setup.py"))

extmod/webrepl/webrepl.py

Lines changed: 99 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,94 @@
11
# This module should be imported from REPL, not run from command line.
2-
import socket
3-
import uos
2+
import binascii
3+
import hashlib
44
import network
5-
import uwebsocket
6-
import websocket_helper
5+
import os
6+
import socket
7+
import sys
8+
import websocket
79
import _webrepl
810

911
listen_s = None
1012
client_s = None
1113

14+
DEBUG = 0
15+
16+
# TODO: Change to https://micropython.org/webrepl/
17+
_DEFAULT_STATIC_HOST = const("https://gitcdn.link/cdn/jimmo/webrepl/webrepl-on-device/")
18+
static_host = _DEFAULT_STATIC_HOST
19+
20+
21+
def server_handshake(cl):
22+
req = cl.makefile("rwb", 0)
23+
# Skip HTTP GET line.
24+
l = req.readline()
25+
if DEBUG:
26+
sys.stdout.write(repr(l))
27+
28+
webkey = None
29+
upgrade = False
30+
websocket = False
31+
32+
while True:
33+
l = req.readline()
34+
if not l:
35+
# EOF in headers.
36+
return False
37+
if l == b"\r\n":
38+
break
39+
if DEBUG:
40+
sys.stdout.write(l)
41+
h, v = [x.strip() for x in l.split(b":", 1)]
42+
if DEBUG:
43+
print((h, v))
44+
if h == b"Sec-WebSocket-Key":
45+
webkey = v
46+
elif h == b"Connection" and v == b"Upgrade":
47+
upgrade = True
48+
elif h == b"Upgrade" and v == b"websocket":
49+
websocket = True
50+
51+
if not (upgrade and websocket and webkey):
52+
return False
53+
54+
if DEBUG:
55+
print("Sec-WebSocket-Key:", webkey, len(webkey))
56+
57+
d = hashlib.sha1(webkey)
58+
d.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
59+
respkey = d.digest()
60+
respkey = binascii.b2a_base64(respkey)[:-1]
61+
if DEBUG:
62+
print("respkey:", respkey)
63+
64+
cl.send(
65+
b"""\
66+
HTTP/1.1 101 Switching Protocols\r
67+
Upgrade: websocket\r
68+
Connection: Upgrade\r
69+
Sec-WebSocket-Accept: """
70+
)
71+
cl.send(respkey)
72+
cl.send("\r\n\r\n")
73+
74+
return True
75+
76+
77+
def send_html(cl):
78+
cl.send(
79+
b"""\
80+
HTTP/1.0 200 OK\r
81+
\r
82+
<base href=\""""
83+
)
84+
cl.send(static_host)
85+
cl.send(
86+
b"""\"></base>\r
87+
<script src="webrepl_content.js"></script>\r
88+
"""
89+
)
90+
cl.close()
91+
1292

1393
def setup_conn(port, accept_handler):
1494
global listen_s
@@ -32,41 +112,48 @@ def setup_conn(port, accept_handler):
32112
def accept_conn(listen_sock):
33113
global client_s
34114
cl, remote_addr = listen_sock.accept()
35-
prev = uos.dupterm(None)
36-
uos.dupterm(prev)
115+
116+
if not server_handshake(cl):
117+
return send_html(cl)
118+
119+
prev = os.dupterm(None)
120+
os.dupterm(prev)
37121
if prev:
38122
print("\nConcurrent WebREPL connection from", remote_addr, "rejected")
39123
cl.close()
40124
return
41125
print("\nWebREPL connection from:", remote_addr)
42126
client_s = cl
43-
websocket_helper.server_handshake(cl)
44-
ws = uwebsocket.websocket(cl, True)
127+
128+
ws = websocket.websocket(cl, True)
45129
ws = _webrepl._webrepl(ws)
46130
cl.setblocking(False)
47131
# notify REPL on socket incoming data (ESP32/ESP8266-only)
48-
if hasattr(uos, "dupterm_notify"):
49-
cl.setsockopt(socket.SOL_SOCKET, 20, uos.dupterm_notify)
50-
uos.dupterm(ws)
132+
if hasattr(os, "dupterm_notify"):
133+
cl.setsockopt(socket.SOL_SOCKET, 20, os.dupterm_notify)
134+
os.dupterm(ws)
51135

52136

53137
def stop():
54138
global listen_s, client_s
55-
uos.dupterm(None)
139+
os.dupterm(None)
56140
if client_s:
57141
client_s.close()
58142
if listen_s:
59143
listen_s.close()
60144

61145

62146
def start(port=8266, password=None, accept_handler=accept_conn):
147+
global static_host
63148
stop()
64149
webrepl_pass = password
65150
if webrepl_pass is None:
66151
try:
67152
import webrepl_cfg
68153

69154
webrepl_pass = webrepl_cfg.PASS
155+
if hasattr(webrepl_cfg, "BASE"):
156+
static_host = webrepl_cfg.BASE
70157
except:
71158
print("WebREPL is not configured, run 'import webrepl_setup'")
72159

extmod/webrepl/webrepl_setup.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import sys
22

3-
# import uos as os
43
import os
54
import machine
65

extmod/webrepl/websocket_helper.py

Lines changed: 0 additions & 85 deletions
This file was deleted.

0 commit comments

Comments
 (0)
0