use std::collections::BTreeMap;
use std::io::Write;
pub const MAX_INPUT_BYTES: usize = 8 * 1024 * 1024;
pub const MAX_OUTPUT_BYTES: usize = 8 * 1024 * 1024;
pub const MAX_NODES: usize = 262_144;
pub const MAX_DEPTH: usize = 64;
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
Null,
Bool(bool),
Signed(i64),
Unsigned(u64),
Float(f64),
String(String),
Array(Vec<Value>),
Object(BTreeMap<String, Value>),
ObjectMembers(Vec<(String, Value)>),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Layout {
Compact,
Pretty,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, thiserror::Error)]
pub enum Error {
#[error("JSON source exceeds byte limit")]
InputTooLarge,
#[error("invalid JSON document")]
InvalidSyntax,
#[error("JSON exceeds value count limit")]
TooManyNodes,
#[error("JSON exceeds depth limit")]
TooDeep,
#[error("JSON numbers must be finite")]
NonFiniteNumber,
#[error("JSON output exceeds byte limit")]
OutputTooLarge,
#[error("JSON encoding failed")]
EncodingFailed,
}
pub fn parse(source: &[u8]) -> Result<Value, Error> {
if source.len() > MAX_INPUT_BYTES {
return Err(Error::InputTooLarge);
}
let value = serde_json::from_slice(source).map_err(|_| Error::InvalidSyntax)?;
let mut remaining = MAX_NODES;
convert(value, 0, &mut remaining)
}
pub fn parse_members(source: &[u8]) -> Result<Value, Error> {
use serde::de::DeserializeSeed;
if source.len() > MAX_INPUT_BYTES {
return Err(Error::InputTooLarge);
}
let mut state = MemberState {
remaining: MAX_NODES,
failure: None,
};
let mut parser = serde_json::Deserializer::from_slice(source);
let result = MemberSeed {
state: &mut state,
depth: 0,
}
.deserialize(&mut parser);
let value = result.map_err(|_| state.failure.unwrap_or(Error::InvalidSyntax))?;
parser.end().map_err(|_| Error::InvalidSyntax)?;
Ok(value)
}
struct MemberState {
remaining: usize,
failure: Option<Error>,
}
struct MemberSeed<'a> {
state: &'a mut MemberState,
depth: usize,
}
impl<'de> serde::de::DeserializeSeed<'de> for MemberSeed<'_> {
type Value = Value;
fn deserialize<D: serde::Deserializer<'de>>(self, deserializer: D) -> Result<Value, D::Error> {
if let Err(error) = visit(self.depth, &mut self.state.remaining) {
self.state.failure = Some(error);
return Err(serde::de::Error::custom("JSON resource limit"));
}
let raw: &'de serde_json::value::RawValue = serde::Deserialize::deserialize(deserializer)?;
let mut parser = serde_json::Deserializer::from_str(raw.get());
use serde::Deserializer;
match raw.get().as_bytes().first() {
Some(b'{') => parser
.deserialize_map(self)
.map_err(serde::de::Error::custom),
Some(b'[') => parser
.deserialize_seq(self)
.map_err(serde::de::Error::custom),
_ => {
let value = serde_json::from_str(raw.get()).map_err(serde::de::Error::custom)?;
let mut scalar_budget = 1;
convert(value, 0, &mut scalar_budget).map_err(serde::de::Error::custom)
}
}
}
}
impl<'de> serde::de::Visitor<'de> for MemberSeed<'_> {
type Value = Value;
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str("a JSON value")
}
fn visit_seq<A: serde::de::SeqAccess<'de>>(self, mut sequence: A) -> Result<Value, A::Error> {
let mut values = Vec::new();
while let Some(value) = sequence.next_element_seed(MemberSeed {
state: &mut *self.state,
depth: self.depth + 1,
})? {
values.push(value);
}
Ok(Value::Array(values))
}
fn visit_map<A: serde::de::MapAccess<'de>>(self, mut object: A) -> Result<Value, A::Error> {
let mut members = Vec::new();
while let Some(key) = object.next_key::<String>()? {
let value = object.next_value_seed(MemberSeed {
state: &mut *self.state,
depth: self.depth + 1,
})?;
members.push((key, value));
}
Ok(Value::ObjectMembers(members))
}
}
fn visit(depth: usize, remaining: &mut usize) -> Result<(), Error> {
if depth > MAX_DEPTH {
return Err(Error::TooDeep);
}
*remaining = remaining.checked_sub(1).ok_or(Error::TooManyNodes)?;
Ok(())
}
fn convert(value: serde_json::Value, depth: usize, remaining: &mut usize) -> Result<Value, Error> {
visit(depth, remaining)?;
Ok(match value {
serde_json::Value::Null => Value::Null,
serde_json::Value::Bool(value) => Value::Bool(value),
serde_json::Value::Number(value) => {
if let Some(value) = value.as_i64() {
Value::Signed(value)
} else if let Some(value) = value.as_u64() {
Value::Unsigned(value)
} else {
Value::Float(value.as_f64().ok_or(Error::InvalidSyntax)?)
}
}
serde_json::Value::String(value) => Value::String(value),
serde_json::Value::Array(values) => Value::Array(
values
.into_iter()
.map(|value| convert(value, depth + 1, remaining))
.collect::<Result<_, _>>()?,
),
serde_json::Value::Object(values) => Value::Object(
values
.into_iter()
.map(|(key, value)| Ok((key, convert(value, depth + 1, remaining)?)))
.collect::<Result<_, Error>>()?,
),
})
}
fn validate(value: &Value, depth: usize, remaining: &mut usize) -> Result<(), Error> {
visit(depth, remaining)?;
match value {
Value::Float(value) if !value.is_finite() => return Err(Error::NonFiniteNumber),
Value::Array(values) => {
for value in values {
validate(value, depth + 1, remaining)?;
}
}
Value::Object(values) => {
for value in values.values() {
validate(value, depth + 1, remaining)?;
}
}
Value::ObjectMembers(values) => {
for (_, value) in values {
validate(value, depth + 1, remaining)?;
}
}
_ => {}
}
Ok(())
}
struct Borrowed<'a>(&'a Value);
impl serde::Serialize for Borrowed<'_> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::{SerializeMap, SerializeSeq};
match self.0 {
Value::Null => serializer.serialize_unit(),
Value::Bool(value) => serializer.serialize_bool(*value),
Value::Signed(value) => serializer.serialize_i64(*value),
Value::Unsigned(value) => serializer.serialize_u64(*value),
Value::Float(value) => serializer.serialize_f64(*value),
Value::String(value) => serializer.serialize_str(value),
Value::Array(values) => {
let mut output = serializer.serialize_seq(Some(values.len()))?;
for value in values {
output.serialize_element(&Borrowed(value))?;
}
output.end()
}
Value::Object(values) => {
let mut output = serializer.serialize_map(Some(values.len()))?;
for (key, value) in values {
output.serialize_entry(key, &Borrowed(value))?;
}
output.end()
}
Value::ObjectMembers(values) => {
let mut output = serializer.serialize_map(Some(values.len()))?;
for (key, value) in values {
output.serialize_entry(key, &Borrowed(value))?;
}
output.end()
}
}
}
}
#[derive(Default)]
struct Output {
bytes: Vec<u8>,
exceeded: bool,
}
impl Write for Output {
fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
if bytes.len() > MAX_OUTPUT_BYTES - self.bytes.len() {
self.exceeded = true;
return Err(std::io::Error::other("JSON output limit"));
}
self.bytes.extend_from_slice(bytes);
Ok(bytes.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
pub fn encode(value: &Value, layout: Layout) -> Result<Vec<u8>, Error> {
let mut remaining = MAX_NODES;
validate(value, 0, &mut remaining)?;
let mut output = Output::default();
let result = match layout {
Layout::Compact => serde_json::to_writer(&mut output, &Borrowed(value)),
Layout::Pretty => serde_json::to_writer_pretty(&mut output, &Borrowed(value)),
};
if output.exceeded {
return Err(Error::OutputTooLarge);
}
result.map_err(|_| Error::EncodingFailed)?;
Ok(output.bytes)
}