use crate::body::BodyHandle;
use crate::request::RequestHandle;
use crate::response::ResponseHandle;
use crate::Error;
use bytes::{Buf, Bytes, BytesMut};
pub use fastly_shared::{HttpVersion, XqdStatus, XQD_ABI_VERSION};
#[link(wasm_import_module = "env")]
extern "C" {
#[no_mangle]
pub fn xqd_body_append(dst_handle: BodyHandle, src_handle: BodyHandle) -> XqdStatus;
#[no_mangle]
pub fn xqd_body_new(handle_out: *mut BodyHandle) -> XqdStatus;
#[no_mangle]
pub fn xqd_body_read(
body_handle: BodyHandle,
buf: *mut u8,
buf_len: usize,
nread_out: *mut usize,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_body_write(
body_handle: BodyHandle,
buf: *const u8,
buf_len: usize,
end: fastly_shared::BodyWriteEnd,
nwritten_out: *mut usize,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_init(abi_version: u64) -> XqdStatus;
#[no_mangle]
pub fn xqd_req_body_downstream_get(
req_handle_out: *mut RequestHandle,
body_handle_out: *mut BodyHandle,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_req_header_append(
req_handle: RequestHandle,
name: *const u8,
name_len: usize,
value: *const u8,
value_len: usize,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_req_header_insert(
req_handle: RequestHandle,
name: *const u8,
name_len: usize,
value: *const u8,
value_len: usize,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_req_header_names_get(
req_handle: RequestHandle,
buf: *mut u8,
buf_len: usize,
cursor: u32,
ending_cursor: *mut i64,
nwritten: *mut usize,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_req_header_values_get(
req_handle: RequestHandle,
name: *const u8,
name_len: usize,
buf: *mut u8,
buf_len: usize,
cursor: u32,
ending_cursor: *mut i64,
nwritten: *mut usize,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_req_header_values_set(
req_handle: RequestHandle,
name: *const u8,
name_len: usize,
values: *const u8,
values_len: usize,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_req_method_get(
req_handle: RequestHandle,
method: *mut u8,
method_max_len: usize,
nwritten: *mut usize,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_req_method_set(
req_handle: RequestHandle,
method: *const u8,
method_len: usize,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_req_new(req_handle_out: *mut RequestHandle) -> XqdStatus;
#[no_mangle]
pub fn xqd_req_send(
req_handle: RequestHandle,
body_handle: BodyHandle,
backend: *const u8,
backend_len: usize,
ttl: i32,
resp_handle_out: *mut ResponseHandle,
resp_body_handle_out: *mut BodyHandle,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_req_uri_get(
req_handle: RequestHandle,
uri: *mut u8,
uri_max_len: usize,
nwritten: *mut usize,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_req_uri_set(req_handle: RequestHandle, uri: *const u8, uri_len: usize) -> XqdStatus;
#[no_mangle]
pub fn xqd_req_version_get(req_handle: RequestHandle, version: *mut u32) -> XqdStatus;
#[no_mangle]
pub fn xqd_req_version_set(req_handle: RequestHandle, version: u32) -> XqdStatus;
#[no_mangle]
pub fn xqd_resp_header_append(
resp_handle: ResponseHandle,
name: *const u8,
name_len: usize,
value: *const u8,
value_len: usize,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_resp_header_insert(
resp_handle: ResponseHandle,
name: *const u8,
name_len: usize,
value: *const u8,
value_len: usize,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_resp_header_names_get(
resp_handle: ResponseHandle,
buf: *mut u8,
buf_len: usize,
cursor: u32,
ending_cursor: *mut i64,
nwritten: *mut usize,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_resp_header_value_get(
resp_handle: ResponseHandle,
name: *const u8,
name_len: usize,
value: *mut u8,
value_max_len: usize,
nwritten: *mut usize,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_resp_header_values_get(
resp_handle: ResponseHandle,
name: *const u8,
name_len: usize,
buf: *mut u8,
buf_len: usize,
cursor: u32,
ending_cursor: *mut i64,
nwritten: *mut usize,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_resp_header_values_set(
resp_handle: ResponseHandle,
name: *const u8,
name_len: usize,
values: *const u8,
values_len: usize,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_resp_new(resp_handle_out: *mut ResponseHandle) -> XqdStatus;
#[no_mangle]
pub fn xqd_resp_send_downstream(
resp_handle: ResponseHandle,
body_handle: BodyHandle,
) -> XqdStatus;
#[no_mangle]
pub fn xqd_resp_status_get(resp_handle: ResponseHandle, status: *mut u16) -> XqdStatus;
#[no_mangle]
pub fn xqd_resp_status_set(resp_handle: ResponseHandle, status: u16) -> XqdStatus;
#[no_mangle]
pub fn xqd_resp_version_get(resp_handle: ResponseHandle, version: *mut u32) -> XqdStatus;
#[no_mangle]
pub fn xqd_resp_version_set(resp_handle: ResponseHandle, version: u32) -> XqdStatus;
#[no_mangle]
pub fn xqd_uap_parse(
user_agent: *const u8,
user_agent_max_len: usize,
family: *mut u8,
family_max_len: usize,
family_written: *mut usize,
major: *mut u8,
major_max_len: usize,
major_written: *mut usize,
minor: *mut u8,
minor_max_len: usize,
minor_written: *mut usize,
patch: *mut u8,
patch_max_len: usize,
patch_written: *mut usize
) -> XqdStatus;
}
pub(crate) struct MultiValueHostcall<F> {
fill_buf: F,
term: u8,
buf: BytesMut,
max_buf_size: usize,
cursor: u32,
is_done: bool,
}
impl<F> MultiValueHostcall<F> {
pub(crate) fn new(term: u8, max_buf_size: usize, fill_buf: F) -> Self {
Self {
fill_buf,
term,
buf: BytesMut::with_capacity(max_buf_size),
max_buf_size,
cursor: 0,
is_done: false,
}
}
}
impl<F> std::iter::Iterator for MultiValueHostcall<F>
where
F: Fn(*mut u8, usize, u32, *mut i64, *mut usize) -> XqdStatus,
{
type Item = Result<Bytes, Error>;
fn next(&mut self) -> Option<Self::Item> {
if self.buf.is_empty() {
if self.is_done {
return None;
}
self.buf.reserve(self.max_buf_size);
let mut ending_cursor = 0;
let mut nwritten = 0;
let status = (self.fill_buf)(
self.buf.as_mut_ptr(),
self.buf.capacity(),
self.cursor,
&mut ending_cursor,
&mut nwritten,
);
if status.is_err() {
self.is_done = true;
return Some(Err(Error::new("MultiValueHostcall closure returned error")));
}
if nwritten == 0 {
self.is_done = true;
return None;
}
unsafe {
self.buf.set_len(nwritten);
}
if self.cursor == ending_cursor as u32 {
self.is_done = true;
return Some(Err(Error::new("MultiValueHostcall buffer too small")));
}
if ending_cursor < 0 {
self.is_done = true;
} else {
self.cursor += ending_cursor as u32;
}
}
let first_term_ix = if let Some(ix) = self.buf.iter().position(|b| b == &self.term) {
ix
} else {
self.is_done = true;
return Some(Err(Error::new(
"MultiValueHostcall separator byte not found",
)));
};
let elt = self.buf.split_to(first_term_ix);
self.buf.advance(1);
Some(Ok(elt.freeze()))
}
}
impl<F> std::iter::FusedIterator for MultiValueHostcall<F> where
F: Fn(*mut u8, usize, u32, *mut i64, *mut usize) -> XqdStatus
{
}