1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
import re
from utils import NOT_FOUND, add_text_headers, HTTP_METHODS
import db
from backend import *
class Route:
def __init__(self, callback, url_format, methods=None):
self.methods = ['GET'] if methods is None else methods
self.url_pattern = re.compile(url_format)
self.callback = callback
def check_route(self, url, method):
match = self.url_pattern.fullmatch(url)
return bool(match) and len(match.groups()) == self.url_pattern.groups and method in self.methods
def invoke_callback(self, url, method, query):
match = self.url_pattern.fullmatch(url)
groups = match.groups()
matched = match and len(groups) == self.url_pattern.groups and method in self.methods
if not matched:
return NOT_FOUND, NOT_FOUND
return self.callback(query, *match.groups())
# url_format - регулярное выражение
def route(url_format, methods=None):
if methods is None:
methods = ['GET']
def wrapper(func):
def inner(url, query, *args, **kwargs):
pattern = re.compile(url_format)
match = re.fullmatch(pattern, url)
if match is None or len(match.groups()) != pattern.groups:
return NOT_FOUND, '404 NOT FOUND'
return func(query, *match.groups(), *args, **kwargs)
# Добавляем вызываемую функцию в дерево роутера.
# Благодаря этому указывать паттерн url и метод нужно указывать
# только в инициализаторе декоратора, а функция run сама разберется
# при каких условиях нужно вызвать конкретную функцию
_router_tree.append(Route(func, url_format, methods))
return inner
return wrapper
def run(request):
res = NOT_FOUND, NOT_FOUND
for key, value in request['cookies'].items():
db.set_cookie(key, value)
method, url = request['method'], request['url']
for route in _router_tree:
if route.check_route(url, method):
res = route.invoke_callback(url, method, request['query'])
break
return add_text_headers(*res)
_router_tree = [
# Пока ничего лучше не придумал
Route(fallback_wrong_method, '/.*', list(set(HTTP_METHODS) ^ {'GET', 'POST'})),
Route(index_get, '/'),
Route(divide_get, r'/div/(\d+)/to/(\d+)/?'),
Route(divide_post, r'/div/?', ['POST']),
Route(show_errors_get, r'/show_errors/(\d{1})/?'),
Route(show_errors_post, r'/show_errors/?', ['POST']),
Route(set_cookie_get, r'/set_cookie/=/(.*)/?'),
Route(set_cookie_post, r'/set_cookie/=/?', ['POST']),
Route(short_log_get, r'/short_log/(\d{1})/?'),
Route(short_log_post, r'/short_log/?', ['POST']),
]
|