wreq-rb 0.6.0 → 0.6.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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +257 -102
  3. data/ext/wreq_rb/Cargo.toml +4 -4
  4. data/ext/wreq_rb/src/client.rs +1 -1
  5. data/lib/wreq-rb/version.rb +1 -1
  6. data/patches/0001-add-transfer-size-tracking.patch +11 -15
  7. data/vendor/wreq/Cargo.toml +9 -8
  8. data/vendor/wreq/README.md +5 -5
  9. data/vendor/wreq/bench/support/bench.rs +6 -2
  10. data/vendor/wreq/bench/support/client.rs +88 -1
  11. data/vendor/wreq/bench/support/exec.rs +0 -0
  12. data/vendor/wreq/bench/support/rt.rs +34 -0
  13. data/vendor/wreq/bench/support/server.rs +1 -1
  14. data/vendor/wreq/bench/support.rs +1 -15
  15. data/vendor/wreq/examples/cert_store.rs +13 -13
  16. data/vendor/wreq/examples/request_with_emulate.rs +1 -1
  17. data/vendor/wreq/examples/tcp_linger.rs +22 -0
  18. data/vendor/wreq/src/client/layer/client/pool.rs +17 -17
  19. data/vendor/wreq/src/client/layer/client.rs +2 -0
  20. data/vendor/wreq/src/client/layer/decoder.rs +71 -17
  21. data/vendor/wreq/src/client/layer/redirect/future.rs +49 -63
  22. data/vendor/wreq/src/client/layer/redirect/policy.rs +2 -26
  23. data/vendor/wreq/src/client/layer/redirect.rs +48 -60
  24. data/vendor/wreq/src/client/layer/retry.rs +12 -15
  25. data/vendor/wreq/src/client/layer/timeout/body.rs +27 -21
  26. data/vendor/wreq/src/client/layer/timeout/future.rs +33 -58
  27. data/vendor/wreq/src/client/layer/timeout.rs +8 -14
  28. data/vendor/wreq/src/client/request.rs +4 -0
  29. data/vendor/wreq/src/client.rs +53 -31
  30. data/vendor/wreq/src/conn/connector.rs +99 -129
  31. data/vendor/wreq/src/conn/http.rs +25 -18
  32. data/vendor/wreq/src/conn/net/tcp.rs +601 -107
  33. data/vendor/wreq/src/conn/proxy/socks.rs +6 -6
  34. data/vendor/wreq/src/conn/timeout.rs +166 -0
  35. data/vendor/wreq/src/conn.rs +5 -4
  36. data/vendor/wreq/src/cookie/jar.rs +1225 -0
  37. data/vendor/wreq/src/cookie/store.rs +321 -0
  38. data/vendor/wreq/src/cookie.rs +108 -612
  39. data/vendor/wreq/src/dns/resolve.rs +8 -2
  40. data/vendor/wreq/src/dns.rs +4 -4
  41. data/vendor/wreq/src/error.rs +53 -20
  42. data/vendor/wreq/src/lib.rs +1 -0
  43. data/vendor/wreq/src/proxy/matcher.rs +26 -12
  44. data/vendor/wreq/src/proxy/win.rs +39 -9
  45. data/vendor/wreq/src/redirect.rs +515 -100
  46. data/vendor/wreq/src/tls/conn.rs +3 -11
  47. data/vendor/wreq/src/tls/session.rs +7 -8
  48. data/vendor/wreq/src/tls/trust/store.rs +4 -4
  49. data/vendor/wreq/src/util.rs +23 -0
  50. data/vendor/wreq/tests/badssl.rs +72 -7
  51. data/vendor/wreq/tests/brotli.rs +1 -1
  52. data/vendor/wreq/tests/client.rs +24 -0
  53. data/vendor/wreq/tests/connector_layers.rs +8 -4
  54. data/vendor/wreq/tests/cookie.rs +59 -0
  55. data/vendor/wreq/tests/deflate.rs +1 -1
  56. data/vendor/wreq/tests/gzip.rs +53 -1
  57. data/vendor/wreq/tests/layers.rs +8 -4
  58. data/vendor/wreq/tests/redirect.rs +180 -97
  59. data/vendor/wreq/tests/timeouts.rs +47 -12
  60. data/vendor/wreq/tests/zstd.rs +1 -1
  61. metadata +7 -1
@@ -57,33 +57,33 @@ pin_project! {
57
57
  /// The timeout resets after every successful read. If a single read
58
58
  /// takes longer than the specified duration, an error is returned.
59
59
  pub struct ReadTimeoutBody<B> {
60
- timeout: Duration,
61
- #[pin]
62
- sleep: Option<Pin<Box<dyn Sleep>>>,
63
60
  #[pin]
64
61
  body: B,
62
+ #[pin]
63
+ sleep: Option<Pin<Box<dyn Sleep>>>,
64
+ timeout: Duration,
65
65
  timer: Timer,
66
66
  }
67
67
  }
68
68
 
69
- /// ==== impl TimeoutBody ====
69
+ // ===== impl TimeoutBody =====
70
+
70
71
  impl<B> TimeoutBody<B> {
71
- /// Creates a new [`TimeoutBody`] with no timeout.
72
+ /// Wraps a body with the active total timeout and an optional read timeout.
72
73
  pub fn new(
74
+ body: B,
73
75
  timer: Timer,
74
- deadline: Option<Duration>,
75
76
  read_timeout: Option<Duration>,
76
- body: B,
77
+ total_timeout: Option<Pin<Box<dyn Sleep>>>,
77
78
  ) -> Self {
78
- let deadline = deadline.map(|deadline| timer.sleep(deadline));
79
- match (deadline, read_timeout) {
79
+ match (total_timeout, read_timeout) {
80
80
  (Some(total_timeout), Some(read_timeout)) => TimeoutBody::CombinedTimeout {
81
81
  body: TotalTimeoutBody {
82
82
  timeout: total_timeout,
83
83
  body: ReadTimeoutBody {
84
- timeout: read_timeout,
85
- sleep: None,
86
84
  body,
85
+ sleep: None,
86
+ timeout: read_timeout,
87
87
  timer,
88
88
  },
89
89
  },
@@ -160,7 +160,8 @@ where
160
160
  )
161
161
  }
162
162
 
163
- // ==== impl TotalTimeoutBody ====
163
+ // ===== impl TotalTimeoutBody =====
164
+
164
165
  impl<B> Body for TotalTimeoutBody<B>
165
166
  where
166
167
  B: Body,
@@ -191,7 +192,8 @@ where
191
192
  }
192
193
  }
193
194
 
194
- /// ==== impl ReadTimeoutBody ====
195
+ // ===== impl ReadTimeoutBody =====
196
+
195
197
  impl<B> Body for ReadTimeoutBody<B>
196
198
  where
197
199
  B: Body,
@@ -206,23 +208,27 @@ where
206
208
  ) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {
207
209
  let mut this = self.project();
208
210
 
209
- // Error if the timeout has expired.
211
+ // Start the timeout on the first poll.
210
212
  if this.sleep.is_none() {
211
- this.sleep.set(Some(this.timer.sleep(*this.timeout)));
213
+ let deadline = this.timer.now() + *this.timeout;
214
+ this.sleep.set(Some(this.timer.sleep_until(deadline)));
212
215
  }
213
216
 
214
217
  // Error if the timeout has expired.
215
- if let Some(sleep) = this.sleep.as_mut().as_pin_mut() {
216
- if sleep.poll(cx).is_ready() {
217
- return Poll::Ready(Some(Err(Box::new(TimedOut))));
218
- }
218
+ if let Some(sleep) = this.sleep.as_mut().as_pin_mut()
219
+ && sleep.poll(cx).is_ready()
220
+ {
221
+ return Poll::Ready(Some(Err(Error::body(TimedOut).into())));
219
222
  }
220
223
 
221
224
  // Poll the actual body
222
225
  match ready!(this.body.poll_frame(cx)) {
223
226
  Some(Ok(frame)) => {
224
- // Reset timeout on successful read
225
- this.sleep.set(None);
227
+ // Reuse the sleep to avoid allocating and registering a new timer for every frame.
228
+ if let Some(sleep) = this.sleep.as_mut().as_pin_mut() {
229
+ let deadline = this.timer.now() + *this.timeout;
230
+ this.timer.reset(sleep.get_mut(), deadline);
231
+ }
226
232
  Poll::Ready(Some(Ok(frame)))
227
233
  }
228
234
  Some(Err(err)) => Poll::Ready(Some(Err(err.into()))),
@@ -16,80 +16,55 @@ use crate::{
16
16
  };
17
17
 
18
18
  pin_project! {
19
- /// [`Timeout`] response future
19
+ /// Waits for response headers, then moves the total timeout into the response body.
20
20
  pub struct ResponseFuture<Fut> {
21
21
  #[pin]
22
- pub(crate) fut: Fut,
23
- pub(crate) total_timeout: Option<Pin<Box<dyn Sleep>>>,
24
- pub(crate) read_timeout: Option<Pin<Box<dyn Sleep>>>,
22
+ pub(super) fut: Fut,
23
+ pub(super) timer: Timer,
24
+ pub(super) read_timeout: Option<Duration>,
25
+ pub(super) read_timeout_fut: Option<Pin<Box<dyn Sleep>>>,
26
+ pub(super) total_timeout_fut: Option<Pin<Box<dyn Sleep>>>,
25
27
  }
26
28
  }
27
29
 
28
- impl<F, T, E> Future for ResponseFuture<F>
30
+ impl<Fut, ResBody, E> Future for ResponseFuture<Fut>
29
31
  where
30
- F: Future<Output = Result<T, E>>,
32
+ Fut: Future<Output = Result<Response<ResBody>, E>>,
31
33
  E: Into<BoxError>,
32
34
  {
33
- type Output = Result<T, BoxError>;
35
+ type Output = Result<Response<TimeoutBody<ResBody>>, BoxError>;
34
36
 
35
37
  fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
36
38
  let this = self.project();
37
39
 
38
- // First, try polling the future
39
- match this.fut.poll(cx) {
40
- Poll::Ready(v) => return Poll::Ready(v.map_err(Into::into)),
41
- Poll::Pending => {}
42
- }
43
-
44
- // Helper closure for polling a timeout and returning a TimedOut error
45
- let mut check_timeout = |sleep: Option<&mut Pin<Box<dyn Sleep>>>| {
46
- if let Some(sleep) = sleep {
47
- if sleep.as_mut().poll(cx).is_ready() {
48
- return Some(Poll::Ready(Err(Error::request(TimedOut).into())));
49
- }
50
- }
51
- None
52
- };
53
-
54
- // Check total timeout first
55
- if let Some(poll) = check_timeout(this.total_timeout.as_mut()) {
56
- return poll;
40
+ // The total timer covers response headers and body. Poll it first so an
41
+ // expired timeout wins, then move it into `TimeoutBody` below.
42
+ if let Some(timeout) = this.total_timeout_fut.as_mut()
43
+ && timeout.as_mut().poll(cx).is_ready()
44
+ {
45
+ return Poll::Ready(Err(Error::request(TimedOut).into()));
57
46
  }
58
47
 
59
- // Check read timeout
60
- if let Some(poll) = check_timeout(this.read_timeout.as_mut()) {
61
- return poll;
48
+ // Before headers arrive, the read timer limits that wait. The body starts
49
+ // and resets its own read timer after each successful frame.
50
+ if let Some(timeout) = this.read_timeout_fut.as_mut()
51
+ && timeout.as_mut().poll(cx).is_ready()
52
+ {
53
+ return Poll::Ready(Err(Error::request(TimedOut).into()));
62
54
  }
63
55
 
64
- Poll::Pending
65
- }
66
- }
56
+ // Poll the request after both timers so every pending future registers the
57
+ // current waker before `ready!` returns.
58
+ let response = ready!(this.fut.poll(cx)).map_err(Into::into)?;
67
59
 
68
- pin_project! {
69
- /// Response future for wrapping the response body in [`TimeoutBody`].
70
- pub struct ResponseBodyTimeoutFuture<Fut> {
71
- #[pin]
72
- pub(super) fut: Fut,
73
- pub(super) timer: Timer,
74
- pub(super) total_timeout: Option<Duration>,
75
- pub(super) read_timeout: Option<Duration>,
76
-
77
- }
78
- }
79
-
80
- impl<Fut, ResBody, E> Future for ResponseBodyTimeoutFuture<Fut>
81
- where
82
- Fut: Future<Output = Result<Response<ResBody>, E>>,
83
- {
84
- type Output = Result<Response<TimeoutBody<ResBody>>, E>;
85
-
86
- #[inline(always)]
87
- fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
88
- let timer = self.timer.clone();
89
- let total_timeout = self.total_timeout;
90
- let read_timeout = self.read_timeout;
91
- let res = ready!(self.project().fut.poll(cx))?
92
- .map(|body| TimeoutBody::new(timer, total_timeout, read_timeout, body));
93
- Poll::Ready(Ok(res))
60
+ // Moving the running total timer preserves the original deadline.
61
+ Poll::Ready(Ok(response.map(|body| {
62
+ TimeoutBody::new(
63
+ body,
64
+ this.timer.clone(),
65
+ *this.read_timeout,
66
+ this.total_timeout_fut.take(),
67
+ )
68
+ })))
94
69
  }
95
70
  }
@@ -12,17 +12,14 @@ use http::{Request, Response};
12
12
  use tower::{BoxError, Layer, Service};
13
13
  use wreq_proto::rt::Timer as _;
14
14
 
15
- use self::{
16
- body::TimeoutBody,
17
- future::{ResponseBodyTimeoutFuture, ResponseFuture},
18
- };
15
+ use self::{body::TimeoutBody, future::ResponseFuture};
19
16
  use crate::{config::RequestConfig, rt::Timer};
20
17
 
21
18
  /// Options for configuring timeouts.
22
19
  #[derive(Clone, Copy, Default)]
23
20
  pub struct TimeoutOptions {
24
- total_timeout: Option<Duration>,
25
21
  read_timeout: Option<Duration>,
22
+ total_timeout: Option<Duration>,
26
23
  }
27
24
 
28
25
  impl TimeoutOptions {
@@ -88,7 +85,7 @@ where
88
85
  {
89
86
  type Response = Response<TimeoutBody<ResBody>>;
90
87
  type Error = BoxError;
91
- type Future = ResponseFuture<ResponseBodyTimeoutFuture<S::Future>>;
88
+ type Future = ResponseFuture<S::Future>;
92
89
 
93
90
  #[inline(always)]
94
91
  fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
@@ -99,14 +96,11 @@ where
99
96
  fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
100
97
  let (total_timeout, read_timeout) = fetch_timeout_options(&self.timeout, req.extensions());
101
98
  ResponseFuture {
102
- fut: ResponseBodyTimeoutFuture {
103
- fut: self.inner.call(req),
104
- timer: self.timer.clone(),
105
- total_timeout,
106
- read_timeout,
107
- },
108
- total_timeout: total_timeout.map(|timeout| self.timer.sleep(timeout)),
109
- read_timeout: read_timeout.map(|timeout| self.timer.sleep(timeout)),
99
+ fut: self.inner.call(req),
100
+ timer: self.timer.clone(),
101
+ read_timeout,
102
+ read_timeout_fut: read_timeout.map(|timeout| self.timer.sleep(timeout)),
103
+ total_timeout_fut: total_timeout.map(|timeout| self.timer.sleep(timeout)),
110
104
  }
111
105
  }
112
106
  }
@@ -473,6 +473,10 @@ impl RequestBuilder {
473
473
 
474
474
  /// Send a JSON body.
475
475
  ///
476
+ /// Serializes the value as JSON and sets the resulting bytes as the request body.
477
+ ///
478
+ /// Sets `Content-Type` to `application/json` unless it is already set.
479
+ ///
476
480
  /// # Optional
477
481
  ///
478
482
  /// This requires the optional `json` feature enabled.
@@ -60,8 +60,10 @@ use crate::dns::hickory::HickoryDnsResolver;
60
60
  use crate::{
61
61
  IntoUri, Method, Proxy,
62
62
  conn::{
63
- BoxedConnectorLayer, BoxedConnectorService, Conn, Unnameable, connector::Connector,
64
- http::HttpConnect, net::SocketBindOptions,
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 = Connector::builder(config.proxies, resolver)
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
- /// - When sending a request and if the request's headers do not already contain an
792
- /// `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `gzip`.
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
- /// - When sending a request and if the request's headers do not already contain an
816
- /// `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `br`. The
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
- /// - When sending a request and if the request's headers do not already contain an
840
- /// `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to `zstd`.
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
- /// - When sending a request and if the request's headers do not already contain an
864
- /// `Accept-Encoding` **and** `Range` values, the `Accept-Encoding` header is set to
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 setting of the `Referer` header.
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
- /// Default is `None`.
1045
- ///
1046
- /// # Note
1048
+ /// The timeout covers DNS resolution, the complete TCP address race,
1049
+ /// proxy tunneling, and the TLS handshake.
1047
1050
  ///
1048
- /// This **requires** the futures be executed in a tokio runtime with
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 timeout for [RFC 6555 (Happy Eyeballs)][RFC 6555] algorithm.
1270
+ /// Set the delay between connection attempts for
1271
+ /// [RFC 8305 (Happy Eyeballs v2)][RFC 8305].
1248
1272
  ///
1249
- /// If hostname resolves to both IPv4 and IPv6 addresses and connection
1250
- /// cannot be established using preferred address family before timeout
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 6555]: https://tools.ietf.org/html/rfc6555
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<BoxedConnectorService> + Clone + Send + Sync + 'static,
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,