#![allow(unused_imports)]
extern crate alloc;
use alloc::ffi::CString;
use alloc::vec::Vec;
use alloc::{boxed::Box, format};
use core::cell::{Cell, RefCell};
use core::ffi::{c_char, c_uchar, c_void};
use core::fmt::Debug;
use core::ptr;
use core::str;
use core::{slice, slice::from_raw_parts};
use milo_macros::{callback, generate, next};
#[repr(C)]
#[derive(Clone, Debug)]
pub struct Parser {
pub autodetect: bool,
pub is_request: bool,
pub manage_unconsumed: bool,
pub continue_without_data: bool,
pub is_connect: bool,
pub skip_body: bool,
pub max_start_line_length: usize,
pub max_header_length: usize,
#[cfg(not(target_family = "wasm"))]
pub context: *mut c_void,
#[cfg(any(debug_assertions, feature = "debug"))]
pub debug: bool,
pub state: u8,
pub position: usize,
pub parsed: u64,
pub paused: bool,
pub error_code: u8,
pub method: u8,
pub status: u32,
pub version_major: u8,
pub version_minor: u8,
pub content_length: u64,
pub chunk_size: u64,
pub remaining_content_length: u64,
pub remaining_chunk_size: u64,
pub has_content_length: bool,
pub has_transfer_encoding: bool,
pub has_chunked_transfer_encoding: bool,
pub has_connection_close: bool,
pub has_connection_upgrade: bool,
pub has_upgrade: bool,
pub has_trailers: bool,
pub active_callbacks: u64,
#[cfg(not(target_family = "wasm"))]
pub callbacks: ParserCallbacks,
#[cfg(target_family = "wasm")]
pub ptr: *mut c_void,
pub error_description: *const c_uchar,
pub error_description_len: u16,
pub unconsumed: *const c_uchar,
pub unconsumed_len: usize,
}
#[cfg(not(target_family = "wasm"))]
mod native;
#[cfg(not(target_family = "wasm"))]
pub use crate::native::*;
#[cfg(target_family = "wasm")]
mod wasm;
#[cfg(target_family = "wasm")]
pub use crate::wasm::*;
generate!();
impl Parser {
pub fn new() -> Parser {
Parser {
autodetect: true,
is_request: false,
manage_unconsumed: false,
continue_without_data: false,
is_connect: false,
skip_body: false,
max_start_line_length: 8192,
max_header_length: 8192,
#[cfg(any(debug_assertions, feature = "debug"))]
debug: false,
#[cfg(not(target_family = "wasm"))]
context: ptr::null_mut(),
state: STATE_START,
position: 0,
parsed: 0,
paused: false,
error_code: ERROR_NONE,
method: 0,
status: 0,
version_major: 0,
version_minor: 0,
content_length: 0,
chunk_size: 0,
remaining_content_length: 0,
remaining_chunk_size: 0,
has_content_length: false,
has_transfer_encoding: false,
has_chunked_transfer_encoding: false,
has_connection_close: false,
has_connection_upgrade: false,
has_upgrade: false,
has_trailers: false,
active_callbacks: 0,
#[cfg(not(target_family = "wasm"))]
callbacks: ParserCallbacks::new(),
#[cfg(target_family = "wasm")]
ptr: ptr::null_mut(),
error_description: ptr::null(),
error_description_len: 0,
unconsumed: ptr::null(),
unconsumed_len: 0,
}
}
pub fn reset(&mut self, keep_parsed: bool) {
self.state = STATE_START;
self.paused = false;
if !keep_parsed {
self.parsed = 0;
}
self.error_code = ERROR_NONE;
if self.error_description_len > 0 {
unsafe {
let _ = slice::from_raw_parts(self.error_description, self.error_description_len as usize);
}
self.error_description = ptr::null();
self.error_description_len = 0;
}
if self.unconsumed_len > 0 {
unsafe {
let _ = slice::from_raw_parts(self.unconsumed, self.unconsumed_len);
}
self.unconsumed = ptr::null();
self.unconsumed_len = 0;
}
self.clear();
callback!(on_reset);
}
pub fn clear(&mut self) {
self.is_connect = false;
self.method = 0;
self.status = 0;
self.version_major = 0;
self.version_minor = 0;
self.has_content_length = false;
self.has_transfer_encoding = false;
self.has_chunked_transfer_encoding = false;
self.has_connection_close = false;
self.has_connection_upgrade = false;
self.has_upgrade = false;
self.has_trailers = false;
self.content_length = 0;
self.chunk_size = 0;
self.remaining_content_length = 0;
self.remaining_chunk_size = 0;
self.skip_body = false;
}
pub fn pause(&mut self) { self.paused = true; }
pub fn resume(&mut self) { self.paused = false; }
pub fn finish(&mut self) {
match self.state {
STATE_START | STATE_REQUEST_LINE | STATE_STATUS_LINE | STATE_FINISH => {
self.state = STATE_FINISH;
}
STATE_BODY_WITH_NO_LENGTH => {
callback!(on_message_complete);
self.state = STATE_FINISH;
}
STATE_ERROR => (),
_ => {
self.fail(ERROR_UNEXPECTED_EOF, "Unexpected end of data");
}
}
}
#[inline(always)]
pub fn fail(&mut self, code: u8, description: &str) {
let description_copy = description.to_string();
let (ptr, _, len) = description_copy.into_raw_parts();
self.state = STATE_ERROR;
self.error_code = code;
self.error_description = ptr;
self.error_description_len = len as u16;
callback!(on_error, 0, 0);
}
pub fn state_str(&self) -> &str { States::try_from(self.state).unwrap().as_str() }
pub fn error_code_str(&self) -> &str { Errors::try_from(self.error_code).unwrap().as_str() }
pub fn error_description_str(&self) -> &str {
unsafe {
if self.error_description_len > 0 {
str::from_utf8_unchecked(from_raw_parts(
self.error_description,
self.error_description_len as usize,
))
} else {
""
}
}
}
}
impl Default for Parser {
fn default() -> Self { Self::new() }
}
mod matchers;
mod parse;