wreq-rb 0.6.0 → 0.6.2
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.
- checksums.yaml +4 -4
- data/Cargo.lock +257 -102
- data/ext/wreq_rb/Cargo.toml +7 -4
- data/ext/wreq_rb/src/client.rs +105 -15
- data/ext/wreq_rb/src/response.rs +28 -3
- data/lib/wreq-rb/version.rb +1 -1
- data/patches/0001-add-transfer-size-tracking.patch +11 -15
- data/vendor/wreq/Cargo.toml +9 -8
- data/vendor/wreq/README.md +5 -5
- data/vendor/wreq/bench/support/bench.rs +6 -2
- data/vendor/wreq/bench/support/client.rs +88 -1
- data/vendor/wreq/bench/support/exec.rs +0 -0
- data/vendor/wreq/bench/support/rt.rs +34 -0
- data/vendor/wreq/bench/support/server.rs +1 -1
- data/vendor/wreq/bench/support.rs +1 -15
- data/vendor/wreq/examples/cert_store.rs +13 -13
- data/vendor/wreq/examples/request_with_emulate.rs +1 -1
- data/vendor/wreq/examples/tcp_linger.rs +22 -0
- data/vendor/wreq/src/client/layer/client/pool.rs +17 -17
- data/vendor/wreq/src/client/layer/client.rs +2 -0
- data/vendor/wreq/src/client/layer/decoder.rs +71 -17
- data/vendor/wreq/src/client/layer/redirect/future.rs +49 -63
- data/vendor/wreq/src/client/layer/redirect/policy.rs +2 -26
- data/vendor/wreq/src/client/layer/redirect.rs +48 -60
- data/vendor/wreq/src/client/layer/retry.rs +12 -15
- data/vendor/wreq/src/client/layer/timeout/body.rs +27 -21
- data/vendor/wreq/src/client/layer/timeout/future.rs +33 -58
- data/vendor/wreq/src/client/layer/timeout.rs +8 -14
- data/vendor/wreq/src/client/request.rs +4 -0
- data/vendor/wreq/src/client.rs +53 -31
- data/vendor/wreq/src/conn/connector.rs +99 -129
- data/vendor/wreq/src/conn/http.rs +25 -18
- data/vendor/wreq/src/conn/net/tcp.rs +601 -107
- data/vendor/wreq/src/conn/proxy/socks.rs +6 -6
- data/vendor/wreq/src/conn/timeout.rs +166 -0
- data/vendor/wreq/src/conn.rs +5 -4
- data/vendor/wreq/src/cookie/jar.rs +1225 -0
- data/vendor/wreq/src/cookie/store.rs +321 -0
- data/vendor/wreq/src/cookie.rs +108 -612
- data/vendor/wreq/src/dns/resolve.rs +8 -2
- data/vendor/wreq/src/dns.rs +4 -4
- data/vendor/wreq/src/error.rs +53 -20
- data/vendor/wreq/src/lib.rs +1 -0
- data/vendor/wreq/src/proxy/matcher.rs +26 -12
- data/vendor/wreq/src/proxy/win.rs +39 -9
- data/vendor/wreq/src/redirect.rs +515 -100
- data/vendor/wreq/src/tls/conn.rs +3 -11
- data/vendor/wreq/src/tls/session.rs +7 -8
- data/vendor/wreq/src/tls/trust/store.rs +4 -4
- data/vendor/wreq/src/util.rs +23 -0
- data/vendor/wreq/tests/badssl.rs +72 -7
- data/vendor/wreq/tests/brotli.rs +1 -1
- data/vendor/wreq/tests/client.rs +24 -0
- data/vendor/wreq/tests/connector_layers.rs +8 -4
- data/vendor/wreq/tests/cookie.rs +59 -0
- data/vendor/wreq/tests/deflate.rs +1 -1
- data/vendor/wreq/tests/gzip.rs +53 -1
- data/vendor/wreq/tests/layers.rs +8 -4
- data/vendor/wreq/tests/redirect.rs +180 -97
- data/vendor/wreq/tests/timeouts.rs +47 -12
- data/vendor/wreq/tests/zstd.rs +1 -1
- metadata +8 -2
data/ext/wreq_rb/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "wreq_rb"
|
|
3
|
-
version = "0.6.
|
|
3
|
+
version = "0.6.2"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
publish = false
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ crate-type = ["cdylib"]
|
|
|
10
10
|
[dependencies]
|
|
11
11
|
magnus = { version = "0.8", features = ["rb-sys"] }
|
|
12
12
|
rb-sys = "0.9"
|
|
13
|
-
wreq = { path = "../../vendor/wreq", version = "=
|
|
13
|
+
wreq = { path = "../../vendor/wreq", version = "=0.16.1", features = [
|
|
14
14
|
"cookies",
|
|
15
15
|
"json",
|
|
16
16
|
"gzip",
|
|
@@ -24,14 +24,17 @@ wreq = { path = "../../vendor/wreq", version = "=6.0.0-rc.29", features = [
|
|
|
24
24
|
"query",
|
|
25
25
|
"form",
|
|
26
26
|
] }
|
|
27
|
-
wreq-util = { version = "=
|
|
27
|
+
wreq-util = { version = "=0.2.0", features = ["emulation", "emulation-serde", "emulation-compression"] }
|
|
28
28
|
tokio = { version = "1", features = ["full"] }
|
|
29
29
|
tokio-util = "0.7"
|
|
30
30
|
serde_json = "1.0"
|
|
31
31
|
bytes = "1"
|
|
32
32
|
http = "1"
|
|
33
33
|
|
|
34
|
+
[dev-dependencies]
|
|
35
|
+
magnus = { version = "0.8", features = ["embed"] }
|
|
36
|
+
|
|
34
37
|
[target.'cfg(target_os = "linux")'.dependencies]
|
|
35
|
-
wreq = { path = "../../vendor/wreq", version = "=
|
|
38
|
+
wreq = { path = "../../vendor/wreq", version = "=0.16.1", features = [
|
|
36
39
|
"prefix-symbols",
|
|
37
40
|
] }
|
data/ext/wreq_rb/src/client.rs
CHANGED
|
@@ -47,7 +47,7 @@ fn runtime() -> &'static Runtime {
|
|
|
47
47
|
/// # Safety
|
|
48
48
|
/// The closure must NOT access any Ruby objects or call any Ruby C API.
|
|
49
49
|
/// Extract all data from Ruby before calling this, convert results after.
|
|
50
|
-
unsafe fn without_gvl<F, R>(f: F) -> R
|
|
50
|
+
unsafe fn without_gvl<F, R>(f: F) -> Result<R, magnus::Error>
|
|
51
51
|
where
|
|
52
52
|
F: FnOnce(CancellationToken) -> R,
|
|
53
53
|
{
|
|
@@ -89,19 +89,22 @@ where
|
|
|
89
89
|
let data_ptr = &mut data as *mut CallData<F, R> as *mut c_void;
|
|
90
90
|
|
|
91
91
|
unsafe {
|
|
92
|
-
rb_sys::
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
92
|
+
magnus::rb_sys::protect(|| {
|
|
93
|
+
rb_sys::rb_thread_call_without_gvl(
|
|
94
|
+
Some(call::<F, R>),
|
|
95
|
+
data_ptr,
|
|
96
|
+
Some(ubf::<F, R>),
|
|
97
|
+
data_ptr,
|
|
98
|
+
);
|
|
99
|
+
0
|
|
100
|
+
})?;
|
|
98
101
|
}
|
|
99
102
|
|
|
100
103
|
if let Some(payload) = data.panic_payload {
|
|
101
104
|
panic::resume_unwind(payload);
|
|
102
105
|
}
|
|
103
106
|
|
|
104
|
-
data.result.unwrap()
|
|
107
|
+
Ok(data.result.unwrap())
|
|
105
108
|
}
|
|
106
109
|
|
|
107
110
|
/// Collected response data as pure Rust types (no Ruby objects).
|
|
@@ -201,7 +204,7 @@ async fn execute_batch(reqs: Vec<wreq::RequestBuilder>, concurrency: usize) -> V
|
|
|
201
204
|
// --------------------------------------------------------------------------
|
|
202
205
|
|
|
203
206
|
/// The default browser profile to apply when none is specified.
|
|
204
|
-
const DEFAULT_EMULATION: BrowserProfile = BrowserProfile::
|
|
207
|
+
const DEFAULT_EMULATION: BrowserProfile = BrowserProfile::Chrome149;
|
|
205
208
|
|
|
206
209
|
/// Parse a Ruby string like "chrome_143" into a BrowserProfile variant.
|
|
207
210
|
fn parse_emulation(name: &str) -> Result<BrowserProfile, magnus::Error> {
|
|
@@ -288,12 +291,13 @@ impl Client {
|
|
|
288
291
|
builder = builder.default_headers(hmap);
|
|
289
292
|
}
|
|
290
293
|
|
|
291
|
-
|
|
292
|
-
|
|
294
|
+
let timeout = hash_get_float(&opts, "timeout")?;
|
|
295
|
+
if let Some(timeout) = timeout {
|
|
296
|
+
builder = builder.timeout(Duration::from_secs_f64(timeout));
|
|
293
297
|
}
|
|
294
298
|
|
|
295
|
-
if let Some(
|
|
296
|
-
builder = builder.connect_timeout(Duration::from_secs_f64(
|
|
299
|
+
if let Some(connect_timeout) = hash_get_float(&opts, "connect_timeout")?.or(timeout) {
|
|
300
|
+
builder = builder.connect_timeout(Duration::from_secs_f64(connect_timeout));
|
|
297
301
|
}
|
|
298
302
|
|
|
299
303
|
if let Some(t) = hash_get_float(&opts, "read_timeout")? {
|
|
@@ -489,7 +493,7 @@ impl Client {
|
|
|
489
493
|
}
|
|
490
494
|
})
|
|
491
495
|
})
|
|
492
|
-
}
|
|
496
|
+
}?;
|
|
493
497
|
|
|
494
498
|
let data = match outcome {
|
|
495
499
|
RequestOutcome::Ok(d) => d,
|
|
@@ -545,7 +549,7 @@ impl Client {
|
|
|
545
549
|
}
|
|
546
550
|
})
|
|
547
551
|
})
|
|
548
|
-
}
|
|
552
|
+
}?;
|
|
549
553
|
|
|
550
554
|
let items = match outcome {
|
|
551
555
|
BatchOutcome::Done(items) => items,
|
|
@@ -877,3 +881,89 @@ pub fn init(_ruby: &magnus::Ruby, module: &magnus::RModule) -> Result<(), magnus
|
|
|
877
881
|
|
|
878
882
|
Ok(())
|
|
879
883
|
}
|
|
884
|
+
|
|
885
|
+
#[cfg(test)]
|
|
886
|
+
mod tests {
|
|
887
|
+
use super::*;
|
|
888
|
+
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
|
889
|
+
|
|
890
|
+
static READY: AtomicBool = AtomicBool::new(false);
|
|
891
|
+
static LIVE: AtomicUsize = AtomicUsize::new(0);
|
|
892
|
+
|
|
893
|
+
struct DropProbe;
|
|
894
|
+
|
|
895
|
+
impl DropProbe {
|
|
896
|
+
fn new() -> Self {
|
|
897
|
+
LIVE.fetch_add(1, Ordering::SeqCst);
|
|
898
|
+
Self
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
impl Drop for DropProbe {
|
|
903
|
+
fn drop(&mut self) {
|
|
904
|
+
LIVE.fetch_sub(1, Ordering::SeqCst);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
fn probe_ready() -> bool {
|
|
909
|
+
READY.load(Ordering::SeqCst)
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
fn drop_probe() -> Result<(), magnus::Error> {
|
|
913
|
+
let _caller_resource = DropProbe::new();
|
|
914
|
+
let result = unsafe {
|
|
915
|
+
without_gvl(|token| {
|
|
916
|
+
let _callback_resource = DropProbe::new();
|
|
917
|
+
READY.store(true, Ordering::SeqCst);
|
|
918
|
+
runtime().block_on(token.cancelled());
|
|
919
|
+
DropProbe::new()
|
|
920
|
+
})
|
|
921
|
+
}?;
|
|
922
|
+
drop(result);
|
|
923
|
+
Ok(())
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
#[test]
|
|
927
|
+
fn ruby_interrupts_drop_native_resources() {
|
|
928
|
+
let ruby = unsafe { magnus::embed::init() };
|
|
929
|
+
let result = unsafe { without_gvl(|_| DropProbe::new()) }.unwrap();
|
|
930
|
+
assert_eq!(LIVE.load(Ordering::SeqCst), 1);
|
|
931
|
+
drop(result);
|
|
932
|
+
assert_eq!(LIVE.load(Ordering::SeqCst), 0);
|
|
933
|
+
|
|
934
|
+
let panicked = panic::catch_unwind(|| unsafe {
|
|
935
|
+
without_gvl::<_, ()>(|_| {
|
|
936
|
+
let _resource = DropProbe::new();
|
|
937
|
+
panic!("probe panic");
|
|
938
|
+
})
|
|
939
|
+
});
|
|
940
|
+
assert!(panicked.is_err());
|
|
941
|
+
assert_eq!(LIVE.load(Ordering::SeqCst), 0);
|
|
942
|
+
|
|
943
|
+
ruby.define_global_function("wreq_drop_probe", function!(drop_probe, 0));
|
|
944
|
+
ruby.define_global_function("wreq_probe_ready", function!(probe_ready, 0));
|
|
945
|
+
|
|
946
|
+
for (interrupt, expected) in [
|
|
947
|
+
("worker.kill", None),
|
|
948
|
+
("worker.raise(RuntimeError, 'stop request')", Some("stop request")),
|
|
949
|
+
] {
|
|
950
|
+
READY.store(false, Ordering::SeqCst);
|
|
951
|
+
let result: Option<String> = ruby.eval(&format!(
|
|
952
|
+
"worker = Thread.new do
|
|
953
|
+
begin
|
|
954
|
+
wreq_drop_probe
|
|
955
|
+
'returned normally'
|
|
956
|
+
rescue RuntimeError => error
|
|
957
|
+
error.message
|
|
958
|
+
end
|
|
959
|
+
end
|
|
960
|
+
Thread.pass until wreq_probe_ready
|
|
961
|
+
{interrupt}
|
|
962
|
+
worker.value"
|
|
963
|
+
)).unwrap();
|
|
964
|
+
|
|
965
|
+
assert_eq!(result.as_deref(), expected);
|
|
966
|
+
assert_eq!(LIVE.load(Ordering::SeqCst), 0, "resources leaked after {interrupt}");
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
}
|
data/ext/wreq_rb/src/response.rs
CHANGED
|
@@ -5,7 +5,8 @@ use magnus::{
|
|
|
5
5
|
use crate::error::generic_error;
|
|
6
6
|
|
|
7
7
|
/// Wraps a wreq::Response in a Ruby-accessible type.
|
|
8
|
-
#[magnus::
|
|
8
|
+
#[derive(magnus::TypedData)]
|
|
9
|
+
#[magnus(class = "Wreq::Response", free_immediately, size)]
|
|
9
10
|
pub struct Response {
|
|
10
11
|
status: u16,
|
|
11
12
|
headers: Vec<(String, String)>,
|
|
@@ -26,7 +27,7 @@ impl Response {
|
|
|
26
27
|
content_length: Option<u64>,
|
|
27
28
|
transfer_size: Option<u64>,
|
|
28
29
|
) -> Self {
|
|
29
|
-
Self {
|
|
30
|
+
let response = Self {
|
|
30
31
|
status,
|
|
31
32
|
headers,
|
|
32
33
|
body,
|
|
@@ -34,7 +35,18 @@ impl Response {
|
|
|
34
35
|
version,
|
|
35
36
|
content_length,
|
|
36
37
|
transfer_size,
|
|
37
|
-
}
|
|
38
|
+
};
|
|
39
|
+
unsafe { Ruby::get_unchecked() }
|
|
40
|
+
.gc_adjust_memory_usage(response.heap_size() as isize);
|
|
41
|
+
response
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
fn heap_size(&self) -> usize {
|
|
45
|
+
self.body.capacity()
|
|
46
|
+
+ self.url.capacity()
|
|
47
|
+
+ self.version.capacity()
|
|
48
|
+
+ self.headers.capacity() * std::mem::size_of::<(String, String)>()
|
|
49
|
+
+ self.headers.iter().map(|(name, value)| name.capacity() + value.capacity()).sum::<usize>()
|
|
38
50
|
}
|
|
39
51
|
|
|
40
52
|
fn status(&self) -> u16 {
|
|
@@ -119,6 +131,19 @@ impl Response {
|
|
|
119
131
|
}
|
|
120
132
|
}
|
|
121
133
|
|
|
134
|
+
impl magnus::DataTypeFunctions for Response {
|
|
135
|
+
fn size(&self) -> usize {
|
|
136
|
+
std::mem::size_of::<Self>() + self.heap_size()
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
impl Drop for Response {
|
|
141
|
+
fn drop(&mut self) {
|
|
142
|
+
unsafe { Ruby::get_unchecked() }
|
|
143
|
+
.gc_adjust_memory_usage(-(self.heap_size() as isize));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
122
147
|
pub fn init(ruby: &magnus::Ruby, module: &magnus::RModule) -> Result<(), magnus::Error> {
|
|
123
148
|
let class = module.define_class("Response", ruby.class_object())?;
|
|
124
149
|
class.define_method("status", method!(Response::status, 0))?;
|
data/lib/wreq-rb/version.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
diff --git a/src/client.rs b/src/client.rs
|
|
2
|
-
index
|
|
2
|
+
index 214fe423..ccbdb0e9 100644
|
|
3
3
|
--- a/src/client.rs
|
|
4
4
|
+++ b/src/client.rs
|
|
5
5
|
@@ -49,6 +49,7 @@ use self::{
|
|
@@ -10,18 +10,14 @@ index 4abe25d8..76e709a8 100644
|
|
|
10
10
|
},
|
|
11
11
|
request::{Request, RequestBuilder},
|
|
12
12
|
response::Response,
|
|
13
|
-
@@ -
|
|
13
|
+
@@ -116,24 +117,26 @@ type MaybeDecompressionBody<T> = tower_http::decompression::DecompressionBody<T>
|
|
14
|
+
|
|
14
15
|
type ClientService = Timeout<
|
|
15
16
|
ConfigService<
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
+ TransferSizeService<
|
|
19
|
-
+
|
|
20
|
-
+ RetryPolicy,
|
|
21
|
-
+ FollowRedirect<HttpClient<Connector, Body>, FollowRedirectPolicy>,
|
|
22
|
-
+ >,
|
|
23
|
-
+ >,
|
|
24
|
-
>,
|
|
17
|
+
- MaybeDecompression<Retry<RetryPolicy, FollowRedirect<HttpClient<Connector, Body>>>>,
|
|
18
|
+
+ MaybeDecompression<
|
|
19
|
+
+ TransferSizeService<Retry<RetryPolicy, FollowRedirect<HttpClient<Connector, Body>>>>,
|
|
20
|
+
+ >,
|
|
25
21
|
>,
|
|
26
22
|
>;
|
|
27
23
|
|
|
@@ -45,7 +41,7 @@ index 4abe25d8..76e709a8 100644
|
|
|
45
41
|
BoxError,
|
|
46
42
|
>;
|
|
47
43
|
|
|
48
|
-
@@ -
|
|
44
|
+
@@ -597,6 +600,10 @@ impl ClientBuilder {
|
|
49
45
|
})
|
|
50
46
|
.service(service);
|
|
51
47
|
|
|
@@ -56,7 +52,7 @@ index 4abe25d8..76e709a8 100644
|
|
|
56
52
|
#[cfg(any(
|
|
57
53
|
feature = "gzip",
|
|
58
54
|
feature = "zstd",
|
|
59
|
-
@@ -
|
|
55
|
+
@@ -1607,7 +1614,7 @@ impl ClientBuilder {
|
|
60
56
|
L: Layer<
|
|
61
57
|
BoxCloneSyncService<
|
|
62
58
|
http::Request<Body>,
|
|
@@ -65,7 +61,7 @@ index 4abe25d8..76e709a8 100644
|
|
|
65
61
|
BoxError,
|
|
66
62
|
>,
|
|
67
63
|
> + Clone
|
|
68
|
-
@@ -
|
|
64
|
+
@@ -1616,7 +1623,7 @@ impl ClientBuilder {
|
|
69
65
|
+ 'static,
|
|
70
66
|
L::Service: Service<
|
|
71
67
|
http::Request<Body>,
|
|
@@ -266,7 +262,7 @@ index 00000000..f155ec8d
|
|
|
266
262
|
+ }
|
|
267
263
|
+}
|
|
268
264
|
diff --git a/src/client/response.rs b/src/client/response.rs
|
|
269
|
-
index 3d3532af..
|
|
265
|
+
index 3d3532af..7d29ec45 100644
|
|
270
266
|
--- a/src/client/response.rs
|
|
271
267
|
+++ b/src/client/response.rs
|
|
272
268
|
@@ -18,6 +18,7 @@ use mime::Mime;
|
data/vendor/wreq/Cargo.toml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "wreq"
|
|
3
|
-
version = "
|
|
4
|
-
description = "An ergonomic Rust HTTP Client
|
|
3
|
+
version = "0.16.1"
|
|
4
|
+
description = "An ergonomic, privacy-aware Rust HTTP Client"
|
|
5
5
|
keywords = ["http", "client", "websocket", "ja3", "ja4"]
|
|
6
6
|
categories = ["web-programming::http-client"]
|
|
7
7
|
repository = "https://github.com/0x676e67/wreq"
|
|
@@ -10,8 +10,8 @@ authors = ["0x676e67 <gngppz@gmail.com>"]
|
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
license = "Apache-2.0"
|
|
12
12
|
edition = "2024"
|
|
13
|
-
rust-version = "1.
|
|
14
|
-
include = ["README.md", "LICENSE", "src/**/*.rs"]
|
|
13
|
+
rust-version = "1.98"
|
|
14
|
+
include = ["/README.md", "/LICENSE", "/src/**/*.rs"]
|
|
15
15
|
|
|
16
16
|
[package.metadata.docs.rs]
|
|
17
17
|
all-features = true
|
|
@@ -92,10 +92,10 @@ http = "1.4.0"
|
|
|
92
92
|
http2 = "0.5.17"
|
|
93
93
|
httparse = "1.10.1"
|
|
94
94
|
http-body = "1.0.1"
|
|
95
|
-
http-body-util = "0.1.
|
|
95
|
+
http-body-util = "0.1.4"
|
|
96
96
|
percent-encoding = "2.3.2"
|
|
97
97
|
pin-project-lite = "0.2.17"
|
|
98
|
-
futures-util = { version = "0.3.
|
|
98
|
+
futures-util = { version = "0.3.33", default-features = false }
|
|
99
99
|
socket2 = { version = "0.6.3", features = ["all"] }
|
|
100
100
|
ipnet = "2.12.0"
|
|
101
101
|
lru = "0.18.0"
|
|
@@ -103,7 +103,7 @@ btls = "0.5.6"
|
|
|
103
103
|
btls-sys = "0.5.6"
|
|
104
104
|
tokio-btls = "0.5.6"
|
|
105
105
|
tokio = { version = "1.52.3", default-features = false }
|
|
106
|
-
compio = { version = "0.19.
|
|
106
|
+
compio = { version = "0.19.2", features = ["io", "io-compat"], optional = true }
|
|
107
107
|
wreq-rt = { version = "0.2.2-rc.2", default-features = false }
|
|
108
108
|
wreq-proto = { version = "0.2.3", default-features = false }
|
|
109
109
|
tower = { version = "0.5.3", default-features = false, features = [
|
|
@@ -174,7 +174,7 @@ tokio = { version = "1.0", default-features = false, features = [
|
|
|
174
174
|
"macros",
|
|
175
175
|
"rt-multi-thread",
|
|
176
176
|
] }
|
|
177
|
-
compio = { version = "0.19.
|
|
177
|
+
compio = { version = "0.19.2", features = ["macros", "net", "runtime", "time", "io", "io-compat"] }
|
|
178
178
|
hyper = { version = "1.7.0", default-features = false, features = [
|
|
179
179
|
"http1",
|
|
180
180
|
"http2",
|
|
@@ -202,6 +202,7 @@ zstd = "0.13.3"
|
|
|
202
202
|
sysinfo = { version = "0.39.1", default-features = false, features = ["system"] }
|
|
203
203
|
criterion = { version = "0.8.2", features = ["async_tokio"] }
|
|
204
204
|
reqwest = { version = "0.13.3", default-features = false, features = ["rustls", "stream", "http2"] }
|
|
205
|
+
cyper = { version = "0.9.0", default-features = false, features = ["rustls", "stream"] }
|
|
205
206
|
|
|
206
207
|
[profile.release]
|
|
207
208
|
codegen-units = 1
|
data/vendor/wreq/README.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/0x676e67/wreq/actions/workflows/ci.yml)
|
|
4
4
|
[](https://github.com/0x676e67/wreq/blob/main/LICENSE)
|
|
5
|
-
[](https://crates.io/crates/wreq)
|
|
6
|
+
[](https://crates.io/crates/wreq)
|
|
7
7
|
[![Discord chat][discord-badge]][discord-url]
|
|
8
8
|
|
|
9
9
|
[discord-badge]: https://img.shields.io/discord/1486741856397164788.svg?logo=discord
|
|
@@ -35,8 +35,8 @@ The following example uses the [Tokio](https://tokio.rs) runtime with optional f
|
|
|
35
35
|
```toml
|
|
36
36
|
[dependencies]
|
|
37
37
|
tokio = { version = "1", features = ["full"] }
|
|
38
|
-
wreq = "
|
|
39
|
-
wreq-util = "
|
|
38
|
+
wreq = "0.16"
|
|
39
|
+
wreq-util = "0.2"
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
And then the code:
|
|
@@ -53,7 +53,7 @@ async fn main() -> wreq::Result<()> {
|
|
|
53
53
|
.build()?;
|
|
54
54
|
|
|
55
55
|
// Use the API you're already familiar with
|
|
56
|
-
let resp = client.get("https://
|
|
56
|
+
let resp = client.get("https://pingly.us.kg/api/all").send().await?;
|
|
57
57
|
println!("{}", resp.text().await?);
|
|
58
58
|
Ok(())
|
|
59
59
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
use criterion::Criterion;
|
|
2
2
|
|
|
3
3
|
use crate::support::{
|
|
4
|
-
BoxError, HttpVersion, Tls,
|
|
5
|
-
|
|
4
|
+
BoxError, HttpVersion, Tls,
|
|
5
|
+
client::bench_clients,
|
|
6
|
+
rt::{current_thread_runtime, multi_thread_runtime},
|
|
7
|
+
server::with_server,
|
|
6
8
|
};
|
|
7
9
|
|
|
8
10
|
pub const CURRENT_THREAD_LABEL: &str = "current_thread";
|
|
@@ -54,6 +56,7 @@ pub fn bench(
|
|
|
54
56
|
bench_clients(
|
|
55
57
|
&mut group,
|
|
56
58
|
current_thread_runtime,
|
|
59
|
+
true,
|
|
57
60
|
addr,
|
|
58
61
|
tls,
|
|
59
62
|
http_version,
|
|
@@ -74,6 +77,7 @@ pub fn bench(
|
|
|
74
77
|
bench_clients(
|
|
75
78
|
&mut group,
|
|
76
79
|
multi_thread_runtime,
|
|
80
|
+
false,
|
|
77
81
|
addr,
|
|
78
82
|
tls,
|
|
79
83
|
http_version,
|
|
@@ -2,10 +2,11 @@ use std::{convert::Infallible, net::SocketAddr, sync::Arc};
|
|
|
2
2
|
|
|
3
3
|
use bytes::Bytes;
|
|
4
4
|
use criterion::{BenchmarkGroup, measurement::WallTime};
|
|
5
|
+
use futures::{StreamExt, TryStreamExt};
|
|
5
6
|
use http_body_util::BodyExt;
|
|
6
7
|
use tokio::{runtime::Runtime, sync::Semaphore};
|
|
7
8
|
|
|
8
|
-
use super::{BoxError, HttpVersion, Tls};
|
|
9
|
+
use super::{BoxError, HttpVersion, Tls, rt::CompioBenchExecutor};
|
|
9
10
|
|
|
10
11
|
fn create_wreq_client(tls: Tls, http_version: HttpVersion) -> Result<wreq::Client, BoxError> {
|
|
11
12
|
let builder = wreq::Client::builder()
|
|
@@ -35,6 +36,20 @@ fn create_reqwest_client(tls: Tls, http_version: HttpVersion) -> Result<reqwest:
|
|
|
35
36
|
Ok(builder.build()?)
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
fn create_cyper_client(tls: Tls, http_version: HttpVersion) -> Result<cyper::Client, BoxError> {
|
|
40
|
+
let builder = cyper::Client::builder()
|
|
41
|
+
.no_proxy()
|
|
42
|
+
.redirect(cyper::redirect::Policy::none())
|
|
43
|
+
.danger_accept_invalid_certs(matches!(tls, Tls::Enabled));
|
|
44
|
+
|
|
45
|
+
let builder = match http_version {
|
|
46
|
+
HttpVersion::Http1 => builder,
|
|
47
|
+
HttpVersion::Http2 => builder.http2_prior_knowledge(),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
Ok(builder.build()?)
|
|
51
|
+
}
|
|
52
|
+
|
|
38
53
|
async fn wreq_body_assert(mut response: wreq::Response, expected_body_size: usize) {
|
|
39
54
|
let mut body_size = 0;
|
|
40
55
|
while let Some(Ok(chunk)) = response.frame().await {
|
|
@@ -59,6 +74,17 @@ async fn reqwest_body_assert(mut response: reqwest::Response, expected_body_size
|
|
|
59
74
|
);
|
|
60
75
|
}
|
|
61
76
|
|
|
77
|
+
async fn cyper_body_assert(mut response: cyper::Response, expected_body_size: usize) {
|
|
78
|
+
let mut body_size = 0;
|
|
79
|
+
while let Some(Ok(chunk)) = response.next().await {
|
|
80
|
+
body_size += chunk.len();
|
|
81
|
+
}
|
|
82
|
+
assert!(
|
|
83
|
+
body_size == expected_body_size,
|
|
84
|
+
"Unexpected response body: got {body_size} bytes, expected {expected_body_size} bytes"
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
62
88
|
fn stream_from_bytes(
|
|
63
89
|
body: &'static [u8],
|
|
64
90
|
chunk_size: usize,
|
|
@@ -94,6 +120,16 @@ fn reqwest_body(stream: bool, (body, chunk_size): (&'static [u8], usize)) -> req
|
|
|
94
120
|
}
|
|
95
121
|
}
|
|
96
122
|
|
|
123
|
+
#[inline]
|
|
124
|
+
fn cyper_body(stream: bool, (body, chunk_size): (&'static [u8], usize)) -> cyper::Body {
|
|
125
|
+
if stream {
|
|
126
|
+
let stream = stream_from_bytes(body, chunk_size).map_err(|never| match never {});
|
|
127
|
+
cyper::Body::stream(stream)
|
|
128
|
+
} else {
|
|
129
|
+
cyper::Body::from(body)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
97
133
|
async fn wreq_requests_concurrent(
|
|
98
134
|
client: &wreq::Client,
|
|
99
135
|
url: &str,
|
|
@@ -158,10 +194,44 @@ async fn reqwest_requests_concurrent(
|
|
|
158
194
|
futures_util::future::join_all(handles).await;
|
|
159
195
|
}
|
|
160
196
|
|
|
197
|
+
async fn cyper_requests_concurrent(
|
|
198
|
+
client: &cyper::Client,
|
|
199
|
+
url: &str,
|
|
200
|
+
num_requests: usize,
|
|
201
|
+
concurrent_limit: usize,
|
|
202
|
+
body: (&'static [u8], usize),
|
|
203
|
+
stream: bool,
|
|
204
|
+
) {
|
|
205
|
+
let semaphore = Arc::new(Semaphore::new(concurrent_limit));
|
|
206
|
+
let mut handles = Vec::with_capacity(num_requests);
|
|
207
|
+
for _ in 0..num_requests {
|
|
208
|
+
let client = client.clone();
|
|
209
|
+
let url = url.to_string();
|
|
210
|
+
let semaphore = semaphore.clone();
|
|
211
|
+
let fut = async move {
|
|
212
|
+
let _permit = semaphore
|
|
213
|
+
.acquire()
|
|
214
|
+
.await
|
|
215
|
+
.expect("Semaphore should be acquirable");
|
|
216
|
+
let response = client
|
|
217
|
+
.post(url)
|
|
218
|
+
.expect("Unexpected request failure")
|
|
219
|
+
.body(cyper_body(stream, body))
|
|
220
|
+
.send()
|
|
221
|
+
.await
|
|
222
|
+
.expect("Unexpected request failure");
|
|
223
|
+
cyper_body_assert(response, body.0.len()).await;
|
|
224
|
+
};
|
|
225
|
+
handles.push(compio::runtime::spawn(fut));
|
|
226
|
+
}
|
|
227
|
+
futures_util::future::join_all(handles).await;
|
|
228
|
+
}
|
|
229
|
+
|
|
161
230
|
#[allow(clippy::too_many_arguments)]
|
|
162
231
|
pub fn bench_clients(
|
|
163
232
|
group: &mut BenchmarkGroup<'_, WallTime>,
|
|
164
233
|
rt: fn() -> Runtime,
|
|
234
|
+
include_cyper: bool,
|
|
165
235
|
addr: SocketAddr,
|
|
166
236
|
tls: Tls,
|
|
167
237
|
http_version: HttpVersion,
|
|
@@ -211,6 +281,23 @@ pub fn bench_clients(
|
|
|
211
281
|
})
|
|
212
282
|
});
|
|
213
283
|
::std::mem::drop(client);
|
|
284
|
+
|
|
285
|
+
if include_cyper {
|
|
286
|
+
let compio_executor = CompioBenchExecutor::new()?;
|
|
287
|
+
let client = create_cyper_client(tls, http_version)?;
|
|
288
|
+
group.bench_function(make_benchmark_label::<cyper::Client>(stream), |b| {
|
|
289
|
+
b.to_async(&compio_executor).iter(|| {
|
|
290
|
+
cyper_requests_concurrent(
|
|
291
|
+
&client,
|
|
292
|
+
&url,
|
|
293
|
+
num_requests,
|
|
294
|
+
concurrent_limit,
|
|
295
|
+
body,
|
|
296
|
+
stream,
|
|
297
|
+
)
|
|
298
|
+
})
|
|
299
|
+
});
|
|
300
|
+
}
|
|
214
301
|
}
|
|
215
302
|
|
|
216
303
|
Ok(())
|
|
File without changes
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
use criterion::async_executor::AsyncExecutor;
|
|
2
|
+
|
|
3
|
+
pub struct CompioBenchExecutor {
|
|
4
|
+
runtime: compio::runtime::Runtime,
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
impl CompioBenchExecutor {
|
|
8
|
+
pub fn new() -> std::io::Result<Self> {
|
|
9
|
+
Ok(Self {
|
|
10
|
+
runtime: compio::runtime::Runtime::new()?,
|
|
11
|
+
})
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
impl AsyncExecutor for &CompioBenchExecutor {
|
|
16
|
+
fn block_on<T>(&self, future: impl std::future::Future<Output = T>) -> T {
|
|
17
|
+
self.runtime.block_on(future)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
pub fn current_thread_runtime() -> tokio::runtime::Runtime {
|
|
22
|
+
tokio::runtime::Builder::new_current_thread()
|
|
23
|
+
.enable_all()
|
|
24
|
+
.build()
|
|
25
|
+
.expect("Failed to build current-thread runtime")
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
pub fn multi_thread_runtime() -> tokio::runtime::Runtime {
|
|
29
|
+
tokio::runtime::Builder::new_multi_thread()
|
|
30
|
+
.worker_threads(4)
|
|
31
|
+
.enable_all()
|
|
32
|
+
.build()
|
|
33
|
+
.expect("Failed to build multi-thread runtime")
|
|
34
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
pub mod bench;
|
|
2
2
|
pub mod client;
|
|
3
|
+
pub mod rt;
|
|
3
4
|
pub mod server;
|
|
4
5
|
|
|
5
6
|
use std::fmt;
|
|
@@ -39,18 +40,3 @@ impl fmt::Display for Tls {
|
|
|
39
40
|
f.write_str(value)
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
|
-
|
|
43
|
-
pub fn current_thread_runtime() -> tokio::runtime::Runtime {
|
|
44
|
-
tokio::runtime::Builder::new_current_thread()
|
|
45
|
-
.enable_all()
|
|
46
|
-
.build()
|
|
47
|
-
.expect("Failed to build current-thread runtime")
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
pub fn multi_thread_runtime() -> tokio::runtime::Runtime {
|
|
51
|
-
tokio::runtime::Builder::new_multi_thread()
|
|
52
|
-
.worker_threads(4)
|
|
53
|
-
.enable_all()
|
|
54
|
-
.build()
|
|
55
|
-
.expect("Failed to build multi-thread runtime")
|
|
56
|
-
}
|