Coverage Report

Created: 2026-06-30 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/axum-0.8.9/src/extension.rs
Line
Count
Source
1
use crate::{extract::rejection::*, response::IntoResponseParts};
2
use axum_core::extract::OptionalFromRequestParts;
3
use axum_core::{
4
    extract::FromRequestParts,
5
    response::{IntoResponse, Response, ResponseParts},
6
};
7
use http::{request::Parts, Extensions, Request};
8
use std::{
9
    convert::Infallible,
10
    task::{Context, Poll},
11
};
12
use tower_service::Service;
13
14
/// Extractor and response for extensions.
15
///
16
/// # As extractor
17
///
18
/// This is commonly used to share state across handlers.
19
///
20
/// ```rust,no_run
21
/// use axum::{
22
///     Router,
23
///     Extension,
24
///     routing::get,
25
/// };
26
/// use std::sync::Arc;
27
///
28
/// // Some shared state used throughout our application
29
/// struct State {
30
///     // ...
31
/// }
32
///
33
/// async fn handler(state: Extension<Arc<State>>) {
34
///     // ...
35
/// }
36
///
37
/// let state = Arc::new(State { /* ... */ });
38
///
39
/// let app = Router::new().route("/", get(handler))
40
///     // Add middleware that inserts the state into all incoming request's
41
///     // extensions.
42
///     .layer(Extension(state));
43
/// # let _: Router = app;
44
/// ```
45
///
46
/// If the extension is missing it will reject the request with a `500 Internal
47
/// Server Error` response. Alternatively, you can use `Option<Extension<T>>` to
48
/// make the extension extractor optional.
49
///
50
/// # As response
51
///
52
/// Response extensions can be used to share state with middleware.
53
///
54
/// ```rust
55
/// use axum::{
56
///     Extension,
57
///     response::IntoResponse,
58
/// };
59
///
60
/// async fn handler() -> (Extension<Foo>, &'static str) {
61
///     (
62
///         Extension(Foo("foo")),
63
///         "Hello, World!"
64
///     )
65
/// }
66
///
67
/// #[derive(Clone)]
68
/// struct Foo(&'static str);
69
/// ```
70
#[derive(Debug, Clone, Copy, Default)]
71
#[must_use]
72
pub struct Extension<T>(pub T);
73
74
impl<T> Extension<T>
75
where
76
    T: Clone + Send + Sync + 'static,
77
{
78
0
    fn from_extensions(extensions: &Extensions) -> Option<Self> {
79
0
        extensions.get::<T>().cloned().map(Extension)
80
0
    }
81
}
82
83
impl<T, S> FromRequestParts<S> for Extension<T>
84
where
85
    T: Clone + Send + Sync + 'static,
86
    S: Send + Sync,
87
{
88
    type Rejection = ExtensionRejection;
89
90
0
    async fn from_request_parts(req: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
91
0
        Ok(Self::from_extensions(&req.extensions).ok_or_else(|| {
92
0
            MissingExtension::from_err(format!(
93
                "Extension of type `{}` was not found. Perhaps you forgot to add it? See `axum::Extension`.",
94
0
                std::any::type_name::<T>()
95
            ))
96
0
        })?)
97
0
    }
98
}
99
100
impl<T, S> OptionalFromRequestParts<S> for Extension<T>
101
where
102
    T: Clone + Send + Sync + 'static,
103
    S: Send + Sync,
104
{
105
    type Rejection = Infallible;
106
107
0
    async fn from_request_parts(
108
0
        req: &mut Parts,
109
0
        _state: &S,
110
0
    ) -> Result<Option<Self>, Self::Rejection> {
111
0
        Ok(Self::from_extensions(&req.extensions))
112
0
    }
113
}
114
115
axum_core::__impl_deref!(Extension);
116
117
impl<T> IntoResponseParts for Extension<T>
118
where
119
    T: Clone + Send + Sync + 'static,
120
{
121
    type Error = Infallible;
122
123
0
    fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
124
0
        res.extensions_mut().insert(self.0);
125
0
        Ok(res)
126
0
    }
127
}
128
129
impl<T> IntoResponse for Extension<T>
130
where
131
    T: Clone + Send + Sync + 'static,
132
{
133
0
    fn into_response(self) -> Response {
134
0
        let mut res = ().into_response();
135
0
        res.extensions_mut().insert(self.0);
136
0
        res
137
0
    }
138
}
139
140
impl<S, T> tower_layer::Layer<S> for Extension<T>
141
where
142
    T: Clone + Send + Sync + 'static,
143
{
144
    type Service = AddExtension<S, T>;
145
146
0
    fn layer(&self, inner: S) -> Self::Service {
147
0
        AddExtension {
148
0
            inner,
149
0
            value: self.0.clone(),
150
0
        }
151
0
    }
152
}
153
154
/// Middleware for adding some shareable value to [request extensions].
155
///
156
/// See [Passing state from middleware to handlers](index.html#passing-state-from-middleware-to-handlers)
157
/// for more details.
158
///
159
/// [request extensions]: https://docs.rs/http/latest/http/struct.Extensions.html
160
///
161
/// If you need a layer to add an extension to every request,
162
/// use the [Layer](tower::Layer) implementation of [Extension].
163
#[derive(Clone, Copy, Debug)]
164
pub struct AddExtension<S, T> {
165
    pub(crate) inner: S,
166
    pub(crate) value: T,
167
}
168
169
impl<ResBody, S, T> Service<Request<ResBody>> for AddExtension<S, T>
170
where
171
    S: Service<Request<ResBody>>,
172
    T: Clone + Send + Sync + 'static,
173
{
174
    type Response = S::Response;
175
    type Error = S::Error;
176
    type Future = S::Future;
177
178
    #[inline]
179
0
    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
180
0
        self.inner.poll_ready(cx)
181
0
    }
182
183
0
    fn call(&mut self, mut req: Request<ResBody>) -> Self::Future {
184
0
        req.extensions_mut().insert(self.value.clone());
185
0
        self.inner.call(req)
186
0
    }
187
}
188
189
#[cfg(test)]
190
mod tests {
191
    use super::*;
192
    use crate::routing::get;
193
    use crate::test_helpers::TestClient;
194
    use crate::Router;
195
    use http::StatusCode;
196
197
    #[derive(Clone)]
198
    struct Foo(String);
199
200
    #[derive(Clone)]
201
    struct Bar(String);
202
203
    #[crate::test]
204
    async fn extension_extractor() {
205
        async fn requires_foo(Extension(foo): Extension<Foo>) -> String {
206
            foo.0
207
        }
208
209
        async fn optional_foo(extension: Option<Extension<Foo>>) -> String {
210
            extension.map(|foo| foo.0 .0).unwrap_or("none".to_owned())
211
        }
212
213
        async fn requires_bar(Extension(bar): Extension<Bar>) -> String {
214
            bar.0
215
        }
216
217
        async fn optional_bar(extension: Option<Extension<Bar>>) -> String {
218
            extension.map(|bar| bar.0 .0).unwrap_or("none".to_owned())
219
        }
220
221
        let app = Router::new()
222
            .route("/requires_foo", get(requires_foo))
223
            .route("/optional_foo", get(optional_foo))
224
            .route("/requires_bar", get(requires_bar))
225
            .route("/optional_bar", get(optional_bar))
226
            .layer(Extension(Foo("foo".to_owned())));
227
228
        let client = TestClient::new(app);
229
230
        let response = client.get("/requires_foo").await;
231
        assert_eq!(response.status(), StatusCode::OK);
232
        assert_eq!(response.text().await, "foo");
233
234
        let response = client.get("/optional_foo").await;
235
        assert_eq!(response.status(), StatusCode::OK);
236
        assert_eq!(response.text().await, "foo");
237
238
        let response = client.get("/requires_bar").await;
239
        assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);
240
        assert_eq!(response.text().await, "Missing request extension: Extension of type `axum::extension::tests::Bar` was not found. Perhaps you forgot to add it? See `axum::Extension`.");
241
242
        let response = client.get("/optional_bar").await;
243
        assert_eq!(response.status(), StatusCode::OK);
244
        assert_eq!(response.text().await, "none");
245
    }
246
}