From eabd85f68b636493277cd9a2880040d2e2a59e16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B2=D0=B0=D0=BD=20=D0=A1=D0=BE=D0=BB=D0=BD=D1=86?= =?UTF-8?q?=D0=B5=D0=B2?= Date: Tue, 8 Oct 2024 13:54:15 +0300 Subject: [PATCH 1/2] Support keep alive Improvements: - Response return Content-Length header; - HTTP handler run recursive after call; - File iterator when call before yield file size. --- server/file_read.py | 5 +++++ server/http_handler.py | 23 ++++++++++++++++------- server/main.py | 2 +- server/response.py | 10 ++++++++-- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/server/file_read.py b/server/file_read.py index e4764b9..394e310 100644 --- a/server/file_read.py +++ b/server/file_read.py @@ -18,11 +18,16 @@ # import logging +import os log = logging.getLogger(__name__) def fileiter(filename): + log.debug("Calc file %s size" % filename) + + yield os.path.getsize(filename) + log.debug("Open file %s to byte-read" % filename) with open(filename, "rb") as f: diff --git a/server/http_handler.py b/server/http_handler.py index 5a8c4d9..c573ac2 100644 --- a/server/http_handler.py +++ b/server/http_handler.py @@ -48,16 +48,25 @@ class HTTPHandler: def __write_data(self, data_iter): for chunk in data_iter: - self.write_fd.write(chunk) - self.write_fd.flush() + try: + self.write_fd.write(chunk) + self.write_fd.flush() + except BrokenPipeError: + pass def __read_data(self, size=MAX_REQUEST_LINE_SIZE+1): - return self.read_fd.readline(size) + try: + return self.read_fd.readline(size) + except BrokenPipeError: + pass def __close(self): - self.write_fd.close() - self.read_fd.close() - self.conn.close() + try: + self.write_fd.close() + self.read_fd.close() + self.conn.close() + except BrokenPipeError: + pass def __handle_connection(self): """ @@ -258,4 +267,4 @@ class HTTPHandler: r = Response(status_code=404, data=b"Not found!") self.__write_data(r) - self.__close() + self.__handle_connection() diff --git a/server/main.py b/server/main.py index 3325429..b63b15b 100644 --- a/server/main.py +++ b/server/main.py @@ -27,7 +27,7 @@ def init_server_socket(server_handler): log.info("Accepted connection from %s", addr[0]) thr_serv_conn = threading.Thread(target=server_handler, args=(conn, addr,), daemon=True) - thr_serv_conn.run() + thr_serv_conn.start() except KeyboardInterrupt: log.info("Server get keyboard interrupt, bye!") diff --git a/server/response.py b/server/response.py index ec2ecf3..7cf4c17 100644 --- a/server/response.py +++ b/server/response.py @@ -51,11 +51,17 @@ class Response: resp = "HTTP/1.1 {} {}\r\n" resp += "Server: cnserv\r\n" - resp += "Connection: close\r\n" + resp += "Connection: keep-alive\r\n" + for key, val in self.additional_headers.items(): resp += "{}: {}\r\n".format(key, val) - resp += "\r\n" + if type(self.data) == bytes: + resp += "Content-Length: {}\r\n".format(len(self.data)) + elif hasattr(self.data, "__iter__"): + resp += "Content-Length: {}\r\n".format(next(self.data)) + + resp += "\r\n" resp = resp.format(self.status_code, STATUS_BY_CODE[self.status_code]) resp = resp.encode("UTF-8") -- 2.47.0 From 346f01c9d96b36511dc082730481be11e405378b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B2=D0=B0=D0=BD=20=D0=A1=D0=BE=D0=BB=D0=BD=D1=86?= =?UTF-8?q?=D0=B5=D0=B2?= Date: Wed, 9 Oct 2024 14:31:57 +0300 Subject: [PATCH 2/2] Add for file iterator check access to file - Rename function fileiter to file_iterator; Fix: - BrokenPipeError for thread; - Log strings; --- server/file_read.py | 10 +++++---- server/http_handler.py | 48 ++++++++++++++++++------------------------ server/main.py | 9 +++++--- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/server/file_read.py b/server/file_read.py index 394e310..8e2da58 100644 --- a/server/file_read.py +++ b/server/file_read.py @@ -23,13 +23,15 @@ import os log = logging.getLogger(__name__) -def fileiter(filename): - log.debug("Calc file %s size" % filename) +def file_iterator(filename): + log.debug("Try access to file \"%s\"", filename) + if not os.path.isfile(filename): + raise FileNotFoundError("File \"%s\" not found", filename) + log.debug("Get size of file \"%s\"", filename) yield os.path.getsize(filename) - log.debug("Open file %s to byte-read" % filename) - + log.debug("Open file \"%s\" to byte-read", filename) with open(filename, "rb") as f: while True: file_data = f.read(1024) diff --git a/server/http_handler.py b/server/http_handler.py index c573ac2..18d2cd3 100644 --- a/server/http_handler.py +++ b/server/http_handler.py @@ -22,7 +22,7 @@ import logging import config from .common import MAX_REQUEST_LINE_SIZE, HandlerType, HTTPMethod -from .file_read import fileiter +from .file_read import file_iterator from .response import Response @@ -44,29 +44,23 @@ class HTTPHandler: self.data = b"" - self.__handle_connection() + try: + self.__handle_connection() + except BrokenPipeError: + log.info("Conenction pipe broken, close thread") - def __write_data(self, data_iter): - for chunk in data_iter: - try: - self.write_fd.write(chunk) - self.write_fd.flush() - except BrokenPipeError: - pass + def __write_data(self, response): + for chunk in response: + self.write_fd.write(chunk) + self.write_fd.flush() def __read_data(self, size=MAX_REQUEST_LINE_SIZE+1): - try: - return self.read_fd.readline(size) - except BrokenPipeError: - pass + return self.read_fd.readline(size) def __close(self): - try: - self.write_fd.close() - self.read_fd.close() - self.conn.close() - except BrokenPipeError: - pass + self.write_fd.close() + self.read_fd.close() + self.conn.close() def __handle_connection(self): """ @@ -211,14 +205,14 @@ class HTTPHandler: self.__close() return - log.debug("Want to receive {} bytes from client".format(bytes_to_receive)) + log.debug("Want to receive %s bytes from client", bytes_to_receive) self.data = self.read_fd.read(bytes_to_receive) - log.debug("Request method: %s" % self.http_method) - log.debug("Requested address: %s" % self.http_address) - log.debug("Request headers: %s" % self.http_headers) - log.debug("Request in GET after ?: %s" % self.http_get_request) - log.debug("Data: %s" % self.data) + log.debug("Request method: %s", self.http_method) + log.debug("Requested address: %s", self.http_address) + log.debug("Request headers: %s", self.http_headers) + log.debug("Request in GET after ?: %s", self.http_get_request) + log.debug("Data: %s", self.data) self.__send_form_data() @@ -234,8 +228,8 @@ class HTTPHandler: found = True if path.handler_type == HandlerType.STATIC_FILE: - log.debug("Address associated with static file on path {}".format(path.link)) - r = Response(data=fileiter(path.link)) + log.debug("Address associated with static file on path %s", path.link) + r = Response(data=file_iterator(path.link)) self.__write_data(r) elif path.handler_type == HandlerType.FUNCTION: diff --git a/server/main.py b/server/main.py index b63b15b..6a4a25c 100644 --- a/server/main.py +++ b/server/main.py @@ -16,15 +16,18 @@ def init_server_socket(server_handler): try: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as main_server_socket: + log.debug("Set socket option REUSEADDR to True") main_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) - log.debug("Attempt to bind socket to 0.0.0.0:{}".format(config.SETUP["server"]["port"])) + + log.info("Attempt to bind socket to 0.0.0.0:%d", config.SETUP["server"]["port"]) main_server_socket.bind(("0.0.0.0", config.SETUP["server"]["port"])) - log.debug("Make socket is listen") + + log.debug("Make socket to listen") main_server_socket.listen() while True: conn, addr = main_server_socket.accept() - log.info("Accepted connection from %s", addr[0]) + log.info("Accept connection from %s", addr[0]) thr_serv_conn = threading.Thread(target=server_handler, args=(conn, addr,), daemon=True) thr_serv_conn.start() -- 2.47.0