examples/network: Add example of HTTPS client using non-blocking socket.

Non-blocking SSL streams can be difficult to get right, so provide a
working example, of a HTTPS client.

Signed-off-by: Damien George <damien@micropython.org>
pull/14467/head
Damien George 2024-04-27 13:42:21 +10:00
rodzic bd610ff016
commit cc3550eeef
1 zmienionych plików z 75 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,75 @@
# Example of a HTTPS client working with non-blocking sockets.
#
# Non-blocking SSL streams works differently in MicroPython compared to CPython. In
# CPython a write to an SSLSocket may raise ssl.SSLWantReadError. In MicroPython an
# SSLSocket behaves like a normal socket/stream and can be polled for reading/writing.
from errno import EINPROGRESS
import select
import socket
import ssl
def connect_nonblocking(sock, addr):
sock.setblocking(False)
try:
sock.connect(addr)
except OSError as er:
if er.errno != EINPROGRESS:
raise er
def write_nonblocking(poller, sock, data):
poller.register(sock, select.POLLOUT)
while data:
poller.poll()
n = sock.write(data)
print("Wrote:", n)
if n is not None:
data = data[n:]
def read_nonblocking(poller, sock, n):
poller.register(sock, select.POLLIN)
poller.poll()
data = sock.read(n)
print("Read:", len(data))
return data
def main(url):
# Split the given URL into components.
proto, _, host, path = url.split(b"/", 3)
assert proto == b"https:"
# Note: this getaddrinfo() call is blocking!
ai = socket.getaddrinfo(host, 443)[0]
addr = ai[-1]
print("Connect address:", addr)
# Create a TCP socket and connect to the server in non-blocking mode.
sock = socket.socket(ai[0], ai[1], ai[2])
connect_nonblocking(sock, addr)
# Wrap the TCP socket in an SSL stream in non-blocking mode.
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
sock = ctx.wrap_socket(sock, server_hostname=host, do_handshake_on_connect=False)
sock.setblocking(False)
# Create an object to poll the SSL stream for readability/writability.
poller = select.poll()
# Send the HTTP request on the SSL stream.
request = b"GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n" % (path, host)
write_nonblocking(poller, sock, request)
# Receive the HTTP response from the SSL stream.
response = read_nonblocking(poller, sock, 1000)
for line in response.split(b"\n"):
print(line)
# Close the SSL stream. This will also close the underlying TCP socket.
sock.close()
main(b"https://micropython.org/ks/test.html")