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.
Files changed (167) hide show
  1. checksums.yaml +7 -0
  2. data/Cargo.lock +2688 -0
  3. data/Cargo.toml +6 -0
  4. data/README.md +179 -0
  5. data/ext/wreq_rb/Cargo.toml +39 -0
  6. data/ext/wreq_rb/extconf.rb +22 -0
  7. data/ext/wreq_rb/src/client.rs +565 -0
  8. data/ext/wreq_rb/src/error.rs +25 -0
  9. data/ext/wreq_rb/src/lib.rs +20 -0
  10. data/ext/wreq_rb/src/response.rs +132 -0
  11. data/lib/wreq-rb/version.rb +5 -0
  12. data/lib/wreq-rb.rb +17 -0
  13. data/patches/0001-add-transfer-size-tracking.patch +292 -0
  14. data/vendor/wreq/Cargo.toml +306 -0
  15. data/vendor/wreq/LICENSE +202 -0
  16. data/vendor/wreq/README.md +122 -0
  17. data/vendor/wreq/examples/cert_store.rs +77 -0
  18. data/vendor/wreq/examples/connect_via_lower_priority_tokio_runtime.rs +258 -0
  19. data/vendor/wreq/examples/emulation.rs +118 -0
  20. data/vendor/wreq/examples/form.rs +14 -0
  21. data/vendor/wreq/examples/http1_websocket.rs +37 -0
  22. data/vendor/wreq/examples/http2_websocket.rs +45 -0
  23. data/vendor/wreq/examples/json_dynamic.rs +41 -0
  24. data/vendor/wreq/examples/json_typed.rs +47 -0
  25. data/vendor/wreq/examples/keylog.rs +16 -0
  26. data/vendor/wreq/examples/request_with_emulation.rs +115 -0
  27. data/vendor/wreq/examples/request_with_interface.rs +37 -0
  28. data/vendor/wreq/examples/request_with_local_address.rs +16 -0
  29. data/vendor/wreq/examples/request_with_proxy.rs +13 -0
  30. data/vendor/wreq/examples/request_with_redirect.rs +22 -0
  31. data/vendor/wreq/examples/request_with_version.rs +15 -0
  32. data/vendor/wreq/examples/tor_socks.rs +24 -0
  33. data/vendor/wreq/examples/unix_socket.rs +33 -0
  34. data/vendor/wreq/src/client/body.rs +304 -0
  35. data/vendor/wreq/src/client/conn/conn.rs +231 -0
  36. data/vendor/wreq/src/client/conn/connector.rs +549 -0
  37. data/vendor/wreq/src/client/conn/http.rs +1023 -0
  38. data/vendor/wreq/src/client/conn/proxy/socks.rs +233 -0
  39. data/vendor/wreq/src/client/conn/proxy/tunnel.rs +260 -0
  40. data/vendor/wreq/src/client/conn/proxy.rs +39 -0
  41. data/vendor/wreq/src/client/conn/tls_info.rs +98 -0
  42. data/vendor/wreq/src/client/conn/uds.rs +44 -0
  43. data/vendor/wreq/src/client/conn/verbose.rs +149 -0
  44. data/vendor/wreq/src/client/conn.rs +323 -0
  45. data/vendor/wreq/src/client/core/body/incoming.rs +485 -0
  46. data/vendor/wreq/src/client/core/body/length.rs +118 -0
  47. data/vendor/wreq/src/client/core/body.rs +34 -0
  48. data/vendor/wreq/src/client/core/common/buf.rs +149 -0
  49. data/vendor/wreq/src/client/core/common/rewind.rs +141 -0
  50. data/vendor/wreq/src/client/core/common/watch.rs +76 -0
  51. data/vendor/wreq/src/client/core/common.rs +3 -0
  52. data/vendor/wreq/src/client/core/conn/http1.rs +342 -0
  53. data/vendor/wreq/src/client/core/conn/http2.rs +307 -0
  54. data/vendor/wreq/src/client/core/conn.rs +11 -0
  55. data/vendor/wreq/src/client/core/dispatch.rs +299 -0
  56. data/vendor/wreq/src/client/core/error.rs +435 -0
  57. data/vendor/wreq/src/client/core/ext.rs +201 -0
  58. data/vendor/wreq/src/client/core/http1.rs +178 -0
  59. data/vendor/wreq/src/client/core/http2.rs +483 -0
  60. data/vendor/wreq/src/client/core/proto/h1/conn.rs +988 -0
  61. data/vendor/wreq/src/client/core/proto/h1/decode.rs +1170 -0
  62. data/vendor/wreq/src/client/core/proto/h1/dispatch.rs +684 -0
  63. data/vendor/wreq/src/client/core/proto/h1/encode.rs +580 -0
  64. data/vendor/wreq/src/client/core/proto/h1/io.rs +879 -0
  65. data/vendor/wreq/src/client/core/proto/h1/role.rs +694 -0
  66. data/vendor/wreq/src/client/core/proto/h1.rs +104 -0
  67. data/vendor/wreq/src/client/core/proto/h2/client.rs +650 -0
  68. data/vendor/wreq/src/client/core/proto/h2/ping.rs +539 -0
  69. data/vendor/wreq/src/client/core/proto/h2.rs +379 -0
  70. data/vendor/wreq/src/client/core/proto/headers.rs +138 -0
  71. data/vendor/wreq/src/client/core/proto.rs +58 -0
  72. data/vendor/wreq/src/client/core/rt/bounds.rs +57 -0
  73. data/vendor/wreq/src/client/core/rt/timer.rs +150 -0
  74. data/vendor/wreq/src/client/core/rt/tokio.rs +99 -0
  75. data/vendor/wreq/src/client/core/rt.rs +25 -0
  76. data/vendor/wreq/src/client/core/upgrade.rs +267 -0
  77. data/vendor/wreq/src/client/core.rs +16 -0
  78. data/vendor/wreq/src/client/emulation.rs +161 -0
  79. data/vendor/wreq/src/client/http/client/error.rs +142 -0
  80. data/vendor/wreq/src/client/http/client/exec.rs +29 -0
  81. data/vendor/wreq/src/client/http/client/extra.rs +77 -0
  82. data/vendor/wreq/src/client/http/client/lazy.rs +79 -0
  83. data/vendor/wreq/src/client/http/client/pool.rs +1105 -0
  84. data/vendor/wreq/src/client/http/client/util.rs +104 -0
  85. data/vendor/wreq/src/client/http/client.rs +1003 -0
  86. data/vendor/wreq/src/client/http/future.rs +99 -0
  87. data/vendor/wreq/src/client/http.rs +1629 -0
  88. data/vendor/wreq/src/client/layer/config/options.rs +156 -0
  89. data/vendor/wreq/src/client/layer/config.rs +116 -0
  90. data/vendor/wreq/src/client/layer/cookie.rs +161 -0
  91. data/vendor/wreq/src/client/layer/decoder.rs +139 -0
  92. data/vendor/wreq/src/client/layer/redirect/future.rs +270 -0
  93. data/vendor/wreq/src/client/layer/redirect/policy.rs +63 -0
  94. data/vendor/wreq/src/client/layer/redirect.rs +145 -0
  95. data/vendor/wreq/src/client/layer/retry/classify.rs +105 -0
  96. data/vendor/wreq/src/client/layer/retry/scope.rs +51 -0
  97. data/vendor/wreq/src/client/layer/retry.rs +151 -0
  98. data/vendor/wreq/src/client/layer/timeout/body.rs +233 -0
  99. data/vendor/wreq/src/client/layer/timeout/future.rs +90 -0
  100. data/vendor/wreq/src/client/layer/timeout.rs +177 -0
  101. data/vendor/wreq/src/client/layer.rs +15 -0
  102. data/vendor/wreq/src/client/multipart.rs +717 -0
  103. data/vendor/wreq/src/client/request.rs +818 -0
  104. data/vendor/wreq/src/client/response.rs +534 -0
  105. data/vendor/wreq/src/client/ws/json.rs +99 -0
  106. data/vendor/wreq/src/client/ws/message.rs +453 -0
  107. data/vendor/wreq/src/client/ws.rs +714 -0
  108. data/vendor/wreq/src/client.rs +27 -0
  109. data/vendor/wreq/src/config.rs +140 -0
  110. data/vendor/wreq/src/cookie.rs +579 -0
  111. data/vendor/wreq/src/dns/gai.rs +249 -0
  112. data/vendor/wreq/src/dns/hickory.rs +78 -0
  113. data/vendor/wreq/src/dns/resolve.rs +180 -0
  114. data/vendor/wreq/src/dns.rs +69 -0
  115. data/vendor/wreq/src/error.rs +502 -0
  116. data/vendor/wreq/src/ext.rs +398 -0
  117. data/vendor/wreq/src/hash.rs +143 -0
  118. data/vendor/wreq/src/header.rs +506 -0
  119. data/vendor/wreq/src/into_uri.rs +187 -0
  120. data/vendor/wreq/src/lib.rs +586 -0
  121. data/vendor/wreq/src/proxy/mac.rs +82 -0
  122. data/vendor/wreq/src/proxy/matcher.rs +806 -0
  123. data/vendor/wreq/src/proxy/uds.rs +66 -0
  124. data/vendor/wreq/src/proxy/win.rs +31 -0
  125. data/vendor/wreq/src/proxy.rs +569 -0
  126. data/vendor/wreq/src/redirect.rs +575 -0
  127. data/vendor/wreq/src/retry.rs +198 -0
  128. data/vendor/wreq/src/sync.rs +129 -0
  129. data/vendor/wreq/src/tls/conn/cache.rs +123 -0
  130. data/vendor/wreq/src/tls/conn/cert_compression.rs +125 -0
  131. data/vendor/wreq/src/tls/conn/ext.rs +82 -0
  132. data/vendor/wreq/src/tls/conn/macros.rs +34 -0
  133. data/vendor/wreq/src/tls/conn/service.rs +138 -0
  134. data/vendor/wreq/src/tls/conn.rs +681 -0
  135. data/vendor/wreq/src/tls/keylog/handle.rs +64 -0
  136. data/vendor/wreq/src/tls/keylog.rs +99 -0
  137. data/vendor/wreq/src/tls/options.rs +464 -0
  138. data/vendor/wreq/src/tls/x509/identity.rs +122 -0
  139. data/vendor/wreq/src/tls/x509/parser.rs +71 -0
  140. data/vendor/wreq/src/tls/x509/store.rs +228 -0
  141. data/vendor/wreq/src/tls/x509.rs +68 -0
  142. data/vendor/wreq/src/tls.rs +154 -0
  143. data/vendor/wreq/src/trace.rs +55 -0
  144. data/vendor/wreq/src/util.rs +122 -0
  145. data/vendor/wreq/tests/badssl.rs +228 -0
  146. data/vendor/wreq/tests/brotli.rs +350 -0
  147. data/vendor/wreq/tests/client.rs +1098 -0
  148. data/vendor/wreq/tests/connector_layers.rs +227 -0
  149. data/vendor/wreq/tests/cookie.rs +306 -0
  150. data/vendor/wreq/tests/deflate.rs +347 -0
  151. data/vendor/wreq/tests/emulation.rs +260 -0
  152. data/vendor/wreq/tests/gzip.rs +347 -0
  153. data/vendor/wreq/tests/layers.rs +261 -0
  154. data/vendor/wreq/tests/multipart.rs +165 -0
  155. data/vendor/wreq/tests/proxy.rs +438 -0
  156. data/vendor/wreq/tests/redirect.rs +629 -0
  157. data/vendor/wreq/tests/retry.rs +135 -0
  158. data/vendor/wreq/tests/support/delay_server.rs +117 -0
  159. data/vendor/wreq/tests/support/error.rs +16 -0
  160. data/vendor/wreq/tests/support/layer.rs +183 -0
  161. data/vendor/wreq/tests/support/mod.rs +9 -0
  162. data/vendor/wreq/tests/support/server.rs +232 -0
  163. data/vendor/wreq/tests/timeouts.rs +281 -0
  164. data/vendor/wreq/tests/unix_socket.rs +135 -0
  165. data/vendor/wreq/tests/upgrade.rs +98 -0
  166. data/vendor/wreq/tests/zstd.rs +559 -0
  167. 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
+ }