qubit_http/sanitize/sensitive_query_params.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10
11use std::collections::BTreeSet;
12
13use super::default_sensitive_names::{
14 canonicalize_structured_sensitive_name,
15 DEFAULT_SENSITIVE_QUERY_PARAM_NAMES,
16};
17
18/// Set of query parameter names whose values should be masked.
19///
20/// Names are matched case-insensitively and common `_` / `-` separators are
21/// ignored, so `access_token`, `access-token`, and `accessToken` are equivalent.
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct SensitiveQueryParams {
24 /// Canonical query parameter names.
25 names: BTreeSet<String>,
26}
27
28impl SensitiveQueryParams {
29 /// Creates an empty set.
30 ///
31 /// # Returns
32 /// Empty [`SensitiveQueryParams`].
33 pub fn new() -> Self {
34 Self {
35 names: BTreeSet::new(),
36 }
37 }
38
39 /// Returns whether `name` is sensitive.
40 ///
41 /// # Parameters
42 /// - `name`: Query parameter name.
43 ///
44 /// # Returns
45 /// `true` if the value should be masked in logged URLs.
46 pub fn contains(&self, name: &str) -> bool {
47 self.names
48 .contains(&canonicalize_structured_sensitive_name(name))
49 }
50
51 /// Inserts one query parameter name.
52 ///
53 /// # Parameters
54 /// - `name`: Query parameter name to mark sensitive.
55 pub fn insert(&mut self, name: &str) {
56 let value = canonicalize_structured_sensitive_name(name);
57 if !value.is_empty() {
58 self.names.insert(value);
59 }
60 }
61
62 /// Inserts many query parameter names.
63 ///
64 /// # Parameters
65 /// - `names`: Query parameter names to mark sensitive.
66 pub fn extend<I, S>(&mut self, names: I)
67 where
68 I: IntoIterator<Item = S>,
69 S: AsRef<str>,
70 {
71 for name in names {
72 self.insert(name.as_ref());
73 }
74 }
75
76 /// Clears all names.
77 pub fn clear(&mut self) {
78 self.names.clear();
79 }
80
81 /// Returns the number of stored query parameter names.
82 ///
83 /// # Returns
84 /// Stored query parameter count.
85 pub fn len(&self) -> usize {
86 self.names.len()
87 }
88
89 /// Returns whether no query parameter names are stored.
90 ///
91 /// # Returns
92 /// `true` when empty.
93 pub fn is_empty(&self) -> bool {
94 self.names.is_empty()
95 }
96
97 /// Iterates canonical query parameter names.
98 ///
99 /// # Returns
100 /// Iterator over stored canonical query parameter names.
101 pub fn iter(&self) -> impl Iterator<Item = &str> {
102 self.names.iter().map(String::as_str)
103 }
104}
105
106impl Default for SensitiveQueryParams {
107 /// Creates a set containing common token-like query parameter names.
108 fn default() -> Self {
109 let mut result = Self::new();
110 result.extend(DEFAULT_SENSITIVE_QUERY_PARAM_NAMES);
111 result
112 }
113}