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
|
/// Returns the count of consumed bytes and output bytes
|
||||||
pub fn parse_json_event(input: &[u8], output: &mut [u8]) -> Result<(usize, usize), Error> {
|
pub fn parse_json_event(input: &[u8], output: &mut [u8]) -> Result<(usize, usize), Error> {
|
||||||
// Minimum-sized JSON event is 204 characters long
|
// Minimum-sized JSON event is 204 characters long
|
||||||
// NOTE: 152 is the minimum binary event
|
|
||||||
if input.len() < 204 {
|
if input.len() < 204 {
|
||||||
return Err(ChorusError::JsonBadEvent("Too Short", 0).into());
|
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.
|
// This tracks where we are currently looking in the input as we scan forward.
|
||||||
// It is short for INput POSition.
|
// It is short for INput POSition.
|
||||||
let mut inpos = 0;
|
let mut inpos = 0;
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use crate::error::{ChorusError, Error};
|
use crate::error::{ChorusError, Error};
|
||||||
use crate::types::parse::json_escape::json_unescape;
|
use crate::types::parse::json_escape::json_unescape;
|
||||||
use crate::types::parse::json_parse::*;
|
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.
|
/// 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
|
/// 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
|
// Start structure with that of an empty filter
|
||||||
output[0..32].copy_from_slice(&[
|
put(
|
||||||
0, 0, // length (we will fill it in later)
|
output,
|
||||||
0, 0, // 0 ids
|
0,
|
||||||
0, 0, // 0 authors
|
&[
|
||||||
0, 0, // 0 kinds
|
0, 0, // length (we will fill it in later)
|
||||||
255, 255, 255, 255, // max limit
|
0, 0, // 0 ids
|
||||||
0, 0, 0, 0, // padding
|
0, 0, // 0 authors
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, // since 1970
|
0, 0, // 0 kinds
|
||||||
255, 255, 255, 255, 255, 255, 255, 255, // until max unixtime
|
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;
|
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)?;
|
eat_colon_with_whitespace(input, &mut inpos)?;
|
||||||
let since = read_u64(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;
|
found |= HAVE_SINCE;
|
||||||
} else if inpos + 6 <= input.len() && &input[inpos..inpos + 6] == b"until\"" {
|
} 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)?;
|
eat_colon_with_whitespace(input, &mut inpos)?;
|
||||||
let until = read_u64(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;
|
found |= HAVE_UNTIL;
|
||||||
} else if inpos + 6 <= input.len() && &input[inpos..inpos + 6] == b"limit\"" {
|
} 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)?;
|
eat_colon_with_whitespace(input, &mut inpos)?;
|
||||||
let limit = read_u64(input, &mut inpos)?;
|
let limit = read_u64(input, &mut inpos)?;
|
||||||
let limit: u32 = limit as u32;
|
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;
|
found |= HAVE_LIMIT;
|
||||||
} else if inpos + 3 <= input.len()
|
} 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
|
// 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
|
// Copy authors
|
||||||
@ -236,7 +241,7 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write num_authors
|
// 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
|
// 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(),
|
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;
|
num_kinds += 1;
|
||||||
end += 2;
|
end += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// write num_kinds
|
// 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
|
// Copy tags
|
||||||
{
|
{
|
||||||
let write_tags_start = end;
|
let write_tags_start = end;
|
||||||
// write number of tags
|
// write number of tags
|
||||||
output[write_tags_start + 2..write_tags_start + 4]
|
put(
|
||||||
.copy_from_slice((num_tag_fields as u16).to_ne_bytes().as_slice());
|
output,
|
||||||
|
write_tags_start + 2,
|
||||||
|
(num_tag_fields as u16).to_ne_bytes().as_slice(),
|
||||||
|
)?;
|
||||||
// bump end past offset fields
|
// bump end past offset fields
|
||||||
end += 4 + 2 * num_tag_fields;
|
end += 4 + 2 * num_tag_fields;
|
||||||
// Now pull in each tag
|
// Now pull in each tag
|
||||||
|
#[allow(clippy::needless_range_loop)]
|
||||||
for w in 0..num_tag_fields {
|
for w in 0..num_tag_fields {
|
||||||
// Write it's offset
|
// Write it's offset
|
||||||
output[write_tags_start + 4 + (2 * w)..write_tags_start + 4 + (2 * w) + 2]
|
put(
|
||||||
.copy_from_slice(((end - write_tags_start) as u16).to_ne_bytes().as_slice());
|
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 mut inpos = start_tags[w];
|
||||||
let letter = input[inpos];
|
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
|
// bump past count output and write letter
|
||||||
let countindex = end;
|
let countindex = end;
|
||||||
end += 2;
|
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;
|
output[end + 2] = letter;
|
||||||
|
|
||||||
// bump past what we just wrote
|
// 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
|
// copy data
|
||||||
let (inlen, outlen) = json_unescape(&input[inpos..], &mut output[end + 2..])?;
|
let (inlen, outlen) = json_unescape(&input[inpos..], &mut output[end + 2..])?;
|
||||||
// write len
|
// 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;
|
end += 2 + outlen;
|
||||||
inpos += inlen + 1;
|
inpos += inlen + 1;
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// write count
|
// 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
|
// write length of tags section
|
||||||
output[write_tags_start..write_tags_start + 2]
|
put(
|
||||||
.copy_from_slice(((end - write_tags_start) as u16).to_ne_bytes().as_slice());
|
output,
|
||||||
|
write_tags_start,
|
||||||
|
((end - write_tags_start) as u16).to_ne_bytes().as_slice(),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if end > 65535 {
|
if end > 65535 {
|
||||||
@ -324,7 +342,7 @@ pub fn parse_json_filter(input: &[u8], output: &mut [u8]) -> Result<(usize, usiz
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write length of filter
|
// 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))
|
Ok((inpos, end))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use super::json_escape::json_unescape;
|
use super::json_escape::json_unescape;
|
||||||
|
use super::put;
|
||||||
use crate::error::{ChorusError, Error};
|
use crate::error::{ChorusError, Error};
|
||||||
|
|
||||||
#[inline]
|
#[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> {
|
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)?;
|
verify_char(input, b'"', inposp)?;
|
||||||
if *inposp + 64 >= input.len() {
|
if *inposp + 64 >= input.len() {
|
||||||
return Err(ChorusError::JsonBad("Too short reading id", *inposp).into());
|
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> {
|
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)?;
|
verify_char(input, b'"', inposp)?;
|
||||||
if *inposp + 64 >= input.len() {
|
if *inposp + 64 >= input.len() {
|
||||||
return Err(ChorusError::JsonBad("Too short reading pubkey", *inposp).into());
|
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
|
verify_char(input, b'[', inposp)?; // outer array open brace
|
||||||
eat_whitespace(input, inposp);
|
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.
|
// NOTE: we cannot write any tag strings until after we have counted the tags.
|
||||||
// (our tags structure is optimized for reading, not writing)
|
// (our tags structure is optimized for reading, not writing)
|
||||||
let num_tags: usize = count_tags(input, *inposp)?;
|
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
|
// Case where we have no tags
|
||||||
if num_tags == 0 {
|
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);
|
return Ok(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,11 +153,18 @@ pub fn read_tags_array(
|
|||||||
|
|
||||||
let mut tag_num = 0;
|
let mut tag_num = 0;
|
||||||
let mut outpos: usize = 4 + num_tags * 2;
|
let mut outpos: usize = 4 + num_tags * 2;
|
||||||
|
if output.len() < outpos {
|
||||||
|
return Err(ChorusError::BufferTooSmall.into());
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Write the offset of this tag
|
// Write the offset of this tag
|
||||||
let offset_slot = 4 + tag_num * 2;
|
let offset_slot = 4 + tag_num * 2;
|
||||||
output[offset_slot..offset_slot + 2]
|
put(
|
||||||
.copy_from_slice((outpos as u16).to_ne_bytes().as_slice());
|
output,
|
||||||
|
offset_slot,
|
||||||
|
(outpos as u16).to_ne_bytes().as_slice(),
|
||||||
|
)?;
|
||||||
|
|
||||||
// Read the tag (bumps inpos and outpos)
|
// Read the tag (bumps inpos and outpos)
|
||||||
read_tag(input, inposp, output, &mut outpos)?;
|
read_tag(input, inposp, output, &mut outpos)?;
|
||||||
@ -176,7 +194,7 @@ pub fn read_tags_array(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write length of tags section
|
// 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)
|
Ok(outpos)
|
||||||
}
|
}
|
||||||
@ -228,7 +246,7 @@ pub fn read_tag(
|
|||||||
// read string
|
// read string
|
||||||
let (inlen, outlen) = json_unescape(&input[*inposp..], &mut output[*outposp + 2..])?;
|
let (inlen, outlen) = json_unescape(&input[*inposp..], &mut output[*outposp + 2..])?;
|
||||||
// write the length before it
|
// 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
|
// bump the outposp past it
|
||||||
*outposp += 2 + outlen;
|
*outposp += 2 + outlen;
|
||||||
// bump the inpos past the string (and the ending quote which isn't counted in the len)
|
// 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
|
// 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -270,16 +292,20 @@ pub fn read_content(
|
|||||||
*inposp += inlen + 1; // +1 to pass the end quote
|
*inposp += inlen + 1; // +1 to pass the end quote
|
||||||
|
|
||||||
// Write content length
|
// 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
|
// Write event size
|
||||||
let event_len = after_tags + 4 + outlen;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME this is too event-offset specific
|
||||||
pub fn read_sig(input: &[u8], inposp: &mut usize, output: &mut [u8]) -> Result<(), Error> {
|
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)?;
|
verify_char(input, b'"', inposp)?;
|
||||||
if *inposp + 128 >= input.len() {
|
if *inposp + 128 >= input.len() {
|
||||||
return Err(ChorusError::JsonBad("Too short reading sig", *inposp).into());
|
return Err(ChorusError::JsonBad("Too short reading sig", *inposp).into());
|
||||||
|
|||||||
@ -3,3 +3,13 @@ pub mod json_escape;
|
|||||||
pub mod json_parse;
|
pub mod json_parse;
|
||||||
|
|
||||||
pub mod utf8;
|
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