GNServer 0.0.0.0.11__tar.gz → 0.0.0.0.12__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -162,29 +162,124 @@ import re
162
162
  from urllib.parse import urlparse
163
163
 
164
164
  def resolve_cors(origin_url: str, rules: list[str]) -> bool:
165
+ """
166
+ Возвращает origin_url если он матчится хотя бы с одним правилом.
167
+ Правила:
168
+ - "*.example.com" -> wildcard (одна метка)
169
+ - "**.example.com" -> globstar (0+ меток)
170
+ - "pages.*.core.gn" -> смешанное
171
+ - "https://*.site.tld" -> с проверкой схемы
172
+ - "!<regex>" -> полное соответствие по regex к origin_url
173
+ """
165
174
  origin = origin_url.rstrip("/")
166
- parsed = urlparse(origin)
167
-
175
+ pu = urlparse(origin)
176
+ scheme = (pu.scheme or "").lower()
177
+ host = (pu.hostname or "").lower()
178
+ port = pu.port # может быть None
179
+
180
+ if not host:
181
+ return False
182
+
168
183
  for rule in rules:
169
184
  rule = rule.rstrip("/")
185
+
186
+ # 1) Регекс-правило
170
187
  if rule.startswith("!"):
171
188
  pattern = rule[1:]
172
- if re.match(pattern, origin):
173
- return True
174
- elif "*" in rule:
175
- r = urlparse(rule.replace("*.", ""))
176
- if r.scheme and r.scheme != parsed.scheme:
177
- continue
178
- regex = "^" + re.escape(rule).replace("\\*", "[^.]+") + "$"
179
- if re.match(regex, origin):
189
+ if re.fullmatch(pattern, origin):
180
190
  return True
191
+ continue
192
+
193
+ # 2) Разбор схемы/хоста в правиле
194
+ r_scheme = ""
195
+ r_host = ""
196
+ r_port = None
197
+
198
+ if "://" in rule:
199
+ pr = urlparse(rule)
200
+ r_scheme = (pr.scheme or "").lower()
201
+ # pr.netloc может содержать порт
202
+ netloc = pr.netloc.lower()
203
+ # разберём порт, если есть
204
+ if ":" in netloc and not netloc.endswith("]"): # простая обработка IPv6 не требуется здесь
205
+ name, _, p = netloc.rpartition(":")
206
+ r_host = name
207
+ try:
208
+ r_port = int(p)
209
+ except ValueError:
210
+ r_port = None
211
+ else:
212
+ r_host = netloc
181
213
  else:
182
- if origin == rule:
183
- return True
184
-
214
+ r_host = rule.lower()
215
+
216
+ # схема в правиле задана -> должна совпасть
217
+ if r_scheme and r_scheme != scheme:
218
+ continue
219
+ # порт в правиле задан -> должен совпасть
220
+ if r_port is not None and r_port != port:
221
+ continue
222
+
223
+ # 3) Сопоставление хоста по шаблону с * и ** (по меткам)
224
+ if _host_matches_pattern(host, r_host):
225
+ return True
226
+
185
227
  return False
186
228
 
187
229
 
230
+ def _host_matches_pattern(host: str, pattern: str) -> bool:
231
+ """
232
+ Матчит host против pattern по доменным меткам:
233
+ - '*' -> ровно одна метка
234
+ - '**' -> ноль или больше меток
235
+ Остальные метки — точное совпадение (без внутр. вайлдкардов).
236
+ Примеры:
237
+ host=pages.static.core.gn, pattern=**.core.gn -> True
238
+ host=pages.static.core.gn, pattern=pages.*.core.gn -> True
239
+ host=pages.static.core.gn, pattern=*.gn.gn -> False
240
+ host=abc.def.example.com, pattern=*.example.com -> False (нужно **.example.com)
241
+ host=abc.example.com, pattern=*.example.com -> True
242
+ """
243
+ host_labels = host.split(".")
244
+ pat_labels = pattern.split(".")
245
+
246
+ # быстрый путь: точное совпадение без вайлдкардов
247
+ if "*" not in pattern:
248
+ return host == pattern
249
+
250
+ # рекурсивный матч с поддержкой ** (globstar)
251
+ def match(hi: int, pi: int) -> bool:
252
+ # оба дошли до конца
253
+ if pi == len(pat_labels) and hi == len(host_labels):
254
+ return True
255
+ # закончился паттерн — нет
256
+ if pi == len(pat_labels):
257
+ return False
258
+
259
+ token = pat_labels[pi]
260
+ if token == "**":
261
+ # два варианта:
262
+ # - пропустить '**' (ноль меток)
263
+ if match(hi, pi + 1):
264
+ return True
265
+ # - съесть одну метку (если есть) и остаться на '**'
266
+ if hi < len(host_labels) and match(hi + 1, pi):
267
+ return True
268
+ return False
269
+ elif token == "*":
270
+ # нужно съесть ровно одну метку
271
+ if hi < len(host_labels):
272
+ return match(hi + 1, pi + 1)
273
+ return False
274
+ else:
275
+ # точное совпадение метки
276
+ if hi < len(host_labels) and host_labels[hi] == token:
277
+ return match(hi + 1, pi + 1)
278
+ return False
279
+
280
+ return match(0, 0)
281
+
282
+
188
283
 
189
284
  @dataclass
190
285
  class Route:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GNServer
3
- Version: 0.0.0.0.11
3
+ Version: 0.0.0.0.12
4
4
  Summary: GNServer
5
5
  Home-page: https://github.com/KeyisB/libs/tree/main/GNServer
6
6
  Author: KeyisB
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GNServer
3
- Version: 0.0.0.0.11
3
+ Version: 0.0.0.0.12
4
4
  Summary: GNServer
5
5
  Home-page: https://github.com/KeyisB/libs/tree/main/GNServer
6
6
  Author: KeyisB
@@ -5,7 +5,7 @@ filesName = 'GNServer'
5
5
 
6
6
  setup(
7
7
  name=name,
8
- version='0.0.0.0.11',
8
+ version='0.0.0.0.12',
9
9
  author="KeyisB",
10
10
  author_email="keyisb.pip@gmail.com",
11
11
  description=name,
File without changes
File without changes
File without changes