axum/routing/
url_params.rs

1use crate::util::PercentDecodedStr;
2use http::Extensions;
3use matchit::Params;
4use std::sync::Arc;
5
6#[derive(Clone)]
7pub(crate) enum UrlParams {
8    Params(Vec<(Arc<str>, PercentDecodedStr)>),
9    InvalidUtf8InPathParam { key: Arc<str> },
10}
11
12pub(super) fn insert_url_params(extensions: &mut Extensions, params: Params) {
13    let current_params = extensions.get_mut();
14
15    if let Some(UrlParams::InvalidUtf8InPathParam { .. }) = current_params {
16        // nothing to do here since an error was stored earlier
17        return;
18    }
19
20    let params = params
21        .iter()
22        .filter(|(key, _)| !key.starts_with(super::NEST_TAIL_PARAM))
23        .filter(|(key, _)| !key.starts_with(super::FALLBACK_PARAM))
24        .map(|(k, v)| {
25            if let Some(decoded) = PercentDecodedStr::new(v) {
26                Ok((Arc::from(k), decoded))
27            } else {
28                Err(Arc::from(k))
29            }
30        })
31        .collect::<Result<Vec<_>, _>>();
32
33    match (current_params, params) {
34        (Some(UrlParams::InvalidUtf8InPathParam { .. }), _) => {
35            unreachable!("we check for this state earlier in this method")
36        }
37        (_, Err(invalid_key)) => {
38            extensions.insert(UrlParams::InvalidUtf8InPathParam { key: invalid_key });
39        }
40        (Some(UrlParams::Params(current)), Ok(params)) => {
41            current.extend(params);
42        }
43        (None, Ok(params)) => {
44            extensions.insert(UrlParams::Params(params));
45        }
46    }
47}