#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum Edition {
Fourth,
#[default]
Fifth,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct Limits {
pub edition: Edition,
pub max_depth: usize,
pub max_attributes_per_element: usize,
pub max_attribute_size: usize,
pub max_name_length: usize,
pub max_nodes: Option<usize>,
pub max_text_length: Option<usize>,
pub max_input_bytes: Option<usize>,
pub max_document_bytes: Option<usize>,
pub max_xpath_depth: usize,
pub max_entity_depth: usize,
pub max_entity_expansion: usize,
pub max_xpath_operators: usize,
pub max_xpath_bytes: Option<usize>,
pub max_xpath_nodes: usize,
pub max_xpath_arguments: usize,
pub max_dtd_bytes: Option<usize>,
pub max_dtd_depth: usize,
pub max_pe_expansion: usize,
pub max_construct_bytes: Option<usize>,
}
impl Default for Limits {
fn default() -> Self {
Self {
edition: Edition::Fifth,
max_depth: 256,
max_attributes_per_element: 1_000,
max_attribute_size: 524_288,
max_name_length: 8_192,
max_nodes: None,
max_text_length: None,
max_input_bytes: None,
max_document_bytes: None,
max_entity_depth: 10,
max_entity_expansion: 10_000_000,
max_xpath_depth: 256,
max_xpath_operators: 10_000,
max_xpath_bytes: Some(1024 * 1024),
max_xpath_nodes: 40_000,
max_xpath_arguments: 10_000,
max_dtd_bytes: Some(16 * 1024 * 1024),
max_dtd_depth: 64,
max_pe_expansion: 10_000_000,
max_construct_bytes: Some(64 * 1024 * 1024),
}
}
}
impl Limits {
pub(crate) fn check_input(&self, len: usize) -> crate::Result<()> {
check_bytes(
len,
self.max_input_bytes,
crate::ErrorKind::InputTooLarge,
0,
)
}
pub(crate) fn check_document(
&self,
len: usize,
at: usize,
) -> crate::Result<()> {
check_bytes(
len,
self.max_document_bytes,
crate::ErrorKind::DocumentTooLarge,
at,
)
}
pub(crate) fn check_nodes(
&self,
current: usize,
additional: usize,
at: usize,
) -> crate::Result<()> {
let total = current.checked_add(additional);
if total.is_none()
|| self
.max_nodes
.is_some_and(|max| total.unwrap_or(usize::MAX) > max)
{
return Err(crate::Error::new(crate::ErrorKind::TooManyNodes, at));
}
Ok(())
}
#[must_use]
pub fn permissive() -> Self {
Self {
edition: Edition::Fifth,
max_depth: Self::default().max_depth,
max_attributes_per_element: 100_000,
max_attribute_size: 64 * 1024 * 1024,
max_name_length: 1024 * 1024,
max_nodes: None,
max_text_length: None,
max_input_bytes: None,
max_document_bytes: None,
max_entity_depth: 40,
max_entity_expansion: 1_000_000_000,
max_xpath_depth: 1_000,
max_xpath_operators: 1_000_000,
max_xpath_bytes: None,
max_xpath_nodes: 4_000_000,
max_xpath_arguments: 1_000_000,
max_dtd_bytes: None,
max_dtd_depth: 64,
max_pe_expansion: 1_000_000_000,
max_construct_bytes: None,
}
}
#[must_use]
pub fn strict() -> Self {
Self {
edition: Edition::Fifth,
max_depth: 64,
max_attributes_per_element: 64,
max_attribute_size: 8 * 1024,
max_name_length: 256,
max_nodes: Some(100_000),
max_text_length: Some(1024 * 1024),
max_input_bytes: Some(8 * 1024 * 1024),
max_document_bytes: Some(8 * 1024 * 1024),
max_entity_depth: 4,
max_entity_expansion: 100_000,
max_xpath_depth: 32,
max_xpath_operators: 1_000,
max_xpath_bytes: Some(64 * 1024),
max_xpath_nodes: 4_000,
max_xpath_arguments: 1_000,
max_dtd_bytes: Some(64 * 1024),
max_dtd_depth: 32,
max_pe_expansion: 100_000,
max_construct_bytes: Some(1024 * 1024),
}
}
}
pub(crate) fn check_bytes(
len: usize,
limit: Option<usize>,
kind: crate::ErrorKind,
at: usize,
) -> crate::Result<()> {
if limit.is_some_and(|max| len > max) {
return Err(crate::Error::new(kind, at));
}
Ok(())
}