qubit_redact/http/body_budget.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//! Hard input and output limits for HTTP body redaction.
9
10use super::BodyBudgetError;
11
12/// Bounds both inspected body bytes and produced log-safe bytes.
13#[must_use]
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct BodyBudget {
16 /// Maximum number of captured source bytes a parser may inspect.
17 max_input_bytes: usize,
18 /// Maximum number of bytes in the final log-safe rendering.
19 max_output_bytes: usize,
20}
21
22impl BodyBudget {
23 /// Smallest output limit that can contain the truncation marker.
24 pub const MIN_OUTPUT_BYTES: usize = "<truncated>".len();
25
26 /// Creates checked hard limits for body processing.
27 ///
28 /// # Parameters
29 ///
30 /// * `max_input_bytes` - Maximum source bytes available to body parsers.
31 /// * `max_output_bytes` - Maximum bytes in the final log-safe result,
32 /// including a complete truncation marker when required.
33 ///
34 /// # Returns
35 ///
36 /// A checked finite body budget.
37 ///
38 /// # Errors
39 ///
40 /// Returns [`BodyBudgetError::ZeroInput`] when `max_input_bytes` is zero,
41 /// or [`BodyBudgetError::OutputTooSmall`] when the output limit cannot
42 /// contain the complete truncation marker.
43 #[inline]
44 pub const fn new(
45 max_input_bytes: usize,
46 max_output_bytes: usize,
47 ) -> Result<Self, BodyBudgetError> {
48 if max_input_bytes == 0 {
49 return Err(BodyBudgetError::ZeroInput);
50 }
51 if max_output_bytes < Self::MIN_OUTPUT_BYTES {
52 return Err(BodyBudgetError::OutputTooSmall {
53 minimum: Self::MIN_OUTPUT_BYTES,
54 actual: max_output_bytes,
55 });
56 }
57 Ok(Self {
58 max_input_bytes,
59 max_output_bytes,
60 })
61 }
62
63 /// Returns the maximum number of source bytes parsers may inspect.
64 ///
65 /// # Returns
66 ///
67 /// The positive input limit in bytes.
68 #[must_use]
69 #[inline(always)]
70 pub const fn max_input_bytes(self) -> usize {
71 self.max_input_bytes
72 }
73
74 /// Returns the maximum final log-safe output size.
75 ///
76 /// # Returns
77 ///
78 /// The output limit in bytes, including any truncation marker.
79 #[must_use]
80 #[inline(always)]
81 pub const fn max_output_bytes(self) -> usize {
82 self.max_output_bytes
83 }
84}
85
86impl Default for BodyBudget {
87 /// Returns the conservative 16 KiB input and 64 KiB output limits.
88 ///
89 /// # Returns
90 ///
91 /// The default finite HTTP body budget.
92 #[inline(always)]
93 fn default() -> Self {
94 Self {
95 max_input_bytes: 16 * 1024,
96 max_output_bytes: 64 * 1024,
97 }
98 }
99}