aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js/api')
-rw-r--r--src/bun.js/api/bun/dns_resolver.zig759
1 files changed, 555 insertions, 204 deletions
diff --git a/src/bun.js/api/bun/dns_resolver.zig b/src/bun.js/api/bun/dns_resolver.zig
index 92577d556..08202a09e 100644
--- a/src/bun.js/api/bun/dns_resolver.zig
+++ b/src/bun.js/api/bun/dns_resolver.zig
@@ -614,104 +614,104 @@ pub const GetAddrInfo = struct {
};
};
-pub const ResolveSrvInfoRequest = struct {
- const log = Output.scoped(.ResolveSrvInfoRequest, false);
-
- resolver_for_caching: ?*DNSResolver = null,
- hash: u64 = 0,
- cache: ResolveSrvInfoRequest.CacheConfig = ResolveSrvInfoRequest.CacheConfig{},
- head: SrvLookup,
- tail: *SrvLookup = undefined,
- task: bun.ThreadPool.Task = undefined,
-
- pub fn init(
- cache: DNSResolver.SrvCacheHit,
- resolver: ?*DNSResolver,
- name: []const u8,
- globalThis: *JSC.JSGlobalObject,
- comptime cache_field: []const u8,
- ) !*ResolveSrvInfoRequest {
- var request = try globalThis.allocator().create(ResolveSrvInfoRequest);
- var hasher = std.hash.Wyhash.init(0);
- hasher.update(name);
- const hash = hasher.final();
- var poll_ref = JSC.PollRef.init();
- poll_ref.ref(globalThis.bunVM());
- request.* = .{
- .resolver_for_caching = resolver,
- .hash = hash,
- .head = .{
- .poll_ref = poll_ref,
- .globalThis = globalThis,
- .promise = JSC.JSPromise.Strong.init(globalThis),
- .allocated = false,
- },
- };
- request.tail = &request.head;
- if (cache == .new) {
- request.resolver_for_caching = resolver;
- request.cache = ResolveSrvInfoRequest.CacheConfig{
- .pending_cache = true,
- .entry_cache = false,
- .pos_in_pending = @truncate(u5, @field(resolver.?, cache_field).indexOf(cache.new).?),
- .name_len = @truncate(u9, name.len),
- };
- cache.new.lookup = request;
- }
- return request;
- }
-
- pub const Task = bun.JSC.WorkTask(ResolveSrvInfoRequest, false);
-
- pub const CacheConfig = packed struct(u16) {
- pending_cache: bool = false,
- entry_cache: bool = false,
- pos_in_pending: u5 = 0,
- name_len: u9 = 0,
- };
-
- pub const PendingCacheKey = struct {
- hash: u64,
- len: u16,
- lookup: *ResolveSrvInfoRequest = undefined,
-
- pub fn append(this: *PendingCacheKey, srv_lookup: *SrvLookup) void {
- var tail = this.lookup.tail;
- tail.next = srv_lookup;
- this.lookup.tail = srv_lookup;
- }
-
- pub fn init(name: []const u8) PendingCacheKey {
+pub fn ResolveInfoRequest(comptime cares_type: type, comptime type_name: []const u8) type {
+ return struct {
+ const request_type = @This();
+
+ const log = Output.scoped(@This(), false);
+
+ resolver_for_caching: ?*DNSResolver = null,
+ hash: u64 = 0,
+ cache: @This().CacheConfig = @This().CacheConfig{},
+ head: CAresLookup(cares_type, type_name),
+ tail: *CAresLookup(cares_type, type_name) = undefined,
+
+ pub fn init(
+ cache: DNSResolver.LookupCacheHit(@This()),
+ resolver: ?*DNSResolver,
+ name_str: *const JSC.ZigString.Slice,
+ globalThis: *JSC.JSGlobalObject,
+ comptime cache_field: []const u8,
+ ) !*@This() {
+ const name = name_str.slice();
+ var request = try globalThis.allocator().create(@This());
var hasher = std.hash.Wyhash.init(0);
hasher.update(name);
const hash = hasher.final();
- return PendingCacheKey{
+ var poll_ref = JSC.PollRef.init();
+ poll_ref.ref(globalThis.bunVM());
+ request.* = .{
+ .resolver_for_caching = resolver,
.hash = hash,
- .len = @truncate(u16, name.len),
- .lookup = undefined,
+ .head = .{ .poll_ref = poll_ref, .globalThis = globalThis, .promise = JSC.JSPromise.Strong.init(globalThis), .allocated = false, .name = name_str },
};
+ request.tail = &request.head;
+ if (cache == .new) {
+ request.resolver_for_caching = resolver;
+ request.cache = @This().CacheConfig{
+ .pending_cache = true,
+ .entry_cache = false,
+ .pos_in_pending = @truncate(u5, @field(resolver.?, cache_field).indexOf(cache.new).?),
+ .name_len = @truncate(u9, name.len),
+ };
+ cache.new.lookup = request;
+ }
+ return request;
}
- };
- pub fn onCaresComplete(this: *ResolveSrvInfoRequest, err_: ?c_ares.Error, timeout: i32, result: ?*c_ares.struct_ares_srv_reply) void {
- if (this.resolver_for_caching) |resolver| {
- if (this.cache.pending_cache) {
- resolver.drainPendingSrvCares(
- this.cache.pos_in_pending,
- err_,
- timeout,
- result,
- );
- return;
+ pub const CacheConfig = packed struct(u16) {
+ pending_cache: bool = false,
+ entry_cache: bool = false,
+ pos_in_pending: u5 = 0,
+ name_len: u9 = 0,
+ };
+
+ pub const PendingCacheKey = struct {
+ hash: u64,
+ len: u16,
+ lookup: *request_type = undefined,
+
+ pub fn append(this: *PendingCacheKey, cares_lookup: *CAresLookup(cares_type, type_name)) void {
+ var tail = this.lookup.tail;
+ tail.next = cares_lookup;
+ this.lookup.tail = cares_lookup;
}
- }
- var head = this.head;
- bun.default_allocator.destroy(this);
+ pub fn init(name: []const u8) PendingCacheKey {
+ var hasher = std.hash.Wyhash.init(0);
+ hasher.update(name);
+ const hash = hasher.final();
+ return PendingCacheKey{
+ .hash = hash,
+ .len = @truncate(u16, name.len),
+ .lookup = undefined,
+ };
+ }
+ };
- head.processResolveSrv(err_, timeout, result);
- }
-};
+ pub fn onCaresComplete(this: *@This(), err_: ?c_ares.Error, timeout: i32, result: ?*cares_type) void {
+ if (this.resolver_for_caching) |resolver| {
+ if (this.cache.pending_cache) {
+ resolver.drainPendingCares(
+ this.cache.pos_in_pending,
+ err_,
+ timeout,
+ @This(),
+ cares_type,
+ type_name,
+ result,
+ );
+ return;
+ }
+ }
+
+ var head = this.head;
+ bun.default_allocator.destroy(this);
+
+ head.processResolve(err_, timeout, result);
+ }
+ };
+}
pub const GetAddrInfoRequest = struct {
const log = Output.scoped(.GetAddrInfoRequest, false);
@@ -934,79 +934,78 @@ pub const GetAddrInfoRequest = struct {
}
};
-pub const SrvLookup = struct {
- const log = Output.scoped(.SrvLookup, true);
-
- globalThis: *JSC.JSGlobalObject = undefined,
- promise: JSC.JSPromise.Strong,
- poll_ref: JSC.PollRef,
- allocated: bool = false,
- next: ?*SrvLookup = null,
+pub fn CAresLookup(comptime cares_type: type, comptime type_name: []const u8) type {
+ return struct {
+ const log = Output.scoped(@This(), true);
+
+ globalThis: *JSC.JSGlobalObject = undefined,
+ promise: JSC.JSPromise.Strong,
+ poll_ref: JSC.PollRef,
+ allocated: bool = false,
+ next: ?*@This() = null,
+ name: *const JSC.ZigString.Slice,
+
+ pub fn init(globalThis: *JSC.JSGlobalObject, allocator: std.mem.Allocator, name: *const JSC.ZigString.Slice) !*@This() {
+ var this = try allocator.create(@This());
+ var poll_ref = JSC.PollRef.init();
+ poll_ref.ref(globalThis.bunVM());
+ this.* = .{ .globalThis = globalThis, .promise = JSC.JSPromise.Strong.init(globalThis), .poll_ref = poll_ref, .allocated = true, .name = name };
+ return this;
+ }
- pub fn init(globalThis: *JSC.JSGlobalObject, allocator: std.mem.Allocator) !*SrvLookup {
- var this = try allocator.create(SrvLookup);
- var poll_ref = JSC.PollRef.init();
- poll_ref.ref(globalThis.bunVM());
- this.* = .{
- .globalThis = globalThis,
- .promise = JSC.JSPromise.Strong.init(globalThis),
- .poll_ref = poll_ref,
- .allocated = true,
- };
- return this;
- }
+ pub fn processResolve(this: *@This(), err_: ?c_ares.Error, _: i32, result: ?*cares_type) void {
+ if (err_) |err| {
+ var promise = this.promise;
+ var globalThis = this.globalThis;
+ const error_value = globalThis.createErrorInstance("{s} lookup failed: {s}", .{ type_name, err.label() });
+ error_value.put(
+ globalThis,
+ JSC.ZigString.static("code"),
+ JSC.ZigString.init(err.code()).toValueGC(globalThis),
+ );
- pub fn processResolveSrv(this: *SrvLookup, err_: ?c_ares.Error, _: i32, result: ?*c_ares.struct_ares_srv_reply) void {
- if (err_) |err| {
- var promise = this.promise;
- var globalThis = this.globalThis;
- const error_value = globalThis.createErrorInstance("SRV lookup failed: {s}", .{err.label()});
- error_value.put(
- globalThis,
- JSC.ZigString.static("code"),
- JSC.ZigString.init(err.code()).toValueGC(globalThis),
- );
+ promise.reject(globalThis, error_value);
+ this.deinit();
+ return;
+ }
+ if (result == null) {
+ var promise = this.promise;
+ var globalThis = this.globalThis;
+ const error_value = globalThis.createErrorInstance("{s} lookup failed: {s}", .{ type_name, "No results" });
+ error_value.put(
+ globalThis,
+ JSC.ZigString.static("code"),
+ JSC.ZigString.init("EUNREACHABLE").toValueGC(globalThis),
+ );
- promise.reject(globalThis, error_value);
- this.deinit();
+ promise.reject(globalThis, error_value);
+ this.deinit();
+ return;
+ }
+ var node = result.?;
+ const array = node.toJSReponse(this.globalThis.allocator(), this.globalThis, type_name);
+ this.onComplete(array);
return;
}
- if (result == null or result.?.next == null) {
+ pub fn onComplete(this: *@This(), result: JSC.JSValue) void {
var promise = this.promise;
var globalThis = this.globalThis;
- const error_value = globalThis.createErrorInstance("SRV lookup failed: {s}", .{"No results"});
- error_value.put(
- globalThis,
- JSC.ZigString.static("code"),
- JSC.ZigString.init("EUNREACHABLE").toValueGC(globalThis),
- );
-
- promise.reject(globalThis, error_value);
+ this.promise = .{};
+ promise.resolve(globalThis, result);
this.deinit();
- return;
}
- var node = result.?;
- const array = node.toJSArray(this.globalThis.allocator(), this.globalThis);
- this.onComplete(array);
- return;
- }
- pub fn onComplete(this: *SrvLookup, result: JSC.JSValue) void {
- var promise = this.promise;
- var globalThis = this.globalThis;
- this.promise = .{};
- promise.resolve(globalThis, result);
- this.deinit();
- }
+ pub fn deinit(this: *@This()) void {
+ this.poll_ref.unrefOnNextTick(this.globalThis.bunVM());
+ this.name.deinit();
- pub fn deinit(this: *SrvLookup) void {
- this.poll_ref.unrefOnNextTick(this.globalThis.bunVM());
+ if (this.allocated)
+ this.globalThis.allocator().destroy(this);
+ }
+ };
+}
- if (this.allocated)
- this.globalThis.allocator().destroy(this);
- }
-};
pub const DNSLookup = struct {
const log = Output.scoped(.DNSLookup, true);
@@ -1141,15 +1140,30 @@ pub const DNSResolver = struct {
polls: std.AutoArrayHashMap(i32, ?*JSC.FilePoll) = undefined,
pending_host_cache_cares: PendingCache = PendingCache.init(),
- pending_srv_cache_cares: SrvPendingCache = SrvPendingCache.init(),
pending_host_cache_native: PendingCache = PendingCache.init(),
- // entry_host_cache: std.BoundedArray(128)
+ pending_srv_cache_cares: SrvPendingCache = SrvPendingCache.init(),
+ pending_soa_cache_cares: SoaPendingCache = SoaPendingCache.init(),
+ pending_txt_cache_cares: TxtPendingCache = TxtPendingCache.init(),
+ pending_naptr_cache_cares: NaptrPendingCache = NaptrPendingCache.init(),
+ pending_mx_cache_cares: MxPendingCache = MxPendingCache.init(),
+ pending_caa_cache_cares: CaaPendingCache = CaaPendingCache.init(),
+ pending_ns_cache_cares: NSPendingCache = NSPendingCache.init(),
+ pending_ptr_cache_cares: PtrPendingCache = PtrPendingCache.init(),
+ pending_cname_cache_cares: CnamePendingCache = CnamePendingCache.init(),
const PendingCache = bun.HiveArray(GetAddrInfoRequest.PendingCacheKey, 32);
- const SrvPendingCache = bun.HiveArray(ResolveSrvInfoRequest.PendingCacheKey, 32);
-
- fn getKey(this: *DNSResolver, index: u8, comptime cache_name: []const u8) GetAddrInfoRequest.PendingCacheKey {
- var cache: *PendingCache = &@field(this, cache_name);
+ const SrvPendingCache = bun.HiveArray(ResolveInfoRequest(c_ares.struct_ares_srv_reply, "srv").PendingCacheKey, 32);
+ const SoaPendingCache = bun.HiveArray(ResolveInfoRequest(c_ares.struct_ares_soa_reply, "soa").PendingCacheKey, 32);
+ const TxtPendingCache = bun.HiveArray(ResolveInfoRequest(c_ares.struct_ares_txt_reply, "txt").PendingCacheKey, 32);
+ const NaptrPendingCache = bun.HiveArray(ResolveInfoRequest(c_ares.struct_ares_naptr_reply, "naptr").PendingCacheKey, 32);
+ const MxPendingCache = bun.HiveArray(ResolveInfoRequest(c_ares.struct_ares_mx_reply, "mx").PendingCacheKey, 32);
+ const CaaPendingCache = bun.HiveArray(ResolveInfoRequest(c_ares.struct_ares_caa_reply, "caa").PendingCacheKey, 32);
+ const NSPendingCache = bun.HiveArray(ResolveInfoRequest(c_ares.struct_hostent, "ns").PendingCacheKey, 32);
+ const PtrPendingCache = bun.HiveArray(ResolveInfoRequest(c_ares.struct_hostent, "ptr").PendingCacheKey, 32);
+ const CnamePendingCache = bun.HiveArray(ResolveInfoRequest(c_ares.struct_hostent, "cname").PendingCacheKey, 32);
+
+ fn getKey(this: *DNSResolver, index: u8, comptime cache_name: []const u8, comptime request_type: type) request_type.PendingCacheKey {
+ var cache = &@field(this, cache_name);
std.debug.assert(!cache.available.isSet(index));
const entry = cache.buffer[index];
cache.buffer[index] = undefined;
@@ -1160,37 +1174,27 @@ pub const DNSResolver = struct {
return entry;
}
- fn getSrvKey(this: *DNSResolver, index: u8, comptime cache_name: []const u8) ResolveSrvInfoRequest.PendingCacheKey {
- var cache: *SrvPendingCache = &@field(this, cache_name);
- std.debug.assert(!cache.available.isSet(index));
- const entry = cache.buffer[index];
- cache.buffer[index] = undefined;
- var available = cache.available;
- available.set(index);
- cache.available = available;
-
- return entry;
- }
+ pub fn drainPendingCares(this: *DNSResolver, index: u8, err: ?c_ares.Error, timeout: i32, comptime request_type: type, comptime cares_type: type, comptime lookup_name: []const u8, result: ?*cares_type) void {
+ const cache_name = comptime std.fmt.comptimePrint("pending_{s}_cache_cares", .{lookup_name});
- pub fn drainPendingSrvCares(this: *DNSResolver, index: u8, err: ?c_ares.Error, timeout: i32, result: ?*c_ares.struct_ares_srv_reply) void {
- const key = this.getSrvKey(index, "pending_srv_cache_cares");
+ const key = this.getKey(index, cache_name, request_type);
var addr = result orelse {
- var pending: ?*SrvLookup = key.lookup.head.next;
- key.lookup.head.processResolveSrv(err, timeout, null);
+ var pending: ?*CAresLookup(cares_type, lookup_name) = key.lookup.head.next;
+ key.lookup.head.processResolve(err, timeout, null);
bun.default_allocator.destroy(key.lookup);
while (pending) |value| {
pending = value.next;
- value.processResolveSrv(err, timeout, null);
+ value.processResolve(err, timeout, null);
}
return;
};
- var pending: ?*SrvLookup = key.lookup.head.next;
+ var pending: ?*CAresLookup(cares_type, lookup_name) = key.lookup.head.next;
var prev_global = key.lookup.head.globalThis;
- var array = addr.toJSArray(this.vm.allocator, prev_global);
+ var array = addr.toJSReponse(this.vm.allocator, prev_global, lookup_name);
defer addr.deinit();
array.ensureStillAlive();
key.lookup.head.onComplete(array);
@@ -1201,7 +1205,7 @@ pub const DNSResolver = struct {
while (pending) |value| {
var new_global = value.globalThis;
if (prev_global != new_global) {
- array = addr.toJSArray(this.vm.allocator, new_global);
+ array = addr.toJSReponse(this.vm.allocator, new_global, lookup_name);
prev_global = new_global;
}
pending = value.next;
@@ -1215,7 +1219,7 @@ pub const DNSResolver = struct {
}
pub fn drainPendingHostCares(this: *DNSResolver, index: u8, err: ?c_ares.Error, timeout: i32, result: ?*c_ares.AddrInfo) void {
- const key = this.getKey(index, "pending_host_cache_cares");
+ const key = this.getKey(index, "pending_host_cache_cares", GetAddrInfoRequest);
var addr = result orelse {
var pending: ?*DNSLookup = key.lookup.head.next;
@@ -1257,7 +1261,7 @@ pub const DNSResolver = struct {
}
pub fn drainPendingHostNative(this: *DNSResolver, index: u8, globalObject: *JSC.JSGlobalObject, err: i32, result: GetAddrInfo.Result.Any) void {
- const key = this.getKey(index, "pending_host_cache_native");
+ const key = this.getKey(index, "pending_host_cache_native", GetAddrInfoRequest);
var array = result.toJS(globalObject) orelse {
var pending: ?*DNSLookup = key.lookup.head.next;
@@ -1305,18 +1309,22 @@ pub const DNSResolver = struct {
new: *GetAddrInfoRequest.PendingCacheKey,
disabled: void,
};
- pub const SrvCacheHit = union(enum) {
- inflight: *ResolveSrvInfoRequest.PendingCacheKey,
- new: *ResolveSrvInfoRequest.PendingCacheKey,
- disabled: void,
- };
- pub fn getOrPutIntoSrvPendingCache(
+ pub fn LookupCacheHit(comptime request_type: type) type {
+ return union(enum) {
+ inflight: *request_type.PendingCacheKey,
+ new: *request_type.PendingCacheKey,
+ disabled: void,
+ };
+ }
+
+ pub fn getOrPutIntoResolvePendingCache(
this: *DNSResolver,
- key: ResolveSrvInfoRequest.PendingCacheKey,
- comptime field: std.meta.FieldEnum(DNSResolver),
- ) SrvCacheHit {
- var cache: *SrvPendingCache = &@field(this, @tagName(field));
+ comptime request_type: type,
+ key: request_type.PendingCacheKey,
+ comptime field: []const u8,
+ ) LookupCacheHit(request_type) {
+ var cache = &@field(this, field);
var inflight_iter = cache.available.iterator(
.{
.kind = .unset,
@@ -1324,7 +1332,7 @@ pub const DNSResolver = struct {
);
while (inflight_iter.next()) |index| {
- var entry: *ResolveSrvInfoRequest.PendingCacheKey = &cache.buffer[index];
+ var entry: *request_type.PendingCacheKey = &cache.buffer[index];
if (entry.hash == key.hash and entry.len == key.len) {
return .{ .inflight = entry };
}
@@ -1504,7 +1512,6 @@ pub const DNSResolver = struct {
return .zero;
};
};
- _ = record_type;
const name_value = arguments.ptr[0];
@@ -1522,9 +1529,44 @@ pub const DNSResolver = struct {
return .zero;
}
- // const name = name_str.toSliceZ(globalThis).cloneZ(bun.default_allocator) catch unreachable;
- // TODO:
- return JSC.JSValue.jsUndefined();
+ const name = name_str.toSlice(globalThis, bun.default_allocator);
+
+ var vm = globalThis.bunVM();
+ var resolver = vm.rareData().globalDNSResolver(vm);
+ //TODO: ANY CASE
+ switch (record_type) {
+ RecordType.A => {
+ defer name.deinit();
+ const options = GetAddrInfo.Options{ .family = GetAddrInfo.Family.inet };
+ return resolver.doLookup(name.slice(), 0, options, globalThis);
+ },
+ RecordType.AAAA => {
+ defer name.deinit();
+ const options = GetAddrInfo.Options{ .family = GetAddrInfo.Family.inet6 };
+ return resolver.doLookup(name.slice(), 0, options, globalThis);
+ },
+ RecordType.CNAME => {
+ return resolver.doResolveCAres(c_ares.struct_hostent, "cname", &name, globalThis);
+ },
+ RecordType.MX => {
+ return resolver.doResolveCAres(c_ares.struct_ares_mx_reply, "mx", &name, globalThis);
+ },
+ RecordType.NS => {
+ return resolver.doResolveCAres(c_ares.struct_hostent, "ns", &name, globalThis);
+ },
+ RecordType.PTR => {
+ return resolver.doResolveCAres(c_ares.struct_hostent, "ptr", &name, globalThis);
+ },
+ RecordType.SOA => {
+ return resolver.doResolveCAres(c_ares.struct_ares_soa_reply, "soa", &name, globalThis);
+ },
+ RecordType.SRV => {
+ return resolver.doResolveCAres(c_ares.struct_ares_srv_reply, "srv", &name, globalThis);
+ },
+ RecordType.TXT => {
+ return resolver.doResolveCAres(c_ares.struct_ares_txt_reply, "txt", &name, globalThis);
+ },
+ }
}
// pub fn reverse(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue {
// const arguments = callframe.arguments(3);
@@ -1622,14 +1664,264 @@ pub const DNSResolver = struct {
}
const name = name_str.toSlice(globalThis, bun.default_allocator);
- defer name.deinit();
+
var vm = globalThis.bunVM();
var resolver = vm.rareData().globalDNSResolver(vm);
- return resolver.doResolveSrv(name.slice(), globalThis);
+ return resolver.doResolveCAres(c_ares.struct_ares_srv_reply, "srv", &name, globalThis);
}
- pub fn doResolveSrv(this: *DNSResolver, name: []const u8, globalThis: *JSC.JSGlobalObject) JSC.JSValue {
+ pub fn resolveSoa(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ const arguments = callframe.arguments(2);
+ if (arguments.len < 1) {
+ globalThis.throwNotEnoughArguments("resolveSoa", 2, arguments.len);
+ return .zero;
+ }
+
+ const name_value = arguments.ptr[0];
+
+ if (name_value.isEmptyOrUndefinedOrNull() or !name_value.isString()) {
+ globalThis.throwInvalidArgumentType("resolveSoa", "hostname", "string");
+ return .zero;
+ }
+
+ const name_str = name_value.toStringOrNull(globalThis) orelse {
+ return .zero;
+ };
+
+ if (name_str.length() == 0) {
+ globalThis.throwInvalidArgumentType("resolveSoa", "hostname", "non-empty string");
+ return .zero;
+ }
+
+ const name = name_str.toSlice(globalThis, bun.default_allocator);
+
+ var vm = globalThis.bunVM();
+ var resolver = vm.rareData().globalDNSResolver(vm);
+
+ return resolver.doResolveCAres(c_ares.struct_ares_soa_reply, "soa", &name, globalThis);
+ }
+
+ pub fn resolveCaa(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ const arguments = callframe.arguments(2);
+ if (arguments.len < 1) {
+ globalThis.throwNotEnoughArguments("resolveCaa", 2, arguments.len);
+ return .zero;
+ }
+
+ const name_value = arguments.ptr[0];
+
+ if (name_value.isEmptyOrUndefinedOrNull() or !name_value.isString()) {
+ globalThis.throwInvalidArgumentType("resolveCaa", "hostname", "string");
+ return .zero;
+ }
+
+ const name_str = name_value.toStringOrNull(globalThis) orelse {
+ return .zero;
+ };
+
+ if (name_str.length() == 0) {
+ globalThis.throwInvalidArgumentType("resolveCaa", "hostname", "non-empty string");
+ return .zero;
+ }
+
+ const name = name_str.toSlice(globalThis, bun.default_allocator);
+
+ var vm = globalThis.bunVM();
+ var resolver = vm.rareData().globalDNSResolver(vm);
+
+ return resolver.doResolveCAres(c_ares.struct_ares_caa_reply, "caa", &name, globalThis);
+ }
+
+ pub fn resolveNs(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ const arguments = callframe.arguments(2);
+ if (arguments.len < 1) {
+ globalThis.throwNotEnoughArguments("resolveNs", 2, arguments.len);
+ return .zero;
+ }
+
+ const name_value = arguments.ptr[0];
+
+ if (name_value.isEmptyOrUndefinedOrNull() or !name_value.isString()) {
+ globalThis.throwInvalidArgumentType("resolveNs", "hostname", "string");
+ return .zero;
+ }
+
+ const name_str = name_value.toStringOrNull(globalThis) orelse {
+ return .zero;
+ };
+
+ if (name_str.length() == 0) {
+ globalThis.throwInvalidArgumentType("resolveNs", "hostname", "non-empty string");
+ return .zero;
+ }
+
+ const name = name_str.toSlice(globalThis, bun.default_allocator);
+
+ var vm = globalThis.bunVM();
+ var resolver = vm.rareData().globalDNSResolver(vm);
+
+ return resolver.doResolveCAres(c_ares.struct_hostent, "ns", &name, globalThis);
+ }
+
+ pub fn resolvePtr(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ const arguments = callframe.arguments(2);
+ if (arguments.len < 1) {
+ globalThis.throwNotEnoughArguments("resolvePtr", 2, arguments.len);
+ return .zero;
+ }
+
+ const name_value = arguments.ptr[0];
+
+ if (name_value.isEmptyOrUndefinedOrNull() or !name_value.isString()) {
+ globalThis.throwInvalidArgumentType("resolvePtr", "hostname", "string");
+ return .zero;
+ }
+
+ const name_str = name_value.toStringOrNull(globalThis) orelse {
+ return .zero;
+ };
+
+ if (name_str.length() == 0) {
+ globalThis.throwInvalidArgumentType("resolvePtr", "hostname", "non-empty string");
+ return .zero;
+ }
+
+ const name = name_str.toSlice(globalThis, bun.default_allocator);
+
+ var vm = globalThis.bunVM();
+ var resolver = vm.rareData().globalDNSResolver(vm);
+
+ return resolver.doResolveCAres(c_ares.struct_hostent, "ptr", &name, globalThis);
+ }
+
+ pub fn resolveCname(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ const arguments = callframe.arguments(2);
+ if (arguments.len < 1) {
+ globalThis.throwNotEnoughArguments("resolveCname", 2, arguments.len);
+ return .zero;
+ }
+
+ const name_value = arguments.ptr[0];
+
+ if (name_value.isEmptyOrUndefinedOrNull() or !name_value.isString()) {
+ globalThis.throwInvalidArgumentType("resolveCname", "hostname", "string");
+ return .zero;
+ }
+
+ const name_str = name_value.toStringOrNull(globalThis) orelse {
+ return .zero;
+ };
+
+ if (name_str.length() == 0) {
+ globalThis.throwInvalidArgumentType("resolveCname", "hostname", "non-empty string");
+ return .zero;
+ }
+
+ const name = name_str.toSlice(globalThis, bun.default_allocator);
+
+ var vm = globalThis.bunVM();
+ var resolver = vm.rareData().globalDNSResolver(vm);
+
+ return resolver.doResolveCAres(c_ares.struct_hostent, "cname", &name, globalThis);
+ }
+
+ pub fn resolveMx(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ const arguments = callframe.arguments(2);
+ if (arguments.len < 1) {
+ globalThis.throwNotEnoughArguments("resolveMx", 2, arguments.len);
+ return .zero;
+ }
+
+ const name_value = arguments.ptr[0];
+
+ if (name_value.isEmptyOrUndefinedOrNull() or !name_value.isString()) {
+ globalThis.throwInvalidArgumentType("resolveMx", "hostname", "string");
+ return .zero;
+ }
+
+ const name_str = name_value.toStringOrNull(globalThis) orelse {
+ return .zero;
+ };
+
+ if (name_str.length() == 0) {
+ globalThis.throwInvalidArgumentType("resolveMx", "hostname", "non-empty string");
+ return .zero;
+ }
+
+ const name = name_str.toSlice(globalThis, bun.default_allocator);
+
+ var vm = globalThis.bunVM();
+ var resolver = vm.rareData().globalDNSResolver(vm);
+
+ return resolver.doResolveCAres(c_ares.struct_ares_mx_reply, "mx", &name, globalThis);
+ }
+
+ pub fn resolveNaptr(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ const arguments = callframe.arguments(2);
+ if (arguments.len < 1) {
+ globalThis.throwNotEnoughArguments("resolveNaptr", 2, arguments.len);
+ return .zero;
+ }
+
+ const name_value = arguments.ptr[0];
+
+ if (name_value.isEmptyOrUndefinedOrNull() or !name_value.isString()) {
+ globalThis.throwInvalidArgumentType("resolveNaptr", "hostname", "string");
+ return .zero;
+ }
+
+ const name_str = name_value.toStringOrNull(globalThis) orelse {
+ return .zero;
+ };
+
+ if (name_str.length() == 0) {
+ globalThis.throwInvalidArgumentType("resolveNaptr", "hostname", "non-empty string");
+ return .zero;
+ }
+
+ const name = name_str.toSlice(globalThis, bun.default_allocator);
+
+ var vm = globalThis.bunVM();
+ var resolver = vm.rareData().globalDNSResolver(vm);
+
+ return resolver.doResolveCAres(c_ares.struct_ares_naptr_reply, "naptr", &name, globalThis);
+ }
+
+ pub fn resolveTxt(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue {
+ const arguments = callframe.arguments(2);
+ if (arguments.len < 1) {
+ globalThis.throwNotEnoughArguments("resolveTxt", 2, arguments.len);
+ return .zero;
+ }
+
+ const name_value = arguments.ptr[0];
+
+ if (name_value.isEmptyOrUndefinedOrNull() or !name_value.isString()) {
+ globalThis.throwInvalidArgumentType("resolveTxt", "hostname", "string");
+ return .zero;
+ }
+
+ const name_str = name_value.toStringOrNull(globalThis) orelse {
+ return .zero;
+ };
+
+ if (name_str.length() == 0) {
+ globalThis.throwInvalidArgumentType("resolveTxt", "hostname", "non-empty string");
+ return .zero;
+ }
+
+ const name = name_str.toSlice(globalThis, bun.default_allocator);
+
+ var vm = globalThis.bunVM();
+ var resolver = vm.rareData().globalDNSResolver(vm);
+
+ return resolver.doResolveCAres(c_ares.struct_ares_txt_reply, "txt", &name, globalThis);
+ }
+
+ pub fn doResolveCAres(this: *DNSResolver, comptime cares_type: type, comptime type_name: []const u8, name_str: *const JSC.ZigString.Slice, globalThis: *JSC.JSGlobalObject) JSC.JSValue {
+ var name = name_str.slice();
+
var channel: *c_ares.Channel = switch (this.getChannel()) {
.result => |res| res,
.err => |err| {
@@ -1644,29 +1936,34 @@ pub const DNSResolver = struct {
},
};
- const key = ResolveSrvInfoRequest.PendingCacheKey.init(name);
+ const cache_name = comptime std.fmt.comptimePrint("pending_{s}_cache_cares", .{type_name});
+
+ const key = ResolveInfoRequest(cares_type, type_name).PendingCacheKey.init(name);
- var cache = this.getOrPutIntoSrvPendingCache(key, .pending_srv_cache_cares);
+ var cache = this.getOrPutIntoResolvePendingCache(ResolveInfoRequest(cares_type, type_name), key, cache_name);
if (cache == .inflight) {
- var srv_lookup = SrvLookup.init(globalThis, globalThis.allocator()) catch unreachable;
- cache.inflight.append(srv_lookup);
- return srv_lookup.promise.value();
+ // CAresLookup will have the name ownership
+ var cares_lookup = CAresLookup(cares_type, type_name).init(globalThis, globalThis.allocator(), name_str) catch unreachable;
+ cache.inflight.append(cares_lookup);
+ return cares_lookup.promise.value();
}
- var request = ResolveSrvInfoRequest.init(
+ var request = ResolveInfoRequest(cares_type, type_name).init(
cache,
this,
- name,
+ name_str, // CAresLookup will have the ownership
globalThis,
- "pending_srv_cache_cares",
+ cache_name,
) catch unreachable;
const promise = request.tail.promise.value();
- channel.resolveSrv(
+ channel.resolve(
name,
- ResolveSrvInfoRequest,
+ type_name,
+ ResolveInfoRequest(cares_type, type_name),
request,
- ResolveSrvInfoRequest.onCaresComplete,
+ cares_type,
+ ResolveInfoRequest(cares_type, type_name).onCaresComplete,
);
return promise;
@@ -1722,17 +2019,71 @@ pub const DNSResolver = struct {
comptime {
@export(
+ resolve,
+ .{
+ .name = "Bun__DNSResolver__resolve",
+ },
+ );
+ @export(
lookup,
.{
.name = "Bun__DNSResolver__lookup",
},
);
@export(
+ resolveTxt,
+ .{
+ .name = "Bun__DNSResolver__resolveTxt",
+ },
+ );
+ @export(
+ resolveSoa,
+ .{
+ .name = "Bun__DNSResolver__resolveSoa",
+ },
+ );
+ @export(
+ resolveMx,
+ .{
+ .name = "Bun__DNSResolver__resolveMx",
+ },
+ );
+ @export(
+ resolveNaptr,
+ .{
+ .name = "Bun__DNSResolver__resolveNaptr",
+ },
+ );
+ @export(
resolveSrv,
.{
.name = "Bun__DNSResolver__resolveSrv",
},
);
+ @export(
+ resolveCaa,
+ .{
+ .name = "Bun__DNSResolver__resolveCaa",
+ },
+ );
+ @export(
+ resolveNs,
+ .{
+ .name = "Bun__DNSResolver__resolveNs",
+ },
+ );
+ @export(
+ resolvePtr,
+ .{
+ .name = "Bun__DNSResolver__resolvePtr",
+ },
+ );
+ @export(
+ resolveCname,
+ .{
+ .name = "Bun__DNSResolver__resolveCname",
+ },
+ );
}
// pub fn lookupService(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSC.JSValue {
// const arguments = callframe.arguments(3);