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.
- {eggfetch-0.1.0 → eggfetch-0.1.3}/Cargo.lock +34 -13
- {eggfetch-0.1.0 → eggfetch-0.1.3}/Cargo.toml +2 -1
- eggfetch-0.1.3/PKG-INFO +392 -0
- {eggfetch-0.1.0/crates/eggfetch-core → eggfetch-0.1.3}/README.md +101 -14
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/Cargo.toml +24 -8
- {eggfetch-0.1.0/crates/eggfetch-python → eggfetch-0.1.3/crates/eggfetch-core}/README.md +101 -14
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/body.rs +447 -11
- eggfetch-0.1.3/crates/eggfetch-core/src/client.rs +1607 -0
- eggfetch-0.1.3/crates/eggfetch-core/src/compression.rs +1400 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/cookie.rs +416 -119
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/error.rs +10 -1
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/headers.rs +158 -6
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/http_version.rs +1 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/lib.rs +14 -3
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/limits.rs +87 -7
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/multipart.rs +294 -38
- eggfetch-0.1.3/crates/eggfetch-core/src/network_stream.rs +611 -0
- eggfetch-0.1.3/crates/eggfetch-core/src/pipeline.rs +2338 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/pool.rs +494 -89
- eggfetch-0.1.3/crates/eggfetch-core/src/proxy.rs +1801 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/redact.rs +8 -10
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/redirect.rs +128 -30
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/request.rs +281 -33
- eggfetch-0.1.3/crates/eggfetch-core/src/response.rs +934 -0
- eggfetch-0.1.3/crates/eggfetch-core/src/response_decode.rs +170 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/retry.rs +154 -40
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/stream/read_timeout.rs +39 -10
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/stream/write_timeout.rs +70 -12
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/timeout.rs +8 -7
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/tls.rs +529 -103
- eggfetch-0.1.3/crates/eggfetch-core/src/trace.rs +368 -0
- eggfetch-0.1.3/crates/eggfetch-core/src/transport/alt_svc.rs +1131 -0
- eggfetch-0.1.3/crates/eggfetch-core/src/transport/connect.rs +587 -0
- eggfetch-0.1.3/crates/eggfetch-core/src/transport/direct.rs +496 -0
- eggfetch-0.1.3/crates/eggfetch-core/src/transport/direct_connector.rs +616 -0
- eggfetch-0.1.3/crates/eggfetch-core/src/transport/http3.rs +1572 -0
- eggfetch-0.1.3/crates/eggfetch-core/src/transport/metrics.rs +543 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/transport/mod.rs +25 -0
- eggfetch-0.1.3/crates/eggfetch-core/src/transport/proxy.rs +1328 -0
- eggfetch-0.1.3/crates/eggfetch-core/src/transport/socks.rs +784 -0
- eggfetch-0.1.3/crates/eggfetch-core/src/transport/uds.rs +270 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/adverse_tests.rs +17 -12
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/cross_feature_tests.rs +52 -0
- eggfetch-0.1.3/crates/eggfetch-core/tests/direct_transport_tests.rs +514 -0
- eggfetch-0.1.3/crates/eggfetch-core/tests/h3_alt_svc_discovery.rs +935 -0
- eggfetch-0.1.3/crates/eggfetch-core/tests/h3_hardening.rs +536 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/h3_integration.rs +1 -1
- eggfetch-0.1.3/crates/eggfetch-core/tests/h3_interop_qualification.rs +937 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/http2_tests.rs +35 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/integration.rs +1 -1
- eggfetch-0.1.3/crates/eggfetch-core/tests/network_stream_tests.rs +695 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/pool_tests.rs +50 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/proxy_tests.rs +691 -8
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/retry_integration.rs +135 -1
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/tls_fixtures.rs +13 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/tls_integration.rs +42 -0
- eggfetch-0.1.3/crates/eggfetch-core/tests/trailer_tests.rs +208 -0
- eggfetch-0.1.3/crates/eggfetch-core/tests/transport_metrics_tests.rs +254 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/Cargo.toml +10 -3
- eggfetch-0.1.3/crates/eggfetch-python/README.md +367 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/async_client.rs +213 -56
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/client.rs +315 -66
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/conversion.rs +191 -42
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/cookies.rs +14 -2
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/errors.rs +3 -0
- eggfetch-0.1.3/crates/eggfetch-python/src/extensions.rs +158 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/headers.rs +22 -30
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/lib.rs +16 -8
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/limits.rs +9 -2
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/multipart.rs +1 -1
- eggfetch-0.1.3/crates/eggfetch-python/src/network_stream.rs +847 -0
- eggfetch-0.1.3/crates/eggfetch-python/src/proxy.rs +177 -0
- eggfetch-0.1.3/crates/eggfetch-python/src/response.rs +577 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/retry.rs +14 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/streaming.rs +345 -163
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/timeout.rs +18 -6
- eggfetch-0.1.3/crates/eggfetch-python/src/tls.rs +270 -0
- eggfetch-0.1.3/crates/eggfetch-python/src/trace_bridge.rs +253 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/fixtures.py +8 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/native_fixtures.py +935 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_auth.py +87 -7
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_auth_input_normalization.py +184 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_client.py +4 -1
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_client_mutability_and_state.py +318 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_client_stream_overrides.py +142 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_config_objects.py +98 -4
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_cookie_scope_parity.py +273 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_cookies.py +40 -17
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_corrective_01_tls_and_proxy_trust_safety.py +449 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_corrective_01_tls_network_proof.py +368 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_corrective_02_extensions_and_wire_metadata.py +364 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_corrective_03_network_stream_upgrade.py +798 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_corrective_kernel.py +375 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_environment.py +56 -5
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_exceptions.py +56 -10
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_extensions.py +84 -22
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_h2_differential.py +647 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_headers.py +92 -2
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_hook_auth_ordering.py +70 -30
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_hook_cookie_auth_ordering.py +230 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_hooks.py +91 -6
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_httpx2_api_parity.py +186 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_httpx2_behavior.py +96 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_httpx2_sse.py +119 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_httpx2_websocket.py +209 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_httpx_reference_pinning.py +173 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_lossy_conversions.py +13 -4
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_merge_matrix.py +4 -1
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_mounts.py +175 -12
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_multihop_cleanup.py +178 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_native_proxy_tls.py +255 -1
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_native_timeout_classification.py +37 -42
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_no_proxy_differential.py +429 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_protocol_and_unsupported_options.py +169 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_proxy_differential.py +153 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_proxy_phase05_tracks.py +461 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_raw_stream_httpx_differential.py +638 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_raw_stream_lifecycle.py +102 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_redirect_state_machine_parity.py +477 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_request.py +7 -6
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_request_construction_parity.py +215 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_request_stream_state.py +138 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_request_streaming.py +5 -3
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_response.py +50 -4
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_response_encoding_parity.py +70 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_response_metadata_parity.py +111 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_response_status_and_redirect_state.py +151 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_response_stream_state_parity.py +199 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_response_streaming.py +5 -6
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_socks_transport.py +301 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_ssl_context_network_proof.py +672 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_ssl_context_translation.py +412 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_stream_resources.py +28 -2
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_timeout_proxysis.py +13 -12
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_timeout_reference_differential.py +119 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_top_level_helpers_parity.py +366 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_trace_detection.py +131 -0
- eggfetch-0.1.3/crates/eggfetch-python/tests/compat/test_uds_transport.py +233 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_url_query.py +104 -1
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_async.py +7 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_http2.py +8 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_response_compat.py +3 -1
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_retry.py +14 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_sync.py +60 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/pyproject.toml +8 -3
- eggfetch-0.1.3/python/eggfetch/compat/httpx/__init__.py +651 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_asgi.py +2 -1
- {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_auth.py +19 -14
- eggfetch-0.1.3/python/eggfetch/compat/httpx/_client.py +2622 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx/_cookies.py +265 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_diagnostics.py +14 -1
- {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_exceptions.py +15 -3
- {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_headers.py +34 -13
- {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_mock.py +8 -3
- eggfetch-0.1.3/python/eggfetch/compat/httpx/_proxy.py +113 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx/_request.py +443 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx/_response.py +782 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx/_ssl_context.py +531 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx/_status_codes.py +74 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_stream.py +25 -19
- eggfetch-0.1.3/python/eggfetch/compat/httpx/_timeout.py +166 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_transports.py +86 -62
- {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_urls.py +38 -5
- {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/httpx/_wsgi.py +2 -1
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/__init__.py +257 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/_alias.py +79 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/_api.py +220 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/_asgi.py +7 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/_auth.py +40 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/_client.py +279 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/_config.py +49 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/_cookies.py +7 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/_exceptions.py +80 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/_headers.py +51 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/_mock.py +7 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/_request.py +7 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/_response.py +7 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/_sse.py +214 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/_status_codes.py +108 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/_stream.py +7 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/_transports.py +7 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/_urls.py +75 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/_wsgi.py +7 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/websockets/__init__.py +57 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/websockets/_api.py +1664 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/websockets/_exceptions.py +55 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/websockets/_ping.py +43 -0
- eggfetch-0.1.3/python/eggfetch/compat/httpx2/websockets/_transport.py +289 -0
- eggfetch-0.1.0/PKG-INFO +0 -19
- eggfetch-0.1.0/crates/eggfetch-core/src/client.rs +0 -911
- eggfetch-0.1.0/crates/eggfetch-core/src/compression.rs +0 -875
- eggfetch-0.1.0/crates/eggfetch-core/src/pipeline.rs +0 -872
- eggfetch-0.1.0/crates/eggfetch-core/src/proxy.rs +0 -986
- eggfetch-0.1.0/crates/eggfetch-core/src/response.rs +0 -472
- eggfetch-0.1.0/crates/eggfetch-core/src/response_decode.rs +0 -54
- eggfetch-0.1.0/crates/eggfetch-core/src/transport/connect.rs +0 -284
- eggfetch-0.1.0/crates/eggfetch-core/src/transport/direct.rs +0 -139
- eggfetch-0.1.0/crates/eggfetch-core/src/transport/http3.rs +0 -261
- eggfetch-0.1.0/crates/eggfetch-core/src/transport/proxy.rs +0 -418
- eggfetch-0.1.0/crates/eggfetch-python/src/proxy.rs +0 -63
- eggfetch-0.1.0/crates/eggfetch-python/src/response.rs +0 -354
- eggfetch-0.1.0/crates/eggfetch-python/src/tls.rs +0 -54
- eggfetch-0.1.0/crates/eggfetch-python/tests/compat/native_fixtures.py +0 -354
- eggfetch-0.1.0/python/eggfetch/compat/httpx/__init__.py +0 -231
- eggfetch-0.1.0/python/eggfetch/compat/httpx/_client.py +0 -1168
- eggfetch-0.1.0/python/eggfetch/compat/httpx/_cookies.py +0 -121
- eggfetch-0.1.0/python/eggfetch/compat/httpx/_proxy.py +0 -70
- eggfetch-0.1.0/python/eggfetch/compat/httpx/_request.py +0 -292
- eggfetch-0.1.0/python/eggfetch/compat/httpx/_response.py +0 -497
- eggfetch-0.1.0/python/eggfetch/compat/httpx/_status_codes.py +0 -80
- eggfetch-0.1.0/python/eggfetch/compat/httpx/_timeout.py +0 -124
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/auth.rs +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/config.rs +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/h2_headers.rs +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/stream/mod.rs +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/src/transport/connect_timeout.rs +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/http3_tests.rs +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/resource_stabilization.rs +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/test_server.rs +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-core/tests/timeout_tests.rs +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/src/auth.rs +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/__init__.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/conftest.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_asgi.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_auth_replay.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_backends.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_behavior_cases.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_downstream_portfolio.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_downstream_runner_negative.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_httpx_extras.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_httpx_required.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_imports.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_lifecycle.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_merge_lossless.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_mock_transport.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_oracle_negative.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_resource_assertions.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_shutdown.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_soak.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_timeout_integration.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_transports.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/compat/test_wsgi.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/conftest.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_auth.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_close_races.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_cookie_auth.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_cookies.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_differential.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_interpreter_shutdown.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_parity.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_proxy.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_redirects.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/crates/eggfetch-python/tests/test_streaming.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/__init__.py +0 -0
- {eggfetch-0.1.0 → eggfetch-0.1.3}/python/eggfetch/compat/__init__.py +0 -0
- {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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
800
|
+
version = "0.4.16"
|
|
792
801
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
793
|
-
checksum = "
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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]
|
eggfetch-0.1.3/PKG-INFO
ADDED
|
@@ -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
|
+
[](https://github.com/eggstack/eggfetch/actions/workflows/ci.yml)
|
|
28
|
+
[](https://crates.io/crates/eggfetch-core)
|
|
29
|
+
[](https://crates.io/crates/eggfetch-core)
|
|
30
|
+
[](https://pypi.org/project/eggfetch/)
|
|
31
|
+
[](https://pepy.tech/projects/eggfetch)
|
|
32
|
+
[](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
|
+
|