Improve logging, fix small issues
This commit is contained in:
@@ -26,9 +26,9 @@ def main():
|
||||
try:
|
||||
main()
|
||||
except UnhandledHTTPCode as e:
|
||||
print(f"[{e.status_code}] {e.cause}:\r\n{e.headers}")
|
||||
logging.info(f"[{e.status_code}] {e.cause}:\r\n{e.headers}")
|
||||
sys.exit(2)
|
||||
except Exception as e:
|
||||
print("[ABRT] Internal error: " + str(e), file=sys.stderr)
|
||||
logging.info("[ABRT] Internal error: %s", e)
|
||||
logging.debug("Internal error", exc_info=e)
|
||||
sys.exit(1)
|
||||
|
@@ -125,17 +125,34 @@ class AbstractCommand(ABC):
|
||||
if not sub_request:
|
||||
client.close()
|
||||
|
||||
|
||||
|
||||
def _get_preamble(self, client):
|
||||
"""
|
||||
Returns the preamble (start-line and headers) of the response of this command.
|
||||
@param client: the client object to retrieve from
|
||||
@return: A Message object containing the HTTP-version, status code, status message, headers and buffer
|
||||
"""
|
||||
retriever = PreambleRetriever(client)
|
||||
lines = retriever.retrieve()
|
||||
(version, status, msg) = parser.parse_status_line(next(lines))
|
||||
headers = parser.parse_headers(lines)
|
||||
|
||||
buffer = retriever.buffer
|
||||
logging.debug("---response begin---\r\n%s---response end---", "".join(buffer))
|
||||
|
||||
return Message(version, status, msg, headers, buffer)
|
||||
|
||||
def _await_response(self, client):
|
||||
"""
|
||||
Simple response method.
|
||||
|
||||
Receives the response and prints to stdout.
|
||||
"""
|
||||
while True:
|
||||
line = client.read_line()
|
||||
print(line, end="")
|
||||
if line in ("\r\n", "\n", ""):
|
||||
break
|
||||
|
||||
msg = self._get_preamble(client)
|
||||
|
||||
print("".join(msg.raw))
|
||||
|
||||
def _build_message(self, message: str) -> bytes:
|
||||
return (message + "\r\n").encode(FORMAT)
|
||||
@@ -163,25 +180,6 @@ class AbstractCommand(ABC):
|
||||
return host, path
|
||||
|
||||
|
||||
class AbstractWithBodyCommand(AbstractCommand, ABC):
|
||||
"""
|
||||
The building block for creating an HTTP message for an HTTP method with a body (POST and PUT).
|
||||
"""
|
||||
|
||||
def _build_message(self, message: str) -> bytes:
|
||||
body = input(f"Enter {self.method} data: ").encode(FORMAT)
|
||||
print()
|
||||
|
||||
message += "Content-Type: text/plain\r\n"
|
||||
message += f"Content-Length: {len(body)}\r\n"
|
||||
message += "\r\n"
|
||||
message = message.encode(FORMAT)
|
||||
message += body
|
||||
message += b"\r\n"
|
||||
|
||||
return message
|
||||
|
||||
|
||||
class HeadCommand(AbstractCommand):
|
||||
"""
|
||||
A Command for sending a `HEAD` request.
|
||||
@@ -207,22 +205,6 @@ class GetCommand(AbstractCommand):
|
||||
def method(self):
|
||||
return "GET"
|
||||
|
||||
def _get_preamble(self, client):
|
||||
"""
|
||||
Returns the preamble (start-line and headers) of the response of this command.
|
||||
@param client: the client object to retrieve from
|
||||
@return: A Message object containing the HTTP-version, status code, status message, headers and buffer
|
||||
"""
|
||||
retriever = PreambleRetriever(client)
|
||||
lines = retriever.retrieve()
|
||||
(version, status, msg) = parser.parse_status_line(next(lines))
|
||||
headers = parser.parse_headers(lines)
|
||||
|
||||
buffer = retriever.buffer
|
||||
logging.debug("---response begin---\r\n%s---response end---", "".join(buffer))
|
||||
|
||||
return Message(version, status, msg, headers, buffer)
|
||||
|
||||
def _await_response(self, client):
|
||||
"""
|
||||
Handles the response of this command.
|
||||
@@ -233,6 +215,27 @@ class GetCommand(AbstractCommand):
|
||||
self.filename = responsehandler.handle(client, msg, self, self.dir)
|
||||
|
||||
|
||||
class AbstractWithBodyCommand(AbstractCommand, ABC):
|
||||
"""
|
||||
The building block for creating an HTTP message for an HTTP method with a body (POST and PUT).
|
||||
"""
|
||||
|
||||
def _build_message(self, message: str) -> bytes:
|
||||
input_line = input(f"Enter {self.method} data: ")
|
||||
input_line += "\r\n"
|
||||
body = input_line.encode(FORMAT)
|
||||
print()
|
||||
|
||||
message += "Content-Type: text/plain\r\n"
|
||||
message += f"Content-Length: {len(body)}\r\n"
|
||||
message += "\r\n"
|
||||
message = message.encode(FORMAT)
|
||||
message += body
|
||||
message += b"\r\n"
|
||||
|
||||
return message
|
||||
|
||||
|
||||
class PostCommand(AbstractWithBodyCommand):
|
||||
"""
|
||||
A command for sending a `POST` request.
|
||||
|
@@ -1,6 +0,0 @@
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
|
||||
class HTMLParser:
|
||||
def __init__(self, soup: BeautifulSoup):
|
||||
pass
|
@@ -65,7 +65,7 @@ class ResponseHandler(ABC):
|
||||
|
||||
class BasicResponseHandler(ResponseHandler):
|
||||
"""
|
||||
Response handler which skips the body of the message and only shows the headers.
|
||||
Response handler which will handle redirects and other HTTP status codes.
|
||||
In case of a redirect, it will process it and pass it to the appropriate response handler.
|
||||
"""
|
||||
|
||||
|
@@ -66,12 +66,10 @@ class HTTPServerException(HTTPException):
|
||||
"""
|
||||
status_code: str
|
||||
message: str
|
||||
body: str
|
||||
arg: str
|
||||
|
||||
def __init__(self, arg, body=""):
|
||||
def __init__(self, arg):
|
||||
self.arg = arg
|
||||
self.body = body
|
||||
|
||||
|
||||
class HTTPServerCloseException(HTTPServerException):
|
||||
@@ -160,5 +158,6 @@ class InvalidRequestLine(BadRequest):
|
||||
Request start-line is invalid
|
||||
"""
|
||||
|
||||
def __init__(self, line):
|
||||
def __init__(self, line, arg):
|
||||
super().__init__(arg)
|
||||
self.request_line = line
|
||||
|
@@ -72,7 +72,7 @@ def parse_request_line(line: str):
|
||||
|
||||
split = list(filter(None, line.rstrip().split(" ", 2)))
|
||||
if len(split) < 3:
|
||||
raise InvalidRequestLine(line)
|
||||
raise InvalidRequestLine(line, "missing argument in request-line")
|
||||
|
||||
method, target, version = split
|
||||
if method not in ("CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "POST", "PUT", "TRACE"):
|
||||
|
@@ -1 +0,0 @@
|
||||
lxml~=4.6.2
|
@@ -5,7 +5,7 @@ from abc import ABC, abstractmethod
|
||||
from datetime import datetime
|
||||
|
||||
from httplib import parser
|
||||
from httplib.exceptions import NotFound, Forbidden, NotModified
|
||||
from httplib.exceptions import NotFound, Forbidden, NotModified, BadRequest
|
||||
from httplib.httpsocket import FORMAT
|
||||
from httplib.message import RequestMessage as Message
|
||||
|
||||
@@ -66,8 +66,6 @@ class AbstractCommand(ABC):
|
||||
|
||||
def _build_message(self, status: int, content_type: str, body: bytes, extra_headers=None):
|
||||
|
||||
if extra_headers is None:
|
||||
extra_headers = {}
|
||||
self._process_conditional_headers()
|
||||
|
||||
message = f"HTTP/1.1 {status} {status_message[status]}\r\n"
|
||||
@@ -237,3 +235,9 @@ class PutCommand(AbstractModifyCommand):
|
||||
@property
|
||||
def _file_mode(self):
|
||||
return "w"
|
||||
|
||||
def execute(self):
|
||||
if "content-range" in self.msg.headers:
|
||||
raise BadRequest("PUT request contains Content-Range header")
|
||||
|
||||
super().execute()
|
||||
|
@@ -1,6 +1,4 @@
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from socket import socket
|
||||
from typing import Union
|
||||
from urllib.parse import ParseResultBytes, ParseResult
|
||||
|
@@ -85,6 +85,7 @@ class Worker:
|
||||
RequestHandler.send_error(conn, InternalServerError.status_code, InternalServerError.message)
|
||||
break
|
||||
|
||||
logging.info("Closing socket for client %s", addr)
|
||||
conn.shutdown(socket.SHUT_RDWR)
|
||||
conn.close()
|
||||
# Finished, put back into queue
|
||||
|
Reference in New Issue
Block a user