Skip to main content

aws_smithy_http_server/routing/
into_make_service_with_connect_info.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6// This code was copied and then modified from Tokio's Axum.
7
8/* Copyright (c) 2021 Tower Contributors
9 *
10 * Permission is hereby granted, free of charge, to any
11 * person obtaining a copy of this software and associated
12 * documentation files (the "Software"), to deal in the
13 * Software without restriction, including without
14 * limitation the rights to use, copy, modify, merge,
15 * publish, distribute, sublicense, and/or sell copies of
16 * the Software, and to permit persons to whom the Software
17 * is furnished to do so, subject to the following
18 * conditions:
19 *
20 * The above copyright notice and this permission notice
21 * shall be included in all copies or substantial portions
22 * of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
25 * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
26 * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
27 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
28 * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
29 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
31 * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32 * DEALINGS IN THE SOFTWARE.
33 */
34
35//! The [`IntoMakeServiceWithConnectInfo`] is a service factory which adjoins [`ConnectInfo`] to the requests.
36
37use std::{
38    convert::Infallible,
39    fmt,
40    future::ready,
41    marker::PhantomData,
42    net::SocketAddr,
43    task::{Context, Poll},
44};
45
46use tower::{Layer, Service};
47use tower_http::add_extension::{AddExtension, AddExtensionLayer};
48
49use crate::request::connect_info::ConnectInfo;
50
51/// A [`MakeService`] used to insert [`ConnectInfo<T>`] into [`Request`](http::Request)s.
52///
53/// The `T` must be derivable from the underlying IO resource using the [`Connected`] trait.
54///
55/// [`MakeService`]: tower::make::MakeService
56pub struct IntoMakeServiceWithConnectInfo<S, C> {
57    inner: S,
58    _connect_info: PhantomData<fn() -> C>,
59}
60
61impl<S, C> IntoMakeServiceWithConnectInfo<S, C> {
62    pub fn new(svc: S) -> Self {
63        Self {
64            inner: svc,
65            _connect_info: PhantomData,
66        }
67    }
68}
69
70impl<S, C> fmt::Debug for IntoMakeServiceWithConnectInfo<S, C>
71where
72    S: fmt::Debug,
73{
74    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75        f.debug_struct("IntoMakeServiceWithConnectInfo")
76            .field("inner", &self.inner)
77            .finish()
78    }
79}
80
81impl<S, C> Clone for IntoMakeServiceWithConnectInfo<S, C>
82where
83    S: Clone,
84{
85    fn clone(&self) -> Self {
86        Self {
87            inner: self.inner.clone(),
88            _connect_info: PhantomData,
89        }
90    }
91}
92
93/// Trait that connected IO resources implement and use to produce information
94/// about the connection.
95///
96/// The goal for this trait is to allow users to implement custom IO types that
97/// can still provide the same connection metadata.
98pub trait Connected<T>: Clone {
99    /// Create type holding information about the connection.
100    fn connect_info(target: T) -> Self;
101}
102
103impl Connected<SocketAddr> for SocketAddr {
104    fn connect_info(target: SocketAddr) -> Self {
105        target
106    }
107}
108
109impl<'a, L> Connected<crate::serve::IncomingStream<'a, L>> for SocketAddr
110where
111    L: crate::serve::Listener<Addr = SocketAddr>,
112{
113    fn connect_info(target: crate::serve::IncomingStream<'a, L>) -> Self {
114        *target.remote_addr()
115    }
116}
117
118impl<S, C, T> Service<T> for IntoMakeServiceWithConnectInfo<S, C>
119where
120    S: Clone,
121    C: Connected<T>,
122{
123    type Response = AddExtension<S, ConnectInfo<C>>;
124    type Error = Infallible;
125    type Future = ResponseFuture<S, C>;
126
127    #[inline]
128    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
129        Poll::Ready(Ok(()))
130    }
131
132    fn call(&mut self, target: T) -> Self::Future {
133        let connect_info = ConnectInfo(C::connect_info(target));
134        let svc = AddExtensionLayer::new(connect_info).layer(self.inner.clone());
135        ResponseFuture::new(ready(Ok(svc)))
136    }
137}
138
139opaque_future! {
140    /// Response future for [`IntoMakeServiceWithConnectInfo`].
141    pub type ResponseFuture<S, C> =
142        std::future::Ready<Result<AddExtension<S, ConnectInfo<C>>, Infallible>>;
143}