wreq-rb 0.3.0
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 +7 -0
- data/Cargo.lock +2688 -0
- data/Cargo.toml +6 -0
- data/README.md +179 -0
- data/ext/wreq_rb/Cargo.toml +39 -0
- data/ext/wreq_rb/extconf.rb +22 -0
- data/ext/wreq_rb/src/client.rs +565 -0
- data/ext/wreq_rb/src/error.rs +25 -0
- data/ext/wreq_rb/src/lib.rs +20 -0
- data/ext/wreq_rb/src/response.rs +132 -0
- data/lib/wreq-rb/version.rb +5 -0
- data/lib/wreq-rb.rb +17 -0
- data/patches/0001-add-transfer-size-tracking.patch +292 -0
- data/vendor/wreq/Cargo.toml +306 -0
- data/vendor/wreq/LICENSE +202 -0
- data/vendor/wreq/README.md +122 -0
- data/vendor/wreq/examples/cert_store.rs +77 -0
- data/vendor/wreq/examples/connect_via_lower_priority_tokio_runtime.rs +258 -0
- data/vendor/wreq/examples/emulation.rs +118 -0
- data/vendor/wreq/examples/form.rs +14 -0
- data/vendor/wreq/examples/http1_websocket.rs +37 -0
- data/vendor/wreq/examples/http2_websocket.rs +45 -0
- data/vendor/wreq/examples/json_dynamic.rs +41 -0
- data/vendor/wreq/examples/json_typed.rs +47 -0
- data/vendor/wreq/examples/keylog.rs +16 -0
- data/vendor/wreq/examples/request_with_emulation.rs +115 -0
- data/vendor/wreq/examples/request_with_interface.rs +37 -0
- data/vendor/wreq/examples/request_with_local_address.rs +16 -0
- data/vendor/wreq/examples/request_with_proxy.rs +13 -0
- data/vendor/wreq/examples/request_with_redirect.rs +22 -0
- data/vendor/wreq/examples/request_with_version.rs +15 -0
- data/vendor/wreq/examples/tor_socks.rs +24 -0
- data/vendor/wreq/examples/unix_socket.rs +33 -0
- data/vendor/wreq/src/client/body.rs +304 -0
- data/vendor/wreq/src/client/conn/conn.rs +231 -0
- data/vendor/wreq/src/client/conn/connector.rs +549 -0
- data/vendor/wreq/src/client/conn/http.rs +1023 -0
- data/vendor/wreq/src/client/conn/proxy/socks.rs +233 -0
- data/vendor/wreq/src/client/conn/proxy/tunnel.rs +260 -0
- data/vendor/wreq/src/client/conn/proxy.rs +39 -0
- data/vendor/wreq/src/client/conn/tls_info.rs +98 -0
- data/vendor/wreq/src/client/conn/uds.rs +44 -0
- data/vendor/wreq/src/client/conn/verbose.rs +149 -0
- data/vendor/wreq/src/client/conn.rs +323 -0
- data/vendor/wreq/src/client/core/body/incoming.rs +485 -0
- data/vendor/wreq/src/client/core/body/length.rs +118 -0
- data/vendor/wreq/src/client/core/body.rs +34 -0
- data/vendor/wreq/src/client/core/common/buf.rs +149 -0
- data/vendor/wreq/src/client/core/common/rewind.rs +141 -0
- data/vendor/wreq/src/client/core/common/watch.rs +76 -0
- data/vendor/wreq/src/client/core/common.rs +3 -0
- data/vendor/wreq/src/client/core/conn/http1.rs +342 -0
- data/vendor/wreq/src/client/core/conn/http2.rs +307 -0
- data/vendor/wreq/src/client/core/conn.rs +11 -0
- data/vendor/wreq/src/client/core/dispatch.rs +299 -0
- data/vendor/wreq/src/client/core/error.rs +435 -0
- data/vendor/wreq/src/client/core/ext.rs +201 -0
- data/vendor/wreq/src/client/core/http1.rs +178 -0
- data/vendor/wreq/src/client/core/http2.rs +483 -0
- data/vendor/wreq/src/client/core/proto/h1/conn.rs +988 -0
- data/vendor/wreq/src/client/core/proto/h1/decode.rs +1170 -0
- data/vendor/wreq/src/client/core/proto/h1/dispatch.rs +684 -0
- data/vendor/wreq/src/client/core/proto/h1/encode.rs +580 -0
- data/vendor/wreq/src/client/core/proto/h1/io.rs +879 -0
- data/vendor/wreq/src/client/core/proto/h1/role.rs +694 -0
- data/vendor/wreq/src/client/core/proto/h1.rs +104 -0
- data/vendor/wreq/src/client/core/proto/h2/client.rs +650 -0
- data/vendor/wreq/src/client/core/proto/h2/ping.rs +539 -0
- data/vendor/wreq/src/client/core/proto/h2.rs +379 -0
- data/vendor/wreq/src/client/core/proto/headers.rs +138 -0
- data/vendor/wreq/src/client/core/proto.rs +58 -0
- data/vendor/wreq/src/client/core/rt/bounds.rs +57 -0
- data/vendor/wreq/src/client/core/rt/timer.rs +150 -0
- data/vendor/wreq/src/client/core/rt/tokio.rs +99 -0
- data/vendor/wreq/src/client/core/rt.rs +25 -0
- data/vendor/wreq/src/client/core/upgrade.rs +267 -0
- data/vendor/wreq/src/client/core.rs +16 -0
- data/vendor/wreq/src/client/emulation.rs +161 -0
- data/vendor/wreq/src/client/http/client/error.rs +142 -0
- data/vendor/wreq/src/client/http/client/exec.rs +29 -0
- data/vendor/wreq/src/client/http/client/extra.rs +77 -0
- data/vendor/wreq/src/client/http/client/lazy.rs +79 -0
- data/vendor/wreq/src/client/http/client/pool.rs +1105 -0
- data/vendor/wreq/src/client/http/client/util.rs +104 -0
- data/vendor/wreq/src/client/http/client.rs +1003 -0
- data/vendor/wreq/src/client/http/future.rs +99 -0
- data/vendor/wreq/src/client/http.rs +1629 -0
- data/vendor/wreq/src/client/layer/config/options.rs +156 -0
- data/vendor/wreq/src/client/layer/config.rs +116 -0
- data/vendor/wreq/src/client/layer/cookie.rs +161 -0
- data/vendor/wreq/src/client/layer/decoder.rs +139 -0
- data/vendor/wreq/src/client/layer/redirect/future.rs +270 -0
- data/vendor/wreq/src/client/layer/redirect/policy.rs +63 -0
- data/vendor/wreq/src/client/layer/redirect.rs +145 -0
- data/vendor/wreq/src/client/layer/retry/classify.rs +105 -0
- data/vendor/wreq/src/client/layer/retry/scope.rs +51 -0
- data/vendor/wreq/src/client/layer/retry.rs +151 -0
- data/vendor/wreq/src/client/layer/timeout/body.rs +233 -0
- data/vendor/wreq/src/client/layer/timeout/future.rs +90 -0
- data/vendor/wreq/src/client/layer/timeout.rs +177 -0
- data/vendor/wreq/src/client/layer.rs +15 -0
- data/vendor/wreq/src/client/multipart.rs +717 -0
- data/vendor/wreq/src/client/request.rs +818 -0
- data/vendor/wreq/src/client/response.rs +534 -0
- data/vendor/wreq/src/client/ws/json.rs +99 -0
- data/vendor/wreq/src/client/ws/message.rs +453 -0
- data/vendor/wreq/src/client/ws.rs +714 -0
- data/vendor/wreq/src/client.rs +27 -0
- data/vendor/wreq/src/config.rs +140 -0
- data/vendor/wreq/src/cookie.rs +579 -0
- data/vendor/wreq/src/dns/gai.rs +249 -0
- data/vendor/wreq/src/dns/hickory.rs +78 -0
- data/vendor/wreq/src/dns/resolve.rs +180 -0
- data/vendor/wreq/src/dns.rs +69 -0
- data/vendor/wreq/src/error.rs +502 -0
- data/vendor/wreq/src/ext.rs +398 -0
- data/vendor/wreq/src/hash.rs +143 -0
- data/vendor/wreq/src/header.rs +506 -0
- data/vendor/wreq/src/into_uri.rs +187 -0
- data/vendor/wreq/src/lib.rs +586 -0
- data/vendor/wreq/src/proxy/mac.rs +82 -0
- data/vendor/wreq/src/proxy/matcher.rs +806 -0
- data/vendor/wreq/src/proxy/uds.rs +66 -0
- data/vendor/wreq/src/proxy/win.rs +31 -0
- data/vendor/wreq/src/proxy.rs +569 -0
- data/vendor/wreq/src/redirect.rs +575 -0
- data/vendor/wreq/src/retry.rs +198 -0
- data/vendor/wreq/src/sync.rs +129 -0
- data/vendor/wreq/src/tls/conn/cache.rs +123 -0
- data/vendor/wreq/src/tls/conn/cert_compression.rs +125 -0
- data/vendor/wreq/src/tls/conn/ext.rs +82 -0
- data/vendor/wreq/src/tls/conn/macros.rs +34 -0
- data/vendor/wreq/src/tls/conn/service.rs +138 -0
- data/vendor/wreq/src/tls/conn.rs +681 -0
- data/vendor/wreq/src/tls/keylog/handle.rs +64 -0
- data/vendor/wreq/src/tls/keylog.rs +99 -0
- data/vendor/wreq/src/tls/options.rs +464 -0
- data/vendor/wreq/src/tls/x509/identity.rs +122 -0
- data/vendor/wreq/src/tls/x509/parser.rs +71 -0
- data/vendor/wreq/src/tls/x509/store.rs +228 -0
- data/vendor/wreq/src/tls/x509.rs +68 -0
- data/vendor/wreq/src/tls.rs +154 -0
- data/vendor/wreq/src/trace.rs +55 -0
- data/vendor/wreq/src/util.rs +122 -0
- data/vendor/wreq/tests/badssl.rs +228 -0
- data/vendor/wreq/tests/brotli.rs +350 -0
- data/vendor/wreq/tests/client.rs +1098 -0
- data/vendor/wreq/tests/connector_layers.rs +227 -0
- data/vendor/wreq/tests/cookie.rs +306 -0
- data/vendor/wreq/tests/deflate.rs +347 -0
- data/vendor/wreq/tests/emulation.rs +260 -0
- data/vendor/wreq/tests/gzip.rs +347 -0
- data/vendor/wreq/tests/layers.rs +261 -0
- data/vendor/wreq/tests/multipart.rs +165 -0
- data/vendor/wreq/tests/proxy.rs +438 -0
- data/vendor/wreq/tests/redirect.rs +629 -0
- data/vendor/wreq/tests/retry.rs +135 -0
- data/vendor/wreq/tests/support/delay_server.rs +117 -0
- data/vendor/wreq/tests/support/error.rs +16 -0
- data/vendor/wreq/tests/support/layer.rs +183 -0
- data/vendor/wreq/tests/support/mod.rs +9 -0
- data/vendor/wreq/tests/support/server.rs +232 -0
- data/vendor/wreq/tests/timeouts.rs +281 -0
- data/vendor/wreq/tests/unix_socket.rs +135 -0
- data/vendor/wreq/tests/upgrade.rs +98 -0
- data/vendor/wreq/tests/zstd.rs +559 -0
- metadata +225 -0
|
@@ -0,0 +1,549 @@
|
|
|
1
|
+
#[cfg(unix)]
|
|
2
|
+
use std::path::Path;
|
|
3
|
+
use std::{
|
|
4
|
+
future::Future,
|
|
5
|
+
pin::Pin,
|
|
6
|
+
sync::Arc,
|
|
7
|
+
task::{Context, Poll},
|
|
8
|
+
time::Duration,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
use http::Uri;
|
|
12
|
+
use tokio::io::{AsyncRead, AsyncWrite};
|
|
13
|
+
use tokio_boring2::SslStream;
|
|
14
|
+
use tower::{
|
|
15
|
+
Service, ServiceBuilder, ServiceExt,
|
|
16
|
+
timeout::TimeoutLayer,
|
|
17
|
+
util::{BoxCloneSyncService, MapRequestLayer},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
#[cfg(unix)]
|
|
21
|
+
use super::uds::UnixConnector;
|
|
22
|
+
use super::{
|
|
23
|
+
AsyncConnWithInfo, BoxedConnectorLayer, BoxedConnectorService, Connection, HttpConnector,
|
|
24
|
+
TlsInfoFactory, Unnameable,
|
|
25
|
+
conn::{Conn, TlsConn},
|
|
26
|
+
proxy,
|
|
27
|
+
verbose::Verbose,
|
|
28
|
+
};
|
|
29
|
+
use crate::{
|
|
30
|
+
client::http::{ConnectExtra, ConnectRequest},
|
|
31
|
+
dns::DynResolver,
|
|
32
|
+
error::{BoxError, ProxyConnect, TimedOut, map_timeout_to_connector_error},
|
|
33
|
+
ext::UriExt,
|
|
34
|
+
proxy::{Intercepted, Matcher as ProxyMatcher, matcher::Intercept},
|
|
35
|
+
tls::{
|
|
36
|
+
TlsOptions,
|
|
37
|
+
conn::{
|
|
38
|
+
EstablishedConn, HttpsConnector, MaybeHttpsStream, TlsConnector, TlsConnectorBuilder,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
type Connecting = Pin<Box<dyn Future<Output = Result<Conn, BoxError>> + Send>>;
|
|
44
|
+
|
|
45
|
+
/// Configuration for the connector service.
|
|
46
|
+
#[derive(Clone)]
|
|
47
|
+
struct Config {
|
|
48
|
+
proxies: Arc<Vec<ProxyMatcher>>,
|
|
49
|
+
verbose: Verbose,
|
|
50
|
+
tcp_nodelay: bool,
|
|
51
|
+
tls_info: bool,
|
|
52
|
+
/// When there is a single timeout layer and no other layers,
|
|
53
|
+
/// we embed it directly inside our base Service::call().
|
|
54
|
+
/// This lets us avoid an extra `Box::pin` indirection layer
|
|
55
|
+
/// since `tokio::time::Timeout` is `Unpin`
|
|
56
|
+
timeout: Option<Duration>,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/// Builder for `Connector`.
|
|
60
|
+
pub struct ConnectorBuilder {
|
|
61
|
+
config: Config,
|
|
62
|
+
#[cfg(feature = "socks")]
|
|
63
|
+
resolver: DynResolver,
|
|
64
|
+
http: HttpConnector,
|
|
65
|
+
tls_options: TlsOptions,
|
|
66
|
+
tls_builder: TlsConnectorBuilder,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/// Connector service that establishes connections.
|
|
70
|
+
#[derive(Clone)]
|
|
71
|
+
pub enum Connector {
|
|
72
|
+
Simple(ConnectorService),
|
|
73
|
+
WithLayers(BoxedConnectorService),
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/// Service that establishes connections to HTTP servers.
|
|
77
|
+
#[derive(Clone)]
|
|
78
|
+
pub struct ConnectorService {
|
|
79
|
+
config: Config,
|
|
80
|
+
#[cfg(feature = "socks")]
|
|
81
|
+
resolver: DynResolver,
|
|
82
|
+
http: HttpConnector,
|
|
83
|
+
tls: TlsConnector,
|
|
84
|
+
tls_builder: Arc<TlsConnectorBuilder>,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ===== impl ConnectorBuilder =====
|
|
88
|
+
|
|
89
|
+
impl ConnectorBuilder {
|
|
90
|
+
/// Set the HTTP connector to use.
|
|
91
|
+
#[inline]
|
|
92
|
+
pub fn with_http<F>(mut self, call: F) -> ConnectorBuilder
|
|
93
|
+
where
|
|
94
|
+
F: FnOnce(&mut HttpConnector),
|
|
95
|
+
{
|
|
96
|
+
call(&mut self.http);
|
|
97
|
+
self
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/// Set the TLS connector builder to use.
|
|
101
|
+
#[inline]
|
|
102
|
+
pub fn with_tls<F>(mut self, call: F) -> ConnectorBuilder
|
|
103
|
+
where
|
|
104
|
+
F: FnOnce(TlsConnectorBuilder) -> TlsConnectorBuilder,
|
|
105
|
+
{
|
|
106
|
+
self.tls_builder = call(self.tls_builder);
|
|
107
|
+
self
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/// Set the connect timeout.
|
|
111
|
+
///
|
|
112
|
+
/// If a domain resolves to multiple IP addresses, the timeout will be
|
|
113
|
+
/// evenly divided across them.
|
|
114
|
+
#[inline]
|
|
115
|
+
pub fn timeout(mut self, timeout: Option<Duration>) -> ConnectorBuilder {
|
|
116
|
+
self.config.timeout = timeout;
|
|
117
|
+
self
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/// Set connecting verbose mode.
|
|
121
|
+
#[inline]
|
|
122
|
+
pub fn verbose(mut self, enabled: bool) -> ConnectorBuilder {
|
|
123
|
+
self.config.verbose.0 = enabled;
|
|
124
|
+
self
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/// Sets the TLS info flag.
|
|
128
|
+
#[inline]
|
|
129
|
+
pub fn tls_info(mut self, enabled: bool) -> ConnectorBuilder {
|
|
130
|
+
self.config.tls_info = enabled;
|
|
131
|
+
self
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/// Sets the TLS options to use.
|
|
135
|
+
#[inline]
|
|
136
|
+
pub fn tls_options(mut self, opts: Option<TlsOptions>) -> ConnectorBuilder {
|
|
137
|
+
if let Some(opts) = opts {
|
|
138
|
+
self.tls_options = opts;
|
|
139
|
+
}
|
|
140
|
+
self
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/// Build a [`Connector`] with the provided layers.
|
|
144
|
+
pub fn build(self, layers: Vec<BoxedConnectorLayer>) -> crate::Result<Connector> {
|
|
145
|
+
let mut service = ConnectorService {
|
|
146
|
+
config: self.config,
|
|
147
|
+
#[cfg(feature = "socks")]
|
|
148
|
+
resolver: self.resolver.clone(),
|
|
149
|
+
http: self.http,
|
|
150
|
+
tls: self.tls_builder.build(&self.tls_options)?,
|
|
151
|
+
tls_builder: Arc::new(self.tls_builder),
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// we have no user-provided layers, only use concrete types
|
|
155
|
+
if layers.is_empty() {
|
|
156
|
+
return Ok(Connector::Simple(service));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// user-provided layers exist, the timeout will be applied as an additional layer.
|
|
160
|
+
let timeout = service.config.timeout.take();
|
|
161
|
+
|
|
162
|
+
// otherwise we have user provided layers
|
|
163
|
+
// so we need type erasure all the way through
|
|
164
|
+
// as well as mapping the unnameable type of the layers back to ConnectRequest for the
|
|
165
|
+
// inner service
|
|
166
|
+
let service = layers.into_iter().fold(
|
|
167
|
+
BoxCloneSyncService::new(
|
|
168
|
+
ServiceBuilder::new()
|
|
169
|
+
.layer(MapRequestLayer::new(|request: Unnameable| request.0))
|
|
170
|
+
.service(service),
|
|
171
|
+
),
|
|
172
|
+
|service, layer| ServiceBuilder::new().layer(layer).service(service),
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
// now we handle the concrete stuff - any `connect_timeout`,
|
|
176
|
+
// plus a final map_err layer we can use to cast default tower layer
|
|
177
|
+
// errors to internal errors
|
|
178
|
+
match timeout {
|
|
179
|
+
Some(timeout) => {
|
|
180
|
+
let service = ServiceBuilder::new()
|
|
181
|
+
.layer(TimeoutLayer::new(timeout))
|
|
182
|
+
.service(service)
|
|
183
|
+
.map_err(map_timeout_to_connector_error);
|
|
184
|
+
|
|
185
|
+
Ok(Connector::WithLayers(BoxCloneSyncService::new(service)))
|
|
186
|
+
}
|
|
187
|
+
None => {
|
|
188
|
+
// no timeout, but still map err
|
|
189
|
+
// no named timeout layer but we still map errors since
|
|
190
|
+
// we might have user-provided timeout layer
|
|
191
|
+
let service = ServiceBuilder::new()
|
|
192
|
+
.service(service)
|
|
193
|
+
.map_err(map_timeout_to_connector_error);
|
|
194
|
+
|
|
195
|
+
Ok(Connector::WithLayers(BoxCloneSyncService::new(service)))
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ===== impl Connector =====
|
|
202
|
+
|
|
203
|
+
impl Connector {
|
|
204
|
+
/// Creates a new [`Connector`] with the provided configuration and optional layers.
|
|
205
|
+
pub(crate) fn builder(proxies: Vec<ProxyMatcher>, resolver: DynResolver) -> ConnectorBuilder {
|
|
206
|
+
ConnectorBuilder {
|
|
207
|
+
config: Config {
|
|
208
|
+
proxies: Arc::new(proxies),
|
|
209
|
+
verbose: Verbose::OFF,
|
|
210
|
+
tcp_nodelay: false,
|
|
211
|
+
tls_info: false,
|
|
212
|
+
timeout: None,
|
|
213
|
+
},
|
|
214
|
+
#[cfg(feature = "socks")]
|
|
215
|
+
resolver: resolver.clone(),
|
|
216
|
+
http: HttpConnector::new_with_resolver(resolver),
|
|
217
|
+
tls_options: TlsOptions::default(),
|
|
218
|
+
tls_builder: TlsConnector::builder(),
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
impl Service<ConnectRequest> for Connector {
|
|
224
|
+
type Response = Conn;
|
|
225
|
+
type Error = BoxError;
|
|
226
|
+
type Future = Connecting;
|
|
227
|
+
|
|
228
|
+
#[inline]
|
|
229
|
+
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
230
|
+
match self {
|
|
231
|
+
Connector::Simple(service) => service.poll_ready(cx),
|
|
232
|
+
Connector::WithLayers(service) => service.poll_ready(cx),
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
#[inline]
|
|
237
|
+
fn call(&mut self, req: ConnectRequest) -> Self::Future {
|
|
238
|
+
match self {
|
|
239
|
+
Connector::Simple(service) => service.call(req),
|
|
240
|
+
Connector::WithLayers(service) => service.call(Unnameable(req)),
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ===== impl ConnectorService =====
|
|
246
|
+
|
|
247
|
+
impl ConnectorService {
|
|
248
|
+
fn tunnel_conn_from_stream<IO>(&self, io: MaybeHttpsStream<IO>) -> Result<Conn, BoxError>
|
|
249
|
+
where
|
|
250
|
+
IO: AsyncConnWithInfo,
|
|
251
|
+
TlsConn<IO>: Connection,
|
|
252
|
+
SslStream<IO>: TlsInfoFactory,
|
|
253
|
+
{
|
|
254
|
+
let conn = match io {
|
|
255
|
+
MaybeHttpsStream::Http(inner) => Conn {
|
|
256
|
+
inner: self.config.verbose.wrap(inner),
|
|
257
|
+
tls_info: false,
|
|
258
|
+
proxy: None,
|
|
259
|
+
},
|
|
260
|
+
MaybeHttpsStream::Https(inner) => Conn {
|
|
261
|
+
inner: self.config.verbose.wrap(TlsConn::new(inner)),
|
|
262
|
+
tls_info: self.config.tls_info,
|
|
263
|
+
proxy: None,
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
Ok(conn)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
fn conn_from_stream<IO, P>(&self, io: MaybeHttpsStream<IO>, proxy: P) -> Result<Conn, BoxError>
|
|
271
|
+
where
|
|
272
|
+
IO: AsyncConnWithInfo,
|
|
273
|
+
TlsConn<IO>: Connection,
|
|
274
|
+
SslStream<IO>: TlsInfoFactory,
|
|
275
|
+
P: Into<Option<Intercept>>,
|
|
276
|
+
{
|
|
277
|
+
let conn = match io {
|
|
278
|
+
MaybeHttpsStream::Http(inner) => self.config.verbose.wrap(inner),
|
|
279
|
+
MaybeHttpsStream::Https(inner) => self.config.verbose.wrap(TlsConn::new(inner)),
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
Ok(Conn {
|
|
283
|
+
inner: conn,
|
|
284
|
+
tls_info: self.config.tls_info,
|
|
285
|
+
proxy: proxy.into(),
|
|
286
|
+
})
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
fn build_https_connector(
|
|
290
|
+
&self,
|
|
291
|
+
extra: &ConnectExtra,
|
|
292
|
+
) -> Result<HttpsConnector<HttpConnector>, BoxError> {
|
|
293
|
+
let mut http = self.http.clone();
|
|
294
|
+
|
|
295
|
+
// Disable Nagle's algorithm for TLS handshake
|
|
296
|
+
//
|
|
297
|
+
// https://www.openssl.org/docs/man1.1.1/man3/SSL_connect.html#NOTES
|
|
298
|
+
if !self.config.tcp_nodelay {
|
|
299
|
+
http.set_nodelay(true);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Apply TCP options if provided in metadata
|
|
303
|
+
if let Some(opts) = extra.tcp_options() {
|
|
304
|
+
http.set_connect_options(opts.clone());
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
self.build_tls_connector_generic(http, extra)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
#[cfg(unix)]
|
|
311
|
+
fn build_unix_connector(
|
|
312
|
+
&self,
|
|
313
|
+
unix_socket: Arc<Path>,
|
|
314
|
+
extra: &ConnectExtra,
|
|
315
|
+
) -> Result<HttpsConnector<UnixConnector>, BoxError> {
|
|
316
|
+
// Create a Unix connector with the specified socket path
|
|
317
|
+
self.build_tls_connector_generic(UnixConnector(unix_socket), extra)
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
fn build_tls_connector_generic<S, T>(
|
|
321
|
+
&self,
|
|
322
|
+
connector: S,
|
|
323
|
+
extra: &ConnectExtra,
|
|
324
|
+
) -> Result<HttpsConnector<S>, BoxError>
|
|
325
|
+
where
|
|
326
|
+
S: Service<Uri, Response = T> + Send,
|
|
327
|
+
S::Error: Into<BoxError>,
|
|
328
|
+
S::Future: Unpin + Send + 'static,
|
|
329
|
+
T: AsyncRead + AsyncWrite + Connection + Unpin + std::fmt::Debug + Sync + Send + 'static,
|
|
330
|
+
{
|
|
331
|
+
// Prefer TLS options from metadata, fallback to default
|
|
332
|
+
let tls = extra
|
|
333
|
+
.tls_options()
|
|
334
|
+
.map(|opts| self.tls_builder.build(opts))
|
|
335
|
+
.transpose()?
|
|
336
|
+
.unwrap_or_else(|| self.tls.clone());
|
|
337
|
+
|
|
338
|
+
Ok(HttpsConnector::with_connector(connector, tls))
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
impl ConnectorService {
|
|
343
|
+
async fn connect_auto_proxy<P>(self, req: ConnectRequest, proxy: P) -> Result<Conn, BoxError>
|
|
344
|
+
where
|
|
345
|
+
P: Into<Option<Intercept>>,
|
|
346
|
+
{
|
|
347
|
+
let proxy = proxy.into();
|
|
348
|
+
trace!("connect with maybe proxy: {:?}", proxy);
|
|
349
|
+
|
|
350
|
+
let mut connector = self.build_https_connector(req.extra())?;
|
|
351
|
+
|
|
352
|
+
// When using a proxy for HTTPS targets, disable ALPN to avoid protocol negotiation issues
|
|
353
|
+
if proxy.is_some() && req.uri().is_https() {
|
|
354
|
+
connector.no_alpn();
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
let io = connector.call(req).await?;
|
|
358
|
+
|
|
359
|
+
// Re-enable Nagle's algorithm if it was disabled earlier
|
|
360
|
+
if !self.config.tcp_nodelay {
|
|
361
|
+
io.get_ref().set_nodelay(false)?;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
self.conn_from_stream(io, proxy)
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
async fn connect_via_proxy(
|
|
368
|
+
self,
|
|
369
|
+
mut req: ConnectRequest,
|
|
370
|
+
proxy: Intercepted,
|
|
371
|
+
) -> Result<Conn, BoxError> {
|
|
372
|
+
let uri = req.uri().clone();
|
|
373
|
+
|
|
374
|
+
match proxy {
|
|
375
|
+
Intercepted::Proxy(proxy) => {
|
|
376
|
+
let proxy_uri = proxy.uri().clone();
|
|
377
|
+
|
|
378
|
+
#[cfg(feature = "socks")]
|
|
379
|
+
{
|
|
380
|
+
use proxy::socks::{DnsResolve, SocksConnector, Version};
|
|
381
|
+
|
|
382
|
+
if let Some((version, dns_resolve)) = match proxy.uri().scheme_str() {
|
|
383
|
+
Some("socks4") => Some((Version::V4, DnsResolve::Local)),
|
|
384
|
+
Some("socks4a") => Some((Version::V4, DnsResolve::Remote)),
|
|
385
|
+
Some("socks5") => Some((Version::V5, DnsResolve::Local)),
|
|
386
|
+
Some("socks5h") => Some((Version::V5, DnsResolve::Remote)),
|
|
387
|
+
_ => None,
|
|
388
|
+
} {
|
|
389
|
+
trace!("connecting via SOCKS proxy: {:?}", proxy_uri);
|
|
390
|
+
|
|
391
|
+
// Connect to the proxy and establish the SOCKS connection.
|
|
392
|
+
let conn = {
|
|
393
|
+
// Build a SOCKS connector.
|
|
394
|
+
let mut socks = SocksConnector::new_with_resolver(
|
|
395
|
+
proxy_uri,
|
|
396
|
+
self.http.clone(),
|
|
397
|
+
self.resolver.clone(),
|
|
398
|
+
);
|
|
399
|
+
socks.set_auth(proxy.raw_auth());
|
|
400
|
+
socks.set_version(version);
|
|
401
|
+
socks.set_dns_mode(dns_resolve);
|
|
402
|
+
socks.call(uri).await?
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
// Build an HTTPS connector.
|
|
406
|
+
let mut connector = self.build_https_connector(req.extra())?;
|
|
407
|
+
|
|
408
|
+
// Wrap the established SOCKS connection with TLS if needed.
|
|
409
|
+
let io = connector.call(EstablishedConn::new(conn, req)).await?;
|
|
410
|
+
|
|
411
|
+
// Re-enable Nagle's algorithm if it was disabled earlier
|
|
412
|
+
if !self.config.tcp_nodelay {
|
|
413
|
+
io.get_ref().set_nodelay(false)?;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return self.tunnel_conn_from_stream(io);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Handle HTTPS proxy tunneling connection
|
|
421
|
+
if uri.is_https() {
|
|
422
|
+
trace!("tunneling over HTTP(s) proxy: {:?}", proxy_uri);
|
|
423
|
+
|
|
424
|
+
// Build an HTTPS connector.
|
|
425
|
+
let mut connector = self.build_https_connector(req.extra())?;
|
|
426
|
+
|
|
427
|
+
// Build a tunnel connector to establish the CONNECT tunnel.
|
|
428
|
+
let tunneled = {
|
|
429
|
+
let mut tunnel =
|
|
430
|
+
proxy::tunnel::TunnelConnector::new(proxy_uri, connector.clone());
|
|
431
|
+
|
|
432
|
+
// If the proxy requires basic authentication, add it to the tunnel.
|
|
433
|
+
if let Some(auth) = proxy.basic_auth() {
|
|
434
|
+
tunnel = tunnel.with_auth(auth.clone());
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// If the proxy has custom headers, add them to the tunnel.
|
|
438
|
+
if let Some(headers) = proxy.custom_headers() {
|
|
439
|
+
tunnel = tunnel.with_headers(headers.clone());
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Connect to the proxy and establish the tunnel.
|
|
443
|
+
tunnel.call(uri).await?
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
// Wrap the established tunneled stream with TLS.
|
|
447
|
+
let io = connector.call(EstablishedConn::new(tunneled, req)).await?;
|
|
448
|
+
|
|
449
|
+
// Re-enable Nagle's algorithm if it was disabled earlier
|
|
450
|
+
if !self.config.tcp_nodelay {
|
|
451
|
+
io.get_ref().get_ref().set_nodelay(false)?;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
return self.tunnel_conn_from_stream(io);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
*req.uri_mut() = proxy_uri;
|
|
458
|
+
self.connect_auto_proxy(req, proxy)
|
|
459
|
+
.await
|
|
460
|
+
.map_err(ProxyConnect)
|
|
461
|
+
.map_err(Into::into)
|
|
462
|
+
}
|
|
463
|
+
#[cfg(unix)]
|
|
464
|
+
Intercepted::Unix(unix_socket) => {
|
|
465
|
+
trace!("connecting via Unix socket: {:?}", unix_socket);
|
|
466
|
+
|
|
467
|
+
// Create a Unix connector with the specified socket path.
|
|
468
|
+
let mut connector = self.build_unix_connector(unix_socket, req.extra())?;
|
|
469
|
+
|
|
470
|
+
// If the target URI is HTTPS, establish a CONNECT tunnel over the Unix socket,
|
|
471
|
+
// then upgrade the tunneled stream to TLS.
|
|
472
|
+
if uri.is_https() {
|
|
473
|
+
// Use a dummy HTTP URI so the HTTPS connector works over the Unix socket.
|
|
474
|
+
let proxy_uri = Uri::from_static("http://localhost");
|
|
475
|
+
|
|
476
|
+
// The tunnel connector will first establish a CONNECT tunnel,
|
|
477
|
+
// then perform the TLS handshake over the tunneled stream.
|
|
478
|
+
let tunneled = {
|
|
479
|
+
// Create a tunnel connector using the Unix socket and the HTTPS connector.
|
|
480
|
+
let mut tunnel =
|
|
481
|
+
proxy::tunnel::TunnelConnector::new(proxy_uri, connector.clone());
|
|
482
|
+
|
|
483
|
+
tunnel.call(uri).await?
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
// Wrap the established tunneled stream with TLS.
|
|
487
|
+
let io = connector.call(EstablishedConn::new(tunneled, req)).await?;
|
|
488
|
+
|
|
489
|
+
return self.tunnel_conn_from_stream(io);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// For plain HTTP, use the Unix connector directly.
|
|
493
|
+
let io = connector.call(req).await?;
|
|
494
|
+
|
|
495
|
+
self.conn_from_stream(io, None)
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
async fn connect_auto(self, req: ConnectRequest) -> Result<Conn, BoxError> {
|
|
501
|
+
debug!("starting new connection: {:?}", req.uri());
|
|
502
|
+
|
|
503
|
+
let timeout = self.config.timeout;
|
|
504
|
+
|
|
505
|
+
// Determine if a proxy should be used for this request.
|
|
506
|
+
let fut = async {
|
|
507
|
+
let intercepted = req
|
|
508
|
+
.extra()
|
|
509
|
+
.proxy_matcher()
|
|
510
|
+
.and_then(|prox| prox.intercept(req.uri()))
|
|
511
|
+
.or_else(|| {
|
|
512
|
+
self.config
|
|
513
|
+
.proxies
|
|
514
|
+
.iter()
|
|
515
|
+
.find_map(|prox| prox.intercept(req.uri()))
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
// If a proxy is matched, connect via proxy; otherwise, connect directly.
|
|
519
|
+
if let Some(intercepted) = intercepted {
|
|
520
|
+
self.connect_via_proxy(req, intercepted).await
|
|
521
|
+
} else {
|
|
522
|
+
self.connect_auto_proxy(req, None).await
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
// Apply timeout if configured.
|
|
527
|
+
if let Some(to) = timeout {
|
|
528
|
+
tokio::time::timeout(to, fut).await.map_err(|_| TimedOut)?
|
|
529
|
+
} else {
|
|
530
|
+
fut.await
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
impl Service<ConnectRequest> for ConnectorService {
|
|
536
|
+
type Response = Conn;
|
|
537
|
+
type Error = BoxError;
|
|
538
|
+
type Future = Connecting;
|
|
539
|
+
|
|
540
|
+
#[inline]
|
|
541
|
+
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
542
|
+
Poll::Ready(Ok(()))
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
#[inline]
|
|
546
|
+
fn call(&mut self, req: ConnectRequest) -> Self::Future {
|
|
547
|
+
Box::pin(self.clone().connect_auto(req))
|
|
548
|
+
}
|
|
549
|
+
}
|