77import sys
88import websocket
99import io
10+ from micropython import const
11+ from legacy_file_transfer import LegacyFileTransfer
1012
1113listen_s = None
1214client_s = None
1315
1416DEBUG = 0
1517
16- _DEFAULT_STATIC_HOST = const ("https://felix.dogcraft.de /webrepl/" )
18+ _DEFAULT_STATIC_HOST = const ("https://micropython.org /webrepl/" )
1719_WELCOME_PROMPT = const ("\r \n WebREPL connected\r \n >>> " )
1820static_host = _DEFAULT_STATIC_HOST
1921webrepl_pass = None
2022
23+ legacy = LegacyFileTransfer ()
24+
25+
2126class WebreplWrapper (io .IOBase ):
2227 def __init__ (self , sock ):
2328 self .sock = sock
24- self .sock .ioctl (9 , 2 )
29+ self .sock .ioctl (9 , 1 if legacy else 2 )
2530 if webrepl_pass is not None :
2631 self .pw = bytearray (16 )
2732 self .pwPos = 0
2833 self .sock .write ("Password: " )
2934 else :
3035 self .pw = None
31- self .sock .write (_WELCOME_PROMPT );
36+ self .sock .write (_WELCOME_PROMPT )
3237
3338 def readinto (self , buf ):
3439 if self .pw is not None :
35- buf = bytearray (1 )
40+ buf1 = bytearray (1 )
3641 while True :
37- l = self .sock .readinto (buf )
42+ l = self .sock .readinto (buf1 )
3843 if l is None :
3944 continue
4045 if l <= 0 :
4146 return l
42- if buf [0 ] == 10 or buf [0 ] == 13 :
47+ if buf1 [0 ] == 10 or buf1 [0 ] == 13 :
4348 print ("Authenticating with:" )
4449 print (self .pw [0 :self .pwPos ])
4550 if bytes (self .pw [0 :self .pwPos ]) == webrepl_pass :
@@ -54,9 +59,21 @@ def readinto(self, buf):
5459 return 0
5560 else :
5661 if self .pwPos < len (self .pw ):
57- self .pw [self .pwPos ] = buf [0 ]
62+ self .pw [self .pwPos ] = buf1 [0 ]
5863 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
6077
6178 def write (self , buf ):
6279 if self .pw is not None :
@@ -72,8 +89,7 @@ def ioctl(self, kind, arg):
7289 def close (self ):
7390 self .sock .close ()
7491
75- def server_handshake (cl ):
76- req = cl .makefile ("rwb" , 0 )
92+ def server_handshake (req ):
7793 # Skip HTTP GET line.
7894 l = req .readline ()
7995 if DEBUG :
@@ -115,30 +131,33 @@ def server_handshake(cl):
115131 if DEBUG :
116132 print ("respkey:" , respkey )
117133
118- cl . send (
134+ req . write (
119135 b"""\
120136 HTTP/1.1 101 Switching Protocols\r
121137Upgrade: websocket\r
122138Connection: Upgrade\r
123139Sec-WebSocket-Accept: """
124140 )
125- cl . send (respkey )
126- cl . send ("\r \n \r \n " )
141+ req . write (respkey )
142+ req . write ("\r \n \r \n " )
127143
128144 return True
129145
130146
131147def send_html (cl ):
132- cl .send (
148+ cl .write (
133149 b"""\
134150 HTTP/1.0 200 OK\r
135151\r
136152<base href=\" """
137153 )
138- cl .send (static_host )
139- cl .send (
154+ cl .write (static_host )
155+ cl .write (
140156 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
142161"""
143162 )
144163 cl .close ()
@@ -149,10 +168,7 @@ def setup_conn(port, accept_handler):
149168 listen_s = socket .socket ()
150169 listen_s .setsockopt (socket .SOL_SOCKET , socket .SO_REUSEADDR , 1 )
151170
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 ))
156172 listen_s .listen (1 )
157173 if accept_handler :
158174 listen_s .setsockopt (socket .SOL_SOCKET , 20 , accept_handler )
@@ -164,11 +180,14 @@ def setup_conn(port, accept_handler):
164180
165181
166182def accept_conn (listen_sock ):
167- global client_s
183+ global client_s , webrepl_ssl_context
168184 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 )
169188
170189 if not server_handshake (cl ):
171- send_html (cl )
190+ send_html (sock )
172191 return False
173192
174193 prev = os .dupterm (None )
@@ -180,13 +199,13 @@ def accept_conn(listen_sock):
180199 print ("\n WebREPL connection from:" , remote_addr )
181200 client_s = cl
182201
183- ws = websocket .websocket (cl , True )
184- ws = WebreplWrapper (ws )
202+ sock = websocket .websocket (sock )
203+ sock = WebreplWrapper (sock )
185204 cl .setblocking (False )
186205 # notify REPL on socket incoming data (ESP32/ESP8266-only)
187206 if hasattr (os , "dupterm_notify" ):
188207 cl .setsockopt (socket .SOL_SOCKET , 20 , os .dupterm_notify )
189- os .dupterm (ws )
208+ os .dupterm (sock )
190209
191210 return True
192211
@@ -200,9 +219,10 @@ def stop():
200219 listen_s .close ()
201220
202221
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
205224 stop ()
225+ webrepl_ssl_context = ssl_context
206226 webrepl_pass = password
207227 if password is None :
208228 try :
@@ -230,5 +250,5 @@ def start(port=8266, password=None, accept_handler=accept_conn):
230250 print ("Started webrepl in manual override mode" )
231251
232252
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