tigrcorn-config 0.3.18.dev1__tar.gz → 0.3.18.dev3__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.
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/PKG-INFO +3 -3
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/README.md +1 -1
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/pyproject.toml +2 -2
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/env.py +6 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/governance_surface.py +3 -3
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/load/listeners.py +4 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/load/mapping.py +5 -1
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/load/namespace.py +8 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/load/public_api.py +20 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/load/public_helpers.py +24 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/model/__init__.py +2 -1
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/model/transports.py +17 -1
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/normalize.py +63 -1
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/observability_surface.py +17 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/quic_surface.py +2 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/validate.py +26 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config.egg-info/PKG-INFO +3 -3
- tigrcorn_config-0.3.18.dev3/src/tigrcorn_config.egg-info/requires.txt +4 -0
- tigrcorn_config-0.3.18.dev1/src/tigrcorn_config.egg-info/requires.txt +0 -4
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/LICENSE +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/setup.cfg +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/__init__.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/audit.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/defaults.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/files.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/load/__init__.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/load/helpers.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/load/sources.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/merge.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/model/app.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/model/http.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/model/observability.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/model/scheduler.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/model/security.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/model/server.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/model/types.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/negative_surface.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/origin_surface.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/policy_surface.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/profiles.py +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/py.typed +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config.egg-info/SOURCES.txt +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config.egg-info/dependency_links.txt +0 -0
- {tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tigrcorn-config
|
|
3
|
-
Version: 0.3.18.
|
|
3
|
+
Version: 0.3.18.dev3
|
|
4
4
|
Summary: Typed configuration models, profiles, environment loading, and validation for the Tigrcorn ASGI/HTTP server stack.
|
|
5
5
|
Author-email: Jacob Stewart <jacob@swarmauri.com>
|
|
6
6
|
License: Apache License
|
|
@@ -186,7 +186,7 @@ Classifier: Typing :: Typed
|
|
|
186
186
|
Requires-Python: <3.15,>=3.10
|
|
187
187
|
Description-Content-Type: text/markdown
|
|
188
188
|
License-File: LICENSE
|
|
189
|
-
Requires-Dist: tigrcorn-core==0.3.18.
|
|
189
|
+
Requires-Dist: tigrcorn-core==0.3.18.dev3
|
|
190
190
|
Provides-Extra: yaml
|
|
191
191
|
Requires-Dist: PyYAML>=6.0; extra == "yaml"
|
|
192
192
|
Dynamic: license-file
|
|
@@ -280,7 +280,7 @@ The package exposes its supported public surface through the <code>tigrcorn_conf
|
|
|
280
280
|
|
|
281
281
|
## Package Graph
|
|
282
282
|
|
|
283
|
-
[tigrcorn-core](https://pypi.org/project/tigrcorn-core/) | [tigrcorn-config](https://pypi.org/project/tigrcorn-config/) | [tigrcorn-http](https://pypi.org/project/tigrcorn-http/) | [tigrcorn-asgi](https://pypi.org/project/tigrcorn-asgi/) | [tigrcorn-contract](https://pypi.org/project/tigrcorn-contract/) | [tigrcorn-transports](https://pypi.org/project/tigrcorn-transports/) | [tigrcorn-security](https://pypi.org/project/tigrcorn-security/) | [tigrcorn-protocols](https://pypi.org/project/tigrcorn-protocols/) | [tigrcorn-static](https://pypi.org/project/tigrcorn-static/) | [tigrcorn-observability](https://pypi.org/project/tigrcorn-observability/) | [tigrcorn-runtime](https://pypi.org/project/tigrcorn-runtime/) | [tigrcorn-compat](https://pypi.org/project/tigrcorn-compat/) | [tigrcorn-certification](https://pypi.org/project/tigrcorn-certification/)
|
|
283
|
+
[tigrcorn-core](https://pypi.org/project/tigrcorn-core/) | [tigrcorn-quic-cc](https://pypi.org/project/tigrcorn-quic-cc/) | [tigrcorn-quic-cc-reno](https://pypi.org/project/tigrcorn-quic-cc-reno/) | [tigrcorn-config](https://pypi.org/project/tigrcorn-config/) | [tigrcorn-http](https://pypi.org/project/tigrcorn-http/) | [tigrcorn-asgi](https://pypi.org/project/tigrcorn-asgi/) | [tigrcorn-contract](https://pypi.org/project/tigrcorn-contract/) | [tigrcorn-transports](https://pypi.org/project/tigrcorn-transports/) | [tigrcorn-security](https://pypi.org/project/tigrcorn-security/) | [tigrcorn-protocols](https://pypi.org/project/tigrcorn-protocols/) | [tigrcorn-static](https://pypi.org/project/tigrcorn-static/) | [tigrcorn-observability](https://pypi.org/project/tigrcorn-observability/) | [tigrcorn-runtime](https://pypi.org/project/tigrcorn-runtime/) | [tigrcorn-compat](https://pypi.org/project/tigrcorn-compat/) | [tigrcorn-certification](https://pypi.org/project/tigrcorn-certification/)
|
|
284
284
|
|
|
285
285
|
## Best Practices
|
|
286
286
|
|
|
@@ -87,7 +87,7 @@ The package exposes its supported public surface through the <code>tigrcorn_conf
|
|
|
87
87
|
|
|
88
88
|
## Package Graph
|
|
89
89
|
|
|
90
|
-
[tigrcorn-core](https://pypi.org/project/tigrcorn-core/) | [tigrcorn-config](https://pypi.org/project/tigrcorn-config/) | [tigrcorn-http](https://pypi.org/project/tigrcorn-http/) | [tigrcorn-asgi](https://pypi.org/project/tigrcorn-asgi/) | [tigrcorn-contract](https://pypi.org/project/tigrcorn-contract/) | [tigrcorn-transports](https://pypi.org/project/tigrcorn-transports/) | [tigrcorn-security](https://pypi.org/project/tigrcorn-security/) | [tigrcorn-protocols](https://pypi.org/project/tigrcorn-protocols/) | [tigrcorn-static](https://pypi.org/project/tigrcorn-static/) | [tigrcorn-observability](https://pypi.org/project/tigrcorn-observability/) | [tigrcorn-runtime](https://pypi.org/project/tigrcorn-runtime/) | [tigrcorn-compat](https://pypi.org/project/tigrcorn-compat/) | [tigrcorn-certification](https://pypi.org/project/tigrcorn-certification/)
|
|
90
|
+
[tigrcorn-core](https://pypi.org/project/tigrcorn-core/) | [tigrcorn-quic-cc](https://pypi.org/project/tigrcorn-quic-cc/) | [tigrcorn-quic-cc-reno](https://pypi.org/project/tigrcorn-quic-cc-reno/) | [tigrcorn-config](https://pypi.org/project/tigrcorn-config/) | [tigrcorn-http](https://pypi.org/project/tigrcorn-http/) | [tigrcorn-asgi](https://pypi.org/project/tigrcorn-asgi/) | [tigrcorn-contract](https://pypi.org/project/tigrcorn-contract/) | [tigrcorn-transports](https://pypi.org/project/tigrcorn-transports/) | [tigrcorn-security](https://pypi.org/project/tigrcorn-security/) | [tigrcorn-protocols](https://pypi.org/project/tigrcorn-protocols/) | [tigrcorn-static](https://pypi.org/project/tigrcorn-static/) | [tigrcorn-observability](https://pypi.org/project/tigrcorn-observability/) | [tigrcorn-runtime](https://pypi.org/project/tigrcorn-runtime/) | [tigrcorn-compat](https://pypi.org/project/tigrcorn-compat/) | [tigrcorn-certification](https://pypi.org/project/tigrcorn-certification/)
|
|
91
91
|
|
|
92
92
|
## Best Practices
|
|
93
93
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tigrcorn-config"
|
|
7
|
-
version = "0.3.18.
|
|
7
|
+
version = "0.3.18.dev3"
|
|
8
8
|
description = "Typed configuration models, profiles, environment loading, and validation for the Tigrcorn ASGI/HTTP server stack."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10,<3.15"
|
|
@@ -28,7 +28,7 @@ classifiers = [
|
|
|
28
28
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
29
29
|
"Typing :: Typed",
|
|
30
30
|
]
|
|
31
|
-
dependencies = ["tigrcorn-core==0.3.18.
|
|
31
|
+
dependencies = ["tigrcorn-core==0.3.18.dev3"]
|
|
32
32
|
|
|
33
33
|
[project.optional-dependencies]
|
|
34
34
|
yaml = ["PyYAML>=6.0"]
|
|
@@ -76,11 +76,17 @@ _FLAT_ENV_MAP = {
|
|
|
76
76
|
"QUIC_MAX_DATAGRAM_SIZE": ("quic", "max_datagram_size"),
|
|
77
77
|
"QUIC_IDLE_TIMEOUT": ("quic", "idle_timeout"),
|
|
78
78
|
"QUIC_EARLY_DATA_POLICY": ("quic", "early_data_policy"),
|
|
79
|
+
"QUIC_CONGESTION_CONTROL": ("quic", "congestion_control", "algorithm"),
|
|
80
|
+
"QUIC_CONGESTION_CONTROL_OPTIONS": ("quic", "congestion_control", "options"),
|
|
79
81
|
"WEBTRANSPORT_MAX_SESSIONS": ("webtransport", "max_sessions"),
|
|
80
82
|
"WEBTRANSPORT_MAX_STREAMS": ("webtransport", "max_streams"),
|
|
81
83
|
"WEBTRANSPORT_MAX_DATAGRAM_SIZE": ("webtransport", "max_datagram_size"),
|
|
84
|
+
"WEBTRANSPORT_STREAM_RECEIVE_COALESCE_BYTES": ("webtransport", "stream_receive_coalesce_bytes"),
|
|
85
|
+
"WEBTRANSPORT_STREAM_RECEIVE_MAX_DELAY_MS": ("webtransport", "stream_receive_max_delay_ms"),
|
|
82
86
|
"WEBTRANSPORT_ORIGIN": ("webtransport", "origins"),
|
|
83
87
|
"WEBTRANSPORT_PATH": ("webtransport", "path"),
|
|
88
|
+
"WEBTRANSPORT_PROFILES": ("webtransport", "profiles"),
|
|
89
|
+
"WEBTRANSPORT_PREFERRED_PROFILE": ("webtransport", "preferred_profile"),
|
|
84
90
|
"TIMEOUT_KEEP_ALIVE": ("http", "keep_alive_timeout"),
|
|
85
91
|
"READ_TIMEOUT": ("http", "read_timeout"),
|
|
86
92
|
"WRITE_TIMEOUT": ("http", "write_timeout"),
|
|
@@ -223,8 +223,6 @@ APPROVED_LEGACY_UNITTEST_FILES = (
|
|
|
223
223
|
'tests/test_stream_probe_fixtures.py',
|
|
224
224
|
'tests/test_websocket_uix_demo.py',
|
|
225
225
|
'tests/test_webtransport_bidi_stream_context.py',
|
|
226
|
-
'tests/test_webtransport_feature_demo_app.py',
|
|
227
|
-
'tests/test_webtransport_feature_coverage.py',
|
|
228
226
|
'tests/test_webtransport_mtls_demo.py',
|
|
229
227
|
'tests/test_webtransport_mtls_demo_cleanup.py',
|
|
230
228
|
'tests/test_webtransport_mtls_demo_runtime.py',
|
|
@@ -241,7 +239,9 @@ def scan_legacy_unittest_files(root: Path) -> list[str]:
|
|
|
241
239
|
detected: list[str] = []
|
|
242
240
|
for path in sorted(tests_root.glob('test_*.py')):
|
|
243
241
|
text = path.read_text(encoding='utf-8')
|
|
244
|
-
|
|
242
|
+
# unittest.mock is a standalone mock utility and does not make a
|
|
243
|
+
# pytest module a legacy unittest test module.
|
|
244
|
+
if 'import unittest' in text or 'from unittest import' in text:
|
|
245
245
|
detected.append(path.as_posix().split(root.as_posix() + '/', 1)[-1])
|
|
246
246
|
return detected
|
|
247
247
|
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/load/listeners.py
RENAMED
|
@@ -120,3 +120,7 @@ def _apply_listener_quic_fields(ns: Namespace, listener: dict[str, Any]) -> None
|
|
|
120
120
|
listener["max_datagram_size"] = ns.quic_max_datagram_size
|
|
121
121
|
if ns.quic_secret is not None:
|
|
122
122
|
listener["quic_secret"] = ns.quic_secret.encode("utf-8") if isinstance(ns.quic_secret, str) else ns.quic_secret
|
|
123
|
+
if getattr(ns, "quic_congestion_control", None) is not None:
|
|
124
|
+
listener.setdefault("congestion_control", {})["algorithm"] = ns.quic_congestion_control
|
|
125
|
+
if getattr(ns, "quic_congestion_control_options", None) is not None:
|
|
126
|
+
listener.setdefault("congestion_control", {})["options"] = dict(ns.quic_congestion_control_options)
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/load/mapping.py
RENAMED
|
@@ -7,7 +7,7 @@ from typing import Any, Mapping
|
|
|
7
7
|
from tigrcorn_config.defaults import default_config
|
|
8
8
|
from tigrcorn_config.files import load_config_source
|
|
9
9
|
from tigrcorn_config.merge import merge_config_dicts
|
|
10
|
-
from tigrcorn_config.model import ListenerConfig, ServerConfig
|
|
10
|
+
from tigrcorn_config.model import CongestionControlConfig, ListenerConfig, ServerConfig
|
|
11
11
|
from tigrcorn_config.normalize import normalize_config
|
|
12
12
|
from tigrcorn_config.profiles import resolve_effective_profile_mapping, resolve_requested_profile
|
|
13
13
|
from tigrcorn_config.validate import validate_config
|
|
@@ -40,6 +40,10 @@ def _apply_mapping(target: Any, data: Mapping[str, Any]) -> None:
|
|
|
40
40
|
_apply_mapping(listener, entry)
|
|
41
41
|
listeners.append(listener)
|
|
42
42
|
setattr(target, key, listeners)
|
|
43
|
+
elif key == "congestion_control" and isinstance(value, Mapping):
|
|
44
|
+
congestion_control = CongestionControlConfig()
|
|
45
|
+
_apply_mapping(congestion_control, value)
|
|
46
|
+
setattr(target, key, congestion_control)
|
|
43
47
|
elif dataclasses.is_dataclass(current) and isinstance(value, Mapping):
|
|
44
48
|
_apply_mapping(current, value)
|
|
45
49
|
else:
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/load/namespace.py
RENAMED
|
@@ -116,6 +116,10 @@ def _populate_special_blocks(
|
|
|
116
116
|
blocks["websocket"]["enabled"] = not ns.disable_websocket
|
|
117
117
|
if ns.quic_secret is not None:
|
|
118
118
|
blocks["quic"]["quic_secret"] = ns.quic_secret.encode("utf-8") if isinstance(ns.quic_secret, str) else ns.quic_secret
|
|
119
|
+
if getattr(ns, "quic_congestion_control", None) is not None:
|
|
120
|
+
blocks["quic"].setdefault("congestion_control", {})["algorithm"] = ns.quic_congestion_control
|
|
121
|
+
if getattr(ns, "quic_congestion_control_options", None) is not None:
|
|
122
|
+
blocks["quic"].setdefault("congestion_control", {})["options"] = dict(ns.quic_congestion_control_options)
|
|
119
123
|
if getattr(ns, "webtransport_origin", None):
|
|
120
124
|
blocks["webtransport"]["origins"] = listify(ns.webtransport_origin)
|
|
121
125
|
|
|
@@ -195,7 +199,11 @@ _NAMESPACE_MAPPING: dict[str, tuple[str, str]] = {
|
|
|
195
199
|
"webtransport_max_sessions": ("webtransport", "max_sessions"),
|
|
196
200
|
"webtransport_max_streams": ("webtransport", "max_streams"),
|
|
197
201
|
"webtransport_max_datagram_size": ("webtransport", "max_datagram_size"),
|
|
202
|
+
"webtransport_stream_receive_coalesce_bytes": ("webtransport", "stream_receive_coalesce_bytes"),
|
|
203
|
+
"webtransport_stream_receive_max_delay_ms": ("webtransport", "stream_receive_max_delay_ms"),
|
|
198
204
|
"webtransport_path": ("webtransport", "path"),
|
|
205
|
+
"webtransport_profiles": ("webtransport", "profiles"),
|
|
206
|
+
"webtransport_preferred_profile": ("webtransport", "preferred_profile"),
|
|
199
207
|
"log_level": ("logging", "level"),
|
|
200
208
|
"access_log": ("logging", "access_log"),
|
|
201
209
|
"access_log_file": ("logging", "access_log_file"),
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/load/public_api.py
RENAMED
|
@@ -62,8 +62,12 @@ def build_config(
|
|
|
62
62
|
webtransport_max_sessions: int | None = None,
|
|
63
63
|
webtransport_max_streams: int | None = None,
|
|
64
64
|
webtransport_max_datagram_size: int | None = None,
|
|
65
|
+
webtransport_stream_receive_coalesce_bytes: int | None = None,
|
|
66
|
+
webtransport_stream_receive_max_delay_ms: int | None = None,
|
|
65
67
|
webtransport_origins: list[str] | None = None,
|
|
66
68
|
webtransport_path: str | None = None,
|
|
69
|
+
webtransport_profiles: list[str] | None = None,
|
|
70
|
+
webtransport_preferred_profile: str | None = None,
|
|
67
71
|
pipe_mode: str = "rawframed",
|
|
68
72
|
config: Mapping[str, Any] | None = None,
|
|
69
73
|
default_headers: list[str] | list[tuple[str, str]] | None = None,
|
|
@@ -99,8 +103,12 @@ def build_config(
|
|
|
99
103
|
webtransport_max_sessions=webtransport_max_sessions,
|
|
100
104
|
webtransport_max_streams=webtransport_max_streams,
|
|
101
105
|
webtransport_max_datagram_size=webtransport_max_datagram_size,
|
|
106
|
+
webtransport_stream_receive_coalesce_bytes=webtransport_stream_receive_coalesce_bytes,
|
|
107
|
+
webtransport_stream_receive_max_delay_ms=webtransport_stream_receive_max_delay_ms,
|
|
102
108
|
webtransport_origins=webtransport_origins,
|
|
103
109
|
webtransport_path=webtransport_path,
|
|
110
|
+
webtransport_profiles=webtransport_profiles,
|
|
111
|
+
webtransport_preferred_profile=webtransport_preferred_profile,
|
|
104
112
|
)
|
|
105
113
|
effective_websocket_enabled = True if websocket is None and direct_runtime_customized else bool(websocket)
|
|
106
114
|
effective_h2c_enabled = _effective_h2c_enabled(enable_h2c, requested_http_versions)
|
|
@@ -156,8 +164,12 @@ def build_config(
|
|
|
156
164
|
webtransport_max_sessions=webtransport_max_sessions,
|
|
157
165
|
webtransport_max_streams=webtransport_max_streams,
|
|
158
166
|
webtransport_max_datagram_size=webtransport_max_datagram_size,
|
|
167
|
+
webtransport_stream_receive_coalesce_bytes=webtransport_stream_receive_coalesce_bytes,
|
|
168
|
+
webtransport_stream_receive_max_delay_ms=webtransport_stream_receive_max_delay_ms,
|
|
159
169
|
webtransport_origins=webtransport_origins,
|
|
160
170
|
webtransport_path=webtransport_path,
|
|
171
|
+
webtransport_profiles=webtransport_profiles,
|
|
172
|
+
webtransport_preferred_profile=webtransport_preferred_profile,
|
|
161
173
|
)
|
|
162
174
|
_apply_listener_override_if_needed(
|
|
163
175
|
overrides,
|
|
@@ -184,8 +196,12 @@ def build_config(
|
|
|
184
196
|
webtransport_max_sessions=webtransport_max_sessions,
|
|
185
197
|
webtransport_max_streams=webtransport_max_streams,
|
|
186
198
|
webtransport_max_datagram_size=webtransport_max_datagram_size,
|
|
199
|
+
webtransport_stream_receive_coalesce_bytes=webtransport_stream_receive_coalesce_bytes,
|
|
200
|
+
webtransport_stream_receive_max_delay_ms=webtransport_stream_receive_max_delay_ms,
|
|
187
201
|
webtransport_origins=webtransport_origins,
|
|
188
202
|
webtransport_path=webtransport_path,
|
|
203
|
+
webtransport_profiles=webtransport_profiles,
|
|
204
|
+
webtransport_preferred_profile=webtransport_preferred_profile,
|
|
189
205
|
)
|
|
190
206
|
_apply_optional_http_overrides(
|
|
191
207
|
overrides,
|
|
@@ -227,8 +243,12 @@ def _direct_runtime_customized(**values: Any) -> bool:
|
|
|
227
243
|
or values["webtransport_max_sessions"] is not None
|
|
228
244
|
or values["webtransport_max_streams"] is not None
|
|
229
245
|
or values["webtransport_max_datagram_size"] is not None
|
|
246
|
+
or values["webtransport_stream_receive_coalesce_bytes"] is not None
|
|
247
|
+
or values["webtransport_stream_receive_max_delay_ms"] is not None
|
|
230
248
|
or values["webtransport_origins"] is not None
|
|
231
249
|
or values["webtransport_path"] is not None
|
|
250
|
+
or values["webtransport_profiles"] is not None
|
|
251
|
+
or values["webtransport_preferred_profile"] is not None
|
|
232
252
|
)
|
|
233
253
|
|
|
234
254
|
|
|
@@ -56,8 +56,12 @@ def apply_webtransport_overrides(
|
|
|
56
56
|
webtransport_max_sessions: int | None,
|
|
57
57
|
webtransport_max_streams: int | None,
|
|
58
58
|
webtransport_max_datagram_size: int | None,
|
|
59
|
+
webtransport_stream_receive_coalesce_bytes: int | None,
|
|
60
|
+
webtransport_stream_receive_max_delay_ms: int | None,
|
|
59
61
|
webtransport_origins: list[str] | None,
|
|
60
62
|
webtransport_path: str | None,
|
|
63
|
+
webtransport_profiles: list[str] | None,
|
|
64
|
+
webtransport_preferred_profile: str | None,
|
|
61
65
|
) -> None:
|
|
62
66
|
if any(
|
|
63
67
|
value is not None
|
|
@@ -65,16 +69,32 @@ def apply_webtransport_overrides(
|
|
|
65
69
|
webtransport_max_sessions,
|
|
66
70
|
webtransport_max_streams,
|
|
67
71
|
webtransport_max_datagram_size,
|
|
72
|
+
webtransport_stream_receive_coalesce_bytes,
|
|
73
|
+
webtransport_stream_receive_max_delay_ms,
|
|
68
74
|
webtransport_origins,
|
|
69
75
|
webtransport_path,
|
|
76
|
+
webtransport_profiles,
|
|
77
|
+
webtransport_preferred_profile,
|
|
70
78
|
)
|
|
71
79
|
):
|
|
72
80
|
overrides["webtransport"] = {
|
|
73
81
|
"max_sessions": webtransport_max_sessions,
|
|
74
82
|
"max_streams": webtransport_max_streams,
|
|
75
83
|
"max_datagram_size": webtransport_max_datagram_size,
|
|
84
|
+
**(
|
|
85
|
+
{"stream_receive_coalesce_bytes": webtransport_stream_receive_coalesce_bytes}
|
|
86
|
+
if webtransport_stream_receive_coalesce_bytes is not None
|
|
87
|
+
else {}
|
|
88
|
+
),
|
|
89
|
+
**(
|
|
90
|
+
{"stream_receive_max_delay_ms": webtransport_stream_receive_max_delay_ms}
|
|
91
|
+
if webtransport_stream_receive_max_delay_ms is not None
|
|
92
|
+
else {}
|
|
93
|
+
),
|
|
76
94
|
"origins": webtransport_origins or [],
|
|
77
95
|
"path": webtransport_path,
|
|
96
|
+
"profiles": webtransport_profiles or [],
|
|
97
|
+
"preferred_profile": webtransport_preferred_profile,
|
|
78
98
|
}
|
|
79
99
|
|
|
80
100
|
|
|
@@ -94,8 +114,12 @@ def apply_listener_override_if_needed(overrides: dict[str, Any], **values: Any)
|
|
|
94
114
|
or values["webtransport_max_sessions"] is not None
|
|
95
115
|
or values["webtransport_max_streams"] is not None
|
|
96
116
|
or values["webtransport_max_datagram_size"] is not None
|
|
117
|
+
or values["webtransport_stream_receive_coalesce_bytes"] is not None
|
|
118
|
+
or values["webtransport_stream_receive_max_delay_ms"] is not None
|
|
97
119
|
or values["webtransport_origins"] is not None
|
|
98
120
|
or values["webtransport_path"] is not None
|
|
121
|
+
or values["webtransport_profiles"] is not None
|
|
122
|
+
or values["webtransport_preferred_profile"] is not None
|
|
99
123
|
)
|
|
100
124
|
if not listener_customized:
|
|
101
125
|
return
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/model/__init__.py
RENAMED
|
@@ -6,13 +6,14 @@ from .observability import LoggingConfig, MetricsConfig
|
|
|
6
6
|
from .scheduler import SchedulerConfig
|
|
7
7
|
from .security import ProxyConfig, TLSConfig
|
|
8
8
|
from .server import ServerConfig
|
|
9
|
-
from .transports import ListenerConfig, QUICConfig, WebTransportConfig
|
|
9
|
+
from .transports import CongestionControlConfig, ListenerConfig, QUICConfig, WebTransportConfig
|
|
10
10
|
from .types import AppInterface, ClaimClass, ListenerKind, ProtocolName
|
|
11
11
|
|
|
12
12
|
__all__ = [
|
|
13
13
|
"AppConfig",
|
|
14
14
|
"AppInterface",
|
|
15
15
|
"ClaimClass",
|
|
16
|
+
"CongestionControlConfig",
|
|
16
17
|
"HTTPConfig",
|
|
17
18
|
"HooksConfig",
|
|
18
19
|
"ListenerConfig",
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/model/transports.py
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
|
-
from typing import Literal
|
|
4
|
+
from typing import Any, Literal
|
|
5
5
|
|
|
6
6
|
from tigrcorn_core.constants import (
|
|
7
7
|
DEFAULT_BACKLOG,
|
|
@@ -15,6 +15,12 @@ from tigrcorn_core.constants import (
|
|
|
15
15
|
from .types import ListenerKind
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
@dataclass(slots=True)
|
|
19
|
+
class CongestionControlConfig:
|
|
20
|
+
algorithm: str | None = None
|
|
21
|
+
options: dict[str, Any] = field(default_factory=dict)
|
|
22
|
+
|
|
23
|
+
|
|
18
24
|
@dataclass(slots=True)
|
|
19
25
|
class QUICConfig:
|
|
20
26
|
quic_secret: bytes | None = None
|
|
@@ -22,13 +28,22 @@ class QUICConfig:
|
|
|
22
28
|
max_datagram_size: int = DEFAULT_MAX_DATAGRAM_SIZE
|
|
23
29
|
idle_timeout: float = DEFAULT_IDLE_TIMEOUT
|
|
24
30
|
early_data_policy: Literal["allow", "deny", "require"] = "deny"
|
|
31
|
+
congestion_control: CongestionControlConfig = field(
|
|
32
|
+
default_factory=lambda: CongestionControlConfig(algorithm="reno")
|
|
33
|
+
)
|
|
25
34
|
|
|
26
35
|
|
|
27
36
|
@dataclass(slots=True)
|
|
28
37
|
class WebTransportConfig:
|
|
38
|
+
enabled: bool = False
|
|
39
|
+
compatibility: Literal["current", "draft13"] = "current"
|
|
40
|
+
profiles: list[str] = field(default_factory=list)
|
|
41
|
+
preferred_profile: str | None = None
|
|
29
42
|
max_sessions: int | None = None
|
|
30
43
|
max_streams: int | None = None
|
|
31
44
|
max_datagram_size: int | None = None
|
|
45
|
+
stream_receive_coalesce_bytes: int = 16 * 1024
|
|
46
|
+
stream_receive_max_delay_ms: int = 5
|
|
32
47
|
origins: list[str] = field(default_factory=list)
|
|
33
48
|
path: str | None = None
|
|
34
49
|
|
|
@@ -69,6 +84,7 @@ class ListenerConfig:
|
|
|
69
84
|
quic_secret: bytes | None = None
|
|
70
85
|
quic_require_retry: bool = False
|
|
71
86
|
max_datagram_size: int = DEFAULT_MAX_DATAGRAM_SIZE
|
|
87
|
+
congestion_control: CongestionControlConfig | None = None
|
|
72
88
|
pipe_mode: Literal["rawframed", "stream"] = DEFAULT_PIPE_MODE
|
|
73
89
|
user: str | int | None = None
|
|
74
90
|
group: str | int | None = None
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/normalize.py
RENAMED
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import secrets
|
|
4
4
|
|
|
5
|
-
from tigrcorn_config.model import ListenerConfig, ServerConfig
|
|
5
|
+
from tigrcorn_config.model import CongestionControlConfig, ListenerConfig, ServerConfig
|
|
6
6
|
from tigrcorn_core.constants import (
|
|
7
7
|
DEFAULT_HTTP2_INITIAL_CONNECTION_WINDOW_SIZE,
|
|
8
8
|
DEFAULT_HTTP2_INITIAL_STREAM_WINDOW_SIZE,
|
|
@@ -90,6 +90,55 @@ def normalize_config(config: ServerConfig) -> None:
|
|
|
90
90
|
config.webtransport.max_streams = int(config.webtransport.max_streams)
|
|
91
91
|
if config.webtransport.max_datagram_size is not None:
|
|
92
92
|
config.webtransport.max_datagram_size = int(config.webtransport.max_datagram_size)
|
|
93
|
+
config.webtransport.stream_receive_coalesce_bytes = int(
|
|
94
|
+
config.webtransport.stream_receive_coalesce_bytes
|
|
95
|
+
)
|
|
96
|
+
config.webtransport.stream_receive_max_delay_ms = int(
|
|
97
|
+
config.webtransport.stream_receive_max_delay_ms
|
|
98
|
+
)
|
|
99
|
+
config.webtransport.enabled = bool(config.webtransport.enabled)
|
|
100
|
+
config.quic.congestion_control.algorithm = str(
|
|
101
|
+
config.quic.congestion_control.algorithm or "reno"
|
|
102
|
+
).strip().lower()
|
|
103
|
+
config.quic.congestion_control.options = dict(
|
|
104
|
+
config.quic.congestion_control.options or {}
|
|
105
|
+
)
|
|
106
|
+
config.webtransport.compatibility = str(config.webtransport.compatibility or 'current').strip().lower()
|
|
107
|
+
aliases = {'current': 'ietf-current', 'chromium': 'draft02'}
|
|
108
|
+
configured_profiles = [
|
|
109
|
+
aliases.get(str(value).strip().lower(), str(value).strip().lower())
|
|
110
|
+
for value in _ensure_list(config.webtransport.profiles)
|
|
111
|
+
if str(value).strip()
|
|
112
|
+
]
|
|
113
|
+
if (
|
|
114
|
+
config.webtransport.compatibility == 'draft13'
|
|
115
|
+
and configured_profiles in (
|
|
116
|
+
['ietf-current'],
|
|
117
|
+
['draft02', 'draft13', 'ietf-current'],
|
|
118
|
+
)
|
|
119
|
+
and config.webtransport.preferred_profile in {None, 'ietf-current', 'current'}
|
|
120
|
+
):
|
|
121
|
+
configured_profiles = ['draft13']
|
|
122
|
+
config.webtransport.preferred_profile = 'draft13'
|
|
123
|
+
if not configured_profiles:
|
|
124
|
+
configured_profiles = (
|
|
125
|
+
['draft13']
|
|
126
|
+
if config.webtransport.compatibility == 'draft13'
|
|
127
|
+
else ['draft02', 'draft13', 'ietf-current']
|
|
128
|
+
)
|
|
129
|
+
config.webtransport.profiles = list(dict.fromkeys(configured_profiles))
|
|
130
|
+
preferred = str(config.webtransport.preferred_profile or '').strip().lower()
|
|
131
|
+
if preferred:
|
|
132
|
+
preferred = aliases.get(preferred, preferred)
|
|
133
|
+
else:
|
|
134
|
+
preferred = (
|
|
135
|
+
'ietf-current'
|
|
136
|
+
if 'ietf-current' in config.webtransport.profiles
|
|
137
|
+
else config.webtransport.profiles[0]
|
|
138
|
+
)
|
|
139
|
+
config.webtransport.preferred_profile = preferred
|
|
140
|
+
if preferred in {'ietf-current', 'draft13'}:
|
|
141
|
+
config.webtransport.compatibility = 'draft13' if preferred == 'draft13' else 'current'
|
|
93
142
|
config.webtransport.origins = [str(v).strip() for v in _ensure_list(config.webtransport.origins) if str(v).strip()]
|
|
94
143
|
if config.webtransport.path is not None:
|
|
95
144
|
path = str(config.webtransport.path).strip()
|
|
@@ -218,7 +267,10 @@ def normalize_config(config: ServerConfig) -> None:
|
|
|
218
267
|
listener.protocols.append("websocket")
|
|
219
268
|
listener.websocket = config.websocket.enabled if listener.websocket else listener.websocket
|
|
220
269
|
if listener.kind == "udp":
|
|
270
|
+
if config.webtransport.enabled and "webtransport" not in listener.protocols:
|
|
271
|
+
listener.protocols.append("webtransport")
|
|
221
272
|
if "webtransport" in listener.protocols:
|
|
273
|
+
config.webtransport.enabled = True
|
|
222
274
|
if "quic" not in listener.protocols:
|
|
223
275
|
listener.protocols.insert(0, "quic")
|
|
224
276
|
if "http3" not in listener.protocols:
|
|
@@ -229,6 +281,16 @@ def normalize_config(config: ServerConfig) -> None:
|
|
|
229
281
|
if "http3" in listener.protocols and "quic" not in listener.protocols:
|
|
230
282
|
listener.protocols.insert(0, "quic")
|
|
231
283
|
listener.max_datagram_size = int(config.quic.max_datagram_size or listener.max_datagram_size)
|
|
284
|
+
listener_cc = listener.congestion_control or CongestionControlConfig()
|
|
285
|
+
listener.congestion_control = CongestionControlConfig(
|
|
286
|
+
algorithm=str(
|
|
287
|
+
listener_cc.algorithm or config.quic.congestion_control.algorithm
|
|
288
|
+
).strip().lower(),
|
|
289
|
+
options={
|
|
290
|
+
**config.quic.congestion_control.options,
|
|
291
|
+
**dict(listener_cc.options or {}),
|
|
292
|
+
},
|
|
293
|
+
)
|
|
232
294
|
listener.quic_require_retry = bool(config.quic.require_retry or listener.quic_require_retry)
|
|
233
295
|
listener.quic_secret = listener.quic_secret or config.quic.quic_secret or secrets.token_bytes(32)
|
|
234
296
|
if not listener.scheme:
|
|
@@ -28,10 +28,22 @@ METRICS_SCHEMA = {
|
|
|
28
28
|
'loss': [
|
|
29
29
|
'quic_packets_lost',
|
|
30
30
|
'quic_pto_expirations',
|
|
31
|
+
'quic_pto_probes',
|
|
32
|
+
'quic_stream_bytes_retransmitted',
|
|
33
|
+
'quic_crypto_bytes_retransmitted',
|
|
34
|
+
'quic_datagram_frames_abandoned',
|
|
35
|
+
'quic_frames_regenerated',
|
|
31
36
|
'quic_path_challenges',
|
|
32
37
|
'quic_path_responses',
|
|
33
38
|
'quic_path_migrations',
|
|
34
39
|
],
|
|
40
|
+
'congestion': [
|
|
41
|
+
'quic_bytes_in_flight',
|
|
42
|
+
'quic_congestion_window_bytes',
|
|
43
|
+
'quic_smoothed_rtt_seconds',
|
|
44
|
+
'quic_pacing_rate_bytes_per_second',
|
|
45
|
+
'quic_pending_outbound_datagrams',
|
|
46
|
+
],
|
|
35
47
|
'http3': [
|
|
36
48
|
'http3_requests_served',
|
|
37
49
|
'http3_stream_resets',
|
|
@@ -45,6 +57,11 @@ METRICS_SCHEMA = {
|
|
|
45
57
|
'active_connections',
|
|
46
58
|
'active_websocket_connections',
|
|
47
59
|
'active_quic_sessions',
|
|
60
|
+
'quic_bytes_in_flight',
|
|
61
|
+
'quic_congestion_window_bytes',
|
|
62
|
+
'quic_smoothed_rtt_seconds',
|
|
63
|
+
'quic_pacing_rate_bytes_per_second',
|
|
64
|
+
'quic_pending_outbound_datagrams',
|
|
48
65
|
],
|
|
49
66
|
'notes': {
|
|
50
67
|
'aggregation': 'Counters are monotonic totals; gauges report current in-process state.',
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/quic_surface.py
RENAMED
|
@@ -94,6 +94,8 @@ QUIC_FLAG_HELP: dict[str, str] = {
|
|
|
94
94
|
'--quic-max-datagram-size': 'Maximum QUIC UDP payload size advertised and accepted by package-owned QUIC listeners',
|
|
95
95
|
'--quic-idle-timeout': 'QUIC idle timeout in seconds for package-owned UDP listeners',
|
|
96
96
|
'--quic-early-data-policy': 'QUIC early-data policy: deny, allow, or require with 425 downgrade handling',
|
|
97
|
+
'--quic-congestion-control': 'Installed QUIC congestion-control provider id (default: reno)',
|
|
98
|
+
'--quic-congestion-control-options': 'JSON object passed to the selected QUIC congestion-control provider at listener startup',
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
|
|
@@ -11,6 +11,7 @@ from tigrcorn_observability.metrics import parse_statsd_host
|
|
|
11
11
|
from tigrcorn_observability.tracing import validate_otel_endpoint
|
|
12
12
|
from tigrcorn_core.errors import ConfigError
|
|
13
13
|
from tigrcorn_config.profiles import list_blessed_profiles
|
|
14
|
+
from tigrcorn_protocols.webtransport.profiles import profile_registry
|
|
14
15
|
|
|
15
16
|
_ALLOWED_PROTOCOLS = {"http1", "http2", "http3", "quic", "websocket", "webtransport", "rawframed", "custom"}
|
|
16
17
|
_ALLOWED_WORKER_CLASSES = {"local", "process", *SUPPORTED_WORKER_CLASS_ALIASES}
|
|
@@ -23,7 +24,20 @@ def _require_positive(name: str, value: int | float | None) -> None:
|
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
def validate_config(config: ServerConfig) -> None:
|
|
27
|
+
if config.webtransport.compatibility not in {'current', 'draft13'}:
|
|
28
|
+
raise ConfigError("webtransport.compatibility must be 'current' or 'draft13'")
|
|
26
29
|
normalize_config(config)
|
|
30
|
+
registry = profile_registry()
|
|
31
|
+
if config.webtransport.enabled and not config.webtransport.profiles:
|
|
32
|
+
raise ConfigError('webtransport.profiles must not be empty when WebTransport is enabled')
|
|
33
|
+
unknown_profiles = [name for name in config.webtransport.profiles if name not in registry]
|
|
34
|
+
if unknown_profiles:
|
|
35
|
+
raise ConfigError(f"unsupported WebTransport profiles: {', '.join(unknown_profiles)}")
|
|
36
|
+
if config.webtransport.preferred_profile not in config.webtransport.profiles:
|
|
37
|
+
raise ConfigError('webtransport.preferred_profile must be included in webtransport.profiles')
|
|
38
|
+
unavailable = [name for name in config.webtransport.profiles if not registry[name].implemented]
|
|
39
|
+
if unavailable:
|
|
40
|
+
raise ConfigError(f"WebTransport profiles are not implemented: {', '.join(unavailable)}")
|
|
27
41
|
if config.app.profile is not None and config.app.profile not in set(list_blessed_profiles()):
|
|
28
42
|
raise ConfigError(f"unsupported app.profile: {config.app.profile!r}")
|
|
29
43
|
if config.app.interface not in {"auto", "tigr-asgi-contract", "asgi3"}:
|
|
@@ -88,6 +102,7 @@ def validate_config(config: ServerConfig) -> None:
|
|
|
88
102
|
"webtransport.max_sessions": config.webtransport.max_sessions,
|
|
89
103
|
"webtransport.max_streams": config.webtransport.max_streams,
|
|
90
104
|
"webtransport.max_datagram_size": config.webtransport.max_datagram_size,
|
|
105
|
+
"webtransport.stream_receive_coalesce_bytes": config.webtransport.stream_receive_coalesce_bytes,
|
|
91
106
|
"tls.ocsp_cache_size": config.tls.ocsp_cache_size,
|
|
92
107
|
"scheduler.limit_concurrency": config.scheduler.limit_concurrency,
|
|
93
108
|
"scheduler.max_connections": config.scheduler.max_connections,
|
|
@@ -97,6 +112,11 @@ def validate_config(config: ServerConfig) -> None:
|
|
|
97
112
|
}.items():
|
|
98
113
|
_require_positive(field_name, value)
|
|
99
114
|
|
|
115
|
+
if config.webtransport.stream_receive_max_delay_ms < 0:
|
|
116
|
+
raise ConfigError(
|
|
117
|
+
"webtransport.stream_receive_max_delay_ms must be nonnegative"
|
|
118
|
+
)
|
|
119
|
+
|
|
100
120
|
if config.http.alt_svc_max_age < 0:
|
|
101
121
|
raise ConfigError('http.alt_svc_max_age must be non-negative')
|
|
102
122
|
if not (16_384 <= config.http.http2_max_frame_size <= 16_777_215):
|
|
@@ -119,6 +139,8 @@ def validate_config(config: ServerConfig) -> None:
|
|
|
119
139
|
raise ConfigError(f"unsupported websocket compression mode: {config.websocket.compression!r}")
|
|
120
140
|
if config.quic.early_data_policy not in {"allow", "deny", "require"}:
|
|
121
141
|
raise ConfigError(f"unsupported quic early data policy: {config.quic.early_data_policy!r}")
|
|
142
|
+
if not config.quic.congestion_control.algorithm:
|
|
143
|
+
raise ConfigError("quic.congestion_control.algorithm must not be empty")
|
|
122
144
|
if config.quic.quic_secret is not None and len(config.quic.quic_secret) == 0:
|
|
123
145
|
raise ConfigError('quic.quic_secret must not be empty when provided')
|
|
124
146
|
if config.webtransport.path is not None and not config.webtransport.path.startswith('/'):
|
|
@@ -213,6 +235,8 @@ def validate_config(config: ServerConfig) -> None:
|
|
|
213
235
|
raise ConfigError("max_datagram_size must be positive for udp listeners")
|
|
214
236
|
if listener.quic_secret is not None and len(listener.quic_secret) == 0:
|
|
215
237
|
raise ConfigError('udp listener quic_secret must not be empty when provided')
|
|
238
|
+
if listener.congestion_control is None or not listener.congestion_control.algorithm:
|
|
239
|
+
raise ConfigError("udp listener congestion_control.algorithm must not be empty")
|
|
216
240
|
if "http3" in listener.enabled_protocols and "quic" not in listener.enabled_protocols:
|
|
217
241
|
raise ConfigError("http3 requires quic on udp listeners")
|
|
218
242
|
if "webtransport" in listener.enabled_protocols:
|
|
@@ -220,6 +244,8 @@ def validate_config(config: ServerConfig) -> None:
|
|
|
220
244
|
raise ConfigError("webtransport requires quic and http3 on udp listeners")
|
|
221
245
|
if "3" not in listener.http_versions:
|
|
222
246
|
raise ConfigError("webtransport requires HTTP/3 on udp listeners")
|
|
247
|
+
if listener.alpn_protocols and 'h3' not in listener.alpn_protocols:
|
|
248
|
+
raise ConfigError("webtransport requires h3 ALPN on udp listeners")
|
|
223
249
|
if listener.ssl_ca_certs and not listener.ssl_enabled:
|
|
224
250
|
raise ConfigError("ssl_ca_certs requires ssl_certfile and ssl_keyfile on udp listeners")
|
|
225
251
|
if listener.ssl_require_client_cert:
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tigrcorn-config
|
|
3
|
-
Version: 0.3.18.
|
|
3
|
+
Version: 0.3.18.dev3
|
|
4
4
|
Summary: Typed configuration models, profiles, environment loading, and validation for the Tigrcorn ASGI/HTTP server stack.
|
|
5
5
|
Author-email: Jacob Stewart <jacob@swarmauri.com>
|
|
6
6
|
License: Apache License
|
|
@@ -186,7 +186,7 @@ Classifier: Typing :: Typed
|
|
|
186
186
|
Requires-Python: <3.15,>=3.10
|
|
187
187
|
Description-Content-Type: text/markdown
|
|
188
188
|
License-File: LICENSE
|
|
189
|
-
Requires-Dist: tigrcorn-core==0.3.18.
|
|
189
|
+
Requires-Dist: tigrcorn-core==0.3.18.dev3
|
|
190
190
|
Provides-Extra: yaml
|
|
191
191
|
Requires-Dist: PyYAML>=6.0; extra == "yaml"
|
|
192
192
|
Dynamic: license-file
|
|
@@ -280,7 +280,7 @@ The package exposes its supported public surface through the <code>tigrcorn_conf
|
|
|
280
280
|
|
|
281
281
|
## Package Graph
|
|
282
282
|
|
|
283
|
-
[tigrcorn-core](https://pypi.org/project/tigrcorn-core/) | [tigrcorn-config](https://pypi.org/project/tigrcorn-config/) | [tigrcorn-http](https://pypi.org/project/tigrcorn-http/) | [tigrcorn-asgi](https://pypi.org/project/tigrcorn-asgi/) | [tigrcorn-contract](https://pypi.org/project/tigrcorn-contract/) | [tigrcorn-transports](https://pypi.org/project/tigrcorn-transports/) | [tigrcorn-security](https://pypi.org/project/tigrcorn-security/) | [tigrcorn-protocols](https://pypi.org/project/tigrcorn-protocols/) | [tigrcorn-static](https://pypi.org/project/tigrcorn-static/) | [tigrcorn-observability](https://pypi.org/project/tigrcorn-observability/) | [tigrcorn-runtime](https://pypi.org/project/tigrcorn-runtime/) | [tigrcorn-compat](https://pypi.org/project/tigrcorn-compat/) | [tigrcorn-certification](https://pypi.org/project/tigrcorn-certification/)
|
|
283
|
+
[tigrcorn-core](https://pypi.org/project/tigrcorn-core/) | [tigrcorn-quic-cc](https://pypi.org/project/tigrcorn-quic-cc/) | [tigrcorn-quic-cc-reno](https://pypi.org/project/tigrcorn-quic-cc-reno/) | [tigrcorn-config](https://pypi.org/project/tigrcorn-config/) | [tigrcorn-http](https://pypi.org/project/tigrcorn-http/) | [tigrcorn-asgi](https://pypi.org/project/tigrcorn-asgi/) | [tigrcorn-contract](https://pypi.org/project/tigrcorn-contract/) | [tigrcorn-transports](https://pypi.org/project/tigrcorn-transports/) | [tigrcorn-security](https://pypi.org/project/tigrcorn-security/) | [tigrcorn-protocols](https://pypi.org/project/tigrcorn-protocols/) | [tigrcorn-static](https://pypi.org/project/tigrcorn-static/) | [tigrcorn-observability](https://pypi.org/project/tigrcorn-observability/) | [tigrcorn-runtime](https://pypi.org/project/tigrcorn-runtime/) | [tigrcorn-compat](https://pypi.org/project/tigrcorn-compat/) | [tigrcorn-certification](https://pypi.org/project/tigrcorn-certification/)
|
|
284
284
|
|
|
285
285
|
## Best Practices
|
|
286
286
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/load/__init__.py
RENAMED
|
File without changes
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/load/helpers.py
RENAMED
|
File without changes
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/load/sources.py
RENAMED
|
File without changes
|
|
File without changes
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/model/app.py
RENAMED
|
File without changes
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/model/http.py
RENAMED
|
File without changes
|
|
File without changes
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/model/scheduler.py
RENAMED
|
File without changes
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/model/security.py
RENAMED
|
File without changes
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/model/server.py
RENAMED
|
File without changes
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/model/types.py
RENAMED
|
File without changes
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/negative_surface.py
RENAMED
|
File without changes
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/origin_surface.py
RENAMED
|
File without changes
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config/policy_surface.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tigrcorn_config-0.3.18.dev1 → tigrcorn_config-0.3.18.dev3}/src/tigrcorn_config.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|