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:" )
44- print (self .pw [0 : self .pwPos ])
45- if bytes (self .pw [0 : self .pwPos ]) == webrepl_pass :
49+ print (self .pw [0 : self .pwPos ])
50+ if bytes (self .pw [0 : self .pwPos ]) == webrepl_pass :
4651 self .pw = None
4752 del self .pwPos
4853 self .sock .write (_WELCOME_PROMPT )
4954 break
5055 else :
51- print (bytes (self .pw [0 : self .pwPos ]))
56+ print (bytes (self .pw [0 : self .pwPos ]))
5257 print (webrepl_pass )
5358 self .sock .write ("\r \n Access denied\r \n " )
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,8 @@ 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+
93+ def server_handshake ( req ):
7794 # Skip HTTP GET line.
7895 l = req .readline ()
7996 if DEBUG :
@@ -115,30 +132,35 @@ def server_handshake(cl):
115132 if DEBUG :
116133 print ("respkey:" , respkey )
117134
118- cl . send (
135+ req . write (
119136 b"""\
120137 HTTP/1.1 101 Switching Protocols\r
121138Upgrade: websocket\r
122139Connection: Upgrade\r
123140Sec-WebSocket-Accept: """
124141 )
125- cl . send (respkey )
126- cl . send ("\r \n \r \n " )
142+ req . write (respkey )
143+ req . write ("\r \n \r \n " )
127144
128145 return True
129146
130147
131148def send_html (cl ):
132- cl .send (
149+ cl .write (
133150 b"""\
134151 HTTP/1.0 200 OK\r
135152\r
136153<base href=\" """
137154 )
138- cl .send (static_host )
139- cl .send (
155+ cl .write (static_host )
156+ cl .write (
140157 b"""\" ></base>\r
141- <script src="webreplv2_content.js"></script>\r
158+ <script src="webrepl"""
159+ )
160+ if not legacy :
161+ cl .write ("v2" )
162+ cl .write (
163+ b"""_content.js"></script>\r
142164"""
143165 )
144166 cl .close ()
@@ -149,10 +171,7 @@ def setup_conn(port, accept_handler):
149171 listen_s = socket .socket ()
150172 listen_s .setsockopt (socket .SOL_SOCKET , socket .SO_REUSEADDR , 1 )
151173
152- ai = socket .getaddrinfo ("0.0.0.0" , port )
153- addr = ai [0 ][4 ]
154-
155- listen_s .bind (addr )
174+ listen_s .bind (("" , port ))
156175 listen_s .listen (1 )
157176 if accept_handler :
158177 listen_s .setsockopt (socket .SOL_SOCKET , 20 , accept_handler )
@@ -164,11 +183,14 @@ def setup_conn(port, accept_handler):
164183
165184
166185def accept_conn (listen_sock ):
167- global client_s
186+ global client_s , webrepl_ssl_context
168187 cl , remote_addr = listen_sock .accept ()
188+ sock = cl
189+ if webrepl_ssl_context is not None :
190+ sock = webrepl_ssl_context .wrap_socket (sock )
169191
170192 if not server_handshake (cl ):
171- send_html (cl )
193+ send_html (sock )
172194 return False
173195
174196 prev = os .dupterm (None )
@@ -180,13 +202,13 @@ def accept_conn(listen_sock):
180202 print ("\n WebREPL connection from:" , remote_addr )
181203 client_s = cl
182204
183- ws = websocket .websocket (cl , True )
184- ws = WebreplWrapper (ws )
205+ sock = websocket .websocket (sock )
206+ sock = WebreplWrapper (sock )
185207 cl .setblocking (False )
186208 # notify REPL on socket incoming data (ESP32/ESP8266-only)
187209 if hasattr (os , "dupterm_notify" ):
188210 cl .setsockopt (socket .SOL_SOCKET , 20 , os .dupterm_notify )
189- os .dupterm (ws )
211+ os .dupterm (sock )
190212
191213 return True
192214
@@ -200,9 +222,10 @@ def stop():
200222 listen_s .close ()
201223
202224
203- def start (port = 8266 , password = None , accept_handler = accept_conn ):
204- global static_host , webrepl_pass
225+ def start (port = 8266 , password = None , ssl_context = None , accept_handler = accept_conn ):
226+ global static_host , webrepl_pass , webrepl_ssl_context
205227 stop ()
228+ webrepl_ssl_context = ssl_context
206229 webrepl_pass = password
207230 if password is None :
208231 try :
@@ -230,5 +253,5 @@ def start(port=8266, password=None, accept_handler=accept_conn):
230253 print ("Started webrepl in manual override mode" )
231254
232255
233- def start_foreground (port = 8266 , password = None ):
234- start (port , password , None )
256+ def start_foreground (port = 8266 , password = None , ssl_context = None ):
257+ start (port , password , ssl_context = ssl_context , accept_handler = None )
0 commit comments