Skip to content

Commit 627dd96

Browse files
committed
Refactor HTTP client response handling and TLS session caching
- Updated the response handling in `crates/hpx/src/client/http/future.rs` to use `Response::from_client_response` for better clarity and consistency. - Enhanced the recovery layer in `crates/hpx/src/client/layer/recovery.rs` to improve error handling and response body processing. - Modified the request construction in `crates/hpx/src/client/request.rs` to support streaming bodies without pre-buffering. - Improved the response struct in `crates/hpx/src/client/response.rs` to allow for better body handling and deserialization. - Refactored header sorting logic in `crates/hpx/src/header.rs` to preserve original casing and order while processing headers. - Enhanced TLS session caching in `crates/hpx/src/tls/boring.rs` and `crates/hpx/src/tls/boring/cache.rs` to support better session management and eviction policies.
1 parent 134767e commit 627dd96

13 files changed

Lines changed: 1069 additions & 211 deletions

File tree

Cargo.toml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ members = ["crates/*", "bin/*"]
33
resolver = "3"
44

55
[workspace.package]
6-
version = "2.4.7"
6+
version = "2.4.8"
77
edition = "2024"
88
authors = ["Akagi201 <akagi201@gmail.com>"]
99
license = "Apache-2.0"
@@ -185,11 +185,11 @@ all = "warn"
185185

186186
[workspace.dependencies]
187187
# local crates
188-
fastwebsockets = { path = "crates/fastwebsockets", package = "hpx-fastwebsockets", version = "2.4.7" }
189-
hpx = { path = "crates/hpx", version = "2.4.7" }
190-
hpx-dl = { path = "crates/hpx-dl", version = "2.4.7" }
191-
hpx-yawc = { path = "crates/yawc", version = "2.4.7" }
192-
yawc = { path = "crates/yawc", version = "2.4.7" }
188+
fastwebsockets = { path = "crates/fastwebsockets", package = "hpx-fastwebsockets", version = "2.4.8" }
189+
hpx = { path = "crates/hpx", version = "2.4.8" }
190+
hpx-dl = { path = "crates/hpx-dl", version = "2.4.8" }
191+
hpx-yawc = { path = "crates/yawc", version = "2.4.8" }
192+
yawc = { path = "crates/yawc", version = "2.4.8" }
193193

194194
# external crates
195195
ahash = "0.8.12"
@@ -253,7 +253,7 @@ pkcs8 = "0.11.0-rc.8"
253253
pretty_env_logger = "0.5.0"
254254
proptest = "1.6.0"
255255
quick-xml = "0.39.2"
256-
rand = "0.10.0"
256+
rand = "0.10.1"
257257
rustls = "0.23.37"
258258
rustls-native-certs = "0.8.3"
259259
rustls-pemfile = "2.2.0"

README.md

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ An ergonomic all-in-one HTTP client for browser emulation with TLS, JA3/JA4, and
1515

1616
| Crate | Version | Description |
1717
|-------|---------|-------------|
18-
| [`hpx`](https://crates.io/crates/hpx) | 2.4.7 | High Performance HTTP Client |
19-
| [`hpx-emulation`](https://crates.io/crates/hpx-emulation) | 2.4.7 | Browser emulation profiles |
20-
| [`hpx-yawc`](https://crates.io/crates/hpx-yawc) | 2.4.7 | WebSocket library (RFC 6455 + compression) |
21-
| [`hpx-fastwebsockets`](https://crates.io/crates/hpx-fastwebsockets) | 2.4.7 | Fast minimal WebSocket implementation |
18+
| [`hpx`](https://crates.io/crates/hpx) | 2.4.8 | High Performance HTTP Client |
19+
| [`hpx-emulation`](https://crates.io/crates/hpx-emulation) | 2.4.8 | Browser emulation profiles |
20+
| [`hpx-yawc`](https://crates.io/crates/hpx-yawc) | 2.4.8 | WebSocket library (RFC 6455 + compression) |
21+
| [`hpx-fastwebsockets`](https://crates.io/crates/hpx-fastwebsockets) | 2.4.8 | Fast minimal WebSocket implementation |
2222

2323
## Features
2424

@@ -64,7 +64,7 @@ Add `hpx` to your `Cargo.toml`:
6464

6565
```toml
6666
[dependencies]
67-
hpx = "2.4.7"
67+
hpx = "2.4.8"
6868
```
6969

7070
The default features include **BoringSSL** TLS, **HTTP/1.1**, and **HTTP/2** support.
@@ -73,8 +73,8 @@ For browser emulation, add the utility crate:
7373

7474
```toml
7575
[dependencies]
76-
hpx = "2.4.7"
77-
hpx-emulation = "2.4.7"
76+
hpx = "2.4.8"
77+
hpx-emulation = "2.4.8"
7878
```
7979

8080
## Feature Flags
@@ -125,7 +125,7 @@ The `ws` feature is an alias for `ws-yawc` (the default WebSocket backend). To u
125125

126126
```toml
127127
[dependencies]
128-
hpx = { version = "2.4.7", features = ["ws-fastwebsockets"] }
128+
hpx = { version = "2.4.8", features = ["ws-fastwebsockets"] }
129129
```
130130

131131
When both `ws-yawc` and `ws-fastwebsockets` are enabled, fastwebsockets takes priority.
@@ -135,37 +135,37 @@ When both `ws-yawc` and `ws-fastwebsockets` are enabled, fastwebsockets takes pr
135135
**Minimal HTTP client:**
136136

137137
```toml
138-
hpx = "2.4.7" # default: boring + http1 + http2
138+
hpx = "2.4.8" # default: boring + http1 + http2
139139
```
140140

141141
**JSON API client:**
142142

143143
```toml
144-
hpx = { version = "2.4.7", features = ["json", "cookies", "gzip"] }
144+
hpx = { version = "2.4.8", features = ["json", "cookies", "gzip"] }
145145
```
146146

147147
**WebSocket client:**
148148

149149
```toml
150-
hpx = { version = "2.4.7", features = ["ws"] }
150+
hpx = { version = "2.4.8", features = ["ws"] }
151151
```
152152

153153
**High-performance trading:**
154154

155155
```toml
156-
hpx = { version = "2.4.7", features = ["simd-json", "hickory-dns", "zstd", "ws"] }
156+
hpx = { version = "2.4.8", features = ["simd-json", "hickory-dns", "zstd", "ws"] }
157157
```
158158

159159
**Pure Rust (no C dependencies):**
160160

161161
```toml
162-
hpx = { version = "2.4.7", default-features = false, features = ["rustls-tls", "http1", "http2"] }
162+
hpx = { version = "2.4.8", default-features = false, features = ["rustls-tls", "http1", "http2"] }
163163
```
164164

165165
**Full-featured:**
166166

167167
```toml
168-
hpx = { version = "2.4.7", features = [
168+
hpx = { version = "2.4.8", features = [
169169
"json", "form", "query", "multipart", "stream",
170170
"cookies", "charset",
171171
"gzip", "brotli", "zstd", "deflate",
@@ -206,7 +206,7 @@ BoringSSL is the default TLS backend, providing robust support for modern TLS fe
206206

207207
```toml
208208
[dependencies]
209-
hpx = "2.4.7"
209+
hpx = "2.4.8"
210210
```
211211

212212
### Rustls
@@ -217,7 +217,7 @@ A pure Rust TLS implementation. Useful for environments where C dependencies are
217217
218218
```toml
219219
[dependencies]
220-
hpx = { version = "2.4.7", default-features = false, features = ["rustls-tls", "http1", "http2"] }
220+
hpx = { version = "2.4.8", default-features = false, features = ["rustls-tls", "http1", "http2"] }
221221
```
222222

223223
## Usage Examples
@@ -269,6 +269,45 @@ async fn main() -> hpx::Result<()> {
269269
}
270270
```
271271

272+
### Streaming / Proxying / Gateway
273+
274+
Requires the `stream` feature. For reverse proxies and API gateways, `hpx` can forward framework-native request bodies without buffering the full payload.
275+
276+
```rust
277+
use axum::{
278+
body::Body as AxumBody,
279+
extract::{Request as AxumRequest, State},
280+
http::{Response as AxumResponse, StatusCode},
281+
};
282+
use hpx::{Body, Client, Request};
283+
284+
async fn proxy(
285+
State(client): State<Client>,
286+
mut req: AxumRequest<AxumBody>,
287+
) -> Result<AxumResponse<Body>, StatusCode> {
288+
let path_and_query = req
289+
.uri()
290+
.path_and_query()
291+
.map(|value| value.as_str())
292+
.unwrap_or("/");
293+
294+
let upstream_uri = format!("https://upstream.internal{path_and_query}")
295+
.parse()
296+
.map_err(|_| StatusCode::BAD_REQUEST)?;
297+
*req.uri_mut() = upstream_uri;
298+
299+
let upstream_req = Request::from_http(req);
300+
let upstream_res = client
301+
.execute(upstream_req)
302+
.await
303+
.map_err(|_| StatusCode::BAD_GATEWAY)?;
304+
305+
Ok(http::Response::<Body>::from(upstream_res))
306+
}
307+
```
308+
309+
If you need to inspect or transform chunks instead of transparently forwarding them, use `Response::bytes_stream()` or `Response::into_body()`. For Tower-native composition, `Client::into_tower_service()` returns the `tower_compat::HpxService` alias.
310+
272311
### Browser Emulation
273312

274313
Requires the `hpx-emulation` crate with default features.

crates/hpx/README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,45 @@ async fn main() -> hpx::Result<()> {
4242
}
4343
```
4444

45+
## Streaming / Proxying / Gateway
46+
47+
Requires the `stream` feature. `Request::from_http(...)` lets you forward framework-native request bodies into `hpx` without buffering them first, which is useful in reverse proxies and API gateways.
48+
49+
```rust
50+
use axum::{
51+
body::Body as AxumBody,
52+
extract::{Request as AxumRequest, State},
53+
http::{Response as AxumResponse, StatusCode},
54+
};
55+
use hpx::{Body, Client, Request};
56+
57+
async fn proxy(
58+
State(client): State<Client>,
59+
mut req: AxumRequest<AxumBody>,
60+
) -> Result<AxumResponse<Body>, StatusCode> {
61+
let path_and_query = req
62+
.uri()
63+
.path_and_query()
64+
.map(|value| value.as_str())
65+
.unwrap_or("/");
66+
67+
let upstream_uri = format!("https://upstream.internal{path_and_query}")
68+
.parse()
69+
.map_err(|_| StatusCode::BAD_REQUEST)?;
70+
*req.uri_mut() = upstream_uri;
71+
72+
let upstream_req = Request::from_http(req);
73+
let upstream_res = client
74+
.execute(upstream_req)
75+
.await
76+
.map_err(|_| StatusCode::BAD_GATEWAY)?;
77+
78+
Ok(http::Response::<Body>::from(upstream_res))
79+
}
80+
```
81+
82+
Use `Response::bytes_stream()` when you need per-chunk inspection, and `Client::into_tower_service()` when you want to compose the client inside a Tower middleware stack via `tower_compat::HpxService`.
83+
4584
## Cloudflare mTLS
4685

4786
`hpx` can attach a client certificate during the TLS handshake, which is required for Cloudflare Access / Zero Trust deployments protected by mutual TLS.

0 commit comments

Comments
 (0)