lkrequest 0.1.0__tar.gz → 0.2.0__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 (82) hide show
  1. {lkrequest-0.1.0 → lkrequest-0.2.0}/.github/workflows/ci.yml +10 -22
  2. lkrequest-0.2.0/CHANGELOG.md +62 -0
  3. {lkrequest-0.1.0 → lkrequest-0.2.0}/CONTRIBUTING.md +1 -1
  4. {lkrequest-0.1.0 → lkrequest-0.2.0}/Cargo.lock +137 -136
  5. {lkrequest-0.1.0 → lkrequest-0.2.0}/Cargo.toml +1 -1
  6. lkrequest-0.1.0/README.md → lkrequest-0.2.0/PKG-INFO +49 -4
  7. {lkrequest-0.1.0 → lkrequest-0.2.0}/README-zh.md +20 -4
  8. lkrequest-0.1.0/PKG-INFO → lkrequest-0.2.0/README.md +20 -33
  9. {lkrequest-0.1.0 → lkrequest-0.2.0}/pyproject.toml +4 -5
  10. {lkrequest-0.1.0 → lkrequest-0.2.0}/python/lkrequest/__init__.py +6 -0
  11. {lkrequest-0.1.0 → lkrequest-0.2.0}/python/lkrequest/_lkrequest.pyi +39 -0
  12. lkrequest-0.2.0/src/bridge.rs +275 -0
  13. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/client.rs +77 -2
  14. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/fingerprint.rs +36 -0
  15. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/lib.rs +36 -0
  16. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/proxy.rs +1 -1
  17. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/quic.rs +10 -0
  18. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/response.rs +5 -5
  19. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/session.rs +6 -6
  20. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/session_pool.rs +7 -7
  21. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/types.rs +4 -2
  22. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/websocket.rs +5 -5
  23. {lkrequest-0.1.0 → lkrequest-0.2.0}/tests/conftest.py +48 -1
  24. {lkrequest-0.1.0 → lkrequest-0.2.0}/tests/test_advanced.py +39 -0
  25. {lkrequest-0.1.0 → lkrequest-0.2.0}/tests/test_followup_features.py +69 -1
  26. lkrequest-0.2.0/tests/test_local_server.py +413 -0
  27. lkrequest-0.1.0/CHANGELOG.md +0 -41
  28. lkrequest-0.1.0/tests/test_local_server.py +0 -120
  29. {lkrequest-0.1.0 → lkrequest-0.2.0}/.editorconfig +0 -0
  30. {lkrequest-0.1.0 → lkrequest-0.2.0}/.gitignore +0 -0
  31. {lkrequest-0.1.0 → lkrequest-0.2.0}/LICENSE +0 -0
  32. {lkrequest-0.1.0 → lkrequest-0.2.0}/NOTICE +0 -0
  33. {lkrequest-0.1.0 → lkrequest-0.2.0}/SECURITY.md +0 -0
  34. {lkrequest-0.1.0 → lkrequest-0.2.0}/benchmarks/README.md +0 -0
  35. {lkrequest-0.1.0 → lkrequest-0.2.0}/benchmarks/bench_latency.py +0 -0
  36. {lkrequest-0.1.0 → lkrequest-0.2.0}/benchmarks/bench_memory.py +0 -0
  37. {lkrequest-0.1.0 → lkrequest-0.2.0}/benchmarks/bench_throughput.py +0 -0
  38. {lkrequest-0.1.0 → lkrequest-0.2.0}/benchmarks/requirements.txt +0 -0
  39. {lkrequest-0.1.0 → lkrequest-0.2.0}/build.rs +0 -0
  40. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/accept_encoding.py +0 -0
  41. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/authentication.py +0 -0
  42. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/basic_requests.py +0 -0
  43. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/browser_fingerprints.py +0 -0
  44. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/certificate_config.py +0 -0
  45. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/client_pool.py +0 -0
  46. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/connection_prewarming.py +0 -0
  47. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/cookie_management.py +0 -0
  48. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/custom_fingerprint.py +0 -0
  49. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/error_handling.py +0 -0
  50. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/event_hooks.py +0 -0
  51. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/fingerprint_validation.py +0 -0
  52. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/http_methods.py +0 -0
  53. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/logging_config.py +0 -0
  54. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/metrics.py +0 -0
  55. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/middleware.py +0 -0
  56. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/multipart_upload.py +0 -0
  57. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/pool_stats.py +0 -0
  58. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/proxy_pool.py +0 -0
  59. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/redirect_history.py +0 -0
  60. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/response_inspection.py +0 -0
  61. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/retry_strategies.py +0 -0
  62. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/session_pool.py +0 -0
  63. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/streaming_response.py +0 -0
  64. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/timeout_config.py +0 -0
  65. {lkrequest-0.1.0 → lkrequest-0.2.0}/examples/websocket.py +0 -0
  66. {lkrequest-0.1.0 → lkrequest-0.2.0}/justfile +0 -0
  67. {lkrequest-0.1.0 → lkrequest-0.2.0}/python/lkrequest/blocking.py +0 -0
  68. {lkrequest-0.1.0 → lkrequest-0.2.0}/python/lkrequest/pcap.py +0 -0
  69. {lkrequest-0.1.0 → lkrequest-0.2.0}/rustfmt.toml +0 -0
  70. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/client_pool.rs +0 -0
  71. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/error.rs +0 -0
  72. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/hsts.rs +0 -0
  73. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/metrics.rs +0 -0
  74. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/middleware.rs +0 -0
  75. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/multipart.rs +0 -0
  76. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/priority.rs +0 -0
  77. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/protocol.rs +0 -0
  78. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/randomize.rs +0 -0
  79. {lkrequest-0.1.0 → lkrequest-0.2.0}/src/retry.rs +0 -0
  80. {lkrequest-0.1.0 → lkrequest-0.2.0}/tests/test_client.py +0 -0
  81. {lkrequest-0.1.0 → lkrequest-0.2.0}/tests/test_package_metadata.py +0 -0
  82. {lkrequest-0.1.0 → lkrequest-0.2.0}/tests/test_stub_parity.py +0 -0
@@ -159,37 +159,25 @@ jobs:
159
159
  dist/*.tar.gz
160
160
  fail_on_unmatched_files: true
161
161
 
162
- check-pypi-token:
163
- name: Check PyPI token
164
- if: startsWith(github.ref, 'refs/tags/v')
165
- runs-on: ubuntu-latest
166
- outputs:
167
- configured: ${{ steps.check.outputs.configured }}
168
- steps:
169
- - id: check
170
- env:
171
- PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
172
- run: |
173
- if [ -n "$PYPI_API_TOKEN" ]; then
174
- echo "configured=true" >> "$GITHUB_OUTPUT"
175
- echo "PYPI_API_TOKEN is set; publish-pypi will run."
176
- else
177
- echo "configured=false" >> "$GITHUB_OUTPUT"
178
- echo "::notice::PYPI_API_TOKEN is not set; skipping publish-pypi (GitHub Release assets are unaffected)."
179
- fi
180
-
181
162
  publish-pypi:
182
163
  name: Publish to PyPI
183
- if: startsWith(github.ref, 'refs/tags/v') && needs.check-pypi-token.outputs.configured == 'true'
184
- needs: [test-wheel, build-sdist, check-pypi-token]
164
+ if: startsWith(github.ref, 'refs/tags/v')
165
+ needs: [test-wheel, build-sdist]
185
166
  runs-on: ubuntu-latest
167
+ environment:
168
+ name: lkrequest-py
169
+ url: https://pypi.org/project/lkrequest/
170
+ permissions:
171
+ id-token: write
186
172
  steps:
173
+ # Only the release artifacts — anything else added to this workflow later
174
+ # would otherwise land in dist/ and be rejected as an invalid package.
187
175
  - uses: actions/download-artifact@v4
188
176
  with:
177
+ pattern: "{wheel-*,sdist}"
189
178
  path: dist
190
179
  merge-multiple: true
191
180
  - name: Publish
192
181
  uses: pypa/gh-action-pypi-publish@release/v1
193
182
  with:
194
183
  packages-dir: dist
195
- password: ${{ secrets.PYPI_API_TOKEN }}
@@ -0,0 +1,62 @@
1
+ # Changelog
2
+
3
+ All important changes to this project will be documented in this file.
4
+
5
+ ## lkrequest-py 0.2.0
6
+
7
+ ### 🚀 Features
8
+ - **System DNS Positive Cache** — Added `system_dns_cache_ttl` and `system_dns_cache_max_entries` to `Client` and `BlockingClient`. The OS resolver already coalesces concurrent identical lookups process-wide; these cache successful, non-empty results for `ttl` seconds (default capacity 1024 entries). A `0` TTL keeps the coalescing while disabling the cache. It selects the system resolver, so it cannot be combined with `dns`; errors and empty results are never cached.
9
+ - **Shutdown Draining** — Added `drain_pending(timeout=None)`, its blocking counterpart `blocking_drain_pending(...)`, and `pending_requests()`. Waiting for in-flight work before tearing down an event loop means results are still delivered rather than dropped on arrival. Counts are process-wide and cover every async call, not only requests.
10
+ - **HTTP/2 Pending-Request Bound** — Added `max_pending_h2_requests` to `Client` and `BlockingClient`. HTTP/2 requests that exceed the peer's concurrent-stream limit now wait for a stream slot instead of failing, and this option caps how many may queue. Omit it (the default) for an unbounded queue; `0` is rejected with `ValueError`.
11
+ - **Synthetic Fingerprint Negotiability (`synthetic-fp`)** — Added `NegotiabilityFloor.UNIVERSAL`, `NegotiabilityFloor.PRESET_FAMILY`, `NegotiabilityFloor.custom(...)`, and `Randomize.negotiability(...)` so synthesized ClientHello profiles retain a configurable signature-algorithm compatibility floor.
12
+ - **Multi-hop Proxy Chains** — Added `ProxyConfig.parse_chain(...)` and `.through(...)`, with chain metadata via `hop_count()` and `identity()`. Client sessions, proxy pools, and session pools now accept either proxy URLs or `ProxyConfig` objects.
13
+ - **Mixed Proxy Transports** — HTTP/1.1 and HTTP/2 can traverse ordered combinations of HTTP CONNECT, SOCKS5, and SOCKS5H hops. QUIC/HTTP3 supports all-SOCKS5 chains when the optional `quic-h3` feature is enabled.
14
+ - **QUIC-TLS Profile Presets** — Added `TlsProfile.chrome_146_quic()`, `TlsProfile.chrome_150_quic()`, and `TlsProfile.chrome_151_quic()`, exposing the ClientHello Chrome sends inside QUIC (previously reachable only through the bundled `Client.chrome_1xx()` presets). Pass one to `Client(quic_fingerprint=...)` when building a client manually; HTTP/3 otherwise reuses the main TLS profile.
15
+ - **Chrome 151 Preset** — Added `Client.chrome_151()`, `BlockingClient.chrome_151()`, `TlsProfile.chrome_151()`, `H2Profile.chrome_151()`, `QuicProfile.chrome_151()`, and the `"chrome_151"` TLS/H2/QUIC profile names. Captured from Chrome 151.0.7922.72: TCP TLS and HTTP/2 keep Chrome 150's stable fields, while the QUIC-TLS capture omits the three ML-DSA signature algorithms; QUIC transport parameters and HTTP/3 SETTINGS stay aligned with Chrome 150.
16
+ - **Chrome 150 QUIC/H3 (`quic-h3`)** — `Client.chrome_150()` now uses dedicated Chrome 150 QUIC TLS and HTTP/3 profiles instead of reusing Chrome 146. The preset covers captured signature algorithms, QUIC transport parameters, QPACK limits, navigation `PRIORITY_UPDATE`, connection-ID lengths, and Initial datagram sizing. Added `QuicProfile.chrome_150()` and the `"chrome_150"` QUIC profile name.
17
+
18
+ ### 🐞 Fixes
19
+ - **No More Crashes From Late-Completing Requests** — A request that finished after its event loop had closed used to print a `RuntimeError: Event loop is closed` traceback from whichever worker thread it landed on. Enough of them at once turned into `Fatal Python error: _enter_buffered_busy` and killed the process with SIGABRT — uncatchable, and it took the whole batch down. Results arriving after the loop closes are now dropped silently, since nothing is left to receive them.
20
+ - **Multi-Address Connect Fallback** — Connecting now tries every address a hostname resolves to, racing them Happy Eyeballs style (RFC 8305) with interleaved address families, rather than giving up when the first candidate is unreachable. Applies to direct TCP and to SOCKS5 proxies.
21
+ - **HTTP/2 Stream-Limit Backpressure** — Requests beyond the peer's advertised `MAX_CONCURRENT_STREAMS` now wait asynchronously for a stream slot instead of failing with a local capacity error.
22
+ - **Redirects Over Reused HTTP/1.1 Connections** — Following a redirect no longer fails when the pooled HTTP/1.1 connection was torn down in the meantime. The reuse attempt surfaces as hyper's `operation was canceled`, which is now recognised as a closed connection, so the request is retried on a fresh connection instead of erroring out. Affects any server that hangs up after answering a `3xx` — a common pattern after `POST`.
23
+ - **HTTP/2 `1xx` Interim Responses** — The HTTP/2 driver now consumes `1xx` informational responses — such as the `103 Early Hints` Cloudflare sends ahead of its `200` — and returns the final response that follows, instead of reporting the interim status as the final one. A plain `GET https://www.cloudflare.com/` previously came back as `103`.
24
+ - **Connection Limit Enforcement** — `max_connections` now bounds *physical* connections, counting those still being dialled and those checked out by an in-flight request rather than only what sits idle in the pool. Exceeding the limit raises instead of quietly opening another connection, and an idle HTTP/1.1 connection is evicted first so one origin's idle connections cannot starve another. `PoolStats.total` correspondingly reports physical connections in use rather than pooled entries.
25
+ - **Optional Client Certificate Requests** — A server that asks for a client certificate no longer breaks the handshake. TLS 1.2 and TLS 1.3 now answer a `CertificateRequest` with an empty client `Certificate` message — echoing the request context on TLS 1.3, as RFC 8446 §4.4.2 requires — so endpoints with optional mutual TLS complete the handshake instead of failing.
26
+ - **TLS Handshake Reassembly** — TLS 1.2 and TLS 1.3 handshake messages fragmented across multiple records are now buffered and reassembled correctly, preventing failures such as `truncated handshake message in record` without changing ClientHello or fingerprint output.
27
+ - **SOCKS5 UDP Relay Compatibility** — QUIC-over-SOCKS5 accepts relay replies from the advertised source IP even when the relay uses a different egress port, preventing affected HTTP/3 requests from hanging.
28
+ - **Package Version Reporting** — `lkrequest.__version__` is now read from installed distribution metadata instead of being maintained as a separate hard-coded value.
29
+ - **TLS 1.3 ECH + HelloRetryRequest** — Real ECH CH2 now reuses the ECH configuration, HPKE sender context, Inner random, GREASE values, extension permutation, and fake ECH bytes. HRR confirmation, selected groups, cookie-only retries, invalid extensions, dummy CCS, and local fatal alerts now follow the browser/RFC flow.
30
+ - **ECH + PSK + HRR Binders** — `pre_shared_key` remains exclusively in `ClientHelloInner`; CH1 and CH2 binders now use the correct truncated Inner transcripts, including `message_hash(ClientHelloInner1) + HRR` for CH2.
31
+ - **QUIC/H3 HRR State Transitions** — QUIC revokes 0-RTT stream and packet state after HRR and maps local TLS alerts to QUIC `CRYPTO_ERROR` codes.
32
+
33
+ ## lkrequest-py 0.1.1
34
+
35
+ ### 🐞 Fixes
36
+ - **Project URLs** — `Homepage`, `Repository`, and `Issues` in the package metadata pointed at a repository path that does not exist, so every link on the PyPI project page returned 404. They now point at `github.com/EZ-XLabs/lkrequest-py`.
37
+ - **README Links on PyPI** — the language switcher at the top of both READMEs used relative paths (`README.md` / `README-zh.md`), which PyPI cannot resolve when it renders the long description. Both now use absolute URLs, so switching between English and 简体中文 works from the project page.
38
+
39
+ ### 📝 Documentation
40
+ - **Development Setup** — the setup section now walks through the full local workflow on Linux/macOS and Windows: creating and activating a virtualenv, installing maturin, `pip install -e ".[test,lint]"`, and running the suite via `just test`. An equivalent `uv sync --extra test --extra lint` path is documented alongside it.
41
+
42
+ ## lkrequest-py 0.1.0
43
+
44
+ ### 🚀 Features
45
+ - **TLS Fingerprint Control** — Byte-level ClientHello generation that matches real browsers (Chrome, Firefox, Safari)
46
+ - **HTTP/2 Fingerprint Control** — SETTINGS frame order, pseudo-header order, WINDOW_UPDATE, PRIORITY frames, and per-request priority weights
47
+ - **HTTP/3 + QUIC** — Optional `quic-h3` feature for full HTTP/3 over QUIC with fingerprint-aware Transport Parameters, Alt-Svc auto-discovery, and H2→H3 seamless upgrade
48
+ - **Built-in Browser Presets** — Chrome 131/144/145/146/147/148/149/150, Firefox 133/147, Safari 18/26 (TLS + H2, plus QUIC when `quic-h3` is enabled)
49
+ - **Session Management** — Cookie jars, connection pooling, HTTP/2 multiplexing, and optional QUIC 0-RTT session resumption
50
+ - **Connection Prewarming** — `session.preconnect()` pre-establishes DNS + TCP + TLS + H2 (or, with `quic-h3`, QUIC + H3) connections
51
+ - **Custom DNS Resolver** — Pluggable DNS with DoH support, auto ECH config and H3 hints via HTTPS/SVCB records
52
+ - **Alt-Svc Discovery** — Automatic HTTP/2 → HTTP/3 protocol upgrade via Alt-Svc headers with broken-QUIC fallback
53
+ - **SessionPool** — High-concurrency pool with proxy rotation (round-robin / random)
54
+ - **Proxy Support** — SOCKS5 and HTTP CONNECT with authentication
55
+ - **WebSocket** — HTTP/1.1 Upgrade (RFC 6455) and H2 Extended CONNECT (RFC 8441)
56
+ - **Middleware** — Interceptor chain for request/response modification
57
+ - **Retry Policies** — Exponential backoff, fixed interval, custom strategies; idempotency-aware (non-idempotent methods are not silently replayed after a possibly-already-sent failure unless marked `Idempotency::Idempotent`)
58
+ - **Redirect Control** — `RedirectPolicy::Follow(n)` or `RedirectPolicy::None` for manual handling
59
+ - **Auto-Decompression** — Brotli, gzip, deflate, zstd
60
+ - **Blocking API** — Synchronous wrapper for non-async contexts
61
+ - **Multipart/Form-Data** — File uploads with streaming support
62
+ - **TCP Fingerprint** — JA4T-style TCP SYN fingerprinting
@@ -7,7 +7,7 @@ binding over the `lkrequest` Rust workspace, built with
7
7
  ## Development setup
8
8
 
9
9
  ```bash
10
- git clone https://github.com/ez-opensource/lkrequest-py
10
+ git clone https://github.com/EZ-XLabs/lkrequest-py
11
11
  cd lkrequest-py
12
12
  python3 -m venv .venv # Linux/macOS
13
13
  # py -m venv .venv # Windows