diff options
Diffstat (limited to 'day7/http_handler.py')
| -rw-r--r-- | day7/http_handler.py | 88 |
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) |