Coverage Report

Created: 2026-08-14 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-rustls-0.26.4/src/client.rs
Line
Count
Source
1
use std::future::Future;
2
#[cfg(unix)]
3
use std::os::unix::io::{AsRawFd, RawFd};
4
#[cfg(windows)]
5
use std::os::windows::io::{AsRawSocket, RawSocket};
6
use std::pin::Pin;
7
#[cfg(feature = "early-data")]
8
use std::task::Waker;
9
use std::task::{Context, Poll};
10
use std::{
11
    io::{self, BufRead as _},
12
    sync::Arc,
13
};
14
15
use rustls::{pki_types::ServerName, ClientConfig, ClientConnection};
16
use tokio::io::{AsyncBufRead, AsyncRead, AsyncWrite, ReadBuf};
17
18
use crate::common::{IoSession, MidHandshake, Stream, TlsState};
19
20
/// A wrapper around a `rustls::ClientConfig`, providing an async `connect` method.
21
#[derive(Clone)]
22
pub struct TlsConnector {
23
    inner: Arc<ClientConfig>,
24
    #[cfg(feature = "early-data")]
25
    early_data: bool,
26
}
27
28
impl TlsConnector {
29
    /// Enable 0-RTT.
30
    ///
31
    /// If you want to use 0-RTT,
32
    /// You must also set `ClientConfig.enable_early_data` to `true`.
33
    #[cfg(feature = "early-data")]
34
    pub fn early_data(mut self, flag: bool) -> Self {
35
        self.early_data = flag;
36
        self
37
    }
38
39
    #[inline]
40
0
    pub fn connect<IO>(&self, domain: ServerName<'static>, stream: IO) -> Connect<IO>
41
0
    where
42
0
        IO: AsyncRead + AsyncWrite + Unpin,
43
    {
44
0
        self.connect_impl(domain, stream, None, |_| ())
45
0
    }
Unexecuted instantiation: <tokio_rustls::client::TlsConnector>::connect::<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>
Unexecuted instantiation: <tokio_rustls::client::TlsConnector>::connect::<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>>
Unexecuted instantiation: <tokio_rustls::client::TlsConnector>::connect::<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>>
Unexecuted instantiation: <tokio_rustls::client::TlsConnector>::connect::<_>
46
47
    #[inline]
48
0
    pub fn connect_with<IO, F>(&self, domain: ServerName<'static>, stream: IO, f: F) -> Connect<IO>
49
0
    where
50
0
        IO: AsyncRead + AsyncWrite + Unpin,
51
0
        F: FnOnce(&mut ClientConnection),
52
    {
53
0
        self.connect_impl(domain, stream, None, f)
54
0
    }
55
56
0
    fn connect_impl<IO, F>(
57
0
        &self,
58
0
        domain: ServerName<'static>,
59
0
        stream: IO,
60
0
        alpn_protocols: Option<Vec<Vec<u8>>>,
61
0
        f: F,
62
0
    ) -> Connect<IO>
63
0
    where
64
0
        IO: AsyncRead + AsyncWrite + Unpin,
65
0
        F: FnOnce(&mut ClientConnection),
66
    {
67
0
        let alpn = alpn_protocols.unwrap_or_else(|| self.inner.alpn_protocols.clone());
Unexecuted instantiation: <tokio_rustls::client::TlsConnector>::connect_impl::<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>, <tokio_rustls::client::TlsConnector>::connect<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>::{closure#0}>::{closure#0}
Unexecuted instantiation: <tokio_rustls::client::TlsConnector>::connect_impl::<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>, <tokio_rustls::client::TlsConnector>::connect<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>>::{closure#0}>::{closure#0}
Unexecuted instantiation: <tokio_rustls::client::TlsConnector>::connect_impl::<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>, <tokio_rustls::client::TlsConnector>::connect<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>>::{closure#0}>::{closure#0}
Unexecuted instantiation: <tokio_rustls::client::TlsConnector>::connect_impl::<_, _>::{closure#0}
68
0
        let mut session = match ClientConnection::new_with_alpn(self.inner.clone(), domain, alpn) {
69
0
            Ok(session) => session,
70
0
            Err(error) => {
71
0
                return Connect(MidHandshake::Error {
72
0
                    io: stream,
73
0
                    // TODO(eliza): should this really return an `io::Error`?
74
0
                    // Probably not...
75
0
                    error: io::Error::new(io::ErrorKind::Other, error),
76
0
                });
77
            }
78
        };
79
0
        f(&mut session);
80
81
0
        Connect(MidHandshake::Handshaking(TlsStream {
82
0
            io: stream,
83
0
84
0
            #[cfg(not(feature = "early-data"))]
85
0
            state: TlsState::Stream,
86
0
87
0
            #[cfg(feature = "early-data")]
88
0
            state: if self.early_data && session.early_data().is_some() {
89
0
                TlsState::EarlyData(0, Vec::new())
90
0
            } else {
91
0
                TlsState::Stream
92
0
            },
93
0
94
0
            need_flush: false,
95
0
96
0
            #[cfg(feature = "early-data")]
97
0
            early_waker: None,
98
0
99
0
            session,
100
0
        }))
101
0
    }
Unexecuted instantiation: <tokio_rustls::client::TlsConnector>::connect_impl::<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>, <tokio_rustls::client::TlsConnector>::connect<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>::{closure#0}>
Unexecuted instantiation: <tokio_rustls::client::TlsConnector>::connect_impl::<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>, <tokio_rustls::client::TlsConnector>::connect<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>>::{closure#0}>
Unexecuted instantiation: <tokio_rustls::client::TlsConnector>::connect_impl::<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>, <tokio_rustls::client::TlsConnector>::connect<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>>::{closure#0}>
Unexecuted instantiation: <tokio_rustls::client::TlsConnector>::connect_impl::<_, _>
102
103
0
    pub fn with_alpn(&self, alpn_protocols: Vec<Vec<u8>>) -> TlsConnectorWithAlpn<'_> {
104
0
        TlsConnectorWithAlpn {
105
0
            inner: self,
106
0
            alpn_protocols,
107
0
        }
108
0
    }
109
110
    /// Get a read-only reference to underlying config
111
0
    pub fn config(&self) -> &Arc<ClientConfig> {
112
0
        &self.inner
113
0
    }
114
}
115
116
impl From<Arc<ClientConfig>> for TlsConnector {
117
0
    fn from(inner: Arc<ClientConfig>) -> Self {
118
0
        Self {
119
0
            inner,
120
0
            #[cfg(feature = "early-data")]
121
0
            early_data: false,
122
0
        }
123
0
    }
124
}
125
126
pub struct TlsConnectorWithAlpn<'c> {
127
    inner: &'c TlsConnector,
128
    alpn_protocols: Vec<Vec<u8>>,
129
}
130
131
impl TlsConnectorWithAlpn<'_> {
132
    #[inline]
133
0
    pub fn connect<IO>(self, domain: ServerName<'static>, stream: IO) -> Connect<IO>
134
0
    where
135
0
        IO: AsyncRead + AsyncWrite + Unpin,
136
    {
137
0
        self.inner
138
0
            .connect_impl(domain, stream, Some(self.alpn_protocols), |_| ())
139
0
    }
140
141
    #[inline]
142
0
    pub fn connect_with<IO, F>(self, domain: ServerName<'static>, stream: IO, f: F) -> Connect<IO>
143
0
    where
144
0
        IO: AsyncRead + AsyncWrite + Unpin,
145
0
        F: FnOnce(&mut ClientConnection),
146
    {
147
0
        self.inner
148
0
            .connect_impl(domain, stream, Some(self.alpn_protocols), f)
149
0
    }
150
}
151
152
/// Future returned from `TlsConnector::connect` which will resolve
153
/// once the connection handshake has finished.
154
pub struct Connect<IO>(MidHandshake<TlsStream<IO>>);
155
156
impl<IO> Connect<IO> {
157
    #[inline]
158
0
    pub fn into_fallible(self) -> FallibleConnect<IO> {
159
0
        FallibleConnect(self.0)
160
0
    }
161
162
0
    pub fn get_ref(&self) -> Option<&IO> {
163
0
        match &self.0 {
164
0
            MidHandshake::Handshaking(sess) => Some(sess.get_ref().0),
165
0
            MidHandshake::SendAlert { io, .. } => Some(io),
166
0
            MidHandshake::Error { io, .. } => Some(io),
167
0
            MidHandshake::End => None,
168
        }
169
0
    }
170
171
0
    pub fn get_mut(&mut self) -> Option<&mut IO> {
172
0
        match &mut self.0 {
173
0
            MidHandshake::Handshaking(sess) => Some(sess.get_mut().0),
174
0
            MidHandshake::SendAlert { io, .. } => Some(io),
175
0
            MidHandshake::Error { io, .. } => Some(io),
176
0
            MidHandshake::End => None,
177
        }
178
0
    }
179
}
180
181
impl<IO: AsyncRead + AsyncWrite + Unpin> Future for Connect<IO> {
182
    type Output = io::Result<TlsStream<IO>>;
183
184
    #[inline]
185
0
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
186
0
        Pin::new(&mut self.0).poll(cx).map_err(|(err, _)| err)
187
0
    }
Unexecuted instantiation: <tokio_rustls::client::Connect<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>> as core::future::future::Future>::poll
Unexecuted instantiation: <tokio_rustls::client::Connect<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>> as core::future::future::Future>::poll
Unexecuted instantiation: <tokio_rustls::client::Connect<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>> as core::future::future::Future>::poll
Unexecuted instantiation: <tokio_rustls::client::Connect<_> as core::future::future::Future>::poll
188
}
189
190
impl<IO: AsyncRead + AsyncWrite + Unpin> Future for FallibleConnect<IO> {
191
    type Output = Result<TlsStream<IO>, (io::Error, IO)>;
192
193
    #[inline]
194
0
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
195
0
        Pin::new(&mut self.0).poll(cx)
196
0
    }
197
}
198
199
/// Like [Connect], but returns `IO` on failure.
200
pub struct FallibleConnect<IO>(MidHandshake<TlsStream<IO>>);
201
202
/// A wrapper around an underlying raw stream which implements the TLS or SSL
203
/// protocol.
204
#[derive(Debug)]
205
pub struct TlsStream<IO> {
206
    pub(crate) io: IO,
207
    pub(crate) session: ClientConnection,
208
    pub(crate) state: TlsState,
209
    pub(crate) need_flush: bool,
210
211
    #[cfg(feature = "early-data")]
212
    pub(crate) early_waker: Option<Waker>,
213
}
214
215
impl<IO> TlsStream<IO> {
216
    #[inline]
217
0
    pub fn get_ref(&self) -> (&IO, &ClientConnection) {
218
0
        (&self.io, &self.session)
219
0
    }
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>>::get_ref
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>>>::get_ref
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>>>::get_ref
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>>>>::get_ref
Unexecuted instantiation: <tokio_rustls::client::TlsStream<_>>::get_ref
220
221
    #[inline]
222
0
    pub fn get_mut(&mut self) -> (&mut IO, &mut ClientConnection) {
223
0
        (&mut self.io, &mut self.session)
224
0
    }
225
226
    #[inline]
227
0
    pub fn into_inner(self) -> (IO, ClientConnection) {
228
0
        (self.io, self.session)
229
0
    }
230
}
231
232
#[cfg(unix)]
233
impl<S> AsRawFd for TlsStream<S>
234
where
235
    S: AsRawFd,
236
{
237
0
    fn as_raw_fd(&self) -> RawFd {
238
0
        self.get_ref().0.as_raw_fd()
239
0
    }
240
}
241
242
#[cfg(windows)]
243
impl<S> AsRawSocket for TlsStream<S>
244
where
245
    S: AsRawSocket,
246
{
247
    fn as_raw_socket(&self) -> RawSocket {
248
        self.get_ref().0.as_raw_socket()
249
    }
250
}
251
252
impl<IO> IoSession for TlsStream<IO> {
253
    type Io = IO;
254
    type Session = ClientConnection;
255
256
    #[inline]
257
0
    fn skip_handshake(&self) -> bool {
258
0
        self.state.is_early_data()
259
0
    }
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>> as tokio_rustls::common::handshake::IoSession>::skip_handshake
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>> as tokio_rustls::common::handshake::IoSession>::skip_handshake
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>> as tokio_rustls::common::handshake::IoSession>::skip_handshake
Unexecuted instantiation: <tokio_rustls::client::TlsStream<_> as tokio_rustls::common::handshake::IoSession>::skip_handshake
260
261
    #[inline]
262
0
    fn get_mut(&mut self) -> (&mut TlsState, &mut Self::Io, &mut Self::Session, &mut bool) {
263
0
        (
264
0
            &mut self.state,
265
0
            &mut self.io,
266
0
            &mut self.session,
267
0
            &mut self.need_flush,
268
0
        )
269
0
    }
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>> as tokio_rustls::common::handshake::IoSession>::get_mut
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>> as tokio_rustls::common::handshake::IoSession>::get_mut
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>> as tokio_rustls::common::handshake::IoSession>::get_mut
Unexecuted instantiation: <tokio_rustls::client::TlsStream<_> as tokio_rustls::common::handshake::IoSession>::get_mut
270
271
    #[inline]
272
0
    fn into_io(self) -> Self::Io {
273
0
        self.io
274
0
    }
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>> as tokio_rustls::common::handshake::IoSession>::into_io
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>> as tokio_rustls::common::handshake::IoSession>::into_io
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>> as tokio_rustls::common::handshake::IoSession>::into_io
Unexecuted instantiation: <tokio_rustls::client::TlsStream<_> as tokio_rustls::common::handshake::IoSession>::into_io
275
}
276
277
#[cfg(feature = "early-data")]
278
impl<IO> TlsStream<IO>
279
where
280
    IO: AsyncRead + AsyncWrite + Unpin,
281
{
282
    fn poll_early_data(&mut self, cx: &mut Context<'_>) {
283
        // In the EarlyData state, we have not really established a Tls connection.
284
        // Before writing data through `AsyncWrite` and completing the tls handshake,
285
        // we ignore read readiness and return to pending.
286
        //
287
        // In order to avoid event loss,
288
        // we need to register a waker and wake it up after tls is connected.
289
        if self
290
            .early_waker
291
            .as_ref()
292
            .filter(|waker| cx.waker().will_wake(waker))
293
            .is_none()
294
        {
295
            self.early_waker = Some(cx.waker().clone());
296
        }
297
    }
298
}
299
300
impl<IO> AsyncRead for TlsStream<IO>
301
where
302
    IO: AsyncRead + AsyncWrite + Unpin,
303
{
304
0
    fn poll_read(
305
0
        mut self: Pin<&mut Self>,
306
0
        cx: &mut Context<'_>,
307
0
        buf: &mut ReadBuf<'_>,
308
0
    ) -> Poll<io::Result<()>> {
309
0
        let data = ready!(self.as_mut().poll_fill_buf(cx))?;
310
0
        let len = data.len().min(buf.remaining());
311
0
        buf.put_slice(&data[..len]);
312
0
        self.consume(len);
313
0
        Poll::Ready(Ok(()))
314
0
    }
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>> as tokio::io::async_read::AsyncRead>::poll_read
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>> as tokio::io::async_read::AsyncRead>::poll_read
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>> as tokio::io::async_read::AsyncRead>::poll_read
Unexecuted instantiation: <tokio_rustls::client::TlsStream<_> as tokio::io::async_read::AsyncRead>::poll_read
315
}
316
317
impl<IO> AsyncBufRead for TlsStream<IO>
318
where
319
    IO: AsyncRead + AsyncWrite + Unpin,
320
{
321
0
    fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
322
0
        match self.state {
323
            #[cfg(feature = "early-data")]
324
            TlsState::EarlyData(..) => {
325
                self.get_mut().poll_early_data(cx);
326
                Poll::Pending
327
            }
328
            TlsState::Stream | TlsState::WriteShutdown => {
329
0
                let this = self.get_mut();
330
0
                let stream =
331
0
                    Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable());
332
333
0
                match stream.poll_fill_buf(cx) {
334
0
                    Poll::Ready(Ok(buf)) => {
335
0
                        if buf.is_empty() {
336
0
                            this.state.shutdown_read();
337
0
                        }
338
339
0
                        Poll::Ready(Ok(buf))
340
                    }
341
0
                    Poll::Ready(Err(err)) if err.kind() == io::ErrorKind::ConnectionAborted => {
342
0
                        this.state.shutdown_read();
343
0
                        Poll::Ready(Err(err))
344
                    }
345
0
                    output => output,
346
                }
347
            }
348
0
            TlsState::ReadShutdown | TlsState::FullyShutdown => Poll::Ready(Ok(&[])),
349
        }
350
0
    }
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>> as tokio::io::async_buf_read::AsyncBufRead>::poll_fill_buf
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>> as tokio::io::async_buf_read::AsyncBufRead>::poll_fill_buf
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>> as tokio::io::async_buf_read::AsyncBufRead>::poll_fill_buf
Unexecuted instantiation: <tokio_rustls::client::TlsStream<_> as tokio::io::async_buf_read::AsyncBufRead>::poll_fill_buf
351
352
0
    fn consume(mut self: Pin<&mut Self>, amt: usize) {
353
0
        self.session.reader().consume(amt);
354
0
    }
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>> as tokio::io::async_buf_read::AsyncBufRead>::consume
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>> as tokio::io::async_buf_read::AsyncBufRead>::consume
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>> as tokio::io::async_buf_read::AsyncBufRead>::consume
Unexecuted instantiation: <tokio_rustls::client::TlsStream<_> as tokio::io::async_buf_read::AsyncBufRead>::consume
355
}
356
357
impl<IO> AsyncWrite for TlsStream<IO>
358
where
359
    IO: AsyncRead + AsyncWrite + Unpin,
360
{
361
    /// Note: that it does not guarantee the final data to be sent.
362
    /// To be cautious, you must manually call `flush`.
363
0
    fn poll_write(
364
0
        self: Pin<&mut Self>,
365
0
        cx: &mut Context<'_>,
366
0
        buf: &[u8],
367
0
    ) -> Poll<io::Result<usize>> {
368
0
        let this = self.get_mut();
369
0
        let mut stream = Stream::new(&mut this.io, &mut this.session)
370
0
            .set_eof(!this.state.readable())
371
0
            .set_need_flush(this.need_flush);
372
373
        #[cfg(feature = "early-data")]
374
        {
375
            let bufs = [io::IoSlice::new(buf)];
376
            let written = poll_handle_early_data(
377
                &mut this.state,
378
                &mut stream,
379
                &mut this.early_waker,
380
                cx,
381
                &bufs,
382
            )?;
383
            match written {
384
                Poll::Ready(0) => {}
385
                Poll::Ready(written) => return Poll::Ready(Ok(written)),
386
                Poll::Pending => {
387
                    this.need_flush = stream.need_flush;
388
                    return Poll::Pending;
389
                }
390
            }
391
        }
392
393
0
        stream.as_mut_pin().poll_write(cx, buf)
394
0
    }
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>> as tokio::io::async_write::AsyncWrite>::poll_write
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>> as tokio::io::async_write::AsyncWrite>::poll_write
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>> as tokio::io::async_write::AsyncWrite>::poll_write
Unexecuted instantiation: <tokio_rustls::client::TlsStream<_> as tokio::io::async_write::AsyncWrite>::poll_write
395
396
    /// Note: that it does not guarantee the final data to be sent.
397
    /// To be cautious, you must manually call `flush`.
398
0
    fn poll_write_vectored(
399
0
        self: Pin<&mut Self>,
400
0
        cx: &mut Context<'_>,
401
0
        bufs: &[io::IoSlice<'_>],
402
0
    ) -> Poll<io::Result<usize>> {
403
0
        let this = self.get_mut();
404
0
        let mut stream = Stream::new(&mut this.io, &mut this.session)
405
0
            .set_eof(!this.state.readable())
406
0
            .set_need_flush(this.need_flush);
407
408
        #[cfg(feature = "early-data")]
409
        {
410
            let written = poll_handle_early_data(
411
                &mut this.state,
412
                &mut stream,
413
                &mut this.early_waker,
414
                cx,
415
                bufs,
416
            )?;
417
            match written {
418
                Poll::Ready(0) => {}
419
                Poll::Ready(written) => return Poll::Ready(Ok(written)),
420
                Poll::Pending => {
421
                    this.need_flush = stream.need_flush;
422
                    return Poll::Pending;
423
                }
424
            }
425
        }
426
427
0
        stream.as_mut_pin().poll_write_vectored(cx, bufs)
428
0
    }
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>> as tokio::io::async_write::AsyncWrite>::poll_write_vectored
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>> as tokio::io::async_write::AsyncWrite>::poll_write_vectored
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>> as tokio::io::async_write::AsyncWrite>::poll_write_vectored
Unexecuted instantiation: <tokio_rustls::client::TlsStream<_> as tokio::io::async_write::AsyncWrite>::poll_write_vectored
429
430
    #[inline]
431
0
    fn is_write_vectored(&self) -> bool {
432
0
        true
433
0
    }
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>> as tokio::io::async_write::AsyncWrite>::is_write_vectored
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>> as tokio::io::async_write::AsyncWrite>::is_write_vectored
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>> as tokio::io::async_write::AsyncWrite>::is_write_vectored
Unexecuted instantiation: <tokio_rustls::client::TlsStream<_> as tokio::io::async_write::AsyncWrite>::is_write_vectored
434
435
0
    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
436
0
        let this = self.get_mut();
437
0
        let mut stream = Stream::new(&mut this.io, &mut this.session)
438
0
            .set_eof(!this.state.readable())
439
0
            .set_need_flush(this.need_flush);
440
441
        #[cfg(feature = "early-data")]
442
        {
443
            let written = poll_handle_early_data(
444
                &mut this.state,
445
                &mut stream,
446
                &mut this.early_waker,
447
                cx,
448
                &[],
449
            )?;
450
            if written.is_pending() {
451
                this.need_flush = stream.need_flush;
452
                return Poll::Pending;
453
            }
454
        }
455
456
0
        stream.as_mut_pin().poll_flush(cx)
457
0
    }
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>> as tokio::io::async_write::AsyncWrite>::poll_flush
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>> as tokio::io::async_write::AsyncWrite>::poll_flush
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>> as tokio::io::async_write::AsyncWrite>::poll_flush
Unexecuted instantiation: <tokio_rustls::client::TlsStream<_> as tokio::io::async_write::AsyncWrite>::poll_flush
458
459
0
    fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
460
        #[cfg(feature = "early-data")]
461
        {
462
            // complete handshake
463
            if matches!(self.state, TlsState::EarlyData(..)) {
464
                ready!(self.as_mut().poll_flush(cx))?;
465
            }
466
        }
467
468
0
        if self.state.writeable() {
469
0
            self.session.send_close_notify();
470
0
            self.state.shutdown_write();
471
0
        }
472
473
0
        let this = self.get_mut();
474
0
        let mut stream =
475
0
            Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable());
476
0
        stream.as_mut_pin().poll_shutdown(cx)
477
0
    }
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>> as tokio::io::async_write::AsyncWrite>::poll_shutdown
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_util::rt::tokio::TokioIo<tokio::net::unix::stream::UnixStream>>> as tokio::io::async_write::AsyncWrite>::poll_shutdown
Unexecuted instantiation: <tokio_rustls::client::TlsStream<hyper_util::rt::tokio::TokioIo<hyper_rustls::stream::MaybeHttpsStream<hyper_util::rt::tokio::TokioIo<tokio::net::tcp::stream::TcpStream>>>> as tokio::io::async_write::AsyncWrite>::poll_shutdown
Unexecuted instantiation: <tokio_rustls::client::TlsStream<_> as tokio::io::async_write::AsyncWrite>::poll_shutdown
478
}
479
480
#[cfg(feature = "early-data")]
481
fn poll_handle_early_data<IO>(
482
    state: &mut TlsState,
483
    stream: &mut Stream<IO, ClientConnection>,
484
    early_waker: &mut Option<Waker>,
485
    cx: &mut Context<'_>,
486
    bufs: &[io::IoSlice<'_>],
487
) -> Poll<io::Result<usize>>
488
where
489
    IO: AsyncRead + AsyncWrite + Unpin,
490
{
491
    if let TlsState::EarlyData(pos, data) = state {
492
        use std::io::Write;
493
494
        // write early data
495
        if let Some(mut early_data) = stream.session.early_data() {
496
            let mut written = 0;
497
498
            for buf in bufs {
499
                if buf.is_empty() {
500
                    continue;
501
                }
502
503
                let len = match early_data.write(buf) {
504
                    Ok(0) => break,
505
                    Ok(n) => n,
506
                    Err(err) => return Poll::Ready(Err(err)),
507
                };
508
509
                written += len;
510
                data.extend_from_slice(&buf[..len]);
511
512
                if len < buf.len() {
513
                    break;
514
                }
515
            }
516
517
            if written != 0 {
518
                return Poll::Ready(Ok(written));
519
            }
520
        }
521
522
        // complete handshake
523
        while stream.session.is_handshaking() {
524
            ready!(stream.handshake(cx))?;
525
        }
526
527
        // write early data (fallback)
528
        if !stream.session.is_early_data_accepted() {
529
            while *pos < data.len() {
530
                let len = ready!(stream.as_mut_pin().poll_write(cx, &data[*pos..]))?;
531
                *pos += len;
532
            }
533
        }
534
535
        // end
536
        *state = TlsState::Stream;
537
538
        if let Some(waker) = early_waker.take() {
539
            waker.wake();
540
        }
541
    }
542
543
    Poll::Ready(Ok(0))
544
}