diff --git a/pyproject.toml b/pyproject.toml index a94892f..d818ff4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "socketwrench" -version = "1.8.6" +version = "1.8.7" description = "A simple Python library for creating web servers and APIs using sockets, supporting openapi and swagger." readme = "README.md" authors = [{ name = "Torin Halsted", email = "modularizer@gmail.com" }] diff --git a/src/socketwrench/connection.py b/src/socketwrench/connection.py index 1ea198b..e6b67ed 100644 --- a/src/socketwrench/connection.py +++ b/src/socketwrench/connection.py @@ -8,6 +8,7 @@ class Connection: default_chunk_size: int = 1024 + timeout = 5 def __init__(self, handler, @@ -24,16 +25,21 @@ def __init__(self, self._rep = None def handle(self): - request = self.receive_request(self.socket) - if self.check_cleanup(): - return request, None, False - response = self.handler(request) - if self.check_cleanup(): - return request, response, False - self.send_response(self.socket, response) - return request, response, True + try: + request = self.receive_request(self.socket) + if self.check_cleanup(): + return request, None, False + response = self.handler(request) + if self.check_cleanup(): + return request, response, False + self.send_response(self.socket, response) + return request, response, True + except Exception as e + self.close() + raise e def receive_request(self, connection_socket: socket.socket, chunk_size: int = None) -> Request: + connection_socket.settimeout(self.timeout) if chunk_size is None: chunk_size = self.chunk_size @@ -64,7 +70,8 @@ def receive_request(self, connection_socket: socket.socket, chunk_size: int = No return r def send_response(self, connection_socket: socket.socket, response: Response): - connection_socket.send(bytes(response)) + connection_socket.sendall(bytes(response)) + connection_socket.shutdown(socket.SHUT_WR) # seems to be needed for linux? connection_socket.close() def check_cleanup(self): @@ -74,6 +81,7 @@ def check_cleanup(self): return False def close(self): + self.socket.shutdown(socket.SHUT_WR) # seems to be needed for linux? self.socket.close() def __repr__(self): diff --git a/src/socketwrench/server.py b/src/socketwrench/server.py index 7048de1..1121eaf 100644 --- a/src/socketwrench/server.py +++ b/src/socketwrench/server.py @@ -17,7 +17,12 @@ class Server(socket.socket): default_backlog = 1 default_chunk_size = Connection.default_chunk_size default_num_connection_threads = 1 - default_socket_options = None + default_socket_options = { + socket.SOL_SOCKET: { + socket.SO_REUSEADDR: 1, + socket.SO_REUSEPORT: 1 + } + } default_pause_sleep = 0.1 default_accept_sleep = 0 default_favicon = RouteHandler.default_favicon diff --git a/src/socketwrench/types.py b/src/socketwrench/types.py index 5f17344..2e26154 100644 --- a/src/socketwrench/types.py +++ b/src/socketwrench/types.py @@ -39,7 +39,7 @@ class Headers(dict): def to_string(self) -> str: s = "" for k, v in self.items(): - s += f"{k}: {v}\n" + s += f"{k}: {v}\r\n" return s def __str__(self):