use crate::ffi::errors::{ErrorHandle, Status};
use crate::ffi::models::HeaderCase;
use crate::ffi::{Buffer, Slice};
use crate::models::{Headers, Message, Method, Version};
use crate::protocol::h1::{BodyLength, Chunk, Field, Number, Octets, Persistence, StartLine};
#[repr(C)]
#[derive(Clone, Copy)]
pub struct H1Limits {
pub max_message_size: u64,
pub max_message_body_size: u64,
pub max_decompressed_body_size: u64,
pub max_startline_size: u32,
pub max_headers_size: u64,
pub max_header_count: u16,
pub max_chunk_header_size: u32,
pub inline_body_size: u64,
pub max_concurrent_streams: u32,
pub read_chunk_size: u64,
pub idle_capacity: u64,
pub read_timeout: f64,
pub write_timeout: f64,
pub receive_timeout: f64,
pub send_timeout: f64,
}
impl H1Limits {
pub fn build(limits: &crate::protocol::h1::H1Limits) -> Self {
Self {
max_message_size: limits.max_message_size,
max_message_body_size: limits.max_message_body_size,
max_decompressed_body_size: limits.max_decompressed_body_size,
max_startline_size: limits.max_startline_size,
max_headers_size: limits.max_headers_size,
max_header_count: limits.max_header_count,
max_chunk_header_size: limits.max_chunk_header_size,
inline_body_size: limits.inline_body_size,
max_concurrent_streams: limits.max_concurrent_streams,
read_chunk_size: limits.read_chunk_size,
idle_capacity: limits.idle_capacity,
read_timeout: limits.read_timeout,
write_timeout: limits.write_timeout,
receive_timeout: limits.receive_timeout,
send_timeout: limits.send_timeout,
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn soyokaze_h1_limits_default() -> H1Limits {
H1Limits::build(&crate::protocol::h1::H1Limits::default())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_h1_limits_of(limits: *const crate::ffi::models::Limits) -> H1Limits {
H1Limits::build(&crate::protocol::h1::H1Limits::from(unsafe { crate::ffi::models::Limits::or_default(limits) }))
}
#[unsafe(no_mangle)]
pub extern "C" fn soyokaze_h1_token() -> u8 {
Octets::TOKEN
}
#[unsafe(no_mangle)]
pub extern "C" fn soyokaze_h1_field() -> u8 {
Octets::FIELD
}
#[unsafe(no_mangle)]
pub extern "C" fn soyokaze_h1_octet_table() -> Slice {
Slice::new(Octets::TABLE)
}
#[unsafe(no_mangle)]
pub extern "C" fn soyokaze_h1_is_control(octet: u8) -> bool {
Octets::is_control(octet)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_h1_is_token(text: *const u8, text_len: usize) -> bool {
Octets::is_token_bytes(unsafe { Slice::borrow(text, text_len) }.unwrap_or_default())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_h1_keep_alive(headers: *const Headers, version: i32) -> bool {
let version = Version::of(version);
Persistence::keep_alive(unsafe { headers.as_ref() }, version)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_h1_start_line_encode(message: *const Message) -> Buffer {
let Some(message) = (unsafe { message.as_ref() }) else {
return Buffer::EMPTY;
};
match StartLine::encode(message) {
Ok(line) => Buffer::new(line.into_bytes()),
Err(_) => Buffer::EMPTY,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_h1_start_line_parse(line: *const u8, line_len: usize, out: *mut *mut Message, error: *mut *mut ErrorHandle) -> Status {
let Some(line) = (unsafe { Slice::borrow(line, line_len) }) else {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
};
match StartLine::parse_bytes(line) {
Ok(message) => {
if !out.is_null() {
unsafe { *out = Box::into_raw(Box::new(message)) };
}
Status::Ok
}
Err(failure) => unsafe { ErrorHandle::report(error, &failure) },
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_h1_start_line_error_status(line: *const u8, line_len: usize) -> u16 {
StartLine::error_status_bytes(unsafe { Slice::borrow(line, line_len) }.unwrap_or_default())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_h1_version_parse(text: *const u8, text_len: usize, out: *mut Version, error: *mut *mut ErrorHandle) -> Status {
let Some(text) = (unsafe { Slice::borrow_text(text, text_len) }) else {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
};
match StartLine::version(text) {
Ok(version) => {
if !out.is_null() {
unsafe { *out = version };
}
Status::Ok
}
Err(failure) => unsafe { ErrorHandle::report(error, &failure) },
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_h1_field_encode(name: *const u8, name_len: usize, value: *const u8, value_len: usize, header_case: i32) -> Buffer {
let header_case = HeaderCase::of(header_case);
let (Some(name), Some(value)) = (unsafe { Slice::borrow_text(name, name_len) }, unsafe { Slice::borrow_text(value, value_len) }) else {
return Buffer::EMPTY;
};
match Field::encode(name, value, header_case.parse()) {
Ok(line) => Buffer::new(line.into_bytes()),
Err(_) => Buffer::EMPTY,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_h1_field_encode_all(headers: *const Headers, header_case: i32) -> Buffer {
let header_case = HeaderCase::of(header_case);
let Some(headers) = (unsafe { headers.as_ref() }) else {
return Buffer::EMPTY;
};
match Field::encode_all(headers, header_case.parse()) {
Ok(block) => Buffer::new(block.into_bytes()),
Err(_) => Buffer::EMPTY,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_h1_field_size(headers: *const Headers) -> u64 {
match unsafe { headers.as_ref() } {
Some(headers) => Field::size(headers),
None => 0,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_h1_field_parse(line: *const u8, line_len: usize, name: *mut Buffer, value: *mut Buffer, error: *mut *mut ErrorHandle) -> Status {
let Some(line) = (unsafe { Slice::borrow(line, line_len) }) else {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
};
match Field::parse_bytes(line) {
Ok((parsed_name, parsed_value)) => {
if !name.is_null() {
unsafe { *name = Buffer::new(parsed_name.into_bytes()) };
}
if !value.is_null() {
unsafe { *value = Buffer::new(parsed_value.into_bytes()) };
}
Status::Ok
}
Err(failure) => unsafe { ErrorHandle::report(error, &failure) },
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_h1_field_parse_block(block: *const u8, block_len: usize, max_count: usize, out: *mut *mut Headers, error: *mut *mut ErrorHandle) -> Status {
let Some(block) = (unsafe { Slice::borrow(block, block_len) }) else {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
};
match Field::parse_block(block, max_count) {
Ok(headers) => {
if !out.is_null() {
unsafe { *out = Box::into_raw(Box::new(headers)) };
}
Status::Ok
}
Err(failure) => unsafe { ErrorHandle::report(error, &failure) },
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_h1_field_block_end(data: *const u8, data_len: usize, searched: *mut usize, fields_end: *mut usize, section_end: *mut usize) -> bool {
let data = unsafe { Slice::borrow(data, data_len) }.unwrap_or_default();
let mut looked = if searched.is_null() { 0 } else { unsafe { *searched } };
let found = Field::block_end(data, &mut looked);
if !searched.is_null() {
unsafe { *searched = looked };
}
let Some((fields, section)) = found else {
return false;
};
if !fields_end.is_null() {
unsafe { *fields_end = fields };
}
if !section_end.is_null() {
unsafe { *section_end = section };
}
true
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_h1_chunk_encode(data: *const u8, data_len: usize) -> Buffer {
Buffer::new(Chunk::encode(unsafe { Slice::borrow(data, data_len) }.unwrap_or_default()))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_h1_chunk_parse_size(data: *const u8, data_len: usize, size: *mut usize, read: *mut usize, error: *mut *mut ErrorHandle) -> Status {
let Some(data) = (unsafe { Slice::borrow(data, data_len) }) else {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
};
match Chunk::parse_size(data) {
Ok(Some((chunk_size, consumed))) => {
if !size.is_null() {
unsafe { *size = chunk_size };
}
if !read.is_null() {
unsafe { *read = consumed };
}
Status::Ok
}
Ok(None) => Status::Closed,
Err(failure) => unsafe { ErrorHandle::report(error, &failure) },
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_h1_chunk_decode(data: *const u8, data_len: usize, start: *mut usize, end: *mut usize, read: *mut usize, error: *mut *mut ErrorHandle) -> Status {
let Some(data) = (unsafe { Slice::borrow(data, data_len) }) else {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
};
match Chunk::decode(data) {
Ok((consumed, span)) => {
if !start.is_null() {
unsafe { *start = span.start };
}
if !end.is_null() {
unsafe { *end = span.end };
}
if !read.is_null() {
unsafe { *read = consumed };
}
Status::Ok
}
Err(failure) => unsafe { ErrorHandle::report(error, &failure) },
}
}
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum BodyKind {
None = 0,
Chunked = 1,
Fixed = 2,
Close = 3,
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_h1_body_length(message: *const Message, method: i32, kind: *mut BodyKind, length: *mut u64, error: *mut *mut ErrorHandle) -> Status {
let Some(message) = (unsafe { message.as_ref() }) else {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
};
match BodyLength::of(message, Method::from_code(method)) {
Ok(framing) => {
let (framed, fixed) = match framing {
BodyLength::None => (BodyKind::None, 0),
BodyLength::Chunked => (BodyKind::Chunked, 0),
BodyLength::Fixed(length) => (BodyKind::Fixed, length),
BodyLength::Close => (BodyKind::Close, 0),
};
if !kind.is_null() {
unsafe { *kind = framed };
}
if !length.is_null() {
unsafe { *length = fixed };
}
Status::Ok
}
Err(failure) => unsafe { ErrorHandle::report(error, &failure) },
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn soyokaze_h1_content_length(value: *const u8, value_len: usize, out: *mut u64, error: *mut *mut ErrorHandle) -> Status {
let Some(value) = (unsafe { Slice::borrow_text(value, value_len) }) else {
return unsafe { ErrorHandle::raise(error, Status::Invalid) };
};
match BodyLength::content_length(value) {
Ok(length) => {
if !out.is_null() {
unsafe { *out = length };
}
Status::Ok
}
Err(failure) => unsafe { ErrorHandle::report(error, &failure) },
}
}
#[unsafe(no_mangle)]
pub extern "C" fn soyokaze_h1_decimal(value: u64) -> Buffer {
let mut digits = [0u8; 20];
let at = Number::decimal(value, &mut digits);
Buffer::new(digits[at..].to_vec())
}
#[unsafe(no_mangle)]
pub extern "C" fn soyokaze_h1_hexadecimal(value: u64) -> Buffer {
let mut digits = [0u8; 16];
let at = Number::hexadecimal(value, &mut digits);
Buffer::new(digits[at..].to_vec())
}