hyper/client/connect/
mod.rs
1use std::fmt;
83
84use ::http::Extensions;
85
86cfg_feature! {
87 #![feature = "tcp"]
88
89 pub use self::http::{HttpConnector, HttpInfo};
90
91 pub mod dns;
92 mod http;
93}
94
95cfg_feature! {
96 #![any(feature = "http1", feature = "http2")]
97
98 pub use self::sealed::Connect;
99}
100
101pub trait Connection {
103 fn connected(&self) -> Connected;
105}
106
107#[derive(Debug)]
112pub struct Connected {
113 pub(super) alpn: Alpn,
114 pub(super) is_proxied: bool,
115 pub(super) extra: Option<Extra>,
116}
117
118pub(super) struct Extra(Box<dyn ExtraInner>);
119
120#[derive(Clone, Copy, Debug, PartialEq)]
121pub(super) enum Alpn {
122 H2,
123 None,
124}
125
126impl Connected {
127 pub fn new() -> Connected {
129 Connected {
130 alpn: Alpn::None,
131 is_proxied: false,
132 extra: None,
133 }
134 }
135
136 pub fn proxy(mut self, is_proxied: bool) -> Connected {
155 self.is_proxied = is_proxied;
156 self
157 }
158
159 pub fn is_proxied(&self) -> bool {
161 self.is_proxied
162 }
163
164 pub fn extra<T: Clone + Send + Sync + 'static>(mut self, extra: T) -> Connected {
166 if let Some(prev) = self.extra {
167 self.extra = Some(Extra(Box::new(ExtraChain(prev.0, extra))));
168 } else {
169 self.extra = Some(Extra(Box::new(ExtraEnvelope(extra))));
170 }
171 self
172 }
173
174 pub fn get_extras(&self, extensions: &mut Extensions) {
176 if let Some(extra) = &self.extra {
177 extra.set(extensions);
178 }
179 }
180
181 pub fn negotiated_h2(mut self) -> Connected {
183 self.alpn = Alpn::H2;
184 self
185 }
186
187 pub fn is_negotiated_h2(&self) -> bool {
189 self.alpn == Alpn::H2
190 }
191
192 #[cfg(feature = "http2")]
195 pub(super) fn clone(&self) -> Connected {
196 Connected {
197 alpn: self.alpn.clone(),
198 is_proxied: self.is_proxied,
199 extra: self.extra.clone(),
200 }
201 }
202}
203
204impl Extra {
207 pub(super) fn set(&self, res: &mut Extensions) {
208 self.0.set(res);
209 }
210}
211
212impl Clone for Extra {
213 fn clone(&self) -> Extra {
214 Extra(self.0.clone_box())
215 }
216}
217
218impl fmt::Debug for Extra {
219 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220 f.debug_struct("Extra").finish()
221 }
222}
223
224trait ExtraInner: Send + Sync {
225 fn clone_box(&self) -> Box<dyn ExtraInner>;
226 fn set(&self, res: &mut Extensions);
227}
228
229#[derive(Clone)]
233struct ExtraEnvelope<T>(T);
234
235impl<T> ExtraInner for ExtraEnvelope<T>
236where
237 T: Clone + Send + Sync + 'static,
238{
239 fn clone_box(&self) -> Box<dyn ExtraInner> {
240 Box::new(self.clone())
241 }
242
243 fn set(&self, res: &mut Extensions) {
244 res.insert(self.0.clone());
245 }
246}
247
248struct ExtraChain<T>(Box<dyn ExtraInner>, T);
249
250impl<T: Clone> Clone for ExtraChain<T> {
251 fn clone(&self) -> Self {
252 ExtraChain(self.0.clone_box(), self.1.clone())
253 }
254}
255
256impl<T> ExtraInner for ExtraChain<T>
257where
258 T: Clone + Send + Sync + 'static,
259{
260 fn clone_box(&self) -> Box<dyn ExtraInner> {
261 Box::new(self.clone())
262 }
263
264 fn set(&self, res: &mut Extensions) {
265 self.0.set(res);
266 res.insert(self.1.clone());
267 }
268}
269
270#[cfg(any(feature = "http1", feature = "http2"))]
271pub(super) mod sealed {
272 use std::error::Error as StdError;
273
274 use ::http::Uri;
275 use tokio::io::{AsyncRead, AsyncWrite};
276
277 use super::Connection;
278 use crate::common::{Future, Unpin};
279
280 pub trait Connect: Sealed + Sized {
293 #[doc(hidden)]
294 type _Svc: ConnectSvc;
295 #[doc(hidden)]
296 fn connect(self, internal_only: Internal, dst: Uri) -> <Self::_Svc as ConnectSvc>::Future;
297 }
298
299 pub trait ConnectSvc {
300 type Connection: AsyncRead + AsyncWrite + Connection + Unpin + Send + 'static;
301 type Error: Into<Box<dyn StdError + Send + Sync>>;
302 type Future: Future<Output = Result<Self::Connection, Self::Error>> + Unpin + Send + 'static;
303
304 fn connect(self, internal_only: Internal, dst: Uri) -> Self::Future;
305 }
306
307 impl<S, T> Connect for S
308 where
309 S: tower_service::Service<Uri, Response = T> + Send + 'static,
310 S::Error: Into<Box<dyn StdError + Send + Sync>>,
311 S::Future: Unpin + Send,
312 T: AsyncRead + AsyncWrite + Connection + Unpin + Send + 'static,
313 {
314 type _Svc = S;
315
316 fn connect(self, _: Internal, dst: Uri) -> crate::service::Oneshot<S, Uri> {
317 crate::service::oneshot(self, dst)
318 }
319 }
320
321 impl<S, T> ConnectSvc for S
322 where
323 S: tower_service::Service<Uri, Response = T> + Send + 'static,
324 S::Error: Into<Box<dyn StdError + Send + Sync>>,
325 S::Future: Unpin + Send,
326 T: AsyncRead + AsyncWrite + Connection + Unpin + Send + 'static,
327 {
328 type Connection = T;
329 type Error = S::Error;
330 type Future = crate::service::Oneshot<S, Uri>;
331
332 fn connect(self, _: Internal, dst: Uri) -> Self::Future {
333 crate::service::oneshot(self, dst)
334 }
335 }
336
337 impl<S, T> Sealed for S
338 where
339 S: tower_service::Service<Uri, Response = T> + Send,
340 S::Error: Into<Box<dyn StdError + Send + Sync>>,
341 S::Future: Unpin + Send,
342 T: AsyncRead + AsyncWrite + Connection + Unpin + Send + 'static,
343 {
344 }
345
346 pub trait Sealed {}
347 #[allow(missing_debug_implementations)]
348 pub struct Internal;
349}
350
351#[cfg(test)]
352mod tests {
353 use super::Connected;
354
355 #[derive(Clone, Debug, PartialEq)]
356 struct Ex1(usize);
357
358 #[derive(Clone, Debug, PartialEq)]
359 struct Ex2(&'static str);
360
361 #[derive(Clone, Debug, PartialEq)]
362 struct Ex3(&'static str);
363
364 #[test]
365 fn test_connected_extra() {
366 let c1 = Connected::new().extra(Ex1(41));
367
368 let mut ex = ::http::Extensions::new();
369
370 assert_eq!(ex.get::<Ex1>(), None);
371
372 c1.extra.as_ref().expect("c1 extra").set(&mut ex);
373
374 assert_eq!(ex.get::<Ex1>(), Some(&Ex1(41)));
375 }
376
377 #[test]
378 fn test_connected_extra_chain() {
379 let c1 = Connected::new()
383 .extra(Ex1(45))
384 .extra(Ex2("zoom"))
385 .extra(Ex3("pew pew"));
386
387 let mut ex1 = ::http::Extensions::new();
388
389 assert_eq!(ex1.get::<Ex1>(), None);
390 assert_eq!(ex1.get::<Ex2>(), None);
391 assert_eq!(ex1.get::<Ex3>(), None);
392
393 c1.extra.as_ref().expect("c1 extra").set(&mut ex1);
394
395 assert_eq!(ex1.get::<Ex1>(), Some(&Ex1(45)));
396 assert_eq!(ex1.get::<Ex2>(), Some(&Ex2("zoom")));
397 assert_eq!(ex1.get::<Ex3>(), Some(&Ex3("pew pew")));
398
399 let c2 = Connected::new()
401 .extra(Ex1(33))
402 .extra(Ex2("hiccup"))
403 .extra(Ex1(99));
404
405 let mut ex2 = ::http::Extensions::new();
406
407 c2.extra.as_ref().expect("c2 extra").set(&mut ex2);
408
409 assert_eq!(ex2.get::<Ex1>(), Some(&Ex1(99)));
410 assert_eq!(ex2.get::<Ex2>(), Some(&Ex2("hiccup")));
411 }
412}