diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index ca782f4da6..738c14d8ce 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -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(self) -> #{SmithyHttpServer}::request::connect_info::IntoMakeServiceWithConnectInfo { - #{SmithyHttpServer}::request::connect_info::IntoMakeServiceWithConnectInfo::new(self) + pub fn into_make_service_with_connect_info(self) -> #{SmithyHttpServer}::routing::IntoMakeServiceWithConnectInfo { + #{SmithyHttpServer}::routing::IntoMakeServiceWithConnectInfo::new(self) } /// Applies a [`Layer`](#{Tower}::Layer) uniformly to all routes. diff --git a/rust-runtime/aws-smithy-http-server/src/request/connect_info.rs b/rust-runtime/aws-smithy-http-server/src/request/connect_info.rs index fd66475fc9..71b744ef5b 100644 --- a/rust-runtime/aws-smithy-http-server/src/request/connect_info.rs +++ b/rust-runtime/aws-smithy-http-server/src/request/connect_info.rs @@ -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`] 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 { - inner: S, - _connect_info: PhantomData C>, -} - -impl IntoMakeServiceWithConnectInfo { - pub fn new(svc: S) -> Self { - Self { - inner: svc, - _connect_info: PhantomData, - } - } -} - -impl fmt::Debug for IntoMakeServiceWithConnectInfo -where - S: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("IntoMakeServiceWithConnectInfo") - .field("inner", &self.inner) - .finish() - } -} - -impl Clone for IntoMakeServiceWithConnectInfo -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: 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 Service for IntoMakeServiceWithConnectInfo -where - S: Clone, - C: Connected, -{ - type Response = AddExtension>; - type Error = Infallible; - type Future = ResponseFuture; - - #[inline] - fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { - 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 = - std::future::Ready>, Infallible>>; -} +use super::FromParts; /// Extractor for getting connection information produced by a `Connected`. /// /// Note this extractor requires the existence of [`Extension>`] 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(pub T); diff --git a/rust-runtime/aws-smithy-http-server/src/routing/into_make_service_with_connect_info.rs b/rust-runtime/aws-smithy-http-server/src/routing/into_make_service_with_connect_info.rs new file mode 100644 index 0000000000..3a43dc9e18 --- /dev/null +++ b/rust-runtime/aws-smithy-http-server/src/routing/into_make_service_with_connect_info.rs @@ -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`] 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 { + inner: S, + _connect_info: PhantomData C>, +} + +impl IntoMakeServiceWithConnectInfo { + pub fn new(svc: S) -> Self { + Self { + inner: svc, + _connect_info: PhantomData, + } + } +} + +impl fmt::Debug for IntoMakeServiceWithConnectInfo +where + S: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("IntoMakeServiceWithConnectInfo") + .field("inner", &self.inner) + .finish() + } +} + +impl Clone for IntoMakeServiceWithConnectInfo +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: 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 Service for IntoMakeServiceWithConnectInfo +where + S: Clone, + C: Connected, +{ + type Response = AddExtension>; + type Error = Infallible; + type Future = ResponseFuture; + + #[inline] + fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { + 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 = + std::future::Ready>, Infallible>>; +} diff --git a/rust-runtime/aws-smithy-http-server/src/routing/mod.rs b/rust-runtime/aws-smithy-http-server/src/routing/mod.rs index 3872c3a90b..d007f99fcf 100644 --- a/rust-runtime/aws-smithy-http-server/src/routing/mod.rs +++ b/rust-runtime/aws-smithy-http-server/src/routing/mod.rs @@ -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; @@ -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.