eggfetch 0.1.3__tar.gz → 0.1.4__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 (239) hide show
  1. {eggfetch-0.1.3 → eggfetch-0.1.4}/Cargo.lock +7 -8
  2. eggfetch-0.1.4/PKG-INFO +240 -0
  3. eggfetch-0.1.4/README.md +215 -0
  4. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/Cargo.toml +29 -18
  5. eggfetch-0.1.4/crates/eggfetch-core/README.md +215 -0
  6. eggfetch-0.1.4/crates/eggfetch-core/examples/quickstart.rs +75 -0
  7. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/client.rs +213 -101
  8. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/error.rs +22 -0
  9. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/lib.rs +3 -1
  10. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/network_stream.rs +9 -0
  11. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/pipeline.rs +152 -14
  12. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/request.rs +267 -1
  13. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/response.rs +74 -0
  14. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/retry.rs +4 -1
  15. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/tls.rs +41 -22
  16. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/transport/connect.rs +9 -18
  17. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/transport/direct.rs +2 -0
  18. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/transport/direct_connector.rs +70 -17
  19. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/transport/http3.rs +3 -16
  20. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/transport/mod.rs +10 -0
  21. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/transport/proxy.rs +3 -8
  22. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/transport/uds.rs +28 -3
  23. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/direct_transport_tests.rs +127 -0
  24. eggfetch-0.1.4/crates/eggfetch-core/tests/native_json.rs +273 -0
  25. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/tls_integration.rs +25 -0
  26. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/Cargo.toml +2 -2
  27. eggfetch-0.1.4/crates/eggfetch-python/README.md +215 -0
  28. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/errors.rs +6 -0
  29. {eggfetch-0.1.3 → eggfetch-0.1.4}/pyproject.toml +1 -1
  30. eggfetch-0.1.3/PKG-INFO +0 -392
  31. eggfetch-0.1.3/README.md +0 -367
  32. eggfetch-0.1.3/crates/eggfetch-core/README.md +0 -367
  33. eggfetch-0.1.3/crates/eggfetch-python/README.md +0 -367
  34. {eggfetch-0.1.3 → eggfetch-0.1.4}/Cargo.toml +0 -0
  35. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/auth.rs +0 -0
  36. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/body.rs +0 -0
  37. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/compression.rs +0 -0
  38. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/config.rs +0 -0
  39. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/cookie.rs +0 -0
  40. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/h2_headers.rs +0 -0
  41. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/headers.rs +0 -0
  42. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/http_version.rs +0 -0
  43. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/limits.rs +0 -0
  44. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/multipart.rs +0 -0
  45. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/pool.rs +0 -0
  46. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/proxy.rs +0 -0
  47. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/redact.rs +0 -0
  48. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/redirect.rs +0 -0
  49. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/response_decode.rs +0 -0
  50. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/stream/mod.rs +0 -0
  51. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/stream/read_timeout.rs +0 -0
  52. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/stream/write_timeout.rs +0 -0
  53. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/timeout.rs +0 -0
  54. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/trace.rs +0 -0
  55. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/transport/alt_svc.rs +0 -0
  56. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/transport/connect_timeout.rs +0 -0
  57. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/transport/metrics.rs +0 -0
  58. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/src/transport/socks.rs +0 -0
  59. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/adverse_tests.rs +0 -0
  60. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/cross_feature_tests.rs +0 -0
  61. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/h3_alt_svc_discovery.rs +0 -0
  62. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/h3_hardening.rs +0 -0
  63. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/h3_integration.rs +0 -0
  64. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/h3_interop_qualification.rs +0 -0
  65. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/http2_tests.rs +0 -0
  66. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/http3_tests.rs +0 -0
  67. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/integration.rs +0 -0
  68. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/network_stream_tests.rs +0 -0
  69. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/pool_tests.rs +0 -0
  70. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/proxy_tests.rs +0 -0
  71. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/resource_stabilization.rs +0 -0
  72. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/retry_integration.rs +0 -0
  73. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/test_server.rs +0 -0
  74. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/timeout_tests.rs +0 -0
  75. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/tls_fixtures.rs +0 -0
  76. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/trailer_tests.rs +0 -0
  77. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-core/tests/transport_metrics_tests.rs +0 -0
  78. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/async_client.rs +0 -0
  79. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/auth.rs +0 -0
  80. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/client.rs +0 -0
  81. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/conversion.rs +0 -0
  82. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/cookies.rs +0 -0
  83. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/extensions.rs +0 -0
  84. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/headers.rs +0 -0
  85. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/lib.rs +0 -0
  86. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/limits.rs +0 -0
  87. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/multipart.rs +0 -0
  88. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/network_stream.rs +0 -0
  89. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/proxy.rs +0 -0
  90. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/response.rs +0 -0
  91. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/retry.rs +0 -0
  92. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/streaming.rs +0 -0
  93. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/timeout.rs +0 -0
  94. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/tls.rs +0 -0
  95. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/src/trace_bridge.rs +0 -0
  96. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/__init__.py +0 -0
  97. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/conftest.py +0 -0
  98. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/fixtures.py +0 -0
  99. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/native_fixtures.py +0 -0
  100. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_asgi.py +0 -0
  101. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_auth.py +0 -0
  102. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_auth_input_normalization.py +0 -0
  103. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_auth_replay.py +0 -0
  104. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_backends.py +0 -0
  105. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_behavior_cases.py +0 -0
  106. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_client.py +0 -0
  107. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_client_mutability_and_state.py +0 -0
  108. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_client_stream_overrides.py +0 -0
  109. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_config_objects.py +0 -0
  110. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_cookie_scope_parity.py +0 -0
  111. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_cookies.py +0 -0
  112. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_corrective_01_tls_and_proxy_trust_safety.py +0 -0
  113. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_corrective_01_tls_network_proof.py +0 -0
  114. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_corrective_02_extensions_and_wire_metadata.py +0 -0
  115. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_corrective_03_network_stream_upgrade.py +0 -0
  116. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_corrective_kernel.py +0 -0
  117. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_downstream_portfolio.py +0 -0
  118. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_downstream_runner_negative.py +0 -0
  119. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_environment.py +0 -0
  120. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_exceptions.py +0 -0
  121. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_extensions.py +0 -0
  122. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_h2_differential.py +0 -0
  123. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_headers.py +0 -0
  124. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_hook_auth_ordering.py +0 -0
  125. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_hook_cookie_auth_ordering.py +0 -0
  126. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_hooks.py +0 -0
  127. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_httpx2_api_parity.py +0 -0
  128. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_httpx2_behavior.py +0 -0
  129. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_httpx2_sse.py +0 -0
  130. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_httpx2_websocket.py +0 -0
  131. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_httpx_extras.py +0 -0
  132. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_httpx_reference_pinning.py +0 -0
  133. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_httpx_required.py +0 -0
  134. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_imports.py +0 -0
  135. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_lifecycle.py +0 -0
  136. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_lossy_conversions.py +0 -0
  137. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_merge_lossless.py +0 -0
  138. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_merge_matrix.py +0 -0
  139. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_mock_transport.py +0 -0
  140. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_mounts.py +0 -0
  141. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_multihop_cleanup.py +0 -0
  142. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_native_proxy_tls.py +0 -0
  143. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_native_timeout_classification.py +0 -0
  144. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_no_proxy_differential.py +0 -0
  145. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_oracle_negative.py +0 -0
  146. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_protocol_and_unsupported_options.py +0 -0
  147. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_proxy_differential.py +0 -0
  148. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_proxy_phase05_tracks.py +0 -0
  149. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_raw_stream_httpx_differential.py +0 -0
  150. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_raw_stream_lifecycle.py +0 -0
  151. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_redirect_state_machine_parity.py +0 -0
  152. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_request.py +0 -0
  153. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_request_construction_parity.py +0 -0
  154. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_request_stream_state.py +0 -0
  155. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_request_streaming.py +0 -0
  156. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_resource_assertions.py +0 -0
  157. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_response.py +0 -0
  158. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_response_encoding_parity.py +0 -0
  159. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_response_metadata_parity.py +0 -0
  160. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_response_status_and_redirect_state.py +0 -0
  161. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_response_stream_state_parity.py +0 -0
  162. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_response_streaming.py +0 -0
  163. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_shutdown.py +0 -0
  164. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_soak.py +0 -0
  165. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_socks_transport.py +0 -0
  166. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_ssl_context_network_proof.py +0 -0
  167. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_ssl_context_translation.py +0 -0
  168. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_stream_resources.py +0 -0
  169. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_timeout_integration.py +0 -0
  170. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_timeout_proxysis.py +0 -0
  171. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_timeout_reference_differential.py +0 -0
  172. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_top_level_helpers_parity.py +0 -0
  173. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_trace_detection.py +0 -0
  174. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_transports.py +0 -0
  175. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_uds_transport.py +0 -0
  176. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_url_query.py +0 -0
  177. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/compat/test_wsgi.py +0 -0
  178. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/conftest.py +0 -0
  179. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/test_async.py +0 -0
  180. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/test_auth.py +0 -0
  181. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/test_close_races.py +0 -0
  182. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/test_cookie_auth.py +0 -0
  183. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/test_cookies.py +0 -0
  184. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/test_differential.py +0 -0
  185. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/test_http2.py +0 -0
  186. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/test_interpreter_shutdown.py +0 -0
  187. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/test_parity.py +0 -0
  188. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/test_proxy.py +0 -0
  189. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/test_redirects.py +0 -0
  190. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/test_response_compat.py +0 -0
  191. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/test_retry.py +0 -0
  192. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/test_streaming.py +0 -0
  193. {eggfetch-0.1.3 → eggfetch-0.1.4}/crates/eggfetch-python/tests/test_sync.py +0 -0
  194. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/__init__.py +0 -0
  195. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/__init__.py +0 -0
  196. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/__init__.py +0 -0
  197. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_asgi.py +0 -0
  198. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_auth.py +0 -0
  199. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_client.py +0 -0
  200. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_cookies.py +0 -0
  201. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_diagnostics.py +0 -0
  202. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_exceptions.py +0 -0
  203. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_headers.py +0 -0
  204. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_limits.py +0 -0
  205. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_mock.py +0 -0
  206. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_proxy.py +0 -0
  207. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_request.py +0 -0
  208. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_response.py +0 -0
  209. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_ssl_context.py +0 -0
  210. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_status_codes.py +0 -0
  211. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_stream.py +0 -0
  212. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_timeout.py +0 -0
  213. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_transports.py +0 -0
  214. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_urls.py +0 -0
  215. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx/_wsgi.py +0 -0
  216. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/__init__.py +0 -0
  217. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/_alias.py +0 -0
  218. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/_api.py +0 -0
  219. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/_asgi.py +0 -0
  220. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/_auth.py +0 -0
  221. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/_client.py +0 -0
  222. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/_config.py +0 -0
  223. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/_cookies.py +0 -0
  224. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/_exceptions.py +0 -0
  225. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/_headers.py +0 -0
  226. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/_mock.py +0 -0
  227. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/_request.py +0 -0
  228. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/_response.py +0 -0
  229. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/_sse.py +0 -0
  230. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/_status_codes.py +0 -0
  231. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/_stream.py +0 -0
  232. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/_transports.py +0 -0
  233. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/_urls.py +0 -0
  234. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/_wsgi.py +0 -0
  235. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/websockets/__init__.py +0 -0
  236. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/websockets/_api.py +0 -0
  237. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/websockets/_exceptions.py +0 -0
  238. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/websockets/_ping.py +0 -0
  239. {eggfetch-0.1.3 → eggfetch-0.1.4}/python/eggfetch/compat/httpx2/websockets/_transport.py +0 -0
@@ -509,7 +509,7 @@ dependencies = [
509
509
 
510
510
  [[package]]
511
511
  name = "eggfetch-cli"
512
- version = "0.1.3"
512
+ version = "0.1.4"
513
513
  dependencies = [
514
514
  "anyhow",
515
515
  "bytes",
@@ -526,7 +526,7 @@ dependencies = [
526
526
 
527
527
  [[package]]
528
528
  name = "eggfetch-core"
529
- version = "0.1.3"
529
+ version = "0.1.4"
530
530
  dependencies = [
531
531
  "async-compression",
532
532
  "base64",
@@ -544,7 +544,6 @@ dependencies = [
544
544
  "http",
545
545
  "http-body",
546
546
  "http-body-util",
547
- "httparse",
548
547
  "httpdate",
549
548
  "hyper",
550
549
  "hyper-rustls",
@@ -557,6 +556,8 @@ dependencies = [
557
556
  "rcgen",
558
557
  "rustls",
559
558
  "rustls-native-certs",
559
+ "serde",
560
+ "serde_json",
560
561
  "tempfile",
561
562
  "thiserror",
562
563
  "tokio",
@@ -571,7 +572,7 @@ dependencies = [
571
572
 
572
573
  [[package]]
573
574
  name = "eggfetch-ffi"
574
- version = "0.1.3"
575
+ version = "0.1.4"
575
576
  dependencies = [
576
577
  "bytes",
577
578
  "eggfetch-core",
@@ -583,7 +584,7 @@ dependencies = [
583
584
 
584
585
  [[package]]
585
586
  name = "eggfetch-node"
586
- version = "0.1.3"
587
+ version = "0.1.4"
587
588
  dependencies = [
588
589
  "eggfetch-ffi",
589
590
  "napi",
@@ -595,7 +596,7 @@ dependencies = [
595
596
 
596
597
  [[package]]
597
598
  name = "eggfetch-python"
598
- version = "0.1.3"
599
+ version = "0.1.4"
599
600
  dependencies = [
600
601
  "bytes",
601
602
  "eggfetch-core",
@@ -954,11 +955,9 @@ dependencies = [
954
955
  "hyper-util",
955
956
  "log",
956
957
  "rustls",
957
- "rustls-native-certs",
958
958
  "tokio",
959
959
  "tokio-rustls",
960
960
  "tower-service",
961
- "webpki-roots 1.0.8",
962
961
  ]
963
962
 
964
963
  [[package]]
@@ -0,0 +1,240 @@
1
+ Metadata-Version: 2.4
2
+ Name: eggfetch
3
+ Version: 0.1.4
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 async HTTP client engine (tokio + hyper) with Python bindings and a CLI. There is exactly one networking implementation, living entirely in `eggfetch-core`; the Python sync API blocks on the async engine while releasing the GIL, and the async API integrates with asyncio.
35
+
36
+ ## Features
37
+
38
+ - **HTTP/1.1, HTTP/2, HTTP/3** — ALPN negotiation; HTTP/3 over QUIC stays experimental ([graduation gate](docs/architecture/core-tls-proxy-protocols.md))
39
+ - **Streaming** — request/response bodies without eager buffering (`bytes_stream()`, `text_lines()`); trailers via `Response::trailers()` ([guide](docs/rust/guide.md))
40
+ - **Pooling, timeouts, observability** — per-origin in-flight limits, phase-aware timeouts (pool/connect/write/read/total), connector/DNS/TLS and H3 transport metrics ([pool/timeouts](docs/architecture/core-timeout-pool.md))
41
+ - **TLS** — rustls with custom CA bundles, mTLS client certs, version policy, verification toggle ([TLS](docs/concepts/tls.md))
42
+ - **Proxy** — HTTP forwarding, HTTPS CONNECT, proxy auth, per-request override, `NO_PROXY`; SOCKS5 and UDS routes ([proxy](docs/concepts/proxy.md))
43
+ - **Cookies, auth, multipart** — RFC 6265 jar, Basic/Bearer with redaction, streaming multipart uploads ([cookies](docs/concepts/cookies.md))
44
+ - **Retries and redirects** — policy-driven backoff with `Retry-After`, replayable-body redirect handling ([retry](docs/concepts/retry.md))
45
+ - **Compression** — feature-gated streaming gzip/brotli/zstd/deflate with zip-bomb limits ([compression](docs/concepts/compression.md))
46
+ - **Native Rust JSON (opt-in)** — replayable `RequestBuilder::json()`, single-consumption `Response::json()` via the `json` feature ([guide](docs/rust/guide.md))
47
+ - **Python API** — requests/HTTPX-compatible sync and async interfaces ([guide](docs/python/guide.md)), plus versioned `eggfetch.compat.httpx` (0.28.1) and `eggfetch.compat.httpx2` (2.12.0) facades ([compatibility](#httpx-compatibility))
48
+ - **Upgrades** — 101 responses expose an owned `network_stream` (WebSocket/SSE building blocks); CONNECT tunnels stay body-iterator only
49
+ - **CLI** — streaming output, machine-readable formats, shell completions ([guide](docs/cli/guide.md))
50
+ - **C ABI and Node.js prototype** — opaque-handle FFI plus an experimental N-API wrapper ([ffi-and-node](docs/architecture/ffi-and-node.md))
51
+
52
+ ## Installation
53
+
54
+ **Python:**
55
+
56
+ ```bash
57
+ pip install eggfetch
58
+ ```
59
+
60
+ **Rust:**
61
+
62
+ ```toml
63
+ [dependencies]
64
+ eggfetch-core = { version = "0.1", features = ["http1", "tls-rustls", "tls-native-roots"] }
65
+ ```
66
+
67
+ See the [feature profile matrix](docs/architecture/feature-flags.md#supported-core-profiles) for minimal, deterministic, and embedded recipes.
68
+
69
+ **CLI:**
70
+
71
+ ```bash
72
+ cargo install eggfetch-cli
73
+ ```
74
+
75
+ ## Usage -- Python
76
+
77
+ ```python
78
+ import eggfetch
79
+
80
+ r = eggfetch.get("https://httpbin.org/get")
81
+ print(r.status_code)
82
+ print(r.text)
83
+ ```
84
+
85
+ ```python
86
+ import eggfetch
87
+
88
+ with eggfetch.Client(headers={"User-Agent": "my-app/1.0"}) as client:
89
+ r = client.get("https://httpbin.org/get")
90
+ print(r.json())
91
+
92
+ r = client.post("https://httpbin.org/post", json={"key": "value"})
93
+ print(r.status_code)
94
+
95
+ with client.stream("GET", "https://httpbin.org/stream-bytes/10000") as r:
96
+ for chunk in r.iter_bytes():
97
+ print(f"chunk: {len(chunk)} bytes")
98
+ ```
99
+
100
+ ```python
101
+ import asyncio
102
+ import eggfetch
103
+
104
+ async def main():
105
+ async with eggfetch.AsyncClient() as client:
106
+ r = await client.get("https://httpbin.org/get")
107
+ print(r.status_code)
108
+
109
+ responses = await asyncio.gather(
110
+ client.get("https://httpbin.org/get"),
111
+ client.get("https://httpbin.org/ip"),
112
+ )
113
+ for resp in responses:
114
+ print(resp.json())
115
+
116
+ asyncio.run(main())
117
+ ```
118
+
119
+ ```python
120
+ import eggfetch
121
+
122
+ client = eggfetch.Client(
123
+ timeout=10.0,
124
+ headers={"User-Agent": "my-app/1.0"},
125
+ limits=eggfetch.Limits(max_connections=100),
126
+ verify="/path/to/ca-bundle.pem", # custom CA bundle
127
+ cert=("/path/to/cert.pem", "/path/to/key.pem"), # mTLS
128
+ proxy="http://proxy:8080",
129
+ http2=True,
130
+ )
131
+ ```
132
+
133
+ Versioned HTTPX-compatible facades over the same engine:
134
+
135
+ ```python
136
+ from eggfetch.compat.httpx import Client # HTTPX 0.28.1 surface
137
+ from eggfetch.compat.httpx2 import Client as H2Client # httpx2 2.12.0 surface
138
+ ```
139
+
140
+ See [`docs/python/guide.md`](docs/python/guide.md) for the full Python API reference.
141
+
142
+ ## Usage -- Rust
143
+
144
+ ```rust
145
+ use eggfetch_core::Client;
146
+ use futures_util::StreamExt;
147
+
148
+ #[tokio::main]
149
+ async fn main() -> Result<(), Box<dyn std::error::Error>> {
150
+ let client = Client::builder()
151
+ .timeout(eggfetch_core::Timeout::from_secs(30))
152
+ .follow_redirects(true)
153
+ .user_agent("my-app/1.0")
154
+ .build();
155
+
156
+ let mut resp = client.get("https://httpbin.org/get").send().await?;
157
+ println!("Status: {}", resp.status());
158
+ println!("Body: {}", resp.text().await?);
159
+
160
+ // Streaming body
161
+ let mut resp = client.get("https://httpbin.org/stream/3").send().await?;
162
+ let mut stream = resp.bytes_stream()?;
163
+ while let Some(chunk) = stream.next().await {
164
+ println!("chunk: {} bytes", chunk?.len());
165
+ }
166
+
167
+ Ok(())
168
+ }
169
+ ```
170
+
171
+ The opt-in `json` feature adds `RequestBuilder::json()` / `Response::json()` Serde helpers, and `resolved_addresses()` pins caller-validated destinations without a second DNS lookup. See [`docs/rust/guide.md`](docs/rust/guide.md) for the full Rust API reference.
172
+
173
+ ## Usage -- CLI
174
+
175
+ ```bash
176
+ # GET request
177
+ eggfetch https://httpbin.org/get
178
+
179
+ # POST JSON
180
+ eggfetch -X POST https://httpbin.org/post --json '{"key": "value"}'
181
+
182
+ # With authentication
183
+ eggfetch --auth user:pass https://httpbin.org/basic-auth/user/pass
184
+
185
+ # Streaming download
186
+ eggfetch --output file.bin https://httpbin.org/stream-bytes/10000
187
+
188
+ # Machine-readable output
189
+ eggfetch --json-output https://httpbin.org/get
190
+ ```
191
+
192
+ See [`docs/cli/guide.md`](docs/cli/guide.md) for the full CLI reference.
193
+
194
+ ## Examples
195
+
196
+ Runnable starting points (each takes an optional base URL argument, default `https://httpbin.org`):
197
+
198
+ - [`crates/eggfetch-core/examples/quickstart.rs`](crates/eggfetch-core/examples/quickstart.rs) — core client: configured GET/POST, timeout override, auth, streaming (`cargo run -p eggfetch-core --example quickstart`)
199
+ - [`examples/python_sync.py`](examples/python_sync.py) — sync client, JSON POST, streaming download
200
+ - [`examples/python_async.py`](examples/python_async.py) — async client with concurrent requests
201
+
202
+ More patterns are in [`docs/cookbook/`](docs/cookbook/).
203
+
204
+ ## HTTPX Compatibility
205
+
206
+ Two versioned, independent facades over the single Rust engine — `eggfetch.compat.httpx` (0.28.1) and `eggfetch.compat.httpx2` (2.12.0, adds `FunctionAuth`, `Origin`/`URL.origin`, `QUERY`, SSE, optional WebSocket). Both are Stage C qualified on frozen executable SHA `22a6f5c0dc0207c1356b6143c0eda3d4075063b0`; HTTPX 1.0 preview under `compat/httpx/1.0-preview/` is reconnaissance only.
207
+
208
+ See [`docs/reference/compatibility.md`](docs/reference/compatibility.md) for the full feature matrix and retained differences.
209
+
210
+ ## Documentation
211
+
212
+ | Section | Description |
213
+ |---------|-------------|
214
+ | [getting-started/](docs/getting-started/) | Installation and quickstart guide |
215
+ | [concepts/](docs/concepts/) | Architecture, lifecycle, timeouts, streaming, cookies, auth, proxy, TLS |
216
+ | [rust/guide.md](docs/rust/guide.md) | Rust API guide with examples |
217
+ | [python/guide.md](docs/python/guide.md) | Python sync/async API guide |
218
+ | [cli/guide.md](docs/cli/guide.md) | CLI reference and usage guide |
219
+ | [migration/](docs/migration/) | Migration guides from requests and HTTPX |
220
+ | [cookbook/](docs/cookbook/) | Practical runnable examples |
221
+ | [reference/](docs/reference/) | Compatibility matrix, feature matrix, error reference |
222
+ | [security/](docs/security/) | Security guidelines and troubleshooting |
223
+ | [architecture/](docs/architecture/) | Internal architecture documentation |
224
+ | [ffi/](docs/ffi/) | C ABI and FFI binding guide |
225
+
226
+ ## Security
227
+
228
+ - **Dependency auditing:** `cargo-deny` configured in `deny.toml`
229
+ - **Secret redaction:** all `Debug`/`Display`/error output redacts credentials, cookies, bearer tokens, and proxy passwords
230
+ - **Threat model:** see [docs/architecture/threat-model.md](docs/architecture/threat-model.md)
231
+ - **Vulnerability reporting:** see [SECURITY.md](SECURITY.md)
232
+
233
+ ## License
234
+
235
+ eggfetch is licensed under the [MIT License](LICENSE-MIT).
236
+
237
+ ## MSRV
238
+
239
+ 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.
240
+
@@ -0,0 +1,215 @@
1
+ # eggfetch
2
+
3
+ [![CI](https://github.com/eggstack/eggfetch/actions/workflows/ci.yml/badge.svg)](https://github.com/eggstack/eggfetch/actions/workflows/ci.yml)
4
+ [![Crates.io](https://img.shields.io/crates/v/eggfetch-core)](https://crates.io/crates/eggfetch-core)
5
+ [![Crates.io Downloads](https://img.shields.io/crates/d/eggfetch-core)](https://crates.io/crates/eggfetch-core)
6
+ [![PyPI version](https://img.shields.io/pypi/v/eggfetch)](https://pypi.org/project/eggfetch/)
7
+ [![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)
8
+ [![License](https://img.shields.io/crates/l/eggfetch-core)](LICENSE-MIT)
9
+
10
+ eggfetch is a Rust-native async HTTP client engine (tokio + hyper) with Python bindings and a CLI. There is exactly one networking implementation, living entirely in `eggfetch-core`; the Python sync API blocks on the async engine while releasing the GIL, and the async API integrates with asyncio.
11
+
12
+ ## Features
13
+
14
+ - **HTTP/1.1, HTTP/2, HTTP/3** — ALPN negotiation; HTTP/3 over QUIC stays experimental ([graduation gate](docs/architecture/core-tls-proxy-protocols.md))
15
+ - **Streaming** — request/response bodies without eager buffering (`bytes_stream()`, `text_lines()`); trailers via `Response::trailers()` ([guide](docs/rust/guide.md))
16
+ - **Pooling, timeouts, observability** — per-origin in-flight limits, phase-aware timeouts (pool/connect/write/read/total), connector/DNS/TLS and H3 transport metrics ([pool/timeouts](docs/architecture/core-timeout-pool.md))
17
+ - **TLS** — rustls with custom CA bundles, mTLS client certs, version policy, verification toggle ([TLS](docs/concepts/tls.md))
18
+ - **Proxy** — HTTP forwarding, HTTPS CONNECT, proxy auth, per-request override, `NO_PROXY`; SOCKS5 and UDS routes ([proxy](docs/concepts/proxy.md))
19
+ - **Cookies, auth, multipart** — RFC 6265 jar, Basic/Bearer with redaction, streaming multipart uploads ([cookies](docs/concepts/cookies.md))
20
+ - **Retries and redirects** — policy-driven backoff with `Retry-After`, replayable-body redirect handling ([retry](docs/concepts/retry.md))
21
+ - **Compression** — feature-gated streaming gzip/brotli/zstd/deflate with zip-bomb limits ([compression](docs/concepts/compression.md))
22
+ - **Native Rust JSON (opt-in)** — replayable `RequestBuilder::json()`, single-consumption `Response::json()` via the `json` feature ([guide](docs/rust/guide.md))
23
+ - **Python API** — requests/HTTPX-compatible sync and async interfaces ([guide](docs/python/guide.md)), plus versioned `eggfetch.compat.httpx` (0.28.1) and `eggfetch.compat.httpx2` (2.12.0) facades ([compatibility](#httpx-compatibility))
24
+ - **Upgrades** — 101 responses expose an owned `network_stream` (WebSocket/SSE building blocks); CONNECT tunnels stay body-iterator only
25
+ - **CLI** — streaming output, machine-readable formats, shell completions ([guide](docs/cli/guide.md))
26
+ - **C ABI and Node.js prototype** — opaque-handle FFI plus an experimental N-API wrapper ([ffi-and-node](docs/architecture/ffi-and-node.md))
27
+
28
+ ## Installation
29
+
30
+ **Python:**
31
+
32
+ ```bash
33
+ pip install eggfetch
34
+ ```
35
+
36
+ **Rust:**
37
+
38
+ ```toml
39
+ [dependencies]
40
+ eggfetch-core = { version = "0.1", features = ["http1", "tls-rustls", "tls-native-roots"] }
41
+ ```
42
+
43
+ See the [feature profile matrix](docs/architecture/feature-flags.md#supported-core-profiles) for minimal, deterministic, and embedded recipes.
44
+
45
+ **CLI:**
46
+
47
+ ```bash
48
+ cargo install eggfetch-cli
49
+ ```
50
+
51
+ ## Usage -- Python
52
+
53
+ ```python
54
+ import eggfetch
55
+
56
+ r = eggfetch.get("https://httpbin.org/get")
57
+ print(r.status_code)
58
+ print(r.text)
59
+ ```
60
+
61
+ ```python
62
+ import eggfetch
63
+
64
+ with eggfetch.Client(headers={"User-Agent": "my-app/1.0"}) as client:
65
+ r = client.get("https://httpbin.org/get")
66
+ print(r.json())
67
+
68
+ r = client.post("https://httpbin.org/post", json={"key": "value"})
69
+ print(r.status_code)
70
+
71
+ with client.stream("GET", "https://httpbin.org/stream-bytes/10000") as r:
72
+ for chunk in r.iter_bytes():
73
+ print(f"chunk: {len(chunk)} bytes")
74
+ ```
75
+
76
+ ```python
77
+ import asyncio
78
+ import eggfetch
79
+
80
+ async def main():
81
+ async with eggfetch.AsyncClient() as client:
82
+ r = await client.get("https://httpbin.org/get")
83
+ print(r.status_code)
84
+
85
+ responses = await asyncio.gather(
86
+ client.get("https://httpbin.org/get"),
87
+ client.get("https://httpbin.org/ip"),
88
+ )
89
+ for resp in responses:
90
+ print(resp.json())
91
+
92
+ asyncio.run(main())
93
+ ```
94
+
95
+ ```python
96
+ import eggfetch
97
+
98
+ client = eggfetch.Client(
99
+ timeout=10.0,
100
+ headers={"User-Agent": "my-app/1.0"},
101
+ limits=eggfetch.Limits(max_connections=100),
102
+ verify="/path/to/ca-bundle.pem", # custom CA bundle
103
+ cert=("/path/to/cert.pem", "/path/to/key.pem"), # mTLS
104
+ proxy="http://proxy:8080",
105
+ http2=True,
106
+ )
107
+ ```
108
+
109
+ Versioned HTTPX-compatible facades over the same engine:
110
+
111
+ ```python
112
+ from eggfetch.compat.httpx import Client # HTTPX 0.28.1 surface
113
+ from eggfetch.compat.httpx2 import Client as H2Client # httpx2 2.12.0 surface
114
+ ```
115
+
116
+ See [`docs/python/guide.md`](docs/python/guide.md) for the full Python API reference.
117
+
118
+ ## Usage -- Rust
119
+
120
+ ```rust
121
+ use eggfetch_core::Client;
122
+ use futures_util::StreamExt;
123
+
124
+ #[tokio::main]
125
+ async fn main() -> Result<(), Box<dyn std::error::Error>> {
126
+ let client = Client::builder()
127
+ .timeout(eggfetch_core::Timeout::from_secs(30))
128
+ .follow_redirects(true)
129
+ .user_agent("my-app/1.0")
130
+ .build();
131
+
132
+ let mut resp = client.get("https://httpbin.org/get").send().await?;
133
+ println!("Status: {}", resp.status());
134
+ println!("Body: {}", resp.text().await?);
135
+
136
+ // Streaming body
137
+ let mut resp = client.get("https://httpbin.org/stream/3").send().await?;
138
+ let mut stream = resp.bytes_stream()?;
139
+ while let Some(chunk) = stream.next().await {
140
+ println!("chunk: {} bytes", chunk?.len());
141
+ }
142
+
143
+ Ok(())
144
+ }
145
+ ```
146
+
147
+ The opt-in `json` feature adds `RequestBuilder::json()` / `Response::json()` Serde helpers, and `resolved_addresses()` pins caller-validated destinations without a second DNS lookup. See [`docs/rust/guide.md`](docs/rust/guide.md) for the full Rust API reference.
148
+
149
+ ## Usage -- CLI
150
+
151
+ ```bash
152
+ # GET request
153
+ eggfetch https://httpbin.org/get
154
+
155
+ # POST JSON
156
+ eggfetch -X POST https://httpbin.org/post --json '{"key": "value"}'
157
+
158
+ # With authentication
159
+ eggfetch --auth user:pass https://httpbin.org/basic-auth/user/pass
160
+
161
+ # Streaming download
162
+ eggfetch --output file.bin https://httpbin.org/stream-bytes/10000
163
+
164
+ # Machine-readable output
165
+ eggfetch --json-output https://httpbin.org/get
166
+ ```
167
+
168
+ See [`docs/cli/guide.md`](docs/cli/guide.md) for the full CLI reference.
169
+
170
+ ## Examples
171
+
172
+ Runnable starting points (each takes an optional base URL argument, default `https://httpbin.org`):
173
+
174
+ - [`crates/eggfetch-core/examples/quickstart.rs`](crates/eggfetch-core/examples/quickstart.rs) — core client: configured GET/POST, timeout override, auth, streaming (`cargo run -p eggfetch-core --example quickstart`)
175
+ - [`examples/python_sync.py`](examples/python_sync.py) — sync client, JSON POST, streaming download
176
+ - [`examples/python_async.py`](examples/python_async.py) — async client with concurrent requests
177
+
178
+ More patterns are in [`docs/cookbook/`](docs/cookbook/).
179
+
180
+ ## HTTPX Compatibility
181
+
182
+ Two versioned, independent facades over the single Rust engine — `eggfetch.compat.httpx` (0.28.1) and `eggfetch.compat.httpx2` (2.12.0, adds `FunctionAuth`, `Origin`/`URL.origin`, `QUERY`, SSE, optional WebSocket). Both are Stage C qualified on frozen executable SHA `22a6f5c0dc0207c1356b6143c0eda3d4075063b0`; HTTPX 1.0 preview under `compat/httpx/1.0-preview/` is reconnaissance only.
183
+
184
+ See [`docs/reference/compatibility.md`](docs/reference/compatibility.md) for the full feature matrix and retained differences.
185
+
186
+ ## Documentation
187
+
188
+ | Section | Description |
189
+ |---------|-------------|
190
+ | [getting-started/](docs/getting-started/) | Installation and quickstart guide |
191
+ | [concepts/](docs/concepts/) | Architecture, lifecycle, timeouts, streaming, cookies, auth, proxy, TLS |
192
+ | [rust/guide.md](docs/rust/guide.md) | Rust API guide with examples |
193
+ | [python/guide.md](docs/python/guide.md) | Python sync/async API guide |
194
+ | [cli/guide.md](docs/cli/guide.md) | CLI reference and usage guide |
195
+ | [migration/](docs/migration/) | Migration guides from requests and HTTPX |
196
+ | [cookbook/](docs/cookbook/) | Practical runnable examples |
197
+ | [reference/](docs/reference/) | Compatibility matrix, feature matrix, error reference |
198
+ | [security/](docs/security/) | Security guidelines and troubleshooting |
199
+ | [architecture/](docs/architecture/) | Internal architecture documentation |
200
+ | [ffi/](docs/ffi/) | C ABI and FFI binding guide |
201
+
202
+ ## Security
203
+
204
+ - **Dependency auditing:** `cargo-deny` configured in `deny.toml`
205
+ - **Secret redaction:** all `Debug`/`Display`/error output redacts credentials, cookies, bearer tokens, and proxy passwords
206
+ - **Threat model:** see [docs/architecture/threat-model.md](docs/architecture/threat-model.md)
207
+ - **Vulnerability reporting:** see [SECURITY.md](SECURITY.md)
208
+
209
+ ## License
210
+
211
+ eggfetch is licensed under the [MIT License](LICENSE-MIT).
212
+
213
+ ## MSRV
214
+
215
+ 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.
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "eggfetch-core"
3
- version = "0.1.3"
3
+ version = "0.1.4"
4
4
  edition.workspace = true
5
5
  rust-version.workspace = true
6
6
  license.workspace = true
@@ -16,18 +16,28 @@ categories = ["network-programming", "web-programming", "asynchronous"]
16
16
  workspace = true
17
17
 
18
18
  [features]
19
- default = ["http1", "tls-rustls"]
20
- http1 = ["hyper/http1", "hyper-util/http1", "hyper-rustls/http1"]
21
- http2 = ["dep:h2", "hyper/http2", "hyper-util/http2", "hyper-rustls/http2"]
22
- tls-rustls = []
23
- http3 = ["dep:quinn", "dep:h3", "dep:h3-quinn"]
24
- json = []
19
+ default = ["http1", "tls-rustls", "tls-native-roots"]
20
+ http1 = ["hyper/http1", "hyper-util/http1", "hyper-rustls?/http1"]
21
+ http2 = ["dep:h2", "hyper/http2", "hyper-util/http2", "hyper-rustls?/http2"]
22
+ tls-rustls = [
23
+ "dep:hyper-rustls",
24
+ "dep:pem-rfc7468",
25
+ "dep:rustls",
26
+ "dep:tokio-rustls",
27
+ "dep:webpki-roots",
28
+ "hyper-rustls/ring",
29
+ "hyper-rustls/logging",
30
+ "hyper-rustls/tls12",
31
+ ]
32
+ tls-native-roots = ["tls-rustls", "dep:rustls-native-certs"]
33
+ http3 = ["http1", "tls-rustls", "dep:quinn", "dep:h3", "dep:h3-quinn"]
34
+ json = ["dep:serde", "dep:serde_json"]
25
35
  compression-gzip = ["dep:async-compression", "async-compression/gzip", "dep:tokio-util", "tokio/io-util", "dep:flate2"]
26
36
  compression-brotli = ["dep:async-compression", "async-compression/brotli", "dep:tokio-util", "tokio/io-util", "dep:brotli"]
27
37
  compression-zstd = ["dep:async-compression", "async-compression/zstd", "dep:tokio-util", "tokio/io-util", "dep:zstd"]
28
38
  compression-deflate = ["dep:async-compression", "async-compression/deflate", "dep:tokio-util", "tokio/io-util", "dep:flate2"]
29
39
  cookies = ["dep:cookie"]
30
- proxy = ["tokio/io-util"]
40
+ proxy = ["http1", "tls-rustls", "tokio/io-util"]
31
41
  tracing = ["dep:tracing"]
32
42
  multipart = []
33
43
  test-util = ["tokio/test-util"]
@@ -40,18 +50,20 @@ futures-util = { version = "0.3", default-features = false, features = ["alloc"]
40
50
  http = "1"
41
51
  http-body = "1"
42
52
  http-body-util = "0.1"
43
- hyper = { version = "1", features = ["client", "http1"] }
53
+ hyper = { version = "1", default-features = false, features = ["client"] }
44
54
  h2 = { version = "0.4", optional = true }
45
- hyper-util = { version = "0.1", features = ["client", "client-legacy", "tokio", "http1"] }
46
- hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "tls12", "ring", "logging", "native-tokio", "webpki-tokio"] }
55
+ hyper-util = { version = "0.1", default-features = false, features = ["client", "client-legacy", "tokio"] }
56
+ hyper-rustls = { version = "0.27", default-features = false, optional = true }
47
57
  pin-project-lite = "0.2"
48
58
  percent-encoding = "2"
49
- rustls = { version = "0.23", default-features = false, features = ["std", "tls12", "ring"] }
50
- rustls-native-certs = "0.8"
51
- tokio = { version = "1", features = ["rt", "net", "time", "sync", "macros", "fs", "io-util"] }
52
- tokio-rustls = { version = "0.26", default-features = false, features = ["logging", "tls12"] }
59
+ rustls = { version = "0.23", default-features = false, features = ["std"], optional = true }
60
+ rustls-native-certs = { version = "0.8", optional = true }
61
+ tokio = { version = "1", default-features = false, features = ["rt", "net", "time", "sync", "macros", "io-util"] }
62
+ tokio-rustls = { version = "0.26", default-features = false, optional = true }
53
63
  url = "2"
54
64
  thiserror = "2"
65
+ serde = { version = "1", optional = true }
66
+ serde_json = { version = "1", optional = true }
55
67
 
56
68
  tower-service = "0.3"
57
69
  base64 = "0.22"
@@ -63,10 +75,9 @@ brotli = { version = "8", optional = true, default-features = false, features =
63
75
  zstd = { version = "0.13", optional = true }
64
76
  tracing = { version = "0.1", optional = true }
65
77
  getrandom = "0.2"
66
- httparse = "1"
67
78
  httpdate = "1"
68
- webpki-roots = "0.26"
69
- pem-rfc7468 = { version = "0.1", features = ["alloc"] }
79
+ webpki-roots = { version = "0.26", optional = true }
80
+ pem-rfc7468 = { version = "0.1", features = ["alloc"], optional = true }
70
81
  quinn = { version = "0.11", default-features = false, features = ["rustls", "ring", "runtime-tokio"], optional = true }
71
82
  # Pinned h3 0.0.8: the `i-implement-...` feature only removes
72
83
  # `#[non_exhaustive]` from error variants and exposes `ConnectionState`