summaryrefslogtreecommitdiff
path: root/day7/http_handler.py
diff options
context:
space:
mode:
Diffstat (limited to 'day7/http_handler.py')
-rw-r--r--day7/http_handler.py88
1 files changed, 65 insertions, 23 deletions
diff --git a/day7/http_handler.py b/day7/http_handler.py
index 4712afe..8fd27bc 100644
--- a/day7/http_handler.py
+++ b/day7/http_handler.py
@@ -1,25 +1,61 @@
-from socket import socket, AF_INET, SOCK_STREAM, SHUT_RDWR
+from socket import socket, AF_INET, SOCK_STREAM, SHUT_RDWR, SOL_SOCKET, SO_REUSEADDR
from time import strftime, gmtime
+import logging
from backend import run
-from utils import validate_url, parse_cookies, parse_query, parse_headers, add_headers, NOT_FOUND, BAD_REQUEST
+from utils import (
+ parse_cookies, parse_query, parse_headers,
+ validate_url, add_text_headers, format_cookies,
+ NOT_FOUND, BAD_REQUEST
+)
from templater import render_template
from config import *
import db
+logging.basicConfig(filename='log.log', level=logging.INFO)
+
+
def log_requests(func):
def wrapper(*args, **kwargs):
address = kwargs['address'] if 'address' in kwargs else args[0]
- method = kwargs['method'] if 'method' in kwargs else args[1]
- url = kwargs['url'] if 'url' in kwargs else args[2]
- http_ver = kwargs['http_ver'] if 'http_ver' in kwargs else args[3]
+ request = kwargs['request'] if 'request' in kwargs else args[1]
response = func(*args, **kwargs)
status = response.split('\n').pop(0).split()[1]
- log_line = f'{address[0]}: {strftime("[%d %b %Y %H:%M:%S]", gmtime())} "{method} {url} {http_ver}" Status: {status}'
+ if not db.get_config_entry('short_log', False):
+ # Формируем строку заголовков для вывода
+ header_pairs = []
+ for header, value in request['headers'].items():
+ if header == 'Cookie':
+ value = format_cookies(value)
+ header_pairs.append(f'{header}: {value}')
+
+ # В логе желательно не использовать переводы строк, когда они не предусмотрены, поэтому
+ # \r\n заменяем на <CRLF>, чтобы мы могли понимать где в строке должны были находиться переводы строк
+ headers_line = '<CRLF>'.join(header_pairs)
+
+ # Формируем строку тела запроса для вывода
+ query_pairs = []
+ for key, value in request['query'].items():
+ query_pairs.append(f'{key}={value}')
+
+ query_line = '&'.join(query_pairs)
+
+ to_logger = f'Headers: {headers_line} | Query: {query_line}'
+ else:
+ to_logger = f'Cookies: {format_cookies(request["cookies"])} '
+
+ log_line = (
+ f'{address[0]}: {strftime("[%d %b %Y %H:%M:%S]", gmtime())} '
+ f'"{request["method"]} {request["url"]} {request["http_ver"]}"'
+ f' | {to_logger} | '
+ f'Status: {status}'
+ )
+
print(log_line)
+ logging.info(log_line)
return response
@@ -27,21 +63,16 @@ def log_requests(func):
@log_requests
-def process_request(address, method, url, http_ver, headers: dict, query):
- if validate_url(url):
- try:
- cookies = parse_cookies(headers['Cookie'])
- except (ValueError, KeyError):
- cookies = {}
-
- response = run(method, url, cookies, query)
+def process_request(address, request: dict):
+ if validate_url(request['url']):
+ response = run(request)
else:
- response = add_headers(NOT_FOUND, '404 NOT FOUND')
+ response = add_text_headers(NOT_FOUND, '404 NOT FOUND')
return response
-def get_request(connection):
+def parse_request(connection):
buffer = b''
request = b''
while not request.endswith(b'\r\n\r\n'):
@@ -55,6 +86,12 @@ def get_request(connection):
buffer += data[1]
method, url, http_ver, headers = parse_headers(request.strip().decode())
+
+ try:
+ cookies = parse_cookies(headers['Cookie'])
+ except (ValueError, KeyError):
+ cookies = {}
+
if 'Content-Type' in headers and headers['Content-Type'] == 'application/x-www-form-urlencoded':
length = int(headers['Content-Length']) - len(buffer)
while length > 0:
@@ -69,7 +106,11 @@ def get_request(connection):
query = parse_query(buffer.strip().decode()) if buffer else {}
- return method, url, http_ver, headers, query
+ return {
+ 'method': method, 'url': url,
+ 'http_ver': http_ver, 'headers': headers,
+ 'query': query, 'cookies': cookies
+ }
def get_color():
@@ -81,9 +122,9 @@ def get_color():
def handle_connection(connection, address):
try:
- request = get_request(connection)
+ request = parse_request(connection)
except ValueError as e:
- response = add_headers(BAD_REQUEST, render_template(
+ response = add_text_headers(BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=get_color(),
text=BAD_REQUEST + ('<br>' + str(e) if db.get_config_entry('show_errors') else '')
))
@@ -93,14 +134,13 @@ def handle_connection(connection, address):
if request is None:
return
- method, url, http_ver, headers, query = request
-
- response = process_request(address, method, url, http_ver, headers, query)
+ response = process_request(address, request)
connection.sendall(response.encode())
def main(host, port):
sock = socket(AF_INET, SOCK_STREAM)
+ sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
sock.bind((host, port))
sock.listen(5)
print(f'* Server started on http://{host}:{port}/')
@@ -123,6 +163,8 @@ def main(host, port):
connection.shutdown(SHUT_RDWR)
connection.close()
except UnboundLocalError:
+ # Если переменная connection еще не создана, то нам не нужно закрывать
+ # соединение, а значит можно игнорировать это исключение.
pass
sock.shutdown(SHUT_RDWR)
@@ -133,5 +175,5 @@ def main(host, port):
if __name__ == '__main__':
- HOST, PORT = ADDR = '0.0.0.0', 4001
+ HOST, PORT = ADDR = '0.0.0.0', 8888
main(HOST, PORT)