Skip to main content

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}