I received my Pico W long time ago but couldn't find the time to finish this.
I decided to do this in Python (using MicroPython) first, then translate to C and see how things can be improved.
It's very simple and very basic, without concurrency. Like my ESP32 setup, it uses Duck DNS. The key and the certificate are at /pyboard/{key,cert}.der and this is /pyboard/boot.py:
import ussl import socket import network import _thread import machine import urequests SSID = 'AAA' PASSPHRASE = 'BBB' DOMAINS = 'CCC' TOKEN = 'DDD' PORT = 1965 keyfile = open("key.der", "rb").read() certfile = open("cert.der", "rb").read() def read_request(sc): buf = sc.read(len('gemini://a')) while not buf.endswith(b'\r') and len(buf) < 64: b = sc.read(1) buf += b if not buf.endswith(b'\r'): raise Exception('Truncated request') url = buf[:-1].decode('utf-8') _, _, _, path = url.split("/", 3) path = path.lstrip('/') print(url) if len(path) == 0 or path == '/': path = 'index.gmi' elif path == 'key.der' or path == 'cert.der' or path == 'main.py': sc.write(f'40 Forbidden\r\n') raise Exception(f"Forbidden path: {path}") return path def handle_request(c): try: sc = ussl.wrap_socket(c, server_side=True, key=keyfile, cert=certfile) try: path = read_request(sc) sc.write(f'20 text/gemini\r\n') with open(path, "rb") as f: while True: chunk = f.read(128) if len(chunk) == 0: break sc.write(chunk) finally: sc.close() finally: c.close() wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect(SSID, PASSPHRASE) s = socket.socket() s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(('0.0.0.0', PORT)) s.listen(1) led = machine.Pin('LED', machine.Pin.OUT) print(f"Local address: {wlan.ifconfig()[0]}") print('Updating public address') urequests.get(f"https://www.duckdns.org/update?domains={DOMAINS}&token={TOKEN}") print('Ready') while True: try: print('Waiting for request') c, _ = s.accept() except Exception as e: print(e) continue try: print('Handling request') c.settimeout(10) led.value(1) try: handle_request(c) finally: led.value(0) except Exception as e: print(e) c.close()
It doesn't send close_notify, something I could fix in my ESP32 Gemini server written in C by forcing mbedtls_ssl_close_notify((mbedtls_ssl_context*)tls), although all other uses of mbedlts are wrapped nicely with the ESP-TLS API. I hope I can do something similar in the Pico without having to patch ussl and rebuild MicroPython.