cn-py-serv/__main__.py

169 lines
4.8 KiB
Python
Raw Normal View History

2023-12-22 02:48:34 +03:00
#!/usr/bin/python3.12
2023-12-29 02:13:10 +03:00
import threading
2023-12-22 02:48:34 +03:00
import socket
import logging
2023-12-29 02:13:10 +03:00
import config
2023-12-22 02:48:34 +03:00
MAX_REQLINE = 64 * 1024
2023-12-30 15:45:47 +03:00
STATUS_CODE = {
200: "OK",
404: "Not Found",
500: "Internal Server Error",
}
class Response:
def __init__(self, status_code=200, additional_headers={}, data=None):
self.status_code = status_code
self.additional_headers = additional_headers
self.data = data
def get(self):
resp = f"HTTP/1.1 {self.status_code} {STATUS_CODE[self.status_code]}\r\n"
resp += "Server: cnserv\r\n"
resp += "Connection: close\r\n"
resp += "\r\n"
resp = resp.encode("UTF-8")
if self.data:
resp += self.data
return resp
2023-12-22 02:48:34 +03:00
2023-12-29 02:13:10 +03:00
class HTTPHandler:
http_type = ""
http_address = ""
headers = {}
data = b""
2023-12-22 02:48:34 +03:00
2023-12-29 02:13:10 +03:00
def __init__(self, conn, addr):
self.conn = conn
self.addr = addr
2023-12-22 02:48:34 +03:00
2023-12-29 02:13:10 +03:00
self.read_fb = conn.makefile("rb")
self.write_fb = conn.makefile("wb")
2023-12-22 02:48:34 +03:00
2023-12-29 02:13:10 +03:00
self.pre_handle_connection()
2023-12-22 02:48:34 +03:00
2023-12-29 02:13:10 +03:00
def pre_handle_connection(self):
raw = self.read_fb.readline(MAX_REQLINE + 1)
2023-12-22 02:48:34 +03:00
2023-12-29 02:13:10 +03:00
if len(raw) > MAX_REQLINE:
logging.debug("Request line too long")
self.conn.send(b"")
self.conn.close()
return
2023-12-22 02:48:34 +03:00
2023-12-29 02:13:10 +03:00
req_line = raw.decode().rstrip("\r\n")
req_line_splited = req_line.split(" ")
2023-12-22 02:48:34 +03:00
2023-12-29 02:13:10 +03:00
if len(req_line_splited) != 3:
logging.debug("Request head too long")
self.conn.send(b"")
self.conn.close()
return
2023-12-22 02:48:34 +03:00
2023-12-29 02:13:10 +03:00
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()
2023-12-22 02:48:34 +03:00
2023-12-29 02:13:10 +03:00
def http_header_handle(self):
2023-12-22 02:48:34 +03:00
while True:
2023-12-29 02:13:10 +03:00
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)
2023-12-30 15:45:47 +03:00
self.headers.update({decoded_data_split[0]: decoded_data_split[1].strip(" ")})
2023-12-29 02:13:10 +03:00
def http_data_handle(self):
2023-12-30 15:45:47 +03:00
# TODO: Get from headers Content-Length and get body from request
2023-12-29 02:13:10 +03:00
"""
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)
"""
2023-12-30 15:45:47 +03:00
logging.debug(self.http_type)
logging.debug(self.http_address)
logging.debug(self.headers)
logging.debug(self.data)
2023-12-29 02:13:10 +03:00
self.send_form_data()
def send_form_data(self):
2023-12-30 15:45:47 +03:00
if self.http_type == "GET":
if self.http_address == "/":
r = Response(data=b"Tested!")
self.write_fb.write(r.get())
elif self.http_address == "/server-status":
form_data = "{\"server-name\": \"cnserv\", \"state\": \"running\"}"
r = Response(data=form_data.encode("UTF-8"))
self.write_fb.write(r.get())
else:
form_data = "Not found!"
r = Response(status_code=404, data=form_data.encode("UTF-8"))
self.write_fb.write(r.get())
2023-12-29 02:13:10 +03:00
self.write_fb.flush()
2023-12-30 15:45:47 +03:00
self.write_fb.close()
self.read_fb.close()
self.conn.close()
2023-12-29 02:13:10 +03:00
if __name__ == "__main__":
logging.basicConfig(filename="main.log", filemode="a", encoding="UTF-8",
level=logging.DEBUG, format="[%(asctime)s][%(levelname)s] %(message)s")
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()
logging.info("Accept connection from %s", addr[0])
2023-12-22 02:48:34 +03:00
2023-12-29 02:13:10 +03:00
thr_serv_conn = threading.Thread(target=HTTPHandler, args=(conn, addr,))
thr_serv_conn.run()
2023-12-22 02:48:34 +03:00
2023-12-29 02:13:10 +03:00
except KeyboardInterrupt:
logging.info("Server get keyboard interrupt. Initialize server to stop")