foghttp 0.3.7__tar.gz → 0.3.8__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 (583) hide show
  1. {foghttp-0.3.7 → foghttp-0.3.8}/Cargo.lock +15 -1
  2. {foghttp-0.3.7 → foghttp-0.3.8}/Cargo.toml +3 -1
  3. {foghttp-0.3.7 → foghttp-0.3.8}/PKG-INFO +11 -2
  4. {foghttp-0.3.7 → foghttp-0.3.8}/README.md +10 -1
  5. {foghttp-0.3.7 → foghttp-0.3.8}/docs/index.md +14 -1
  6. {foghttp-0.3.7 → foghttp-0.3.8}/docs/limitations.md +18 -3
  7. {foghttp-0.3.7 → foghttp-0.3.8}/docs/policy-hooks.md +6 -5
  8. {foghttp-0.3.7 → foghttp-0.3.8}/docs/proxies.md +13 -4
  9. {foghttp-0.3.7 → foghttp-0.3.8}/docs/pyo3-boundary.md +5 -3
  10. {foghttp-0.3.7 → foghttp-0.3.8}/docs/request-builder.md +4 -3
  11. foghttp-0.3.8/docs/retries.md +224 -0
  12. foghttp-0.3.8/docs/ssrf.md +132 -0
  13. {foghttp-0.3.7 → foghttp-0.3.8}/docs/telemetry.md +13 -5
  14. {foghttp-0.3.7 → foghttp-0.3.8}/docs/timeouts.md +14 -4
  15. {foghttp-0.3.7 → foghttp-0.3.8}/docs/upload-types.md +3 -3
  16. {foghttp-0.3.7 → foghttp-0.3.8}/docs/use-cases.md +3 -2
  17. {foghttp-0.3.7 → foghttp-0.3.8}/examples/README.md +6 -0
  18. foghttp-0.3.8/examples/retry_policy.py +41 -0
  19. foghttp-0.3.8/examples/ssrf_policy.py +30 -0
  20. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/__init__.py +17 -0
  21. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/config.py +5 -1
  22. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/options.py +3 -1
  23. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/raw/errors.py +18 -2
  24. foghttp-0.3.8/foghttp/_client/raw/lifecycle.py +108 -0
  25. foghttp-0.3.8/foghttp/_client/raw/ssrf_errors.py +32 -0
  26. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/raw/timeout_errors.py +1 -0
  27. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/response.py +38 -27
  28. foghttp-0.3.8/foghttp/_client/retry.py +45 -0
  29. foghttp-0.3.8/foghttp/_client/retry_trace_mapping.py +89 -0
  30. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/telemetry/dispatcher.py +14 -1
  31. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/telemetry/emission.py +13 -1
  32. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/telemetry/request_context.py +31 -0
  33. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/telemetry/request_events.py +7 -0
  34. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/telemetry/responses.py +12 -0
  35. foghttp-0.3.8/foghttp/_client/telemetry/retries.py +19 -0
  36. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_foghttp.pyi +51 -0
  37. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_telemetry.py +1 -1
  38. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_upload_body/runtime.py +2 -8
  39. foghttp-0.3.8/foghttp/_validation/ssrf.py +100 -0
  40. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/async_client.py +9 -0
  41. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/client.py +9 -0
  42. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/errors/__init__.py +5 -1
  43. foghttp-0.3.8/foghttp/errors/base.py +25 -0
  44. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/errors/response.py +14 -1
  45. foghttp-0.3.8/foghttp/errors/ssrf.py +32 -0
  46. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/policy.py +5 -0
  47. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/response.py +17 -2
  48. foghttp-0.3.8/foghttp/retry.py +135 -0
  49. foghttp-0.3.8/foghttp/retry_trace.py +35 -0
  50. foghttp-0.3.8/foghttp/ssrf.py +91 -0
  51. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/stream_response/base.py +11 -0
  52. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/stream_response/status.py +12 -0
  53. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/telemetry/__init__.py +10 -1
  54. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/telemetry/events.py +21 -0
  55. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/timeout_diagnostics.py +1 -0
  56. {foghttp-0.3.7 → foghttp-0.3.8}/pyproject.toml +1 -1
  57. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/client/mod.rs +9 -2
  58. foghttp-0.3.8/src/core/client/ssrf.rs +284 -0
  59. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/policy/error.rs +10 -0
  60. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/policy/mod.rs +4 -0
  61. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/policy/pipeline.rs +50 -2
  62. foghttp-0.3.8/src/core/policy/retry/tests.rs +253 -0
  63. foghttp-0.3.8/src/core/policy/retry.rs +160 -0
  64. foghttp-0.3.8/src/core/policy/ssrf.rs +749 -0
  65. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/policy/tests.rs +3 -1
  66. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/url/mod.rs +8 -0
  67. {foghttp-0.3.7 → foghttp-0.3.8}/src/errors.rs +4 -0
  68. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/mod.rs +66 -1
  69. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/streams/parts.rs +2 -0
  70. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/streams/response.rs +21 -0
  71. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/timeout_diagnostics.rs +2 -0
  72. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/transport/body.rs +11 -0
  73. foghttp-0.3.8/src/py/client/transport/buffered.rs +163 -0
  74. foghttp-0.3.8/src/py/client/transport/errors.rs +81 -0
  75. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/transport/mod.rs +1 -0
  76. foghttp-0.3.8/src/py/client/transport/request.rs +601 -0
  77. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/transport/response.rs +16 -1
  78. foghttp-0.3.8/src/py/client/transport/retry.rs +93 -0
  79. foghttp-0.3.8/src/py/client/transport/streaming.rs +198 -0
  80. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/transport/tests.rs +7 -5
  81. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/upload_body.rs +47 -21
  82. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/mod.rs +4 -0
  83. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/response.rs +22 -0
  84. foghttp-0.3.8/src/py/retry.rs +343 -0
  85. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_lifecycle/helpers.py +2 -0
  86. foghttp-0.3.8/tests/client_options/raw_options.py +39 -0
  87. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_options/test_raw_numeric_boundary.py +15 -45
  88. foghttp-0.3.8/tests/client_options/test_raw_retry_boundary.py +59 -0
  89. foghttp-0.3.8/tests/client_options/test_raw_ssrf_boundary.py +170 -0
  90. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_proxy/client_options.py +2 -0
  91. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_proxy/test_http_proxy_transport.py +6 -4
  92. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_proxy/test_https_proxy_connect.py +17 -17
  93. foghttp-0.3.8/tests/client_retry/assertions.py +36 -0
  94. foghttp-0.3.8/tests/client_retry/conftest.py +11 -0
  95. foghttp-0.3.8/tests/client_retry/constants.py +18 -0
  96. foghttp-0.3.8/tests/client_retry/models.py +19 -0
  97. foghttp-0.3.8/tests/client_retry/server.py +339 -0
  98. foghttp-0.3.8/tests/client_retry/sources.py +114 -0
  99. foghttp-0.3.8/tests/client_retry/test_async_retry.py +181 -0
  100. foghttp-0.3.8/tests/client_retry/test_attempt_trace.py +528 -0
  101. foghttp-0.3.8/tests/client_retry/test_policy_config.py +114 -0
  102. foghttp-0.3.8/tests/client_retry/test_sync_retry.py +506 -0
  103. foghttp-0.3.8/tests/client_ssrf/__init__.py +1 -0
  104. foghttp-0.3.8/tests/client_ssrf/test_async_ssrf.py +70 -0
  105. foghttp-0.3.8/tests/client_ssrf/test_policy_config.py +124 -0
  106. foghttp-0.3.8/tests/client_ssrf/test_sync_ssrf.py +210 -0
  107. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_telemetry/test_event_contract.py +4 -0
  108. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_tls/test_async_tls.py +1 -2
  109. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_tls/test_sync_tls.py +1 -2
  110. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_tls/test_tls_config.py +1 -3
  111. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_upload/test_upload_helpers.py +1 -1
  112. {foghttp-0.3.7 → foghttp-0.3.8}/tests/fault_injection/test_async_fault_injection.py +7 -5
  113. {foghttp-0.3.7 → foghttp-0.3.8}/tests/fault_injection/test_sync_fault_injection.py +7 -5
  114. {foghttp-0.3.7 → foghttp-0.3.8}/tests/fault_injection/test_sync_socket_shutdown.py +1 -1
  115. {foghttp-0.3.7 → foghttp-0.3.8}/tests/network_errors/test_async_network_errors.py +5 -4
  116. {foghttp-0.3.7 → foghttp-0.3.8}/tests/network_errors/test_sync_network_errors.py +5 -4
  117. {foghttp-0.3.7 → foghttp-0.3.8}/tests/pyo3_boundary/test_async_future_boundary.py +2 -2
  118. {foghttp-0.3.7 → foghttp-0.3.8}/tests/pyo3_boundary/test_raw_client_signatures.py +9 -0
  119. {foghttp-0.3.7 → foghttp-0.3.8}/tests/support/transport_stats.py +10 -4
  120. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_public_api.py +10 -0
  121. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_raw_client.py +20 -0
  122. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_raw_client_errors.py +75 -0
  123. foghttp-0.3.8/tests/test_transport_stats_waiters.py +52 -0
  124. foghttp-0.3.8/tests/types/__init__.py +0 -0
  125. foghttp-0.3.8/tests/types/test_policy_contracts.py +91 -0
  126. foghttp-0.3.8/tests/types/test_retry_trace_contracts.py +87 -0
  127. {foghttp-0.3.7 → foghttp-0.3.8}/uv.lock +1 -1
  128. foghttp-0.3.7/foghttp/_client/raw/lifecycle.py +0 -45
  129. foghttp-0.3.7/foghttp/errors/base.py +0 -9
  130. foghttp-0.3.7/src/py/client/transport/buffered.rs +0 -108
  131. foghttp-0.3.7/src/py/client/transport/errors.rs +0 -31
  132. foghttp-0.3.7/src/py/client/transport/request.rs +0 -302
  133. foghttp-0.3.7/src/py/client/transport/streaming.rs +0 -156
  134. foghttp-0.3.7/tests/types/test_policy_contracts.py +0 -40
  135. {foghttp-0.3.7 → foghttp-0.3.8}/.flake8 +0 -0
  136. {foghttp-0.3.7 → foghttp-0.3.8}/.github/workflows/ci.yml +0 -0
  137. {foghttp-0.3.7 → foghttp-0.3.8}/.github/workflows/release.yml +0 -0
  138. {foghttp-0.3.7 → foghttp-0.3.8}/.gitignore +0 -0
  139. {foghttp-0.3.7 → foghttp-0.3.8}/.pre-commit-config.yaml +0 -0
  140. {foghttp-0.3.7 → foghttp-0.3.8}/CODE_OF_CONDUCT.md +0 -0
  141. {foghttp-0.3.7 → foghttp-0.3.8}/CONTRIBUTING.md +0 -0
  142. {foghttp-0.3.7 → foghttp-0.3.8}/LICENSE +0 -0
  143. {foghttp-0.3.7 → foghttp-0.3.8}/SECURITY.md +0 -0
  144. {foghttp-0.3.7 → foghttp-0.3.8}/docs/benchmarks.md +0 -0
  145. {foghttp-0.3.7 → foghttp-0.3.8}/docs/lifecycle.md +0 -0
  146. {foghttp-0.3.7 → foghttp-0.3.8}/docs/packaging.md +0 -0
  147. {foghttp-0.3.7 → foghttp-0.3.8}/docs/quickstart.md +0 -0
  148. {foghttp-0.3.7 → foghttp-0.3.8}/docs/redirects.md +0 -0
  149. {foghttp-0.3.7 → foghttp-0.3.8}/docs/streaming.md +0 -0
  150. {foghttp-0.3.7 → foghttp-0.3.8}/docs/tls.md +0 -0
  151. {foghttp-0.3.7 → foghttp-0.3.8}/examples/async_json_fanout.py +0 -0
  152. {foghttp-0.3.7 → foghttp-0.3.8}/examples/async_lifecycle_debug.py +0 -0
  153. {foghttp-0.3.7 → foghttp-0.3.8}/examples/async_resource_limits.py +0 -0
  154. {foghttp-0.3.7 → foghttp-0.3.8}/examples/async_streaming.py +0 -0
  155. {foghttp-0.3.7 → foghttp-0.3.8}/examples/compressed_response.py +0 -0
  156. {foghttp-0.3.7 → foghttp-0.3.8}/examples/http_proxy.py +0 -0
  157. {foghttp-0.3.7 → foghttp-0.3.8}/examples/multipart_uploads.py +0 -0
  158. {foghttp-0.3.7 → foghttp-0.3.8}/examples/prepared_requests.py +0 -0
  159. {foghttp-0.3.7 → foghttp-0.3.8}/examples/redirects.py +0 -0
  160. {foghttp-0.3.7 → foghttp-0.3.8}/examples/request_builder_compatibility.py +0 -0
  161. {foghttp-0.3.7 → foghttp-0.3.8}/examples/sync_json_api.py +0 -0
  162. {foghttp-0.3.7 → foghttp-0.3.8}/examples/sync_streaming.py +0 -0
  163. {foghttp-0.3.7 → foghttp-0.3.8}/examples/telemetry_hooks.py +0 -0
  164. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/__init__.py +0 -0
  165. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/asyncio_futures.py +0 -0
  166. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/constants.py +0 -0
  167. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/core.py +0 -0
  168. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/lifecycle_debug.py +0 -0
  169. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/process.py +0 -0
  170. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/proxy/__init__.py +0 -0
  171. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/proxy/auth.py +0 -0
  172. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/proxy/constants.py +0 -0
  173. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/proxy/environment.py +0 -0
  174. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/proxy/models.py +0 -0
  175. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/proxy/no_proxy.py +0 -0
  176. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/proxy/no_proxy_rule.py +0 -0
  177. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/proxy/no_proxy_tokens.py +0 -0
  178. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/proxy/resolver.py +0 -0
  179. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/proxy/transport_policy.py +0 -0
  180. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/proxy/url_parsing.py +0 -0
  181. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/raw/__init__.py +0 -0
  182. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/raw/requests.py +0 -0
  183. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/request_builder/__init__.py +0 -0
  184. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/request_builder/builder.py +0 -0
  185. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/request_builder/defaults.py +0 -0
  186. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/request_builder/header_policy.py +0 -0
  187. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/request_builder/merge.py +0 -0
  188. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/request_builder/models.py +0 -0
  189. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/runtime/__init__.py +0 -0
  190. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/runtime/constants.py +0 -0
  191. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/runtime/mode.py +0 -0
  192. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/runtime/validation.py +0 -0
  193. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/runtime/workers.py +0 -0
  194. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/stats.py +0 -0
  195. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/stream_context.py +0 -0
  196. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/telemetry/__init__.py +0 -0
  197. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/telemetry/clock.py +0 -0
  198. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/telemetry/url.py +0 -0
  199. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/tls.py +0 -0
  200. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/transport.py +0 -0
  201. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/transport_requests.py +0 -0
  202. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_client/transport_snapshot_mapping.py +0 -0
  203. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_multipart/__init__.py +0 -0
  204. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_multipart/constants.py +0 -0
  205. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_multipart/content_type.py +0 -0
  206. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_multipart/encoding.py +0 -0
  207. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_multipart/fields.py +0 -0
  208. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_multipart/file_parts.py +0 -0
  209. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_multipart/iterators.py +0 -0
  210. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_multipart/length.py +0 -0
  211. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_multipart/models.py +0 -0
  212. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_multipart/normalize.py +0 -0
  213. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_multipart/parts.py +0 -0
  214. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_multipart/stream.py +0 -0
  215. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_multipart/values.py +0 -0
  216. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_redaction.py +0 -0
  217. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_request_body.py +0 -0
  218. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_response/__init__.py +0 -0
  219. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_response/encoding.py +0 -0
  220. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_response/status.py +0 -0
  221. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_streaming/__init__.py +0 -0
  222. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_streaming/text/__init__.py +0 -0
  223. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_streaming/text/async_chunks.py +0 -0
  224. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_streaming/text/iterators.py +0 -0
  225. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_streaming/text/lines.py +0 -0
  226. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_streaming/text/sync_chunks.py +0 -0
  227. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_upload_body/__init__.py +0 -0
  228. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_upload_body/async_sending.py +0 -0
  229. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_upload_body/chunks.py +0 -0
  230. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_upload_body/feeders.py +0 -0
  231. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_upload_body/file_source.py +0 -0
  232. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_upload_body/models.py +0 -0
  233. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_upload_body/normalize.py +0 -0
  234. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_upload_body/predicates.py +0 -0
  235. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_upload_body/thread_bridge.py +0 -0
  236. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_validation/__init__.py +0 -0
  237. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/_validation/numeric.py +0 -0
  238. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/body.py +0 -0
  239. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/errors/lifecycle.py +0 -0
  240. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/errors/timeout.py +0 -0
  241. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/headers.py +0 -0
  242. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/lifecycle_debug.py +0 -0
  243. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/limits.py +0 -0
  244. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/messages.py +0 -0
  245. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/methods.py +0 -0
  246. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/models.py +0 -0
  247. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/pool_diagnostics.py +0 -0
  248. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/py.typed +0 -0
  249. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/request.py +0 -0
  250. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/request_extensions.py +0 -0
  251. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/request_info.py +0 -0
  252. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/stats.py +0 -0
  253. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/status_codes/__init__.py +0 -0
  254. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/status_codes/client_error.py +0 -0
  255. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/status_codes/redirect.py +0 -0
  256. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/status_codes/server_error.py +0 -0
  257. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/status_codes/success.py +0 -0
  258. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/stream_response/__init__.py +0 -0
  259. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/stream_response/async_response.py +0 -0
  260. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/stream_response/bindings.py +0 -0
  261. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/stream_response/constants.py +0 -0
  262. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/stream_response/lifecycle_debug.py +0 -0
  263. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/stream_response/sync_response.py +0 -0
  264. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/stream_response/telemetry.py +0 -0
  265. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/telemetry/config.py +0 -0
  266. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/telemetry/errors.py +0 -0
  267. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/telemetry/sinks.py +0 -0
  268. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/timeouts.py +0 -0
  269. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/tls.py +0 -0
  270. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/transport_state.py +0 -0
  271. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/transport_stats.py +0 -0
  272. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/types/__init__.py +0 -0
  273. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/types/http.py +0 -0
  274. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/types/multipart.py +0 -0
  275. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/types/request.py +0 -0
  276. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/types/streams.py +0 -0
  277. {foghttp-0.3.7 → foghttp-0.3.8}/foghttp/url.py +0 -0
  278. {foghttp-0.3.7 → foghttp-0.3.8}/logo.png +0 -0
  279. {foghttp-0.3.7 → foghttp-0.3.8}/ruff.toml +0 -0
  280. {foghttp-0.3.7 → foghttp-0.3.8}/scripts/check_all_position.py +0 -0
  281. {foghttp-0.3.7 → foghttp-0.3.8}/scripts/install_wheel_smoke.py +0 -0
  282. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/client/body.rs +0 -0
  283. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/client/connection_limit.rs +0 -0
  284. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/client/proxy/authorization.rs +0 -0
  285. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/client/proxy/endpoint.rs +0 -0
  286. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/client/proxy/http.rs +0 -0
  287. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/client/proxy/mod.rs +0 -0
  288. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/client/proxy/tests.rs +0 -0
  289. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/client/proxy/tunnel.rs +0 -0
  290. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/client/telemetry/mod.rs +0 -0
  291. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/client/telemetry/tests.rs +0 -0
  292. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/client/write_timeout.rs +0 -0
  293. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/headers/mod.rs +0 -0
  294. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/headers/request.rs +0 -0
  295. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/headers/response.rs +0 -0
  296. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/headers/tests.rs +0 -0
  297. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/method.rs +0 -0
  298. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/metrics/atomic.rs +0 -0
  299. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/metrics/buffered.rs +0 -0
  300. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/metrics/counters.rs +0 -0
  301. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/metrics/lifecycle.rs +0 -0
  302. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/metrics/mod.rs +0 -0
  303. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/metrics/origin/blocking.rs +0 -0
  304. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/metrics/origin/metrics.rs +0 -0
  305. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/metrics/origin/mod.rs +0 -0
  306. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/metrics/origin/registry.rs +0 -0
  307. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/metrics/origin/snapshots.rs +0 -0
  308. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/metrics/origin/tests.rs +0 -0
  309. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/metrics/origin/waiters.rs +0 -0
  310. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/metrics/snapshots.rs +0 -0
  311. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/metrics/telemetry.rs +0 -0
  312. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/metrics/tests.rs +0 -0
  313. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/mod.rs +0 -0
  314. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/numeric/mod.rs +0 -0
  315. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/numeric/tests.rs +0 -0
  316. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/policy/proxy.rs +0 -0
  317. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/policy/redirect/action.rs +0 -0
  318. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/policy/redirect/headers.rs +0 -0
  319. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/policy/redirect/method.rs +0 -0
  320. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/policy/redirect/mod.rs +0 -0
  321. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/policy/redirect/policy.rs +0 -0
  322. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/policy/redirect/status.rs +0 -0
  323. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/policy/redirect/tests.rs +0 -0
  324. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/policy/redirect/utils.rs +0 -0
  325. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/policy/request.rs +0 -0
  326. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/request.rs +0 -0
  327. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/response/body.rs +0 -0
  328. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/response/budget.rs +0 -0
  329. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/response/decompression.rs +0 -0
  330. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/response/mod.rs +0 -0
  331. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/tls/mod.rs +0 -0
  332. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/tls/tests.rs +0 -0
  333. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/url/constants.rs +0 -0
  334. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/url/origin.rs +0 -0
  335. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/url/scheme.rs +0 -0
  336. {foghttp-0.3.7 → foghttp-0.3.8}/src/core/url/tests.rs +0 -0
  337. {foghttp-0.3.7 → foghttp-0.3.8}/src/lib.rs +0 -0
  338. {foghttp-0.3.7 → foghttp-0.3.8}/src/messages.rs +0 -0
  339. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/acquire/diagnostics.rs +0 -0
  340. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/acquire/gate.rs +0 -0
  341. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/acquire/mod.rs +0 -0
  342. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/acquire/origin.rs +0 -0
  343. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/acquire/pending.rs +0 -0
  344. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/acquire/permit.rs +0 -0
  345. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/acquire/telemetry.rs +0 -0
  346. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/acquire/tests.rs +0 -0
  347. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/async_requests/active.rs +0 -0
  348. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/async_requests/callback.rs +0 -0
  349. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/async_requests/mod.rs +0 -0
  350. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/async_requests/registry.rs +0 -0
  351. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/async_requests/spawn.rs +0 -0
  352. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/async_requests/stream_spawn.rs +0 -0
  353. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/future.rs +0 -0
  354. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/lifecycle/mod.rs +0 -0
  355. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/lifecycle/tests.rs +0 -0
  356. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/options.rs +0 -0
  357. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/policy_hooks.rs +0 -0
  358. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/process.rs +0 -0
  359. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/runtime/constants.rs +0 -0
  360. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/runtime/mod.rs +0 -0
  361. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/runtime/shared.rs +0 -0
  362. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/runtime/tests.rs +0 -0
  363. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/runtime/workers.rs +0 -0
  364. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/streams/callback.rs +0 -0
  365. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/streams/constants.rs +0 -0
  366. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/streams/mod.rs +0 -0
  367. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/streams/read.rs +0 -0
  368. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/streams/registry.rs +0 -0
  369. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/streams/state.rs +0 -0
  370. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/streams/state_tests.rs +0 -0
  371. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/transport/client.rs +0 -0
  372. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/client/transport/context.rs +0 -0
  373. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/pool_diagnostics.rs +0 -0
  374. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/stats.rs +0 -0
  375. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/transport_state.rs +0 -0
  376. {foghttp-0.3.7 → foghttp-0.3.8}/src/py/url.rs +0 -0
  377. {foghttp-0.3.7 → foghttp-0.3.8}/tests/__init__.py +0 -0
  378. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_cancellation/__init__.py +0 -0
  379. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_cancellation/conftest.py +0 -0
  380. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_cancellation/constants.py +0 -0
  381. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_cancellation/helpers.py +0 -0
  382. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_cancellation/lifecycle_debug_actions.py +0 -0
  383. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_cancellation/lifecycle_debug_assertions.py +0 -0
  384. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_cancellation/lifecycle_debug_data.py +0 -0
  385. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_cancellation/lifecycle_debug_predicates.py +0 -0
  386. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_cancellation/test_async_cancellation.py +0 -0
  387. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_cancellation/test_async_lifecycle_debug_buffered.py +0 -0
  388. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_cancellation/test_async_lifecycle_debug_messages.py +0 -0
  389. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_cancellation/test_async_lifecycle_debug_streaming.py +0 -0
  390. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_cancellation/test_async_lifecycle_debug_strict.py +0 -0
  391. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_cancellation/test_async_telemetry.py +0 -0
  392. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_cancellation/test_asyncio_helpers.py +0 -0
  393. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_keepalive/__init__.py +0 -0
  394. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_keepalive/assertions.py +0 -0
  395. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_keepalive/conftest.py +0 -0
  396. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_keepalive/constants.py +0 -0
  397. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_keepalive/models.py +0 -0
  398. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_keepalive/server.py +0 -0
  399. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_keepalive/test_async_keepalive.py +0 -0
  400. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_keepalive/test_sync_keepalive.py +0 -0
  401. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_lifecycle/__init__.py +0 -0
  402. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_lifecycle/conftest.py +0 -0
  403. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_lifecycle/constants.py +0 -0
  404. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_lifecycle/fork_actions.py +0 -0
  405. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_lifecycle/test_async_client_lifecycle.py +0 -0
  406. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_lifecycle/test_fork_close_safety.py +0 -0
  407. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_lifecycle/test_fork_safety.py +0 -0
  408. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_lifecycle/test_fork_stream_safety.py +0 -0
  409. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_lifecycle/test_raw_client_lifecycle.py +0 -0
  410. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_lifecycle/test_sync_client_lifecycle.py +0 -0
  411. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_lifecycle/test_sync_close_race.py +0 -0
  412. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_lifecycle/test_sync_close_waits.py +0 -0
  413. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_multipart/__init__.py +0 -0
  414. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_multipart/assertions.py +0 -0
  415. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_multipart/models.py +0 -0
  416. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_multipart/sources.py +0 -0
  417. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_multipart/test_async_multipart.py +0 -0
  418. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_multipart/test_multipart_internals.py +0 -0
  419. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_multipart/test_request_builder.py +0 -0
  420. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_multipart/test_sync_multipart.py +0 -0
  421. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_options/__init__.py +0 -0
  422. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_options/test_numeric_validation.py +0 -0
  423. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_policy_hooks/__init__.py +0 -0
  424. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_policy_hooks/requests.py +0 -0
  425. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_policy_hooks/test_async_hooks.py +0 -0
  426. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_policy_hooks/test_contract.py +0 -0
  427. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_policy_hooks/test_sync_hooks.py +0 -0
  428. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_proxy/__init__.py +0 -0
  429. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_proxy/conftest.py +0 -0
  430. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_proxy/connect_proxy_server.py +0 -0
  431. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_proxy/environment.py +0 -0
  432. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_proxy/http_proxy_server.py +0 -0
  433. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_proxy/test_client_config.py +0 -0
  434. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_proxy/test_environment.py +0 -0
  435. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_proxy/test_no_proxy.py +0 -0
  436. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_proxy/test_proxy_models.py +0 -0
  437. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_query/__init__.py +0 -0
  438. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_query/assertions.py +0 -0
  439. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_query/constants.py +0 -0
  440. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_query/test_async_query.py +0 -0
  441. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_query/test_async_query_redirects.py +0 -0
  442. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_query/test_request_builder.py +0 -0
  443. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_query/test_sync_query.py +0 -0
  444. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_query/test_sync_query_redirects.py +0 -0
  445. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_resources/__init__.py +0 -0
  446. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_resources/conftest.py +0 -0
  447. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_resources/constants.py +0 -0
  448. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_resources/helpers.py +0 -0
  449. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_resources/test_async_connection_limits.py +0 -0
  450. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_resources/test_async_global_limits.py +0 -0
  451. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_resources/test_async_origin_limits.py +0 -0
  452. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_resources/test_async_pool_diagnostics.py +0 -0
  453. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_resources/test_async_response_body_limits.py +0 -0
  454. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_resources/test_async_transport_state.py +0 -0
  455. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_resources/test_diagnostic_snapshot_contract.py +0 -0
  456. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_resources/test_sync_connection_limits.py +0 -0
  457. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_resources/test_sync_global_limits.py +0 -0
  458. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_resources/test_sync_origin_limits.py +0 -0
  459. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_resources/test_sync_pool_diagnostics.py +0 -0
  460. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_resources/test_sync_response_body_limits.py +0 -0
  461. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_resources/test_sync_transport_state.py +0 -0
  462. {foghttp-0.3.7/tests/client_telemetry → foghttp-0.3.8/tests/client_retry}/__init__.py +0 -0
  463. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_streaming/__init__.py +0 -0
  464. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_streaming/conftest.py +0 -0
  465. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_streaming/constants.py +0 -0
  466. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_streaming/server.py +0 -0
  467. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_streaming/stream_readers.py +0 -0
  468. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_streaming/test_async_streaming.py +0 -0
  469. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_streaming/test_async_streaming_text_lines.py +0 -0
  470. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_streaming/test_streaming_text_decoding.py +0 -0
  471. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_streaming/test_sync_streaming.py +0 -0
  472. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_streaming/test_sync_streaming_text_lines.py +0 -0
  473. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_streaming/text_decoding_sources.py +0 -0
  474. {foghttp-0.3.7/tests/client_timeouts → foghttp-0.3.8/tests/client_telemetry}/__init__.py +0 -0
  475. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_telemetry/assertions.py +0 -0
  476. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_telemetry/conftest.py +0 -0
  477. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_telemetry/constants.py +0 -0
  478. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_telemetry/models.py +0 -0
  479. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_telemetry/test_async_stream_hooks.py +0 -0
  480. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_telemetry/test_async_stream_telemetry.py +0 -0
  481. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_telemetry/test_async_telemetry.py +0 -0
  482. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_telemetry/test_concurrent_delivery.py +0 -0
  483. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_telemetry/test_sync_stream_telemetry.py +0 -0
  484. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_telemetry/test_sync_telemetry.py +0 -0
  485. {foghttp-0.3.7/tests/client_tls → foghttp-0.3.8/tests/client_timeouts}/__init__.py +0 -0
  486. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_timeouts/conftest.py +0 -0
  487. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_timeouts/constants.py +0 -0
  488. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_timeouts/helpers.py +0 -0
  489. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_timeouts/test_async_timeouts.py +0 -0
  490. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_timeouts/test_sync_timeouts.py +0 -0
  491. {foghttp-0.3.7/tests/client_upload → foghttp-0.3.8/tests/client_tls}/__init__.py +0 -0
  492. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_tls/assertions.py +0 -0
  493. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_tls/certificates.py +0 -0
  494. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_tls/conftest.py +0 -0
  495. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_tls/constants.py +0 -0
  496. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_tls/handshake_server.py +0 -0
  497. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_tls/models.py +0 -0
  498. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_tls/server.py +0 -0
  499. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_tls/test_async_tls_redirects.py +0 -0
  500. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_tls/test_sync_tls_redirects.py +0 -0
  501. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_transport/__init__.py +0 -0
  502. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_transport/models.py +0 -0
  503. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_transport/test_transport_adapter.py +0 -0
  504. {foghttp-0.3.7/tests/fault_injection → foghttp-0.3.8/tests/client_upload}/__init__.py +0 -0
  505. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_upload/helpers.py +0 -0
  506. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_upload/test_streaming_upload.py +0 -0
  507. {foghttp-0.3.7 → foghttp-0.3.8}/tests/client_warning_actions.py +0 -0
  508. {foghttp-0.3.7 → foghttp-0.3.8}/tests/conftest.py +0 -0
  509. {foghttp-0.3.7/tests/network_errors → foghttp-0.3.8/tests/fault_injection}/__init__.py +0 -0
  510. {foghttp-0.3.7 → foghttp-0.3.8}/tests/fault_injection/conftest.py +0 -0
  511. {foghttp-0.3.7 → foghttp-0.3.8}/tests/fault_injection/constants.py +0 -0
  512. {foghttp-0.3.7 → foghttp-0.3.8}/tests/fault_injection/models.py +0 -0
  513. {foghttp-0.3.7 → foghttp-0.3.8}/tests/fault_injection/protocol.py +0 -0
  514. {foghttp-0.3.7 → foghttp-0.3.8}/tests/fault_injection/responses.py +0 -0
  515. {foghttp-0.3.7 → foghttp-0.3.8}/tests/fault_injection/server.py +0 -0
  516. {foghttp-0.3.7 → foghttp-0.3.8}/tests/fault_injection/state.py +0 -0
  517. {foghttp-0.3.7 → foghttp-0.3.8}/tests/fault_injection/state_assertions.py +0 -0
  518. {foghttp-0.3.7 → foghttp-0.3.8}/tests/fault_injection/test_async_socket_shutdown.py +0 -0
  519. {foghttp-0.3.7 → foghttp-0.3.8}/tests/fault_injection/timeout_assertions.py +0 -0
  520. {foghttp-0.3.7 → foghttp-0.3.8}/tests/fault_injection/transport_waiters.py +0 -0
  521. {foghttp-0.3.7 → foghttp-0.3.8}/tests/http_body_scenarios.py +0 -0
  522. {foghttp-0.3.7/tests/request_builder → foghttp-0.3.8/tests/network_errors}/__init__.py +0 -0
  523. {foghttp-0.3.7 → foghttp-0.3.8}/tests/network_errors/conftest.py +0 -0
  524. {foghttp-0.3.7 → foghttp-0.3.8}/tests/network_errors/constants.py +0 -0
  525. {foghttp-0.3.7 → foghttp-0.3.8}/tests/network_errors/helpers.py +0 -0
  526. {foghttp-0.3.7 → foghttp-0.3.8}/tests/pyo3_boundary/__init__.py +0 -0
  527. {foghttp-0.3.7 → foghttp-0.3.8}/tests/pyo3_boundary/async_future_server.py +0 -0
  528. {foghttp-0.3.7 → foghttp-0.3.8}/tests/pyo3_boundary/conftest.py +0 -0
  529. {foghttp-0.3.7 → foghttp-0.3.8}/tests/pyo3_boundary/constants.py +0 -0
  530. {foghttp-0.3.7 → foghttp-0.3.8}/tests/pyo3_boundary/gil_progress.py +0 -0
  531. {foghttp-0.3.7 → foghttp-0.3.8}/tests/pyo3_boundary/test_sync_gil_boundary.py +0 -0
  532. {foghttp-0.3.7 → foghttp-0.3.8}/tests/pyo3_boundary/thread_worker.py +0 -0
  533. {foghttp-0.3.7 → foghttp-0.3.8}/tests/redirect_helpers.py +0 -0
  534. {foghttp-0.3.7/tests/response_decompression → foghttp-0.3.8/tests/request_builder}/__init__.py +0 -0
  535. {foghttp-0.3.7 → foghttp-0.3.8}/tests/request_builder/encoding_property_helpers.py +0 -0
  536. {foghttp-0.3.7 → foghttp-0.3.8}/tests/request_builder/test_base_url.py +0 -0
  537. {foghttp-0.3.7 → foghttp-0.3.8}/tests/request_builder/test_body.py +0 -0
  538. {foghttp-0.3.7 → foghttp-0.3.8}/tests/request_builder/test_default_headers.py +0 -0
  539. {foghttp-0.3.7 → foghttp-0.3.8}/tests/request_builder/test_default_params.py +0 -0
  540. {foghttp-0.3.7 → foghttp-0.3.8}/tests/request_builder/test_encoding_properties.py +0 -0
  541. {foghttp-0.3.7 → foghttp-0.3.8}/tests/request_builder/test_extensions.py +0 -0
  542. {foghttp-0.3.7 → foghttp-0.3.8}/tests/request_builder/test_header_policy.py +0 -0
  543. {foghttp-0.3.7 → foghttp-0.3.8}/tests/request_builder/test_headers.py +0 -0
  544. {foghttp-0.3.7 → foghttp-0.3.8}/tests/request_builder/test_merge_contract.py +0 -0
  545. {foghttp-0.3.7 → foghttp-0.3.8}/tests/request_builder/test_no_mutation.py +0 -0
  546. {foghttp-0.3.7 → foghttp-0.3.8}/tests/request_builder/test_parity.py +0 -0
  547. {foghttp-0.3.7 → foghttp-0.3.8}/tests/request_builder/test_query_params.py +0 -0
  548. {foghttp-0.3.7 → foghttp-0.3.8}/tests/request_builder/test_shortcuts.py +0 -0
  549. {foghttp-0.3.7 → foghttp-0.3.8}/tests/request_factories.py +0 -0
  550. {foghttp-0.3.7/tests/types → foghttp-0.3.8/tests/response_decompression}/__init__.py +0 -0
  551. {foghttp-0.3.7 → foghttp-0.3.8}/tests/response_decompression/conftest.py +0 -0
  552. {foghttp-0.3.7 → foghttp-0.3.8}/tests/response_decompression/constants.py +0 -0
  553. {foghttp-0.3.7 → foghttp-0.3.8}/tests/response_decompression/helpers.py +0 -0
  554. {foghttp-0.3.7 → foghttp-0.3.8}/tests/response_decompression/payloads.py +0 -0
  555. {foghttp-0.3.7 → foghttp-0.3.8}/tests/response_decompression/server.py +0 -0
  556. {foghttp-0.3.7 → foghttp-0.3.8}/tests/response_decompression/test_async_response_decompression.py +0 -0
  557. {foghttp-0.3.7 → foghttp-0.3.8}/tests/response_decompression/test_sync_response_decompression.py +0 -0
  558. {foghttp-0.3.7 → foghttp-0.3.8}/tests/support/__init__.py +0 -0
  559. {foghttp-0.3.7 → foghttp-0.3.8}/tests/support/async_http_server.py +0 -0
  560. {foghttp-0.3.7 → foghttp-0.3.8}/tests/support/http_routes.py +0 -0
  561. {foghttp-0.3.7 → foghttp-0.3.8}/tests/support/raw_responses.py +0 -0
  562. {foghttp-0.3.7 → foghttp-0.3.8}/tests/support/sync_http_server.py +0 -0
  563. {foghttp-0.3.7 → foghttp-0.3.8}/tests/support/timeout_diagnostics.py +0 -0
  564. {foghttp-0.3.7 → foghttp-0.3.8}/tests/support/transport_state.py +0 -0
  565. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_async_client.py +0 -0
  566. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_async_redirects.py +0 -0
  567. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_async_response.py +0 -0
  568. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_client_options.py +0 -0
  569. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_headers.py +0 -0
  570. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_query_params.py +0 -0
  571. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_redaction.py +0 -0
  572. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_request_extensions.py +0 -0
  573. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_request_model.py +0 -0
  574. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_response_encoding.py +0 -0
  575. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_response_flags.py +0 -0
  576. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_runtime_workers.py +0 -0
  577. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_sync_client.py +0 -0
  578. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_sync_redirects.py +0 -0
  579. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_sync_response.py +0 -0
  580. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_transport_stats.py +0 -0
  581. {foghttp-0.3.7 → foghttp-0.3.8}/tests/test_url.py +0 -0
  582. {foghttp-0.3.7 → foghttp-0.3.8}/tests/types/test_request_extensions_contracts.py +0 -0
  583. {foghttp-0.3.7 → foghttp-0.3.8}/tests/types/test_upload_contracts.py +0 -0
@@ -92,6 +92,12 @@ dependencies = [
92
92
  "syn",
93
93
  ]
94
94
 
95
+ [[package]]
96
+ name = "fastrand"
97
+ version = "2.4.1"
98
+ source = "registry+https://github.com/rust-lang/crates.io-index"
99
+ checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
100
+
95
101
  [[package]]
96
102
  name = "find-msvc-tools"
97
103
  version = "0.1.9"
@@ -110,12 +116,14 @@ dependencies = [
110
116
 
111
117
  [[package]]
112
118
  name = "foghttp"
113
- version = "0.3.7"
119
+ version = "0.3.8"
114
120
  dependencies = [
115
121
  "brotli",
116
122
  "bytes",
123
+ "fastrand",
117
124
  "flate2",
118
125
  "http-body-util",
126
+ "httpdate",
119
127
  "hyper",
120
128
  "hyper-rustls",
121
129
  "hyper-util",
@@ -224,6 +232,12 @@ version = "1.10.1"
224
232
  source = "registry+https://github.com/rust-lang/crates.io-index"
225
233
  checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
226
234
 
235
+ [[package]]
236
+ name = "httpdate"
237
+ version = "1.0.3"
238
+ source = "registry+https://github.com/rust-lang/crates.io-index"
239
+ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
240
+
227
241
  [[package]]
228
242
  name = "hyper"
229
243
  version = "1.10.1"
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "foghttp"
3
- version = "0.3.7"
3
+ version = "0.3.8"
4
4
  description = "Observable Rust-powered HTTP client for Python services."
5
5
  edition = "2021"
6
6
  homepage = "https://github.com/AmberFog/foghttp"
@@ -20,8 +20,10 @@ extension-module = ["pyo3/extension-module"]
20
20
  [dependencies]
21
21
  brotli = "8.0.4"
22
22
  bytes = "1.12.0"
23
+ fastrand = "2.3.0"
23
24
  flate2 = "1.1.9"
24
25
  http-body-util = "0.1.3"
26
+ httpdate = "1.0.3"
25
27
  url = "2.5.8"
26
28
 
27
29
  [dependencies.hyper]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: foghttp
3
- Version: 0.3.7
3
+ Version: 0.3.8
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Framework :: AsyncIO
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -74,6 +74,8 @@ try to keep public interfaces stable and avoid unnecessary breaking changes.
74
74
  - typed telemetry event hooks with redacted request/response lifecycle events
75
75
  - versioned telemetry snapshots that separate alert-oriented stats from
76
76
  diagnostic dump APIs
77
+ - opt-in Rust-owned retries with replayability gates and immutable attempt
78
+ traces, plus opt-in per-hop and post-DNS SSRF destination controls
77
79
  - opt-in async lifecycle debug snapshots for staging and tests
78
80
  - lazy process-wide shared Tokio runtime by default, opt-in dedicated runtime
79
81
  tuning, and fail-closed client ownership across `fork()`
@@ -170,6 +172,10 @@ async with foghttp.AsyncClient() as client:
170
172
  response body, and request completion lifecycle
171
173
  - opt-in typed transport policy hooks for lightweight request admission and
172
174
  response-head checks without default-path Python callbacks
175
+ - opt-in Rust-owned retry policy for selected statuses and pre-header network
176
+ failures, with safe methods, replayable bodies, and immutable attempt traces
177
+ - opt-in Rust-owned SSRF destination policy with per-hop allowlists,
178
+ post-resolution IP checks, and DNS rebinding mitigation
173
179
  - versioned telemetry snapshot metadata for `stats()`, `dump_transport_state()`,
174
180
  and `dump_pool_diagnostics()`
175
181
  - opt-in async lifecycle debug mode for active request snapshots, strict leak
@@ -189,6 +195,8 @@ async with foghttp.AsyncClient() as client:
189
195
  - [Timeout model](https://github.com/AmberFog/foghttp/blob/main/docs/timeouts.md)
190
196
  - [Upload typing contracts](https://github.com/AmberFog/foghttp/blob/main/docs/upload-types.md)
191
197
  - [Transport policy hooks](https://github.com/AmberFog/foghttp/blob/main/docs/policy-hooks.md)
198
+ - [Retry policy](https://github.com/AmberFog/foghttp/blob/main/docs/retries.md)
199
+ - [SSRF protection](https://github.com/AmberFog/foghttp/blob/main/docs/ssrf.md)
192
200
  - [Telemetry contract](https://github.com/AmberFog/foghttp/blob/main/docs/telemetry.md)
193
201
  - [Response streaming](https://github.com/AmberFog/foghttp/blob/main/docs/streaming.md)
194
202
  - [Proxy and trust_env](https://github.com/AmberFog/foghttp/blob/main/docs/proxies.md)
@@ -207,7 +215,8 @@ available as bytes/text/line context-managed APIs. Streaming `content=` uploads
207
215
  and multipart `files=` uploads are available with explicit replayability and
208
216
  cleanup rules. HTTP proxy routing and HTTPS proxy `CONNECT` tunnelling are
209
217
  available through `proxy=` and `trust_env=True` when the proxy endpoint itself
210
- uses `http://`.
218
+ uses `http://`. Proxy-routed requests fail closed when `SSRFPolicy` is enabled
219
+ because the client cannot prove which target address a remote proxy resolves.
211
220
  Cookies, auth helpers, HTTP/2, automatic `Accept-Encoding` negotiation,
212
221
  streaming decompression, and per-request connect timeout reconfiguration are
213
222
  planned for later versions. Physical connection caps currently apply to the
@@ -31,6 +31,8 @@ try to keep public interfaces stable and avoid unnecessary breaking changes.
31
31
  - typed telemetry event hooks with redacted request/response lifecycle events
32
32
  - versioned telemetry snapshots that separate alert-oriented stats from
33
33
  diagnostic dump APIs
34
+ - opt-in Rust-owned retries with replayability gates and immutable attempt
35
+ traces, plus opt-in per-hop and post-DNS SSRF destination controls
34
36
  - opt-in async lifecycle debug snapshots for staging and tests
35
37
  - lazy process-wide shared Tokio runtime by default, opt-in dedicated runtime
36
38
  tuning, and fail-closed client ownership across `fork()`
@@ -127,6 +129,10 @@ async with foghttp.AsyncClient() as client:
127
129
  response body, and request completion lifecycle
128
130
  - opt-in typed transport policy hooks for lightweight request admission and
129
131
  response-head checks without default-path Python callbacks
132
+ - opt-in Rust-owned retry policy for selected statuses and pre-header network
133
+ failures, with safe methods, replayable bodies, and immutable attempt traces
134
+ - opt-in Rust-owned SSRF destination policy with per-hop allowlists,
135
+ post-resolution IP checks, and DNS rebinding mitigation
130
136
  - versioned telemetry snapshot metadata for `stats()`, `dump_transport_state()`,
131
137
  and `dump_pool_diagnostics()`
132
138
  - opt-in async lifecycle debug mode for active request snapshots, strict leak
@@ -146,6 +152,8 @@ async with foghttp.AsyncClient() as client:
146
152
  - [Timeout model](https://github.com/AmberFog/foghttp/blob/main/docs/timeouts.md)
147
153
  - [Upload typing contracts](https://github.com/AmberFog/foghttp/blob/main/docs/upload-types.md)
148
154
  - [Transport policy hooks](https://github.com/AmberFog/foghttp/blob/main/docs/policy-hooks.md)
155
+ - [Retry policy](https://github.com/AmberFog/foghttp/blob/main/docs/retries.md)
156
+ - [SSRF protection](https://github.com/AmberFog/foghttp/blob/main/docs/ssrf.md)
149
157
  - [Telemetry contract](https://github.com/AmberFog/foghttp/blob/main/docs/telemetry.md)
150
158
  - [Response streaming](https://github.com/AmberFog/foghttp/blob/main/docs/streaming.md)
151
159
  - [Proxy and trust_env](https://github.com/AmberFog/foghttp/blob/main/docs/proxies.md)
@@ -164,7 +172,8 @@ available as bytes/text/line context-managed APIs. Streaming `content=` uploads
164
172
  and multipart `files=` uploads are available with explicit replayability and
165
173
  cleanup rules. HTTP proxy routing and HTTPS proxy `CONNECT` tunnelling are
166
174
  available through `proxy=` and `trust_env=True` when the proxy endpoint itself
167
- uses `http://`.
175
+ uses `http://`. Proxy-routed requests fail closed when `SSRFPolicy` is enabled
176
+ because the client cannot prove which target address a remote proxy resolves.
168
177
  Cookies, auth helpers, HTTP/2, automatic `Accept-Encoding` negotiation,
169
178
  streaming decompression, and per-request connect timeout reconfiguration are
170
179
  planned for later versions. Physical connection caps currently apply to the
@@ -4,7 +4,7 @@ layout: "home"
4
4
  hero:
5
5
  name: "FogHTTP"
6
6
  text: "Rust-powered HTTP client for Python"
7
- tagline: "Buffered JSON and form requests, streaming and multipart uploads, sync and async response streaming, transparent response decoding, base URL clients, default headers and params, sync and async APIs, redirects, custom CA certificates, cancellation, and observable request limits with pool diagnostics."
7
+ tagline: "Buffered JSON and form requests, streaming and multipart uploads, sync and async response streaming, transparent response decoding, base URL clients, default headers and params, opt-in safe retries and SSRF destination controls, redirects, custom CA certificates, cancellation, and observable request limits with pool diagnostics."
8
8
 
9
9
  features:
10
10
  - title: "Rust transport"
@@ -62,6 +62,10 @@ FogHTTP is designed around a few engineering priorities:
62
62
  events
63
63
  - opt-in typed transport policy hooks for lightweight request admission and
64
64
  response-head checks, with Rust-owned redirect safety
65
+ - opt-in Rust-owned retry policy with safe-method defaults, replayability
66
+ gating, bounded backoff, typed decisions, and immutable attempt traces
67
+ - opt-in Rust-owned SSRF destination policy with per-hop allowlists,
68
+ post-resolution IP checks, and DNS rebinding mitigation
65
69
  - versioned telemetry snapshots that separate alert-oriented stats from
66
70
  diagnostic dump APIs
67
71
  - opt-in async lifecycle debug snapshots for tests, staging, and incident
@@ -79,6 +83,8 @@ try to keep public interfaces stable and avoid unnecessary breaking changes.
79
83
  - [Timeout model](./timeouts.md)
80
84
  - [Upload typing contracts](./upload-types.md)
81
85
  - [Transport policy hooks](./policy-hooks.md)
86
+ - [Retry policy](./retries.md)
87
+ - [SSRF protection](./ssrf.md)
82
88
  - [Telemetry contract](./telemetry.md)
83
89
  - [Response streaming](./streaming.md)
84
90
  - [TLS trust](./tls.md)
@@ -98,6 +104,9 @@ try to keep public interfaces stable and avoid unnecessary breaking changes.
98
104
  - cancellable buffered async requests
99
105
  - bounded sync and async response streaming
100
106
  - prepared requests that can be inspected before sending
107
+ - opt-in safe retries with request-scoped attempt diagnostics
108
+ - direct service clients that need an opt-in SSRF guard for partially trusted
109
+ destination URLs
101
110
  - simple benchmarks against other buffered HTTP clients
102
111
 
103
112
  ## Key Features
@@ -136,6 +145,10 @@ try to keep public interfaces stable and avoid unnecessary breaking changes.
136
145
  response body, and request completion lifecycle
137
146
  - opt-in typed transport policy hooks with immutable request/response views and
138
147
  no default-path Python callback
148
+ - opt-in retry policy for selected statuses and pre-header network failures,
149
+ with safe methods, replayable bodies, and immutable attempt traces
150
+ - opt-in SSRF destination policy that validates initial and redirected targets,
151
+ then pins each connection attempt to its checked DNS result
139
152
  - versioned telemetry snapshot metadata for `stats()`, `dump_transport_state()`,
140
153
  and `dump_pool_diagnostics()`
141
154
  - opt-in async lifecycle debug mode for active request snapshots and strict
@@ -55,6 +55,12 @@ try to keep public interfaces stable and avoid unnecessary breaking changes.
55
55
  response body, and request completion lifecycle
56
56
  - opt-in synchronous transport policy hooks with immutable request/response
57
57
  snapshots and Rust-owned redirect safety
58
+ - opt-in retry policy for selected statuses and pre-header network failures,
59
+ gated by method safety and request-body replayability, with immutable
60
+ request-scoped attempt traces on responses and terminal `FogHTTPError`
61
+ - opt-in SSRF destination policy with scheme/origin/domain allowlists,
62
+ per-redirect checks, post-resolution address validation, and typed redacted
63
+ `SSRFError` reasons
58
64
  - opt-in async lifecycle debug snapshots for active async request handles,
59
65
  pending transport pressure, strict test checks, and unclosed-client context
60
66
  - default per-response and aggregate buffered response memory limits
@@ -99,6 +105,8 @@ try to keep public interfaces stable and avoid unnecessary breaking changes.
99
105
  | socket lifecycle telemetry granularity | `TransportStats` and `dump_transport_state()["origins"]` expose opened, open-failed, closed, reused, aborted, idle-timeout eviction, active, and idle tracked connection counters for the current HTTP/1 path; dedicated failed-reuse and close-reason taxonomy are not exposed yet because current connector hooks do not provide a stable reason signal |
100
106
  | telemetry hook granularity | `TelemetryConfig` currently dispatches Python-level request/response lifecycle events; lower-level Rust pool acquire and connection lifecycle event delivery is planned before Prometheus/OpenTelemetry exporters |
101
107
  | transport policy hook execution | `TransportPolicyHooks` callbacks are synchronous, inline, non-reentrant, and may run on Rust transport worker threads; `after_response_body` observes only redirect bodies consumed internally, not the final response body returned to the caller |
108
+ | retry scope | Retry is client-level and opt-in. It covers configured response statuses and pre-header `NetworkError` only; response-body errors, FogHTTP timeouts, local upload-provider failures, auth refresh, hedging, and circuit breaking are not retried. |
109
+ | SSRF protection scope | `SSRFPolicy` is client-level and opt-in. It validates initial and redirected destinations plus every resolved address, but it is not a replacement for network egress policy. Proxy routes fail closed because a remote proxy can resolve the target independently. |
102
110
  | diagnostic snapshot transactionality | `stats()`, `dump_transport_state()`, and `dump_pool_diagnostics()` include `schema_version` and a monotonic `snapshot_sequence`, but the `dump_*` APIs remain diagnostic snapshots rather than lock-protected SLA transactions; use `stats()` for alert-oriented low-cardinality metrics |
103
111
 
104
112
  ## Practical Guidance
@@ -116,6 +124,8 @@ Use FogHTTP today when:
116
124
  - async request cancellation and sync/async stream cleanup behavior are useful
117
125
  - global/per-origin request-slot backpressure and opt-in global/per-host
118
126
  physical connection caps are enough for your resource control needs
127
+ - you accept partially trusted destination URLs and can use direct connections
128
+ with an explicit client-level `SSRFPolicy`
119
129
  - you can reuse clients instead of creating many short-lived transport and pool
120
130
  instances once requests start flowing
121
131
 
@@ -123,6 +133,8 @@ Wait before using FogHTTP when:
123
133
 
124
134
  - you need transparent streaming decompression
125
135
  - you need SOCKS, PAC, WPAD, or platform proxy discovery
136
+ - you require proxy routing and application-layer SSRF protection on the same
137
+ client; enforce destination policy at the proxy or network egress boundary
126
138
  - you rely on cookies across requests
127
139
  - you need per-request connect timeout reconfiguration
128
140
  - you need automatic compression negotiation instead of manual
@@ -132,12 +144,15 @@ Wait before using FogHTTP when:
132
144
 
133
145
  ## Error Surface
134
146
 
135
- Network and protocol failures map to `RequestError`. Pool acquire timeout and
147
+ Pre-header transport failures map to `NetworkError`, a `RequestError` subtype;
148
+ local request-provider and other request failures remain `RequestError`. Pool acquire timeout and
136
149
  queue-full conditions map to `PoolTimeout`. Response body progress timeout maps
137
150
  to `ReadTimeout` for buffered responses and streamed body chunks. Buffered and
138
151
  streamed request body write progress timeout maps to `WriteTimeout`. The broader
139
152
  buffered transport deadline maps to the base `TimeoutError` with phase-aware
140
153
  diagnostics; for streaming responses it covers acquire, redirects, and response
141
- headers before the stream is returned. Dedicated connect timeout exception mapping is
142
- reserved for later timeout work. See
154
+ headers before the stream is returned. An enabled SSRF policy raises
155
+ `SSRFError` with a stable `SSRFViolationReason` before a blocked destination is
156
+ sent. Dedicated connect timeout exception mapping is reserved for later timeout
157
+ work. See
143
158
  [Timeout model](./timeouts.md) for the current behavior.
@@ -47,13 +47,14 @@ or replace transport state.
47
47
 
48
48
  | Hook | Ordering and scope |
49
49
  |---|---|
50
- | `before_send` | Runs for the initial request and every redirect hop after Rust has selected and validated the transport route, but before request-slot acquire. |
51
- | `on_response_headers` | Runs for every response after Rust has classified any redirect action and before FogHTTP consumes or returns the response body. |
50
+ | `before_send` | Runs for the initial request, every retry attempt, and every redirect hop after Rust has selected and validated the transport route, but before request-slot acquire. |
51
+ | `on_response_headers` | Runs for every response attempt after Rust has classified any redirect action and before FogHTTP consumes or returns the response body. |
52
52
  | `after_response_body` | Runs only for redirect response bodies consumed internally by FogHTTP. Rust first validates the redirect limit, replayability, scheme downgrade, header policy, and proxy boundary; the hook runs before the already validated mutation is applied. It does not run for the final body returned to the caller. |
53
53
 
54
- There is deliberately no error, timeout, or cancellation hook. Those stages
55
- remain unavailable until FogHTTP has a Rust-owned failure taxonomy and a real
56
- retry-policy consumer.
54
+ There is deliberately no public error, timeout, cancellation, or retry-decision
55
+ hook. The built-in retry policy uses a Rust-owned pre-header network-error
56
+ classification and exposes decisions through typed telemetry instead of
57
+ calling Python policy code from failure paths.
57
58
 
58
59
  ## Snapshot Contract
59
60
 
@@ -7,8 +7,9 @@ For `https://` targets, FogHTTP opens a `CONNECT` tunnel to the proxy and then
7
7
  performs the TLS handshake against the **target** host over that tunnel, so the
8
8
  certificate is validated for the target origin, not the proxy. If the tunnel
9
9
  cannot be established — proxy authentication failure, a non-2xx `CONNECT`
10
- status, or the proxy closing the tunnel early — FogHTTP raises `RequestError`
11
- instead of silently falling back to a direct connection.
10
+ status, or the proxy closing the tunnel early — FogHTTP raises `NetworkError`
11
+ (a `RequestError` subtype) instead of silently falling back to a direct
12
+ connection.
12
13
 
13
14
  ## Explicit Proxy
14
15
 
@@ -61,7 +62,7 @@ Host: api.internal:443
61
62
  TLS is validated against the **target** host using the same `TLSConfig` rules as
62
63
  a direct connection; the proxy never terminates TLS and cannot impersonate the
63
64
  target. A failed tunnel (`CONNECT` non-2xx, proxy auth failure, or early close)
64
- maps to a stable `RequestError`, releases the request slot, and does not return
65
+ maps to a stable `NetworkError`, releases the request slot, and does not return
65
66
  a poisoned connection to the pool. The tunnelled request itself is sent in
66
67
  origin-form, exactly like a direct HTTPS request.
67
68
 
@@ -193,10 +194,18 @@ FogHTTP intentionally does not expose a `verify=False` compatibility mode and
193
194
  does not honor environment variables that disable certificate verification.
194
195
  Use explicit `TLSConfig` for custom CA bundles and custom-only trust.
195
196
 
197
+ ## SSRF Policy Compatibility
198
+
199
+ Requests that select a proxy route fail closed when `SSRFPolicy` is enabled.
200
+ Forward and `CONNECT` proxies can resolve the target hostname remotely, so the
201
+ client cannot guarantee that its locally checked DNS result is the address
202
+ used by the proxy. See [SSRF protection](./ssrf.md) for the trust boundary and
203
+ recommended network-layer controls.
204
+
196
205
  ## Not Implemented Yet
197
206
 
198
207
  - SOCKS5/SOCKS5h
199
208
  - TLS-to-proxy endpoints (`https://proxy.example:443`)
200
209
  - PAC/WPAD or platform/browser proxy discovery
201
210
  - per-route proxy policies
202
- - proxy retry policy
211
+ - proxy failover, rotation, or per-route policy
@@ -73,9 +73,11 @@ seam does not mutate response status, headers, or body content.
73
73
  Policy diagnostics may include a normalized origin, but must not include URL
74
74
  userinfo, path, query parameters, or fragments.
75
75
 
76
- Error and timeout policy stages are intentionally absent until the retry work
77
- defines a Rust-owned failure taxonomy. Core policy code must not accept or
78
- return `PyErr` merely to reserve a future hook.
76
+ The built-in retry stage owns a narrow Rust failure taxonomy: eligible network
77
+ failures occur before response headers and exclude timeout, connection-acquire,
78
+ and user request-body provider errors. Retry decisions remain typed core values;
79
+ core policy code does not accept or return `PyErr`. The PyO3 adapter maps final
80
+ errors and carries structured retry decisions to optional Python telemetry.
79
81
 
80
82
  The PyO3 bridge lives outside `src/core/policy/`. It invokes only callbacks
81
83
  resolved when `RawClient` is created, rejects non-`None` callback returns, and
@@ -64,9 +64,10 @@ sniff the body or invent a media type. `Accept-Query` response headers are
64
64
  available through the normal case-insensitive `response.headers` interface;
65
65
  FogHTTP does not yet parse that Structured Field value.
66
66
 
67
- RFC 10008 classifies QUERY as safe and idempotent. FogHTTP records the method
68
- name in request metadata and telemetry, but does not currently provide an
69
- automatic retry policy or an HTTP cache. RFC 10008 permits QUERY responses to
67
+ RFC 10008 classifies QUERY as safe and idempotent. FogHTTP therefore includes
68
+ it in the default method set of the opt-in [retry policy](./retries.md), but a
69
+ body-bearing QUERY is eligible only when its provider is replayable. FogHTTP
70
+ does not currently provide an HTTP cache. RFC 10008 permits QUERY responses to
70
71
  be cached, but a QUERY cache key must incorporate the request content and
71
72
  related metadata, including `Content-Type`; a URL-only GET-style cache key is
72
73
  not valid for QUERY.
@@ -0,0 +1,224 @@
1
+ # Retry Policy
2
+
3
+ FogHTTP provides an opt-in, client-level retry policy for transient response
4
+ statuses and network failures before response headers arrive. The default
5
+ client does not enable this policy.
6
+
7
+ ```python
8
+ import foghttp
9
+
10
+
11
+ retry = foghttp.RetryPolicy(
12
+ retries=2,
13
+ backoff=0.1,
14
+ jitter=0.1,
15
+ )
16
+
17
+ with foghttp.Client(retry=retry) as client:
18
+ response = client.get("https://api.example.com/items")
19
+ ```
20
+
21
+ `retries` is the number of additional sends allowed by retry decisions across
22
+ one logical request. With no redirects, a policy with `retries=2` can therefore
23
+ make at most three attempts; redirect hops are bounded separately by
24
+ `max_redirects`. The same policy contract is available on `Client` and
25
+ `AsyncClient`, including buffered and streaming response entry points. For a
26
+ streaming response, retries finish before the response object is exposed;
27
+ failures while the caller consumes the returned response body are not retried.
28
+
29
+ ## Defaults
30
+
31
+ `RetryPolicy()` uses these defaults:
32
+
33
+ | Option | Default | Meaning |
34
+ |---|---:|---|
35
+ | `retries` | `2` | Additional attempts after the initial send. |
36
+ | `backoff` | `0.1` | Base exponential delay in seconds. |
37
+ | `jitter` | `0.1` | Maximum random delay added to each backoff, in seconds. |
38
+ | `retry_on.statuses` | `429`, `502`, `503`, `504` | Response statuses eligible for retry. |
39
+ | `retry_on.exceptions` | `NetworkError` | Pre-header transport failure eligible for retry. |
40
+ | `methods` | `GET`, `HEAD`, `OPTIONS`, `QUERY`, `TRACE` | Methods eligible for automatic retry. |
41
+
42
+ The delay before retry number `n`, starting at zero, is
43
+ `backoff * 2**n + uniform(0, jitter)`. A valid `Retry-After` delta or HTTP date
44
+ on a retryable response is honored as a minimum delay. Backoff and response
45
+ draining remain inside the request's shared `Timeouts.total` budget, including
46
+ any redirect hops in the same logical request. Malformed `Retry-After` values
47
+ are ignored, and accepted server delays are capped by the same duration ceiling
48
+ as local numeric options.
49
+
50
+ `RetryConditions` makes triggers explicit:
51
+
52
+ ```python
53
+ conditions = foghttp.RetryConditions(
54
+ statuses=(429, 503),
55
+ exceptions=(foghttp.NetworkError,),
56
+ )
57
+
58
+ retry = foghttp.RetryPolicy(
59
+ retries=3,
60
+ backoff=0.2,
61
+ jitter=0.05,
62
+ retry_on=conditions,
63
+ )
64
+ ```
65
+
66
+ Use an empty tuple to disable a trigger category. The current exception
67
+ contract supports `NetworkError` only; local upload-provider failures and
68
+ FogHTTP timeout exceptions are not classified as retryable network failures.
69
+ Response-body failures after headers are also not retried.
70
+
71
+ ## Method And Body Safety
72
+
73
+ `POST` is deliberately absent from the default method set. This prevents an
74
+ automatic retry from duplicating a side effect. Applications can explicitly
75
+ replace `methods`, but they then own the endpoint's idempotency guarantee:
76
+
77
+ ```python
78
+ retry = foghttp.RetryPolicy(methods=("GET", "PUT", "POST"))
79
+ ```
80
+
81
+ Method eligibility is necessary but not sufficient. A non-empty request body
82
+ must also be replayable:
83
+
84
+ | Body source | Replayable |
85
+ |---|---|
86
+ | `bytes`, `str`, `json=`, encoded `data=` | Yes |
87
+ | bytes-like multipart parts | Yes |
88
+ | zero-argument stream or multipart factory | Yes, if it returns equivalent fresh content |
89
+ | direct iterator, async iterator, or file-like `content=` | No |
90
+ | direct file or stream multipart part | No |
91
+
92
+ RFC 10008 classifies `QUERY` as safe and idempotent, so it is enabled by
93
+ default. A body-bearing QUERY is still retried only when its provider is
94
+ replayable. If a matching response or network failure occurs with a
95
+ non-replayable body, FogHTTP returns the response or raises the original error
96
+ without a second send and records `block_non_replayable` with reason
97
+ `non_replayable_body`.
98
+
99
+ There is no public `body_replayable=True` escape hatch. Use a zero-argument
100
+ factory when a stream can be recreated safely for every attempt.
101
+
102
+ ## Ordering And Resources
103
+
104
+ Retry runs inside the Rust transport policy pipeline. Redirect classification
105
+ has priority for a response that is both a redirect and listed in retry
106
+ statuses. Each new retry attempt reruns route selection and lightweight
107
+ `before_send`/`on_response_headers` policy hooks.
108
+
109
+ Before retrying a status response, FogHTTP drains its body under the configured
110
+ read and total deadlines. A clean keep-alive connection can then return to the
111
+ pool. A connection that fails before headers is not reused. The request slot is
112
+ released before backoff, so sleeping retries do not occupy active transport
113
+ capacity. Cancelling an async request cancels its pending backoff and releases
114
+ the logical request lifecycle.
115
+
116
+ ## Observability
117
+
118
+ A request made by a client with `RetryPolicy` exposes one immutable,
119
+ request-scoped `RetryTrace` when transport execution returns a buffered or
120
+ streaming response, or raises a terminal `FogHTTPError`. Responses provide it
121
+ as `response.retry_trace`; terminal `FogHTTPError` instances provide the same
122
+ property. Errors raised before native transport execution are outside this
123
+ contract. A client without a retry policy returns `None`, so the default path
124
+ does not collect attempt history or allocate terminal trace values.
125
+
126
+ ```python
127
+ try:
128
+ response = client.get("https://api.example.com/items")
129
+ except foghttp.FogHTTPError as error:
130
+ trace = error.retry_trace
131
+ else:
132
+ trace = response.retry_trace
133
+
134
+ if trace is not None:
135
+ for attempt in trace.attempts:
136
+ print(attempt.attempt, attempt.decision, attempt.reason)
137
+ ```
138
+
139
+ `RetryTrace` contains:
140
+
141
+ | Field | Meaning |
142
+ |---|---|
143
+ | `attempts` | Ordered immutable tuple, bounded to at most `retries + 1` entries. |
144
+ | `outcome` | `response` when the transport returned a response object, or `error` when it raised. |
145
+ | `status_code` | Final response status, otherwise `None`. |
146
+ | `error_type` | Diagnostic name of the final public exception class, otherwise `None`. |
147
+ | `elapsed` | Total logical-request time in seconds through the returned response or error. |
148
+
149
+ Each `RetryAttempt` represents one retry-policy execution cycle inside the
150
+ native transport, not one socket send or server-observed request. Redirect hops
151
+ remain within the same retry attempt and rerun route selection, the
152
+ `before_send` hook and request-slot/connection acquisition. An attempt can
153
+ therefore end with a policy or acquire error before a connection sends any
154
+ request bytes.
155
+
156
+ An attempt contains the 1-based `attempt`, normalized `method`, credential-free
157
+ `origin`, zero-based `redirect_hop`, optional `status_code` and `error_type`,
158
+ typed `decision` and `reason`, selected `backoff` in seconds, optional cumulative
159
+ `decision_elapsed` seconds when the retry decision was committed by the
160
+ transport, and cumulative `completed_elapsed` seconds when that execution
161
+ attempt ended. All elapsed values are measured from the start of the logical
162
+ request, not from the start of an individual attempt. A buffered attempt can
163
+ contain both a status and a later body-read error. The final retry execution
164
+ attempt is always present. Its `decision` and `reason` are `None` when that
165
+ attempt did not trigger retry policy; a terminal method stop, replayability
166
+ block or exhaustion retains its typed decision and reason.
167
+
168
+ `error_type` follows the corresponding public exception class name and is a
169
+ diagnostic field rather than a separate error-category enum. When class-name
170
+ comparison is needed, prefer `foghttp.NetworkError.__name__` over a repeated
171
+ string literal. `backoff` is the delay selected by policy, not a measurement of
172
+ time actually slept; a timeout or cancellation can end the wait early.
173
+
174
+ A logical request can fail after its latest transport attempt has completed.
175
+ For example, a total timeout during retry backoff is reported by
176
+ `RetryTrace.error_type` and `RetryTrace.elapsed`; it does not overwrite the
177
+ completed status or network result of the preceding attempt.
178
+
179
+ `RetryTraceOutcome.RESPONSE` means that request execution produced a response;
180
+ it does not classify an HTTP status as successful. For streaming responses the
181
+ trace is complete when response headers are exposed, because body-consumption
182
+ failures are outside the retry scope and do not mutate the immutable trace.
183
+ `HTTPStatusError` preserves the trace of its response.
184
+
185
+ FogHTTP preserves the original terminal request error if CPython cannot
186
+ allocate or attach the native trace handoff object. That exceptional attachment
187
+ failure is reported through `sys.unraisablehook`; the error then has no trace
188
+ rather than being replaced by an observability error.
189
+
190
+ Trace values never include a request path, query, headers, body, credentials or
191
+ userinfo. They retain only the normalized origin and typed operational fields,
192
+ so their default representation is safe for diagnostics.
193
+
194
+ When telemetry is enabled and the native request returns or raises, each retry
195
+ decision emits a typed `TelemetryEventType.RETRY_DECISION` event with:
196
+
197
+ - `retry_attempt`, starting at `1` for the failed initial attempt;
198
+ - `status_code` or `error_type`;
199
+ - `retry_decision`: `retry`, `stop`, or `block_non_replayable`;
200
+ - `retry_reason`: `status`, `network_error`, `method_not_allowed`,
201
+ `non_replayable_body`, or `retries_exhausted`;
202
+ - `retry_backoff_ns` and `elapsed_ns`;
203
+ - normalized method and origin, without request path, query, headers, or body.
204
+
205
+ The public trace and telemetry events are derived from the same native attempt
206
+ records; terminal attempts without a retry decision do not emit a
207
+ `retry_decision` event. The final `request_finished` event still reports the
208
+ logical request outcome. Native records are delivered when the transport
209
+ returns or raises, not as live callbacks during backoff.
210
+ `RetryAttempt.decision` and `RetryAttempt.reason` intentionally reuse
211
+ `TelemetryRetryDecision` and `TelemetryRetryReason` as the shared public retry
212
+ vocabulary; telemetry is a projection of the same decision records rather than
213
+ a separate enum contract.
214
+ For a `retry_decision` event, `elapsed_ns` is derived from
215
+ `RetryAttempt.decision_elapsed`, and `status_code`/`error_type` describe the
216
+ trigger seen when that decision was committed. A later buffered-body error can
217
+ therefore appear on the state-oriented `RetryAttempt` without rewriting the
218
+ earlier decision event.
219
+
220
+ Cancelling an async caller can abort the native task before a response or
221
+ exception is returned. `asyncio.CancelledError` therefore does not manufacture
222
+ a partial `retry_trace`, and buffered retry decisions, including the decision
223
+ that selected a cancelled backoff, are not emitted to the Python sink. There is
224
+ no global retry-trace history.