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/vendor/wreq/src/client.rs
CHANGED
|
@@ -60,8 +60,10 @@ use crate::dns::hickory::HickoryDnsResolver;
|
|
|
60
60
|
use crate::{
|
|
61
61
|
IntoUri, Method, Proxy,
|
|
62
62
|
conn::{
|
|
63
|
-
BoxedConnectorLayer,
|
|
64
|
-
|
|
63
|
+
BoxedConnectorLayer, BoxedTransportConnector, Conn, Unnameable,
|
|
64
|
+
connector::{Connector, ConnectorBuilder},
|
|
65
|
+
http::HttpConnect,
|
|
66
|
+
net::SocketBindOptions,
|
|
65
67
|
},
|
|
66
68
|
dns::{DnsResolverWithOverrides, DynResolver, GaiResolver, IntoResolve, Resolve},
|
|
67
69
|
error::{self, Error},
|
|
@@ -114,9 +116,7 @@ type MaybeDecompressionBody<T> = tower_http::decompression::DecompressionBody<T>
|
|
|
114
116
|
|
|
115
117
|
type ClientService = Timeout<
|
|
116
118
|
ConfigService<
|
|
117
|
-
MaybeDecompression<
|
|
118
|
-
Retry<RetryPolicy, FollowRedirect<HttpClient<Connector, Body>, FollowRedirectPolicy>>,
|
|
119
|
-
>,
|
|
119
|
+
MaybeDecompression<Retry<RetryPolicy, FollowRedirect<HttpClient<Connector, Body>>>>,
|
|
120
120
|
>,
|
|
121
121
|
>;
|
|
122
122
|
|
|
@@ -185,6 +185,7 @@ struct Config {
|
|
|
185
185
|
pool_max_size: Option<NonZeroUsize>,
|
|
186
186
|
tcp_nodelay: bool,
|
|
187
187
|
tcp_reuse_address: bool,
|
|
188
|
+
tcp_linger: Option<Duration>,
|
|
188
189
|
tcp_keepalive: Option<Duration>,
|
|
189
190
|
tcp_keepalive_interval: Option<Duration>,
|
|
190
191
|
tcp_keepalive_retries: Option<u32>,
|
|
@@ -276,6 +277,7 @@ impl Client {
|
|
|
276
277
|
tcp_user_timeout: Some(Duration::from_secs(30)),
|
|
277
278
|
tcp_nodelay: true,
|
|
278
279
|
tcp_reuse_address: false,
|
|
280
|
+
tcp_linger: None,
|
|
279
281
|
tcp_send_buffer_size: None,
|
|
280
282
|
tcp_recv_buffer_size: None,
|
|
281
283
|
tcp_happy_eyeballs_timeout: Some(Duration::from_millis(300)),
|
|
@@ -502,7 +504,8 @@ impl ClientBuilder {
|
|
|
502
504
|
DynResolver::new(resolver)
|
|
503
505
|
};
|
|
504
506
|
|
|
505
|
-
let connector =
|
|
507
|
+
let connector = ConnectorBuilder::new(config.proxies, resolver)
|
|
508
|
+
.timer(config.timer.clone())
|
|
506
509
|
.timeout(config.connect_timeout)
|
|
507
510
|
.tls_info(config.tls_info)
|
|
508
511
|
.tcp_nodelay(config.tcp_nodelay)
|
|
@@ -529,6 +532,7 @@ impl ClientBuilder {
|
|
|
529
532
|
http.set_keepalive_interval(config.tcp_keepalive_interval);
|
|
530
533
|
http.set_keepalive_retries(config.tcp_keepalive_retries);
|
|
531
534
|
http.set_reuse_address(config.tcp_reuse_address);
|
|
535
|
+
http.set_linger(config.tcp_linger);
|
|
532
536
|
http.set_connect_timeout(config.connect_timeout);
|
|
533
537
|
http.set_nodelay(config.tcp_nodelay);
|
|
534
538
|
http.set_send_buffer_size(config.tcp_send_buffer_size);
|
|
@@ -788,9 +792,8 @@ impl ClientBuilder {
|
|
|
788
792
|
///
|
|
789
793
|
/// If auto gzip decompression is turned on:
|
|
790
794
|
///
|
|
791
|
-
/// -
|
|
792
|
-
/// `
|
|
793
|
-
/// The request body is **not** automatically compressed.
|
|
795
|
+
/// - Requests without `Accept-Encoding` advertise `gzip`. Range requests use `Accept-Encoding:
|
|
796
|
+
/// identity` instead. The request body is **not** automatically compressed.
|
|
794
797
|
/// - When receiving a response, if its headers contain a `Content-Encoding` value of `gzip`,
|
|
795
798
|
/// both `Content-Encoding` and `Content-Length` are removed from the headers' set. The
|
|
796
799
|
/// response body is automatically decompressed.
|
|
@@ -812,9 +815,8 @@ impl ClientBuilder {
|
|
|
812
815
|
///
|
|
813
816
|
/// If auto brotli decompression is turned on:
|
|
814
817
|
///
|
|
815
|
-
/// -
|
|
816
|
-
/// `
|
|
817
|
-
/// request body is **not** automatically compressed.
|
|
818
|
+
/// - Requests without `Accept-Encoding` advertise `br`. Range requests use `Accept-Encoding:
|
|
819
|
+
/// identity` instead. The request body is **not** automatically compressed.
|
|
818
820
|
/// - When receiving a response, if its headers contain a `Content-Encoding` value of `br`, both
|
|
819
821
|
/// `Content-Encoding` and `Content-Length` are removed from the headers' set. The response
|
|
820
822
|
/// body is automatically decompressed.
|
|
@@ -836,9 +838,8 @@ impl ClientBuilder {
|
|
|
836
838
|
///
|
|
837
839
|
/// If auto zstd decompression is turned on:
|
|
838
840
|
///
|
|
839
|
-
/// -
|
|
840
|
-
/// `
|
|
841
|
-
/// The request body is **not** automatically compressed.
|
|
841
|
+
/// - Requests without `Accept-Encoding` advertise `zstd`. Range requests use `Accept-Encoding:
|
|
842
|
+
/// identity` instead. The request body is **not** automatically compressed.
|
|
842
843
|
/// - When receiving a response, if its headers contain a `Content-Encoding` value of `zstd`,
|
|
843
844
|
/// both `Content-Encoding` and `Content-Length` are removed from the headers' set. The
|
|
844
845
|
/// response body is automatically decompressed.
|
|
@@ -860,9 +861,8 @@ impl ClientBuilder {
|
|
|
860
861
|
///
|
|
861
862
|
/// If auto deflate decompression is turned on:
|
|
862
863
|
///
|
|
863
|
-
/// -
|
|
864
|
-
/// `Accept-Encoding
|
|
865
|
-
/// `deflate`. The request body is **not** automatically compressed.
|
|
864
|
+
/// - Requests without `Accept-Encoding` advertise `deflate`. Range requests use
|
|
865
|
+
/// `Accept-Encoding: identity` instead. The request body is **not** automatically compressed.
|
|
866
866
|
/// - When receiving a response, if it's headers contain a `Content-Encoding` value that equals
|
|
867
867
|
/// to `deflate`, both values `Content-Encoding` and `Content-Length` are removed from the
|
|
868
868
|
/// headers' set. The response body is automatically decompressed.
|
|
@@ -963,7 +963,11 @@ impl ClientBuilder {
|
|
|
963
963
|
self
|
|
964
964
|
}
|
|
965
965
|
|
|
966
|
-
/// Enable or disable automatic
|
|
966
|
+
/// Enable or disable automatic `Referer` management during redirects.
|
|
967
|
+
///
|
|
968
|
+
/// When enabled, redirect responses can control how an existing `Referer`
|
|
969
|
+
/// is forwarded through `Referrer-Policy`. No header is added when the
|
|
970
|
+
/// request has none.
|
|
967
971
|
///
|
|
968
972
|
/// Default is `true`.
|
|
969
973
|
#[inline]
|
|
@@ -1041,12 +1045,10 @@ impl ClientBuilder {
|
|
|
1041
1045
|
|
|
1042
1046
|
/// Set a timeout for only the connect phase of a `Client`.
|
|
1043
1047
|
///
|
|
1044
|
-
///
|
|
1045
|
-
///
|
|
1046
|
-
/// # Note
|
|
1048
|
+
/// The timeout covers DNS resolution, the complete TCP address race,
|
|
1049
|
+
/// proxy tunneling, and the TLS handshake.
|
|
1047
1050
|
///
|
|
1048
|
-
///
|
|
1049
|
-
/// a tokio timer enabled.
|
|
1051
|
+
/// Default is `None`.
|
|
1050
1052
|
#[inline]
|
|
1051
1053
|
pub fn connect_timeout(mut self, timeout: Duration) -> ClientBuilder {
|
|
1052
1054
|
self.config.connect_timeout = Some(timeout);
|
|
@@ -1220,6 +1222,27 @@ impl ClientBuilder {
|
|
|
1220
1222
|
self
|
|
1221
1223
|
}
|
|
1222
1224
|
|
|
1225
|
+
/// Set that all sockets have `SO_LINGER` set with the supplied duration.
|
|
1226
|
+
///
|
|
1227
|
+
/// This option controls how long the socket lingers on close while data
|
|
1228
|
+
/// remains unsent. A duration of zero aborts the connection on close: unsent
|
|
1229
|
+
/// data is discarded, the connection is reset (`RST`) rather than going
|
|
1230
|
+
/// through the normal `FIN` termination sequence, and the socket does not
|
|
1231
|
+
/// enter `TIME_WAIT`.
|
|
1232
|
+
///
|
|
1233
|
+
/// If `None`, the option will not be set and the operating system default
|
|
1234
|
+
/// applies.
|
|
1235
|
+
///
|
|
1236
|
+
/// Default is `None`.
|
|
1237
|
+
#[inline]
|
|
1238
|
+
pub fn tcp_linger<D>(mut self, val: D) -> ClientBuilder
|
|
1239
|
+
where
|
|
1240
|
+
D: Into<Option<Duration>>,
|
|
1241
|
+
{
|
|
1242
|
+
self.config.tcp_linger = val.into();
|
|
1243
|
+
self
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1223
1246
|
/// Sets the size of the TCP send buffer on this client socket.
|
|
1224
1247
|
///
|
|
1225
1248
|
/// On most operating systems, this sets the `SO_SNDBUF` socket option.
|
|
@@ -1244,18 +1267,17 @@ impl ClientBuilder {
|
|
|
1244
1267
|
self
|
|
1245
1268
|
}
|
|
1246
1269
|
|
|
1247
|
-
/// Set
|
|
1270
|
+
/// Set the delay between connection attempts for
|
|
1271
|
+
/// [RFC 8305 (Happy Eyeballs v2)][RFC 8305].
|
|
1248
1272
|
///
|
|
1249
|
-
///
|
|
1250
|
-
///
|
|
1251
|
-
/// elapses, then connector will in parallel attempt connection using other
|
|
1252
|
-
/// address family.
|
|
1273
|
+
/// The first address is attempted immediately. Later addresses are started
|
|
1274
|
+
/// after this delay without waiting for the previous attempt to finish.
|
|
1253
1275
|
///
|
|
1254
1276
|
/// If `None`, parallel connection attempts are disabled.
|
|
1255
1277
|
///
|
|
1256
1278
|
/// Default is 300 milliseconds.
|
|
1257
1279
|
///
|
|
1258
|
-
/// [RFC
|
|
1280
|
+
/// [RFC 8305]: https://www.rfc-editor.org/rfc/rfc8305.html#section-5
|
|
1259
1281
|
#[inline]
|
|
1260
1282
|
pub fn tcp_happy_eyeballs_timeout<D>(mut self, val: D) -> ClientBuilder
|
|
1261
1283
|
where
|
|
@@ -1631,7 +1653,7 @@ impl ClientBuilder {
|
|
|
1631
1653
|
#[inline]
|
|
1632
1654
|
pub fn connector_layer<L>(mut self, layer: L) -> ClientBuilder
|
|
1633
1655
|
where
|
|
1634
|
-
L: Layer<
|
|
1656
|
+
L: Layer<BoxedTransportConnector> + Clone + Send + Sync + 'static,
|
|
1635
1657
|
L::Service:
|
|
1636
1658
|
Service<Unnameable, Response = Conn, Error = BoxError> + Clone + Send + Sync + 'static,
|
|
1637
1659
|
<L::Service as Service<Unnameable>>::Future: Send + 'static,
|
|
@@ -1,31 +1,35 @@
|
|
|
1
1
|
use std::{
|
|
2
2
|
borrow::Cow,
|
|
3
|
-
future::Future,
|
|
4
|
-
pin::Pin,
|
|
5
3
|
sync::Arc,
|
|
6
4
|
task::{Context, Poll},
|
|
7
5
|
time::Duration,
|
|
8
6
|
};
|
|
9
7
|
|
|
8
|
+
use futures_util::future::BoxFuture;
|
|
10
9
|
use tokio_btls::SslStream;
|
|
11
10
|
use tower::{
|
|
12
|
-
BoxError, Service, ServiceBuilder, ServiceExt,
|
|
13
|
-
|
|
14
|
-
util::{BoxCloneSyncService, MapRequestLayer},
|
|
11
|
+
BoxError, Layer, Service, ServiceBuilder, ServiceExt,
|
|
12
|
+
util::{BoxCloneSyncService, Either, MapRequest, MapRequestLayer},
|
|
15
13
|
};
|
|
16
14
|
|
|
17
15
|
#[cfg(unix)]
|
|
18
16
|
use super::net::UnixConnector;
|
|
19
17
|
use super::{
|
|
20
|
-
AsyncConnWithInfo, BoxedConnectorLayer,
|
|
21
|
-
TlsConn, TlsInfoFactory, Unnameable,
|
|
22
|
-
|
|
18
|
+
AsyncConnWithInfo, BoxedConnectorLayer, BoxedTransportConnector, Conn, Connection,
|
|
19
|
+
HttpConnector, TlsConn, TlsInfoFactory, Unnameable,
|
|
20
|
+
descriptor::ConnectionDescriptor,
|
|
21
|
+
http::HttpConnect,
|
|
22
|
+
net::TcpConnector,
|
|
23
|
+
proxy,
|
|
24
|
+
timeout::{Timeout, TimeoutLayer},
|
|
25
|
+
verbose::Verbose,
|
|
23
26
|
};
|
|
24
27
|
use crate::{
|
|
25
28
|
dns::DynResolver,
|
|
26
|
-
error::{ProxyConnect,
|
|
29
|
+
error::{ProxyConnect, map_timeout_to_connector_error},
|
|
27
30
|
ext::UriExt,
|
|
28
31
|
proxy::{Intercepted, Matcher as ProxyMatcher, matcher::Intercept},
|
|
32
|
+
rt::Timer,
|
|
29
33
|
tls::{
|
|
30
34
|
TlsOptions,
|
|
31
35
|
conn::{
|
|
@@ -34,41 +38,51 @@ use crate::{
|
|
|
34
38
|
},
|
|
35
39
|
};
|
|
36
40
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
///
|
|
41
|
+
/// Client-wide connection settings retained by each transport connector.
|
|
42
|
+
///
|
|
43
|
+
/// These defaults control proxy selection, socket behavior, stream instrumentation, and TLS
|
|
44
|
+
/// metadata. Settings that can vary per request remain in [`ConnectionDescriptor`] and are
|
|
45
|
+
/// applied when a connection starts.
|
|
40
46
|
#[derive(Clone)]
|
|
41
47
|
struct Config {
|
|
42
48
|
proxies: Arc<Vec<ProxyMatcher>>,
|
|
43
49
|
verbose: Verbose,
|
|
44
50
|
nodelay: bool,
|
|
45
51
|
tls_info: bool,
|
|
46
|
-
/// When there is a single timeout layer and no other layers,
|
|
47
|
-
/// we embed it directly inside our base Service::call().
|
|
48
|
-
/// This lets us avoid an extra `Box::pin` indirection layer
|
|
49
|
-
/// since `tokio::time::Timeout` is `Unpin`
|
|
50
|
-
timeout: Option<Duration>,
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
///
|
|
54
|
+
/// Assembles the transport service graph used by a client.
|
|
55
|
+
///
|
|
56
|
+
/// The builder owns DNS, TCP, TLS, and timeout configuration until [`ConnectorBuilder::build`]
|
|
57
|
+
/// places the timeout around the concrete connector and any user-provided layers.
|
|
54
58
|
pub struct ConnectorBuilder {
|
|
55
59
|
config: Config,
|
|
60
|
+
timer: Timer,
|
|
61
|
+
timeout: Option<Duration>,
|
|
56
62
|
#[cfg(feature = "socks")]
|
|
57
63
|
resolver: DynResolver,
|
|
58
64
|
http: HttpConnector,
|
|
59
65
|
builder: TlsConnectorBuilder,
|
|
60
66
|
}
|
|
61
67
|
|
|
62
|
-
///
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
/// Client-owned transport service selected when the connector graph is assembled.
|
|
69
|
+
///
|
|
70
|
+
/// The left branch keeps the graph concrete when no custom layers are present. The right branch
|
|
71
|
+
/// wraps the type-erased custom-layer graph so it also accepts [`ConnectionDescriptor`]. Both
|
|
72
|
+
/// branches remain with the client and create a separately timed future for each connection
|
|
73
|
+
/// attempt.
|
|
74
|
+
pub type Connector = Either<
|
|
75
|
+
Timeout<TransportConnector>,
|
|
76
|
+
MapRequest<BoxedTransportConnector, fn(ConnectionDescriptor) -> Unnameable>,
|
|
77
|
+
>;
|
|
78
|
+
|
|
79
|
+
/// Establishes the transport consumed by the HTTP protocol layer.
|
|
80
|
+
///
|
|
81
|
+
/// Each call selects the proxy path, applies request-specific socket and TLS settings, and returns
|
|
82
|
+
/// an established [`Conn`]. The service is cloned into each in-flight connection future, while its
|
|
83
|
+
/// immutable TLS builder is shared across those attempts.
|
|
70
84
|
#[derive(Clone)]
|
|
71
|
-
pub struct
|
|
85
|
+
pub struct TransportConnector {
|
|
72
86
|
config: Config,
|
|
73
87
|
#[cfg(feature = "socks")]
|
|
74
88
|
resolver: DynResolver,
|
|
@@ -80,6 +94,24 @@ pub struct ConnectorService {
|
|
|
80
94
|
// ===== impl ConnectorBuilder =====
|
|
81
95
|
|
|
82
96
|
impl ConnectorBuilder {
|
|
97
|
+
/// Creates a builder with the client's proxy and DNS configuration.
|
|
98
|
+
pub(crate) fn new(proxies: Vec<ProxyMatcher>, resolver: DynResolver) -> Self {
|
|
99
|
+
Self {
|
|
100
|
+
config: Config {
|
|
101
|
+
proxies: Arc::new(proxies),
|
|
102
|
+
verbose: Verbose::OFF,
|
|
103
|
+
nodelay: true,
|
|
104
|
+
tls_info: false,
|
|
105
|
+
},
|
|
106
|
+
timer: Timer::default(),
|
|
107
|
+
timeout: None,
|
|
108
|
+
#[cfg(feature = "socks")]
|
|
109
|
+
resolver: resolver.clone(),
|
|
110
|
+
http: HttpConnector::new(resolver, TcpConnector::new()),
|
|
111
|
+
builder: TlsConnector::builder(),
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
83
115
|
/// Set the HTTP connector to use.
|
|
84
116
|
#[inline]
|
|
85
117
|
pub fn with_http<F>(mut self, call: F) -> ConnectorBuilder
|
|
@@ -101,12 +133,16 @@ impl ConnectorBuilder {
|
|
|
101
133
|
}
|
|
102
134
|
|
|
103
135
|
/// Set the connect timeout.
|
|
104
|
-
///
|
|
105
|
-
/// If a domain resolves to multiple IP addresses, the timeout will be
|
|
106
|
-
/// evenly divided across them.
|
|
107
136
|
#[inline]
|
|
108
137
|
pub fn timeout(mut self, timeout: Option<Duration>) -> ConnectorBuilder {
|
|
109
|
-
self.
|
|
138
|
+
self.timeout = timeout;
|
|
139
|
+
self
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/// Set the timer used to drive the connect timeout.
|
|
143
|
+
#[inline]
|
|
144
|
+
pub fn timer(mut self, timer: Timer) -> ConnectorBuilder {
|
|
145
|
+
self.timer = timer;
|
|
110
146
|
self
|
|
111
147
|
}
|
|
112
148
|
|
|
@@ -137,7 +173,8 @@ impl ConnectorBuilder {
|
|
|
137
173
|
tls_options: Option<TlsOptions>,
|
|
138
174
|
layers: Vec<BoxedConnectorLayer>,
|
|
139
175
|
) -> crate::Result<Connector> {
|
|
140
|
-
let
|
|
176
|
+
let timeout = TimeoutLayer::new(self.timer, self.timeout);
|
|
177
|
+
let service = TransportConnector {
|
|
141
178
|
config: self.config,
|
|
142
179
|
#[cfg(feature = "socks")]
|
|
143
180
|
resolver: self.resolver.clone(),
|
|
@@ -150,12 +187,9 @@ impl ConnectorBuilder {
|
|
|
150
187
|
|
|
151
188
|
// we have no user-provided layers, only use concrete types
|
|
152
189
|
if layers.is_empty() {
|
|
153
|
-
return Ok(
|
|
190
|
+
return Ok(Either::Left(timeout.layer(service)));
|
|
154
191
|
}
|
|
155
192
|
|
|
156
|
-
// user-provided layers exist, the timeout will be applied as an additional layer.
|
|
157
|
-
let timeout = service.config.timeout.take();
|
|
158
|
-
|
|
159
193
|
// otherwise we have user provided layers
|
|
160
194
|
// so we need type erasure all the way through
|
|
161
195
|
// as well as mapping the unnameable type of the layers back to ConnectionDescriptor for the
|
|
@@ -169,78 +203,25 @@ impl ConnectorBuilder {
|
|
|
169
203
|
|service, layer| ServiceBuilder::new().layer(layer).service(service),
|
|
170
204
|
);
|
|
171
205
|
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
.layer(TimeoutLayer::new(timeout))
|
|
179
|
-
.service(service)
|
|
180
|
-
.map_err(map_timeout_to_connector_error);
|
|
181
|
-
|
|
182
|
-
Ok(Connector::WithLayers(BoxCloneSyncService::new(service)))
|
|
183
|
-
}
|
|
184
|
-
None => {
|
|
185
|
-
// no timeout, but still map err
|
|
186
|
-
// no named timeout layer but we still map errors since
|
|
187
|
-
// we might have user-provided timeout layer
|
|
188
|
-
let service = ServiceBuilder::new()
|
|
189
|
-
.service(service)
|
|
190
|
-
.map_err(map_timeout_to_connector_error);
|
|
191
|
-
|
|
192
|
-
Ok(Connector::WithLayers(BoxCloneSyncService::new(service)))
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// ===== impl Connector =====
|
|
199
|
-
|
|
200
|
-
impl Connector {
|
|
201
|
-
/// Creates a new [`Connector`] with the provided configuration and optional layers.
|
|
202
|
-
pub(crate) fn builder(proxies: Vec<ProxyMatcher>, resolver: DynResolver) -> ConnectorBuilder {
|
|
203
|
-
ConnectorBuilder {
|
|
204
|
-
config: Config {
|
|
205
|
-
proxies: Arc::new(proxies),
|
|
206
|
-
verbose: Verbose::OFF,
|
|
207
|
-
nodelay: true,
|
|
208
|
-
tls_info: false,
|
|
209
|
-
timeout: None,
|
|
210
|
-
},
|
|
211
|
-
#[cfg(feature = "socks")]
|
|
212
|
-
resolver: resolver.clone(),
|
|
213
|
-
http: HttpConnector::new(resolver, TcpConnector::new()),
|
|
214
|
-
builder: TlsConnector::builder(),
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
206
|
+
// Keep the built-in timeout outside user layers so it covers their work too.
|
|
207
|
+
// The final mapping also handles a tower timeout supplied by the caller.
|
|
208
|
+
let service = ServiceBuilder::new()
|
|
209
|
+
.layer(timeout)
|
|
210
|
+
.service(service)
|
|
211
|
+
.map_err(map_timeout_to_connector_error);
|
|
218
212
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
#[inline]
|
|
225
|
-
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
226
|
-
match self {
|
|
227
|
-
Connector::Simple(service) => service.poll_ready(cx),
|
|
228
|
-
Connector::WithLayers(service) => service.poll_ready(cx),
|
|
229
|
-
}
|
|
230
|
-
}
|
|
213
|
+
let service = MapRequest::new(
|
|
214
|
+
BoxCloneSyncService::new(service),
|
|
215
|
+
Unnameable as fn(ConnectionDescriptor) -> Unnameable,
|
|
216
|
+
);
|
|
231
217
|
|
|
232
|
-
|
|
233
|
-
fn call(&mut self, descriptor: ConnectionDescriptor) -> Self::Future {
|
|
234
|
-
match self {
|
|
235
|
-
Connector::Simple(service) => service.call(descriptor),
|
|
236
|
-
Connector::WithLayers(service) => service.call(Unnameable(descriptor)),
|
|
237
|
-
}
|
|
218
|
+
Ok(Either::Right(service))
|
|
238
219
|
}
|
|
239
220
|
}
|
|
240
221
|
|
|
241
|
-
// ===== impl
|
|
222
|
+
// ===== impl TransportConnector =====
|
|
242
223
|
|
|
243
|
-
impl
|
|
224
|
+
impl TransportConnector {
|
|
244
225
|
fn build_https_connector(
|
|
245
226
|
&self,
|
|
246
227
|
https: bool,
|
|
@@ -503,41 +484,30 @@ impl ConnectorService {
|
|
|
503
484
|
async fn connect_auto(self, req: ConnectionDescriptor) -> Result<Conn, BoxError> {
|
|
504
485
|
debug!("starting new connection: {:?}", req.uri());
|
|
505
486
|
|
|
506
|
-
let timeout = self.config.timeout;
|
|
507
|
-
|
|
508
487
|
// Determine if a proxy should be used for this request.
|
|
509
|
-
let
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
.
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
self.connect_via_proxy(req, intercepted).await
|
|
523
|
-
} else {
|
|
524
|
-
self.connect_auto_proxy(req, None).await
|
|
525
|
-
}
|
|
526
|
-
};
|
|
527
|
-
|
|
528
|
-
// Apply timeout if configured.
|
|
529
|
-
if let Some(to) = timeout {
|
|
530
|
-
tokio::time::timeout(to, fut).await.map_err(|_| TimedOut)?
|
|
488
|
+
let intercepted = req
|
|
489
|
+
.proxy()
|
|
490
|
+
.and_then(|prox| prox.intercept(req.uri()))
|
|
491
|
+
.or_else(|| {
|
|
492
|
+
self.config
|
|
493
|
+
.proxies
|
|
494
|
+
.iter()
|
|
495
|
+
.find_map(|prox| prox.intercept(req.uri()))
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
// If a proxy is matched, connect via proxy; otherwise, connect directly.
|
|
499
|
+
if let Some(intercepted) = intercepted {
|
|
500
|
+
self.connect_via_proxy(req, intercepted).await
|
|
531
501
|
} else {
|
|
532
|
-
|
|
502
|
+
self.connect_auto_proxy(req, None).await
|
|
533
503
|
}
|
|
534
504
|
}
|
|
535
505
|
}
|
|
536
506
|
|
|
537
|
-
impl Service<ConnectionDescriptor> for
|
|
507
|
+
impl Service<ConnectionDescriptor> for TransportConnector {
|
|
538
508
|
type Response = Conn;
|
|
539
509
|
type Error = BoxError;
|
|
540
|
-
type Future =
|
|
510
|
+
type Future = BoxFuture<'static, Result<Conn, BoxError>>;
|
|
541
511
|
|
|
542
512
|
#[inline]
|
|
543
513
|
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
@@ -20,7 +20,7 @@ use super::{
|
|
|
20
20
|
tcp::{ConnectError, ConnectingTcp, TcpConnector, TcpKeepaliveOptions, TcpOptions},
|
|
21
21
|
},
|
|
22
22
|
};
|
|
23
|
-
use crate::dns::{self,
|
|
23
|
+
use crate::dns::{self, DnsResolver};
|
|
24
24
|
|
|
25
25
|
static INVALID_NOT_HTTP: &str = "invalid URI, scheme is not http";
|
|
26
26
|
static INVALID_MISSING_SCHEME: &str = "invalid URI, scheme is missing";
|
|
@@ -56,16 +56,19 @@ where
|
|
|
56
56
|
/// Set that all socket have `SO_REUSEADDR` set to the supplied value `reuse_address`.
|
|
57
57
|
fn set_reuse_address(&mut self, reuse: bool);
|
|
58
58
|
|
|
59
|
+
/// Sets the value of the `SO_LINGER` option on the socket.
|
|
60
|
+
fn set_linger(&mut self, linger: Option<Duration>);
|
|
61
|
+
|
|
59
62
|
/// Sets the value of the `TCP_USER_TIMEOUT` option on the socket.
|
|
60
63
|
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
|
61
64
|
fn set_tcp_user_timeout(&mut self, time: Option<Duration>);
|
|
62
65
|
|
|
63
|
-
/// Set the
|
|
66
|
+
/// Set the timeout for the complete TCP connection race.
|
|
64
67
|
fn set_connect_timeout(&mut self, dur: Option<Duration>);
|
|
65
68
|
|
|
66
|
-
/// Set
|
|
69
|
+
/// Set the delay between connection attempts for [RFC 8305 (Happy Eyeballs v2)][RFC 8305].
|
|
67
70
|
///
|
|
68
|
-
/// [RFC
|
|
71
|
+
/// [RFC 8305]: https://www.rfc-editor.org/rfc/rfc8305.html#section-5
|
|
69
72
|
fn set_happy_eyeballs_timeout(&mut self, dur: Option<Duration>);
|
|
70
73
|
|
|
71
74
|
/// Set that all sockets have `SO_KEEPALIVE` set with the supplied duration
|
|
@@ -156,6 +159,7 @@ impl<R, S> HttpConnector<R, S> {
|
|
|
156
159
|
happy_eyeballs_timeout: Some(Duration::from_millis(300)),
|
|
157
160
|
nodelay: false,
|
|
158
161
|
reuse_address: false,
|
|
162
|
+
linger: None,
|
|
159
163
|
send_buffer_size: None,
|
|
160
164
|
recv_buffer_size: None,
|
|
161
165
|
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
|
@@ -178,7 +182,7 @@ impl<R, S> HttpConnector<R, S> {
|
|
|
178
182
|
|
|
179
183
|
impl<R, S> HttpConnect for HttpConnector<R, S>
|
|
180
184
|
where
|
|
181
|
-
R:
|
|
185
|
+
R: DnsResolver + Clone + Send + Sync + 'static,
|
|
182
186
|
R::Future: Send,
|
|
183
187
|
S: TcpConnector,
|
|
184
188
|
{
|
|
@@ -218,6 +222,14 @@ where
|
|
|
218
222
|
self.config_mut().reuse_address = reuse_address;
|
|
219
223
|
}
|
|
220
224
|
|
|
225
|
+
/// Sets the value of the SO_LINGER option on the socket.
|
|
226
|
+
///
|
|
227
|
+
/// Default is `None`, which leaves the option untouched.
|
|
228
|
+
#[inline]
|
|
229
|
+
fn set_linger(&mut self, linger: Option<Duration>) {
|
|
230
|
+
self.config_mut().linger = linger;
|
|
231
|
+
}
|
|
232
|
+
|
|
221
233
|
/// Sets the value of the TCP_USER_TIMEOUT option on the socket.
|
|
222
234
|
#[inline]
|
|
223
235
|
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
|
|
@@ -225,10 +237,7 @@ where
|
|
|
225
237
|
self.config_mut().tcp_user_timeout = time;
|
|
226
238
|
}
|
|
227
239
|
|
|
228
|
-
/// Set the
|
|
229
|
-
///
|
|
230
|
-
/// If a domain resolves to multiple IP addresses, the timeout will be
|
|
231
|
-
/// evenly divided across them.
|
|
240
|
+
/// Set the timeout for the complete TCP connection race.
|
|
232
241
|
///
|
|
233
242
|
/// Default is `None`.
|
|
234
243
|
#[inline]
|
|
@@ -236,18 +245,16 @@ where
|
|
|
236
245
|
self.config_mut().connect_timeout = dur;
|
|
237
246
|
}
|
|
238
247
|
|
|
239
|
-
/// Set
|
|
248
|
+
/// Set the delay between connection attempts for [RFC 8305 (Happy Eyeballs v2)][RFC 8305].
|
|
240
249
|
///
|
|
241
|
-
///
|
|
242
|
-
///
|
|
243
|
-
/// elapses, then connector will in parallel attempt connection using other
|
|
244
|
-
/// address family.
|
|
250
|
+
/// The first address is attempted immediately. Later addresses are started
|
|
251
|
+
/// after this delay without waiting for the previous attempt to finish.
|
|
245
252
|
///
|
|
246
253
|
/// If `None`, parallel connection attempts are disabled.
|
|
247
254
|
///
|
|
248
255
|
/// Default is 300 milliseconds.
|
|
249
256
|
///
|
|
250
|
-
/// [RFC
|
|
257
|
+
/// [RFC 8305]: https://www.rfc-editor.org/rfc/rfc8305.html#section-5
|
|
251
258
|
#[inline]
|
|
252
259
|
fn set_happy_eyeballs_timeout(&mut self, dur: Option<Duration>) {
|
|
253
260
|
self.config_mut().happy_eyeballs_timeout = dur;
|
|
@@ -337,7 +344,7 @@ where
|
|
|
337
344
|
|
|
338
345
|
impl<R, S> Service<Uri> for HttpConnector<R, S>
|
|
339
346
|
where
|
|
340
|
-
R:
|
|
347
|
+
R: DnsResolver + Clone + Send + Sync + 'static,
|
|
341
348
|
R::Future: Send,
|
|
342
349
|
S: TcpConnector,
|
|
343
350
|
S::TcpStream: From<socket2::Socket>,
|
|
@@ -358,7 +365,7 @@ where
|
|
|
358
365
|
let options = &this.options;
|
|
359
366
|
|
|
360
367
|
let (host, port) = get_host_port(options, &dst)?;
|
|
361
|
-
let host = host
|
|
368
|
+
let host = crate::util::strip_ipv6_brackets(host);
|
|
362
369
|
|
|
363
370
|
let addrs = if let Some(addrs) = dns::SocketAddrs::try_parse(host, port) {
|
|
364
371
|
addrs
|
|
@@ -472,7 +479,7 @@ pin_project! {
|
|
|
472
479
|
|
|
473
480
|
impl<R, S> Future for HttpConnecting<R, S>
|
|
474
481
|
where
|
|
475
|
-
R:
|
|
482
|
+
R: DnsResolver,
|
|
476
483
|
S: TcpConnector,
|
|
477
484
|
{
|
|
478
485
|
type Output = ConnectResult<S>;
|