qubit_redact/http/http_redaction_policy.rs
1// =============================================================================
2// Copyright (c) 2025 - 2026 Haixing Hu.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Immutable policy snapshot for every HTTP redaction context.
9
10use crate::{
11 DiagnosticBudget,
12 RedactionPolicy,
13};
14
15use super::{
16 BodyBudget,
17 HttpRedactionPolicyBuilder,
18 TextBodyPolicy,
19 UnkeyedJsonValuePolicy,
20 UrlPathPolicy,
21};
22
23/// Combines independent HTTP field policies, behavior choices, and hard limits.
24#[must_use]
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct HttpRedactionPolicy {
27 /// Field policy used for HTTP header names and values.
28 header_policy: RedactionPolicy,
29 /// Field policy used for URL query and form names and values.
30 query_policy: RedactionPolicy,
31 /// Field policy used inside structured HTTP body formats.
32 body_policy: RedactionPolicy,
33 /// Visibility choice for non-root URL paths.
34 url_path_policy: UrlPathPolicy,
35 /// Visibility choice for opaque UTF-8 text bodies.
36 text_body_policy: TextBodyPolicy,
37 /// Visibility choice for JSON scalar values without a field name.
38 unkeyed_json_value_policy: UnkeyedJsonValuePolicy,
39 /// Finite parser-input and log-output byte limits.
40 body_budget: BodyBudget,
41 /// Finite input and output limits for non-body diagnostics.
42 diagnostic_budget: DiagnosticBudget,
43}
44
45impl HttpRedactionPolicy {
46 /// Creates a builder without header, query, or body field rules.
47 ///
48 /// # Returns
49 ///
50 /// A mutable HTTP policy builder with fail-closed behavior defaults and
51 /// finite budgets.
52 #[inline(always)]
53 pub fn builder() -> HttpRedactionPolicyBuilder {
54 HttpRedactionPolicyBuilder::new()
55 }
56
57 /// Creates a builder initialized from the current default HTTP policy.
58 ///
59 /// # Returns
60 ///
61 /// A mutable HTTP policy builder containing a snapshot of the current
62 /// default policy.
63 #[inline(always)]
64 pub fn builder_from_default() -> HttpRedactionPolicyBuilder {
65 HttpRedactionPolicyBuilder::from_policy(&Self::default())
66 }
67
68 /// Creates a builder with three mutable copies of `base`.
69 ///
70 /// # Parameters
71 ///
72 /// * `base` - Field policy copied for header, query, and body contexts.
73 ///
74 /// # Returns
75 ///
76 /// A mutable HTTP policy builder using fail-closed behavior defaults and
77 /// `base`'s diagnostic budget snapshot.
78 pub fn builder_from(base: RedactionPolicy) -> HttpRedactionPolicyBuilder {
79 HttpRedactionPolicyBuilder::from_base_policy(base)
80 }
81
82 /// Creates an immutable HTTP policy from complete builder state.
83 ///
84 /// # Parameters
85 ///
86 /// * `header_policy` - Header field-policy snapshot.
87 /// * `query_policy` - Query and form field-policy snapshot.
88 /// * `body_policy` - Structured-body field-policy snapshot.
89 /// * `url_path_policy` - URL path visibility choice.
90 /// * `text_body_policy` - Opaque text-body visibility choice.
91 /// * `unkeyed_json_value_policy` - Unkeyed scalar visibility choice.
92 /// * `body_budget` - Checked body input and output byte limits.
93 ///
94 /// # Returns
95 ///
96 /// A complete immutable HTTP policy.
97 #[inline(always)]
98 pub(super) fn from_parts(
99 header_policy: RedactionPolicy,
100 query_policy: RedactionPolicy,
101 body_policy: RedactionPolicy,
102 url_path_policy: UrlPathPolicy,
103 text_body_policy: TextBodyPolicy,
104 unkeyed_json_value_policy: UnkeyedJsonValuePolicy,
105 body_budget: BodyBudget,
106 ) -> Self {
107 let diagnostic_budget = body_policy.diagnostic_budget();
108 Self {
109 header_policy,
110 query_policy,
111 body_policy,
112 url_path_policy,
113 text_body_policy,
114 unkeyed_json_value_policy,
115 body_budget,
116 diagnostic_budget,
117 }
118 }
119
120 /// Replaces the non-body diagnostic input and output byte limits.
121 ///
122 /// # Parameters
123 ///
124 /// * `diagnostic_budget` - Replacement limits for non-body diagnostics.
125 ///
126 /// # Returns
127 ///
128 /// The policy with its diagnostic budget replaced.
129 #[inline(always)]
130 pub(super) const fn with_diagnostic_budget(
131 mut self,
132 diagnostic_budget: DiagnosticBudget,
133 ) -> Self {
134 self.diagnostic_budget = diagnostic_budget;
135 self
136 }
137
138 /// Returns the immutable header-field policy snapshot.
139 ///
140 /// # Returns
141 ///
142 /// The policy used for HTTP headers.
143 #[inline(always)]
144 pub const fn header_policy(&self) -> &RedactionPolicy {
145 &self.header_policy
146 }
147
148 /// Returns the immutable query and form field-policy snapshot.
149 ///
150 /// # Returns
151 ///
152 /// The policy used for URL query and form fields.
153 #[inline(always)]
154 pub const fn query_policy(&self) -> &RedactionPolicy {
155 &self.query_policy
156 }
157
158 /// Returns the immutable structured-body field-policy snapshot.
159 ///
160 /// # Returns
161 ///
162 /// The policy used for fields inside HTTP bodies.
163 #[inline(always)]
164 pub const fn body_policy(&self) -> &RedactionPolicy {
165 &self.body_policy
166 }
167
168 /// Returns the URL path visibility choice.
169 ///
170 /// # Returns
171 ///
172 /// The immutable URL path behavior.
173 #[inline(always)]
174 pub const fn url_path_policy(&self) -> UrlPathPolicy {
175 self.url_path_policy
176 }
177
178 /// Returns the opaque text-body visibility choice.
179 ///
180 /// # Returns
181 ///
182 /// The immutable text-body behavior.
183 #[inline(always)]
184 pub const fn text_body_policy(&self) -> TextBodyPolicy {
185 self.text_body_policy
186 }
187
188 /// Returns the unkeyed JSON scalar visibility choice.
189 ///
190 /// # Returns
191 ///
192 /// The immutable unkeyed JSON behavior.
193 #[inline(always)]
194 pub const fn unkeyed_json_value_policy(&self) -> UnkeyedJsonValuePolicy {
195 self.unkeyed_json_value_policy
196 }
197
198 /// Returns the finite body input and output limits.
199 ///
200 /// # Returns
201 ///
202 /// The checked hard body budget.
203 #[inline(always)]
204 pub const fn body_budget(&self) -> BodyBudget {
205 self.body_budget
206 }
207
208 /// Returns the finite diagnostic input and output limits.
209 ///
210 /// # Returns
211 ///
212 /// The checked hard diagnostic budget.
213 #[inline(always)]
214 pub const fn diagnostic_budget(&self) -> DiagnosticBudget {
215 self.diagnostic_budget
216 }
217}
218
219impl Default for HttpRedactionPolicy {
220 /// Creates a fail-closed HTTP policy from the current global field default.
221 ///
222 /// # Returns
223 ///
224 /// Three independent default policy snapshots and finite body limits.
225 #[inline(always)]
226 fn default() -> Self {
227 let base = RedactionPolicy::default();
228 Self::from_parts(
229 base.clone(),
230 base.clone(),
231 base,
232 UrlPathPolicy::default(),
233 TextBodyPolicy::default(),
234 UnkeyedJsonValuePolicy::default(),
235 BodyBudget::default(),
236 )
237 }
238}