Improve logging, fix small issues
This commit is contained in:
@@ -26,9 +26,9 @@ def main():
|
|||||||
try:
|
try:
|
||||||
main()
|
main()
|
||||||
except UnhandledHTTPCode as e:
|
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)
|
sys.exit(2)
|
||||||
except Exception as e:
|
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)
|
logging.debug("Internal error", exc_info=e)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
@@ -125,17 +125,34 @@ class AbstractCommand(ABC):
|
|||||||
if not sub_request:
|
if not sub_request:
|
||||||
client.close()
|
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):
|
def _await_response(self, client):
|
||||||
"""
|
"""
|
||||||
Simple response method.
|
Simple response method.
|
||||||
|
|
||||||
Receives the response and prints to stdout.
|
Receives the response and prints to stdout.
|
||||||
"""
|
"""
|
||||||
while True:
|
|
||||||
line = client.read_line()
|
msg = self._get_preamble(client)
|
||||||
print(line, end="")
|
|
||||||
if line in ("\r\n", "\n", ""):
|
print("".join(msg.raw))
|
||||||
break
|
|
||||||
|
|
||||||
def _build_message(self, message: str) -> bytes:
|
def _build_message(self, message: str) -> bytes:
|
||||||
return (message + "\r\n").encode(FORMAT)
|
return (message + "\r\n").encode(FORMAT)
|
||||||
@@ -163,25 +180,6 @@ class AbstractCommand(ABC):
|
|||||||
return host, path
|
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):
|
class HeadCommand(AbstractCommand):
|
||||||
"""
|
"""
|
||||||
A Command for sending a `HEAD` request.
|
A Command for sending a `HEAD` request.
|
||||||
@@ -207,22 +205,6 @@ class GetCommand(AbstractCommand):
|
|||||||
def method(self):
|
def method(self):
|
||||||
return "GET"
|
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):
|
def _await_response(self, client):
|
||||||
"""
|
"""
|
||||||
Handles the response of this command.
|
Handles the response of this command.
|
||||||
@@ -233,6 +215,27 @@ class GetCommand(AbstractCommand):
|
|||||||
self.filename = responsehandler.handle(client, msg, self, self.dir)
|
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):
|
class PostCommand(AbstractWithBodyCommand):
|
||||||
"""
|
"""
|
||||||
A command for sending a `POST` request.
|
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):
|
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.
|
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
|
status_code: str
|
||||||
message: str
|
message: str
|
||||||
body: str
|
|
||||||
arg: str
|
arg: str
|
||||||
|
|
||||||
def __init__(self, arg, body=""):
|
def __init__(self, arg):
|
||||||
self.arg = arg
|
self.arg = arg
|
||||||
self.body = body
|
|
||||||
|
|
||||||
|
|
||||||
class HTTPServerCloseException(HTTPServerException):
|
class HTTPServerCloseException(HTTPServerException):
|
||||||
@@ -160,5 +158,6 @@ class InvalidRequestLine(BadRequest):
|
|||||||
Request start-line is invalid
|
Request start-line is invalid
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, line):
|
def __init__(self, line, arg):
|
||||||
|
super().__init__(arg)
|
||||||
self.request_line = line
|
self.request_line = line
|
||||||
|
@@ -72,7 +72,7 @@ def parse_request_line(line: str):
|
|||||||
|
|
||||||
split = list(filter(None, line.rstrip().split(" ", 2)))
|
split = list(filter(None, line.rstrip().split(" ", 2)))
|
||||||
if len(split) < 3:
|
if len(split) < 3:
|
||||||
raise InvalidRequestLine(line)
|
raise InvalidRequestLine(line, "missing argument in request-line")
|
||||||
|
|
||||||
method, target, version = split
|
method, target, version = split
|
||||||
if method not in ("CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "POST", "PUT", "TRACE"):
|
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 datetime import datetime
|
||||||
|
|
||||||
from httplib import parser
|
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.httpsocket import FORMAT
|
||||||
from httplib.message import RequestMessage as Message
|
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):
|
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()
|
self._process_conditional_headers()
|
||||||
|
|
||||||
message = f"HTTP/1.1 {status} {status_message[status]}\r\n"
|
message = f"HTTP/1.1 {status} {status_message[status]}\r\n"
|
||||||
@@ -237,3 +235,9 @@ class PutCommand(AbstractModifyCommand):
|
|||||||
@property
|
@property
|
||||||
def _file_mode(self):
|
def _file_mode(self):
|
||||||
return "w"
|
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 logging
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
from socket import socket
|
from socket import socket
|
||||||
from typing import Union
|
from typing import Union
|
||||||
from urllib.parse import ParseResultBytes, ParseResult
|
from urllib.parse import ParseResultBytes, ParseResult
|
||||||
|
@@ -85,6 +85,7 @@ class Worker:
|
|||||||
RequestHandler.send_error(conn, InternalServerError.status_code, InternalServerError.message)
|
RequestHandler.send_error(conn, InternalServerError.status_code, InternalServerError.message)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
logging.info("Closing socket for client %s", addr)
|
||||||
conn.shutdown(socket.SHUT_RDWR)
|
conn.shutdown(socket.SHUT_RDWR)
|
||||||
conn.close()
|
conn.close()
|
||||||
# Finished, put back into queue
|
# Finished, put back into queue
|
||||||
|
Reference in New Issue
Block a user