Skip to content

Commit

Permalink
Restore into_make_service_with_connect_info module (#2039)
Browse files Browse the repository at this point in the history
  • Loading branch information
hlbarber authored Nov 30, 2022
1 parent 2226fef commit b67f492
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 132 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -378,8 +378,8 @@ class ServerServiceGeneratorV2(
}
/// Converts [`$serviceName`] into a [`MakeService`](tower::make::MakeService) with [`ConnectInfo`](#{SmithyHttpServer}::request::connect_info::ConnectInfo).
pub fn into_make_service_with_connect_info<C>(self) -> #{SmithyHttpServer}::request::connect_info::IntoMakeServiceWithConnectInfo<Self, C> {
#{SmithyHttpServer}::request::connect_info::IntoMakeServiceWithConnectInfo::new(self)
pub fn into_make_service_with_connect_info<C>(self) -> #{SmithyHttpServer}::routing::IntoMakeServiceWithConnectInfo<Self, C> {
#{SmithyHttpServer}::routing::IntoMakeServiceWithConnectInfo::new(self)
}
/// Applies a [`Layer`](#{Tower}::Layer) uniformly to all routes.
Expand Down
140 changes: 11 additions & 129 deletions rust-runtime/aws-smithy-http-server/src/request/connect_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,143 +3,25 @@
* SPDX-License-Identifier: Apache-2.0
*/

// This code was copied and then modified from Tokio's Axum.

/* Copyright (c) 2021 Tower Contributors
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without
* limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/

//! Extractor for getting connection information from a client.
use std::{
convert::Infallible,
fmt,
future::ready,
marker::PhantomData,
net::SocketAddr,
task::{Context, Poll},
};
//! The [`ConnectInfo`] struct is included in [`http::Request`]s when
//! [`IntoMakeServiceWithConnectInfo`](crate::routing::IntoMakeServiceWithConnectInfo) is used. [`ConnectInfo`]'s
//! [`FromParts`] implementation allows it to be extracted from the [`http::Request`].
//!
//! The [`pokemon-service-connect-info.rs`](https://github.com/awslabs/smithy-rs/blob/main/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/bin/pokemon-service-connect-info.rs)
//! example illustrates the use of [`IntoMakeServiceWithConnectInfo`](crate::routing::IntoMakeServiceWithConnectInfo)
//! and [`ConnectInfo`] with a service builder.
use http::request::Parts;
use hyper::server::conn::AddrStream;
use tower::{Layer, Service};
use tower_http::add_extension::{AddExtension, AddExtensionLayer};

use crate::{request::FromParts, Extension};

/// A [`MakeService`] used to insert [`ConnectInfo<T>`] into [`http::Request`]s.
///
/// The `T` must be derivable from the underlying IO resource using the [`Connected`] trait.
///
/// [`MakeService`]: tower::make::MakeService
pub struct IntoMakeServiceWithConnectInfo<S, C> {
inner: S,
_connect_info: PhantomData<fn() -> C>,
}

impl<S, C> IntoMakeServiceWithConnectInfo<S, C> {
pub fn new(svc: S) -> Self {
Self {
inner: svc,
_connect_info: PhantomData,
}
}
}

impl<S, C> fmt::Debug for IntoMakeServiceWithConnectInfo<S, C>
where
S: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IntoMakeServiceWithConnectInfo")
.field("inner", &self.inner)
.finish()
}
}

impl<S, C> Clone for IntoMakeServiceWithConnectInfo<S, C>
where
S: Clone,
{
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
_connect_info: PhantomData,
}
}
}

/// Trait that connected IO resources implement and use to produce information
/// about the connection.
///
/// The goal for this trait is to allow users to implement custom IO types that
/// can still provide the same connection metadata.
pub trait Connected<T>: Clone {
/// Create type holding information about the connection.
fn connect_info(target: T) -> Self;
}

impl Connected<&AddrStream> for SocketAddr {
fn connect_info(target: &AddrStream) -> Self {
target.remote_addr()
}
}

impl<S, C, T> Service<T> for IntoMakeServiceWithConnectInfo<S, C>
where
S: Clone,
C: Connected<T>,
{
type Response = AddExtension<S, ConnectInfo<C>>;
type Error = Infallible;
type Future = ResponseFuture<S, C>;

#[inline]
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
use crate::Extension;

fn call(&mut self, target: T) -> Self::Future {
let connect_info = ConnectInfo(C::connect_info(target));
let svc = AddExtensionLayer::new(connect_info).layer(self.inner.clone());
ResponseFuture::new(ready(Ok(svc)))
}
}

opaque_future! {
/// Response future for [`IntoMakeServiceWithConnectInfo`].
pub type ResponseFuture<S, C> =
std::future::Ready<Result<AddExtension<S, ConnectInfo<C>>, Infallible>>;
}
use super::FromParts;

/// Extractor for getting connection information produced by a `Connected`.
///
/// Note this extractor requires the existence of [`Extension<ConnectInfo<T>>`] in the [`http::Extensions`]. This is
/// automatically inserted by the [`IntoMakeServiceWithConnectInfo`] middleware, which can be applied using the
/// `into_make_service_with_connect_info` method on your generated service.
/// automatically inserted by the [`IntoMakeServiceWithConnectInfo`](crate::routing::IntoMakeServiceWithConnectInfo)
/// middleware, which can be applied using the `into_make_service_with_connect_info` method on your generated service.
#[derive(Clone, Debug)]
pub struct ConnectInfo<T>(pub T);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

// This code was copied and then modified from Tokio's Axum.

/* Copyright (c) 2021 Tower Contributors
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without
* limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/

//! The [`IntoMakeServiceWithConnectInfo`] is a service factory which adjoins [`ConnectInfo`] to the requests.
use std::{
convert::Infallible,
fmt,
future::ready,
marker::PhantomData,
net::SocketAddr,
task::{Context, Poll},
};

use hyper::server::conn::AddrStream;
use tower::{Layer, Service};
use tower_http::add_extension::{AddExtension, AddExtensionLayer};

use crate::request::connect_info::ConnectInfo;

/// A [`MakeService`] used to insert [`ConnectInfo<T>`] into [`http::Request`]s.
///
/// The `T` must be derivable from the underlying IO resource using the [`Connected`] trait.
///
/// [`MakeService`]: tower::make::MakeService
pub struct IntoMakeServiceWithConnectInfo<S, C> {
inner: S,
_connect_info: PhantomData<fn() -> C>,
}

impl<S, C> IntoMakeServiceWithConnectInfo<S, C> {
pub fn new(svc: S) -> Self {
Self {
inner: svc,
_connect_info: PhantomData,
}
}
}

impl<S, C> fmt::Debug for IntoMakeServiceWithConnectInfo<S, C>
where
S: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IntoMakeServiceWithConnectInfo")
.field("inner", &self.inner)
.finish()
}
}

impl<S, C> Clone for IntoMakeServiceWithConnectInfo<S, C>
where
S: Clone,
{
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
_connect_info: PhantomData,
}
}
}

/// Trait that connected IO resources implement and use to produce information
/// about the connection.
///
/// The goal for this trait is to allow users to implement custom IO types that
/// can still provide the same connection metadata.
pub trait Connected<T>: Clone {
/// Create type holding information about the connection.
fn connect_info(target: T) -> Self;
}

impl Connected<&AddrStream> for SocketAddr {
fn connect_info(target: &AddrStream) -> Self {
target.remote_addr()
}
}

impl<S, C, T> Service<T> for IntoMakeServiceWithConnectInfo<S, C>
where
S: Clone,
C: Connected<T>,
{
type Response = AddExtension<S, ConnectInfo<C>>;
type Error = Infallible;
type Future = ResponseFuture<S, C>;

#[inline]
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}

fn call(&mut self, target: T) -> Self::Future {
let connect_info = ConnectInfo(C::connect_info(target));
let svc = AddExtensionLayer::new(connect_info).layer(self.inner.clone());
ResponseFuture::new(ready(Ok(svc)))
}
}

opaque_future! {
/// Response future for [`IntoMakeServiceWithConnectInfo`].
pub type ResponseFuture<S, C> =
std::future::Ready<Result<AddExtension<S, ConnectInfo<C>>, Infallible>>;
}
8 changes: 7 additions & 1 deletion rust-runtime/aws-smithy-http-server/src/routing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use tower_http::map_response_body::MapResponseBodyLayer;

mod future;
mod into_make_service;
mod into_make_service_with_connect_info;
#[cfg(feature = "aws-lambda")]
#[cfg_attr(docsrs, doc(cfg(feature = "aws-lambda")))]
mod lambda_handler;
Expand All @@ -43,7 +44,12 @@ pub(crate) mod tiny_map;
#[cfg(feature = "aws-lambda")]
#[cfg_attr(docsrs, doc(cfg(feature = "aws-lambda")))]
pub use self::lambda_handler::LambdaHandler;
pub use self::{future::RouterFuture, into_make_service::IntoMakeService, route::Route};
pub use self::{
future::RouterFuture,
into_make_service::IntoMakeService,
into_make_service_with_connect_info::{Connected, IntoMakeServiceWithConnectInfo},
route::Route,
};

/// The router is a [`tower::Service`] that routes incoming requests to other `Service`s
/// based on the request's URI and HTTP method or on some specific header setting the target operation.
Expand Down

0 comments on commit b67f492

Please sign in to comment.