tigrcorn-protocols 0.3.16.dev5__py3-none-any.whl
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_protocols/__init__.py +1 -0
- tigrcorn_protocols/_compression.py +219 -0
- tigrcorn_protocols/connect.py +107 -0
- tigrcorn_protocols/content_coding.py +179 -0
- tigrcorn_protocols/custom/__init__.py +3 -0
- tigrcorn_protocols/custom/adapters.py +18 -0
- tigrcorn_protocols/custom/registry.py +15 -0
- tigrcorn_protocols/flow/__init__.py +1 -0
- tigrcorn_protocols/flow/backpressure.py +17 -0
- tigrcorn_protocols/flow/buffers.py +29 -0
- tigrcorn_protocols/flow/credits.py +21 -0
- tigrcorn_protocols/flow/keepalive.py +85 -0
- tigrcorn_protocols/flow/timeouts.py +17 -0
- tigrcorn_protocols/flow/watermarks.py +16 -0
- tigrcorn_protocols/http1/__init__.py +16 -0
- tigrcorn_protocols/http1/keepalive.py +21 -0
- tigrcorn_protocols/http1/parser.py +481 -0
- tigrcorn_protocols/http1/serializer.py +198 -0
- tigrcorn_protocols/http1/state.py +9 -0
- tigrcorn_protocols/http2/__init__.py +16 -0
- tigrcorn_protocols/http2/codec.py +266 -0
- tigrcorn_protocols/http2/flow.py +35 -0
- tigrcorn_protocols/http2/handler.py +1303 -0
- tigrcorn_protocols/http2/hpack.py +393 -0
- tigrcorn_protocols/http2/state.py +226 -0
- tigrcorn_protocols/http2/streams.py +76 -0
- tigrcorn_protocols/http2/websocket.py +360 -0
- tigrcorn_protocols/http3/__init__.py +82 -0
- tigrcorn_protocols/http3/codec.py +148 -0
- tigrcorn_protocols/http3/handler/__init__.py +3 -0
- tigrcorn_protocols/http3/handler/core.py +1823 -0
- tigrcorn_protocols/http3/handler/webtransport.py +184 -0
- tigrcorn_protocols/http3/handler.py +3 -0
- tigrcorn_protocols/http3/qpack.py +843 -0
- tigrcorn_protocols/http3/state.py +129 -0
- tigrcorn_protocols/http3/streams.py +657 -0
- tigrcorn_protocols/http3/websocket.py +360 -0
- tigrcorn_protocols/lifespan/__init__.py +3 -0
- tigrcorn_protocols/lifespan/driver.py +83 -0
- tigrcorn_protocols/py.typed +1 -0
- tigrcorn_protocols/rawframed/__init__.py +5 -0
- tigrcorn_protocols/rawframed/codec.py +18 -0
- tigrcorn_protocols/rawframed/frames.py +28 -0
- tigrcorn_protocols/rawframed/handler.py +72 -0
- tigrcorn_protocols/rawframed/state.py +9 -0
- tigrcorn_protocols/registry.py +22 -0
- tigrcorn_protocols/scheduler/__init__.py +17 -0
- tigrcorn_protocols/scheduler/cancellation.py +40 -0
- tigrcorn_protocols/scheduler/dispatch.py +27 -0
- tigrcorn_protocols/scheduler/fairness.py +21 -0
- tigrcorn_protocols/scheduler/policy.py +12 -0
- tigrcorn_protocols/scheduler/priorities.py +8 -0
- tigrcorn_protocols/scheduler/quotas.py +19 -0
- tigrcorn_protocols/scheduler/runtime.py +156 -0
- tigrcorn_protocols/scheduler/tasks.py +31 -0
- tigrcorn_protocols/sessions/__init__.py +1 -0
- tigrcorn_protocols/sessions/base.py +16 -0
- tigrcorn_protocols/sessions/connection.py +12 -0
- tigrcorn_protocols/sessions/limits.py +12 -0
- tigrcorn_protocols/sessions/manager.py +31 -0
- tigrcorn_protocols/sessions/metadata.py +10 -0
- tigrcorn_protocols/sessions/quic.py +14 -0
- tigrcorn_protocols/streams/__init__.py +1 -0
- tigrcorn_protocols/streams/base.py +13 -0
- tigrcorn_protocols/streams/ids.py +5 -0
- tigrcorn_protocols/streams/multiplex.py +6 -0
- tigrcorn_protocols/streams/registry.py +22 -0
- tigrcorn_protocols/streams/singleplex.py +6 -0
- tigrcorn_protocols/websocket/__init__.py +1 -0
- tigrcorn_protocols/websocket/codec.py +31 -0
- tigrcorn_protocols/websocket/extensions.py +324 -0
- tigrcorn_protocols/websocket/frames.py +174 -0
- tigrcorn_protocols/websocket/handler.py +462 -0
- tigrcorn_protocols/websocket/handshake.py +66 -0
- tigrcorn_protocols/websocket/state.py +10 -0
- tigrcorn_protocols-0.3.16.dev5.dist-info/METADATA +240 -0
- tigrcorn_protocols-0.3.16.dev5.dist-info/RECORD +80 -0
- tigrcorn_protocols-0.3.16.dev5.dist-info/WHEEL +5 -0
- tigrcorn_protocols-0.3.16.dev5.dist-info/licenses/LICENSE +163 -0
- tigrcorn_protocols-0.3.16.dev5.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from contextlib import suppress
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from tigrcorn_asgi.receive import QueueReceive
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from tigrcorn_protocols.http1.parser import ParsedRequest
|
|
11
|
+
from tigrcorn_transports.udp.endpoint import UDPEndpoint
|
|
12
|
+
|
|
13
|
+
from .core import HTTP3DatagramHandler, HTTP3Session
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class _HTTP3WebTransportSession:
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
*,
|
|
20
|
+
handler: HTTP3DatagramHandler,
|
|
21
|
+
session: HTTP3Session,
|
|
22
|
+
stream_id: int,
|
|
23
|
+
request: ParsedRequest,
|
|
24
|
+
client: tuple[str, int] | None,
|
|
25
|
+
server: tuple[str, int] | tuple[str, None] | None,
|
|
26
|
+
scheme: str,
|
|
27
|
+
endpoint: UDPEndpoint,
|
|
28
|
+
work_lease: object | None = None,
|
|
29
|
+
) -> None:
|
|
30
|
+
self.handler = handler
|
|
31
|
+
self.session = session
|
|
32
|
+
self.stream_id = stream_id
|
|
33
|
+
self.request = request
|
|
34
|
+
self.client = client
|
|
35
|
+
self.server = server
|
|
36
|
+
self.scheme = scheme
|
|
37
|
+
self.endpoint = endpoint
|
|
38
|
+
self.work_lease = work_lease
|
|
39
|
+
self.session_id = f"h3-{stream_id}"
|
|
40
|
+
self.receive = QueueReceive(max_size=handler.config.webtransport.max_streams)
|
|
41
|
+
self.task: asyncio.Task[None] | None = None
|
|
42
|
+
self.accepted = False
|
|
43
|
+
self.closed = False
|
|
44
|
+
self.connect_stream_ended = False
|
|
45
|
+
|
|
46
|
+
async def start(self) -> None:
|
|
47
|
+
scope = {
|
|
48
|
+
"type": "webtransport",
|
|
49
|
+
"asgi": {"version": "3.0", "spec_version": "2.5"},
|
|
50
|
+
"http_version": "3",
|
|
51
|
+
"scheme": self.scheme,
|
|
52
|
+
"path": self.request.path,
|
|
53
|
+
"raw_path": self.request.raw_path,
|
|
54
|
+
"query_string": self.request.query_string,
|
|
55
|
+
"headers": self.request.headers,
|
|
56
|
+
"client": self.client,
|
|
57
|
+
"server": self.server,
|
|
58
|
+
"session_id": self.session_id,
|
|
59
|
+
"extensions": {
|
|
60
|
+
"h3": {"datagram": True, "stream_id": self.stream_id},
|
|
61
|
+
"quic": {"connection_id": self.session.quic.local_cid.hex()},
|
|
62
|
+
"tigrcorn.security": self.handler._webtransport_security_extension(self.session),
|
|
63
|
+
"tigrcorn.transport": self.handler._webtransport_transport_extension(self.session),
|
|
64
|
+
"tigrcorn.unit": {"session_id": self.session_id},
|
|
65
|
+
"tigrcorn.webtransport": {"max_datagram_size": self.handler._webtransport_max_datagram_size()},
|
|
66
|
+
},
|
|
67
|
+
}
|
|
68
|
+
await self.receive.put({"type": "webtransport.connect", "session_id": self.session_id})
|
|
69
|
+
self.task = asyncio.create_task(
|
|
70
|
+
self._start_webtransport_app(scope),
|
|
71
|
+
name=f"tigrcorn-h3-webtransport-{self.stream_id}",
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
async def _start_webtransport_app(self, scope: dict) -> None:
|
|
75
|
+
try:
|
|
76
|
+
await self.handler.app(scope, self.receive, self._send)
|
|
77
|
+
finally:
|
|
78
|
+
if not self.closed:
|
|
79
|
+
self.closed = True
|
|
80
|
+
with suppress(Exception):
|
|
81
|
+
await self.handler._send_webtransport_stream_data(
|
|
82
|
+
self.session,
|
|
83
|
+
self.stream_id,
|
|
84
|
+
b"",
|
|
85
|
+
end_stream=True,
|
|
86
|
+
endpoint=self.endpoint,
|
|
87
|
+
)
|
|
88
|
+
self.handler._on_webtransport_stream_closed(self.session, self.stream_id)
|
|
89
|
+
|
|
90
|
+
async def _send(self, message: dict) -> None:
|
|
91
|
+
typ = message.get("type")
|
|
92
|
+
if typ == "webtransport.accept":
|
|
93
|
+
if self.accepted:
|
|
94
|
+
raise RuntimeError("webtransport.accept sent more than once")
|
|
95
|
+
self.accepted = True
|
|
96
|
+
return
|
|
97
|
+
if typ == "webtransport.stream.send":
|
|
98
|
+
if not self.accepted:
|
|
99
|
+
raise RuntimeError("webtransport.stream.send before webtransport.accept")
|
|
100
|
+
target_stream_id = int(message.get("stream_id", self.stream_id))
|
|
101
|
+
await self.handler._send_webtransport_stream_data(
|
|
102
|
+
self.session,
|
|
103
|
+
target_stream_id,
|
|
104
|
+
bytes(message.get("data", b"")),
|
|
105
|
+
end_stream=not bool(message.get("more", False)),
|
|
106
|
+
endpoint=self.endpoint,
|
|
107
|
+
)
|
|
108
|
+
return
|
|
109
|
+
if typ == "webtransport.datagram.send":
|
|
110
|
+
if not self.accepted:
|
|
111
|
+
raise RuntimeError("webtransport.datagram.send before webtransport.accept")
|
|
112
|
+
await self.handler._send_webtransport_datagram(
|
|
113
|
+
self.session,
|
|
114
|
+
self.stream_id,
|
|
115
|
+
bytes(message.get("data", b"")),
|
|
116
|
+
datagram_id=str(message.get("datagram_id", "datagram")),
|
|
117
|
+
endpoint=self.endpoint,
|
|
118
|
+
)
|
|
119
|
+
return
|
|
120
|
+
if typ in {"webtransport.close", "webtransport.disconnect"}:
|
|
121
|
+
self.closed = True
|
|
122
|
+
await self.handler._send_webtransport_stream_data(
|
|
123
|
+
self.session,
|
|
124
|
+
self.stream_id,
|
|
125
|
+
b"",
|
|
126
|
+
end_stream=True,
|
|
127
|
+
endpoint=self.endpoint,
|
|
128
|
+
)
|
|
129
|
+
return
|
|
130
|
+
raise RuntimeError(f"unexpected webtransport send message: {typ!r}")
|
|
131
|
+
|
|
132
|
+
async def feed_stream_data(
|
|
133
|
+
self,
|
|
134
|
+
data: bytes,
|
|
135
|
+
*,
|
|
136
|
+
end_stream: bool = False,
|
|
137
|
+
disconnect_on_end: bool = True,
|
|
138
|
+
stream_id: int | None = None,
|
|
139
|
+
) -> None:
|
|
140
|
+
if self.closed:
|
|
141
|
+
return
|
|
142
|
+
event_stream_id = str(self.stream_id if stream_id is None else stream_id)
|
|
143
|
+
if data:
|
|
144
|
+
await self.receive.put(
|
|
145
|
+
{
|
|
146
|
+
"type": "webtransport.stream.receive",
|
|
147
|
+
"session_id": self.session_id,
|
|
148
|
+
"stream_id": event_stream_id,
|
|
149
|
+
"data": data,
|
|
150
|
+
"more": not end_stream,
|
|
151
|
+
}
|
|
152
|
+
)
|
|
153
|
+
if end_stream and disconnect_on_end and not self.closed:
|
|
154
|
+
self.closed = True
|
|
155
|
+
await self.receive.put({"type": "webtransport.disconnect", "session_id": self.session_id, "code": 0, "reason": ""})
|
|
156
|
+
|
|
157
|
+
async def feed_connect_stream_data(self, data: bytes, *, end_stream: bool = False) -> None:
|
|
158
|
+
if self.closed:
|
|
159
|
+
return
|
|
160
|
+
await self.feed_stream_data(data, end_stream=end_stream, disconnect_on_end=False)
|
|
161
|
+
if end_stream:
|
|
162
|
+
self.connect_stream_ended = True
|
|
163
|
+
|
|
164
|
+
def note_connect_stream_stopped(self) -> None:
|
|
165
|
+
self.connect_stream_ended = True
|
|
166
|
+
|
|
167
|
+
async def feed_datagram(self, datagram_id: str, data: bytes) -> None:
|
|
168
|
+
if self.closed:
|
|
169
|
+
return
|
|
170
|
+
await self.receive.put(
|
|
171
|
+
{
|
|
172
|
+
"type": "webtransport.datagram.receive",
|
|
173
|
+
"session_id": self.session_id,
|
|
174
|
+
"datagram_id": datagram_id,
|
|
175
|
+
"data": data,
|
|
176
|
+
}
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
async def abort(self) -> None:
|
|
180
|
+
self.closed = True
|
|
181
|
+
if self.task is not None:
|
|
182
|
+
self.task.cancel()
|
|
183
|
+
with suppress(asyncio.CancelledError):
|
|
184
|
+
await self.task
|