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,129 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
HTTP3_REQUEST_PHASE_INITIAL = 'initial'
|
|
7
|
+
HTTP3_REQUEST_PHASE_DATA = 'data'
|
|
8
|
+
HTTP3_REQUEST_PHASE_TRAILERS = 'trailers'
|
|
9
|
+
|
|
10
|
+
HTTP3RequestPhase_INITIAL = HTTP3_REQUEST_PHASE_INITIAL
|
|
11
|
+
HTTP3RequestPhase_DATA = HTTP3_REQUEST_PHASE_DATA
|
|
12
|
+
HTTP3RequestPhase_TRAILERS = HTTP3_REQUEST_PHASE_TRAILERS
|
|
13
|
+
|
|
14
|
+
HTTP3_REQUEST_TRANSITION_TABLE: tuple[dict[str, object], ...] = (
|
|
15
|
+
{'from': 'initial', 'event': 'HEADERS', 'to': 'data', 'notes': 'initial request header section decoded successfully'},
|
|
16
|
+
{'from': 'initial', 'event': 'HEADERS (QPACK blocked)', 'to': 'initial', 'notes': 'blocked section is preserved until encoder instructions arrive'},
|
|
17
|
+
{'from': 'initial', 'event': 'DATA', 'to': 'error', 'notes': 'DATA before initial HEADERS is forbidden'},
|
|
18
|
+
{'from': 'data', 'event': 'DATA', 'to': 'data', 'notes': 'body payload accumulates and content-length accounting advances'},
|
|
19
|
+
{'from': 'data', 'event': 'HEADERS', 'to': 'trailers', 'notes': 'trailing header section closes the data phase'},
|
|
20
|
+
{'from': 'trailers', 'event': 'DATA', 'to': 'error', 'notes': 'DATA after trailers is forbidden'},
|
|
21
|
+
{'from': 'initial|data|trailers', 'event': 'FIN + complete parse + validators satisfied', 'to': 'ready', 'notes': 'request is ready only when fin is seen, initial headers exist, no blocked sections remain, and content-length matches'},
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
HTTP3_CONTROL_STREAM_RULES: tuple[dict[str, object], ...] = (
|
|
25
|
+
{'rule': 'single-control-stream', 'error_code': 'H3_STREAM_CREATION_ERROR', 'notes': 'peer must not open more than one control stream'},
|
|
26
|
+
{'rule': 'control-stream-begins-with-settings', 'error_code': 'H3_MISSING_SETTINGS', 'notes': 'first frame on control stream must be SETTINGS'},
|
|
27
|
+
{'rule': 'duplicate-settings-forbidden', 'error_code': 'H3_FRAME_UNEXPECTED', 'notes': 'second SETTINGS frame is rejected'},
|
|
28
|
+
{'rule': 'control-stream-close-is-fatal', 'error_code': 'H3_CLOSED_CRITICAL_STREAM', 'notes': 'control stream cannot be closed'},
|
|
29
|
+
{'rule': 'request-frames-forbidden-on-control-stream', 'error_code': 'H3_FRAME_UNEXPECTED', 'notes': 'HEADERS, DATA, and PUSH_PROMISE are not valid control-stream frames'},
|
|
30
|
+
{'rule': 'goaway-id-must-not-increase', 'error_code': 'H3_ID_ERROR', 'notes': 'successive GOAWAY identifiers are monotonic non-increasing'},
|
|
31
|
+
{'rule': 'server-goaway-id-must-name-client-bidi-stream', 'error_code': 'H3_ID_ERROR', 'notes': 'server GOAWAY identifier must reference a client-initiated bidirectional stream id'},
|
|
32
|
+
{'rule': 'server-cannot-send-max-push-id', 'error_code': 'H3_FRAME_UNEXPECTED', 'notes': 'MAX_PUSH_ID is only valid from the client'},
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
HTTP3_QPACK_ACCOUNTING_RULES: tuple[dict[str, object], ...] = (
|
|
36
|
+
{'rule': 'blocked-header-sections-are-retained', 'notes': 'request body and partial parse state are preserved until QPACK unblocks'},
|
|
37
|
+
{'rule': 'encoder-stream-errors-map-to-encoder-stream-error', 'notes': 'invalid encoder stream payload is surfaced as QPACK_ENCODER_STREAM_ERROR'},
|
|
38
|
+
{'rule': 'decoder-stream-errors-map-to-decoder-stream-error', 'notes': 'invalid decoder stream payload is surfaced as QPACK_DECODER_STREAM_ERROR'},
|
|
39
|
+
{'rule': 'field-section-errors-map-to-decompression-failed', 'notes': 'bad field sections surface as QPACK_DECOMPRESSION_FAILED'},
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def http3_request_transition_table() -> tuple[dict[str, object], ...]:
|
|
44
|
+
return tuple(dict(entry) for entry in HTTP3_REQUEST_TRANSITION_TABLE)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def http3_control_stream_rule_table() -> tuple[dict[str, object], ...]:
|
|
48
|
+
return tuple(dict(entry) for entry in HTTP3_CONTROL_STREAM_RULES)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def http3_qpack_accounting_rule_table() -> tuple[dict[str, object], ...]:
|
|
52
|
+
return tuple(dict(entry) for entry in HTTP3_QPACK_ACCOUNTING_RULES)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass(slots=True)
|
|
56
|
+
class HTTP3BlockedSection:
|
|
57
|
+
kind: str
|
|
58
|
+
payload: bytes
|
|
59
|
+
push_id: int | None = None
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@dataclass(slots=True)
|
|
63
|
+
class HTTP3PushPromiseState:
|
|
64
|
+
push_id: int
|
|
65
|
+
headers: list[tuple[bytes, bytes]]
|
|
66
|
+
request_stream_ids: set[int] = field(default_factory=set)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@dataclass(slots=True)
|
|
70
|
+
class HTTP3RequestState:
|
|
71
|
+
stream_id: int
|
|
72
|
+
headers: list[tuple[bytes, bytes]] = field(default_factory=list)
|
|
73
|
+
informational_headers: list[list[tuple[bytes, bytes]]] = field(default_factory=list)
|
|
74
|
+
trailers: list[tuple[bytes, bytes]] = field(default_factory=list)
|
|
75
|
+
body_parts: list[bytes] = field(default_factory=list)
|
|
76
|
+
ended: bool = False
|
|
77
|
+
parse_buffer: bytearray = field(default_factory=bytearray)
|
|
78
|
+
blocked_header_sections: list[HTTP3BlockedSection] = field(default_factory=list)
|
|
79
|
+
phase: str = HTTP3_REQUEST_PHASE_INITIAL
|
|
80
|
+
received_initial_headers: bool = False
|
|
81
|
+
received_trailers: bool = False
|
|
82
|
+
expected_content_length: int | None = None
|
|
83
|
+
received_content_length: int = 0
|
|
84
|
+
push_promises: dict[int, HTTP3PushPromiseState] = field(default_factory=dict)
|
|
85
|
+
abandoned: bool = False
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def body(self) -> bytes:
|
|
89
|
+
return b''.join(self.body_parts)
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def ready(self) -> bool:
|
|
93
|
+
return (
|
|
94
|
+
not self.abandoned
|
|
95
|
+
and self.ended
|
|
96
|
+
and self.received_initial_headers
|
|
97
|
+
and not self.blocked_header_sections
|
|
98
|
+
and not self.parse_buffer
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@dataclass(slots=True)
|
|
103
|
+
class HTTP3UniStreamState:
|
|
104
|
+
stream_id: int
|
|
105
|
+
stream_type: int | None = None
|
|
106
|
+
parse_buffer: bytearray = field(default_factory=bytearray)
|
|
107
|
+
settings_received: bool = False
|
|
108
|
+
discard_stream: bool = False
|
|
109
|
+
push_id: int | None = None
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@dataclass(slots=True)
|
|
113
|
+
class HTTP3ConnectionState:
|
|
114
|
+
local_settings: dict[int, int] = field(default_factory=dict)
|
|
115
|
+
remote_settings: dict[int, int] = field(default_factory=dict)
|
|
116
|
+
goaway_stream_id: int | None = field(default=None)
|
|
117
|
+
local_goaway_id: int | None = None
|
|
118
|
+
peer_goaway_id: int | None = None
|
|
119
|
+
peer_goaway_direction: str | None = None
|
|
120
|
+
control_stream_opened: bool = False
|
|
121
|
+
remote_control_stream_id: int | None = None
|
|
122
|
+
remote_qpack_encoder_stream_id: int | None = None
|
|
123
|
+
remote_qpack_decoder_stream_id: int | None = None
|
|
124
|
+
remote_push_stream_ids: set[int] = field(default_factory=set)
|
|
125
|
+
uni_streams: dict[int, HTTP3UniStreamState] = field(default_factory=dict)
|
|
126
|
+
promised_pushes: dict[int, HTTP3PushPromiseState] = field(default_factory=dict)
|
|
127
|
+
cancelled_push_ids: set[int] = field(default_factory=set)
|
|
128
|
+
local_max_push_id: int | None = None
|
|
129
|
+
peer_max_push_id: int | None = None
|