From bf467a5d1f27840d21e3de203440f7bf5791d5df Mon Sep 17 00:00:00 2001 From: Karl Fleischmann Date: Fri, 1 Jul 2022 20:35:04 -0400 Subject: [PATCH 1/4] Split serve_forever to allow polling in loop. Add polling example. Fix root_path bug when loading static pages. --- adafruit_httpserver.py | 59 ++++++++++++++++++----------- examples/httpserve_simplepolling.py | 36 ++++++++++++++++++ 2 files changed, 73 insertions(+), 22 deletions(-) create mode 100644 examples/httpserve_simplepolling.py diff --git a/adafruit_httpserver.py b/adafruit_httpserver.py index ae2f75a..85301e2 100644 --- a/adafruit_httpserver.py +++ b/adafruit_httpserver.py @@ -302,33 +302,48 @@ def serve_forever(self, host: str, port: int = 80, root: str = "") -> None: :param int port: port :param str root: root directory to serve files from """ - self._sock = self._socket_source.socket( - self._socket_source.AF_INET, self._socket_source.SOCK_STREAM - ) - self._sock.bind((host, port)) - self._sock.listen(1) + self.start_server(host,port,root) while True: try: - conn, _ = self._sock.accept() + self.poll_server() except OSError: continue - with conn: - # If reading fails, close connection and retry. - try: - length, _ = conn.recvfrom_into(self._buffer) - except OSError: - continue - request = _HTTPRequest(raw_request=self._buffer[:length]) + def start(self, host: str, port: int = 80, root: str = "") -> None: + """ + Start the HTTP server at the given host and port. Requires calling + poll() in a while loop to handle incoming requests. + + :param str host: host name or IP address + :param int port: port + :param str root: root directory to serve files from + """ + self.root_path = root - # If a route exists for this request, call it. Otherwise try to serve a file. - route = self.routes.get(request, None) - if route: - response = route(request) - elif request.method == "GET": - response = HTTPResponse(filename=request.path, root=root) - else: - response = HTTPResponse(status=HTTPStatus.INTERNAL_SERVER_ERROR) + self._sock = self._socket_source.socket(self._socket_source.AF_INET, self._socket_source.SOCK_STREAM) + self._sock.bind((host, port)) + self._sock.listen(10) - response.send(conn) + def poll(self): + """ + Call this method inside your main event loop to get the server to + check for new incoming client requests. When a request comes in, + the application callable will be invoked. + """ + conn, _ = self._sock.accept() + with conn: + length, remaddr = conn.recvfrom_into(self._buffer) + + request = _HTTPRequest(raw_request=self._buffer[:length]) + + # If a route exists for this request, call it. Otherwise try to serve a file. + route = self.routes.get(request, None) + if route: + response = route(request) + elif request.method == "GET": + response = HTTPResponse(filename=request.path, root=self.root_path) + else: + response = HTTPResponse(status=HTTPStatus.INTERNAL_SERVER_ERROR) + + response.send(conn) diff --git a/examples/httpserve_simplepolling.py b/examples/httpserve_simplepolling.py new file mode 100644 index 0000000..68831f6 --- /dev/null +++ b/examples/httpserve_simplepolling.py @@ -0,0 +1,36 @@ +# SPDX-FileCopyrightText: 2022 Dan Halbert for Adafruit Industries +# +# SPDX-License-Identifier: Unlicense + +from secrets import secrets # pylint: disable=no-name-in-module + +import socketpool +import wifi + +from adafruit_httpserver import HTTPServer, HTTPResponse + +ssid = secrets["ssid"] +print("Connecting to", ssid) +wifi.radio.connect(ssid, secrets["password"]) +print("Connected to", ssid) +print(f"Listening on http://{wifi.radio.ipv4_address}:80") + +pool = socketpool.SocketPool(wifi.radio) +server = HTTPServer(pool) + + +@server.route("/") +def base(request): # pylint: disable=unused-argument + """Default reponse is /index.html""" + return HTTPResponse(filename="/index.html") + + +# startup the server +server.start(str(wifi.radio.ipv4_address)) + +while True: + try: + # processing any waiting requests + server.poll() + except OSError: + continue \ No newline at end of file From 83e7d2305e3013beb2b1785c391c34c8e3aaa22d Mon Sep 17 00:00:00 2001 From: Karl Fleischmann Date: Sat, 2 Jul 2022 14:21:16 -0400 Subject: [PATCH 2/4] Fix CI Build errors related to serve_forever split --- adafruit_httpserver.py | 5 +++-- examples/httpserve_simplepolling.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/adafruit_httpserver.py b/adafruit_httpserver.py index 85301e2..1677172 100644 --- a/adafruit_httpserver.py +++ b/adafruit_httpserver.py @@ -275,6 +275,7 @@ def __init__(self, socket_source: Any) -> None: self.routes = {} self._socket_source = socket_source self._sock = None + self.root_path = "/" def route(self, path: str, method: str = "GET"): """Decorator used to add a route. @@ -302,11 +303,11 @@ def serve_forever(self, host: str, port: int = 80, root: str = "") -> None: :param int port: port :param str root: root directory to serve files from """ - self.start_server(host,port,root) + self.start(host,port,root) while True: try: - self.poll_server() + self.poll() except OSError: continue diff --git a/examples/httpserve_simplepolling.py b/examples/httpserve_simplepolling.py index 68831f6..12211fc 100644 --- a/examples/httpserve_simplepolling.py +++ b/examples/httpserve_simplepolling.py @@ -33,4 +33,4 @@ def base(request): # pylint: disable=unused-argument # processing any waiting requests server.poll() except OSError: - continue \ No newline at end of file + continue From 606116ffcccb1803f7ecce4833a75d0b82e32158 Mon Sep 17 00:00:00 2001 From: Karl Fleischmann Date: Sat, 2 Jul 2022 14:38:30 -0400 Subject: [PATCH 3/4] CI Build Cleanup - unused variable --- adafruit_httpserver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_httpserver.py b/adafruit_httpserver.py index 1677172..6924e37 100644 --- a/adafruit_httpserver.py +++ b/adafruit_httpserver.py @@ -334,7 +334,7 @@ def poll(self): """ conn, _ = self._sock.accept() with conn: - length, remaddr = conn.recvfrom_into(self._buffer) + length, _ = conn.recvfrom_into(self._buffer) request = _HTTPRequest(raw_request=self._buffer[:length]) From 1824d21c724dc4984dc88f879b44358073f4e0a9 Mon Sep 17 00:00:00 2001 From: Karl Fleischmann Date: Sat, 2 Jul 2022 14:59:46 -0400 Subject: [PATCH 4/4] CI Build error - Fix format issue (sigh!) --- adafruit_httpserver.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/adafruit_httpserver.py b/adafruit_httpserver.py index 6924e37..dd233b5 100644 --- a/adafruit_httpserver.py +++ b/adafruit_httpserver.py @@ -303,7 +303,7 @@ def serve_forever(self, host: str, port: int = 80, root: str = "") -> None: :param int port: port :param str root: root directory to serve files from """ - self.start(host,port,root) + self.start(host, port, root) while True: try: @@ -322,7 +322,9 @@ def start(self, host: str, port: int = 80, root: str = "") -> None: """ self.root_path = root - self._sock = self._socket_source.socket(self._socket_source.AF_INET, self._socket_source.SOCK_STREAM) + self._sock = self._socket_source.socket( + self._socket_source.AF_INET, self._socket_source.SOCK_STREAM + ) self._sock.bind((host, port)) self._sock.listen(10)