mirror of
https://github.com/mikedilger/chorus.git
synced 2026-05-03 06:51:42 +00:00
fix: Output buffer length checking
This commit is contained in:
parent
c157b9e03c
commit
cdf202c3f3
@ -5,11 +5,15 @@ use crate::types::parse::json_parse::*;
|
||||
/// Returns the count of consumed bytes and output bytes
|
||||
pub fn parse_json_event(input: &[u8], output: &mut [u8]) -> Result<(usize, usize), Error> {
|
||||
// Minimum-sized JSON event is 204 characters long
|
||||
// NOTE: 152 is the minimum binary event
|
||||
if input.len() < 204 {
|
||||
return Err(ChorusError::JsonBadEvent("Too Short", 0).into());
|
||||
}
|
||||
|
||||
// NOTE: 152 is the minimum binary event
|
||||
if output.len() < 152 {
|
||||
return Err(ChorusError::BufferTooSmall.into());
|
||||
}
|
||||
|
||||
// This tracks where we are currently looking in the input as we scan forward.
|
||||
// It is short for INput POSition.
|
||||
let mut inpos = 0;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use crate::error::{ChorusError, Error};
|
||||
use crate::types::parse::json_escape::json_unescape;
|
||||
use crate::types::parse::json_parse::*;
|
||||
use crate::types::parse::put;
|
||||
|
||||
/// Parses a JSON filter from the `input` buffer. Places the parsed filter into the `output` buffer.
|
||||
/// Returns the count of consumed bytes and output bytes
|
||||
@ -35,16 +36,20 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
|
||||
};
|
||||
|
||||
// Start structure with that of an empty filter
|
||||
output[0..32].copy_from_slice(&[
|
||||
0, 0, // length (we will fill it in later)
|
||||
0, 0, // 0 ids
|
||||
0, 0, // 0 authors
|
||||
0, 0, // 0 kinds
|
||||
255, 255, 255, 255, // max limit
|
||||
0, 0, 0, 0, // padding
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // since 1970
|
||||
255, 255, 255, 255, 255, 255, 255, 255, // until max unixtime
|
||||
]);
|
||||
put(
|
||||
output,
|
||||
0,
|
||||
&[
|
||||
0, 0, // length (we will fill it in later)
|
||||
0, 0, // 0 ids
|
||||
0, 0, // 0 authors
|
||||
0, 0, // 0 kinds
|
||||
255, 255, 255, 255, // max limit
|
||||
0, 0, 0, 0, // padding
|
||||
0, 0, 0, 0, 0, 0, 0, 0, // since 1970
|
||||
255, 255, 255, 255, 255, 255, 255, 255, // until max unixtime
|
||||
],
|
||||
)?;
|
||||
|
||||
let mut end: usize = 32;
|
||||
|
||||
@ -143,7 +148,7 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
|
||||
|
||||
eat_colon_with_whitespace(input, &mut inpos)?;
|
||||
let since = read_u64(input, &mut inpos)?;
|
||||
output[16..24].copy_from_slice(since.to_ne_bytes().as_slice());
|
||||
put(output, 16, since.to_ne_bytes().as_slice())?;
|
||||
|
||||
found |= HAVE_SINCE;
|
||||
} else if inpos + 6 <= input.len() && &input[inpos..inpos + 6] == b"until\"" {
|
||||
@ -155,7 +160,7 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
|
||||
|
||||
eat_colon_with_whitespace(input, &mut inpos)?;
|
||||
let until = read_u64(input, &mut inpos)?;
|
||||
output[24..32].copy_from_slice(until.to_ne_bytes().as_slice());
|
||||
put(output, 24, until.to_ne_bytes().as_slice())?;
|
||||
|
||||
found |= HAVE_UNTIL;
|
||||
} else if inpos + 6 <= input.len() && &input[inpos..inpos + 6] == b"limit\"" {
|
||||
@ -168,7 +173,7 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
|
||||
eat_colon_with_whitespace(input, &mut inpos)?;
|
||||
let limit = read_u64(input, &mut inpos)?;
|
||||
let limit: u32 = limit as u32;
|
||||
output[8..12].copy_from_slice(limit.to_ne_bytes().as_slice());
|
||||
put(output, 8, limit.to_ne_bytes().as_slice())?;
|
||||
|
||||
found |= HAVE_LIMIT;
|
||||
} else if inpos + 3 <= input.len()
|
||||
@ -218,7 +223,7 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
|
||||
}
|
||||
|
||||
// Write num_ids
|
||||
output[2..4].copy_from_slice(num_ids.to_ne_bytes().as_slice());
|
||||
put(output, 2, num_ids.to_ne_bytes().as_slice())?;
|
||||
}
|
||||
|
||||
// Copy authors
|
||||
@ -236,7 +241,7 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
|
||||
}
|
||||
|
||||
// write num_authors
|
||||
output[4..6].copy_from_slice(num_authors.to_ne_bytes().as_slice());
|
||||
put(output, 4, num_authors.to_ne_bytes().as_slice())?;
|
||||
}
|
||||
|
||||
// Copy kinds
|
||||
@ -254,28 +259,35 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
|
||||
ChorusError::JsonBadFilter("Filter has kind number too large", inpos).into(),
|
||||
);
|
||||
}
|
||||
output[end..end + 2].copy_from_slice((u as u16).to_ne_bytes().as_slice());
|
||||
put(output, end, (u as u16).to_ne_bytes().as_slice())?;
|
||||
num_kinds += 1;
|
||||
end += 2;
|
||||
}
|
||||
|
||||
// write num_kinds
|
||||
output[6..8].copy_from_slice(num_kinds.to_ne_bytes().as_slice());
|
||||
put(output, 6, num_kinds.to_ne_bytes().as_slice())?;
|
||||
}
|
||||
|
||||
// Copy tags
|
||||
{
|
||||
let write_tags_start = end;
|
||||
// write number of tags
|
||||
output[write_tags_start + 2..write_tags_start + 4]
|
||||
.copy_from_slice((num_tag_fields as u16).to_ne_bytes().as_slice());
|
||||
put(
|
||||
output,
|
||||
write_tags_start + 2,
|
||||
(num_tag_fields as u16).to_ne_bytes().as_slice(),
|
||||
)?;
|
||||
// bump end past offset fields
|
||||
end += 4 + 2 * num_tag_fields;
|
||||
// Now pull in each tag
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
for w in 0..num_tag_fields {
|
||||
// Write it's offset
|
||||
output[write_tags_start + 4 + (2 * w)..write_tags_start + 4 + (2 * w) + 2]
|
||||
.copy_from_slice(((end - write_tags_start) as u16).to_ne_bytes().as_slice());
|
||||
put(
|
||||
output,
|
||||
write_tags_start + 4 + (2 * w),
|
||||
((end - write_tags_start) as u16).to_ne_bytes().as_slice(),
|
||||
)?;
|
||||
|
||||
let mut inpos = start_tags[w];
|
||||
let letter = input[inpos];
|
||||
@ -283,7 +295,10 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
|
||||
// bump past count output and write letter
|
||||
let countindex = end;
|
||||
end += 2;
|
||||
output[end..end + 2].copy_from_slice(1_u16.to_ne_bytes().as_slice());
|
||||
put(output, end, 1_u16.to_ne_bytes().as_slice())?;
|
||||
if output.len() < end + 2 {
|
||||
return Err(crate::error::ChorusError::BufferTooSmall.into());
|
||||
}
|
||||
output[end + 2] = letter;
|
||||
|
||||
// bump past what we just wrote
|
||||
@ -305,18 +320,21 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
|
||||
// copy data
|
||||
let (inlen, outlen) = json_unescape(&input[inpos..], &mut output[end + 2..])?;
|
||||
// write len
|
||||
output[end..end + 2].copy_from_slice((outlen as u16).to_ne_bytes().as_slice());
|
||||
put(output, end, (outlen as u16).to_ne_bytes().as_slice())?;
|
||||
end += 2 + outlen;
|
||||
inpos += inlen + 1;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
// write count
|
||||
output[countindex..countindex + 2].copy_from_slice(count.to_ne_bytes().as_slice());
|
||||
put(output, countindex, count.to_ne_bytes().as_slice())?;
|
||||
}
|
||||
// write length of tags section
|
||||
output[write_tags_start..write_tags_start + 2]
|
||||
.copy_from_slice(((end - write_tags_start) as u16).to_ne_bytes().as_slice());
|
||||
put(
|
||||
output,
|
||||
write_tags_start,
|
||||
((end - write_tags_start) as u16).to_ne_bytes().as_slice(),
|
||||
)?;
|
||||
}
|
||||
|
||||
if end > 65535 {
|
||||
@ -324,7 +342,7 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
|
||||
}
|
||||
|
||||
// Write length of filter
|
||||
output[..2].copy_from_slice((end as u16).to_ne_bytes().as_slice());
|
||||
put(output, 0, (end as u16).to_ne_bytes().as_slice())?;
|
||||
|
||||
Ok((inpos, end))
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use super::json_escape::json_unescape;
|
||||
use super::put;
|
||||
use crate::error::{ChorusError, Error};
|
||||
|
||||
#[inline]
|
||||
@ -52,6 +53,9 @@ pub fn next_object_field(input: &[u8], inposp: &mut usize) -> Result<bool, Error
|
||||
}
|
||||
|
||||
pub fn read_id(input: &[u8], inposp: &mut usize, output: &mut [u8]) -> Result<(), Error> {
|
||||
if output.len() < 32 {
|
||||
return Err(ChorusError::BufferTooSmall.into());
|
||||
}
|
||||
verify_char(input, b'"', inposp)?;
|
||||
if *inposp + 64 >= input.len() {
|
||||
return Err(ChorusError::JsonBad("Too short reading id", *inposp).into());
|
||||
@ -64,6 +68,9 @@ pub fn read_id(input: &[u8], inposp: &mut usize, output: &mut [u8]) -> Result<()
|
||||
}
|
||||
|
||||
pub fn read_pubkey(input: &[u8], inposp: &mut usize, output: &mut [u8]) -> Result<(), Error> {
|
||||
if output.len() < 32 {
|
||||
return Err(ChorusError::BufferTooSmall.into());
|
||||
}
|
||||
verify_char(input, b'"', inposp)?;
|
||||
if *inposp + 64 >= input.len() {
|
||||
return Err(ChorusError::JsonBad("Too short reading pubkey", *inposp).into());
|
||||
@ -126,14 +133,18 @@ pub fn read_tags_array(
|
||||
verify_char(input, b'[', inposp)?; // outer array open brace
|
||||
eat_whitespace(input, inposp);
|
||||
|
||||
if output.len() < 4 {
|
||||
return Err(ChorusError::BufferTooSmall.into());
|
||||
}
|
||||
|
||||
// NOTE: we cannot write any tag strings until after we have counted the tags.
|
||||
// (our tags structure is optimized for reading, not writing)
|
||||
let num_tags: usize = count_tags(input, *inposp)?;
|
||||
output[2..4].copy_from_slice((num_tags as u16).to_ne_bytes().as_slice());
|
||||
put(output, 2, (num_tags as u16).to_ne_bytes().as_slice())?;
|
||||
|
||||
// Case where we have no tags
|
||||
if num_tags == 0 {
|
||||
output[0..2].copy_from_slice(4_u16.to_ne_bytes().as_slice());
|
||||
put(output, 0, 4_u16.to_ne_bytes().as_slice())?;
|
||||
return Ok(4);
|
||||
}
|
||||
|
||||
@ -142,11 +153,18 @@ pub fn read_tags_array(
|
||||
|
||||
let mut tag_num = 0;
|
||||
let mut outpos: usize = 4 + num_tags * 2;
|
||||
if output.len() < outpos {
|
||||
return Err(ChorusError::BufferTooSmall.into());
|
||||
}
|
||||
|
||||
loop {
|
||||
// Write the offset of this tag
|
||||
let offset_slot = 4 + tag_num * 2;
|
||||
output[offset_slot..offset_slot + 2]
|
||||
.copy_from_slice((outpos as u16).to_ne_bytes().as_slice());
|
||||
put(
|
||||
output,
|
||||
offset_slot,
|
||||
(outpos as u16).to_ne_bytes().as_slice(),
|
||||
)?;
|
||||
|
||||
// Read the tag (bumps inpos and outpos)
|
||||
read_tag(input, inposp, output, &mut outpos)?;
|
||||
@ -176,7 +194,7 @@ pub fn read_tags_array(
|
||||
}
|
||||
|
||||
// Write length of tags section
|
||||
output[0..2].copy_from_slice((outpos as u16).to_ne_bytes().as_slice());
|
||||
put(output, 0, (outpos as u16).to_ne_bytes().as_slice())?;
|
||||
|
||||
Ok(outpos)
|
||||
}
|
||||
@ -228,7 +246,7 @@ pub fn read_tag(
|
||||
// read string
|
||||
let (inlen, outlen) = json_unescape(&input[*inposp..], &mut output[*outposp + 2..])?;
|
||||
// write the length before it
|
||||
output[*outposp..*outposp + 2].copy_from_slice((outlen as u16).to_ne_bytes().as_slice());
|
||||
put(output, *outposp, (outlen as u16).to_ne_bytes().as_slice())?;
|
||||
// bump the outposp past it
|
||||
*outposp += 2 + outlen;
|
||||
// bump the inpos past the string (and the ending quote which isn't counted in the len)
|
||||
@ -252,7 +270,11 @@ pub fn read_tag(
|
||||
}
|
||||
|
||||
// Write the count of strings at the very start
|
||||
output[countpos..countpos + 2].copy_from_slice((num_strings as u16).to_ne_bytes().as_slice());
|
||||
put(
|
||||
output,
|
||||
countpos,
|
||||
(num_strings as u16).to_ne_bytes().as_slice(),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -270,16 +292,20 @@ pub fn read_content(
|
||||
*inposp += inlen + 1; // +1 to pass the end quote
|
||||
|
||||
// Write content length
|
||||
output[after_tags..after_tags + 4].copy_from_slice((outlen as u32).to_ne_bytes().as_slice());
|
||||
put(output, after_tags, (outlen as u32).to_ne_bytes().as_slice())?;
|
||||
|
||||
// Write event size
|
||||
let event_len = after_tags + 4 + outlen;
|
||||
output[0..4].copy_from_slice((event_len as u32).to_ne_bytes().as_slice());
|
||||
put(output, 0, (event_len as u32).to_ne_bytes().as_slice())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// FIXME this is too event-offset specific
|
||||
pub fn read_sig(input: &[u8], inposp: &mut usize, output: &mut [u8]) -> Result<(), Error> {
|
||||
if output.len() < 144 {
|
||||
return Err(ChorusError::BufferTooSmall.into());
|
||||
}
|
||||
verify_char(input, b'"', inposp)?;
|
||||
if *inposp + 128 >= input.len() {
|
||||
return Err(ChorusError::JsonBad("Too short reading sig", *inposp).into());
|
||||
|
||||
@ -3,3 +3,13 @@ pub mod json_escape;
|
||||
pub mod json_parse;
|
||||
|
||||
pub mod utf8;
|
||||
|
||||
#[inline]
|
||||
pub fn put(output: &mut [u8], offset: usize, data: &[u8]) -> Result<(), crate::error::Error> {
|
||||
if output.len() < offset + data.len() {
|
||||
Err(crate::error::ChorusError::BufferTooSmall.into())
|
||||
} else {
|
||||
output[offset..offset + data.len()].copy_from_slice(data);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user