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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
|
import re
from templater import render_template
from utils import parse_cookies, add_text_headers, SUCCESS, BAD_REQUEST, NOT_FOUND, HTTP_METHODS, METHOD_NOT_ALLOWED
from config import TEXT_TEMPLATE_NAME
import db
_router_tree = {}
# 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 BAD_REQUEST, '400 BAD REQUEST'
return func(query, *match.groups(), *args, **kwargs)
# Добавляем вызываемую функцию в дерево роутера.
# Благодаря этому указывать паттерн url и метод нужно указывать
# только в инициализаторе декоратора, а функция run сама разберется
# при каких условиях нужно вызвать конкретную функцию
_router_tree[url_format] = _router_tree.get(url_format, {})
for method in methods:
_router_tree[url_format][method] = inner
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 url_pattern in _router_tree:
if re.fullmatch(url_pattern, url) and method in _router_tree[url_pattern]:
res = _router_tree[url_pattern][method](url, request['query'])
break
return add_text_headers(*res)
# По заданию любой метод, кроме GET и POST должны быть запрещены на сервере.
@route('/.*', list(set(HTTP_METHODS) ^ {'GET', 'POST'}))
def fallback_wrong_method(query, *args):
return METHOD_NOT_ALLOWED, 'This method is not allowed'
@route('/')
def index_get(query, *args):
return SUCCESS, render_template('form', color=get_color())
# Хотелось попробовать сделать что-то высокоуровневое с декораторами.
# Если в этом коде есть какие-то серьезные проблемы, то скажите сразу.
@route(r'/div/(\d+)/to/(\d+)/?')
def divide_get(query, *args):
color = get_color()
try:
text = str(int(args[0]) / int(args[1]))
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, text=text, color=color)
except ZeroDivisionError as e:
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text=BAD_REQUEST + ('<br>' + str(e) if db.get_config_entry('show_errors') else '')
)
@route(r'/div/?', ['POST'])
def divide_post(query, *args):
color = get_color()
try:
text = str(int(query['numerator']) / int(query['denominator']))
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, text=text, color=color)
except KeyError:
field = 'числитель' if 'numerator' not in query else 'знаменатель'
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text=BAD_REQUEST + ('<br>' + f'Указан неверный {field}')
)
except (ValueError, ZeroDivisionError) as e:
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text=BAD_REQUEST + ('<br>' + str(e) if db.get_config_entry('show_errors') else '')
)
@route(r'/show_errors/(\d{1})/?')
def show_errors_get(query, *args):
color = get_color()
if args[0] == '1':
db.set_config_entry('show_errors', 1)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Опция show_errors включена')
elif args[0] == '0':
db.set_config_entry('show_errors', 0)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Опция show_errors выключена')
else:
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text='Опция show_errors не может принимать такое значение'
)
@route(r'/show_errors/?', ['POST'])
def show_errors_post(query, *args):
color = get_color()
if 'show_errors' not in query:
db.set_config_entry('show_errors', 0)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Опция show_errors выключена')
elif query['show_errors'] == '1':
db.set_config_entry('show_errors', 1)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Опция show_errors включена')
else:
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text='Опция show_errors не может принимать такое значение'
)
@route(r'/set_cookie/=/(.*)/?')
def set_cookie_get(query, *args):
cookie_line = args[0]
color = get_color()
try:
cookies = parse_cookies(cookie_line)
for key, value in cookies.items():
db.set_cookie(key, value)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Cookie-файл обновлен')
except ValueError as e:
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text=BAD_REQUEST + ('<br>' + str(e) if db.get_config_entry('show_errors') else '')
)
@route(r'/set_cookie/=/?', ['POST'])
def set_cookie_post(query, *args):
color = get_color()
try:
cookie_line = query['cookie_line']
cookies = parse_cookies(cookie_line)
for key, value in cookies.items():
db.set_cookie(key, value)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Cookie-файл обновлен')
except KeyError:
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text=BAD_REQUEST + ('<br>' + f'Не указана строка с cookie')
)
except ValueError as e:
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text=BAD_REQUEST + ('<br>' + str(e) if db.get_config_entry('show_errors') else '')
)
@route(r'/short_log/(\d{1})/?')
def short_log_get(query, *args):
color = get_color()
if args[0] == '1':
db.set_config_entry('short_log', 1)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Опция short_log включена')
elif args[0] == '0':
db.set_config_entry('short_log', 0)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Опция short_log выключена')
else:
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text='Опция short_log не может принимать такое значение'
)
@route(r'/short_log/?', ['POST'])
def short_log_post(query, *args):
color = get_color()
if 'short_log' not in query:
db.set_config_entry('short_log', 0)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Опция short_log выключена')
elif query['short_log'] == '1':
db.set_config_entry('short_log', 1)
return SUCCESS, render_template(TEXT_TEMPLATE_NAME, color=color, text='Опция short_log включена')
else:
return BAD_REQUEST, render_template(
TEXT_TEMPLATE_NAME, color=color,
text='Опция short_log не может принимать такое значение'
)
def get_color():
color = db.get_cookie('bg_color', 'white')
if color not in ['green', 'white']:
color = 'white'
return color
|