Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
b287022
port node internal bindings to rust
nathanwhit Jun 10, 2026
c7f9e4f
port more node internal bindings to rust
nathanwhit Jun 10, 2026
67dd772
port buffer and util internal bindings to rust
nathanwhit Jun 10, 2026
2b27e3e
port block list internal binding to rust
nathanwhit Jun 10, 2026
1a77209
port node file internal binding to rust
nathanwhit Jun 10, 2026
df0ec7d
port node options internal binding to rust
nathanwhit Jun 10, 2026
58f36cd
port node utils internal binding to rust
nathanwhit Jun 10, 2026
1c7a60d
port async wrap internal binding to rust
nathanwhit Jun 10, 2026
2e45aeb
port stream wrap internal binding to rust
nathanwhit Jun 10, 2026
8e514c1
port tcp wrap internal binding to rust
nathanwhit Jun 10, 2026
c463680
port pipe wrap internal binding to rust
nathanwhit Jun 10, 2026
9d25bb3
port http2 internal binding to rust
nathanwhit Jun 10, 2026
ff4f4e4
port tls wrap internal binding to rust
nathanwhit Jun 10, 2026
2d34c92
port http parser internal binding to rust
nathanwhit Jun 10, 2026
cf208d0
lazy load http internal bindings
nathanwhit Jun 10, 2026
567a03a
port udp send wrap internal binding to rust
nathanwhit Jun 10, 2026
baa300f
port dns request wraps to rust
nathanwhit Jun 11, 2026
9ff0a17
port udp handle base to rust
nathanwhit Jun 11, 2026
58ba147
port dns channel wrap base to rust
nathanwhit Jun 11, 2026
daf7fb2
lazy load cares internal binding
nathanwhit Jun 11, 2026
550e3b8
port udp state and sync methods to rust
nathanwhit Jun 11, 2026
d6c97ba
port udp send path to rust
nathanwhit Jun 11, 2026
d895454
port udp receive result handling to rust
nathanwhit Jun 11, 2026
365d2f2
port dns reverse lookup name generation to rust
nathanwhit Jun 11, 2026
e00266c
port dns lookup address ordering to rust
nathanwhit Jun 11, 2026
d798f2e
perf(node): cache HTTP parser callbacks
nathanwhit Jun 12, 2026
bbb55e3
fix(node): stabilize internal binding callbacks
nathanwhit Jun 12, 2026
670e6aa
chore(node): update polyfill lint baseline
nathanwhit Jun 12, 2026
ee0ae29
fix(node): address internal binding CI regressions
nathanwhit Jun 12, 2026
d327a91
fix(node): validate buffer fill range
nathanwhit Jun 12, 2026
1fee1db
fix(node): map windows udp EINVAL
nathanwhit Jun 13, 2026
82eff55
fix(node): map windows udp address errors
nathanwhit Jun 13, 2026
cff0ee3
fix(node): use windows udp address uv code
nathanwhit Jun 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 78 additions & 4 deletions ext/node/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ deno_core::extension!(deno_node,

ops::blocklist::op_socket_address_parse,
ops::blocklist::op_socket_address_get_serialization,
ops::blocklist::op_node_internal_binding_block_list,

ops::blocklist::op_blocklist_new,
ops::blocklist::op_blocklist_add_address,
Expand All @@ -217,6 +218,8 @@ deno_core::extension!(deno_node,
ops::buffer::op_node_encoding_slice,
ops::dns::op_node_getaddrinfo,
ops::dns::op_node_getnameinfo,
ops::dns::op_node_dns_reverse_name,
ops::dns::op_node_dns_sort_lookup_addresses,
ops::fs::op_node_fs_exists_sync,
ops::fs::op_node_fs_exists,
ops::fs::op_node_lchmod_sync,
Expand All @@ -234,13 +237,16 @@ deno_core::extension!(deno_node,
ops::fs::op_node_statfs_sync,
ops::fs::op_node_statfs,
ops::fs::op_node_create_pipe,
ops::pipe_wrap::op_node_internal_binding_pipe_wrap,
ops::fs::op_node_fd_set_blocking,
ops::fs::op_node_fs_close,
ops::fs::op_node_fs_read_sync,
ops::fs::op_node_fs_read_deferred,
ops::fs::op_node_fs_write_sync,
ops::fs::op_node_fs_write_deferred,
ops::fs::op_node_fs_seek_sync,
ops::fs::op_node_file_write_buffer,
ops::llhttp::binding::op_node_internal_binding_http_parser,
ops::fs::op_node_fs_seek,
ops::fs::op_node_fs_fstat_sync,
ops::fs::op_node_fs_fstat,
Expand Down Expand Up @@ -320,15 +326,43 @@ deno_core::extension!(deno_node,
ops::idna::op_node_idna_punycode_to_unicode,
ops::idna::op_node_idna_punycode_decode,
ops::idna::op_node_idna_punycode_encode,
ops::buffer::op_node_internal_binding_buffer,
ops::internal_binding::op_node_internal_binding_ares,
ops::internal_binding::op_node_internal_binding_encodings,
ops::internal_binding::op_node_internal_binding_handle_wrap,
ops::internal_binding::op_node_internal_binding_inspector,
ops::internal_binding::op_node_internal_binding_libuv_winerror,
ops::internal_binding::op_node_internal_binding_string_decoder,
ops::internal_binding::op_node_internal_binding_symbols,
ops::internal_binding::op_node_internal_binding_tty_wrap,
ops::internal_binding::op_node_internal_binding_types,
ops::internal_binding::op_node_ares_strerror,
ops::internal_binding_async_wrap::op_node_internal_binding_async_wrap,
ops::internal_binding_constants::op_node_internal_binding_constants,
ops::internal_binding_crypto::op_node_crypto_get_fips,
ops::internal_binding_crypto::op_node_crypto_set_fips,
ops::internal_binding_crypto::op_node_crypto_timing_safe_equal,
ops::internal_binding_crypto::op_node_internal_binding_crypto,
ops::internal_binding_crypto::op_node_internal_binding_timing_safe_equal,
ops::internal_binding_node_options::op_node_options_get_exec_argv_options,
ops::internal_binding_node_options::op_node_options_get_options<TSys>,
ops::internal_binding_node_options::op_node_options_set_exec_argv,
ops::internal_binding_utils::op_node_internal_binding_utils,
ops::internal_binding_uv::op_node_internal_binding_uv,
ops::internal_binding_uv::op_node_uv_errname,
ops::internal_binding_uv::op_node_uv_get_code_map,
ops::internal_binding_uv::op_node_uv_get_error_map,
ops::internal_binding_uv::op_node_uv_get_error_message,
ops::internal_binding_uv::op_node_uv_map_sys_errno_to_uv_errno,
ops::util::op_node_internal_binding_util,
ops::zlib::op_zlib_crc32,
ops::zlib::op_zlib_crc32_string,
ops::handle_wrap::op_node_new_async_id,
ops::http2::op_http2_callbacks,
ops::http2::op_node_internal_binding_http2,
// Keep the HTTP/2 error-string op wired so `internal/test/binding`
// can mirror Node's `internalBinding('http2').nghttp2ErrorString()`
// in node_compat tests; the JS side also exposes `respond` /
// `pushPromise` shims on `Http2Stream` so tests can monkey-patch the
// prototype to inject NGHTTP2 error codes.
// in node_compat tests.
ops::http2::op_http2_error_string,
ops::http2::op_http2_http_state,
ops::os::op_node_os_get_priority,
Expand Down Expand Up @@ -425,24 +459,37 @@ deno_core::extension!(deno_node,
ops::udp::op_node_udp_recv,
ops::udp::op_node_udp_fd_for_ipc,
ops::udp::op_node_udp_open,
ops::tcp_wrap::op_node_internal_binding_tcp_wrap,
ops::stream_wrap::op_node_internal_binding_stream_wrap,
ops::stream_wrap::op_stream_base_register_state,
ops::tls_wrap::op_node_internal_binding_tls_wrap,
ops::tty_wrap::op_tty_check_fd_permission,
],
objects = [
ops::perf_hooks::EldHistogram,
ops::perf_hooks::BaseHistogram,
ops::handle_wrap::AsyncWrap,
ops::handle_wrap::HandleWrap,
ops::dns::GetAddrInfoReqWrap,
ops::dns::GetNameInfoReqWrap,
ops::dns::QueryReqWrap,
ops::dns::ChannelWrap,
ops::wasi::WasiContext,
ops::stream_wrap::WriteWrap,
ops::stream_wrap::ShutdownWrap,
ops::stream_wrap::LibUvStreamWrap,
ops::tty_wrap::TTY,
ops::zlib::BrotliDecoder,
ops::zlib::BrotliEncoder,
ops::zlib::Zlib,
ops::zlib::ZstdCompress,
ops::zlib::ZstdDecompress,
ops::tcp_wrap::TCPConnectWrap,
ops::tcp_wrap::TCPWrap,
ops::pipe_wrap::PipeConnectWrap,
ops::pipe_wrap::PipeWrap,
ops::udp::SendWrap,
ops::udp::UDP,
ops::tls_wrap::TLSWrap,
ops::llhttp::binding::HTTPParser,
ops::http2::Http2Session,
Expand Down Expand Up @@ -614,7 +661,6 @@ deno_core::extension!(deno_node,
"_process/process.ts",
"_util/_util_callbackify.js",
"_zlib_binding.mjs",
"internal_binding/_listen.ts",
"internal_binding/_node.ts",
"internal_binding/_utils.ts",
"internal_binding/ares.ts",
Expand Down Expand Up @@ -772,6 +818,7 @@ deno_core::extension!(deno_node,
state = |state, options| {
state.put(options.fs.clone());
state.put(ops::module_hooks::LoaderHookRegistry::default());
state.put(ops::internal_binding_node_options::NodeOptionsState::default());

if let Some(init) = &options.maybe_init {
state.put(init.sys.clone());
Expand Down Expand Up @@ -876,6 +923,33 @@ deno_core::extension!(deno_node,
];

ext.external_references.to_mut().extend(external_references);
ext.external_references.to_mut().extend(
ops::internal_binding_crypto::external_references(),
);
ext.external_references.to_mut().extend(
ops::util::external_references(),
);
ext.external_references.to_mut().extend(
ops::buffer::external_references(),
);
ext.external_references.to_mut().extend(
ops::blocklist::internal_binding_external_references(),
);
ext.external_references.to_mut().extend(
ops::internal_binding_utils::external_references(),
);
ext.external_references.to_mut().extend(
ops::internal_binding_async_wrap::external_references(),
);
ext.external_references.to_mut().extend(
ops::http2::internal_binding_external_references(),
);
ext.external_references.to_mut().extend(
ops::tls_wrap::internal_binding_external_references(),
);
ext.external_references.to_mut().extend(
ops::llhttp::binding::internal_binding_external_references(),
);
},
);

Expand Down
193 changes: 193 additions & 0 deletions ext/node/ops/blocklist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ use std::net::SocketAddr;
use deno_core::OpState;
use deno_core::ToV8;
use deno_core::op2;
use deno_core::v8;
use deno_core::v8::ExternalReference;
use deno_core::v8::MapFnTo;
use ipnet::IpNet;
use ipnet::Ipv4Net;
use ipnet::Ipv6Net;
Expand Down Expand Up @@ -43,6 +46,196 @@ pub enum BlocklistError {
IpVersionMismatch,
}

fn set_value(
scope: &mut v8::PinScope,
obj: v8::Local<v8::Object>,
name: &str,
value: v8::Local<v8::Value>,
) {
let key = v8::String::new(scope, name).unwrap();
obj.set(scope, key.into(), value);
}

fn set_i32(
scope: &mut v8::PinScope,
obj: v8::Local<v8::Object>,
name: &str,
value: i32,
) {
let value = v8::Integer::new(scope, value);
set_value(scope, obj, name, value.into());
}

fn set_function(
scope: &mut v8::PinScope,
obj: v8::Local<v8::Object>,
export_name: &str,
function: v8::Local<v8::Function>,
) {
let name = v8::String::new(scope, export_name).unwrap();
function.set_name(name);
set_value(scope, obj, export_name, function.into());
}

fn private_key<'s>(
scope: &mut v8::PinScope<'s, '_>,
name: &str,
) -> v8::Local<'s, v8::Private> {
let name = v8::String::new(scope, name).unwrap();
v8::Private::for_api(scope, Some(name))
}

fn set_private(
scope: &mut v8::PinScope,
obj: v8::Local<v8::Object>,
name: &str,
value: v8::Local<v8::Value>,
) {
let key = private_key(scope, name);
obj.set_private(scope, key, value);
}

fn get_private<'s>(
scope: &mut v8::PinScope<'s, '_>,
obj: v8::Local<'s, v8::Object>,
name: &str,
) -> v8::Local<'s, v8::Value> {
let key = private_key(scope, name);
obj
.get_private(scope, key)
.unwrap_or_else(|| v8::undefined(scope).into())
}

fn socket_address_constructor<'s>(
scope: &mut v8::PinScope<'s, '_>,
args: v8::FunctionCallbackArguments<'s>,
_rv: v8::ReturnValue<'s>,
) {
let this = args.this();
set_private(scope, this, "address", args.get(0));
set_private(scope, this, "port", args.get(1));
set_private(scope, this, "family", args.get(2));
set_private(scope, this, "flowlabel", args.get(3));
}

fn socket_address_address<'s>(
scope: &mut v8::PinScope<'s, '_>,
args: v8::FunctionCallbackArguments<'s>,
mut rv: v8::ReturnValue<'s>,
) {
rv.set(get_private(scope, args.this(), "address"));
}

fn socket_address_port<'s>(
scope: &mut v8::PinScope<'s, '_>,
args: v8::FunctionCallbackArguments<'s>,
mut rv: v8::ReturnValue<'s>,
) {
rv.set(get_private(scope, args.this(), "port"));
}

fn socket_address_family<'s>(
scope: &mut v8::PinScope<'s, '_>,
args: v8::FunctionCallbackArguments<'s>,
mut rv: v8::ReturnValue<'s>,
) {
rv.set(get_private(scope, args.this(), "family"));
}

fn socket_address_flowlabel<'s>(
scope: &mut v8::PinScope<'s, '_>,
args: v8::FunctionCallbackArguments<'s>,
mut rv: v8::ReturnValue<'s>,
) {
rv.set(get_private(scope, args.this(), "flowlabel"));
}

pub(crate) fn internal_binding_external_references() -> [ExternalReference; 5] {
[
SOCKET_ADDRESS_CONSTRUCTOR.with(|callback| ExternalReference {
function: *callback,
}),
SOCKET_ADDRESS_ADDRESS.with(|callback| ExternalReference {
function: *callback,
}),
SOCKET_ADDRESS_PORT.with(|callback| ExternalReference {
function: *callback,
}),
SOCKET_ADDRESS_FAMILY.with(|callback| ExternalReference {
function: *callback,
}),
SOCKET_ADDRESS_FLOWLABEL.with(|callback| ExternalReference {
function: *callback,
}),
]
}

thread_local! {
static SOCKET_ADDRESS_CONSTRUCTOR: v8::FunctionCallback = socket_address_constructor.map_fn_to();
static SOCKET_ADDRESS_ADDRESS: v8::FunctionCallback = socket_address_address.map_fn_to();
static SOCKET_ADDRESS_PORT: v8::FunctionCallback = socket_address_port.map_fn_to();
static SOCKET_ADDRESS_FAMILY: v8::FunctionCallback = socket_address_family.map_fn_to();
static SOCKET_ADDRESS_FLOWLABEL: v8::FunctionCallback = socket_address_flowlabel.map_fn_to();
}

fn function_template_from_callback<'s>(
scope: &mut v8::PinScope<'s, '_>,
callback: v8::FunctionCallback,
) -> v8::Local<'s, v8::FunctionTemplate> {
v8::FunctionTemplate::new_raw(scope, callback)
}

fn function_from_callback<'s>(
scope: &mut v8::PinScope<'s, '_>,
callback: v8::FunctionCallback,
) -> v8::Local<'s, v8::Function> {
function_template_from_callback(scope, callback)
.get_function(scope)
.unwrap()
}

#[op2]
pub fn op_node_internal_binding_block_list<'s>(
scope: &mut v8::PinScope<'s, '_>,
) -> v8::Local<'s, v8::Object> {
let obj = v8::Object::new(scope);
set_i32(scope, obj, "AF_INET", 2);
set_i32(scope, obj, "AF_INET6", 10);

let constructor_template = SOCKET_ADDRESS_CONSTRUCTOR
.with(|callback| function_template_from_callback(scope, *callback));
let constructor = constructor_template.get_function(scope).unwrap();
let constructor_name = v8::String::new(scope, "SocketAddress").unwrap();
constructor.set_name(constructor_name);
let prototype_key = v8::String::new(scope, "prototype").unwrap();
let prototype = constructor.get(scope, prototype_key.into()).unwrap();
let prototype = v8::Local::<v8::Object>::try_from(prototype).unwrap();

let address = SOCKET_ADDRESS_ADDRESS
.with(|callback| function_from_callback(scope, *callback));
set_function(scope, prototype, "address", address);
let port = SOCKET_ADDRESS_PORT
.with(|callback| function_from_callback(scope, *callback));
set_function(scope, prototype, "port", port);
let family = SOCKET_ADDRESS_FAMILY
.with(|callback| function_from_callback(scope, *callback));
set_function(scope, prototype, "family", family);
let flowlabel = SOCKET_ADDRESS_FLOWLABEL
.with(|callback| function_from_callback(scope, *callback));
set_function(scope, prototype, "flowlabel", flowlabel);

set_value(scope, obj, "SocketAddress", constructor.into());

let default_obj = v8::Object::new(scope);
for name in ["AF_INET", "AF_INET6", "SocketAddress"] {
let key = v8::String::new(scope, name).unwrap();
let value = obj.get(scope, key.into()).unwrap();
set_value(scope, default_obj, name, value);
}
set_value(scope, obj, "default", default_obj.into());
obj
}

#[op2(fast)]
pub fn op_socket_address_parse(
state: &mut OpState,
Expand Down
Loading
Loading