hyper_client_sockets/
connector.rs

1use std::{
2    pin::Pin,
3    task::{Context, Poll},
4};
5
6use hyper_util::client::legacy::connect::{Connected, Connection};
7
8/// This is an internal wrapper over an IO type that implements [hyper::rt::Write] and
9/// [hyper::rt::Read] that also implements [Connection] to achieve compatibility with hyper-util.
10pub struct ConnectableIo<IO>(IO);
11
12impl<IO: hyper::rt::Write + hyper::rt::Read + Send + Unpin> hyper::rt::Write for ConnectableIo<IO> {
13    #[inline(always)]
14    fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize, std::io::Error>> {
15        Pin::new(&mut self.get_mut().0).poll_write(cx, buf)
16    }
17
18    #[inline(always)]
19    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>> {
20        Pin::new(&mut self.get_mut().0).poll_flush(cx)
21    }
22
23    #[inline(always)]
24    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>> {
25        Pin::new(&mut self.get_mut().0).poll_shutdown(cx)
26    }
27}
28
29impl<IO: hyper::rt::Write + hyper::rt::Read + Send + Unpin> hyper::rt::Read for ConnectableIo<IO> {
30    #[inline(always)]
31    fn poll_read(
32        self: Pin<&mut Self>,
33        cx: &mut Context<'_>,
34        buf: hyper::rt::ReadBufCursor<'_>,
35    ) -> Poll<Result<(), std::io::Error>> {
36        Pin::new(&mut self.get_mut().0).poll_read(cx, buf)
37    }
38}
39
40impl<IO: hyper::rt::Write + hyper::rt::Read + Send + Unpin> Connection for ConnectableIo<IO> {
41    fn connected(&self) -> Connected {
42        Connected::new()
43    }
44}
45
46#[cfg(feature = "unix")]
47#[cfg_attr(docsrs, doc(cfg(feature = "unix")))]
48mod unix {
49    use std::{future::Future, marker::PhantomData, pin::Pin, task::Poll};
50
51    use http::Uri;
52
53    use crate::{uri::UnixUri, Backend};
54
55    use super::ConnectableIo;
56
57    /// A hyper-util connector that accepts hex-encoded Unix URIs and uses them to connect
58    /// to Unix sockets via the given [Backend].
59    #[derive(Debug, Clone)]
60    pub struct UnixConnector<B: Backend> {
61        marker: PhantomData<B>,
62    }
63
64    impl<B: Backend> UnixConnector<B> {
65        pub fn new() -> Self {
66            Self { marker: PhantomData }
67        }
68    }
69
70    impl<B: Backend> tower_service::Service<Uri> for UnixConnector<B> {
71        type Response = ConnectableIo<B::UnixIo>;
72
73        type Error = std::io::Error;
74
75        type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + 'static>>;
76
77        #[inline(always)]
78        fn poll_ready(&mut self, _cx: &mut std::task::Context<'_>) -> Poll<Result<(), Self::Error>> {
79            Poll::Ready(Ok(()))
80        }
81
82        #[inline(always)]
83        fn call(&mut self, uri: Uri) -> Self::Future {
84            Box::pin(async move {
85                let socket_path = uri.parse_unix()?;
86                let io = B::connect_to_unix_socket(&socket_path).await?;
87                Ok(ConnectableIo(io))
88            })
89        }
90    }
91}
92
93#[cfg(feature = "unix")]
94#[cfg_attr(docsrs, doc(cfg(feature = "unix")))]
95pub use unix::UnixConnector;
96
97#[cfg(feature = "vsock")]
98#[cfg_attr(docsrs, doc(cfg(feature = "vsock")))]
99mod vsock {
100    use std::{future::Future, marker::PhantomData, pin::Pin, task::Poll};
101
102    use http::Uri;
103
104    use crate::{uri::VsockUri, Backend};
105
106    use super::ConnectableIo;
107
108    /// A hyper-util connector that accepts hex-encoded virtio-vsock URIs and uses them to connect
109    /// to virtio-vsock sockets via the given [Backend].
110    #[derive(Debug, Clone)]
111    pub struct VsockConnector<B: Backend> {
112        marker: PhantomData<B>,
113    }
114
115    impl<B: Backend> VsockConnector<B> {
116        pub fn new() -> Self {
117            Self { marker: PhantomData }
118        }
119    }
120
121    impl<B: Backend> tower_service::Service<Uri> for VsockConnector<B> {
122        type Response = ConnectableIo<B::VsockIo>;
123
124        type Error = std::io::Error;
125
126        type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + 'static>>;
127
128        #[inline(always)]
129        fn poll_ready(&mut self, _cx: &mut std::task::Context<'_>) -> Poll<Result<(), Self::Error>> {
130            Poll::Ready(Ok(()))
131        }
132
133        #[inline(always)]
134        fn call(&mut self, uri: Uri) -> Self::Future {
135            Box::pin(async move {
136                let addr = uri.parse_vsock()?;
137                let io = B::connect_to_vsock_socket(addr).await?;
138                Ok(ConnectableIo(io))
139            })
140        }
141    }
142}
143
144#[cfg(feature = "vsock")]
145#[cfg_attr(docsrs, doc(cfg(feature = "vsock")))]
146pub use vsock::VsockConnector;
147
148#[cfg(feature = "firecracker")]
149#[cfg_attr(docsrs, doc(cfg(feature = "firecracker")))]
150mod firecracker {
151    use std::{future::Future, marker::PhantomData, pin::Pin, task::Poll};
152
153    use http::Uri;
154
155    use crate::{uri::FirecrackerUri, Backend};
156
157    use super::ConnectableIo;
158
159    /// A hyper-util connector that accepts hex-encoded Firecracker URIs and uses them to connect
160    /// to Firecracker sockets via the given [Backend].
161    #[derive(Debug, Clone)]
162    pub struct FirecrackerConnector<B: Backend> {
163        marker: PhantomData<B>,
164    }
165
166    impl<B: Backend> FirecrackerConnector<B> {
167        pub fn new() -> Self {
168            Self { marker: PhantomData }
169        }
170    }
171
172    impl<B: Backend> tower_service::Service<Uri> for FirecrackerConnector<B> {
173        type Response = ConnectableIo<B::FirecrackerIo>;
174
175        type Error = std::io::Error;
176
177        type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + 'static>>;
178
179        #[inline(always)]
180        fn poll_ready(&mut self, _cx: &mut std::task::Context<'_>) -> Poll<Result<(), Self::Error>> {
181            Poll::Ready(Ok(()))
182        }
183
184        #[inline(always)]
185        fn call(&mut self, uri: Uri) -> Self::Future {
186            Box::pin(async move {
187                let (host_socket_path, guest_port) = uri.parse_firecracker()?;
188                let io = B::connect_to_firecracker_socket(&host_socket_path, guest_port).await?;
189                Ok(ConnectableIo(io))
190            })
191        }
192    }
193}
194
195#[cfg(feature = "firecracker")]
196#[cfg_attr(docsrs, doc(cfg(feature = "firecracker")))]
197pub use firecracker::FirecrackerConnector;