|
|
|
@ -17,6 +17,7 @@
|
|
|
|
|
|
|
|
|
|
#![allow(clippy::missing_safety_doc)]
|
|
|
|
|
|
|
|
|
|
use std::collections::TryReserveError;
|
|
|
|
|
use std::ffi::CStr;
|
|
|
|
|
use std::os::raw::c_char;
|
|
|
|
|
use std::str::Utf8Error;
|
|
|
|
@ -27,6 +28,7 @@ const INIT_SIZE: usize = 4096;
|
|
|
|
|
pub enum JsonError {
|
|
|
|
|
InvalidState,
|
|
|
|
|
Utf8Error(Utf8Error),
|
|
|
|
|
Memory,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl std::error::Error for JsonError {}
|
|
|
|
@ -36,10 +38,17 @@ impl std::fmt::Display for JsonError {
|
|
|
|
|
match self {
|
|
|
|
|
JsonError::InvalidState => write!(f, "invalid state"),
|
|
|
|
|
JsonError::Utf8Error(ref e) => e.fmt(f),
|
|
|
|
|
JsonError::Memory => write!(f, "memory error"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<TryReserveError> for JsonError {
|
|
|
|
|
fn from(_: TryReserveError) -> Self {
|
|
|
|
|
JsonError::Memory
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<Utf8Error> for JsonError {
|
|
|
|
|
fn from(e: Utf8Error) -> Self {
|
|
|
|
|
JsonError::Utf8Error(e)
|
|
|
|
@ -427,6 +436,22 @@ impl JsonBuilder {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Set a key and a string value (from bytes) on an object, with a limited size
|
|
|
|
|
pub fn set_string_from_bytes_limited(&mut self, key: &str, val: &[u8], limit: usize) -> Result<&mut Self, JsonError> {
|
|
|
|
|
let mut valtrunc = Vec::new();
|
|
|
|
|
let val = if val.len() > limit {
|
|
|
|
|
valtrunc.extend_from_slice(&val[..limit]);
|
|
|
|
|
valtrunc.extend_from_slice(b"[truncated]");
|
|
|
|
|
&valtrunc
|
|
|
|
|
} else {
|
|
|
|
|
val
|
|
|
|
|
};
|
|
|
|
|
match std::str::from_utf8(val) {
|
|
|
|
|
Ok(s) => self.set_string(key, s),
|
|
|
|
|
Err(_) => self.set_string(key, &try_string_from_bytes(val)?),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Set a key and an unsigned integer type on an object.
|
|
|
|
|
pub fn set_uint(&mut self, key: &str, val: u64) -> Result<&mut Self, JsonError> {
|
|
|
|
|
match self.current_state() {
|
|
|
|
@ -570,6 +595,26 @@ fn string_from_bytes(input: &[u8]) -> String {
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A Suricata specific function to create a string from bytes when UTF-8 decoding fails.
|
|
|
|
|
///
|
|
|
|
|
/// For bytes over 0x0f, we encode as hex like "\xf2".
|
|
|
|
|
fn try_string_from_bytes(input: &[u8]) -> Result<String, JsonError> {
|
|
|
|
|
let mut out = String::new();
|
|
|
|
|
|
|
|
|
|
// Allocate enough data to handle the worst case scenario of every
|
|
|
|
|
// byte needing to be presented as a byte.
|
|
|
|
|
out.try_reserve(input.len() * 4)?;
|
|
|
|
|
|
|
|
|
|
for b in input.iter() {
|
|
|
|
|
if *b < 128 {
|
|
|
|
|
out.push(*b as char);
|
|
|
|
|
} else {
|
|
|
|
|
out.push_str(&format!("\\x{:02x}", *b));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Ok(out);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
|
pub extern "C" fn jb_new_object() -> *mut JsonBuilder {
|
|
|
|
|
let boxed = Box::new(JsonBuilder::new_object());
|
|
|
|
|