use core::ffi::{c_int, c_void};
use core::marker::{PhantomData, PhantomPinned};
use crate::thunk;
use crate::thunk::OpaqueHandle;
use crate::us_socket_t;
use bun_core::{BoundedArray, Fd};
pub struct SocketAddress {
ip: BoundedArray<u8, 64>,
pub port: i32,
pub is_ipv6: bool,
}
impl SocketAddress {
pub(crate) fn new(ip: &[u8], port: i32, is_ipv6: bool) -> SocketAddress {
let ip = &ip[..ip.len().min(64)];
SocketAddress {
ip: BoundedArray::from_slice(ip).expect("clamped to capacity"),
port,
is_ipv6,
}
}
pub fn ip(&self) -> &[u8] {
self.ip.as_slice()
}
pub fn is_loopback(&self) -> bool {
let ip = self.ip();
if ip.starts_with(b"127.") {
return true;
}
if ip.starts_with(b"::ffff:127.") || ip == b"::1" || ip == b"0:0:0:0:0:0:0:1" {
return true;
}
false
}
}
bun_opaque::opaque_ffi! {
pub struct Socket;
pub(crate) struct SocketData;
pub struct WebSocketUpgradeContext;
}
#[repr(C)]
pub struct Response<const SSL: bool> {
_p: core::cell::UnsafeCell<[u8; 0]>,
_m: PhantomData<(*mut u8, PhantomPinned)>,
}
impl<const SSL: bool> Response<SSL> {
#[inline(always)]
const fn ssl_flag() -> i32 {
SSL as i32
}
#[inline]
pub fn cast_res(res: *mut c::uws_res) -> *mut Response<SSL> {
res.cast::<Response<SSL>>()
}
#[inline]
pub fn downcast(&mut self) -> *mut c::uws_res {
std::ptr::from_mut::<Self>(self).cast::<c::uws_res>()
}
#[inline]
fn as_raw(&mut self) -> &mut c::uws_res {
unsafe { &mut *std::ptr::from_mut::<Self>(self).cast::<c::uws_res>() }
}
#[inline]
pub fn downcast_socket(&mut self) -> *mut us_socket_t {
std::ptr::from_mut::<Self>(self).cast::<us_socket_t>()
}
pub fn end(&mut self, data: &[u8], close_connection: bool) {
unsafe {
c::uws_res_end(
Self::ssl_flag(),
self.downcast(),
data.as_ptr(),
data.len(),
close_connection,
);
}
}
pub fn try_end(&mut self, data: &[u8], total: usize, close_: bool) -> bool {
unsafe {
c::uws_res_try_end(
Self::ssl_flag(),
self.downcast(),
data.as_ptr(),
data.len(),
total,
close_,
)
}
}
pub fn get_socket_data(&mut self) -> *mut c_void {
c::uws_res_get_socket_data(Self::ssl_flag(), self.as_raw()).cast()
}
pub fn is_connect_request(&mut self) -> bool {
c::uws_res_is_connect_request(Self::ssl_flag(), self.as_raw())
}
pub fn flush_headers(&mut self, flush_immediately: bool) {
c::uws_res_flush_headers(Self::ssl_flag(), self.as_raw(), flush_immediately)
}
pub fn is_corked(&mut self) -> bool {
c::uws_res_is_corked(Self::ssl_flag(), self.as_raw())
}
pub fn state(&self) -> State {
c::uws_res_state(Self::ssl_flag() as c_int, unsafe {
&*std::ptr::from_ref::<Self>(self).cast::<c::uws_res>()
})
}
pub fn should_close_connection(&self) -> bool {
self.state().is_http_connection_close()
}
pub fn prepare_for_sendfile(&mut self) {
c::uws_res_prepare_for_sendfile(Self::ssl_flag(), self.as_raw())
}
pub fn uncork(&mut self) {
c::uws_res_uncork(Self::ssl_flag(), self.as_raw())
}
pub fn pause(&mut self) {
c::uws_res_pause(Self::ssl_flag(), self.as_raw())
}
pub fn resume_(&mut self) {
c::uws_res_resume(Self::ssl_flag(), self.as_raw())
}
pub fn write_continue(&mut self) {
c::uws_res_write_continue(Self::ssl_flag(), self.as_raw())
}
pub fn write_status(&mut self, status: &[u8]) {
unsafe {
c::uws_res_write_status(
Self::ssl_flag(),
self.downcast(),
status.as_ptr(),
status.len(),
)
}
}
pub fn write_header(&mut self, key: &[u8], value: &[u8]) {
unsafe {
c::uws_res_write_header(
Self::ssl_flag(),
self.downcast(),
key.as_ptr(),
key.len(),
value.as_ptr(),
value.len(),
)
}
}
pub fn write_header_int(&mut self, key: &[u8], value: u64) {
unsafe {
c::uws_res_write_header_int(
Self::ssl_flag(),
self.downcast(),
key.as_ptr(),
key.len(),
value,
)
}
}
pub fn end_without_body(&mut self, close_connection: bool) {
c::uws_res_end_without_body(Self::ssl_flag(), self.as_raw(), close_connection)
}
pub fn end_send_file(&mut self, write_offset: u64, close_connection: bool) {
c::uws_res_end_sendfile(
Self::ssl_flag(),
self.as_raw(),
write_offset,
close_connection,
)
}
pub fn timeout(&mut self, seconds: u8) {
c::uws_res_timeout(Self::ssl_flag(), self.as_raw(), seconds)
}
pub fn reset_timeout(&mut self) {
c::uws_res_reset_timeout(Self::ssl_flag(), self.as_raw())
}
pub fn get_buffered_amount(&mut self) -> u64 {
c::uws_res_get_buffered_amount(Self::ssl_flag(), self.as_raw())
}
pub fn write(&mut self, data: &[u8]) -> WriteResult {
let mut len: usize = data.len();
match unsafe {
c::uws_res_write(
Self::ssl_flag(),
self.downcast(),
data.as_ptr(),
&raw mut len,
)
} {
true => WriteResult::WantMore(len),
false => WriteResult::Backpressure(len),
}
}
pub fn get_write_offset(&mut self) -> u64 {
c::uws_res_get_write_offset(Self::ssl_flag(), self.as_raw())
}
pub fn override_write_offset<T>(&mut self, offset: T)
where
u64: TryFrom<T>,
<u64 as TryFrom<T>>::Error: core::fmt::Debug,
{
c::uws_res_override_write_offset(
Self::ssl_flag(),
self.as_raw(),
u64::try_from(offset).expect("int cast"),
)
}
pub fn has_responded(&mut self) -> bool {
c::uws_res_has_responded(Self::ssl_flag(), self.as_raw())
}
pub fn mark_wrote_content_length_header(&mut self) {
c::uws_res_mark_wrote_content_length_header(Self::ssl_flag(), self.as_raw())
}
pub fn write_mark(&mut self) {
c::uws_res_write_mark(Self::ssl_flag(), self.as_raw())
}
pub fn get_native_handle(&mut self) -> Fd {
#[cfg(windows)]
{
return Fd::from_system(
c::uws_res_get_native_handle(Self::ssl_flag(), self.as_raw())
as *mut core::ffi::c_void,
);
}
#[cfg(not(windows))]
{
Fd::from_native(
c_int::try_from(
c::uws_res_get_native_handle(Self::ssl_flag(), self.as_raw()) as usize,
)
.unwrap(),
)
}
}
pub fn get_remote_address_as_text(&mut self) -> Option<&[u8]> {
let mut buf: *const u8 = core::ptr::null();
let size = c::uws_res_get_remote_address_as_text(Self::ssl_flag(), self.as_raw(), &mut buf);
if size > 0 {
Some(unsafe { bun_core::ffi::slice(buf, size) })
} else {
None
}
}
pub fn get_remote_socket_info(&mut self) -> Option<SocketAddress> {
let mut ip_ptr: *const u8 = core::ptr::null();
let mut port: i32 = 0;
let mut is_ipv6: bool = false;
let ip_len =
c::uws_res_get_remote_address_info(self.as_raw(), &mut ip_ptr, &mut port, &mut is_ipv6);
if ip_len > 0 {
Some(SocketAddress::new(
unsafe { bun_core::ffi::slice(ip_ptr, ip_len) },
port,
is_ipv6,
))
} else {
None
}
}
pub fn on_writable<U, H>(&mut self, _handler: H, user_data: *mut U)
where
H: Fn(*mut U, u64, &mut Response<SSL>) -> bool + Copy + 'static,
{
extern "C" fn handle<U, H, const SSL: bool>(
this: *mut c::uws_res,
amount: u64,
data: *mut c_void,
) -> bool
where
H: Fn(*mut U, u64, &mut Response<SSL>) -> bool + Copy + 'static,
{
if data.is_null() {
return true;
}
unsafe {
thunk::zst::<H>()(
data.cast::<U>(),
amount,
thunk::handle_mut(Response::<SSL>::cast_res(this)),
)
}
}
c::uws_res_on_writable(
Self::ssl_flag(),
self.as_raw(),
Some(handle::<U, H, SSL>),
user_data.cast(),
);
}
pub fn clear_on_writable(&mut self) {
c::uws_res_clear_on_writable(Self::ssl_flag(), self.as_raw())
}
#[inline]
pub fn mark_needs_more(&mut self) {
if !SSL {
c::us_socket_mark_needs_more_not_ssl(self.as_raw())
}
}
pub fn on_aborted<U, H>(&mut self, _handler: H, optional_data: *mut U)
where
H: Fn(*mut U, &mut Response<SSL>) + Copy + 'static,
{
extern "C" fn handle<U, H, const SSL: bool>(this: *mut c::uws_res, user_data: *mut c_void)
where
H: Fn(*mut U, &mut Response<SSL>) + Copy + 'static,
{
if user_data.is_null() {
return;
}
unsafe {
thunk::zst::<H>()(
user_data.cast::<U>(),
thunk::handle_mut(Response::<SSL>::cast_res(this)),
)
}
}
c::uws_res_on_aborted(
Self::ssl_flag(),
self.as_raw(),
Some(handle::<U, H, SSL>),
optional_data.cast(),
);
}
pub fn clear_aborted(&mut self) {
c::uws_res_on_aborted(Self::ssl_flag(), self.as_raw(), None, core::ptr::null_mut())
}
pub fn on_timeout<U, H>(&mut self, _handler: H, optional_data: *mut U)
where
H: Fn(*mut U, &mut Response<SSL>) + Copy + 'static,
{
extern "C" fn handle<U, H, const SSL: bool>(this: *mut c::uws_res, user_data: *mut c_void)
where
H: Fn(*mut U, &mut Response<SSL>) + Copy + 'static,
{
if user_data.is_null() {
return;
}
unsafe {
thunk::zst::<H>()(
user_data.cast::<U>(),
thunk::handle_mut(Response::<SSL>::cast_res(this)),
)
}
}
c::uws_res_on_timeout(
Self::ssl_flag(),
self.as_raw(),
Some(handle::<U, H, SSL>),
optional_data.cast(),
);
}
pub fn clear_timeout(&mut self) {
c::uws_res_on_timeout(Self::ssl_flag(), self.as_raw(), None, core::ptr::null_mut())
}
pub fn clear_on_data(&mut self) {
c::uws_res_on_data(Self::ssl_flag(), self.as_raw(), None, core::ptr::null_mut())
}
pub fn on_data<U, H>(&mut self, _handler: H, optional_data: *mut U)
where
H: Fn(*mut U, &mut Response<SSL>, &[u8], bool) + Copy + 'static,
{
extern "C" fn handle<U, H, const SSL: bool>(
this: *mut c::uws_res,
chunk_ptr: *const u8,
len: usize,
last: bool,
user_data: *mut c_void,
) where
H: Fn(*mut U, &mut Response<SSL>, &[u8], bool) + Copy + 'static,
{
if user_data.is_null() {
return;
}
unsafe {
thunk::zst::<H>()(
user_data.cast::<U>(),
thunk::handle_mut(Response::<SSL>::cast_res(this)),
thunk::c_slice(chunk_ptr, len),
last,
)
}
}
c::uws_res_on_data(
Self::ssl_flag(),
self.as_raw(),
Some(handle::<U, H, SSL>),
optional_data.cast(),
);
}
pub fn end_stream(&mut self, close_connection: bool) {
c::uws_res_end_stream(Self::ssl_flag(), self.as_raw(), close_connection)
}
pub fn corked<F: FnOnce()>(&mut self, f: F) {
extern "C" fn handle<F: FnOnce()>(user_data: *mut c_void) {
let f = unsafe { core::ptr::read(user_data.cast::<F>()) };
f();
}
let mut f = core::mem::ManuallyDrop::new(f);
c::uws_res_cork(
Self::ssl_flag(),
self.as_raw(),
(&raw mut *f).cast::<c_void>(),
handle::<F>,
);
}
pub fn run_corked_with_type<U>(&mut self, handler: fn(*mut U), optional_data: *mut U) {
type Ctx<U> = (fn(*mut U), *mut U);
extern "C" fn handle<U>(user_data: *mut c_void) {
let ctx = unsafe { &*user_data.cast::<Ctx<U>>() };
(ctx.0)(ctx.1);
}
let mut ctx: Ctx<U> = (handler, optional_data);
c::uws_res_cork(
Self::ssl_flag(),
self.as_raw(),
(&raw mut ctx).cast::<c_void>(),
handle::<U>,
);
}
pub fn upgrade<D>(
&mut self,
data: *mut D,
sec_web_socket_key: &[u8],
sec_web_socket_protocol: &[u8],
sec_web_socket_extensions: &[u8],
ctx: Option<&mut WebSocketUpgradeContext>,
) -> *mut Socket {
unsafe {
c::uws_res_upgrade(
Self::ssl_flag(),
self.downcast(),
data.cast::<c_void>(),
sec_web_socket_key.as_ptr(),
sec_web_socket_key.len(),
sec_web_socket_protocol.as_ptr(),
sec_web_socket_protocol.len(),
sec_web_socket_extensions.as_ptr(),
sec_web_socket_extensions.len(),
ctx.map_or(core::ptr::null_mut(), std::ptr::from_mut),
)
}
}
}
pub type TCPResponse = Response<false>;
pub type TLSResponse = Response<true>;
unsafe impl<const SSL: bool> OpaqueHandle for Response<SSL> {}
unsafe impl OpaqueHandle for H3Response {}
#[derive(Clone, Copy)]
pub enum AnyResponse {
SSL(*mut TLSResponse),
TCP(*mut TCPResponse),
H3(*mut H3Response),
}
macro_rules! any_dispatch {
($self:expr, |$r:ident| $body:expr) => {
match $self {
AnyResponse::SSL(ptr) => {
let $r = TLSResponse::as_handle(ptr);
$body
}
AnyResponse::TCP(ptr) => {
let $r = TCPResponse::as_handle(ptr);
$body
}
AnyResponse::H3(ptr) => {
let $r = H3Response::as_handle(ptr);
$body
}
}
};
}
macro_rules! any_response_register_cb {
(
$self:expr, $method:ident, $opt_data:expr;
<$U:ident, $H:ident : [$($bound:tt)*]>
|$u:ident $(, $pre:ident : $pre_ty:ty)* ; $r:ident, $any:ident $(, $post:ident : $post_ty:ty)*| -> $ret:ty
{ $($body:tt)* }
) => {{
const { assert!(core::mem::size_of::<$H>() == 0, "handler must be a fn item or capture-less closure") };
fn ssl<$U, $H: $($bound)*>($u: *mut $U $(, $pre: $pre_ty)*, $r: &mut TLSResponse $(, $post: $post_ty)*) -> $ret {
let $any = AnyResponse::SSL(std::ptr::from_mut($r));
$($body)*
}
fn tcp<$U, $H: $($bound)*>($u: *mut $U $(, $pre: $pre_ty)*, $r: &mut TCPResponse $(, $post: $post_ty)*) -> $ret {
let $any = AnyResponse::TCP(std::ptr::from_mut($r));
$($body)*
}
fn h3<$U, $H: $($bound)*>($u: &mut $U $(, $pre: $pre_ty)*, $r: &mut H3Response $(, $post: $post_ty)*) -> $ret {
let $u = std::ptr::from_mut::<$U>($u);
let $any = AnyResponse::H3(std::ptr::from_mut($r));
$($body)*
}
match $self {
AnyResponse::SSL(ptr) => TLSResponse::as_handle(ptr).$method(ssl::<$U, $H>, $opt_data),
AnyResponse::TCP(ptr) => TCPResponse::as_handle(ptr).$method(tcp::<$U, $H>, $opt_data),
AnyResponse::H3(ptr) => H3Response::as_handle(ptr).$method(h3::<$U, $H>, $opt_data),
}
}};
}
impl AnyResponse {
pub fn assert_ssl(self) -> *mut TLSResponse {
match self {
AnyResponse::SSL(resp) => resp,
AnyResponse::TCP(_) => panic!("Expected SSL response, got TCP response"),
AnyResponse::H3(_) => panic!("Expected SSL response, got H3 response"),
}
}
pub fn assert_no_ssl(self) -> *mut TCPResponse {
match self {
AnyResponse::SSL(_) => panic!("Expected TCP response, got SSL response"),
AnyResponse::TCP(resp) => resp,
AnyResponse::H3(_) => panic!("Expected TCP response, got H3 response"),
}
}
pub fn mark_needs_more(self) {
any_dispatch!(self, |r| r.mark_needs_more())
}
pub fn mark_wrote_content_length_header(self) {
any_dispatch!(self, |r| r.mark_wrote_content_length_header())
}
pub fn write_mark(self) {
any_dispatch!(self, |r| r.write_mark())
}
pub fn end_send_file(self, write_offset: u64, close_connection: bool) {
any_dispatch!(self, |r| r.end_send_file(write_offset, close_connection))
}
pub fn socket(self) -> *mut c::uws_res {
match self {
AnyResponse::H3(_) => panic!("socket() is not available for HTTP/3 responses"),
AnyResponse::SSL(ptr) => TLSResponse::as_handle(ptr).downcast(),
AnyResponse::TCP(ptr) => TCPResponse::as_handle(ptr).downcast(),
}
}
pub fn get_socket_data(self) -> *mut c_void {
any_dispatch!(self, |r| r.get_socket_data())
}
pub fn get_remote_socket_info(self) -> Option<SocketAddress> {
any_dispatch!(self, |r| r.get_remote_socket_info())
}
pub fn flush_headers(self, flush_immediately: bool) {
any_dispatch!(self, |r| r.flush_headers(flush_immediately))
}
pub fn is_corked(self) -> bool {
any_dispatch!(self, |r| r.is_corked())
}
pub fn uncork(self) {
any_dispatch!(self, |r| r.uncork())
}
pub fn get_write_offset(self) -> u64 {
any_dispatch!(self, |r| r.get_write_offset())
}
pub fn get_buffered_amount(self) -> u64 {
any_dispatch!(self, |r| r.get_buffered_amount())
}
pub fn write_continue(self) {
any_dispatch!(self, |r| r.write_continue())
}
pub fn state(self) -> State {
any_dispatch!(self, |r| r.state())
}
#[inline]
pub fn init<T>(response: T) -> AnyResponse
where
AnyResponse: From<T>,
{
AnyResponse::from(response)
}
pub fn timeout(self, seconds: u8) {
any_dispatch!(self, |r| r.timeout(seconds))
}
pub fn on_data<U: 'static, H>(self, _handler: H, optional_data: *mut U)
where
H: Fn(*mut U, &[u8], bool) + Copy + 'static,
{
any_response_register_cb! {
self, on_data, optional_data;
<U, H: [Fn(*mut U, &[u8], bool) + Copy + 'static]>
|u; _r, _any, d: &[u8], l: bool| -> () { thunk::zst::<H>()(u, d, l) }
}
}
pub fn write_status(self, status: &[u8]) {
any_dispatch!(self, |r| r.write_status(status))
}
pub fn write_header(self, key: &[u8], value: &[u8]) {
any_dispatch!(self, |r| r.write_header(key, value))
}
pub fn write(self, data: &[u8]) -> WriteResult {
any_dispatch!(self, |r| r.write(data))
}
pub fn end(self, data: &[u8], close_connection: bool) {
any_dispatch!(self, |r| r.end(data, close_connection))
}
pub fn should_close_connection(self) -> bool {
any_dispatch!(self, |r| r.should_close_connection())
}
pub fn try_end(self, data: &[u8], total_size: usize, close_connection: bool) -> bool {
any_dispatch!(self, |r| r.try_end(data, total_size, close_connection))
}
pub fn pause(self) {
any_dispatch!(self, |r| r.pause())
}
pub fn resume_(self) {
any_dispatch!(self, |r| r.resume_())
}
pub fn write_header_int(self, key: &[u8], value: u64) {
any_dispatch!(self, |r| r.write_header_int(key, value))
}
pub fn end_without_body(self, close_connection: bool) {
any_dispatch!(self, |r| r.end_without_body(close_connection))
}
pub fn force_close(self) {
match self {
AnyResponse::SSL(ptr) => {
us_socket_t::opaque_mut(TLSResponse::as_handle(ptr).downcast_socket())
.close(crate::us_socket::CloseCode::failure);
}
AnyResponse::TCP(ptr) => {
us_socket_t::opaque_mut(TCPResponse::as_handle(ptr).downcast_socket())
.close(crate::us_socket::CloseCode::failure);
}
AnyResponse::H3(ptr) => H3Response::as_handle(ptr).force_close(),
}
}
pub fn get_native_handle(self) -> Fd {
match self {
AnyResponse::H3(_) => bun_core::Fd::INVALID,
AnyResponse::SSL(ptr) => TLSResponse::as_handle(ptr).get_native_handle(),
AnyResponse::TCP(ptr) => TCPResponse::as_handle(ptr).get_native_handle(),
}
}
pub fn prepare_for_sendfile(self) {
any_dispatch!(self, |r| r.prepare_for_sendfile())
}
pub fn on_writable<U: 'static, H>(self, _handler: H, optional_data: *mut U)
where
H: Fn(*mut U, u64, AnyResponse) -> bool + Copy + 'static,
{
any_response_register_cb! {
self, on_writable, optional_data;
<U, H: [Fn(*mut U, u64, AnyResponse) -> bool + Copy + 'static]>
|u, off: u64; r, any| -> bool { thunk::zst::<H>()(u, off, any) }
}
}
pub fn on_timeout<U: 'static, H>(self, _handler: H, optional_data: *mut U)
where
H: Fn(*mut U, AnyResponse) + Copy + 'static,
{
any_response_register_cb! {
self, on_timeout, optional_data;
<U, H: [Fn(*mut U, AnyResponse) + Copy + 'static]>
|u; r, any| -> () { thunk::zst::<H>()(u, any) }
}
}
pub fn on_aborted<U: 'static, H>(self, _handler: H, optional_data: *mut U)
where
H: Fn(*mut U, AnyResponse) + Copy + 'static,
{
any_response_register_cb! {
self, on_aborted, optional_data;
<U, H: [Fn(*mut U, AnyResponse) + Copy + 'static]>
|u; r, any| -> () { thunk::zst::<H>()(u, any) }
}
}
pub fn clear_aborted(self) {
any_dispatch!(self, |r| r.clear_aborted())
}
pub fn clear_timeout(self) {
any_dispatch!(self, |r| r.clear_timeout())
}
pub fn clear_on_writable(self) {
any_dispatch!(self, |r| r.clear_on_writable())
}
pub fn has_responded(self) -> bool {
any_dispatch!(self, |r| r.has_responded())
}
pub fn reset_timeout(self) {
any_dispatch!(self, |r| r.reset_timeout())
}
pub fn clear_on_data(self) {
any_dispatch!(self, |r| r.clear_on_data())
}
pub fn is_connect_request(self) -> bool {
any_dispatch!(self, |r| r.is_connect_request())
}
pub fn end_stream(self, close_connection: bool) {
any_dispatch!(self, |r| r.end_stream(close_connection))
}
pub fn corked<F: FnOnce()>(self, f: F) {
any_dispatch!(self, |r| r.corked(f))
}
pub fn run_corked_with_type<U>(self, handler: fn(*mut U), optional_data: *mut U) {
any_dispatch!(self, |r| r.run_corked_with_type(handler, optional_data))
}
pub fn upgrade<D>(
self,
data: *mut D,
sec_web_socket_key: &[u8],
sec_web_socket_protocol: &[u8],
sec_web_socket_extensions: &[u8],
ctx: Option<&mut WebSocketUpgradeContext>,
) -> *mut Socket {
match self {
AnyResponse::H3(_) => unreachable!(),
AnyResponse::SSL(ptr) => TLSResponse::as_handle(ptr).upgrade(
data,
sec_web_socket_key,
sec_web_socket_protocol,
sec_web_socket_extensions,
ctx,
),
AnyResponse::TCP(ptr) => TCPResponse::as_handle(ptr).upgrade(
data,
sec_web_socket_key,
sec_web_socket_protocol,
sec_web_socket_extensions,
ctx,
),
}
}
}
impl From<*mut TLSResponse> for AnyResponse {
#[inline]
fn from(r: *mut TLSResponse) -> Self {
AnyResponse::SSL(r)
}
}
impl From<*mut TCPResponse> for AnyResponse {
#[inline]
fn from(r: *mut TCPResponse) -> Self {
AnyResponse::TCP(r)
}
}
impl From<*mut H3Response> for AnyResponse {
#[inline]
fn from(r: *mut H3Response) -> Self {
AnyResponse::H3(r)
}
}
pub(crate) type H3Response = crate::h3::Response;
bitflags::bitflags! {
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct State: u8 {
const HTTP_STATUS_CALLED = 1;
const HTTP_WRITE_CALLED = 2;
const HTTP_END_CALLED = 4;
const HTTP_RESPONSE_PENDING = 8;
const HTTP_CONNECTION_CLOSE = 16;
const HTTP_WROTE_CONTENT_LENGTH_HEADER = 32;
}
}
impl State {
#[inline]
pub fn is_response_pending(self) -> bool {
self.bits() & State::HTTP_RESPONSE_PENDING.bits() != 0
}
#[inline]
pub fn has_written_content_length_header(self) -> bool {
self.bits() & State::HTTP_WROTE_CONTENT_LENGTH_HEADER.bits() != 0
}
#[inline]
pub fn is_http_end_called(self) -> bool {
self.bits() & State::HTTP_END_CALLED.bits() != 0
}
#[inline]
pub fn is_http_write_called(self) -> bool {
self.bits() & State::HTTP_WRITE_CALLED.bits() != 0
}
#[inline]
pub fn is_http_status_called(self) -> bool {
self.bits() & State::HTTP_STATUS_CALLED.bits() != 0
}
#[inline]
pub fn is_http_connection_close(self) -> bool {
self.bits() & State::HTTP_CONNECTION_CLOSE.bits() != 0
}
}
pub enum WriteResult {
WantMore(usize),
Backpressure(usize),
}
pub use c::uws_res;
#[allow(non_camel_case_types)]
pub mod c {
use super::*;
bun_opaque::opaque_ffi! {
pub struct uws_res;
}
unsafe extern "C" {
pub(crate) safe fn uws_res_mark_wrote_content_length_header(ssl: i32, res: &mut uws_res);
pub(crate) safe fn uws_res_write_mark(ssl: i32, res: &mut uws_res);
pub(crate) safe fn us_socket_mark_needs_more_not_ssl(socket: &mut uws_res);
pub(crate) safe fn uws_res_state(ssl: c_int, res: &uws_res) -> State;
pub(crate) safe fn uws_res_is_connect_request(ssl: i32, res: &mut uws_res) -> bool;
pub(crate) safe fn uws_res_get_remote_address_info(
res: &mut uws_res,
dest: &mut *const u8,
port: &mut i32,
is_ipv6: &mut bool,
) -> usize;
pub(crate) safe fn uws_res_uncork(ssl: i32, res: &mut uws_res);
pub(crate) fn uws_res_end(
ssl: i32,
res: *mut uws_res,
data: *const u8,
length: usize,
close_connection: bool,
);
pub(crate) safe fn uws_res_flush_headers(
ssl: i32,
res: &mut uws_res,
flush_immediately: bool,
);
pub(crate) safe fn uws_res_is_corked(ssl: i32, res: &mut uws_res) -> bool;
pub(crate) safe fn uws_res_get_socket_data(ssl: i32, res: &mut uws_res) -> *mut SocketData;
pub(crate) safe fn uws_res_pause(ssl: i32, res: &mut uws_res);
pub(crate) safe fn uws_res_resume(ssl: i32, res: &mut uws_res);
pub(crate) safe fn uws_res_write_continue(ssl: i32, res: &mut uws_res);
pub(crate) fn uws_res_write_status(
ssl: i32,
res: *mut uws_res,
status: *const u8,
length: usize,
);
pub(crate) fn uws_res_write_header(
ssl: i32,
res: *mut uws_res,
key: *const u8,
key_length: usize,
value: *const u8,
value_length: usize,
);
pub(crate) fn uws_res_write_header_int(
ssl: i32,
res: *mut uws_res,
key: *const u8,
key_length: usize,
value: u64,
);
pub(crate) safe fn uws_res_end_without_body(
ssl: i32,
res: &mut uws_res,
close_connection: bool,
);
pub(crate) safe fn uws_res_end_sendfile(
ssl: i32,
res: &mut uws_res,
write_offset: u64,
close_connection: bool,
);
pub(crate) safe fn uws_res_timeout(ssl: i32, res: &mut uws_res, timeout: u8);
pub(crate) safe fn uws_res_reset_timeout(ssl: i32, res: &mut uws_res);
pub(crate) safe fn uws_res_get_buffered_amount(ssl: i32, res: &mut uws_res) -> u64;
pub(crate) fn uws_res_write(
ssl: i32,
res: *mut uws_res,
data: *const u8,
length: *mut usize,
) -> bool;
pub(crate) safe fn uws_res_get_write_offset(ssl: i32, res: &mut uws_res) -> u64;
pub(crate) safe fn uws_res_override_write_offset(ssl: i32, res: &mut uws_res, offset: u64);
pub(crate) safe fn uws_res_has_responded(ssl: i32, res: &mut uws_res) -> bool;
pub(crate) safe fn uws_res_on_writable(
ssl: i32,
res: &mut uws_res,
handler: Option<unsafe extern "C" fn(*mut uws_res, u64, *mut c_void) -> bool>,
user_data: *mut c_void,
);
pub(crate) safe fn uws_res_clear_on_writable(ssl: i32, res: &mut uws_res);
pub(crate) safe fn uws_res_on_aborted(
ssl: i32,
res: &mut uws_res,
handler: Option<unsafe extern "C" fn(*mut uws_res, *mut c_void)>,
optional_data: *mut c_void,
);
pub(crate) safe fn uws_res_on_timeout(
ssl: i32,
res: &mut uws_res,
handler: Option<unsafe extern "C" fn(*mut uws_res, *mut c_void)>,
optional_data: *mut c_void,
);
pub(crate) fn uws_res_try_end(
ssl: i32,
res: *mut uws_res,
data: *const u8,
length: usize,
total: usize,
close: bool,
) -> bool;
pub(crate) safe fn uws_res_end_stream(ssl: i32, res: &mut uws_res, close_connection: bool);
pub(crate) safe fn uws_res_prepare_for_sendfile(ssl: i32, res: &mut uws_res);
pub(crate) safe fn uws_res_get_native_handle(ssl: i32, res: &mut uws_res) -> *mut Socket;
pub(crate) safe fn uws_res_get_remote_address_as_text(
ssl: i32,
res: &mut uws_res,
dest: &mut *const u8,
) -> usize;
pub(crate) safe fn uws_res_on_data(
ssl: i32,
res: &mut uws_res,
handler: Option<
unsafe extern "C" fn(*mut uws_res, *const u8, usize, bool, *mut c_void),
>,
optional_data: *mut c_void,
);
pub(crate) fn uws_res_upgrade(
ssl: i32,
res: *mut uws_res,
data: *mut c_void,
sec_web_socket_key: *const u8,
sec_web_socket_key_length: usize,
sec_web_socket_protocol: *const u8,
sec_web_socket_protocol_length: usize,
sec_web_socket_extensions: *const u8,
sec_web_socket_extensions_length: usize,
ws: *mut WebSocketUpgradeContext,
) -> *mut Socket;
pub(crate) safe fn uws_res_cork(
ssl: i32,
res: &mut uws_res,
ctx: *mut c_void,
corker: unsafe extern "C" fn(*mut c_void),
);
}
}