Add HW 3
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import logging
|
||||
import pathlib
|
||||
from dataclasses import dataclass
|
||||
from socketserver import StreamRequestHandler
|
||||
import typing as t
|
||||
import click
|
||||
import socket
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class HTTPServer:
|
||||
server_address: t.Tuple[str, int]
|
||||
socket: socket.socket
|
||||
server_domain: str
|
||||
working_directory: pathlib.Path
|
||||
|
||||
|
||||
class HTTPHandler(StreamRequestHandler):
|
||||
server: HTTPServer
|
||||
|
||||
# Use self.rfile and self.wfile to interact with the client
|
||||
# Access domain and working directory with self.server.{attr}
|
||||
def handle(self) -> None:
|
||||
first_line = self.rfile.readline()
|
||||
logger.info(f"Handle connection from {self.client_address}, first_line {first_line}")
|
||||
|
||||
# TODO: Read the remaining headers, handle the request and send a response.
|
||||
# Read the body separately using its Content-Length, not until EOF.
|
||||
# Keep memory bounded when processing large files.
|
||||
|
||||
pass
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option("--host", envvar="SERVER_HOST", default="0.0.0.0", type=str)
|
||||
@click.option("--port", envvar="SERVER_PORT", default=8080, type=int)
|
||||
@click.option("--server-domain", envvar="SERVER_DOMAIN", default="localhost", type=str)
|
||||
@click.option("--working-directory", envvar="SERVER_WORKING_DIRECTORY", type=str)
|
||||
def main(host, port, server_domain, working_directory):
|
||||
if not working_directory:
|
||||
raise SystemExit(1)
|
||||
|
||||
working_directory_path = pathlib.Path(working_directory)
|
||||
|
||||
logger.info(
|
||||
f"Starting server on {host}:{port}, domain {server_domain}, working directory {working_directory}"
|
||||
)
|
||||
|
||||
# Create a server socket
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
||||
# Set SO_REUSEADDR option
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
|
||||
# Bind the socket object to the address and port
|
||||
s.bind((host, port))
|
||||
# Start listening for incoming connections
|
||||
s.listen()
|
||||
|
||||
logger.info(f"Listening at {s.getsockname()}")
|
||||
server = HTTPServer((host, port), s, server_domain, working_directory_path)
|
||||
|
||||
while True:
|
||||
# Accept any new connection (request, client_address)
|
||||
try:
|
||||
conn, addr = s.accept()
|
||||
except OSError:
|
||||
break
|
||||
|
||||
try:
|
||||
# Handle the request
|
||||
HTTPHandler(conn, addr, server)
|
||||
|
||||
# Close the connection
|
||||
conn.shutdown(socket.SHUT_WR)
|
||||
conn.close()
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
conn.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user