pub mod adjacency_writer;
pub mod delta_index;
pub mod free_space;
pub use adjacency_writer::{AdjacencyWriter, WrittenOffset};
pub use delta_index::{DeltaIndex, DeltaRecord, SharedDeltaIndex};
pub use free_space::{
CHAIN_THRESHOLD, ChainAllocationTrigger, ContiguousAllocation, FreeSpaceError,
FreeSpaceManager, Region, WalRecoveryState,
};
pub use self::json_validation::{
JsonLimits, JsonValidationError, parse_and_validate_json, parse_and_validate_json_str,
};
mod json_validation {
use serde_json::Value;
const DEFAULT_MAX_JSON_SIZE: usize = 10 * 1024 * 1024;
const DEFAULT_MAX_JSON_DEPTH: usize = 128;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct JsonLimits {
pub max_size: usize,
pub max_depth: usize,
}
impl Default for JsonLimits {
fn default() -> Self {
Self {
max_size: DEFAULT_MAX_JSON_SIZE,
max_depth: DEFAULT_MAX_JSON_DEPTH,
}
}
}
impl JsonLimits {
pub fn new(max_size: usize, max_depth: usize) -> Self {
Self {
max_size,
max_depth,
}
}
pub fn with_max_size(max_size: usize) -> Self {
Self {
max_size,
..Default::default()
}
}
pub fn with_max_depth(max_depth: usize) -> Self {
Self {
max_depth,
..Default::default()
}
}
#[cfg(test)]
pub fn test_limits() -> Self {
Self {
max_size: 1000,
max_depth: 10,
}
}
}
#[derive(Debug, thiserror::Error)]
pub enum JsonValidationError {
#[error("JSON size {actual} bytes exceeds maximum {max} bytes")]
SizeTooLarge { actual: usize, max: usize },
#[error("JSON depth {actual} exceeds maximum {max}")]
DepthTooLarge { actual: usize, max: usize },
#[error("JSON parsing error: {0}")]
ParseError(#[from] serde_json::Error),
}
pub fn validate_json_size(
input: &[u8],
limits: &JsonLimits,
) -> Result<(), JsonValidationError> {
if input.len() > limits.max_size {
return Err(JsonValidationError::SizeTooLarge {
actual: input.len(),
max: limits.max_size,
});
}
Ok(())
}
fn calculate_json_depth(value: &Value, current: usize) -> usize {
match value {
Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => current,
Value::Array(arr) => arr
.iter()
.map(|v| calculate_json_depth(v, current + 1))
.max()
.unwrap_or(current),
Value::Object(obj) => obj
.values()
.map(|v| calculate_json_depth(v, current + 1))
.max()
.unwrap_or(current),
}
}
pub fn validate_json_depth(
value: &Value,
limits: &JsonLimits,
) -> Result<(), JsonValidationError> {
let depth = calculate_json_depth(value, 0);
if depth > limits.max_depth {
return Err(JsonValidationError::DepthTooLarge {
actual: depth,
max: limits.max_depth,
});
}
Ok(())
}
pub fn parse_and_validate_json(
input: &[u8],
limits: &JsonLimits,
) -> Result<Value, JsonValidationError> {
validate_json_size(input, limits)?;
let value: Value = serde_json::from_slice(input)?;
validate_json_depth(&value, limits)?;
Ok(value)
}
pub fn parse_and_validate_json_str(
input: &str,
limits: &JsonLimits,
) -> Result<Value, JsonValidationError> {
parse_and_validate_json(input.as_bytes(), limits)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_json_size_within_limit() {
let limits = JsonLimits {
max_size: 1000,
max_depth: 128,
};
let input = br#"{"test": "data"}"#;
let result = parse_and_validate_json(input, &limits);
assert!(result.is_ok());
assert_eq!(result.unwrap()["test"], "data");
}
#[test]
fn test_json_size_exceeds_limit() {
let limits = JsonLimits {
max_size: 10,
max_depth: 128,
};
let input = br#"{"large": "this value exceeds limit"}"#;
let result = parse_and_validate_json(input, &limits);
assert!(matches!(
result,
Err(JsonValidationError::SizeTooLarge { .. })
));
}
#[test]
fn test_json_depth_within_limit() {
let limits = JsonLimits {
max_size: 10000,
max_depth: 64,
};
let mut json_str = String::from("null");
for _ in 0..10 {
json_str = format!("[{}]", json_str);
}
let result = parse_and_validate_json(json_str.as_bytes(), &limits);
assert!(result.is_ok());
}
#[test]
fn test_json_depth_exceeds_limit() {
let limits = JsonLimits {
max_size: 10000,
max_depth: 10,
};
let mut json_str = String::from("null");
for _ in 0..20 {
json_str = format!("[{}]", json_str);
}
let result = parse_and_validate_json(json_str.as_bytes(), &limits);
assert!(matches!(
result,
Err(JsonValidationError::DepthTooLarge { .. })
));
}
#[test]
fn test_json_depth_exactly_at_limit() {
let limits = JsonLimits {
max_size: 10000,
max_depth: 10,
};
let mut json_str = String::from("null");
for _ in 0..10 {
json_str = format!("[{}]", json_str);
}
let result = parse_and_validate_json(json_str.as_bytes(), &limits);
assert!(result.is_ok());
}
#[test]
fn test_empty_json() {
let limits = JsonLimits::default();
let result = parse_and_validate_json(b"{}", &limits);
assert!(result.is_ok());
}
#[test]
fn test_empty_array() {
let limits = JsonLimits::default();
let result = parse_and_validate_json(b"[]", &limits);
assert!(result.is_ok());
}
#[test]
fn test_invalid_json_syntax() {
let limits = JsonLimits::default();
let result = parse_and_validate_json(b"{invalid json}", &limits);
assert!(matches!(result, Err(JsonValidationError::ParseError(_))));
}
#[test]
fn test_nested_object_depth() {
let limits = JsonLimits {
max_size: 10000,
max_depth: 5,
};
let json_str = r#"{"a":{"a":{"a":{"a":{"a":null}}}}}"#;
let result = parse_and_validate_json(json_str.as_bytes(), &limits);
assert!(result.is_ok());
}
#[test]
fn test_mixed_nesting_depth() {
let limits = JsonLimits {
max_size: 10000,
max_depth: 4,
};
let json_str = r#"[{"a": [null]}]"#;
let result = parse_and_validate_json(json_str.as_bytes(), &limits);
assert!(result.is_ok());
}
#[test]
fn test_default_limits() {
let limits = JsonLimits::default();
assert_eq!(limits.max_size, 10 * 1024 * 1024);
assert_eq!(limits.max_depth, 128);
}
#[test]
fn test_custom_limits() {
let limits = JsonLimits::new(100, 10);
assert_eq!(limits.max_size, 100);
assert_eq!(limits.max_depth, 10);
}
#[test]
fn test_with_max_size() {
let limits = JsonLimits::with_max_size(500);
assert_eq!(limits.max_size, 500);
assert_eq!(limits.max_depth, 128); }
#[test]
fn test_with_max_depth() {
let limits = JsonLimits::with_max_depth(64);
assert_eq!(limits.max_size, 10 * 1024 * 1024); assert_eq!(limits.max_depth, 64);
}
#[test]
fn test_string_input() {
let limits = JsonLimits::default();
let result = parse_and_validate_json_str(r#"{"key": "value"}"#, &limits);
assert!(result.is_ok());
assert_eq!(result.unwrap()["key"], "value");
}
#[test]
fn test_zero_size_input() {
let limits = JsonLimits::default();
let result = parse_and_validate_json(b"", &limits);
assert!(matches!(result, Err(JsonValidationError::ParseError(_))));
}
} }