|
1 | | -use super::{Extension, FromRequestParts}; |
2 | | -use http::{request::Parts, Uri}; |
3 | | -use std::convert::Infallible; |
4 | | - |
5 | | -/// Extractor that gets the original request URI regardless of nesting. |
6 | | -/// |
7 | | -/// This is necessary since [`Uri`](http::Uri), when used as an extractor, will |
8 | | -/// have the prefix stripped if used in a nested service. |
9 | | -/// |
10 | | -/// # Example |
11 | | -/// |
12 | | -/// ``` |
13 | | -/// use axum::{ |
14 | | -/// routing::get, |
15 | | -/// Router, |
16 | | -/// extract::OriginalUri, |
17 | | -/// http::Uri |
18 | | -/// }; |
19 | | -/// |
20 | | -/// let api_routes = Router::new() |
21 | | -/// .route( |
22 | | -/// "/users", |
23 | | -/// get(|uri: Uri, OriginalUri(original_uri): OriginalUri| async { |
24 | | -/// // `uri` is `/users` |
25 | | -/// // `original_uri` is `/api/users` |
26 | | -/// }), |
27 | | -/// ); |
28 | | -/// |
29 | | -/// let app = Router::new().nest("/api", api_routes); |
30 | | -/// # let _: Router = app; |
31 | | -/// ``` |
32 | | -/// |
33 | | -/// # Extracting via request extensions |
34 | | -/// |
35 | | -/// `OriginalUri` can also be accessed from middleware via request extensions. |
36 | | -/// This is useful for example with [`Trace`](tower_http::trace::Trace) to |
37 | | -/// create a span that contains the full path, if your service might be nested: |
38 | | -/// |
39 | | -/// ``` |
40 | | -/// use axum::{ |
41 | | -/// Router, |
42 | | -/// extract::OriginalUri, |
43 | | -/// http::Request, |
44 | | -/// routing::get, |
45 | | -/// }; |
46 | | -/// use tower_http::trace::TraceLayer; |
47 | | -/// |
48 | | -/// let api_routes = Router::new() |
49 | | -/// .route("/users/{id}", get(|| async { /* ... */ })) |
50 | | -/// .layer( |
51 | | -/// TraceLayer::new_for_http().make_span_with(|req: &Request<_>| { |
52 | | -/// let path = if let Some(path) = req.extensions().get::<OriginalUri>() { |
53 | | -/// // This will include `/api` |
54 | | -/// path.0.path().to_owned() |
55 | | -/// } else { |
56 | | -/// // The `OriginalUri` extension will always be present if using |
57 | | -/// // `Router` unless another extractor or middleware has removed it |
58 | | -/// req.uri().path().to_owned() |
59 | | -/// }; |
60 | | -/// tracing::info_span!("http-request", %path) |
61 | | -/// }), |
62 | | -/// ); |
63 | | -/// |
64 | | -/// let app = Router::new().nest("/api", api_routes); |
65 | | -/// # let _: Router = app; |
66 | | -/// ``` |
67 | | -#[cfg(feature = "original-uri")] |
68 | | -#[derive(Debug, Clone)] |
69 | | -pub struct OriginalUri(pub Uri); |
70 | | - |
71 | | -#[cfg(feature = "original-uri")] |
72 | | -impl<S> FromRequestParts<S> for OriginalUri |
73 | | -where |
74 | | - S: Send + Sync, |
75 | | -{ |
76 | | - type Rejection = Infallible; |
77 | | - |
78 | | - async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> { |
79 | | - let uri = Extension::<Self>::from_request_parts(parts, state) |
80 | | - .await |
81 | | - .unwrap_or_else(|_| Extension(OriginalUri(parts.uri.clone()))) |
82 | | - .0; |
83 | | - Ok(uri) |
84 | | - } |
85 | | -} |
86 | | - |
87 | | -#[cfg(feature = "original-uri")] |
88 | | -axum_core::__impl_deref!(OriginalUri: Uri); |
89 | | - |
| 1 | +/// This module contains the tests for the `impl<S> FromRequestParts<S> for Parts` |
| 2 | +/// implementation in the `axum-core` crate. The tests cannot be moved there |
| 3 | +/// because we don't have access to the `TestClient` and `Router` types there. |
90 | 4 | #[cfg(test)] |
91 | 5 | mod tests { |
92 | 6 | use crate::{extract::Extension, routing::get, test_helpers::*, Router}; |
|
0 commit comments