From 6daf9ab0b2fdff48530f59fe34b633ade6d40080 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: Fri, 29 Dec 2023 02:13:10 +0300 Subject: [PATCH] Create simple threading http server --- __main__.py | 140 +++++++++++++++++++++++++++++++++++++++------------- config.py | 5 ++ 2 files changed, 112 insertions(+), 33 deletions(-) create mode 100644 config.py diff --git a/__main__.py b/__main__.py index ba4acb2..965fc9f 100755 --- a/__main__.py +++ b/__main__.py @@ -1,54 +1,128 @@ #!/usr/bin/python3.12 -import os +import threading import socket import logging +import config + MAX_REQLINE = 64 * 1024 -def service_connections(conn, addr): - recv_file = conn.makefile("rb") - logging.debug("START RECV") - raw = recv_file.readline(MAX_REQLINE + 1) - logging.debug("END RDLINE") - if len(raw) > MAX_REQLINE: - logging.debug("Request line is too long") - return +class HTTPHandler: + http_type = "" + http_address = "" + headers = {} + data = b"" - req_line = raw.decode().rstrip("\r\n") + def __init__(self, conn, addr): + self.conn = conn + self.addr = addr - words = req_line.split(" ") + self.read_fb = conn.makefile("rb") + self.write_fb = conn.makefile("wb") - if len(words) != 3: - logging.debug("Request head too long") - return + self.pre_handle_connection() - if words[0] == "GET": - logging.debug("SEND") - conn.send(b"HTTP/1.1 200 OK\r\nServer: cnserv\r\n\r\nNone") - logging.debug("SENDEND") - conn.close() - logging.debug("CONNEND") + def pre_handle_connection(self): + raw = self.read_fb.readline(MAX_REQLINE + 1) + if len(raw) > MAX_REQLINE: + logging.debug("Request line too long") + self.conn.send(b"") + self.conn.close() + return + req_line = raw.decode().rstrip("\r\n") + req_line_splited = req_line.split(" ") + + if len(req_line_splited) != 3: + logging.debug("Request head too long") + self.conn.send(b"") + self.conn.close() + return + + if req_line_splited[2] == "HTTP/1.0" or req_line_splited[2] == "HTTP/1.1": + self.http_type = req_line_splited[0] + self.http_address = req_line_splited[1] + self.http_header_handle() + else: + self.conn.send(b"") + self.conn.close() + + def http_header_handle(self): + while True: + raw = self.read_fb.readline(MAX_REQLINE + 1) + + if len(raw) > MAX_REQLINE: + logging.debug("Request header line too long") + self.conn.send(b"") + self.conn.close() + return + + if raw == b"": + self.conn.send(b"") + self.conn.close() + return + + if raw == b"\r\n": + self.http_data_handle() + break + else: + decoded_data = raw.decode("UTF-8").rstrip("\r\n") + decoded_data_split = decoded_data.split(":", 1) + self.headers.update({decoded_data_split[0]: decoded_data_split[1]}) + + def http_data_handle(self): + # Get from headers Content-Length and get body from request + """ + + raw = self.read_fb.readline(1024) + + if len(raw) == 1024: + while True: + self.data += raw + + if len(raw) < 1024: + break + else: + raw = self.read_fb.readline(1024) + """ + + print(self.http_type) + print(self.http_address) + print(self.headers) + print(self.data) + + self.send_form_data() + + def send_form_data(self): + if self.http_address == "/" and self.http_type == "GET": + self.write_fb.write(b"HTTP/1.1 200 OK\r\nConnection: close\r\nServer: cnserv\r\n\r\nTested!") + self.write_fb.flush() + + self.write_fb.close() + self.read_fb.close() + self.conn.close() if __name__ == "__main__": - logging.basicConfig(filename="main.log", filemode="w", encoding="UTF-8", - level=logging.DEBUG) + logging.basicConfig(filename="main.log", filemode="a", encoding="UTF-8", + level=logging.DEBUG, format="[%(asctime)s][%(levelname)s] %(message)s") - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as main_server_socket: - main_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) - main_server_socket.bind(("0.0.0.0", 8080)) - main_server_socket.listen() + logging.info("=== Separator ===") + try: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as main_server_socket: + main_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) + main_server_socket.bind(("0.0.0.0", config.SETUP["server"]["port"])) + main_server_socket.listen() - while True: - conn, addr = main_server_socket.accept() - conn.settimeout(1) - logging.info("Accept connection from %s", addr[0]) + while True: + conn, addr = main_server_socket.accept() + logging.info("Accept connection from %s", addr[0]) - pid = os.fork() + thr_serv_conn = threading.Thread(target=HTTPHandler, args=(conn, addr,)) + thr_serv_conn.run() - if pid == 0: - service_connections(conn, addr) + except KeyboardInterrupt: + logging.info("Server get keyboard interrupt. Initialize server to stop") diff --git a/config.py b/config.py new file mode 100644 index 0000000..1a473d3 --- /dev/null +++ b/config.py @@ -0,0 +1,5 @@ +SETUP = { + "server": { + "port": 8080, + } +}