use super::BodyLogContext;
#[derive(Debug, Clone, Copy)]
pub(crate) struct BodyPreview<'a> {
pub(crate) bytes: &'a [u8],
pub(crate) limit: usize,
pub(crate) source_len: usize,
pub(crate) truncated: bool,
pub(crate) content_type: Option<&'a str>,
pub(crate) context: BodyLogContext,
}
impl<'a> BodyPreview<'a> {
pub(crate) fn new(bytes: &'a [u8], limit: usize, context: BodyLogContext) -> Self {
Self {
bytes,
limit: limit.max(1),
source_len: bytes.len(),
truncated: false,
content_type: None,
context,
}
}
pub(crate) fn from_limited_bytes(
bytes: &'a [u8],
source_len: usize,
truncated: bool,
context: BodyLogContext,
) -> Self {
Self {
bytes,
limit: bytes.len().max(1),
source_len,
truncated,
content_type: None,
context,
}
}
pub(crate) fn with_content_type(mut self, content_type: &'a str) -> Self {
self.content_type = Some(content_type);
self
}
pub(crate) fn prefix(&self) -> &'a [u8] {
if self.truncated {
self.bytes
} else {
let end = self.bytes.len().min(self.limit);
&self.bytes[..end]
}
}
pub(crate) fn is_truncated(&self) -> bool {
self.truncated || self.bytes.len() > self.limit
}
pub(crate) fn source_len(&self) -> usize {
self.source_len.max(self.bytes.len())
}
pub(crate) fn truncation_suffix(&self) -> String {
if !self.is_truncated() {
return String::new();
}
match self.context {
BodyLogContext::ErrorResponse => "...<truncated>".to_string(),
BodyLogContext::Request | BodyLogContext::Response => {
let truncated = self.source_len().saturating_sub(self.prefix().len());
format!("...<truncated {truncated} bytes>")
}
}
}
}