tigrcorn-protocols 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.
Files changed (145) hide show
  1. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/PKG-INFO +7 -7
  2. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/README.md +1 -1
  3. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/pyproject.toml +6 -6
  4. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/handler/connect.py +8 -0
  5. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/handler/core.py +6 -0
  6. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/handler/frames.py +1 -0
  7. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/handler/imports.py +1 -0
  8. tigrcorn_protocols-0.3.18.dev3/src/tigrcorn_protocols/http2/handler/inventory.py +56 -0
  9. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/handler/streams.py +12 -0
  10. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/handler/websocket_support.py +10 -1
  11. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/codec.py +2 -0
  12. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/handler/connect.py +15 -2
  13. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/handler/core.py +10 -1
  14. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/handler/custom.py +1 -1
  15. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/handler/imports.py +6 -0
  16. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/handler/lifecycle.py +77 -1
  17. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/handler/outbound.py +113 -19
  18. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/handler/packet.py +118 -21
  19. tigrcorn_protocols-0.3.18.dev3/src/tigrcorn_protocols/http3/handler/priority_lock.py +107 -0
  20. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/handler/requests.py +15 -2
  21. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/handler/responses.py +5 -5
  22. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/handler/session.py +16 -1
  23. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/handler/websocket_runtime.py +32 -3
  24. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/handler/webtransport.py +232 -74
  25. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/handler/webtransport_datagrams.py +1 -1
  26. tigrcorn_protocols-0.3.18.dev3/src/tigrcorn_protocols/http3/handler/webtransport_send.py +166 -0
  27. tigrcorn_protocols-0.3.18.dev3/src/tigrcorn_protocols/http3/handler/webtransport_stream_flow.py +104 -0
  28. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/handler/webtransport_streams.py +100 -5
  29. tigrcorn_protocols-0.3.18.dev3/src/tigrcorn_protocols/http3/handler/webtransport_support.py +256 -0
  30. tigrcorn_protocols-0.3.18.dev3/src/tigrcorn_protocols/sessions/__init__.py +27 -0
  31. tigrcorn_protocols-0.3.18.dev3/src/tigrcorn_protocols/sessions/inventory.py +317 -0
  32. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/webtransport/__init__.py +44 -0
  33. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/webtransport/governance.py +5 -0
  34. tigrcorn_protocols-0.3.18.dev3/src/tigrcorn_protocols/webtransport/negotiation.py +107 -0
  35. tigrcorn_protocols-0.3.18.dev3/src/tigrcorn_protocols/webtransport/profiles.py +179 -0
  36. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols.egg-info/PKG-INFO +7 -7
  37. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols.egg-info/SOURCES.txt +7 -0
  38. tigrcorn_protocols-0.3.18.dev3/src/tigrcorn_protocols.egg-info/requires.txt +5 -0
  39. tigrcorn_protocols-0.3.18.dev1/src/tigrcorn_protocols/http3/handler/webtransport_support.py +0 -101
  40. tigrcorn_protocols-0.3.18.dev1/src/tigrcorn_protocols/sessions/__init__.py +0 -1
  41. tigrcorn_protocols-0.3.18.dev1/src/tigrcorn_protocols.egg-info/requires.txt +0 -5
  42. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/LICENSE +0 -0
  43. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/setup.cfg +0 -0
  44. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/__init__.py +0 -0
  45. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/_compression.py +0 -0
  46. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/client_session_coverage/__init__.py +0 -0
  47. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/client_session_coverage/matrix.py +0 -0
  48. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/client_session_coverage/models.py +0 -0
  49. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/client_session_coverage/robustness.py +0 -0
  50. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/client_session_coverage/topology.py +0 -0
  51. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/client_session_coverage/validation.py +0 -0
  52. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/connect.py +0 -0
  53. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/content_coding.py +0 -0
  54. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/custom/__init__.py +0 -0
  55. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/custom/adapters.py +0 -0
  56. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/custom/registry.py +0 -0
  57. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/flow/__init__.py +0 -0
  58. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/flow/backpressure.py +0 -0
  59. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/flow/buffers.py +0 -0
  60. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/flow/credits.py +0 -0
  61. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/flow/keepalive.py +0 -0
  62. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/flow/timeouts.py +0 -0
  63. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/flow/watermarks.py +0 -0
  64. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http1/__init__.py +0 -0
  65. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http1/keepalive.py +0 -0
  66. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http1/parser/__init__.py +0 -0
  67. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http1/parser/body.py +0 -0
  68. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http1/parser/core.py +0 -0
  69. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http1/parser/head.py +0 -0
  70. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http1/parser/models.py +0 -0
  71. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http1/parser/target.py +0 -0
  72. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http1/parser/validation.py +0 -0
  73. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http1/serializer.py +0 -0
  74. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http1/state.py +0 -0
  75. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/__init__.py +0 -0
  76. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/codec.py +0 -0
  77. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/flow.py +0 -0
  78. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/handler/__init__.py +0 -0
  79. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/handler/flow_control.py +0 -0
  80. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/handler/headers.py +0 -0
  81. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/handler/io.py +0 -0
  82. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/handler/requests.py +0 -0
  83. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/handler/responses.py +0 -0
  84. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/hpack.py +0 -0
  85. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/state.py +0 -0
  86. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/streams.py +0 -0
  87. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http2/websocket.py +0 -0
  88. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/__init__.py +0 -0
  89. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/handler/__init__.py +0 -0
  90. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/qpack/__init__.py +0 -0
  91. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/qpack/decoder.py +0 -0
  92. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/qpack/encoder.py +0 -0
  93. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/qpack/model.py +0 -0
  94. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/qpack/static_table.py +0 -0
  95. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/qpack/wire.py +0 -0
  96. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/state.py +0 -0
  97. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/streams/__init__.py +0 -0
  98. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/streams/connection.py +0 -0
  99. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/streams/constants.py +0 -0
  100. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/streams/request.py +0 -0
  101. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/http3/websocket.py +0 -0
  102. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/lifespan/__init__.py +0 -0
  103. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/lifespan/driver.py +0 -0
  104. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/py.typed +0 -0
  105. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/rawframed/__init__.py +0 -0
  106. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/rawframed/codec.py +0 -0
  107. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/rawframed/frames.py +0 -0
  108. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/rawframed/handler.py +0 -0
  109. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/rawframed/state.py +0 -0
  110. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/registry.py +0 -0
  111. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/resume.py +0 -0
  112. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/scheduler/__init__.py +0 -0
  113. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/scheduler/cancellation.py +0 -0
  114. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/scheduler/dispatch.py +0 -0
  115. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/scheduler/fairness.py +0 -0
  116. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/scheduler/policy.py +0 -0
  117. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/scheduler/priorities.py +0 -0
  118. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/scheduler/quotas.py +0 -0
  119. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/scheduler/runtime.py +0 -0
  120. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/scheduler/tasks.py +0 -0
  121. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/sessions/base.py +0 -0
  122. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/sessions/connection.py +0 -0
  123. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/sessions/limits.py +0 -0
  124. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/sessions/manager.py +0 -0
  125. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/sessions/metadata.py +0 -0
  126. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/sessions/quic.py +0 -0
  127. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/streams/__init__.py +0 -0
  128. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/streams/base.py +0 -0
  129. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/streams/ids.py +0 -0
  130. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/streams/multiplex.py +0 -0
  131. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/streams/registry.py +0 -0
  132. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/streams/singleplex.py +0 -0
  133. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/websocket/__init__.py +0 -0
  134. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/websocket/codec.py +0 -0
  135. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/websocket/extensions.py +0 -0
  136. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/websocket/frames.py +0 -0
  137. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/websocket/handler/__init__.py +0 -0
  138. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/websocket/handler/app_send.py +0 -0
  139. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/websocket/handler/core.py +0 -0
  140. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/websocket/handler/errors.py +0 -0
  141. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/websocket/handshake.py +0 -0
  142. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/websocket/state.py +0 -0
  143. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols/webtransport/wire.py +0 -0
  144. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols.egg-info/dependency_links.txt +0 -0
  145. {tigrcorn_protocols-0.3.18.dev1 → tigrcorn_protocols-0.3.18.dev3}/src/tigrcorn_protocols.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tigrcorn-protocols
3
- Version: 0.3.18.dev1
3
+ Version: 0.3.18.dev3
4
4
  Summary: Protocol handlers for Tigrcorn HTTP/1.1, HTTP/2, HTTP/3, QUIC, WebSocket, WebTransport, lifespan, and ASGI3 traffic.
5
5
  Author-email: Jacob Stewart <jacob@swarmauri.com>
6
6
  License: Apache License
@@ -187,11 +187,11 @@ Classifier: Typing :: Typed
187
187
  Requires-Python: <3.15,>=3.10
188
188
  Description-Content-Type: text/markdown
189
189
  License-File: LICENSE
190
- Requires-Dist: tigrcorn-core==0.3.18.dev1
191
- Requires-Dist: tigrcorn-config==0.3.18.dev1
192
- Requires-Dist: tigrcorn-asgi==0.3.18.dev1
193
- Requires-Dist: tigrcorn-http==0.3.18.dev1
194
- Requires-Dist: tigrcorn-transports==0.3.18.dev1
190
+ Requires-Dist: tigrcorn-core==0.3.18.dev3
191
+ Requires-Dist: tigrcorn-config==0.3.18.dev3
192
+ Requires-Dist: tigrcorn-asgi==0.3.18.dev3
193
+ Requires-Dist: tigrcorn-http==0.3.18.dev3
194
+ Requires-Dist: tigrcorn-transports==0.3.18.dev3
195
195
  Dynamic: license-file
196
196
 
197
197
  <div align="center">
@@ -284,7 +284,7 @@ The package exposes its supported public surface through the <code>tigrcorn_prot
284
284
 
285
285
  ## Package Graph
286
286
 
287
- [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/)
287
+ [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/)
288
288
 
289
289
  ## Best Practices
290
290
 
@@ -88,7 +88,7 @@ The package exposes its supported public surface through the <code>tigrcorn_prot
88
88
 
89
89
  ## Package Graph
90
90
 
91
- [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/)
91
+ [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/)
92
92
 
93
93
  ## Best Practices
94
94
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tigrcorn-protocols"
7
- version = "0.3.18.dev1"
7
+ version = "0.3.18.dev3"
8
8
  description = "Protocol handlers for Tigrcorn HTTP/1.1, HTTP/2, HTTP/3, QUIC, WebSocket, WebTransport, lifespan, and ASGI3 traffic."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10,<3.15"
@@ -30,11 +30,11 @@ classifiers = [
30
30
  "Typing :: Typed",
31
31
  ]
32
32
  dependencies = [
33
- "tigrcorn-core==0.3.18.dev1",
34
- "tigrcorn-config==0.3.18.dev1",
35
- "tigrcorn-asgi==0.3.18.dev1",
36
- "tigrcorn-http==0.3.18.dev1",
37
- "tigrcorn-transports==0.3.18.dev1",
33
+ "tigrcorn-core==0.3.18.dev3",
34
+ "tigrcorn-config==0.3.18.dev3",
35
+ "tigrcorn-asgi==0.3.18.dev3",
36
+ "tigrcorn-http==0.3.18.dev3",
37
+ "tigrcorn-transports==0.3.18.dev3",
38
38
  ]
39
39
 
40
40
  [tool.setuptools]
@@ -67,6 +67,7 @@ class _HTTP2ConnectTunnel:
67
67
  if self.work_lease is not None:
68
68
  self.work_lease.release()
69
69
  await close_tcp_writer(self.upstream_writer)
70
+ self.handler._close_inventory_session(self.stream_id, reason="connect-complete")
70
71
  self.handler._finalize_stream_if_complete(self.stream_id)
71
72
 
72
73
  async def _relay_upstream_to_client(self) -> None:
@@ -108,6 +109,7 @@ class HTTP2ConnectMixin:
108
109
  await self._write_raw(serialize_rst_stream(stream_id, H2_CONNECT_ERROR))
109
110
  state.mark_reset_sent()
110
111
  self._cancel_stream(stream_id)
112
+ self._close_inventory_session(stream_id, reason="connect-reset")
111
113
  self.streams.close(stream_id)
112
114
  self._maybe_finish_after_goaway()
113
115
 
@@ -163,11 +165,17 @@ class HTTP2ConnectMixin:
163
165
  work_lease=self.stream_work_leases.get(stream_id),
164
166
  )
165
167
  state.connect_tunnel = tunnel
168
+ self._open_inventory_session(
169
+ stream_id,
170
+ kind="connect-tunnel",
171
+ metadata={"authority": request.target},
172
+ )
166
173
  self.state.last_stream_id = max(self.state.last_stream_id, stream_id)
167
174
  try:
168
175
  await tunnel.start()
169
176
  except Exception:
170
177
  state.connect_tunnel = None
178
+ self._close_inventory_session(stream_id, reason="connect-start-failed")
171
179
  await close_tcp_writer(upstream_writer)
172
180
  raise
173
181
  if state.end_stream_received:
@@ -5,6 +5,7 @@ from .connect import HTTP2ConnectMixin
5
5
  from .flow_control import HTTP2FlowControlMixin
6
6
  from .frames import HTTP2FrameDispatchMixin
7
7
  from .headers import HTTP2HeadersMixin
8
+ from .inventory import HTTP2InventoryMixin
8
9
  from .io import HTTP2IOMixin
9
10
  from .requests import HTTP2RequestsMixin
10
11
  from .responses import HTTP2ResponsesMixin
@@ -22,6 +23,7 @@ class HTTP2ConnectionHandler(
22
23
  HTTP2ResponsesMixin,
23
24
  HTTP2ConnectMixin,
24
25
  HTTP2WebSocketSupportMixin,
26
+ HTTP2InventoryMixin,
25
27
  ):
26
28
  def __init__(
27
29
  self,
@@ -38,6 +40,8 @@ class HTTP2ConnectionHandler(
38
40
  scheme: str,
39
41
  prebuffer: bytes = b"",
40
42
  scope_extensions: dict | None = None,
43
+ connection_id: str | None = None,
44
+ connection_inventory: RuntimeConnectionInventory | None = None,
41
45
  ) -> None:
42
46
  self.app = app
43
47
  self.config = config
@@ -51,6 +55,8 @@ class HTTP2ConnectionHandler(
51
55
  self.scheme = scheme
52
56
  self.prebuffer = prebuffer
53
57
  self.scope_extensions = dict(scope_extensions or {})
58
+ self.connection_id = connection_id
59
+ self.connection_inventory = connection_inventory
54
60
  self.state = H2ConnectionState()
55
61
  self.state.local_settings[SETTING_MAX_CONCURRENT_STREAMS] = self.config.http.http2_max_concurrent_streams
56
62
  self.state.local_settings[SETTING_MAX_HEADER_LIST_SIZE] = self.config.http.http2_max_headers_size
@@ -116,6 +116,7 @@ class HTTP2FrameDispatchMixin:
116
116
  await state.connect_tunnel.abort()
117
117
  self._cancel_stream(frame.stream_id)
118
118
  state.mark_reset_received()
119
+ self._close_inventory_session(frame.stream_id, reason="rst-stream")
119
120
  self.streams.close(frame.stream_id)
120
121
  self._notify_waiter(frame.stream_id)
121
122
  self._maybe_finish_after_goaway()
@@ -63,6 +63,7 @@ from tigrcorn_protocols.scheduler.runtime import ProductionScheduler, WorkLease
63
63
  from tigrcorn_protocols.http2.streams import H2StreamRegistry
64
64
  from tigrcorn_protocols.connect import close_tcp_writer, half_close_tcp_writer, is_connect_allowed, parse_connect_authority
65
65
  from tigrcorn_protocols.http2.websocket import H2WebSocketSession
66
+ from tigrcorn_protocols.sessions import RuntimeConnectionInventory
66
67
  from tigrcorn_core.types import ASGIApp
67
68
  from tigrcorn_core.utils.authority import authority_allowed
68
69
  from tigrcorn_core.utils.headers import apply_response_header_policy, sanitize_early_hints_headers, strip_connection_specific_headers
@@ -0,0 +1,56 @@
1
+ from __future__ import annotations
2
+
3
+ from .imports import *
4
+
5
+
6
+ class HTTP2InventoryMixin:
7
+ def _inventory_session_id(self, stream_id: int) -> str | None:
8
+ if self.connection_inventory is None or self.connection_id is None:
9
+ return None
10
+ return f"h2:{self.connection_id}:{stream_id}"
11
+
12
+ def _open_inventory_session(
13
+ self,
14
+ stream_id: int,
15
+ *,
16
+ kind: str,
17
+ metadata: dict | None = None,
18
+ ) -> str | None:
19
+ session_id = self._inventory_session_id(stream_id)
20
+ if session_id is None:
21
+ return None
22
+ payload = {"protocol": "http2", "stream_id": stream_id}
23
+ payload.update(metadata or {})
24
+ self.connection_inventory.open_session(
25
+ session_id,
26
+ connection_id=self.connection_id,
27
+ kind=kind,
28
+ stream_ids=(str(stream_id),),
29
+ metadata=payload,
30
+ )
31
+ self.connection_inventory.increment_connection_counter(self.connection_id, "streams")
32
+ if kind == "http-request":
33
+ self.connection_inventory.increment_connection_counter(self.connection_id, "requests")
34
+ elif kind == "websocket":
35
+ self.connection_inventory.increment_connection_counter(self.connection_id, "websockets")
36
+ elif kind == "connect-tunnel":
37
+ self.connection_inventory.increment_connection_counter(self.connection_id, "connect_tunnels")
38
+ return session_id
39
+
40
+ def _update_inventory_session(
41
+ self,
42
+ stream_id: int,
43
+ *,
44
+ state: str | None = None,
45
+ metadata: dict | None = None,
46
+ ) -> None:
47
+ session_id = self._inventory_session_id(stream_id)
48
+ if session_id is None:
49
+ return
50
+ self.connection_inventory.update_session(session_id, state=state, metadata=metadata)
51
+
52
+ def _close_inventory_session(self, stream_id: int, *, reason: str | None = None) -> None:
53
+ session_id = self._inventory_session_id(stream_id)
54
+ if session_id is None:
55
+ return
56
+ self.connection_inventory.close_session(session_id, reason=reason)
@@ -51,6 +51,12 @@ class HTTP2StreamsMixin:
51
51
  await self._start_connect_tunnel(stream_id)
52
52
  return
53
53
  self.state.last_stream_id = max(self.state.last_stream_id, stream_id)
54
+ request = self._build_request(state)
55
+ self._open_inventory_session(
56
+ stream_id,
57
+ kind="http-request",
58
+ metadata={"method": request.method, "path": request.path},
59
+ )
54
60
  task = asyncio.create_task(self._run_stream(stream_id), name=f"tigrcorn-h2-stream-{stream_id}")
55
61
  self.stream_tasks[stream_id] = task
56
62
 
@@ -66,6 +72,7 @@ class HTTP2StreamsMixin:
66
72
  if state is not None:
67
73
  state.websocket_session = None
68
74
  self._release_stream_work_lease(stream_id)
75
+ self._close_inventory_session(stream_id, reason="websocket-complete")
69
76
  self._finalize_stream_if_complete(stream_id)
70
77
 
71
78
 
@@ -87,6 +94,7 @@ class HTTP2StreamsMixin:
87
94
  if state is None or state.websocket_session is not None or state.connect_tunnel is not None:
88
95
  return
89
96
  if state.local_closed and state.end_stream_received:
97
+ self._close_inventory_session(stream_id, reason="stream-complete")
90
98
  self._release_stream_work_lease(stream_id)
91
99
  self._cancel_stream(stream_id)
92
100
  self.streams.close(stream_id)
@@ -125,6 +133,7 @@ class HTTP2StreamsMixin:
125
133
  self._finalize_stream_if_complete(stream_id)
126
134
  self._maybe_finish_after_goaway()
127
135
  finally:
136
+ self._close_inventory_session(stream_id, reason="request-complete")
128
137
  self._release_stream_work_lease(stream_id)
129
138
 
130
139
 
@@ -141,14 +150,17 @@ class HTTP2StreamsMixin:
141
150
  if state.websocket_session is not None:
142
151
  with suppress(Exception):
143
152
  await state.websocket_session.abort()
153
+ self._close_inventory_session(state.stream_id, reason="shutdown")
144
154
  if state.connect_tunnel is not None:
145
155
  with suppress(Exception):
146
156
  await state.connect_tunnel.abort()
157
+ self._close_inventory_session(state.stream_id, reason="shutdown")
147
158
  for stream_id, task in list(self.stream_tasks.items()):
148
159
  task.cancel()
149
160
  with suppress(asyncio.CancelledError):
150
161
  await task
151
162
  self.stream_tasks.pop(stream_id, None)
163
+ self._close_inventory_session(stream_id, reason="shutdown")
152
164
  if not self.state.local_goaway_sent:
153
165
  self.state.local_goaway_sent = True
154
166
  self.state.local_goaway_last_stream_id = self.state.last_stream_id
@@ -41,6 +41,15 @@ class HTTP2WebSocketSupportMixin:
41
41
  on_close=lambda stream_id=stream_id: self._on_websocket_stream_closed(stream_id),
42
42
  )
43
43
  state.websocket_session = session
44
+ self._open_inventory_session(
45
+ stream_id,
46
+ kind="websocket",
47
+ metadata={"path": request.path},
48
+ )
44
49
  self.state.last_stream_id = max(self.state.last_stream_id, stream_id)
45
- await session.start()
50
+ try:
51
+ await session.start()
52
+ except Exception:
53
+ self._close_inventory_session(stream_id, reason="websocket-start-failed")
54
+ raise
46
55
 
@@ -25,6 +25,7 @@ SETTING_ENABLE_CONNECT_PROTOCOL = 0x08
25
25
  SETTING_H3_DATAGRAM = 0x33
26
26
  SETTING_ENABLE_WEBTRANSPORT = 0x2B603742
27
27
  SETTING_WT_MAX_SESSIONS = 0x14E9CD29
28
+ SETTING_WT_ENABLED = 0x2C7CF000
28
29
 
29
30
  H3_DATAGRAM_ERROR = 0x33
30
31
  H3_NO_ERROR = 0x0100
@@ -69,6 +70,7 @@ HTTP3_IANA_SETTINGS = {
69
70
  "SETTINGS_ENABLE_CONNECT_PROTOCOL": SETTING_ENABLE_CONNECT_PROTOCOL,
70
71
  "SETTINGS_H3_DATAGRAM": SETTING_H3_DATAGRAM,
71
72
  "SETTINGS_WT_MAX_SESSIONS": SETTING_WT_MAX_SESSIONS,
73
+ "SETTINGS_WT_ENABLED": SETTING_WT_ENABLED,
72
74
  }
73
75
 
74
76
  HTTP3_IANA_ERROR_CODES = {
@@ -70,6 +70,11 @@ class _HTTP3ConnectTunnel:
70
70
  with suppress(asyncio.CancelledError):
71
71
  await self.relay_task
72
72
  self.session.connect_tunnels.pop(self.stream_id, None)
73
+ if self.handler.connection_inventory is not None:
74
+ self.handler.connection_inventory.close_session(
75
+ f"{self.handler._connection_id_for_session(self.session)}:connect:{self.stream_id}",
76
+ reason='connect-abort',
77
+ )
73
78
  lease = self.session.stream_work_leases.pop(self.stream_id, None)
74
79
  if lease is not None:
75
80
  lease.release()
@@ -128,7 +133,7 @@ class HTTP3ConnectMixin:
128
133
  already_locked: bool = False,
129
134
  ) -> None:
130
135
  if not already_locked:
131
- async with self._lock:
136
+ async with session.lock:
132
137
  await self._send_http3_tunnel_data(
133
138
  session,
134
139
  stream_id,
@@ -154,7 +159,7 @@ class HTTP3ConnectMixin:
154
159
  already_locked: bool = False,
155
160
  ) -> None:
156
161
  if not already_locked:
157
- async with self._lock:
162
+ async with session.lock:
158
163
  await self._reset_http3_tunnel_stream(
159
164
  session,
160
165
  stream_id,
@@ -252,6 +257,14 @@ class HTTP3ConnectMixin:
252
257
  work_lease=session.stream_work_leases.get(stream_id),
253
258
  )
254
259
  session.connect_tunnels[stream_id] = tunnel
260
+ if self.connection_inventory is not None:
261
+ self.connection_inventory.open_session(
262
+ f"{self._connection_id_for_session(session)}:connect:{stream_id}",
263
+ connection_id=self._connection_id_for_session(session),
264
+ kind='connect-tunnel',
265
+ stream_ids=(str(stream_id),),
266
+ metadata={'authority': authority, 'protocol': 'http3'},
267
+ )
255
268
  tunnel.start()
256
269
  self.access_logger.log_http(session.addr, 'CONNECT', authority, 200, 'HTTP/3')
257
270
  return self._build_http3_response_datagrams_locked(session, stream_id, 200, [], b'', end_stream=False)
@@ -6,16 +6,19 @@ from .custom import HTTP3CustomQuicMixin
6
6
  from .lifecycle import HTTP3LifecycleMixin
7
7
  from .outbound import HTTP3OutboundMixin
8
8
  from .packet import HTTP3PacketMixin
9
+ from .priority_lock import PriorityLock
9
10
  from .requests import HTTP3RequestsMixin
10
11
  from .responses import HTTP3ResponsesMixin
11
12
  from .websocket_runtime import HTTP3WebSocketRuntimeMixin
12
13
  from .webtransport_datagrams import HTTP3WebTransportDatagramsMixin
14
+ from .webtransport_stream_flow import HTTP3WebTransportStreamFlowMixin
13
15
  from .webtransport_streams import HTTP3WebTransportStreamsMixin
14
16
  from .webtransport_support import HTTP3WebTransportSupportMixin
15
17
 
16
18
 
17
19
  class HTTP3DatagramHandler(
18
20
  HTTP3PacketMixin,
21
+ HTTP3WebTransportStreamFlowMixin,
19
22
  HTTP3WebTransportStreamsMixin,
20
23
  HTTP3WebTransportDatagramsMixin,
21
24
  HTTP3WebTransportSupportMixin,
@@ -41,6 +44,9 @@ class HTTP3DatagramHandler(
41
44
  scheduler: ProductionScheduler | None = None,
42
45
  metrics: Metrics | None = None,
43
46
  webtransport_governance: Any | None = None,
47
+ connection_inventory: RuntimeConnectionInventory | None = None,
48
+ congestion_controller_factory: Any | None = None,
49
+ congestion_controller_options: Any | None = None,
44
50
  ) -> None:
45
51
  self.app = app
46
52
  self.config = config
@@ -49,10 +55,13 @@ class HTTP3DatagramHandler(
49
55
  self.scheduler = scheduler
50
56
  self.metrics = metrics
51
57
  self.webtransport_governance = webtransport_governance
58
+ self.connection_inventory = connection_inventory
59
+ self.congestion_controller_factory = congestion_controller_factory
60
+ self.congestion_controller_options = dict(congestion_controller_options or {})
52
61
  self.sessions: dict[tuple[str, int], HTTP3Session] = {}
53
62
  self.sessions_by_local_cid: dict[bytes, HTTP3Session] = {}
54
63
  self._session_sequence = 0
55
- self._lock = asyncio.Lock()
64
+ self._lock = PriorityLock()
56
65
  self.webtransport_trace: list[dict[str, object]] = []
57
66
 
58
67
 
@@ -47,7 +47,7 @@ class _CustomQuicSend:
47
47
  raise RuntimeError(f'unexpected custom quic send event: {typ!r}')
48
48
  data = bytes(message.get('data', b''))
49
49
  fin = not bool(message.get('more_data', False))
50
- self.messages.append(self.session.quic.send_stream_data(self.stream_id, data, fin=fin))
50
+ self.messages.extend(self.session.quic.send_stream_data_packets(self.stream_id, data, fin=fin))
51
51
 
52
52
  def flush(self) -> list[bytes]:
53
53
  return list(self.messages)
@@ -1,6 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
+ import logging
5
+ import time
4
6
  from contextlib import suppress
5
7
  from dataclasses import dataclass, field
6
8
  from typing import Any
@@ -31,6 +33,7 @@ from tigrcorn_protocols.http3.codec import (
31
33
  SETTING_MAX_FIELD_SECTION_SIZE,
32
34
  SETTING_QPACK_MAX_TABLE_CAPACITY,
33
35
  SETTING_WT_MAX_SESSIONS,
36
+ SETTING_WT_ENABLED,
34
37
  HTTP3ConnectionError,
35
38
  HTTP3StreamError,
36
39
  encode_frame,
@@ -42,7 +45,10 @@ from tigrcorn_protocols.http3.streams import (
42
45
  HTTP3ConnectionCore,
43
46
  )
44
47
  from tigrcorn_protocols.http3.websocket import H3WebSocketSession
48
+ from tigrcorn_protocols.sessions import RuntimeConnectionInventory, peer_id_from_address
45
49
  from tigrcorn_protocols.webtransport.governance import WebTransportGovernanceError
50
+ from tigrcorn_protocols.webtransport.negotiation import negotiate_profiles, settings_for_profiles
51
+ from tigrcorn_protocols.webtransport.profiles import conflicting_request_profile, missing_peer_requirement, missing_request_requirement, profile_spec
46
52
  from tigrcorn_transports.quic.connection import QuicConnection
47
53
  from tigrcorn_transports.quic.handshake import QuicTlsHandshakeDriver, TransportParameters
48
54
  from tigrcorn_transports.quic.packets import QuicLongHeaderPacket, QuicLongHeaderType, QuicRetryPacket, QuicShortHeaderPacket, QuicVersionNegotiationPacket, decode_packet
@@ -25,6 +25,62 @@ class HTTP3LifecycleMixin:
25
25
  def _webtransport_address(addr: tuple[str, int]) -> str:
26
26
  return f"{addr[0]}:{addr[1]}"
27
27
 
28
+ def _connection_id_for_session(self, session: HTTP3Session) -> str:
29
+ return f"conn:h3:{session.runtime_id or session.quic.local_cid.hex() or 'session'}"
30
+
31
+ def _listener_id(self) -> str:
32
+ return self.listener.label or f"{self.listener.kind}:{self.listener.host}:{self.listener.port}"
33
+
34
+ def _register_h3_connection(self, session: HTTP3Session) -> None:
35
+ inventory = self.connection_inventory
36
+ if inventory is None:
37
+ return
38
+ address = self._webtransport_address(session.addr)
39
+ handshake = session.quic.handshake_driver
40
+ inventory.open_connection(
41
+ self._connection_id_for_session(session),
42
+ transport='quic',
43
+ protocols=tuple(sorted(self.listener.enabled_protocols)),
44
+ listener_id=self._listener_id(),
45
+ peer_id=peer_id_from_address(address),
46
+ remote_address=address,
47
+ local_address=self.listener.label,
48
+ security={
49
+ 'alpn': getattr(handshake, 'selected_alpn', None) if handshake is not None else None,
50
+ 'local_cid': session.quic.local_cid.hex(),
51
+ 'remote_cid': session.quic.remote_cid.hex() if isinstance(session.quic.remote_cid, bytes) else None,
52
+ 'tls': bool(handshake is not None),
53
+ },
54
+ )
55
+
56
+ def _update_h3_connection(self, session: HTTP3Session) -> None:
57
+ inventory = self.connection_inventory
58
+ if inventory is None:
59
+ return
60
+ inventory.update_connection(
61
+ self._connection_id_for_session(session),
62
+ remote_address=self._webtransport_address(session.addr),
63
+ counters={
64
+ 'bytes_received': session.bytes_received,
65
+ 'bytes_sent': session.bytes_sent,
66
+ 'requests': len(session.responded_streams),
67
+ 'streams': len(session.h3.requests) + len(session.webtransport_streams),
68
+ 'webtransport_sessions': len(session.webtransport_sessions),
69
+ 'websocket_sessions': len(session.websocket_sessions),
70
+ },
71
+ security={
72
+ 'local_cid': session.quic.local_cid.hex(),
73
+ 'remote_cid': session.quic.remote_cid.hex() if isinstance(session.quic.remote_cid, bytes) else None,
74
+ },
75
+ )
76
+
77
+ def _close_h3_connection(self, session: HTTP3Session, *, reason: str) -> None:
78
+ inventory = self.connection_inventory
79
+ if inventory is None:
80
+ return
81
+ self._update_h3_connection(session)
82
+ inventory.close_connection(self._connection_id_for_session(session), reason=reason)
83
+
28
84
  def _webtransport_budget_snapshot(self) -> dict[str, Any] | None:
29
85
  manager = self.webtransport_governance
30
86
  if manager is None:
@@ -37,16 +93,29 @@ class HTTP3LifecycleMixin:
37
93
  return None
38
94
  return manager.open_session(
39
95
  webtransport.session_id,
40
- peer_id=self._webtransport_address(session.addr),
96
+ peer_id=peer_id_from_address(self._webtransport_address(session.addr)),
41
97
  address=self._webtransport_address(session.addr),
42
98
  )
43
99
 
44
100
  def _webtransport_register_stream(self, webtransport: _HTTP3WebTransportSession, stream_id: int | str) -> dict[str, Any] | None:
101
+ if self.connection_inventory is not None:
102
+ self.connection_inventory.update_session(
103
+ webtransport.session_id,
104
+ stream_ids=(str(stream_id),),
105
+ )
45
106
  manager = self.webtransport_governance
46
107
  if manager is None:
47
108
  return None
48
109
  return manager.open_stream(webtransport.session_id, str(stream_id))
49
110
 
111
+ def _webtransport_release_stream(
112
+ self, webtransport: _HTTP3WebTransportSession, stream_id: int | str
113
+ ) -> dict[str, Any] | None:
114
+ manager = self.webtransport_governance
115
+ if manager is None:
116
+ return None
117
+ return manager.close_stream(webtransport.session_id, str(stream_id))
118
+
50
119
  def _webtransport_register_datagram(
51
120
  self,
52
121
  webtransport: _HTTP3WebTransportSession,
@@ -107,6 +176,13 @@ class HTTP3LifecycleMixin:
107
176
  max_streams_uni=self.config.scheduler.max_streams or 128,
108
177
  idle_timeout=int(self.config.quic.idle_timeout * 1000),
109
178
  max_datagram_frame_size=self.listener.max_datagram_size,
179
+ reset_stream_at=(
180
+ 'webtransport' in self.listener.enabled_protocols
181
+ and any(
182
+ profile_spec(name, max_sessions=int(self.config.webtransport.max_sessions or 1)).requires_reset_stream_at
183
+ for name in self.config.webtransport.profiles
184
+ )
185
+ ),
110
186
  )
111
187
  session.quic.configure_handshake(
112
188
  QuicTlsHandshakeDriver(