aws_smithy_http_server/request/extension.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//! Extension types.
36//!
37//! Extension types are types that are stored in and extracted from _both_ requests and
38//! responses.
39//!
40//! There is only one _generic_ extension type _for requests_, [`Extension`].
41//!
42//! On the other hand, the server SDK uses multiple concrete extension types for responses in order
43//! to store a variety of information, like the operation that was executed, the operation error
44//! that got returned, or the runtime error that happened, among others. The information stored in
45//! these types may be useful to [`tower::Layer`]s that post-process the response: for instance, a
46//! particular metrics layer implementation might want to emit metrics about the number of times an
47//! an operation got executed.
48//!
49//! [extensions]: https://docs.rs/http/latest/http/struct.Extensions.html
50
51use std::ops::Deref;
52
53use thiserror::Error;
54
55use crate::{body::BoxBody, request::FromParts, response::IntoResponse};
56
57use super::internal_server_error;
58
59/// Generic extension type stored in and extracted from [request extensions].
60///
61/// This is commonly used to share state across handlers.
62///
63/// If the extension is missing it will reject the request with a `500 Internal
64/// Server Error` response.
65///
66/// [request extensions]: https://docs.rs/http/latest/http/struct.Extensions.html
67#[derive(Debug, Clone)]
68pub struct Extension<T>(pub T);
69
70impl<T> Deref for Extension<T> {
71 type Target = T;
72
73 fn deref(&self) -> &Self::Target {
74 &self.0
75 }
76}
77
78/// The extension has not been added to the [`Request`](http::Request) or has been previously removed.
79#[non_exhaustive]
80#[derive(Debug, Error)]
81#[error("the `Extension` is not present in the `http::Request`")]
82pub struct MissingExtension;
83
84impl<Protocol> IntoResponse<Protocol> for MissingExtension {
85 fn into_response(self) -> http::Response<BoxBody> {
86 internal_server_error()
87 }
88}
89
90impl<Protocol, T> FromParts<Protocol> for Extension<T>
91where
92 T: Send + Sync + 'static,
93{
94 type Rejection = MissingExtension;
95
96 fn from_parts(parts: &mut http::request::Parts) -> Result<Self, Self::Rejection> {
97 parts.extensions.remove::<T>().map(Extension).ok_or(MissingExtension)
98 }
99}