1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
use core::ffi::c_ushort;
// TODO(port): verify module path for H3 request opaque (h3.zig:19 — H3.Request = opaque{})
use crate::h3::Request as H3Request;
// PORT NOTE: `dateForHeader` (Request.zig:62) is NOT ported here. Parsing an
// HTTP date needs `bun_jsc::VirtualMachine` (T6); rather than hook upward, the
// sole caller (`bun_runtime::server::FileRoute`) does
// `req.header(name).and_then(parse_http_date)` itself — call site moved UP per
// docs/PORTING.md §"Low crate needs to call high crate" option (a).
/// Transport-agnostic request handle. Static/file routes (and RangeRequest)
/// take this so the same handler body serves HTTP/1.1 and HTTP/3 without
/// `anytype` — `inline else` keeps dispatch monomorphic.
pub enum AnyRequest {
H1(*mut Request),
H3(*mut H3Request),
}
impl AnyRequest {
// S008: variant payloads are `opaque_ffi!` ZST handles (`Request` /
// `h3::Request`); route the per-arm `*mut → &mut` deref through the
// const-asserted `bun_opaque::opaque_deref_mut` so dispatch is `unsafe`-free.
pub fn header(&self, name: &[u8]) -> Option<&[u8]> {
match self {
Self::H1(r) => bun_opaque::opaque_deref_mut(*r).header(name),
Self::H3(r) => bun_opaque::opaque_deref_mut(*r).header(name),
}
}
pub fn method(&self) -> &[u8] {
match self {
Self::H1(r) => bun_opaque::opaque_deref_mut(*r).method(),
Self::H3(r) => bun_opaque::opaque_deref_mut(*r).method(),
}
}
pub fn url(&self) -> &[u8] {
match self {
Self::H1(r) => bun_opaque::opaque_deref_mut(*r).url(),
Self::H3(r) => bun_opaque::opaque_deref_mut(*r).url(),
}
}
pub fn set_yield(&mut self, y: bool) {
match self {
Self::H1(r) => bun_opaque::opaque_deref_mut(*r).set_yield(y),
Self::H3(r) => bun_opaque::opaque_deref_mut(*r).set_yield(y),
}
}
}
bun_opaque::opaque_ffi! {
/// uWS::Request C++ -> Rust bindings.
pub struct Request;
}
impl Request {
pub fn is_ancient(&self) -> bool {
c::uws_req_is_ancient(self)
}
pub fn get_yield(&self) -> bool {
c::uws_req_get_yield(self)
}
pub fn set_yield(&mut self, yield_: bool) {
c::uws_req_set_yield(self, yield_)
}
pub fn url(&self) -> &[u8] {
let mut ptr: *const u8 = core::ptr::null();
let len = c::uws_req_get_url(self, &mut ptr);
// SAFETY: ptr/len describe a valid slice owned by the request for its lifetime;
// ffi::slice tolerates the (null, 0) shape uWS returns when no URL is present.
unsafe { bun_core::ffi::slice(ptr, len) }
}
pub fn method(&self) -> &[u8] {
let mut ptr: *const u8 = core::ptr::null();
let len = c::uws_req_get_method(self, &mut ptr);
// SAFETY: ptr/len describe a valid slice owned by the request for its lifetime;
// ffi::slice tolerates the (null, 0) shape uWS returns when no method is present.
unsafe { bun_core::ffi::slice(ptr, len) }
}
pub fn header(&self, name: &[u8]) -> Option<&[u8]> {
debug_assert!(name[0].is_ascii_lowercase());
let mut ptr: *const u8 = core::ptr::null();
// SAFETY: uws_req_get_header writes a pointer into request-owned storage and returns its length
let len = unsafe { c::uws_req_get_header(self, name.as_ptr(), name.len(), &raw mut ptr) };
if len == 0 {
return None;
}
// SAFETY: ptr/len describe a valid slice owned by the request for its lifetime
Some(unsafe { bun_core::ffi::slice(ptr, len) })
}
pub fn query(&self, name: &[u8]) -> &[u8] {
let mut ptr: *const u8 = core::ptr::null();
// SAFETY: uws_req_get_query writes a pointer into request-owned storage and returns its length
let len = unsafe { c::uws_req_get_query(self, name.as_ptr(), name.len(), &raw mut ptr) };
// SAFETY: ptr/len describe a valid slice owned by the request for its lifetime;
// ffi::slice tolerates the (null, 0) shape uWS returns when no query is present.
unsafe { bun_core::ffi::slice(ptr, len) }
}
pub fn parameter(&self, index: u16) -> &[u8] {
let mut ptr: *const u8 = core::ptr::null();
let len = c::uws_req_get_parameter(self, c_ushort::try_from(index).unwrap(), &mut ptr);
// SAFETY: ptr/len describe a valid slice owned by the request for its lifetime;
// ffi::slice tolerates the (null, 0) shape uWS returns when no parameter is present.
unsafe { bun_core::ffi::slice(ptr, len) }
}
/// Iterate all request headers.
///
/// Calls `cb(ctx, name, value)` for each header in the request.
/// The callback receives borrowed slices valid for the duration of the call.
/// Modeled after `h3::Request::for_each_header` with the same ZST-handler
/// trampoline pattern.
pub fn for_each_header<Ctx, H>(&self, _cb: H, ctx: *mut Ctx)
where
H: Fn(&mut Ctx, &[u8], &[u8]) + Copy + 'static,
{
extern "C" fn each<Ctx, H>(
n: *const u8,
nl: usize,
v: *const u8,
vl: usize,
ud: *mut core::ffi::c_void,
) where
H: Fn(&mut Ctx, &[u8], &[u8]) + Copy + 'static,
{
unsafe {
let Some(ctx) = crate::thunk::user_mut::<Ctx>(ud) else {
return;
};
crate::thunk::zst::<H>()(ctx, crate::thunk::c_slice(n, nl), crate::thunk::c_slice(v, vl));
}
}
unsafe { c::uws_req_for_each_header(self, each::<Ctx, H>, ctx.cast()) }
}
}
mod c {
use super::Request;
use core::ffi::c_ushort;
unsafe extern "C" {
pub(super) safe fn uws_req_is_ancient(res: &Request) -> bool;
pub(super) safe fn uws_req_get_yield(res: &Request) -> bool;
pub(super) safe fn uws_req_set_yield(res: &mut Request, yield_: bool);
// Out-param `dest` is a `&mut *const u8` (non-null, valid for write); the C
// shim only stores a pointer into request-owned storage and returns its
// length — no read-through-ptr precondition, so `safe fn`.
pub(super) safe fn uws_req_get_url(res: &Request, dest: &mut *const u8) -> usize;
pub(super) safe fn uws_req_get_method(res: &Request, dest: &mut *const u8) -> usize;
pub(super) fn uws_req_get_header(
res: *const Request,
lower_case_header: *const u8,
lower_case_header_length: usize,
dest: *mut *const u8,
) -> usize;
pub(super) fn uws_req_get_query(
res: *const Request,
key: *const u8,
key_length: usize,
dest: *mut *const u8,
) -> usize;
pub(super) safe fn uws_req_get_parameter(
res: &Request,
index: c_ushort,
dest: &mut *const u8,
) -> usize;
pub(super) fn uws_req_for_each_header(
res: *const Request,
handler: extern "C" fn(*const u8, usize, *const u8, usize, *mut core::ffi::c_void),
user_data: *mut core::ffi::c_void,
);
}
}
// ported from: src/uws_sys/Request.zig