What's Changed
Summary
Major release v2.0.0 — main → dev — 367 files +32k / -73k.
Former wrapper around forked reqwest / hyper / hyper-util / hyper-rustls / tokio-rustls replaced by a standalone crates/primp built directly on hyper, hyper-util, h2 and rustls. The Python extension is rebound to the new native core.
Breaking Changes / Migration
Workspace
- Removed crates:
primp-reqwest,primp-hyper,primp-hyper-util,primp-hyper-rustls,primp-tokio-rustls crates/primpis now the product;Cargo.tomlworkspace.memberstrimmed toprimp,primp-rustls/rustls,primp-h2,primp-python[profile.bench]added (lto = false,codegen-units = 256)
Dependencies
primp/Cargo.tomlno longer re-exportsreqwest/*; now declareshyper@1.8,hyper-util@0.1,tower@0.5+tower-http@0.7(follow-redirect,decompression-*),http-body/http-body-util,tokio,foldhash@0.2,rustls@0.23(impersonate,aws-lc-rs,ml-dsa),hickory-resolver@0.26optional,quinn/h3optionalprimp-rustls0.23.40→0.23.42,hashbrown0.16→0.17primp-h2tracks upstream0.4.17/0.4.18
Features
default = [cookies, gzip, brotli, zstd, deflate, query, form, json, multipart, stream, system-proxy, charset]- Removed
impersonate/default-tls/http2/rustls-no-provider(always on viarustls/h2) - Fine-grained
charset/hickory-dns/http3remain
Versions
primp1.3.1→2.0.0primp-python1.3.1→2.0.0- MSRV
1.89,panic = "abort"/lto = "fat"/codegen-units = 1unchanged
Python
pyo3/pyo3-async-runtimes0.28→0.29html2text0.16→0.17- Added
jiter@0.16,log;crate-type = cdylibdoc disabled
Features
Core
- Native
src/{lib, config, error, connect, tls, tls_bridge, impersonation}+async_impl/{client, body, request, response, multipart, negotiate, range_guard, h1_client, h2_client, h3_client}+dns/{cache, lru, hosts, resolve, plain, doh, dot, gai, hickory}+imp/{chrome, edge, opera, firefox, safari}+retry/redirect/proxy/cookie
Pool / ALPN
- H1 keep-alive:
busy/idle_since,PlaceholderGuard, origin-form rewrite, lazyevict_stale(90s / 256) - H2 / H3:
AtomicU64 last_used,active_streamsrefcount, owner-only abort +detach_driver_until_idle,watchsentinel dedup, busy-gate, single conn per key, REFUSED retry ≤32, backpressure 1 KiB gate - Other: proxy / redirect / TLS bridge (bounded 128 drain,
close_notify), DNS LRU 30s/5s +DynResolver::http_resolve+ChainedResolver
Impersonation
- Browser profiles
chrome_144-152,edge_144-151,opera_126-135,firefox_140,146-151,safari_18.5/26/26.3/26.4+random - TLS / JA4 / Akamai / header-order capture-verified
emulator_extension_orderper-version (GREASE0x6a6a/0x0a0a, ALPS0x44cd,compress_certificatebrotli-vs-zlib, ML-DSA150+/134+)SelectedUnofferedcipher fallback
DNS / Proxy / Cookie
- Global
OnceLockHostsMap(Box<str>+Arc<[IpAddr]>), non-blocking threaded load (3.6s → 0.2s) - Custom-port / empty-set /
DNSTimeoutcapping; SOCKS primp-owned (bracket-strip, ATYP=4, 255 B caps, 8 KiB CONNECT,with_timeout) - First-match
Proxy-Authorizationper-hop re-attach - PSL (
psl@2.1) rejection, one-shot cookie merge,referer=Falsehonored
Fixes / Performance
- Pool:
Dropno-abort whileactive_streams > 0→ fixesbroken pipeunder 100 concurrent temp clients; off-runtime GCmem::forgetleak,primp_body_error_to_pyerris_timeoutbeforeis_decode(pool_concurrent_drop) - Hosts: compaction + threaded load;
foldhash::fast::RandomStatefor H1/H2/H3/DNSHashMap+ h2IndexMap(~2×:17msvs107mshash,615ms → 278mspool 256-entry) - Proxy: socks5-https via h2 + timeout / tls-buffer fixes; referer / proxy attrs + cipher fallback;
StatusError.status_code/url - Forks: sync to upstream
rustls@0.23.42/h2@0.4.17, header-abuse (>4× max_header_list_size→GOAWAY ENHANCE_YOUR_CALMvs431+RST) + flow-control hardening; clippy clean,manylinux_2_28forppc64le(GCC 7.5), WindowsTimeoutErrorfor127.0.0.1:1
Python
- Rebound
primp-pythonto nativeprimp@2.0(Client/AsyncClient/RequestBuilder/Response) - Real coroutines via
future_into_coroutine(14 sites,create_task-checked),ACTIVE_TASKS+SHUTTING_DOWN+call_soon_threadsafeinterpreter-exit safety,py.detach+block_on,get_runtimePyOnceLock::get_or_try_init→PyRuntimeError areadcache_drained,exhausted Arc<AtomicBool>iterators (TOCTOUstream_exhausted→ quiet EOF)chunk_size/timeoutvalidation,text_markdown(html2text),DNSTimeoutErrorPyOnceLock
Tests / Docs
- New suites:
h1_fallback,h2_pool_saturation,range_accept_encoding(RangeGuard→identity),cookie_psl,proxy_review,redirect,retry(tower×pool3×33=99),tls_close_notify,pool_concurrent_drop,socks_ipv6,window_increment,test_pool_concurrent_drop.py - Python:
test_client/request_params/streaming/exceptions primp.pyi/ examples updated;READMEprimp = "2"
Full Changelog: v1.3.1...v2.0.0