1
1
# This module should be imported from REPL, not run from command line.
2
- import socket
3
- import uos
2
+ import binascii
3
+ import hashlib
4
4
import network
5
- import uwebsocket
6
- import websocket_helper
5
+ import os
6
+ import socket
7
+ import sys
8
+ import websocket
7
9
import _webrepl
8
10
9
11
listen_s = None
10
12
client_s = None
11
13
14
+ DEBUG = 0
15
+
16
+ _DEFAULT_STATIC_HOST = const ("https://micropython.org/webrepl/" )
17
+ static_host = _DEFAULT_STATIC_HOST
18
+
19
+
20
+ def server_handshake (cl ):
21
+ req = cl .makefile ("rwb" , 0 )
22
+ # Skip HTTP GET line.
23
+ l = req .readline ()
24
+ if DEBUG :
25
+ sys .stdout .write (repr (l ))
26
+
27
+ webkey = None
28
+ upgrade = False
29
+ websocket = False
30
+
31
+ while True :
32
+ l = req .readline ()
33
+ if not l :
34
+ # EOF in headers.
35
+ return False
36
+ if l == b"\r \n " :
37
+ break
38
+ if DEBUG :
39
+ sys .stdout .write (l )
40
+ h , v = [x .strip () for x in l .split (b":" , 1 )]
41
+ if DEBUG :
42
+ print ((h , v ))
43
+ if h == b"Sec-WebSocket-Key" :
44
+ webkey = v
45
+ elif h == b"Connection" and b"Upgrade" in v :
46
+ upgrade = True
47
+ elif h == b"Upgrade" and v == b"websocket" :
48
+ websocket = True
49
+
50
+ if not (upgrade and websocket and webkey ):
51
+ return False
52
+
53
+ if DEBUG :
54
+ print ("Sec-WebSocket-Key:" , webkey , len (webkey ))
55
+
56
+ d = hashlib .sha1 (webkey )
57
+ d .update (b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11" )
58
+ respkey = d .digest ()
59
+ respkey = binascii .b2a_base64 (respkey )[:- 1 ]
60
+ if DEBUG :
61
+ print ("respkey:" , respkey )
62
+
63
+ cl .send (
64
+ b"""\
65
+ HTTP/1.1 101 Switching Protocols\r
66
+ Upgrade: websocket\r
67
+ Connection: Upgrade\r
68
+ Sec-WebSocket-Accept: """
69
+ )
70
+ cl .send (respkey )
71
+ cl .send ("\r \n \r \n " )
72
+
73
+ return True
74
+
75
+
76
+ def send_html (cl ):
77
+ cl .send (
78
+ b"""\
79
+ HTTP/1.0 200 OK\r
80
+ \r
81
+ <base href=\" """
82
+ )
83
+ cl .send (static_host )
84
+ cl .send (
85
+ b"""\" ></base>\r
86
+ <script src="webrepl_content.js"></script>\r
87
+ """
88
+ )
89
+ cl .close ()
90
+
12
91
13
92
def setup_conn (port , accept_handler ):
14
93
global listen_s
@@ -25,48 +104,58 @@ def setup_conn(port, accept_handler):
25
104
for i in (network .AP_IF , network .STA_IF ):
26
105
iface = network .WLAN (i )
27
106
if iface .active ():
28
- print ("WebREPL daemon started on ws ://%s:%d" % (iface .ifconfig ()[0 ], port ))
107
+ print ("WebREPL server started on http ://%s:%d/ " % (iface .ifconfig ()[0 ], port ))
29
108
return listen_s
30
109
31
110
32
111
def accept_conn (listen_sock ):
33
112
global client_s
34
113
cl , remote_addr = listen_sock .accept ()
35
- prev = uos .dupterm (None )
36
- uos .dupterm (prev )
114
+
115
+ if not server_handshake (cl ):
116
+ send_html (cl )
117
+ return False
118
+
119
+ prev = os .dupterm (None )
120
+ os .dupterm (prev )
37
121
if prev :
38
122
print ("\n Concurrent WebREPL connection from" , remote_addr , "rejected" )
39
123
cl .close ()
40
- return
124
+ return False
41
125
print ("\n WebREPL connection from:" , remote_addr )
42
126
client_s = cl
43
- websocket_helper . server_handshake ( cl )
44
- ws = uwebsocket .websocket (cl , True )
127
+
128
+ ws = websocket .websocket (cl , True )
45
129
ws = _webrepl ._webrepl (ws )
46
130
cl .setblocking (False )
47
131
# 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 )
135
+
136
+ return True
51
137
52
138
53
139
def stop ():
54
140
global listen_s , client_s
55
- uos .dupterm (None )
141
+ os .dupterm (None )
56
142
if client_s :
57
143
client_s .close ()
58
144
if listen_s :
59
145
listen_s .close ()
60
146
61
147
62
148
def start (port = 8266 , password = None , accept_handler = accept_conn ):
149
+ global static_host
63
150
stop ()
64
151
webrepl_pass = password
65
152
if webrepl_pass is None :
66
153
try :
67
154
import webrepl_cfg
68
155
69
156
webrepl_pass = webrepl_cfg .PASS
157
+ if hasattr (webrepl_cfg , "BASE" ):
158
+ static_host = webrepl_cfg .BASE
70
159
except :
71
160
print ("WebREPL is not configured, run 'import webrepl_setup'" )
72
161
@@ -75,7 +164,9 @@ def start(port=8266, password=None, accept_handler=accept_conn):
75
164
76
165
if accept_handler is None :
77
166
print ("Starting webrepl in foreground mode" )
78
- accept_conn (s )
167
+ # Run accept_conn to serve HTML until we get a websocket connection.
168
+ while not accept_conn (s ):
169
+ pass
79
170
elif password is None :
80
171
print ("Started webrepl in normal mode" )
81
172
else :
0 commit comments