pub(crate) use fastly_shared::{FastlyStatus, INVALID_BODY_HANDLE};
use crate::error::HandleError;
use super::super::handle::BodyHandle;
use std::io::Write;
use std::mem::ManuallyDrop;
use http::header::{HeaderMap, HeaderName, HeaderValue};
#[derive(Debug, Eq, Hash, PartialEq)]
#[repr(transparent)]
#[must_use = "streaming body handles must be `.finish()`ed"]
pub struct StreamingBodyHandle {
handle: ManuallyDrop<BodyHandle>,
}
impl StreamingBodyHandle {
pub fn finish(mut self) -> Result<(), HandleError> {
let handle = std::mem::replace(&mut self.handle.handle, INVALID_BODY_HANDLE);
match unsafe { fastly_sys::fastly_http_body::close(handle) } {
FastlyStatus::OK => Ok(()),
FastlyStatus::BADF => Err(HandleError::InvalidHandle),
other => panic!(
"unexpected error from `fastly_http_body::close`: {:?}; \
please report this as a bug",
other
),
}
}
pub fn abandon(mut self) -> Result<(), HandleError> {
let handle = std::mem::replace(&mut self.handle.handle, INVALID_BODY_HANDLE);
unsafe { abandon_handle(handle) }
}
pub fn from_body_handle(body_handle: BodyHandle) -> Self {
Self {
handle: ManuallyDrop::new(body_handle),
}
}
#[cfg_attr(
not(target_env = "p1"),
deprecated(
since = "0.11.6",
note = "This code will need to be updated for wasip2."
)
)]
pub unsafe fn as_u32(&self) -> u32 {
self.handle.as_u32()
}
#[cfg_attr(
not(target_env = "p1"),
deprecated(
since = "0.11.6",
note = "This code will need to be updated for wasip2."
)
)]
pub fn into_u32(self) -> u32 {
unsafe { ManuallyDrop::new(self).as_u32() }
}
pub(crate) fn into_body_handle(self) -> BodyHandle {
unsafe { BodyHandle::from_u32(self.into_u32()) }
}
#[doc = include_str!("../../../../docs/snippets/body-append-constant-time.md")]
pub fn append(&mut self, other: BodyHandle) {
self.handle.append(other)
}
pub(crate) fn set_trailers(&mut self, trailers: &HeaderMap) {
self.handle.trailers_replace(trailers);
}
pub(crate) fn append_trailer(&mut self, name: &HeaderName, value: &HeaderValue) {
self.handle.append_trailer(name, value);
}
}
impl Write for StreamingBodyHandle {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.handle.write(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
self.handle.flush()
}
}
impl Drop for StreamingBodyHandle {
fn drop(&mut self) {
let _ = unsafe { abandon_handle(self.as_u32()) };
}
}
#[inline(always)]
unsafe fn abandon_handle(handle: u32) -> Result<(), HandleError> {
if handle == INVALID_BODY_HANDLE {
return Err(HandleError::InvalidHandle);
}
match fastly_sys::fastly_http_body::abandon(handle) {
FastlyStatus::OK => Ok(()),
FastlyStatus::BADF => Err(HandleError::InvalidHandle),
other => panic!(
"unexpected error from `fastly_http_body::abandon`: {:?}; \
please report this as a bug",
other
),
}
}