lkrequest 0.1.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 (79) hide show
  1. lkrequest-0.1.0/.editorconfig +23 -0
  2. lkrequest-0.1.0/.github/workflows/ci.yml +195 -0
  3. lkrequest-0.1.0/.gitignore +20 -0
  4. lkrequest-0.1.0/CHANGELOG.md +41 -0
  5. lkrequest-0.1.0/CONTRIBUTING.md +74 -0
  6. lkrequest-0.1.0/Cargo.lock +3214 -0
  7. lkrequest-0.1.0/Cargo.toml +64 -0
  8. lkrequest-0.1.0/LICENSE +201 -0
  9. lkrequest-0.1.0/NOTICE +9 -0
  10. lkrequest-0.1.0/PKG-INFO +900 -0
  11. lkrequest-0.1.0/README-zh.md +870 -0
  12. lkrequest-0.1.0/README.md +871 -0
  13. lkrequest-0.1.0/SECURITY.md +28 -0
  14. lkrequest-0.1.0/benchmarks/README.md +49 -0
  15. lkrequest-0.1.0/benchmarks/bench_latency.py +95 -0
  16. lkrequest-0.1.0/benchmarks/bench_memory.py +75 -0
  17. lkrequest-0.1.0/benchmarks/bench_throughput.py +126 -0
  18. lkrequest-0.1.0/benchmarks/requirements.txt +5 -0
  19. lkrequest-0.1.0/build.rs +7 -0
  20. lkrequest-0.1.0/examples/accept_encoding.py +70 -0
  21. lkrequest-0.1.0/examples/authentication.py +44 -0
  22. lkrequest-0.1.0/examples/basic_requests.py +101 -0
  23. lkrequest-0.1.0/examples/browser_fingerprints.py +88 -0
  24. lkrequest-0.1.0/examples/certificate_config.py +59 -0
  25. lkrequest-0.1.0/examples/client_pool.py +77 -0
  26. lkrequest-0.1.0/examples/connection_prewarming.py +91 -0
  27. lkrequest-0.1.0/examples/cookie_management.py +80 -0
  28. lkrequest-0.1.0/examples/custom_fingerprint.py +268 -0
  29. lkrequest-0.1.0/examples/error_handling.py +98 -0
  30. lkrequest-0.1.0/examples/event_hooks.py +83 -0
  31. lkrequest-0.1.0/examples/fingerprint_validation.py +68 -0
  32. lkrequest-0.1.0/examples/http_methods.py +44 -0
  33. lkrequest-0.1.0/examples/logging_config.py +58 -0
  34. lkrequest-0.1.0/examples/metrics.py +55 -0
  35. lkrequest-0.1.0/examples/middleware.py +108 -0
  36. lkrequest-0.1.0/examples/multipart_upload.py +59 -0
  37. lkrequest-0.1.0/examples/pool_stats.py +60 -0
  38. lkrequest-0.1.0/examples/proxy_pool.py +124 -0
  39. lkrequest-0.1.0/examples/redirect_history.py +72 -0
  40. lkrequest-0.1.0/examples/response_inspection.py +106 -0
  41. lkrequest-0.1.0/examples/retry_strategies.py +98 -0
  42. lkrequest-0.1.0/examples/session_pool.py +94 -0
  43. lkrequest-0.1.0/examples/streaming_response.py +87 -0
  44. lkrequest-0.1.0/examples/timeout_config.py +72 -0
  45. lkrequest-0.1.0/examples/websocket.py +85 -0
  46. lkrequest-0.1.0/justfile +58 -0
  47. lkrequest-0.1.0/pyproject.toml +67 -0
  48. lkrequest-0.1.0/python/lkrequest/__init__.py +215 -0
  49. lkrequest-0.1.0/python/lkrequest/_lkrequest.pyi +1923 -0
  50. lkrequest-0.1.0/python/lkrequest/blocking.py +79 -0
  51. lkrequest-0.1.0/python/lkrequest/pcap.py +161 -0
  52. lkrequest-0.1.0/rustfmt.toml +3 -0
  53. lkrequest-0.1.0/src/client.rs +1289 -0
  54. lkrequest-0.1.0/src/client_pool.rs +113 -0
  55. lkrequest-0.1.0/src/error.rs +48 -0
  56. lkrequest-0.1.0/src/fingerprint.rs +1207 -0
  57. lkrequest-0.1.0/src/hsts.rs +121 -0
  58. lkrequest-0.1.0/src/lib.rs +298 -0
  59. lkrequest-0.1.0/src/metrics.rs +263 -0
  60. lkrequest-0.1.0/src/middleware.rs +188 -0
  61. lkrequest-0.1.0/src/multipart.rs +70 -0
  62. lkrequest-0.1.0/src/priority.rs +91 -0
  63. lkrequest-0.1.0/src/protocol.rs +200 -0
  64. lkrequest-0.1.0/src/proxy.rs +267 -0
  65. lkrequest-0.1.0/src/quic.rs +85 -0
  66. lkrequest-0.1.0/src/randomize.rs +246 -0
  67. lkrequest-0.1.0/src/response.rs +734 -0
  68. lkrequest-0.1.0/src/retry.rs +113 -0
  69. lkrequest-0.1.0/src/session.rs +1865 -0
  70. lkrequest-0.1.0/src/session_pool.rs +332 -0
  71. lkrequest-0.1.0/src/types.rs +438 -0
  72. lkrequest-0.1.0/src/websocket.rs +318 -0
  73. lkrequest-0.1.0/tests/conftest.py +187 -0
  74. lkrequest-0.1.0/tests/test_advanced.py +1589 -0
  75. lkrequest-0.1.0/tests/test_client.py +858 -0
  76. lkrequest-0.1.0/tests/test_followup_features.py +382 -0
  77. lkrequest-0.1.0/tests/test_local_server.py +120 -0
  78. lkrequest-0.1.0/tests/test_package_metadata.py +9 -0
  79. lkrequest-0.1.0/tests/test_stub_parity.py +125 -0
@@ -0,0 +1,23 @@
1
+ root = true
2
+
3
+ [*]
4
+ end_of_line = lf
5
+ insert_final_newline = true
6
+ trim_trailing_whitespace = true
7
+ charset = utf-8
8
+
9
+ [*.rs]
10
+ indent_style = space
11
+ indent_size = 4
12
+
13
+ [*.py]
14
+ indent_style = space
15
+ indent_size = 4
16
+
17
+ [*.{toml,yml,yaml}]
18
+ indent_style = space
19
+ indent_size = 2
20
+
21
+ [Justfile]
22
+ indent_style = space
23
+ indent_size = 4
@@ -0,0 +1,195 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, master]
6
+ tags: ["v*"]
7
+ pull_request:
8
+ branches: [main, master]
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ env:
14
+ CARGO_TERM_COLOR: always
15
+ # Keep PEP 517 source installs aligned with the all-feature release wheels.
16
+ MATURIN_PEP517_ARGS: "--all-features"
17
+
18
+ jobs:
19
+ lint:
20
+ name: Lint
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ - uses: dtolnay/rust-toolchain@stable
25
+ with:
26
+ components: rustfmt, clippy
27
+ - name: cargo fmt --check
28
+ run: cargo fmt --check
29
+ - name: cargo clippy
30
+ run: cargo clippy --all-targets --all-features -- -D warnings
31
+
32
+ test:
33
+ name: Test (source)
34
+ needs: [lint]
35
+ runs-on: ubuntu-latest
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+ - uses: dtolnay/rust-toolchain@stable
39
+ - uses: actions/setup-python@v5
40
+ with:
41
+ python-version: "3.12"
42
+ - name: Build & install (source, all features) + test deps
43
+ run: pip install ".[test]"
44
+ - name: Verify all feature APIs
45
+ run: python -c "import lkrequest; required = ('QuicProfile', 'Layers', 'NegotiabilityFloor'); missing = [name for name in required if not hasattr(lkrequest, name)]; assert not missing, f'missing all-feature APIs:{missing}'"
46
+ - name: Run tests
47
+ run: pytest tests/ -v
48
+
49
+ build-wheels:
50
+ name: Wheel · ${{ matrix.target }}
51
+ needs: [test]
52
+ runs-on: ${{ matrix.runner }}
53
+ strategy:
54
+ fail-fast: false
55
+ matrix:
56
+ include:
57
+ - target: x86_64-unknown-linux-gnu
58
+ runner: ubuntu-latest
59
+ manylinux: "2_28"
60
+ - target: x86_64-pc-windows-msvc
61
+ runner: windows-latest
62
+ manylinux: "auto"
63
+ - target: aarch64-apple-darwin
64
+ runner: macos-15
65
+ manylinux: "auto"
66
+ - target: x86_64-apple-darwin
67
+ runner: macos-15-intel
68
+ manylinux: "auto"
69
+ steps:
70
+ - uses: actions/checkout@v4
71
+ - name: Set up NASM (Windows)
72
+ if: runner.os == 'Windows'
73
+ uses: ilammy/setup-nasm@v1
74
+ - name: Build wheel
75
+ uses: PyO3/maturin-action@v1
76
+ with:
77
+ target: ${{ matrix.target }}
78
+ manylinux: ${{ matrix.manylinux }}
79
+ args: --release --strip --all-features --out dist
80
+ sccache: "true"
81
+ before-script-linux: |
82
+ dnf install -y cmake perl clang || yum install -y cmake perl clang
83
+ - name: Upload wheel artifact
84
+ uses: actions/upload-artifact@v4
85
+ with:
86
+ name: wheel-${{ matrix.target }}
87
+ path: dist/*.whl
88
+ if-no-files-found: error
89
+
90
+ build-sdist:
91
+ name: sdist
92
+ needs: [test]
93
+ runs-on: ubuntu-latest
94
+ steps:
95
+ - uses: actions/checkout@v4
96
+ - name: Build sdist
97
+ uses: PyO3/maturin-action@v1
98
+ with:
99
+ command: sdist
100
+ args: --out dist
101
+ - name: Upload sdist artifact
102
+ uses: actions/upload-artifact@v4
103
+ with:
104
+ name: sdist
105
+ path: dist/*.tar.gz
106
+ if-no-files-found: error
107
+
108
+ test-wheel:
109
+ name: Test wheel · ${{ matrix.os }} · py${{ matrix.python }}
110
+ needs: [build-wheels]
111
+ runs-on: ${{ matrix.os }}
112
+ strategy:
113
+ fail-fast: false
114
+ matrix:
115
+ include:
116
+ - os: ubuntu-latest
117
+ wheel: wheel-x86_64-unknown-linux-gnu
118
+ python: "3.9"
119
+ - os: ubuntu-latest
120
+ wheel: wheel-x86_64-unknown-linux-gnu
121
+ python: "3.12"
122
+ - os: windows-latest
123
+ wheel: wheel-x86_64-pc-windows-msvc
124
+ python: "3.12"
125
+ steps:
126
+ - uses: actions/checkout@v4
127
+ - uses: actions/setup-python@v5
128
+ with:
129
+ python-version: ${{ matrix.python }}
130
+ - uses: actions/download-artifact@v4
131
+ with:
132
+ name: ${{ matrix.wheel }}
133
+ path: dist
134
+ - name: Install wheel + test deps
135
+ shell: bash
136
+ run: pip install "$(ls dist/*.whl)[test]"
137
+ - name: Verify all feature APIs
138
+ run: python -c "import lkrequest; required = ('QuicProfile', 'Layers', 'NegotiabilityFloor'); missing = [name for name in required if not hasattr(lkrequest, name)]; assert not missing, f'missing all-feature APIs:{missing}'"
139
+ - name: Run tests
140
+ run: pytest tests/ -v
141
+
142
+ release-assets:
143
+ name: Upload to GitHub Release
144
+ if: startsWith(github.ref, 'refs/tags/v')
145
+ needs: [test-wheel, build-sdist]
146
+ runs-on: ubuntu-latest
147
+ permissions:
148
+ contents: write
149
+ steps:
150
+ - uses: actions/download-artifact@v4
151
+ with:
152
+ path: dist
153
+ merge-multiple: true
154
+ - name: Attach artifacts to release
155
+ uses: softprops/action-gh-release@v2
156
+ with:
157
+ files: |
158
+ dist/*.whl
159
+ dist/*.tar.gz
160
+ fail_on_unmatched_files: true
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
+ publish-pypi:
182
+ 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]
185
+ runs-on: ubuntu-latest
186
+ steps:
187
+ - uses: actions/download-artifact@v4
188
+ with:
189
+ path: dist
190
+ merge-multiple: true
191
+ - name: Publish
192
+ uses: pypa/gh-action-pypi-publish@release/v1
193
+ with:
194
+ packages-dir: dist
195
+ password: ${{ secrets.PYPI_API_TOKEN }}
@@ -0,0 +1,20 @@
1
+ /target
2
+ __pycache__
3
+ *.pyc
4
+ *.pyo
5
+ *.egg-info
6
+ dist/
7
+ build/
8
+ .venv/
9
+ *.so
10
+ *.pyd
11
+ *.dll
12
+ .pytest_cache/
13
+ .cargo/
14
+ .claude/
15
+ EVOLUTION_PLAN.md
16
+ .idea
17
+ .DS_Store
18
+ CLAUDE.md
19
+ Makefile
20
+ AGENTS.md
@@ -0,0 +1,41 @@
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
+ - **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.
9
+ - **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.
10
+ - **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.
11
+ - **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.
12
+
13
+ ### 🐞 Fixes
14
+ - **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.
15
+ - **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.
16
+ - **Package Version Reporting** — `lkrequest.__version__` is now read from installed distribution metadata instead of being maintained as a separate hard-coded value.
17
+ - **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.
18
+ - **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.
19
+ - **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.
20
+
21
+ ## lkrequest-py 0.1.0
22
+
23
+ ### 🚀 Features
24
+ - **TLS Fingerprint Control** — Byte-level ClientHello generation that matches real browsers (Chrome, Firefox, Safari)
25
+ - **HTTP/2 Fingerprint Control** — SETTINGS frame order, pseudo-header order, WINDOW_UPDATE, PRIORITY frames, and per-request priority weights
26
+ - **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
27
+ - **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)
28
+ - **Session Management** — Cookie jars, connection pooling, HTTP/2 multiplexing, and optional QUIC 0-RTT session resumption
29
+ - **Connection Prewarming** — `session.preconnect()` pre-establishes DNS + TCP + TLS + H2 (or, with `quic-h3`, QUIC + H3) connections
30
+ - **Custom DNS Resolver** — Pluggable DNS with DoH support, auto ECH config and H3 hints via HTTPS/SVCB records
31
+ - **Alt-Svc Discovery** — Automatic HTTP/2 → HTTP/3 protocol upgrade via Alt-Svc headers with broken-QUIC fallback
32
+ - **SessionPool** — High-concurrency pool with proxy rotation (round-robin / random)
33
+ - **Proxy Support** — SOCKS5 and HTTP CONNECT with authentication
34
+ - **WebSocket** — HTTP/1.1 Upgrade (RFC 6455) and H2 Extended CONNECT (RFC 8441)
35
+ - **Middleware** — Interceptor chain for request/response modification
36
+ - **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`)
37
+ - **Redirect Control** — `RedirectPolicy::Follow(n)` or `RedirectPolicy::None` for manual handling
38
+ - **Auto-Decompression** — Brotli, gzip, deflate, zstd
39
+ - **Blocking API** — Synchronous wrapper for non-async contexts
40
+ - **Multipart/Form-Data** — File uploads with streaming support
41
+ - **TCP Fingerprint** — JA4T-style TCP SYN fingerprinting
@@ -0,0 +1,74 @@
1
+ # Contributing to lkrequest
2
+
3
+ Thanks for your interest in contributing! This package is a [PyO3](https://pyo3.rs)
4
+ binding over the `lkrequest` Rust workspace, built with
5
+ [maturin](https://www.maturin.rs).
6
+
7
+ ## Development setup
8
+
9
+ ```bash
10
+ git clone https://github.com/ez-opensource/lkrequest-py
11
+ cd lkrequest-py
12
+ python3 -m venv .venv # Linux/macOS
13
+ # py -m venv .venv # Windows
14
+ # Windows: .venv\Scripts\Activate.ps1
15
+ # Linux / macOS: source .venv/bin/activate
16
+ python -m pip install --upgrade pip
17
+ python -m pip install maturin
18
+ python -m pip install -e ".[test,lint]"
19
+ ```
20
+
21
+ Alternatively, use uv to create and manage the environment:
22
+
23
+ ```bash
24
+ uv sync --extra test --extra lint
25
+ ```
26
+
27
+ Optional build features:
28
+
29
+ ```bash
30
+ maturin develop --features telemetry # enable metrics_snapshot() counters
31
+ maturin develop --features quic-h3 # enable QUIC / HTTP3
32
+ ```
33
+
34
+ ## Running the test suite
35
+
36
+ ```bash
37
+ python -m pip install -e ".[test]" # pytest + local server dependencies
38
+ just test
39
+
40
+ # With uv:
41
+ just test
42
+ # Or:
43
+ uv run pytest tests/ -v
44
+
45
+ # Skip the network/server tests and run only unit-level checks:
46
+ python -m pytest tests/ -v -k "not httpbin and not echo"
47
+ ```
48
+
49
+ ## Before opening a pull request
50
+
51
+ The CI lint gate is strict — please run these locally and make sure they pass:
52
+
53
+ ```bash
54
+ cargo fmt --all # format (CI runs `cargo fmt --check`)
55
+ cargo clippy -- -D warnings
56
+ python -m pytest tests/ -v
57
+ ```
58
+
59
+ A few project conventions:
60
+
61
+ - **Type stubs are the source of truth for the public API.** Any new public
62
+ class, method, or module function in Rust must also be declared in
63
+ `python/lkrequest/_lkrequest.pyi`. `tests/test_stub_parity.py` enforces this.
64
+ - **Avoid `unwrap()` / `expect()`** in non-test code (clippy is configured to
65
+ warn). Propagate errors with `?` and the project's error types, or add an
66
+ `#[allow(...)]` with a justifying comment where a panic is genuinely
67
+ unreachable (e.g. a `LazyLock` initializer).
68
+ - Keep new code formatted to match the surrounding style; `cargo fmt` handles
69
+ this for Rust.
70
+
71
+ ## License
72
+
73
+ By contributing, you agree that your contributions will be licensed under the
74
+ [Apache License 2.0](LICENSE), consistent with the rest of the project.