wreq-rb 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Cargo.lock +2688 -0
- data/Cargo.toml +6 -0
- data/README.md +179 -0
- data/ext/wreq_rb/Cargo.toml +39 -0
- data/ext/wreq_rb/extconf.rb +22 -0
- data/ext/wreq_rb/src/client.rs +565 -0
- data/ext/wreq_rb/src/error.rs +25 -0
- data/ext/wreq_rb/src/lib.rs +20 -0
- data/ext/wreq_rb/src/response.rs +132 -0
- data/lib/wreq-rb/version.rb +5 -0
- data/lib/wreq-rb.rb +17 -0
- data/patches/0001-add-transfer-size-tracking.patch +292 -0
- data/vendor/wreq/Cargo.toml +306 -0
- data/vendor/wreq/LICENSE +202 -0
- data/vendor/wreq/README.md +122 -0
- data/vendor/wreq/examples/cert_store.rs +77 -0
- data/vendor/wreq/examples/connect_via_lower_priority_tokio_runtime.rs +258 -0
- data/vendor/wreq/examples/emulation.rs +118 -0
- data/vendor/wreq/examples/form.rs +14 -0
- data/vendor/wreq/examples/http1_websocket.rs +37 -0
- data/vendor/wreq/examples/http2_websocket.rs +45 -0
- data/vendor/wreq/examples/json_dynamic.rs +41 -0
- data/vendor/wreq/examples/json_typed.rs +47 -0
- data/vendor/wreq/examples/keylog.rs +16 -0
- data/vendor/wreq/examples/request_with_emulation.rs +115 -0
- data/vendor/wreq/examples/request_with_interface.rs +37 -0
- data/vendor/wreq/examples/request_with_local_address.rs +16 -0
- data/vendor/wreq/examples/request_with_proxy.rs +13 -0
- data/vendor/wreq/examples/request_with_redirect.rs +22 -0
- data/vendor/wreq/examples/request_with_version.rs +15 -0
- data/vendor/wreq/examples/tor_socks.rs +24 -0
- data/vendor/wreq/examples/unix_socket.rs +33 -0
- data/vendor/wreq/src/client/body.rs +304 -0
- data/vendor/wreq/src/client/conn/conn.rs +231 -0
- data/vendor/wreq/src/client/conn/connector.rs +549 -0
- data/vendor/wreq/src/client/conn/http.rs +1023 -0
- data/vendor/wreq/src/client/conn/proxy/socks.rs +233 -0
- data/vendor/wreq/src/client/conn/proxy/tunnel.rs +260 -0
- data/vendor/wreq/src/client/conn/proxy.rs +39 -0
- data/vendor/wreq/src/client/conn/tls_info.rs +98 -0
- data/vendor/wreq/src/client/conn/uds.rs +44 -0
- data/vendor/wreq/src/client/conn/verbose.rs +149 -0
- data/vendor/wreq/src/client/conn.rs +323 -0
- data/vendor/wreq/src/client/core/body/incoming.rs +485 -0
- data/vendor/wreq/src/client/core/body/length.rs +118 -0
- data/vendor/wreq/src/client/core/body.rs +34 -0
- data/vendor/wreq/src/client/core/common/buf.rs +149 -0
- data/vendor/wreq/src/client/core/common/rewind.rs +141 -0
- data/vendor/wreq/src/client/core/common/watch.rs +76 -0
- data/vendor/wreq/src/client/core/common.rs +3 -0
- data/vendor/wreq/src/client/core/conn/http1.rs +342 -0
- data/vendor/wreq/src/client/core/conn/http2.rs +307 -0
- data/vendor/wreq/src/client/core/conn.rs +11 -0
- data/vendor/wreq/src/client/core/dispatch.rs +299 -0
- data/vendor/wreq/src/client/core/error.rs +435 -0
- data/vendor/wreq/src/client/core/ext.rs +201 -0
- data/vendor/wreq/src/client/core/http1.rs +178 -0
- data/vendor/wreq/src/client/core/http2.rs +483 -0
- data/vendor/wreq/src/client/core/proto/h1/conn.rs +988 -0
- data/vendor/wreq/src/client/core/proto/h1/decode.rs +1170 -0
- data/vendor/wreq/src/client/core/proto/h1/dispatch.rs +684 -0
- data/vendor/wreq/src/client/core/proto/h1/encode.rs +580 -0
- data/vendor/wreq/src/client/core/proto/h1/io.rs +879 -0
- data/vendor/wreq/src/client/core/proto/h1/role.rs +694 -0
- data/vendor/wreq/src/client/core/proto/h1.rs +104 -0
- data/vendor/wreq/src/client/core/proto/h2/client.rs +650 -0
- data/vendor/wreq/src/client/core/proto/h2/ping.rs +539 -0
- data/vendor/wreq/src/client/core/proto/h2.rs +379 -0
- data/vendor/wreq/src/client/core/proto/headers.rs +138 -0
- data/vendor/wreq/src/client/core/proto.rs +58 -0
- data/vendor/wreq/src/client/core/rt/bounds.rs +57 -0
- data/vendor/wreq/src/client/core/rt/timer.rs +150 -0
- data/vendor/wreq/src/client/core/rt/tokio.rs +99 -0
- data/vendor/wreq/src/client/core/rt.rs +25 -0
- data/vendor/wreq/src/client/core/upgrade.rs +267 -0
- data/vendor/wreq/src/client/core.rs +16 -0
- data/vendor/wreq/src/client/emulation.rs +161 -0
- data/vendor/wreq/src/client/http/client/error.rs +142 -0
- data/vendor/wreq/src/client/http/client/exec.rs +29 -0
- data/vendor/wreq/src/client/http/client/extra.rs +77 -0
- data/vendor/wreq/src/client/http/client/lazy.rs +79 -0
- data/vendor/wreq/src/client/http/client/pool.rs +1105 -0
- data/vendor/wreq/src/client/http/client/util.rs +104 -0
- data/vendor/wreq/src/client/http/client.rs +1003 -0
- data/vendor/wreq/src/client/http/future.rs +99 -0
- data/vendor/wreq/src/client/http.rs +1629 -0
- data/vendor/wreq/src/client/layer/config/options.rs +156 -0
- data/vendor/wreq/src/client/layer/config.rs +116 -0
- data/vendor/wreq/src/client/layer/cookie.rs +161 -0
- data/vendor/wreq/src/client/layer/decoder.rs +139 -0
- data/vendor/wreq/src/client/layer/redirect/future.rs +270 -0
- data/vendor/wreq/src/client/layer/redirect/policy.rs +63 -0
- data/vendor/wreq/src/client/layer/redirect.rs +145 -0
- data/vendor/wreq/src/client/layer/retry/classify.rs +105 -0
- data/vendor/wreq/src/client/layer/retry/scope.rs +51 -0
- data/vendor/wreq/src/client/layer/retry.rs +151 -0
- data/vendor/wreq/src/client/layer/timeout/body.rs +233 -0
- data/vendor/wreq/src/client/layer/timeout/future.rs +90 -0
- data/vendor/wreq/src/client/layer/timeout.rs +177 -0
- data/vendor/wreq/src/client/layer.rs +15 -0
- data/vendor/wreq/src/client/multipart.rs +717 -0
- data/vendor/wreq/src/client/request.rs +818 -0
- data/vendor/wreq/src/client/response.rs +534 -0
- data/vendor/wreq/src/client/ws/json.rs +99 -0
- data/vendor/wreq/src/client/ws/message.rs +453 -0
- data/vendor/wreq/src/client/ws.rs +714 -0
- data/vendor/wreq/src/client.rs +27 -0
- data/vendor/wreq/src/config.rs +140 -0
- data/vendor/wreq/src/cookie.rs +579 -0
- data/vendor/wreq/src/dns/gai.rs +249 -0
- data/vendor/wreq/src/dns/hickory.rs +78 -0
- data/vendor/wreq/src/dns/resolve.rs +180 -0
- data/vendor/wreq/src/dns.rs +69 -0
- data/vendor/wreq/src/error.rs +502 -0
- data/vendor/wreq/src/ext.rs +398 -0
- data/vendor/wreq/src/hash.rs +143 -0
- data/vendor/wreq/src/header.rs +506 -0
- data/vendor/wreq/src/into_uri.rs +187 -0
- data/vendor/wreq/src/lib.rs +586 -0
- data/vendor/wreq/src/proxy/mac.rs +82 -0
- data/vendor/wreq/src/proxy/matcher.rs +806 -0
- data/vendor/wreq/src/proxy/uds.rs +66 -0
- data/vendor/wreq/src/proxy/win.rs +31 -0
- data/vendor/wreq/src/proxy.rs +569 -0
- data/vendor/wreq/src/redirect.rs +575 -0
- data/vendor/wreq/src/retry.rs +198 -0
- data/vendor/wreq/src/sync.rs +129 -0
- data/vendor/wreq/src/tls/conn/cache.rs +123 -0
- data/vendor/wreq/src/tls/conn/cert_compression.rs +125 -0
- data/vendor/wreq/src/tls/conn/ext.rs +82 -0
- data/vendor/wreq/src/tls/conn/macros.rs +34 -0
- data/vendor/wreq/src/tls/conn/service.rs +138 -0
- data/vendor/wreq/src/tls/conn.rs +681 -0
- data/vendor/wreq/src/tls/keylog/handle.rs +64 -0
- data/vendor/wreq/src/tls/keylog.rs +99 -0
- data/vendor/wreq/src/tls/options.rs +464 -0
- data/vendor/wreq/src/tls/x509/identity.rs +122 -0
- data/vendor/wreq/src/tls/x509/parser.rs +71 -0
- data/vendor/wreq/src/tls/x509/store.rs +228 -0
- data/vendor/wreq/src/tls/x509.rs +68 -0
- data/vendor/wreq/src/tls.rs +154 -0
- data/vendor/wreq/src/trace.rs +55 -0
- data/vendor/wreq/src/util.rs +122 -0
- data/vendor/wreq/tests/badssl.rs +228 -0
- data/vendor/wreq/tests/brotli.rs +350 -0
- data/vendor/wreq/tests/client.rs +1098 -0
- data/vendor/wreq/tests/connector_layers.rs +227 -0
- data/vendor/wreq/tests/cookie.rs +306 -0
- data/vendor/wreq/tests/deflate.rs +347 -0
- data/vendor/wreq/tests/emulation.rs +260 -0
- data/vendor/wreq/tests/gzip.rs +347 -0
- data/vendor/wreq/tests/layers.rs +261 -0
- data/vendor/wreq/tests/multipart.rs +165 -0
- data/vendor/wreq/tests/proxy.rs +438 -0
- data/vendor/wreq/tests/redirect.rs +629 -0
- data/vendor/wreq/tests/retry.rs +135 -0
- data/vendor/wreq/tests/support/delay_server.rs +117 -0
- data/vendor/wreq/tests/support/error.rs +16 -0
- data/vendor/wreq/tests/support/layer.rs +183 -0
- data/vendor/wreq/tests/support/mod.rs +9 -0
- data/vendor/wreq/tests/support/server.rs +232 -0
- data/vendor/wreq/tests/timeouts.rs +281 -0
- data/vendor/wreq/tests/unix_socket.rs +135 -0
- data/vendor/wreq/tests/upgrade.rs +98 -0
- data/vendor/wreq/tests/zstd.rs +559 -0
- metadata +225 -0
|
@@ -0,0 +1,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
|
+
}
|