wreq-rb 0.4.0 → 0.5.1
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 +1922 -397
- data/LICENSE +203 -0
- data/README.md +47 -16
- data/exe/wreq +211 -0
- data/ext/wreq_rb/Cargo.toml +4 -6
- data/ext/wreq_rb/src/client.rs +145 -41
- data/lib/wreq-rb/version.rb +1 -1
- data/patches/0001-add-transfer-size-tracking.patch +76 -67
- data/vendor/wreq/Cargo.toml +119 -71
- data/vendor/wreq/README.md +25 -20
- data/vendor/wreq/bench/http1.rs +25 -0
- data/vendor/wreq/bench/http1_over_tls.rs +25 -0
- data/vendor/wreq/bench/http2.rs +25 -0
- data/vendor/wreq/bench/http2_over_tls.rs +25 -0
- data/vendor/wreq/bench/support/bench.rs +91 -0
- data/vendor/wreq/bench/support/client.rs +217 -0
- data/vendor/wreq/bench/support/server.rs +188 -0
- data/vendor/wreq/bench/support.rs +56 -0
- data/vendor/wreq/examples/cert_store.rs +4 -4
- data/vendor/wreq/examples/{emulation.rs → emulate.rs} +2 -2
- data/vendor/wreq/examples/http2_websocket.rs +2 -2
- data/vendor/wreq/examples/keylog.rs +3 -3
- data/vendor/wreq/examples/{request_with_emulation.rs → request_with_emulate.rs} +2 -2
- data/vendor/wreq/examples/rt.rs +23 -0
- data/vendor/wreq/src/client/body.rs +23 -61
- data/vendor/wreq/src/client/emulate.rs +119 -0
- data/vendor/wreq/src/client/{http/future.rs → future.rs} +11 -32
- data/vendor/wreq/src/client/{http → layer}/client/pool.rs +66 -61
- data/vendor/wreq/src/client/{http → layer}/client.rs +416 -270
- data/vendor/wreq/src/client/layer/config.rs +27 -6
- data/vendor/wreq/src/client/layer/decoder.rs +9 -4
- data/vendor/wreq/src/client/layer/redirect/future.rs +6 -3
- data/vendor/wreq/src/client/layer/redirect.rs +4 -5
- data/vendor/wreq/src/client/layer/retry.rs +8 -5
- data/vendor/wreq/src/client/layer/timeout/body.rs +15 -6
- data/vendor/wreq/src/client/layer/timeout/future.rs +23 -18
- data/vendor/wreq/src/client/layer/timeout.rs +24 -74
- data/vendor/wreq/src/client/layer.rs +1 -2
- data/vendor/wreq/src/client/multipart.rs +137 -154
- data/vendor/wreq/src/client/request.rs +202 -118
- data/vendor/wreq/src/client/response.rs +46 -45
- data/vendor/wreq/src/client/upgrade.rs +15 -0
- data/vendor/wreq/src/client/ws.rs +73 -25
- data/vendor/wreq/src/client.rs +1655 -17
- data/vendor/wreq/src/config.rs +11 -11
- data/vendor/wreq/src/{client/conn → conn}/connector.rs +139 -137
- data/vendor/wreq/src/conn/descriptor.rs +143 -0
- data/vendor/wreq/src/conn/http.rs +484 -0
- data/vendor/wreq/src/conn/net/io.rs +75 -0
- data/vendor/wreq/src/conn/net/tcp/compio.rs +71 -0
- data/vendor/wreq/src/conn/net/tcp/tokio.rs +57 -0
- data/vendor/wreq/src/conn/net/tcp.rs +561 -0
- data/vendor/wreq/src/conn/net/uds/compio.rs +60 -0
- data/vendor/wreq/src/{client/conn/uds.rs → conn/net/uds/tokio.rs} +18 -12
- data/vendor/wreq/src/conn/net/uds.rs +11 -0
- data/vendor/wreq/src/conn/net.rs +130 -0
- data/vendor/wreq/src/{client/conn → conn}/proxy/socks.rs +2 -9
- data/vendor/wreq/src/{client/conn → conn}/proxy/tunnel.rs +21 -56
- data/vendor/wreq/src/conn/tls_info.rs +47 -0
- data/vendor/wreq/src/{client/conn.rs → conn.rs} +202 -54
- data/vendor/wreq/src/cookie.rs +302 -142
- data/vendor/wreq/src/dns/gai/compio.rs +77 -0
- data/vendor/wreq/src/dns/gai/tokio.rs +90 -0
- data/vendor/wreq/src/dns/gai.rs +14 -164
- data/vendor/wreq/src/dns/hickory.rs +16 -23
- data/vendor/wreq/src/dns/resolve.rs +7 -41
- data/vendor/wreq/src/dns.rs +90 -7
- data/vendor/wreq/src/error.rs +57 -31
- data/vendor/wreq/src/ext.rs +25 -0
- data/vendor/wreq/src/group.rs +211 -0
- data/vendor/wreq/src/header.rs +100 -112
- data/vendor/wreq/src/lib.rs +124 -73
- data/vendor/wreq/src/proxy.rs +6 -20
- data/vendor/wreq/src/redirect.rs +1 -1
- data/vendor/wreq/src/rt.rs +208 -0
- data/vendor/wreq/src/sync.rs +97 -98
- data/vendor/wreq/src/tls/compress.rs +124 -0
- data/vendor/wreq/src/tls/conn/ext.rs +54 -45
- data/vendor/wreq/src/tls/conn/service.rs +14 -18
- data/vendor/wreq/src/tls/conn.rs +169 -241
- data/vendor/wreq/src/tls/keylog.rs +68 -5
- data/vendor/wreq/src/tls/session.rs +205 -0
- data/vendor/wreq/src/tls/{x509 → trust}/identity.rs +4 -21
- data/vendor/wreq/src/tls/{x509/parser.rs → trust/parse.rs} +1 -1
- data/vendor/wreq/src/tls/{x509 → trust}/store.rs +42 -81
- data/vendor/wreq/src/tls/{x509.rs → trust.rs} +8 -2
- data/vendor/wreq/src/tls.rs +489 -25
- data/vendor/wreq/src/trace.rs +0 -12
- data/vendor/wreq/src/util.rs +1 -1
- data/vendor/wreq/tests/badssl.rs +10 -10
- data/vendor/wreq/tests/client.rs +3 -9
- data/vendor/wreq/tests/cookie.rs +6 -8
- data/vendor/wreq/tests/{emulation.rs → emulate.rs} +130 -22
- data/vendor/wreq/tests/multipart.rs +43 -1
- data/vendor/wreq/tests/proxy.rs +1 -1
- data/vendor/wreq/tests/support/layer.rs +1 -0
- metadata +53 -72
- data/vendor/wreq/src/client/conn/conn.rs +0 -231
- data/vendor/wreq/src/client/conn/http.rs +0 -1023
- data/vendor/wreq/src/client/conn/tls_info.rs +0 -98
- data/vendor/wreq/src/client/core/body/incoming.rs +0 -485
- data/vendor/wreq/src/client/core/body/length.rs +0 -118
- data/vendor/wreq/src/client/core/body.rs +0 -34
- data/vendor/wreq/src/client/core/common/buf.rs +0 -149
- data/vendor/wreq/src/client/core/common/rewind.rs +0 -141
- data/vendor/wreq/src/client/core/common/watch.rs +0 -76
- data/vendor/wreq/src/client/core/common.rs +0 -3
- data/vendor/wreq/src/client/core/conn/http1.rs +0 -342
- data/vendor/wreq/src/client/core/conn/http2.rs +0 -307
- data/vendor/wreq/src/client/core/conn.rs +0 -11
- data/vendor/wreq/src/client/core/dispatch.rs +0 -299
- data/vendor/wreq/src/client/core/error.rs +0 -435
- data/vendor/wreq/src/client/core/ext.rs +0 -201
- data/vendor/wreq/src/client/core/http1.rs +0 -178
- data/vendor/wreq/src/client/core/http2.rs +0 -483
- data/vendor/wreq/src/client/core/proto/h1/conn.rs +0 -988
- data/vendor/wreq/src/client/core/proto/h1/decode.rs +0 -1170
- data/vendor/wreq/src/client/core/proto/h1/dispatch.rs +0 -684
- data/vendor/wreq/src/client/core/proto/h1/encode.rs +0 -580
- data/vendor/wreq/src/client/core/proto/h1/io.rs +0 -879
- data/vendor/wreq/src/client/core/proto/h1/role.rs +0 -694
- data/vendor/wreq/src/client/core/proto/h1.rs +0 -104
- data/vendor/wreq/src/client/core/proto/h2/client.rs +0 -650
- data/vendor/wreq/src/client/core/proto/h2/ping.rs +0 -539
- data/vendor/wreq/src/client/core/proto/h2.rs +0 -379
- data/vendor/wreq/src/client/core/proto/headers.rs +0 -138
- data/vendor/wreq/src/client/core/proto.rs +0 -58
- data/vendor/wreq/src/client/core/rt/bounds.rs +0 -57
- data/vendor/wreq/src/client/core/rt/timer.rs +0 -150
- data/vendor/wreq/src/client/core/rt/tokio.rs +0 -99
- data/vendor/wreq/src/client/core/rt.rs +0 -25
- data/vendor/wreq/src/client/core/upgrade.rs +0 -267
- data/vendor/wreq/src/client/core.rs +0 -16
- data/vendor/wreq/src/client/emulation.rs +0 -161
- data/vendor/wreq/src/client/http/client/error.rs +0 -142
- data/vendor/wreq/src/client/http/client/exec.rs +0 -29
- data/vendor/wreq/src/client/http/client/extra.rs +0 -77
- data/vendor/wreq/src/client/http/client/util.rs +0 -104
- data/vendor/wreq/src/client/http.rs +0 -1629
- data/vendor/wreq/src/client/layer/config/options.rs +0 -156
- data/vendor/wreq/src/client/layer/cookie.rs +0 -161
- data/vendor/wreq/src/hash.rs +0 -143
- data/vendor/wreq/src/tls/conn/cache.rs +0 -123
- data/vendor/wreq/src/tls/conn/cert_compression.rs +0 -125
- data/vendor/wreq/src/tls/keylog/handle.rs +0 -64
- data/vendor/wreq/src/tls/options.rs +0 -464
- /data/vendor/wreq/src/client/{http → layer}/client/lazy.rs +0 -0
- /data/vendor/wreq/src/{client/conn → conn}/proxy.rs +0 -0
- /data/vendor/wreq/src/{client/conn → conn}/verbose.rs +0 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
use std::{convert::Infallible, net::SocketAddr, sync::Arc};
|
|
2
|
+
|
|
3
|
+
use bytes::Bytes;
|
|
4
|
+
use criterion::{BenchmarkGroup, measurement::WallTime};
|
|
5
|
+
use http_body_util::BodyExt;
|
|
6
|
+
use tokio::{runtime::Runtime, sync::Semaphore};
|
|
7
|
+
|
|
8
|
+
use super::{BoxError, HttpVersion, Tls};
|
|
9
|
+
|
|
10
|
+
fn create_wreq_client(tls: Tls, http_version: HttpVersion) -> Result<wreq::Client, BoxError> {
|
|
11
|
+
let builder = wreq::Client::builder()
|
|
12
|
+
.no_proxy()
|
|
13
|
+
.redirect(wreq::redirect::Policy::none())
|
|
14
|
+
.tls_cert_verification(!matches!(tls, Tls::Enabled));
|
|
15
|
+
|
|
16
|
+
let builder = match http_version {
|
|
17
|
+
HttpVersion::Http1 => builder.http1_only(),
|
|
18
|
+
HttpVersion::Http2 => builder.http2_only(),
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
Ok(builder.build()?)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
fn create_reqwest_client(tls: Tls, http_version: HttpVersion) -> Result<reqwest::Client, BoxError> {
|
|
25
|
+
let builder = reqwest::Client::builder()
|
|
26
|
+
.no_proxy()
|
|
27
|
+
.redirect(reqwest::redirect::Policy::none())
|
|
28
|
+
.danger_accept_invalid_certs(matches!(tls, Tls::Enabled));
|
|
29
|
+
|
|
30
|
+
let builder = match http_version {
|
|
31
|
+
HttpVersion::Http1 => builder.http1_only(),
|
|
32
|
+
HttpVersion::Http2 => builder.http2_prior_knowledge(),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
Ok(builder.build()?)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async fn wreq_body_assert(mut response: wreq::Response, expected_body_size: usize) {
|
|
39
|
+
let mut body_size = 0;
|
|
40
|
+
while let Some(Ok(chunk)) = response.frame().await {
|
|
41
|
+
if let Ok(chunk) = chunk.into_data() {
|
|
42
|
+
body_size += chunk.len();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
assert!(
|
|
46
|
+
body_size == expected_body_size,
|
|
47
|
+
"Unexpected response body: got {body_size} bytes, expected {expected_body_size} bytes"
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async fn reqwest_body_assert(mut response: reqwest::Response, expected_body_size: usize) {
|
|
52
|
+
let mut body_size = 0;
|
|
53
|
+
while let Ok(Some(chunk)) = response.chunk().await {
|
|
54
|
+
body_size += chunk.len();
|
|
55
|
+
}
|
|
56
|
+
assert!(
|
|
57
|
+
body_size == expected_body_size,
|
|
58
|
+
"Unexpected response body: got {body_size} bytes, expected {expected_body_size} bytes"
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
fn stream_from_bytes(
|
|
63
|
+
body: &'static [u8],
|
|
64
|
+
chunk_size: usize,
|
|
65
|
+
) -> impl futures_util::stream::TryStream<Ok = Bytes, Error = Infallible> + Send + 'static {
|
|
66
|
+
futures_util::stream::unfold((body, 0), move |(body, offset)| async move {
|
|
67
|
+
if offset >= body.len() {
|
|
68
|
+
None
|
|
69
|
+
} else {
|
|
70
|
+
let end = (offset + chunk_size).min(body.len());
|
|
71
|
+
let chunk = Bytes::from_static(&body[offset..end]);
|
|
72
|
+
Some((Ok::<Bytes, Infallible>(chunk), (body, end)))
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
#[inline]
|
|
78
|
+
fn wreq_body(stream: bool, (body, chunk_size): (&'static [u8], usize)) -> wreq::Body {
|
|
79
|
+
if stream {
|
|
80
|
+
let stream = stream_from_bytes(body, chunk_size);
|
|
81
|
+
wreq::Body::wrap_stream(stream)
|
|
82
|
+
} else {
|
|
83
|
+
wreq::Body::from(body)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
#[inline]
|
|
88
|
+
fn reqwest_body(stream: bool, (body, chunk_size): (&'static [u8], usize)) -> reqwest::Body {
|
|
89
|
+
if stream {
|
|
90
|
+
let stream = stream_from_bytes(body, chunk_size);
|
|
91
|
+
reqwest::Body::wrap_stream(stream)
|
|
92
|
+
} else {
|
|
93
|
+
reqwest::Body::from(body)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async fn wreq_requests_concurrent(
|
|
98
|
+
client: &wreq::Client,
|
|
99
|
+
url: &str,
|
|
100
|
+
num_requests: usize,
|
|
101
|
+
concurrent_limit: usize,
|
|
102
|
+
body: (&'static [u8], usize),
|
|
103
|
+
stream: bool,
|
|
104
|
+
) {
|
|
105
|
+
let semaphore = Arc::new(Semaphore::new(concurrent_limit));
|
|
106
|
+
let mut handles = Vec::with_capacity(num_requests);
|
|
107
|
+
for _ in 0..num_requests {
|
|
108
|
+
let client = client.clone();
|
|
109
|
+
let url = url.to_string();
|
|
110
|
+
let semaphore = semaphore.clone();
|
|
111
|
+
let fut = async move {
|
|
112
|
+
let _permit = semaphore
|
|
113
|
+
.acquire()
|
|
114
|
+
.await
|
|
115
|
+
.expect("Semaphore should be acquirable");
|
|
116
|
+
let response = client
|
|
117
|
+
.post(url)
|
|
118
|
+
.body(wreq_body(stream, body))
|
|
119
|
+
.send()
|
|
120
|
+
.await
|
|
121
|
+
.expect("Unexpected request failure");
|
|
122
|
+
wreq_body_assert(response, body.0.len()).await;
|
|
123
|
+
};
|
|
124
|
+
handles.push(tokio::spawn(fut));
|
|
125
|
+
}
|
|
126
|
+
futures_util::future::join_all(handles).await;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async fn reqwest_requests_concurrent(
|
|
130
|
+
client: &reqwest::Client,
|
|
131
|
+
url: &str,
|
|
132
|
+
num_requests: usize,
|
|
133
|
+
concurrent_limit: usize,
|
|
134
|
+
body: (&'static [u8], usize),
|
|
135
|
+
stream: bool,
|
|
136
|
+
) {
|
|
137
|
+
let semaphore = Arc::new(Semaphore::new(concurrent_limit));
|
|
138
|
+
let mut handles = Vec::with_capacity(num_requests);
|
|
139
|
+
for _ in 0..num_requests {
|
|
140
|
+
let client = client.clone();
|
|
141
|
+
let url = url.to_string();
|
|
142
|
+
let semaphore = semaphore.clone();
|
|
143
|
+
let fut = async move {
|
|
144
|
+
let _permit = semaphore
|
|
145
|
+
.acquire()
|
|
146
|
+
.await
|
|
147
|
+
.expect("Semaphore should be acquirable");
|
|
148
|
+
let response = client
|
|
149
|
+
.post(url)
|
|
150
|
+
.body(reqwest_body(stream, body))
|
|
151
|
+
.send()
|
|
152
|
+
.await
|
|
153
|
+
.expect("Unexpected request failure");
|
|
154
|
+
reqwest_body_assert(response, body.0.len()).await;
|
|
155
|
+
};
|
|
156
|
+
handles.push(tokio::spawn(fut));
|
|
157
|
+
}
|
|
158
|
+
futures_util::future::join_all(handles).await;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
#[allow(clippy::too_many_arguments)]
|
|
162
|
+
pub fn bench_clients(
|
|
163
|
+
group: &mut BenchmarkGroup<'_, WallTime>,
|
|
164
|
+
rt: fn() -> Runtime,
|
|
165
|
+
addr: SocketAddr,
|
|
166
|
+
tls: Tls,
|
|
167
|
+
http_version: HttpVersion,
|
|
168
|
+
num_requests: usize,
|
|
169
|
+
concurrent_limit: usize,
|
|
170
|
+
body: (&'static [u8], usize),
|
|
171
|
+
) -> Result<(), BoxError> {
|
|
172
|
+
let url = format!("{tls}://{addr}");
|
|
173
|
+
|
|
174
|
+
fn make_benchmark_label<T: ?Sized>(stream: bool) -> String {
|
|
175
|
+
let client = std::any::type_name::<T>()
|
|
176
|
+
.split("::")
|
|
177
|
+
.next()
|
|
178
|
+
.expect("Type name should contain at least one segment");
|
|
179
|
+
|
|
180
|
+
let body_type = if stream { "stream" } else { "full" };
|
|
181
|
+
format!("{body_type}/{client}")
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
for stream in [false, true] {
|
|
185
|
+
let client = create_wreq_client(tls, http_version)?;
|
|
186
|
+
group.bench_function(make_benchmark_label::<wreq::Client>(stream), |b| {
|
|
187
|
+
b.to_async(rt()).iter(|| {
|
|
188
|
+
wreq_requests_concurrent(
|
|
189
|
+
&client,
|
|
190
|
+
&url,
|
|
191
|
+
num_requests,
|
|
192
|
+
concurrent_limit,
|
|
193
|
+
body,
|
|
194
|
+
stream,
|
|
195
|
+
)
|
|
196
|
+
})
|
|
197
|
+
});
|
|
198
|
+
::std::mem::drop(client);
|
|
199
|
+
|
|
200
|
+
let client = create_reqwest_client(tls, http_version)?;
|
|
201
|
+
group.bench_function(make_benchmark_label::<reqwest::Client>(stream), |b| {
|
|
202
|
+
b.to_async(rt()).iter(|| {
|
|
203
|
+
reqwest_requests_concurrent(
|
|
204
|
+
&client,
|
|
205
|
+
&url,
|
|
206
|
+
num_requests,
|
|
207
|
+
concurrent_limit,
|
|
208
|
+
body,
|
|
209
|
+
stream,
|
|
210
|
+
)
|
|
211
|
+
})
|
|
212
|
+
});
|
|
213
|
+
::std::mem::drop(client);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
Ok(())
|
|
217
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
use std::{convert::Infallible, io, net::SocketAddr, pin::Pin, sync::Arc, time::Duration};
|
|
2
|
+
|
|
3
|
+
use btls::{
|
|
4
|
+
pkey::PKey,
|
|
5
|
+
ssl::{Ssl, SslAcceptor, SslMethod},
|
|
6
|
+
x509::X509,
|
|
7
|
+
};
|
|
8
|
+
use bytes::Bytes;
|
|
9
|
+
use http_body_util::{BodyExt, Collected, Full};
|
|
10
|
+
use hyper::{body::Incoming, service::service_fn};
|
|
11
|
+
use hyper_util::{
|
|
12
|
+
rt::{TokioExecutor, TokioIo, TokioTimer},
|
|
13
|
+
server::conn::auto::Builder,
|
|
14
|
+
};
|
|
15
|
+
use tokio::{
|
|
16
|
+
io::{AsyncRead, AsyncWrite},
|
|
17
|
+
net::{TcpListener, TcpStream},
|
|
18
|
+
sync::oneshot,
|
|
19
|
+
task::JoinSet,
|
|
20
|
+
};
|
|
21
|
+
use tokio_btls::SslStream;
|
|
22
|
+
|
|
23
|
+
use super::{BoxError, Tls, multi_thread_runtime};
|
|
24
|
+
|
|
25
|
+
pub struct Server {
|
|
26
|
+
listener: std::net::TcpListener,
|
|
27
|
+
tls_acceptor: Option<Arc<SslAcceptor>>,
|
|
28
|
+
builder: Builder<TokioExecutor>,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
impl Server {
|
|
32
|
+
pub fn new(tls: Tls) -> Result<Self, BoxError> {
|
|
33
|
+
let tls_acceptor = match tls {
|
|
34
|
+
Tls::Enabled => {
|
|
35
|
+
let mut builder = SslAcceptor::mozilla_intermediate_v5(SslMethod::tls())?;
|
|
36
|
+
|
|
37
|
+
let cert = X509::from_der(include_bytes!("../../tests/support/server.cert"))?;
|
|
38
|
+
let key =
|
|
39
|
+
PKey::private_key_from_der(include_bytes!("../../tests/support/server.key"))?;
|
|
40
|
+
|
|
41
|
+
builder.set_certificate(&cert)?;
|
|
42
|
+
builder.set_private_key(&key)?;
|
|
43
|
+
builder.check_private_key()?;
|
|
44
|
+
|
|
45
|
+
Some(Arc::new(builder.build()))
|
|
46
|
+
}
|
|
47
|
+
Tls::Disabled => None,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
let mut builder = Builder::new(TokioExecutor::new());
|
|
51
|
+
builder.http1().timer(TokioTimer::new()).keep_alive(true);
|
|
52
|
+
builder
|
|
53
|
+
.http2()
|
|
54
|
+
.timer(TokioTimer::new())
|
|
55
|
+
.keep_alive_interval(Duration::from_secs(30));
|
|
56
|
+
|
|
57
|
+
let listener = std::net::TcpListener::bind("127.0.0.1:0")?;
|
|
58
|
+
listener.set_nonblocking(true)?;
|
|
59
|
+
|
|
60
|
+
Ok(Server {
|
|
61
|
+
listener,
|
|
62
|
+
tls_acceptor,
|
|
63
|
+
builder,
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
fn local_addr(&self) -> io::Result<SocketAddr> {
|
|
68
|
+
self.listener.local_addr()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async fn run(self, mut shutdown: oneshot::Receiver<()>) -> Result<(), BoxError> {
|
|
72
|
+
let mut join_set = JoinSet::new();
|
|
73
|
+
let listener = TcpListener::from_std(self.listener)?;
|
|
74
|
+
|
|
75
|
+
loop {
|
|
76
|
+
tokio::select! {
|
|
77
|
+
_ = &mut shutdown => {
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
accept = listener.accept() => {
|
|
81
|
+
if let Ok((socket, _peer_addr)) = accept {
|
|
82
|
+
let tls_acceptor = self.tls_acceptor.clone();
|
|
83
|
+
let builder = self.builder.clone();
|
|
84
|
+
join_set.spawn(async move {
|
|
85
|
+
handle_connection(socket, tls_acceptor, builder).await;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
while let Some(result) = join_set.join_next().await {
|
|
93
|
+
if let Err(e) = result {
|
|
94
|
+
eprintln!("connection task failed: {e}");
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Tokio internally accepts TCP connections while the TCPListener is active;
|
|
99
|
+
// drop the listener to immediately refuse connections rather than letting
|
|
100
|
+
// them hang.
|
|
101
|
+
::std::mem::drop(listener);
|
|
102
|
+
Ok(())
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
pub struct Handle {
|
|
107
|
+
shutdown: oneshot::Sender<()>,
|
|
108
|
+
join: std::thread::JoinHandle<()>,
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
impl Handle {
|
|
112
|
+
pub fn shutdown(self) {
|
|
113
|
+
let _ = self.shutdown.send(());
|
|
114
|
+
let _ = self.join.join();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
pub fn with_server<F>(tls: Tls, f: F) -> Result<(), BoxError>
|
|
119
|
+
where
|
|
120
|
+
F: FnOnce(SocketAddr) -> Result<(), BoxError>,
|
|
121
|
+
{
|
|
122
|
+
let server = Server::new(tls)?;
|
|
123
|
+
let addr = server.local_addr()?;
|
|
124
|
+
|
|
125
|
+
let (shutdown_tx, shutdown_rx) = oneshot::channel();
|
|
126
|
+
|
|
127
|
+
let join = std::thread::spawn(move || {
|
|
128
|
+
let rt = multi_thread_runtime();
|
|
129
|
+
rt.block_on(server.run(shutdown_rx))
|
|
130
|
+
.expect("Failed to run server with shutdown");
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
std::thread::sleep(Duration::from_millis(100));
|
|
134
|
+
|
|
135
|
+
let handle = Handle {
|
|
136
|
+
shutdown: shutdown_tx,
|
|
137
|
+
join,
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
f(addr)?;
|
|
141
|
+
handle.shutdown();
|
|
142
|
+
|
|
143
|
+
std::thread::sleep(Duration::from_millis(100));
|
|
144
|
+
Ok(())
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async fn serve<S>(builder: Builder<TokioExecutor>, stream: S)
|
|
148
|
+
where
|
|
149
|
+
S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
|
|
150
|
+
{
|
|
151
|
+
let _ = builder
|
|
152
|
+
.serve_connection(
|
|
153
|
+
TokioIo::new(stream),
|
|
154
|
+
service_fn(|req: http::Request<Incoming>| async {
|
|
155
|
+
let bytes = req
|
|
156
|
+
.into_body()
|
|
157
|
+
.collect()
|
|
158
|
+
.await
|
|
159
|
+
.map(Collected::<Bytes>::to_bytes);
|
|
160
|
+
let bytes = bytes.unwrap_or_else(|_| Bytes::new());
|
|
161
|
+
Ok::<_, Infallible>(http::Response::new(Full::new(bytes)))
|
|
162
|
+
}),
|
|
163
|
+
)
|
|
164
|
+
.await;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async fn handle_connection(
|
|
168
|
+
socket: TcpStream,
|
|
169
|
+
tls_acceptor: Option<Arc<SslAcceptor>>,
|
|
170
|
+
builder: Builder<TokioExecutor>,
|
|
171
|
+
) {
|
|
172
|
+
if let Some(acceptor) = tls_acceptor {
|
|
173
|
+
let ssl = Ssl::new(acceptor.context()).expect("failed to create Ssl");
|
|
174
|
+
let mut stream = SslStream::new(ssl, socket).expect("failed to create SslStream");
|
|
175
|
+
|
|
176
|
+
// The client (or its connection pool) may proactively close the connection,
|
|
177
|
+
// especially during benchmarks or when cleaning up idle connections.
|
|
178
|
+
// This can cause TLS handshake failures (e.g., ConnectionReset, ConnectionAborted).
|
|
179
|
+
// Such errors are expected and should be handled gracefully to avoid panicking
|
|
180
|
+
// and to ensure the server remains robust under load.
|
|
181
|
+
if Pin::new(&mut stream).accept().await.is_err() {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
serve(builder, stream).await;
|
|
185
|
+
} else {
|
|
186
|
+
serve(builder, socket).await;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
pub mod bench;
|
|
2
|
+
pub mod client;
|
|
3
|
+
pub mod server;
|
|
4
|
+
|
|
5
|
+
use std::fmt;
|
|
6
|
+
|
|
7
|
+
pub type BoxError = Box<dyn std::error::Error + Send + Sync>;
|
|
8
|
+
|
|
9
|
+
#[allow(unused)]
|
|
10
|
+
#[derive(Clone, Copy, Debug)]
|
|
11
|
+
pub enum HttpVersion {
|
|
12
|
+
Http1,
|
|
13
|
+
Http2,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
impl fmt::Display for HttpVersion {
|
|
17
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
18
|
+
let value = match self {
|
|
19
|
+
HttpVersion::Http1 => "h1",
|
|
20
|
+
HttpVersion::Http2 => "h2",
|
|
21
|
+
};
|
|
22
|
+
f.write_str(value)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#[allow(unused)]
|
|
27
|
+
#[derive(Clone, Copy, Debug)]
|
|
28
|
+
pub enum Tls {
|
|
29
|
+
Enabled,
|
|
30
|
+
Disabled,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
impl fmt::Display for Tls {
|
|
34
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
35
|
+
let value = match self {
|
|
36
|
+
Tls::Enabled => "https",
|
|
37
|
+
Tls::Disabled => "http",
|
|
38
|
+
};
|
|
39
|
+
f.write_str(value)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
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
|
+
}
|
|
@@ -2,7 +2,7 @@ use std::time::Duration;
|
|
|
2
2
|
|
|
3
3
|
use wreq::{
|
|
4
4
|
Client,
|
|
5
|
-
tls::{
|
|
5
|
+
tls::{TlsInfo, trust::CertStore},
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
/// Certificate Store Example
|
|
@@ -39,7 +39,7 @@ use wreq::{
|
|
|
39
39
|
async fn main() -> wreq::Result<()> {
|
|
40
40
|
// Create a client with a custom certificate store using webpki-roots
|
|
41
41
|
let client = Client::builder()
|
|
42
|
-
.
|
|
42
|
+
.tls_cert_store(CertStore::from_der_certs(
|
|
43
43
|
webpki_root_certs::TLS_SERVER_ROOT_CERTS,
|
|
44
44
|
)?)
|
|
45
45
|
.build()?;
|
|
@@ -51,7 +51,7 @@ async fn main() -> wreq::Result<()> {
|
|
|
51
51
|
// Skip certificate verification for self-signed certificates
|
|
52
52
|
let client = Client::builder()
|
|
53
53
|
.tls_info(true)
|
|
54
|
-
.
|
|
54
|
+
.tls_cert_verification(false)
|
|
55
55
|
.build()?;
|
|
56
56
|
|
|
57
57
|
// Use the API you're already familiar with
|
|
@@ -63,7 +63,7 @@ async fn main() -> wreq::Result<()> {
|
|
|
63
63
|
|
|
64
64
|
// Create a client with self-signed certificate store
|
|
65
65
|
let client = Client::builder()
|
|
66
|
-
.
|
|
66
|
+
.tls_cert_store(self_signed_store)
|
|
67
67
|
.connect_timeout(Duration::from_secs(10))
|
|
68
68
|
.build()?;
|
|
69
69
|
|
|
@@ -102,12 +102,12 @@ async fn main() -> wreq::Result<()> {
|
|
|
102
102
|
.http2_options(http2)
|
|
103
103
|
.headers(headers)
|
|
104
104
|
.orig_headers(orig_headers)
|
|
105
|
-
.build();
|
|
105
|
+
.build(Default::default());
|
|
106
106
|
|
|
107
107
|
// Build a client with emulation config
|
|
108
108
|
let client = Client::builder()
|
|
109
109
|
.emulation(emulation)
|
|
110
|
-
.
|
|
110
|
+
.tls_cert_verification(false)
|
|
111
111
|
.build()?;
|
|
112
112
|
|
|
113
113
|
// Use the API you're already familiar with
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
//! ```
|
|
7
7
|
|
|
8
8
|
use futures_util::{SinkExt, StreamExt, TryStreamExt};
|
|
9
|
-
use wreq::{header, ws::message::Message};
|
|
9
|
+
use wreq::{Version, header, ws::message::Message};
|
|
10
10
|
|
|
11
11
|
#[tokio::main]
|
|
12
12
|
async fn main() -> wreq::Result<()> {
|
|
13
13
|
// Use the API you're already familiar with
|
|
14
14
|
let resp = wreq::websocket("wss://127.0.0.1:3000/ws")
|
|
15
|
-
.
|
|
15
|
+
.version(Version::HTTP_2)
|
|
16
16
|
.header(header::USER_AGENT, env!("CARGO_PKG_NAME"))
|
|
17
17
|
.read_buffer_size(1024 * 1024)
|
|
18
18
|
.send()
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
use wreq::tls::KeyLog;
|
|
1
|
+
use wreq::tls::keylog::KeyLog;
|
|
2
2
|
|
|
3
3
|
#[tokio::main]
|
|
4
4
|
async fn main() -> wreq::Result<()> {
|
|
5
5
|
// Build a client
|
|
6
6
|
let client = wreq::Client::builder()
|
|
7
|
-
.
|
|
8
|
-
.
|
|
7
|
+
.tls_keylog(KeyLog::from_file("keylog.txt"))
|
|
8
|
+
.tls_cert_verification(false)
|
|
9
9
|
.build()?;
|
|
10
10
|
|
|
11
11
|
// Use the API you're already familiar with
|
|
@@ -100,9 +100,9 @@ async fn main() -> wreq::Result<()> {
|
|
|
100
100
|
let emulation = Emulation::builder()
|
|
101
101
|
.tls_options(tls)
|
|
102
102
|
.http2_options(http2)
|
|
103
|
-
.headers(headers)
|
|
104
103
|
.orig_headers(orig_headers)
|
|
105
|
-
.
|
|
104
|
+
.headers(headers)
|
|
105
|
+
.build(Default::default());
|
|
106
106
|
|
|
107
107
|
// Use the API you're already familiar with
|
|
108
108
|
let resp = wreq::get("https://tls.peet.ws/api/all")
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
use wreq::{Client, dns};
|
|
2
|
+
use wreq_rt::rt;
|
|
3
|
+
|
|
4
|
+
// Short example of a POST request with form data.
|
|
5
|
+
//
|
|
6
|
+
// This is using the `tokio` runtime. You'll need the following dependency:
|
|
7
|
+
//
|
|
8
|
+
// `tokio = { version = "1", features = ["full"] }`
|
|
9
|
+
#[compio::main]
|
|
10
|
+
async fn main() {
|
|
11
|
+
Client::builder()
|
|
12
|
+
.timer(rt::compio::CompioTimer::new())
|
|
13
|
+
.executor(rt::compio::CompioExecutor::new())
|
|
14
|
+
.dns_resolver(dns::GaiResolver::new())
|
|
15
|
+
.build()
|
|
16
|
+
.expect("build client");
|
|
17
|
+
|
|
18
|
+
let response = wreq::post("http://www.baidu.com")
|
|
19
|
+
.send()
|
|
20
|
+
.await
|
|
21
|
+
.expect("send");
|
|
22
|
+
println!("Response status {}", response.status());
|
|
23
|
+
}
|