7
7
import sys
8
8
import websocket
9
9
import io
10
+ from micropython import const
11
+ from legacy_file_transfer import LegacyFileTransfer
10
12
11
13
listen_s = None
12
14
client_s = None
13
15
14
16
DEBUG = 0
15
17
16
- _DEFAULT_STATIC_HOST = const ("https://felix.dogcraft.de /webrepl/" )
18
+ _DEFAULT_STATIC_HOST = const ("https://micropython.org /webrepl/" )
17
19
_WELCOME_PROMPT = const ("\r \n WebREPL connected\r \n >>> " )
18
20
static_host = _DEFAULT_STATIC_HOST
19
21
webrepl_pass = None
20
22
23
+ legacy = LegacyFileTransfer ()
24
+
25
+
21
26
class WebreplWrapper (io .IOBase ):
22
27
def __init__ (self , sock ):
23
28
self .sock = sock
24
- self .sock .ioctl (9 , 2 )
29
+ self .sock .ioctl (9 , 1 if legacy else 2 )
25
30
if webrepl_pass is not None :
26
31
self .pw = bytearray (16 )
27
32
self .pwPos = 0
28
33
self .sock .write ("Password: " )
29
34
else :
30
35
self .pw = None
31
- self .sock .write (_WELCOME_PROMPT );
36
+ self .sock .write (_WELCOME_PROMPT )
32
37
33
38
def readinto (self , buf ):
34
39
if self .pw is not None :
35
- buf = bytearray (1 )
40
+ buf1 = bytearray (1 )
36
41
while True :
37
- l = self .sock .readinto (buf )
42
+ l = self .sock .readinto (buf1 )
38
43
if l is None :
39
44
continue
40
45
if l <= 0 :
41
46
return l
42
- if buf [0 ] == 10 or buf [0 ] == 13 :
47
+ if buf1 [0 ] == 10 or buf1 [0 ] == 13 :
43
48
print ("Authenticating with:" )
44
49
print (self .pw [0 :self .pwPos ])
45
50
if bytes (self .pw [0 :self .pwPos ]) == webrepl_pass :
@@ -54,9 +59,21 @@ def readinto(self, buf):
54
59
return 0
55
60
else :
56
61
if self .pwPos < len (self .pw ):
57
- self .pw [self .pwPos ] = buf [0 ]
62
+ self .pw [self .pwPos ] = buf1 [0 ]
58
63
self .pwPos = self .pwPos + 1
59
- return self .sock .readinto (buf )
64
+ ret = None
65
+ while True :
66
+ ret = self .sock .readinto (buf )
67
+ if ret is None or ret <= 0 :
68
+ break
69
+ # ignore any non-data frames
70
+ if self .sock .ioctl (8 ) >= 8 :
71
+ continue
72
+ if self .sock .ioctl (8 ) == 2 and legacy :
73
+ legacy .handle (buf , self .sock )
74
+ continue
75
+ break
76
+ return ret
60
77
61
78
def write (self , buf ):
62
79
if self .pw is not None :
@@ -72,8 +89,7 @@ def ioctl(self, kind, arg):
72
89
def close (self ):
73
90
self .sock .close ()
74
91
75
- def server_handshake (cl ):
76
- req = cl .makefile ("rwb" , 0 )
92
+ def server_handshake (req ):
77
93
# Skip HTTP GET line.
78
94
l = req .readline ()
79
95
if DEBUG :
@@ -115,30 +131,33 @@ def server_handshake(cl):
115
131
if DEBUG :
116
132
print ("respkey:" , respkey )
117
133
118
- cl . send (
134
+ req . write (
119
135
b"""\
120
136
HTTP/1.1 101 Switching Protocols\r
121
137
Upgrade: websocket\r
122
138
Connection: Upgrade\r
123
139
Sec-WebSocket-Accept: """
124
140
)
125
- cl . send (respkey )
126
- cl . send ("\r \n \r \n " )
141
+ req . write (respkey )
142
+ req . write ("\r \n \r \n " )
127
143
128
144
return True
129
145
130
146
131
147
def send_html (cl ):
132
- cl .send (
148
+ cl .write (
133
149
b"""\
134
150
HTTP/1.0 200 OK\r
135
151
\r
136
152
<base href=\" """
137
153
)
138
- cl .send (static_host )
139
- cl .send (
154
+ cl .write (static_host )
155
+ cl .write (
140
156
b"""\" ></base>\r
141
- <script src="webreplv2_content.js"></script>\r
157
+ <script src="webrepl""" )
158
+ if not legacy :
159
+ cl .write ("v2" )
160
+ cl .write (b"""_content.js"></script>\r
142
161
"""
143
162
)
144
163
cl .close ()
@@ -149,10 +168,7 @@ def setup_conn(port, accept_handler):
149
168
listen_s = socket .socket ()
150
169
listen_s .setsockopt (socket .SOL_SOCKET , socket .SO_REUSEADDR , 1 )
151
170
152
- ai = socket .getaddrinfo ("0.0.0.0" , port )
153
- addr = ai [0 ][4 ]
154
-
155
- listen_s .bind (addr )
171
+ listen_s .bind (("" , port ))
156
172
listen_s .listen (1 )
157
173
if accept_handler :
158
174
listen_s .setsockopt (socket .SOL_SOCKET , 20 , accept_handler )
@@ -164,11 +180,14 @@ def setup_conn(port, accept_handler):
164
180
165
181
166
182
def accept_conn (listen_sock ):
167
- global client_s
183
+ global client_s , webrepl_ssl_context
168
184
cl , remote_addr = listen_sock .accept ()
185
+ sock = cl
186
+ if webrepl_ssl_context is not None :
187
+ sock = webrepl_ssl_context .wrap_socket (sock )
169
188
170
189
if not server_handshake (cl ):
171
- send_html (cl )
190
+ send_html (sock )
172
191
return False
173
192
174
193
prev = os .dupterm (None )
@@ -180,13 +199,13 @@ def accept_conn(listen_sock):
180
199
print ("\n WebREPL connection from:" , remote_addr )
181
200
client_s = cl
182
201
183
- ws = websocket .websocket (cl , True )
184
- ws = WebreplWrapper (ws )
202
+ sock = websocket .websocket (sock )
203
+ sock = WebreplWrapper (sock )
185
204
cl .setblocking (False )
186
205
# notify REPL on socket incoming data (ESP32/ESP8266-only)
187
206
if hasattr (os , "dupterm_notify" ):
188
207
cl .setsockopt (socket .SOL_SOCKET , 20 , os .dupterm_notify )
189
- os .dupterm (ws )
208
+ os .dupterm (sock )
190
209
191
210
return True
192
211
@@ -200,9 +219,10 @@ def stop():
200
219
listen_s .close ()
201
220
202
221
203
- def start (port = 8266 , password = None , accept_handler = accept_conn ):
204
- global static_host , webrepl_pass
222
+ def start (port = 8266 , password = None , ssl_context = None , accept_handler = accept_conn ):
223
+ global static_host , webrepl_pass , webrepl_ssl_context
205
224
stop ()
225
+ webrepl_ssl_context = ssl_context
206
226
webrepl_pass = password
207
227
if password is None :
208
228
try :
@@ -230,5 +250,5 @@ def start(port=8266, password=None, accept_handler=accept_conn):
230
250
print ("Started webrepl in manual override mode" )
231
251
232
252
233
- def start_foreground (port = 8266 , password = None ):
234
- start (port , password , None )
253
+ def start_foreground (port = 8266 , password = None , ssl_context = None ):
254
+ start (port , password , ssl_context = ssl_context , accept_handler = None )
0 commit comments