Unverified Commit 86fd8f59 authored by Harry Barber's avatar Harry Barber Committed by GitHub
Browse files

Collect extractors into `request` module (#2008)

parent 07967dad
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -355,9 +355,9 @@ class ServerServiceGeneratorV2(
                    #{SmithyHttpServer}::routing::IntoMakeService::new(self)
                }

                /// Converts [`$serviceName`] into a [`MakeService`](tower::make::MakeService) with [`ConnectInfo`](#{SmithyHttpServer}::routing::into_make_service_with_connect_info::ConnectInfo).
                pub fn into_make_service_with_connect_info<C>(self) -> #{SmithyHttpServer}::routing::IntoMakeServiceWithConnectInfo<Self, C> {
                    #{SmithyHttpServer}::routing::IntoMakeServiceWithConnectInfo::new(self)
                /// 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)
                }

                /// Applies a [`Layer`](#{Tower}::Layer) uniformly to all routes.
+17 −10
Original line number Diff line number Diff line
@@ -3,10 +3,19 @@
 * SPDX-License-Identifier: Apache-2.0
 */

use std::net::{IpAddr, SocketAddr};

use aws_smithy_http_server::request::connect_info::ConnectInfo;
use clap::Parser;
use pokemon_service::{
    capture_pokemon, check_health, do_nothing, get_pokemon_species, get_server_statistics, setup_tracing,
};
use pokemon_service_server_sdk::{
    error::{GetStorageError, NotAuthorized},
    input::GetStorageInput,
    output::GetStorageOutput,
    PokemonService,
};

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
@@ -21,20 +30,20 @@ struct Args {

/// Retrieves the user's storage. No authentication required for locals.
pub async fn get_storage_with_local_approved(
    input: pokemon_service_server_sdk::input::GetStorageInput,
    connect_info: aws_smithy_http_server::Extension<aws_smithy_http_server::routing::ConnectInfo<std::net::SocketAddr>>,
) -> Result<pokemon_service_server_sdk::output::GetStorageOutput, pokemon_service_server_sdk::error::GetStorageError> {
    input: GetStorageInput,
    connect_info: ConnectInfo<SocketAddr>,
) -> Result<GetStorageOutput, GetStorageError> {
    tracing::debug!("attempting to authenticate storage user");
    let local = connect_info.0 .0.ip() == "127.0.0.1".parse::<std::net::IpAddr>().unwrap();
    let local = connect_info.0.ip() == "127.0.0.1".parse::<IpAddr>().unwrap();

    // We currently support Ash: he has nothing stored
    if input.user == "ash" && input.passcode == "pikachu123" {
        return Ok(pokemon_service_server_sdk::output::GetStorageOutput { collection: vec![] });
        return Ok(GetStorageOutput { collection: vec![] });
    }
    // We support trainers in our gym
    if local {
        tracing::info!("welcome back");
        return Ok(pokemon_service_server_sdk::output::GetStorageOutput {
        return Ok(GetStorageOutput {
            collection: vec![
                String::from("bulbasaur"),
                String::from("charmander"),
@@ -43,16 +52,14 @@ pub async fn get_storage_with_local_approved(
        });
    }
    tracing::debug!("authentication failed");
    Err(pokemon_service_server_sdk::error::GetStorageError::NotAuthorized(
        pokemon_service_server_sdk::error::NotAuthorized {},
    ))
    Err(GetStorageError::NotAuthorized(NotAuthorized {}))
}

#[tokio::main]
async fn main() {
    let args = Args::parse();
    setup_tracing();
    let app = pokemon_service_server_sdk::service::PokemonService::builder_without_plugins()
    let app = PokemonService::builder_without_plugins()
        .get_pokemon_species(get_pokemon_species)
        .get_storage(get_storage_with_local_approved)
        .get_server_statistics(get_server_statistics)
+4 −78
Original line number Diff line number Diff line
@@ -3,35 +3,6 @@
 * 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.
 */

//! Extension types.
//!
//! Extension types are types that are stored in and extracted from _both_ requests and
@@ -50,14 +21,12 @@

use std::ops::Deref;

use http::StatusCode;
use thiserror::Error;

use crate::{
    body::{empty, BoxBody},
    request::{FromParts, RequestParts},
    response::IntoResponse,
};
use crate::request::RequestParts;

pub use crate::request::extension::Extension;
pub use crate::request::extension::MissingExtension;

/// Extension type used to store information about Smithy operations in HTTP responses.
/// This extension type is set when it has been correctly determined that the request should be
@@ -151,49 +120,6 @@ impl Deref for RuntimeErrorExtension {
    }
}

/// Generic extension type stored in and extracted from [request extensions].
///
/// This is commonly used to share state across handlers.
///
/// If the extension is missing it will reject the request with a `500 Internal
/// Server Error` response.
///
/// [request extensions]: https://docs.rs/http/latest/http/struct.Extensions.html
#[derive(Debug, Clone)]
pub struct Extension<T>(pub T);

impl<T> Deref for Extension<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

/// The extension has not been added to the [`Request`](http::Request) or has been previously removed.
#[derive(Debug, Error)]
#[error("the `Extension` is not present in the `http::Request`")]
pub struct MissingExtension;

impl<Protocol> IntoResponse<Protocol> for MissingExtension {
    fn into_response(self) -> http::Response<BoxBody> {
        let mut response = http::Response::new(empty());
        *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
        response
    }
}

impl<Protocol, T> FromParts<Protocol> for Extension<T>
where
    T: Send + Sync + 'static,
{
    type Rejection = MissingExtension;

    fn from_parts(parts: &mut http::request::Parts) -> Result<Self, Self::Rejection> {
        parts.extensions.remove::<T>().map(Extension).ok_or(MissingExtension)
    }
}

/// Extract an [`Extension`] from a request.
/// This is essentially the implementation of `FromRequest` for `Extension`, but with a
/// protocol-agnostic rejection type. The actual code-generated implementation simply delegates to
+1 −1
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ pub mod routers;

#[doc(inline)]
pub(crate) use self::error::Error;
pub use self::extension::Extension;
pub use self::request::extension::Extension;
#[doc(inline)]
pub use self::routing::Router;
#[doc(inline)]
+7 −14
Original line number Diff line number Diff line
@@ -32,6 +32,8 @@
 * DEALINGS IN THE SOFTWARE.
 */

//! Extractor for getting connection information from a client.

use std::{
    convert::Infallible,
    fmt,
@@ -48,12 +50,11 @@ use tower_http::add_extension::{AddExtension, AddExtensionLayer};

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

/// A [`MakeService`] created from a router.
/// A [`MakeService`] used to insert [`ConnectInfo<T>`] into [`http::Request`]s.
///
/// See [`Router::into_make_service_with_connect_info`] for more details.
/// The `T` must be derivable from the underlying IO resource using the [`Connected`] trait.
///
/// [`MakeService`]: tower::make::MakeService
/// [`Router::into_make_service_with_connect_info`]: crate::routing::Router::into_make_service_with_connect_info
pub struct IntoMakeServiceWithConnectInfo<S, C> {
    inner: S,
    _connect_info: PhantomData<fn() -> C>,
@@ -96,10 +97,6 @@ where
///
/// The goal for this trait is to allow users to implement custom IO types that
/// can still provide the same connection metadata.
///
/// See [`Router::into_make_service_with_connect_info`] for more details.
///
/// [`Router::into_make_service_with_connect_info`]: crate::routing::Router::into_make_service_with_connect_info
pub trait Connected<T>: Clone {
    /// Create type holding information about the connection.
    fn connect_info(target: T) -> Self;
@@ -140,13 +137,9 @@ opaque_future! {

/// Extractor for getting connection information produced by a `Connected`.
///
/// Note this extractor requires you to use
/// [`Router::into_make_service_with_connect_info`] to run your app
/// otherwise it will fail at runtime.
///
/// See [`Router::into_make_service_with_connect_info`] for more details.
///
/// [`Router::into_make_service_with_connect_info`]: crate::routing::Router::into_make_service_with_connect_info
/// 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.
#[derive(Clone, Debug)]
pub struct ConnectInfo<T>(pub T);

Loading