eggfetch 0.1.0__tar.gz → 0.1.3__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 (256) hide show
  1. {eggfetch-0.1.0 → eggfetch-0.1.3}/Cargo.lock +34 -13
  2. {eggfetch-0.1.0 → eggfetch-0.1.3}/Cargo.toml +2 -1
  3. eggfetch-0.1.3/PKG-INFO +392 -0
  4. {eggfetch-0.1.0/crates/eggfetch-core → eggfetch-0.1.3}/README.md +101 -14
  5. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/Cargo.toml +24 -8
  6. {eggfetch-0.1.0/crates/eggfetch-python → eggfetch-0.1.3/crates/eggfetch-core}/README.md +101 -14
  7. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/body.rs +447 -11
  8. eggfetch-0.1.3/crates/eggfetch-core/src/client.rs +1607 -0
  9. eggfetch-0.1.3/crates/eggfetch-core/src/compression.rs +1400 -0
  10. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/cookie.rs +416 -119
  11. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/error.rs +10 -1
  12. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/headers.rs +158 -6
  13. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/http_version.rs +1 -0
  14. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/lib.rs +14 -3
  15. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/limits.rs +87 -7
  16. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/multipart.rs +294 -38
  17. eggfetch-0.1.3/crates/eggfetch-core/src/network_stream.rs +611 -0
  18. eggfetch-0.1.3/crates/eggfetch-core/src/pipeline.rs +2338 -0
  19. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/pool.rs +494 -89
  20. eggfetch-0.1.3/crates/eggfetch-core/src/proxy.rs +1801 -0
  21. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/redact.rs +8 -10
  22. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/redirect.rs +128 -30
  23. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/request.rs +281 -33
  24. eggfetch-0.1.3/crates/eggfetch-core/src/response.rs +934 -0
  25. eggfetch-0.1.3/crates/eggfetch-core/src/response_decode.rs +170 -0
  26. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/retry.rs +154 -40
  27. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/stream/read_timeout.rs +39 -10
  28. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/stream/write_timeout.rs +70 -12
  29. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/timeout.rs +8 -7
  30. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/tls.rs +529 -103
  31. eggfetch-0.1.3/crates/eggfetch-core/src/trace.rs +368 -0
  32. eggfetch-0.1.3/crates/eggfetch-core/src/transport/alt_svc.rs +1131 -0
  33. eggfetch-0.1.3/crates/eggfetch-core/src/transport/connect.rs +587 -0
  34. eggfetch-0.1.3/crates/eggfetch-core/src/transport/direct.rs +496 -0
  35. eggfetch-0.1.3/crates/eggfetch-core/src/transport/direct_connector.rs +616 -0
  36. eggfetch-0.1.3/crates/eggfetch-core/src/transport/http3.rs +1572 -0
  37. eggfetch-0.1.3/crates/eggfetch-core/src/transport/metrics.rs +543 -0
  38. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/transport/mod.rs +25 -0
  39. eggfetch-0.1.3/crates/eggfetch-core/src/transport/proxy.rs +1328 -0
  40. eggfetch-0.1.3/crates/eggfetch-core/src/transport/socks.rs +784 -0
  41. eggfetch-0.1.3/crates/eggfetch-core/src/transport/uds.rs +270 -0
  42. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/adverse_tests.rs +17 -12
  43. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/cross_feature_tests.rs +52 -0
  44. eggfetch-0.1.3/crates/eggfetch-core/tests/direct_transport_tests.rs +514 -0
  45. eggfetch-0.1.3/crates/eggfetch-core/tests/h3_alt_svc_discovery.rs +935 -0
  46. eggfetch-0.1.3/crates/eggfetch-core/tests/h3_hardening.rs +536 -0
  47. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/h3_integration.rs +1 -1
  48. eggfetch-0.1.3/crates/eggfetch-core/tests/h3_interop_qualification.rs +937 -0
  49. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/http2_tests.rs +35 -0
  50. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/integration.rs +1 -1
  51. eggfetch-0.1.3/crates/eggfetch-core/tests/network_stream_tests.rs +695 -0
  52. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/pool_tests.rs +50 -0
  53. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/proxy_tests.rs +691 -8
  54. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/retry_integration.rs +135 -1
  55. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/tls_fixtures.rs +13 -0
  56. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/tls_integration.rs +42 -0
  57. eggfetch-0.1.3/crates/eggfetch-core/tests/trailer_tests.rs +208 -0
  58. eggfetch-0.1.3/crates/eggfetch-core/tests/transport_metrics_tests.rs +254 -0
  59. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/Cargo.toml +10 -3
  60. eggfetch-0.1.3/crates/eggfetch-python/README.md +367 -0
  61. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/async_client.rs +213 -56
  62. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/client.rs +315 -66
  63. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/conversion.rs +191 -42
  64. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/cookies.rs +14 -2
  65. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/errors.rs +3 -0
  66. eggfetch-0.1.3/crates/eggfetch-python/src/extensions.rs +158 -0
  67. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/headers.rs +22 -30
  68. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/lib.rs +16 -8
  69. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/limits.rs +9 -2
  70. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/multipart.rs +1 -1
  71. eggfetch-0.1.3/crates/eggfetch-python/src/network_stream.rs +847 -0
  72. eggfetch-0.1.3/crates/eggfetch-python/src/proxy.rs +177 -0
  73. eggfetch-0.1.3/crates/eggfetch-python/src/response.rs +577 -0
  74. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/retry.rs +14 -0
  75. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/streaming.rs +345 -163
  76. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/timeout.rs +18 -6
  77. eggfetch-0.1.3/crates/eggfetch-python/src/tls.rs +270 -0
  78. eggfetch-0.1.3/crates/eggfetch-python/src/trace_bridge.rs +253 -0
  79. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/fixtures.py +8 -0
  80. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/native_fixtures.py +935 -0
  81. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_auth.py +87 -7
  82. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_auth_input_normalization.py +184 -0
  83. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_client.py +4 -1
  84. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_client_mutability_and_state.py +318 -0
  85. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_client_stream_overrides.py +142 -0
  86. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_config_objects.py +98 -4
  87. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_cookie_scope_parity.py +273 -0
  88. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_cookies.py +40 -17
  89. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_corrective_01_tls_and_proxy_trust_safety.py +449 -0
  90. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_corrective_01_tls_network_proof.py +368 -0
  91. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_corrective_02_extensions_and_wire_metadata.py +364 -0
  92. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_corrective_03_network_stream_upgrade.py +798 -0
  93. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_corrective_kernel.py +375 -0
  94. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_environment.py +56 -5
  95. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_exceptions.py +56 -10
  96. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_extensions.py +84 -22
  97. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_h2_differential.py +647 -0
  98. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_headers.py +92 -2
  99. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_hook_auth_ordering.py +70 -30
  100. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_hook_cookie_auth_ordering.py +230 -0
  101. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_hooks.py +91 -6
  102. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_httpx2_api_parity.py +186 -0
  103. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_httpx2_behavior.py +96 -0
  104. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_httpx2_sse.py +119 -0
  105. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_httpx2_websocket.py +209 -0
  106. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_httpx_reference_pinning.py +173 -0
  107. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_lossy_conversions.py +13 -4
  108. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_merge_matrix.py +4 -1
  109. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_mounts.py +175 -12
  110. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_multihop_cleanup.py +178 -0
  111. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_native_proxy_tls.py +255 -1
  112. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_native_timeout_classification.py +37 -42
  113. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_no_proxy_differential.py +429 -0
  114. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_protocol_and_unsupported_options.py +169 -0
  115. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_proxy_differential.py +153 -0
  116. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_proxy_phase05_tracks.py +461 -0
  117. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_raw_stream_httpx_differential.py +638 -0
  118. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_raw_stream_lifecycle.py +102 -0
  119. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_redirect_state_machine_parity.py +477 -0
  120. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_request.py +7 -6
  121. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_request_construction_parity.py +215 -0
  122. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_request_stream_state.py +138 -0
  123. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_request_streaming.py +5 -3
  124. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_response.py +50 -4
  125. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_response_encoding_parity.py +70 -0
  126. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_response_metadata_parity.py +111 -0
  127. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_response_status_and_redirect_state.py +151 -0
  128. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_response_stream_state_parity.py +199 -0
  129. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_response_streaming.py +5 -6
  130. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_socks_transport.py +301 -0
  131. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_ssl_context_network_proof.py +672 -0
  132. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_ssl_context_translation.py +412 -0
  133. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_stream_resources.py +28 -2
  134. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_timeout_proxysis.py +13 -12
  135. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_timeout_reference_differential.py +119 -0
  136. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_top_level_helpers_parity.py +366 -0
  137. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_trace_detection.py +131 -0
  138. eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_uds_transport.py +233 -0
  139. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_url_query.py +104 -1
  140. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_async.py +7 -0
  141. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_http2.py +8 -0
  142. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_response_compat.py +3 -1
  143. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_retry.py +14 -0
  144. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_sync.py +60 -0
  145. {eggfetch-0.1.0 → eggfetch-0.1.3}/pyproject.toml +8 -3
  146. eggfetch-0.1.3/python/eggfetch/compat/httpx/__init__.py +651 -0
  147. {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_asgi.py +2 -1
  148. {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_auth.py +19 -14
  149. eggfetch-0.1.3/python/eggfetch/compat/httpx/_client.py +2622 -0
  150. eggfetch-0.1.3/python/eggfetch/compat/httpx/_cookies.py +265 -0
  151. {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_diagnostics.py +14 -1
  152. {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_exceptions.py +15 -3
  153. {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_headers.py +34 -13
  154. {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_mock.py +8 -3
  155. eggfetch-0.1.3/python/eggfetch/compat/httpx/_proxy.py +113 -0
  156. eggfetch-0.1.3/python/eggfetch/compat/httpx/_request.py +443 -0
  157. eggfetch-0.1.3/python/eggfetch/compat/httpx/_response.py +782 -0
  158. eggfetch-0.1.3/python/eggfetch/compat/httpx/_ssl_context.py +531 -0
  159. eggfetch-0.1.3/python/eggfetch/compat/httpx/_status_codes.py +74 -0
  160. {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_stream.py +25 -19
  161. eggfetch-0.1.3/python/eggfetch/compat/httpx/_timeout.py +166 -0
  162. {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_transports.py +86 -62
  163. {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_urls.py +38 -5
  164. {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_wsgi.py +2 -1
  165. eggfetch-0.1.3/python/eggfetch/compat/httpx2/__init__.py +257 -0
  166. eggfetch-0.1.3/python/eggfetch/compat/httpx2/_alias.py +79 -0
  167. eggfetch-0.1.3/python/eggfetch/compat/httpx2/_api.py +220 -0
  168. eggfetch-0.1.3/python/eggfetch/compat/httpx2/_asgi.py +7 -0
  169. eggfetch-0.1.3/python/eggfetch/compat/httpx2/_auth.py +40 -0
  170. eggfetch-0.1.3/python/eggfetch/compat/httpx2/_client.py +279 -0
  171. eggfetch-0.1.3/python/eggfetch/compat/httpx2/_config.py +49 -0
  172. eggfetch-0.1.3/python/eggfetch/compat/httpx2/_cookies.py +7 -0
  173. eggfetch-0.1.3/python/eggfetch/compat/httpx2/_exceptions.py +80 -0
  174. eggfetch-0.1.3/python/eggfetch/compat/httpx2/_headers.py +51 -0
  175. eggfetch-0.1.3/python/eggfetch/compat/httpx2/_mock.py +7 -0
  176. eggfetch-0.1.3/python/eggfetch/compat/httpx2/_request.py +7 -0
  177. eggfetch-0.1.3/python/eggfetch/compat/httpx2/_response.py +7 -0
  178. eggfetch-0.1.3/python/eggfetch/compat/httpx2/_sse.py +214 -0
  179. eggfetch-0.1.3/python/eggfetch/compat/httpx2/_status_codes.py +108 -0
  180. eggfetch-0.1.3/python/eggfetch/compat/httpx2/_stream.py +7 -0
  181. eggfetch-0.1.3/python/eggfetch/compat/httpx2/_transports.py +7 -0
  182. eggfetch-0.1.3/python/eggfetch/compat/httpx2/_urls.py +75 -0
  183. eggfetch-0.1.3/python/eggfetch/compat/httpx2/_wsgi.py +7 -0
  184. eggfetch-0.1.3/python/eggfetch/compat/httpx2/websockets/__init__.py +57 -0
  185. eggfetch-0.1.3/python/eggfetch/compat/httpx2/websockets/_api.py +1664 -0
  186. eggfetch-0.1.3/python/eggfetch/compat/httpx2/websockets/_exceptions.py +55 -0
  187. eggfetch-0.1.3/python/eggfetch/compat/httpx2/websockets/_ping.py +43 -0
  188. eggfetch-0.1.3/python/eggfetch/compat/httpx2/websockets/_transport.py +289 -0
  189. eggfetch-0.1.0/PKG-INFO +0 -19
  190. eggfetch-0.1.0/crates/eggfetch-core/src/client.rs +0 -911
  191. eggfetch-0.1.0/crates/eggfetch-core/src/compression.rs +0 -875
  192. eggfetch-0.1.0/crates/eggfetch-core/src/pipeline.rs +0 -872
  193. eggfetch-0.1.0/crates/eggfetch-core/src/proxy.rs +0 -986
  194. eggfetch-0.1.0/crates/eggfetch-core/src/response.rs +0 -472
  195. eggfetch-0.1.0/crates/eggfetch-core/src/response_decode.rs +0 -54
  196. eggfetch-0.1.0/crates/eggfetch-core/src/transport/connect.rs +0 -284
  197. eggfetch-0.1.0/crates/eggfetch-core/src/transport/direct.rs +0 -139
  198. eggfetch-0.1.0/crates/eggfetch-core/src/transport/http3.rs +0 -261
  199. eggfetch-0.1.0/crates/eggfetch-core/src/transport/proxy.rs +0 -418
  200. eggfetch-0.1.0/crates/eggfetch-python/src/proxy.rs +0 -63
  201. eggfetch-0.1.0/crates/eggfetch-python/src/response.rs +0 -354
  202. eggfetch-0.1.0/crates/eggfetch-python/src/tls.rs +0 -54
  203. eggfetch-0.1.0/crates/eggfetch-python/tests/compat/native_fixtures.py +0 -354
  204. eggfetch-0.1.0/python/eggfetch/compat/httpx/__init__.py +0 -231
  205. eggfetch-0.1.0/python/eggfetch/compat/httpx/_client.py +0 -1168
  206. eggfetch-0.1.0/python/eggfetch/compat/httpx/_cookies.py +0 -121
  207. eggfetch-0.1.0/python/eggfetch/compat/httpx/_proxy.py +0 -70
  208. eggfetch-0.1.0/python/eggfetch/compat/httpx/_request.py +0 -292
  209. eggfetch-0.1.0/python/eggfetch/compat/httpx/_response.py +0 -497
  210. eggfetch-0.1.0/python/eggfetch/compat/httpx/_status_codes.py +0 -80
  211. eggfetch-0.1.0/python/eggfetch/compat/httpx/_timeout.py +0 -124
  212. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/auth.rs +0 -0
  213. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/config.rs +0 -0
  214. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/h2_headers.rs +0 -0
  215. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/stream/mod.rs +0 -0
  216. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/transport/connect_timeout.rs +0 -0
  217. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/http3_tests.rs +0 -0
  218. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/resource_stabilization.rs +0 -0
  219. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/test_server.rs +0 -0
  220. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/timeout_tests.rs +0 -0
  221. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/auth.rs +0 -0
  222. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/__init__.py +0 -0
  223. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/conftest.py +0 -0
  224. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_asgi.py +0 -0
  225. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_auth_replay.py +0 -0
  226. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_backends.py +0 -0
  227. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_behavior_cases.py +0 -0
  228. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_downstream_portfolio.py +0 -0
  229. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_downstream_runner_negative.py +0 -0
  230. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_httpx_extras.py +0 -0
  231. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_httpx_required.py +0 -0
  232. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_imports.py +0 -0
  233. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_lifecycle.py +0 -0
  234. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_merge_lossless.py +0 -0
  235. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_mock_transport.py +0 -0
  236. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_oracle_negative.py +0 -0
  237. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_resource_assertions.py +0 -0
  238. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_shutdown.py +0 -0
  239. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_soak.py +0 -0
  240. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_timeout_integration.py +0 -0
  241. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_transports.py +0 -0
  242. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_wsgi.py +0 -0
  243. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/conftest.py +0 -0
  244. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_auth.py +0 -0
  245. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_close_races.py +0 -0
  246. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_cookie_auth.py +0 -0
  247. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_cookies.py +0 -0
  248. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_differential.py +0 -0
  249. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_interpreter_shutdown.py +0 -0
  250. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_parity.py +0 -0
  251. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_proxy.py +0 -0
  252. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_redirects.py +0 -0
  253. {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_streaming.py +0 -0
  254. {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/__init__.py +0 -0
  255. {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/__init__.py +0 -0
  256. {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_limits.py +0 -0
@@ -509,7 +509,7 @@ dependencies = [
509
509
 
510
510
  [[package]]
511
511
  name = "eggfetch-cli"
512
- version = "0.1.0"
512
+ version = "0.1.3"
513
513
  dependencies = [
514
514
  "anyhow",
515
515
  "bytes",
@@ -526,10 +526,11 @@ dependencies = [
526
526
 
527
527
  [[package]]
528
528
  name = "eggfetch-core"
529
- version = "0.1.0"
529
+ version = "0.1.3"
530
530
  dependencies = [
531
531
  "async-compression",
532
532
  "base64",
533
+ "brotli",
533
534
  "bytes",
534
535
  "cookie",
535
536
  "dashmap",
@@ -537,6 +538,7 @@ dependencies = [
537
538
  "futures-core",
538
539
  "futures-util",
539
540
  "getrandom 0.2.17",
541
+ "h2",
540
542
  "h3",
541
543
  "h3-quinn",
542
544
  "http",
@@ -548,24 +550,28 @@ dependencies = [
548
550
  "hyper-rustls",
549
551
  "hyper-util",
550
552
  "pem-rfc7468",
553
+ "percent-encoding",
551
554
  "pin-project-lite",
552
555
  "proptest",
553
556
  "quinn",
554
557
  "rcgen",
555
558
  "rustls",
559
+ "rustls-native-certs",
556
560
  "tempfile",
557
561
  "thiserror",
558
562
  "tokio",
559
563
  "tokio-rustls",
560
564
  "tokio-util",
561
565
  "tower-service",
566
+ "tracing",
562
567
  "url",
563
568
  "webpki-roots 0.26.11",
569
+ "zstd",
564
570
  ]
565
571
 
566
572
  [[package]]
567
573
  name = "eggfetch-ffi"
568
- version = "0.1.0"
574
+ version = "0.1.3"
569
575
  dependencies = [
570
576
  "bytes",
571
577
  "eggfetch-core",
@@ -577,7 +583,7 @@ dependencies = [
577
583
 
578
584
  [[package]]
579
585
  name = "eggfetch-node"
580
- version = "0.1.0"
586
+ version = "0.1.3"
581
587
  dependencies = [
582
588
  "eggfetch-ffi",
583
589
  "napi",
@@ -589,7 +595,7 @@ dependencies = [
589
595
 
590
596
  [[package]]
591
597
  name = "eggfetch-python"
592
- version = "0.1.0"
598
+ version = "0.1.3"
593
599
  dependencies = [
594
600
  "bytes",
595
601
  "eggfetch-core",
@@ -599,8 +605,11 @@ dependencies = [
599
605
  "pyo3",
600
606
  "pyo3-async-runtimes",
601
607
  "pyo3-build-config",
608
+ "rustls",
602
609
  "tokio",
610
+ "tokio-rustls",
603
611
  "url",
612
+ "webpki-roots 0.26.11",
604
613
  ]
605
614
 
606
615
  [[package]]
@@ -631,7 +640,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
631
640
  checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
632
641
  dependencies = [
633
642
  "libc",
634
- "windows-sys 0.61.2",
643
+ "windows-sys 0.52.0",
635
644
  ]
636
645
 
637
646
  [[package]]
@@ -788,9 +797,9 @@ dependencies = [
788
797
 
789
798
  [[package]]
790
799
  name = "h2"
791
- version = "0.4.15"
800
+ version = "0.4.16"
792
801
  source = "registry+https://github.com/rust-lang/crates.io-index"
793
- checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155"
802
+ checksum = "a9f37a958b41b3b19ee2707c06439c0e9e547e847223eb791ecb0cb821c65e27"
794
803
  dependencies = [
795
804
  "atomic-waker",
796
805
  "bytes",
@@ -1102,7 +1111,7 @@ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46"
1102
1111
  dependencies = [
1103
1112
  "hermit-abi",
1104
1113
  "libc",
1105
- "windows-sys 0.61.2",
1114
+ "windows-sys 0.52.0",
1106
1115
  ]
1107
1116
 
1108
1117
  [[package]]
@@ -1617,7 +1626,7 @@ dependencies = [
1617
1626
  "once_cell",
1618
1627
  "socket2",
1619
1628
  "tracing",
1620
- "windows-sys 0.61.2",
1629
+ "windows-sys 0.52.0",
1621
1630
  ]
1622
1631
 
1623
1632
  [[package]]
@@ -1801,7 +1810,7 @@ dependencies = [
1801
1810
  "errno",
1802
1811
  "libc",
1803
1812
  "linux-raw-sys",
1804
- "windows-sys 0.61.2",
1813
+ "windows-sys 0.52.0",
1805
1814
  ]
1806
1815
 
1807
1816
  [[package]]
@@ -2066,7 +2075,7 @@ dependencies = [
2066
2075
  "getrandom 0.4.3",
2067
2076
  "once_cell",
2068
2077
  "rustix",
2069
- "windows-sys 0.61.2",
2078
+ "windows-sys 0.52.0",
2070
2079
  ]
2071
2080
 
2072
2081
  [[package]]
@@ -2227,9 +2236,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
2227
2236
  checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
2228
2237
  dependencies = [
2229
2238
  "pin-project-lite",
2239
+ "tracing-attributes",
2230
2240
  "tracing-core",
2231
2241
  ]
2232
2242
 
2243
+ [[package]]
2244
+ name = "tracing-attributes"
2245
+ version = "0.1.31"
2246
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2247
+ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
2248
+ dependencies = [
2249
+ "proc-macro2",
2250
+ "quote",
2251
+ "syn",
2252
+ ]
2253
+
2233
2254
  [[package]]
2234
2255
  name = "tracing-core"
2235
2256
  version = "0.1.36"
@@ -2428,7 +2449,7 @@ version = "0.1.11"
2428
2449
  source = "registry+https://github.com/rust-lang/crates.io-index"
2429
2450
  checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
2430
2451
  dependencies = [
2431
- "windows-sys 0.61.2",
2452
+ "windows-sys 0.52.0",
2432
2453
  ]
2433
2454
 
2434
2455
  [[package]]
@@ -5,8 +5,9 @@ members = ["crates/eggfetch-core", "crates/eggfetch-python"]
5
5
  [workspace.package]
6
6
  edition = "2021"
7
7
  rust-version = "1.80"
8
- license = "MIT OR Apache-2.0"
8
+ license = "MIT"
9
9
  repository = "https://github.com/eggstack/eggfetch"
10
+ homepage = "https://github.com/eggstack/eggfetch"
10
11
  readme = "README.md"
11
12
 
12
13
  [workspace.lints.rust]
@@ -0,0 +1,392 @@
1
+ Metadata-Version: 2.4
2
+ Name: eggfetch
3
+ Version: 0.1.3
4
+ Classifier: Development Status :: 3 - Alpha
5
+ Classifier: Programming Language :: Python :: 3
6
+ Classifier: Programming Language :: Python :: 3.10
7
+ Classifier: Programming Language :: Python :: 3.11
8
+ Classifier: Programming Language :: Python :: 3.12
9
+ Classifier: Programming Language :: Python :: 3.13
10
+ Classifier: Programming Language :: Rust
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Requires-Dist: pytest>=8.4 ; extra == 'test'
13
+ Requires-Dist: pytest-asyncio>=1.0 ; extra == 'test'
14
+ Provides-Extra: test
15
+ Summary: Python bindings for eggfetch
16
+ Keywords: http,client,httpx,async,rust
17
+ Home-Page: https://github.com/eggstack/eggfetch
18
+ Author: eggfetch contributors
19
+ License: MIT
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
22
+ Project-URL: Homepage, https://github.com/eggstack/eggfetch
23
+ Project-URL: Repository, https://github.com/eggstack/eggfetch
24
+
25
+ # eggfetch
26
+
27
+ [![CI](https://github.com/eggstack/eggfetch/actions/workflows/ci.yml/badge.svg)](https://github.com/eggstack/eggfetch/actions/workflows/ci.yml)
28
+ [![Crates.io](https://img.shields.io/crates/v/eggfetch-core)](https://crates.io/crates/eggfetch-core)
29
+ [![Crates.io Downloads](https://img.shields.io/crates/d/eggfetch-core)](https://crates.io/crates/eggfetch-core)
30
+ [![PyPI version](https://img.shields.io/pypi/v/eggfetch)](https://pypi.org/project/eggfetch/)
31
+ [![PyPI Downloads](https://static.pepy.tech/personalized-badge/eggfetch?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/eggfetch)
32
+ [![License](https://img.shields.io/crates/l/eggfetch-core)](LICENSE-MIT)
33
+
34
+ eggfetch is a Rust-native HTTP client engine with Python bindings and a CLI tool. The core is async-first: a Rust engine built on tokio and hyper provides connection pooling, phase-aware timeouts, TLS configuration, streaming, and response decompression. The Python bindings expose both sync and async APIs; the sync API blocks on the async engine while releasing the GIL, and the async API integrates with asyncio. There is exactly one networking implementation, living entirely in Rust.
35
+
36
+ ## Features
37
+
38
+ - **HTTP/1.1, HTTP/2, HTTP/3** -- ALPN negotiation, multiplexed connections, experimental QUIC transport (bounded per-origin cache, shared connect budget with address fallback, phase-correct timeouts, keepalive-derived idle, authenticated Alt-Svc discovery with suppression/safe fallback/draining; retained experimental — see [`docs/architecture/core-tls-proxy-protocols.md`](docs/architecture/core-tls-proxy-protocols.md) § "Production Graduation Decision")
39
+ - **Streaming** -- request and response bodies stream without eager buffering; `bytes_stream()` and `text_lines()` for incremental reads
40
+ - **HTTP trailers** -- H1 chunked trailers, H2 trailing HEADERS, and H3 trailing headers captured without buffering (`Response::trailers()` after body EOF; H1 duplicate same-name trailers collapse upstream in hyper and are documented)
41
+ - **Response decompression** -- gzip, brotli, zstd, deflate via feature-gated streaming decoders
42
+ - **Connection pooling** -- semaphore-based logical in-flight request concurrency (`max_in_flight_requests*`, aliases `max_connections*` for pre-1.0) with per-origin limits, pool metrics, and separate transport observability counters
43
+ - **Transport observability** -- connector/DNS/TLS attempt counters, H3 creation/eviction counts, Alt-Svc learned/expired/cleared/rejected, H3 attempted/suppressed/fallback/drain/close/reconnect, and 101 upgrade counts where observable; HTTP/3 builds also expose bounded Quinn snapshots (remote address, RTT, path counters, route generation, and sanitized close codes); Hyper socket-reuse counts intentionally absent
44
+ - **Phase-aware timeouts** -- pool, connect, write, read, and total timeout phases with cancellation safety
45
+ - **TLS** -- rustls with custom CA bundles, client certificates (mTLS), version policy, and verification toggle
46
+ - **Proxy** -- HTTP forwarding, HTTPS CONNECT tunneling, proxy auth, per-request override, `NO_PROXY` bypass
47
+ - **Cookies** -- RFC 6265 cookie jar with domain/path matching, cross-origin stripping
48
+ - **Authentication** -- Basic and Bearer auth with credential redaction in all output paths
49
+ - **Multipart** -- streaming multipart/form-data with known-length optimization
50
+ - **Retries** -- policy-driven retries with exponential backoff and `Retry-After` support
51
+ - **Python API** -- requests/HTTPX-compatible sync and async interfaces, GIL-releasing blocking I/O
52
+ - **HTTPX compatibility facade** -- compatible asyncio surface targeting HTTPX 0.28.1 (`eggfetch.compat.httpx`)
53
+ - **Network stream exposure** -- 101 Switching Protocols responses expose an owned upgraded stream through `extensions["network_stream"]`; direct-connector upgrades carry real local/remote addrs and TLS version/cipher/ALPN, UDS upgrades report `Unix` without IPs, standard opaque upgrades remain explicitly unavailable; `start_tls` uses the same safe TLS translation as the default client
54
+ - **Python/FFI trailer policy** -- core retains trailers; Python native, HTTPX facade, FFI, and Node defer trailer exposure in this milestone (facade unchanged; HTTPX 0.28.1 has no `trailers` surface to compare against)
55
+ - **CLI** -- full-featured HTTP client with streaming output, machine-readable formats, and shell completions
56
+ - **Node.js (experimental prototype)** -- N-API binding with narrow guarantees (UTF-8 string bodies, buffered responses, unstructured errors, stub declarations); see [`docs/architecture/ffi-and-node.md`](docs/architecture/ffi-and-node.md)
57
+
58
+ HTTP/3 remains experimental. See [`docs/architecture/core-tls-proxy-protocols.md`](docs/architecture/core-tls-proxy-protocols.md) § "Production Graduation Decision" for the graduation gate and current status.
59
+
60
+ ## Installation
61
+
62
+ **Python:**
63
+
64
+ ```bash
65
+ pip install eggfetch
66
+ ```
67
+
68
+ **Rust:**
69
+
70
+ ```toml
71
+ [dependencies]
72
+ eggfetch-core = { version = "0.1", features = ["http1", "tls-rustls"] }
73
+ ```
74
+
75
+ **CLI:**
76
+
77
+ ```bash
78
+ cargo install eggfetch-cli
79
+ ```
80
+
81
+ ## Usage -- Python
82
+
83
+ ### Quick requests
84
+
85
+ ```python
86
+ import eggfetch
87
+
88
+ r = eggfetch.get("https://httpbin.org/get")
89
+ print(r.status_code)
90
+ print(r.text)
91
+ ```
92
+
93
+ ### Using a client
94
+
95
+ ```python
96
+ import eggfetch
97
+
98
+ with eggfetch.Client(headers={"User-Agent": "my-app/1.0"}) as client:
99
+ # Buffered response
100
+ r = client.get("https://httpbin.org/get")
101
+ print(r.json())
102
+
103
+ # POST with JSON body
104
+ r = client.post("https://httpbin.org/post", json={"key": "value"})
105
+ print(r.status_code)
106
+
107
+ # Streaming response
108
+ with client.stream("GET", "https://httpbin.org/stream-bytes/10000") as r:
109
+ for chunk in r.iter_bytes():
110
+ print(f"chunk: {len(chunk)} bytes")
111
+ ```
112
+
113
+ ### Async client
114
+
115
+ ```python
116
+ import asyncio
117
+ import eggfetch
118
+
119
+ async def main():
120
+ async with eggfetch.AsyncClient() as client:
121
+ r = await client.get("https://httpbin.org/get")
122
+ print(r.status_code)
123
+
124
+ # Concurrent requests
125
+ responses = await asyncio.gather(
126
+ client.get("https://httpbin.org/get"),
127
+ client.get("https://httpbin.org/ip"),
128
+ )
129
+ for resp in responses:
130
+ print(resp.json())
131
+
132
+ asyncio.run(main())
133
+ ```
134
+
135
+ ### Configuration
136
+
137
+ ```python
138
+ import eggfetch
139
+
140
+ client = eggfetch.Client(
141
+ timeout=10.0,
142
+ headers={"User-Agent": "my-app/1.0"},
143
+ limits=eggfetch.Limits(max_connections=100),
144
+ verify="/path/to/ca-bundle.pem", # custom CA bundle
145
+ cert=("/path/to/cert.pem", "/path/to/key.pem"), # mTLS
146
+ proxy="http://proxy:8080",
147
+ http2=True,
148
+ )
149
+ ```
150
+
151
+ ### HTTPX-compatible facade
152
+
153
+ ```python
154
+ from eggfetch.compat.httpx import Client, AsyncClient
155
+
156
+ # HTTPX 0.28.1 asyncio-compatible facade
157
+ client = Client()
158
+ response = client.get("https://example.com")
159
+ ```
160
+
161
+ See [`docs/python/guide.md`](docs/python/guide.md) for the full Python API reference.
162
+
163
+ ## Usage -- Rust
164
+
165
+ ### Basic requests
166
+
167
+ ```rust
168
+ use eggfetch_core::Client;
169
+
170
+ #[tokio::main]
171
+ async fn main() -> Result<(), Box<dyn std::error::Error>> {
172
+ let client = Client::new();
173
+
174
+ // GET request
175
+ let resp = client.get("https://httpbin.org/get").send().await?;
176
+ println!("Status: {}", resp.status());
177
+ println!("Body: {}", resp.text().await?);
178
+
179
+ // POST with JSON
180
+ let resp = client
181
+ .post("https://httpbin.org/post")
182
+ .header("Content-Type", "application/json")
183
+ .body(r#"{"key": "value"}"#)
184
+ .send()
185
+ .await?;
186
+ println!("Status: {}", resp.status());
187
+
188
+ Ok(())
189
+ }
190
+ ```
191
+
192
+ ### Builder pattern
193
+
194
+ ```rust
195
+ use eggfetch_core::{Client, Timeout};
196
+
197
+ let client = Client::builder()
198
+ .timeout(Timeout::from_secs(30))
199
+ .follow_redirects(true)
200
+ .max_redirects(5)
201
+ .user_agent("my-app/1.0")
202
+ .automatic_decompression(true)
203
+ .build();
204
+
205
+ let resp = client
206
+ .get("https://httpbin.org/get")?
207
+ .header("accept", "application/json")
208
+ .query("page", "1")
209
+ .send()
210
+ .await?;
211
+ ```
212
+
213
+ ### Streaming
214
+
215
+ ```rust
216
+ use eggfetch_core::Client;
217
+ use futures_util::StreamExt;
218
+
219
+ let mut resp = client.get("https://httpbin.org/stream/3").send().await?;
220
+ let mut stream = resp.bytes_stream()?;
221
+
222
+ while let Some(chunk) = stream.next().await {
223
+ let chunk = chunk?;
224
+ println!("chunk: {} bytes", chunk.len());
225
+ }
226
+ ```
227
+
228
+ ### Feature flags
229
+
230
+ ```toml
231
+ [dependencies]
232
+ eggfetch-core = { version = "0.1", features = [
233
+ "http1", # HTTP/1.1 (default)
234
+ "http2", # HTTP/2 via ALPN
235
+ "tls-rustls", # TLS via rustls (default)
236
+ "cookies", # RFC 6265 cookie jar
237
+ "proxy", # HTTP proxy and CONNECT tunneling
238
+ "compression-gzip",
239
+ "compression-brotli",
240
+ "compression-zstd",
241
+ "compression-deflate",
242
+ "multipart", # streaming multipart/form-data
243
+ ] }
244
+ ```
245
+
246
+ See [`docs/rust/guide.md`](docs/rust/guide.md) for the full Rust API reference.
247
+
248
+ ## Usage -- CLI
249
+
250
+ ```bash
251
+ # GET request
252
+ eggfetch https://httpbin.org/get
253
+
254
+ # POST JSON
255
+ eggfetch -X POST https://httpbin.org/post --json '{"key": "value"}'
256
+
257
+ # With authentication
258
+ eggfetch --auth user:pass https://httpbin.org/basic-auth/user/pass
259
+
260
+ # Streaming download
261
+ eggfetch --output file.bin https://httpbin.org/stream-bytes/10000
262
+
263
+ # Machine-readable output
264
+ eggfetch --json-output https://httpbin.org/get
265
+ ```
266
+
267
+ See [`docs/cli/guide.md`](docs/cli/guide.md) for the full CLI reference.
268
+
269
+ ## HTTPX Compatibility
270
+
271
+ eggfetch provides two versioned, independent compatibility facades over the
272
+ single Rust engine. They coexist and never mutate each other.
273
+
274
+ ### HTTPX 0.28.1 (`eggfetch.compat.httpx`)
275
+
276
+ An asyncio-compatible facade targeting HTTPX 0.28.1. See
277
+ `compat/httpx/0.28.1/profile.toml` for the pinned compatibility profile.
278
+
279
+ Key differences from HTTPX:
280
+ - Trio/AnyIO not supported (asyncio only, tokio-based)
281
+ - Python 3.8/3.9 not supported (requires 3.10+)
282
+ - `ssl_context` and proxy `ssl_context` are translated through the safe rustls
283
+ boundary when representable; contexts with unrepresentable cipher, ALPN,
284
+ TLS-version, or client-certificate provenance fail closed with `TypeError`
285
+ - HTTPX timeout values map to `connect`, `read`, `write`, and `pool` only;
286
+ the facade does not synthesize EggFetch's native `total` deadline
287
+ - HTTPX `Timeout` preserves omitted versus explicitly disabled (`None`) phase
288
+ values; `Timeout()` without a scalar or all four phases raises as in HTTPX
289
+ - Core proxy configuration is explicit; the HTTPX compatibility facade honors
290
+ scheme-specific `HTTP_PROXY`/`HTTPS_PROXY` with `ALL_PROXY` fallback,
291
+ lowercase forms, `NO_PROXY`, and `trust_env=False`
292
+ - Redirects with buffered retained bodies replay correctly; arbitrary one-shot body iterators are rejected before the next hop
293
+ - Request-local cookies and explicit Cookie headers are preserved within the facade jar model
294
+ - Response streaming is asyncio-compatible and supports incremental text decoding and chunk-size control
295
+ - `Proxy(headers=...)` is forwarded on the proxy leg only and is never sent
296
+ through a CONNECT tunnel or to the origin; sensitive values are redacted in
297
+ diagnostic representations
298
+ - HTTP/2-only works for direct TLS, cleartext prior knowledge, the SNI override
299
+ route, the SOCKS HTTPS route, and the specialized direct/UDS paths. HTTP
300
+ CONNECT proxy origin framing remains HTTP/1.1, and HTTP/2 `stream_id` remains
301
+ metadata-only and unavailable
302
+ - Sync trace callbacks work on both `Client` and `AsyncClient`; coroutine
303
+ trace callbacks are rejected with `TypeError` before dispatch because
304
+ the core `TraceObserver` is synchronous
305
+
306
+ Remaining differences are documented in `compat/httpx/0.28.1/allowed-differences.toml`; the compatibility claim is limited to the pinned HTTPX 0.28.1 profile and the supported asyncio surface.
307
+
308
+ ### HTTPX2 2.12.0 (`eggfetch.compat.httpx2`)
309
+
310
+ A sibling facade for the maintained `httpx2==2.12.0` line, pinned in
311
+ `compat/httpx2/2.12.0/` with its own reference manifest and
312
+ allowed-difference ledger. It reuses the same Rust engine and shared
313
+ compatibility helpers where semantics are identical; HTTPX2-specific
314
+ semantics live behind explicit profile boundaries and never
315
+ leak into `eggfetch.compat.httpx`.
316
+
317
+ ```python
318
+ from eggfetch.compat.httpx2 import Client, AsyncClient
319
+
320
+ client = Client() # httpx2 2.12.0 surface: FunctionAuth, Origin, QUERY, SSE, optional WS
321
+ ```
322
+
323
+ New surface vs 0.28.1: `FunctionAuth`, `Origin` + `URL.origin`,
324
+ `QUERY` (`query` top-level + `Client.query`/`AsyncClient.query`),
325
+ `Headers` merge operators (`|`/`|=`), `alias_httpx()` (explicit
326
+ opt-in only), truststore OS-trust default, RFC 9110 status renames,
327
+ plus SSE (`EventSource` over streamed responses) and optional WebSocket
328
+ (wsproto framing over the existing 101 `network_stream` — no second
329
+ socket/TLS stack, `pip install httpx2[ws]` for WS support).
330
+ Python 3.10–3.13 distribution scope.
331
+
332
+ ### HTTPX 1.0 preview (no compatibility promise)
333
+
334
+ `compat/httpx/1.0-preview/` tracks the HTTPX 1.0 redesign as
335
+ reconnaissance only. No dev release is a supported contract; see that
336
+ directory for the observed version, delta notes, and entry criteria.
337
+
338
+ ### 101 Switching Protocols and `network_stream`
339
+
340
+ When a request upgrades (e.g. WebSocket via `Connection: Upgrade`), the
341
+ response carries a live owned `NetworkStream` exposed through
342
+ `response.extensions["network_stream"]`. The wrapper type follows the
343
+ caller's API mode: sync `Client.stream()` and `Client.request()` 101
344
+ responses expose the sync `NetworkStream`; async `AsyncClient.stream()`
345
+ and `AsyncClient.request()` 101 responses expose the async wrapper.
346
+ For ordinary pooled HTTP/1.1 and HTTP/2 connections, `network_stream` is
347
+ `None`; the connection is returned to the pool and not user-writable.
348
+ Internal HTTPS proxy CONNECT tunnels are also classified as `None` — the
349
+ canonical access path is the body iterator, not the upgraded stream.
350
+
351
+ The `NetworkStream` object supports `read`, `write`, `close`, `is_upgraded`,
352
+ `get_extra_info`, and `start_tls(ssl_context=..., server_hostname=...,
353
+ timeout=...)`. `start_tls` uses the same safe TLS policy as the default
354
+ client; it is rejected for Hyper-opaque adapter streams and for streams that
355
+ are already TLS-wrapped. Leading bytes written immediately after the 101
356
+ headers are returned by the first reads from the upgraded stream.
357
+
358
+ See [`docs/reference/compatibility.md`](docs/reference/compatibility.md) for the full feature matrix.
359
+
360
+ ## Documentation
361
+
362
+ | Section | Description |
363
+ |---------|-------------|
364
+ | [getting-started/](docs/getting-started/) | Installation and quickstart guide |
365
+ | [concepts/](docs/concepts/) | Architecture, lifecycle, timeouts, streaming, cookies, auth, proxy, TLS |
366
+ | [rust/guide.md](docs/rust/guide.md) | Rust API guide with examples |
367
+ | [python/guide.md](docs/python/guide.md) | Python sync/async API guide |
368
+ | [cli/guide.md](docs/cli/guide.md) | CLI reference and usage guide |
369
+ | [migration/](docs/migration/) | Migration guides from requests and HTTPX |
370
+ | [cookbook/](docs/cookbook/) | Practical runnable examples |
371
+ | [reference/](docs/reference/) | Compatibility matrix, feature matrix, error reference |
372
+ | [security/](docs/security/) | Security guidelines and troubleshooting |
373
+ | [architecture/](docs/architecture/) | Internal architecture documentation |
374
+ | [ffi/](docs/ffi/) | C ABI and FFI binding guide |
375
+
376
+ ## Security
377
+
378
+ eggfetch follows a security-hardening program covering dependencies, TLS, redirects, auth, cookies, proxies, decompression, multipart, retries, and protocol handling.
379
+
380
+ - **Dependency auditing:** `cargo-deny` configured in `deny.toml`
381
+ - **Secret redaction:** All `Debug`/`Display`/error output redacts credentials, cookies, bearer tokens, and proxy passwords
382
+ - **Threat model:** See [docs/architecture/threat-model.md](docs/architecture/threat-model.md)
383
+ - **Vulnerability reporting:** See [SECURITY.md](SECURITY.md)
384
+
385
+ ## License
386
+
387
+ eggfetch is licensed under the [MIT License](LICENSE-MIT).
388
+
389
+ ## MSRV
390
+
391
+ The minimum supported Rust version is **1.80**, declared in `workspace.package.rust-version` and checked in extended validation. `rust-toolchain.toml` pins the stable channel for development.
392
+