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,681 @@
1
+ //! SSL support via BoringSSL.
2
+
3
+ #[macro_use]
4
+ mod macros;
5
+ mod cache;
6
+ mod cert_compression;
7
+ mod ext;
8
+ mod service;
9
+
10
+ use std::{
11
+ borrow::Cow,
12
+ fmt::{self, Debug},
13
+ io,
14
+ pin::Pin,
15
+ sync::{Arc, LazyLock},
16
+ task::{Context, Poll},
17
+ };
18
+
19
+ use boring2::{
20
+ error::ErrorStack,
21
+ ex_data::Index,
22
+ ssl::{Ssl, SslConnector, SslMethod, SslOptions, SslSessionCacheMode},
23
+ };
24
+ use cache::{SessionCache, SessionKey};
25
+ use http::Uri;
26
+ use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
27
+ use tokio_boring2::SslStream;
28
+ use tower::Service;
29
+
30
+ use crate::{
31
+ Error,
32
+ client::{ConnectIdentity, ConnectRequest, Connected, Connection},
33
+ error::BoxError,
34
+ sync::Mutex,
35
+ tls::{
36
+ AlpnProtocol, AlpsProtocol, CertStore, Identity, KeyLog, TlsOptions, TlsVersion,
37
+ conn::ext::SslConnectorBuilderExt,
38
+ },
39
+ };
40
+
41
+ fn key_index() -> Result<Index<Ssl, SessionKey<ConnectIdentity>>, ErrorStack> {
42
+ static IDX: LazyLock<Result<Index<Ssl, SessionKey<ConnectIdentity>>, ErrorStack>> =
43
+ LazyLock::new(Ssl::new_ex_index);
44
+ IDX.clone()
45
+ }
46
+
47
+ /// Builds for [`HandshakeConfig`].
48
+ pub struct HandshakeConfigBuilder {
49
+ settings: HandshakeConfig,
50
+ }
51
+
52
+ /// Settings for [`TlsConnector`]
53
+ #[derive(Clone)]
54
+ pub struct HandshakeConfig {
55
+ no_ticket: bool,
56
+ enable_ech_grease: bool,
57
+ verify_hostname: bool,
58
+ tls_sni: bool,
59
+ alpn_protocols: Option<Cow<'static, [AlpnProtocol]>>,
60
+ alps_protocols: Option<Cow<'static, [AlpsProtocol]>>,
61
+ alps_use_new_codepoint: bool,
62
+ random_aes_hw_override: bool,
63
+ }
64
+
65
+ impl HandshakeConfigBuilder {
66
+ /// Skips the session ticket.
67
+ pub fn no_ticket(mut self, skip: bool) -> Self {
68
+ self.settings.no_ticket = skip;
69
+ self
70
+ }
71
+
72
+ /// Enables or disables ECH grease.
73
+ pub fn enable_ech_grease(mut self, enable: bool) -> Self {
74
+ self.settings.enable_ech_grease = enable;
75
+ self
76
+ }
77
+
78
+ /// Sets hostname verification.
79
+ pub fn verify_hostname(mut self, verify: bool) -> Self {
80
+ self.settings.verify_hostname = verify;
81
+ self
82
+ }
83
+
84
+ /// Sets TLS SNI.
85
+ pub fn tls_sni(mut self, sni: bool) -> Self {
86
+ self.settings.tls_sni = sni;
87
+ self
88
+ }
89
+
90
+ /// Sets ALPN protocols.
91
+ pub fn alpn_protocols<P>(mut self, alpn_protocols: P) -> Self
92
+ where
93
+ P: Into<Option<Cow<'static, [AlpnProtocol]>>>,
94
+ {
95
+ self.settings.alpn_protocols = alpn_protocols.into();
96
+ self
97
+ }
98
+
99
+ /// Sets ALPS protocol.
100
+ pub fn alps_protocols<P>(mut self, alps_protocols: P) -> Self
101
+ where
102
+ P: Into<Option<Cow<'static, [AlpsProtocol]>>>,
103
+ {
104
+ self.settings.alps_protocols = alps_protocols.into();
105
+ self
106
+ }
107
+
108
+ /// Sets ALPS new codepoint usage.
109
+ pub fn alps_use_new_codepoint(mut self, use_new: bool) -> Self {
110
+ self.settings.alps_use_new_codepoint = use_new;
111
+ self
112
+ }
113
+
114
+ /// Sets random AES hardware override.
115
+ pub fn random_aes_hw_override(mut self, override_: bool) -> Self {
116
+ self.settings.random_aes_hw_override = override_;
117
+ self
118
+ }
119
+
120
+ /// Builds the `HandshakeConfig`.
121
+ pub fn build(self) -> HandshakeConfig {
122
+ self.settings
123
+ }
124
+ }
125
+
126
+ impl HandshakeConfig {
127
+ /// Creates a new `HandshakeConfigBuilder`.
128
+ pub fn builder() -> HandshakeConfigBuilder {
129
+ HandshakeConfigBuilder {
130
+ settings: HandshakeConfig::default(),
131
+ }
132
+ }
133
+ }
134
+
135
+ impl Default for HandshakeConfig {
136
+ fn default() -> Self {
137
+ Self {
138
+ no_ticket: false,
139
+ enable_ech_grease: false,
140
+ verify_hostname: true,
141
+ tls_sni: true,
142
+ alpn_protocols: None,
143
+ alps_protocols: None,
144
+ alps_use_new_codepoint: false,
145
+ random_aes_hw_override: false,
146
+ }
147
+ }
148
+ }
149
+
150
+ /// A Connector using BoringSSL to support `http` and `https` schemes.
151
+ #[derive(Clone)]
152
+ pub struct HttpsConnector<T> {
153
+ http: T,
154
+ inner: Inner,
155
+ }
156
+
157
+ #[derive(Clone)]
158
+ struct Inner {
159
+ ssl: SslConnector,
160
+ cache: Option<Arc<Mutex<SessionCache<ConnectIdentity>>>>,
161
+ config: HandshakeConfig,
162
+ }
163
+
164
+ /// A builder for creating a `TlsConnector`.
165
+ #[derive(Clone)]
166
+ pub struct TlsConnectorBuilder {
167
+ session_cache: Arc<Mutex<SessionCache<ConnectIdentity>>>,
168
+ alpn_protocol: Option<AlpnProtocol>,
169
+ max_version: Option<TlsVersion>,
170
+ min_version: Option<TlsVersion>,
171
+ tls_sni: bool,
172
+ verify_hostname: bool,
173
+ identity: Option<Identity>,
174
+ cert_store: Option<CertStore>,
175
+ cert_verification: bool,
176
+ keylog: Option<KeyLog>,
177
+ }
178
+
179
+ /// A layer which wraps services in an `SslConnector`.
180
+ #[derive(Clone)]
181
+ pub struct TlsConnector {
182
+ inner: Inner,
183
+ }
184
+
185
+ // ===== impl HttpsConnector =====
186
+
187
+ impl<S, T> HttpsConnector<S>
188
+ where
189
+ S: Service<Uri, Response = T> + Send,
190
+ S::Error: Into<BoxError>,
191
+ S::Future: Unpin + Send + 'static,
192
+ T: AsyncRead + AsyncWrite + Connection + Unpin + Debug + Sync + Send + 'static,
193
+ {
194
+ /// Creates a new [`HttpsConnector`] with a given [`TlsConnector`].
195
+ #[inline]
196
+ pub fn with_connector(http: S, connector: TlsConnector) -> HttpsConnector<S> {
197
+ HttpsConnector {
198
+ http,
199
+ inner: connector.inner,
200
+ }
201
+ }
202
+
203
+ /// Disables ALPN negotiation.
204
+ #[inline]
205
+ pub fn no_alpn(&mut self) -> &mut Self {
206
+ self.inner.config.alpn_protocols = None;
207
+ self
208
+ }
209
+ }
210
+
211
+ // ===== impl Inner =====
212
+
213
+ impl Inner {
214
+ fn setup_ssl(&self, uri: Uri) -> Result<Ssl, BoxError> {
215
+ let cfg = self.ssl.configure()?;
216
+ let host = uri.host().ok_or("URI missing host")?;
217
+ let host = Self::normalize_host(host);
218
+ let ssl = cfg.into_ssl(host)?;
219
+ Ok(ssl)
220
+ }
221
+
222
+ fn setup_ssl2(&self, req: ConnectRequest) -> Result<Ssl, BoxError> {
223
+ let mut cfg = self.ssl.configure()?;
224
+
225
+ // Use server name indication
226
+ cfg.set_use_server_name_indication(self.config.tls_sni);
227
+
228
+ // Verify hostname
229
+ cfg.set_verify_hostname(self.config.verify_hostname);
230
+
231
+ // Set ECH grease
232
+ cfg.set_enable_ech_grease(self.config.enable_ech_grease);
233
+
234
+ // Set random AES hardware override
235
+ if self.config.random_aes_hw_override {
236
+ let random = (crate::util::fast_random() & 1) == 0;
237
+ cfg.set_aes_hw_override(random);
238
+ }
239
+
240
+ // Set ALPS protos
241
+ if let Some(ref alps_values) = self.config.alps_protocols {
242
+ for alps in alps_values.iter() {
243
+ cfg.add_application_settings(alps.0)?;
244
+ }
245
+
246
+ // By default, the old endpoint is used.
247
+ if !alps_values.is_empty() && self.config.alps_use_new_codepoint {
248
+ cfg.set_alps_use_new_codepoint(true);
249
+ }
250
+ }
251
+
252
+ // Set ALPN protocols
253
+ if let Some(alpn) = req.extra().alpn_protocol() {
254
+ // If ALPN is set in the request, it takes precedence over the connector configuration.
255
+ cfg.set_alpn_protos(&alpn.encode())?;
256
+ } else {
257
+ // Default use the connector configuration.
258
+ if let Some(ref alpn_values) = self.config.alpn_protocols {
259
+ let encoded = AlpnProtocol::encode_sequence(alpn_values.as_ref());
260
+ cfg.set_alpn_protos(&encoded)?;
261
+ }
262
+ }
263
+
264
+ let uri = req.uri().clone();
265
+ let host = uri.host().ok_or("URI missing host")?;
266
+ let host = Self::normalize_host(host);
267
+
268
+ if let Some(ref cache) = self.cache {
269
+ let key = SessionKey(req.identify());
270
+
271
+ // If the session cache is enabled, we try to retrieve the session
272
+ // associated with the key. If it exists, we set it in the SSL configuration.
273
+ if let Some(session) = cache.lock().get(&key) {
274
+ #[allow(unsafe_code)]
275
+ unsafe { cfg.set_session(&session) }?;
276
+
277
+ if self.config.no_ticket {
278
+ cfg.set_options(SslOptions::NO_TICKET)?;
279
+ }
280
+ }
281
+
282
+ let idx = key_index()?;
283
+ cfg.set_ex_data(idx, key);
284
+ }
285
+
286
+ let ssl = cfg.into_ssl(host)?;
287
+ Ok(ssl)
288
+ }
289
+
290
+ /// If `host` is an IPv6 address, we must strip away the square brackets that surround
291
+ /// it (otherwise, boring will fail to parse the host as an IP address, eventually
292
+ /// causing the handshake to fail due a hostname verification error).
293
+ fn normalize_host(host: &str) -> &str {
294
+ if host.is_empty() {
295
+ return host;
296
+ }
297
+
298
+ let last = host.len() - 1;
299
+ let mut chars = host.chars();
300
+
301
+ if let (Some('['), Some(']')) = (chars.next(), chars.last()) {
302
+ if host[1..last].parse::<std::net::Ipv6Addr>().is_ok() {
303
+ return &host[1..last];
304
+ }
305
+ }
306
+
307
+ host
308
+ }
309
+ }
310
+
311
+ // ====== impl TlsConnectorBuilder =====
312
+
313
+ impl TlsConnectorBuilder {
314
+ /// Sets the alpn protocol to be used.
315
+ #[inline(always)]
316
+ pub fn alpn_protocol(mut self, protocol: Option<AlpnProtocol>) -> Self {
317
+ self.alpn_protocol = protocol;
318
+ self
319
+ }
320
+
321
+ /// Sets the TLS keylog policy.
322
+ #[inline(always)]
323
+ pub fn keylog(mut self, keylog: Option<KeyLog>) -> Self {
324
+ self.keylog = keylog;
325
+ self
326
+ }
327
+
328
+ /// Sets the identity to be used for client certificate authentication.
329
+ #[inline(always)]
330
+ pub fn identity(mut self, identity: Option<Identity>) -> Self {
331
+ self.identity = identity;
332
+ self
333
+ }
334
+
335
+ /// Sets the certificate store used for TLS verification.
336
+ #[inline(always)]
337
+ pub fn cert_store<T>(mut self, cert_store: T) -> Self
338
+ where
339
+ T: Into<Option<CertStore>>,
340
+ {
341
+ self.cert_store = cert_store.into();
342
+ self
343
+ }
344
+
345
+ /// Sets the certificate verification flag.
346
+ #[inline(always)]
347
+ pub fn cert_verification(mut self, enabled: bool) -> Self {
348
+ self.cert_verification = enabled;
349
+ self
350
+ }
351
+
352
+ /// Sets the minimum TLS version to use.
353
+ #[inline(always)]
354
+ pub fn min_version<T>(mut self, version: T) -> Self
355
+ where
356
+ T: Into<Option<TlsVersion>>,
357
+ {
358
+ self.min_version = version.into();
359
+ self
360
+ }
361
+
362
+ /// Sets the maximum TLS version to use.
363
+ #[inline(always)]
364
+ pub fn max_version<T>(mut self, version: T) -> Self
365
+ where
366
+ T: Into<Option<TlsVersion>>,
367
+ {
368
+ self.max_version = version.into();
369
+ self
370
+ }
371
+
372
+ /// Sets the Server Name Indication (SNI) flag.
373
+ #[inline(always)]
374
+ pub fn tls_sni(mut self, enabled: bool) -> Self {
375
+ self.tls_sni = enabled;
376
+ self
377
+ }
378
+
379
+ /// Sets the hostname verification flag.
380
+ #[inline(always)]
381
+ pub fn verify_hostname(mut self, enabled: bool) -> Self {
382
+ self.verify_hostname = enabled;
383
+ self
384
+ }
385
+
386
+ /// Build the `TlsConnector` with the provided configuration.
387
+ pub fn build(&self, opts: &TlsOptions) -> crate::Result<TlsConnector> {
388
+ // Replace the default configuration with the provided one
389
+ let max_tls_version = opts.max_tls_version.or(self.max_version);
390
+ let min_tls_version = opts.min_tls_version.or(self.min_version);
391
+ let alpn_protocols = self
392
+ .alpn_protocol
393
+ .map(|proto| Cow::Owned(vec![proto]))
394
+ .or_else(|| opts.alpn_protocols.clone());
395
+
396
+ // Create the SslConnector with the provided options
397
+ let mut connector = SslConnector::no_default_verify_builder(SslMethod::tls_client())
398
+ .map_err(Error::tls)?
399
+ .set_cert_store(self.cert_store.as_ref())?
400
+ .set_cert_verification(self.cert_verification)?
401
+ .add_certificate_compression_algorithms(
402
+ opts.certificate_compression_algorithms.as_deref(),
403
+ )?;
404
+
405
+ // Set Identity
406
+ if let Some(ref identity) = self.identity {
407
+ identity.add_to_tls(&mut connector)?;
408
+ }
409
+
410
+ // Set minimum TLS version
411
+ set_option_inner_try!(min_tls_version, connector, set_min_proto_version);
412
+
413
+ // Set maximum TLS version
414
+ set_option_inner_try!(max_tls_version, connector, set_max_proto_version);
415
+
416
+ // Set OCSP stapling
417
+ set_bool!(opts, enable_ocsp_stapling, connector, enable_ocsp_stapling);
418
+
419
+ // Set Signed Certificate Timestamps (SCT)
420
+ set_bool!(
421
+ opts,
422
+ enable_signed_cert_timestamps,
423
+ connector,
424
+ enable_signed_cert_timestamps
425
+ );
426
+
427
+ // Set TLS Session ticket options
428
+ set_bool!(
429
+ opts,
430
+ !session_ticket,
431
+ connector,
432
+ set_options,
433
+ SslOptions::NO_TICKET
434
+ );
435
+
436
+ // Set TLS PSK DHE key exchange options
437
+ set_bool!(
438
+ opts,
439
+ !psk_dhe_ke,
440
+ connector,
441
+ set_options,
442
+ SslOptions::NO_PSK_DHE_KE
443
+ );
444
+
445
+ // Set TLS No Renegotiation options
446
+ set_bool!(
447
+ opts,
448
+ !renegotiation,
449
+ connector,
450
+ set_options,
451
+ SslOptions::NO_RENEGOTIATION
452
+ );
453
+
454
+ // Set TLS grease options
455
+ set_option!(opts, grease_enabled, connector, set_grease_enabled);
456
+
457
+ // Set TLS permute extensions options
458
+ set_option!(opts, permute_extensions, connector, set_permute_extensions);
459
+
460
+ // Set TLS curves list
461
+ set_option_ref_try!(opts, curves_list, connector, set_curves_list);
462
+
463
+ // Set TLS signature algorithms list
464
+ set_option_ref_try!(opts, sigalgs_list, connector, set_sigalgs_list);
465
+
466
+ // Set TLS prreserve TLS 1.3 cipher list order
467
+ set_option!(
468
+ opts,
469
+ preserve_tls13_cipher_list,
470
+ connector,
471
+ set_preserve_tls13_cipher_list
472
+ );
473
+
474
+ // Set TLS cipher list
475
+ set_option_ref_try!(opts, cipher_list, connector, set_cipher_list);
476
+
477
+ // Set TLS delegated credentials
478
+ set_option_ref_try!(
479
+ opts,
480
+ delegated_credentials,
481
+ connector,
482
+ set_delegated_credentials
483
+ );
484
+
485
+ // Set TLS record size limit
486
+ set_option!(opts, record_size_limit, connector, set_record_size_limit);
487
+
488
+ // Set TLS key shares limit
489
+ set_option!(opts, key_shares_limit, connector, set_key_shares_limit);
490
+
491
+ // Set TLS aes hardware override
492
+ set_option!(opts, aes_hw_override, connector, set_aes_hw_override);
493
+
494
+ // Set TLS extension permutation
495
+ if let Some(ref extension_permutation) = opts.extension_permutation {
496
+ connector
497
+ .set_extension_permutation(extension_permutation)
498
+ .map_err(Error::tls)?;
499
+ }
500
+
501
+ // Set TLS keylog handler.
502
+ if let Some(ref policy) = self.keylog {
503
+ let handle = policy.clone().handle().map_err(Error::tls)?;
504
+ connector.set_keylog_callback(move |_, line| {
505
+ handle.write(line);
506
+ });
507
+ }
508
+
509
+ // Create the handshake config with the default session cache capacity.
510
+ let config = HandshakeConfig::builder()
511
+ .no_ticket(opts.psk_skip_session_ticket)
512
+ .alpn_protocols(alpn_protocols)
513
+ .alps_protocols(opts.alps_protocols.clone())
514
+ .alps_use_new_codepoint(opts.alps_use_new_codepoint)
515
+ .enable_ech_grease(opts.enable_ech_grease)
516
+ .tls_sni(self.tls_sni)
517
+ .verify_hostname(self.verify_hostname)
518
+ .random_aes_hw_override(opts.random_aes_hw_override)
519
+ .build();
520
+
521
+ // If the session cache is disabled, we don't need to set up any callbacks.
522
+ let cache = opts.pre_shared_key.then(|| {
523
+ let cache = self.session_cache.clone();
524
+
525
+ connector.set_session_cache_mode(SslSessionCacheMode::CLIENT);
526
+ connector.set_new_session_callback({
527
+ let cache = cache.clone();
528
+ move |ssl, session| {
529
+ if let Ok(Some(key)) = key_index().map(|idx| ssl.ex_data(idx)) {
530
+ cache.lock().insert(key.clone(), session);
531
+ }
532
+ }
533
+ });
534
+
535
+ cache
536
+ });
537
+
538
+ Ok(TlsConnector {
539
+ inner: Inner {
540
+ ssl: connector.build(),
541
+ cache,
542
+ config,
543
+ },
544
+ })
545
+ }
546
+ }
547
+
548
+ // ===== impl TlsConnector =====
549
+
550
+ impl TlsConnector {
551
+ /// Creates a new `TlsConnectorBuilder` with the given configuration.
552
+ pub fn builder() -> TlsConnectorBuilder {
553
+ const DEFAULT_SESSION_CACHE_CAPACITY: usize = 8;
554
+ TlsConnectorBuilder {
555
+ session_cache: Arc::new(Mutex::new(SessionCache::with_capacity(
556
+ DEFAULT_SESSION_CACHE_CAPACITY,
557
+ ))),
558
+ alpn_protocol: None,
559
+ min_version: None,
560
+ max_version: None,
561
+ identity: None,
562
+ cert_store: None,
563
+ cert_verification: true,
564
+ tls_sni: true,
565
+ verify_hostname: true,
566
+ keylog: None,
567
+ }
568
+ }
569
+ }
570
+
571
+ /// A stream which may be wrapped with TLS.
572
+ pub enum MaybeHttpsStream<T> {
573
+ /// A raw HTTP stream.
574
+ Http(T),
575
+ /// An SSL-wrapped HTTP stream.
576
+ Https(SslStream<T>),
577
+ }
578
+
579
+ /// A connection that has been established with a TLS handshake.
580
+ pub struct EstablishedConn<IO> {
581
+ io: IO,
582
+ req: ConnectRequest,
583
+ }
584
+
585
+ // ===== impl MaybeHttpsStream =====
586
+
587
+ impl<T> MaybeHttpsStream<T> {
588
+ /// Returns a reference to the underlying stream.
589
+ #[inline]
590
+ pub fn get_ref(&self) -> &T {
591
+ match self {
592
+ MaybeHttpsStream::Http(s) => s,
593
+ MaybeHttpsStream::Https(s) => s.get_ref(),
594
+ }
595
+ }
596
+ }
597
+
598
+ impl<T> fmt::Debug for MaybeHttpsStream<T> {
599
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
600
+ match *self {
601
+ MaybeHttpsStream::Http(..) => f.pad("Http(..)"),
602
+ MaybeHttpsStream::Https(..) => f.pad("Https(..)"),
603
+ }
604
+ }
605
+ }
606
+
607
+ impl<T> Connection for MaybeHttpsStream<T>
608
+ where
609
+ T: Connection,
610
+ {
611
+ fn connected(&self) -> Connected {
612
+ match self {
613
+ MaybeHttpsStream::Http(s) => s.connected(),
614
+ MaybeHttpsStream::Https(s) => {
615
+ let mut connected = s.get_ref().connected();
616
+
617
+ if s.ssl().selected_alpn_protocol() == Some(b"h2") {
618
+ connected = connected.negotiated_h2();
619
+ }
620
+
621
+ connected
622
+ }
623
+ }
624
+ }
625
+ }
626
+
627
+ impl<T> AsyncRead for MaybeHttpsStream<T>
628
+ where
629
+ T: AsyncRead + AsyncWrite + Unpin,
630
+ {
631
+ fn poll_read(
632
+ mut self: Pin<&mut Self>,
633
+ cx: &mut Context<'_>,
634
+ buf: &mut ReadBuf<'_>,
635
+ ) -> Poll<io::Result<()>> {
636
+ match self.as_mut().get_mut() {
637
+ MaybeHttpsStream::Http(inner) => Pin::new(inner).poll_read(cx, buf),
638
+ MaybeHttpsStream::Https(inner) => Pin::new(inner).poll_read(cx, buf),
639
+ }
640
+ }
641
+ }
642
+
643
+ impl<T> AsyncWrite for MaybeHttpsStream<T>
644
+ where
645
+ T: AsyncRead + AsyncWrite + Unpin,
646
+ {
647
+ fn poll_write(
648
+ mut self: Pin<&mut Self>,
649
+ ctx: &mut Context<'_>,
650
+ buf: &[u8],
651
+ ) -> Poll<io::Result<usize>> {
652
+ match self.as_mut().get_mut() {
653
+ MaybeHttpsStream::Http(inner) => Pin::new(inner).poll_write(ctx, buf),
654
+ MaybeHttpsStream::Https(inner) => Pin::new(inner).poll_write(ctx, buf),
655
+ }
656
+ }
657
+
658
+ fn poll_flush(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
659
+ match self.as_mut().get_mut() {
660
+ MaybeHttpsStream::Http(inner) => Pin::new(inner).poll_flush(ctx),
661
+ MaybeHttpsStream::Https(inner) => Pin::new(inner).poll_flush(ctx),
662
+ }
663
+ }
664
+
665
+ fn poll_shutdown(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
666
+ match self.as_mut().get_mut() {
667
+ MaybeHttpsStream::Http(inner) => Pin::new(inner).poll_shutdown(ctx),
668
+ MaybeHttpsStream::Https(inner) => Pin::new(inner).poll_shutdown(ctx),
669
+ }
670
+ }
671
+ }
672
+
673
+ // ===== impl EstablishedConn =====
674
+
675
+ impl<IO> EstablishedConn<IO> {
676
+ /// Creates a new [`EstablishedConn`].
677
+ #[inline]
678
+ pub fn new(io: IO, req: ConnectRequest) -> EstablishedConn<IO> {
679
+ EstablishedConn { io, req }
680
+ }
681
+ }