Skip to main content

cloud_sdk_testkit/
prepared.rs

1//! Redacted records of prepared request policy and shape.
2
3use core::fmt;
4
5use cloud_sdk::Method;
6use cloud_sdk::operation::{OperationMetadata, PreparedRequest, ProviderService, ResponsePolicy};
7use cloud_sdk::transport::HeaderSensitivity;
8
9/// Non-secret record of one prepared request for policy assertions.
10#[derive(Clone, Copy, Eq, PartialEq)]
11pub struct PreparedRequestRecord<'endpoint> {
12    method: Method,
13    target_len: usize,
14    body_len: usize,
15    has_request_content_type: bool,
16    header_count: usize,
17    sensitive_header_count: usize,
18    service: ProviderService<'endpoint>,
19    metadata: OperationMetadata,
20    response_policy: ResponsePolicy,
21}
22
23impl<'endpoint> PreparedRequestRecord<'endpoint> {
24    /// Captures request shape and complete policy without copying target or body bytes.
25    #[must_use]
26    pub fn capture(prepared: PreparedRequest<'endpoint>) -> Self {
27        let request = prepared.transport_request();
28        Self {
29            method: request.method(),
30            target_len: request.target().len(),
31            body_len: request.body().len(),
32            has_request_content_type: request.headers().get("content-type").is_some(),
33            header_count: request.headers().as_slice().len(),
34            sensitive_header_count: request
35                .headers()
36                .as_slice()
37                .iter()
38                .filter(|header| matches!(header.sensitivity(), HeaderSensitivity::Sensitive))
39                .count(),
40            service: prepared.service(),
41            metadata: prepared.metadata(),
42            response_policy: prepared.response_policy(),
43        }
44    }
45
46    /// Returns the HTTP method.
47    #[must_use]
48    pub const fn method(self) -> Method {
49        self.method
50    }
51
52    /// Returns the redacted request-target length.
53    #[must_use]
54    pub const fn target_len(self) -> usize {
55        self.target_len
56    }
57
58    /// Returns the redacted request-body length.
59    #[must_use]
60    pub const fn body_len(self) -> usize {
61        self.body_len
62    }
63
64    /// Reports whether a request content type is configured.
65    #[must_use]
66    pub const fn has_request_content_type(self) -> bool {
67        self.has_request_content_type
68    }
69
70    /// Returns the request-header count without exposing values.
71    #[must_use]
72    pub const fn header_count(self) -> usize {
73        self.header_count
74    }
75
76    /// Returns the number of headers marked sensitive.
77    #[must_use]
78    pub const fn sensitive_header_count(self) -> usize {
79        self.sensitive_header_count
80    }
81
82    /// Returns the bound provider service and endpoint.
83    #[must_use]
84    pub const fn service(self) -> ProviderService<'endpoint> {
85        self.service
86    }
87
88    /// Returns complete operation safety and retry metadata.
89    #[must_use]
90    pub const fn metadata(self) -> OperationMetadata {
91        self.metadata
92    }
93
94    /// Returns complete checked-response policy.
95    #[must_use]
96    pub const fn response_policy(self) -> ResponsePolicy {
97        self.response_policy
98    }
99}
100
101impl fmt::Debug for PreparedRequestRecord<'_> {
102    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
103        formatter
104            .debug_struct("PreparedRequestRecord")
105            .field("method", &self.method)
106            .field("target_len", &self.target_len)
107            .field("target", &"[redacted]")
108            .field("body_len", &self.body_len)
109            .field("body", &"[redacted]")
110            .field("has_request_content_type", &self.has_request_content_type)
111            .field("header_count", &self.header_count)
112            .field("sensitive_header_count", &self.sensitive_header_count)
113            .field("service", &self.service)
114            .field("metadata", &self.metadata)
115            .field("response_policy", &self.response_policy)
116            .finish()
117    }
118}