Update uasyncio to include new TLS support
This commit is contained in:
@@ -172,10 +172,8 @@ configure the web server.
|
|||||||
app.run(port=4443, debug=True, ssl=sslctx)
|
app.run(port=4443, debug=True, ssl=sslctx)
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
The ``ssl`` argument can only be used with CPython at this time, because
|
When using CPython, the certificate and key files must be given in PEM
|
||||||
MicroPython's asyncio module does not currently support SSL certificates or
|
format. When using MicroPython, these files must be given in DER format.
|
||||||
TLS encryption. Work on this is
|
|
||||||
`in progress <https://github.com/micropython/micropython/pull/11897>`_.
|
|
||||||
|
|
||||||
Defining Routes
|
Defining Routes
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import ssl
|
import ssl
|
||||||
|
import sys
|
||||||
from microdot import Microdot
|
from microdot import Microdot
|
||||||
|
|
||||||
app = Microdot()
|
app = Microdot()
|
||||||
@@ -31,6 +32,7 @@ async def shutdown(request):
|
|||||||
return 'The server is shutting down...'
|
return 'The server is shutting down...'
|
||||||
|
|
||||||
|
|
||||||
|
ext = 'der' if sys.implementation.name == 'micropython' else 'pem'
|
||||||
sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||||
sslctx.load_cert_chain('cert.pem', 'key.pem')
|
sslctx.load_cert_chain('cert.' + ext, 'key.' + ext)
|
||||||
app.run(port=4443, debug=True, ssl=sslctx)
|
app.run(port=4443, debug=True, ssl=sslctx)
|
||||||
|
|||||||
@@ -13,12 +13,6 @@ class Stream:
|
|||||||
def get_extra_info(self, v):
|
def get_extra_info(self, v):
|
||||||
return self.e[v]
|
return self.e[v]
|
||||||
|
|
||||||
async def __aenter__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
async def __aexit__(self, exc_type, exc, tb):
|
|
||||||
await self.close()
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -63,6 +57,8 @@ class Stream:
|
|||||||
while True:
|
while True:
|
||||||
yield core._io_queue.queue_read(self.s)
|
yield core._io_queue.queue_read(self.s)
|
||||||
l2 = self.s.readline() # may do multiple reads but won't block
|
l2 = self.s.readline() # may do multiple reads but won't block
|
||||||
|
if l2 is None:
|
||||||
|
continue
|
||||||
l += l2
|
l += l2
|
||||||
if not l2 or l[-1] == 10: # \n (check l in case l2 is str)
|
if not l2 or l[-1] == 10: # \n (check l in case l2 is str)
|
||||||
return l
|
return l
|
||||||
@@ -100,19 +96,29 @@ StreamWriter = Stream
|
|||||||
# Create a TCP stream connection to a remote host
|
# Create a TCP stream connection to a remote host
|
||||||
#
|
#
|
||||||
# async
|
# async
|
||||||
def open_connection(host, port):
|
def open_connection(host, port, ssl=None, server_hostname=None):
|
||||||
from errno import EINPROGRESS
|
from errno import EINPROGRESS
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)[0] # TODO this is blocking!
|
ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)[0] # TODO this is blocking!
|
||||||
s = socket.socket(ai[0], ai[1], ai[2])
|
s = socket.socket(ai[0], ai[1], ai[2])
|
||||||
s.setblocking(False)
|
s.setblocking(False)
|
||||||
ss = Stream(s)
|
|
||||||
try:
|
try:
|
||||||
s.connect(ai[-1])
|
s.connect(ai[-1])
|
||||||
except OSError as er:
|
except OSError as er:
|
||||||
if er.errno != EINPROGRESS:
|
if er.errno != EINPROGRESS:
|
||||||
raise er
|
raise er
|
||||||
|
# wrap with SSL, if requested
|
||||||
|
if ssl:
|
||||||
|
if ssl is True:
|
||||||
|
import ssl as _ssl
|
||||||
|
|
||||||
|
ssl = _ssl.SSLContext(_ssl.PROTOCOL_TLS_CLIENT)
|
||||||
|
if not server_hostname:
|
||||||
|
server_hostname = host
|
||||||
|
s = ssl.wrap_socket(s, server_hostname=server_hostname, do_handshake_on_connect=False)
|
||||||
|
s.setblocking(False)
|
||||||
|
ss = Stream(s)
|
||||||
yield core._io_queue.queue_write(s)
|
yield core._io_queue.queue_write(s)
|
||||||
return ss, ss
|
return ss, ss
|
||||||
|
|
||||||
@@ -135,7 +141,7 @@ class Server:
|
|||||||
async def wait_closed(self):
|
async def wait_closed(self):
|
||||||
await self.task
|
await self.task
|
||||||
|
|
||||||
async def _serve(self, s, cb):
|
async def _serve(self, s, cb, ssl):
|
||||||
self.state = False
|
self.state = False
|
||||||
# Accept incoming connections
|
# Accept incoming connections
|
||||||
while True:
|
while True:
|
||||||
@@ -156,6 +162,13 @@ class Server:
|
|||||||
except:
|
except:
|
||||||
# Ignore a failed accept
|
# Ignore a failed accept
|
||||||
continue
|
continue
|
||||||
|
if ssl:
|
||||||
|
try:
|
||||||
|
s2 = ssl.wrap_socket(s2, server_side=True, do_handshake_on_connect=False)
|
||||||
|
except OSError as e:
|
||||||
|
core.sys.print_exception(e)
|
||||||
|
s2.close()
|
||||||
|
continue
|
||||||
s2.setblocking(False)
|
s2.setblocking(False)
|
||||||
s2s = Stream(s2, {"peername": addr})
|
s2s = Stream(s2, {"peername": addr})
|
||||||
core.create_task(cb(s2s, s2s))
|
core.create_task(cb(s2s, s2s))
|
||||||
@@ -163,7 +176,7 @@ class Server:
|
|||||||
|
|
||||||
# Helper function to start a TCP stream server, running as a new task
|
# Helper function to start a TCP stream server, running as a new task
|
||||||
# TODO could use an accept-callback on socket read activity instead of creating a task
|
# TODO could use an accept-callback on socket read activity instead of creating a task
|
||||||
async def start_server(cb, host, port, backlog=5):
|
async def start_server(cb, host, port, backlog=5, ssl=None):
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
# Create and bind server socket.
|
# Create and bind server socket.
|
||||||
@@ -176,7 +189,7 @@ async def start_server(cb, host, port, backlog=5):
|
|||||||
|
|
||||||
# Create and return server object and task.
|
# Create and return server object and task.
|
||||||
srv = Server()
|
srv = Server()
|
||||||
srv.task = core.create_task(srv._serve(s, cb))
|
srv.task = core.create_task(srv._serve(s, cb, ssl))
|
||||||
try:
|
try:
|
||||||
# Ensure that the _serve task has been scheduled so that it gets to
|
# Ensure that the _serve task has been scheduled so that it gets to
|
||||||
# handle cancellation.
|
# handle cancellation.
|
||||||
|
|||||||
Reference in New Issue
Block a user