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.
Files changed (80) hide show
  1. tigrcorn_protocols/__init__.py +1 -0
  2. tigrcorn_protocols/_compression.py +219 -0
  3. tigrcorn_protocols/connect.py +107 -0
  4. tigrcorn_protocols/content_coding.py +179 -0
  5. tigrcorn_protocols/custom/__init__.py +3 -0
  6. tigrcorn_protocols/custom/adapters.py +18 -0
  7. tigrcorn_protocols/custom/registry.py +15 -0
  8. tigrcorn_protocols/flow/__init__.py +1 -0
  9. tigrcorn_protocols/flow/backpressure.py +17 -0
  10. tigrcorn_protocols/flow/buffers.py +29 -0
  11. tigrcorn_protocols/flow/credits.py +21 -0
  12. tigrcorn_protocols/flow/keepalive.py +85 -0
  13. tigrcorn_protocols/flow/timeouts.py +17 -0
  14. tigrcorn_protocols/flow/watermarks.py +16 -0
  15. tigrcorn_protocols/http1/__init__.py +16 -0
  16. tigrcorn_protocols/http1/keepalive.py +21 -0
  17. tigrcorn_protocols/http1/parser.py +481 -0
  18. tigrcorn_protocols/http1/serializer.py +198 -0
  19. tigrcorn_protocols/http1/state.py +9 -0
  20. tigrcorn_protocols/http2/__init__.py +16 -0
  21. tigrcorn_protocols/http2/codec.py +266 -0
  22. tigrcorn_protocols/http2/flow.py +35 -0
  23. tigrcorn_protocols/http2/handler.py +1303 -0
  24. tigrcorn_protocols/http2/hpack.py +393 -0
  25. tigrcorn_protocols/http2/state.py +226 -0
  26. tigrcorn_protocols/http2/streams.py +76 -0
  27. tigrcorn_protocols/http2/websocket.py +360 -0
  28. tigrcorn_protocols/http3/__init__.py +82 -0
  29. tigrcorn_protocols/http3/codec.py +148 -0
  30. tigrcorn_protocols/http3/handler/__init__.py +3 -0
  31. tigrcorn_protocols/http3/handler/core.py +1823 -0
  32. tigrcorn_protocols/http3/handler/webtransport.py +184 -0
  33. tigrcorn_protocols/http3/handler.py +3 -0
  34. tigrcorn_protocols/http3/qpack.py +843 -0
  35. tigrcorn_protocols/http3/state.py +129 -0
  36. tigrcorn_protocols/http3/streams.py +657 -0
  37. tigrcorn_protocols/http3/websocket.py +360 -0
  38. tigrcorn_protocols/lifespan/__init__.py +3 -0
  39. tigrcorn_protocols/lifespan/driver.py +83 -0
  40. tigrcorn_protocols/py.typed +1 -0
  41. tigrcorn_protocols/rawframed/__init__.py +5 -0
  42. tigrcorn_protocols/rawframed/codec.py +18 -0
  43. tigrcorn_protocols/rawframed/frames.py +28 -0
  44. tigrcorn_protocols/rawframed/handler.py +72 -0
  45. tigrcorn_protocols/rawframed/state.py +9 -0
  46. tigrcorn_protocols/registry.py +22 -0
  47. tigrcorn_protocols/scheduler/__init__.py +17 -0
  48. tigrcorn_protocols/scheduler/cancellation.py +40 -0
  49. tigrcorn_protocols/scheduler/dispatch.py +27 -0
  50. tigrcorn_protocols/scheduler/fairness.py +21 -0
  51. tigrcorn_protocols/scheduler/policy.py +12 -0
  52. tigrcorn_protocols/scheduler/priorities.py +8 -0
  53. tigrcorn_protocols/scheduler/quotas.py +19 -0
  54. tigrcorn_protocols/scheduler/runtime.py +156 -0
  55. tigrcorn_protocols/scheduler/tasks.py +31 -0
  56. tigrcorn_protocols/sessions/__init__.py +1 -0
  57. tigrcorn_protocols/sessions/base.py +16 -0
  58. tigrcorn_protocols/sessions/connection.py +12 -0
  59. tigrcorn_protocols/sessions/limits.py +12 -0
  60. tigrcorn_protocols/sessions/manager.py +31 -0
  61. tigrcorn_protocols/sessions/metadata.py +10 -0
  62. tigrcorn_protocols/sessions/quic.py +14 -0
  63. tigrcorn_protocols/streams/__init__.py +1 -0
  64. tigrcorn_protocols/streams/base.py +13 -0
  65. tigrcorn_protocols/streams/ids.py +5 -0
  66. tigrcorn_protocols/streams/multiplex.py +6 -0
  67. tigrcorn_protocols/streams/registry.py +22 -0
  68. tigrcorn_protocols/streams/singleplex.py +6 -0
  69. tigrcorn_protocols/websocket/__init__.py +1 -0
  70. tigrcorn_protocols/websocket/codec.py +31 -0
  71. tigrcorn_protocols/websocket/extensions.py +324 -0
  72. tigrcorn_protocols/websocket/frames.py +174 -0
  73. tigrcorn_protocols/websocket/handler.py +462 -0
  74. tigrcorn_protocols/websocket/handshake.py +66 -0
  75. tigrcorn_protocols/websocket/state.py +10 -0
  76. tigrcorn_protocols-0.3.16.dev5.dist-info/METADATA +240 -0
  77. tigrcorn_protocols-0.3.16.dev5.dist-info/RECORD +80 -0
  78. tigrcorn_protocols-0.3.16.dev5.dist-info/WHEEL +5 -0
  79. tigrcorn_protocols-0.3.16.dev5.dist-info/licenses/LICENSE +163 -0
  80. 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
@@ -0,0 +1,3 @@
1
+ from .handler import HTTP3DatagramHandler, HTTP3Session
2
+
3
+ __all__ = ["HTTP3DatagramHandler", "HTTP3Session"]