aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/bun-types/dns.d.ts368
-rw-r--r--packages/bun-types/dns/promises.d.ts86
-rw-r--r--src/bun.js/api/bun/dns_resolver.zig759
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp27
-rw-r--r--src/bun.js/node-dns.exports.js371
-rw-r--r--src/bun.js/webcore/encoding.zig14
-rw-r--r--src/deps/c_ares.zig489
m---------src/deps/uws0
-rw-r--r--test/bun.js/node-dns.test.js144
9 files changed, 1736 insertions, 522 deletions
diff --git a/packages/bun-types/dns.d.ts b/packages/bun-types/dns.d.ts
index a51afe145..f5c24c7f2 100644
--- a/packages/bun-types/dns.d.ts
+++ b/packages/bun-types/dns.d.ts
@@ -318,127 +318,127 @@ declare module "dns" {
hostname: string,
callback: (err: ErrnoException | null, addresses: string[]) => void,
): void;
- // export function resolve(
- // hostname: string,
- // rrtype: "A",
- // callback: (err: ErrnoException | null, addresses: string[]) => void,
- // ): void;
- // export function resolve(
- // hostname: string,
- // rrtype: "AAAA",
- // callback: (err: ErrnoException | null, addresses: string[]) => void,
- // ): void;
- // export function resolve(
- // hostname: string,
- // rrtype: "ANY",
- // callback: (
- // err: ErrnoException | null,
- // addresses: AnyRecord[],
- // ) => void,
- // ): void;
- // export function resolve(
- // hostname: string,
- // rrtype: "CNAME",
- // callback: (err: ErrnoException | null, addresses: string[]) => void,
- // ): void;
- // export function resolve(
- // hostname: string,
- // rrtype: "MX",
- // callback: (
- // err: ErrnoException | null,
- // addresses: MxRecord[],
- // ) => void,
- // ): void;
- // export function resolve(
- // hostname: string,
- // rrtype: "NAPTR",
- // callback: (
- // err: ErrnoException | null,
- // addresses: NaptrRecord[],
- // ) => void,
- // ): void;
- // export function resolve(
- // hostname: string,
- // rrtype: "NS",
- // callback: (err: ErrnoException | null, addresses: string[]) => void,
- // ): void;
- // export function resolve(
- // hostname: string,
- // rrtype: "PTR",
- // callback: (err: ErrnoException | null, addresses: string[]) => void,
- // ): void;
- // export function resolve(
- // hostname: string,
- // rrtype: "SOA",
- // callback: (err: ErrnoException | null, addresses: SoaRecord) => void,
- // ): void;
- // export function resolve(
- // hostname: string,
- // rrtype: "SRV",
- // callback: (
- // err: ErrnoException | null,
- // addresses: SrvRecord[],
- // ) => void,
- // ): void;
- // export function resolve(
- // hostname: string,
- // rrtype: "TXT",
- // callback: (
- // err: ErrnoException | null,
- // addresses: string[][],
- // ) => void,
- // ): void;
- // export function resolve(
- // hostname: string,
- // rrtype: string,
- // callback: (
- // err: ErrnoException | null,
- // addresses:
- // | string[]
- // | MxRecord[]
- // | NaptrRecord[]
- // | SoaRecord
- // | SrvRecord[]
- // | string[][]
- // | AnyRecord[],
- // ) => void,
- // ): void;
- // export namespace resolve {
- // function __promisify__(
- // hostname: string,
- // rrtype?: "A" | "AAAA" | "CNAME" | "NS" | "PTR",
- // ): Promise<string[]>;
- // function __promisify__(
- // hostname: string,
- // rrtype: "ANY",
- // ): Promise<AnyRecord[]>;
- // function __promisify__(hostname: string, rrtype: "MX"): Promise<MxRecord[]>;
- // function __promisify__(
- // hostname: string,
- // rrtype: "NAPTR",
- // ): Promise<NaptrRecord[]>;
- // function __promisify__(hostname: string, rrtype: "SOA"): Promise<SoaRecord>;
- // function __promisify__(
- // hostname: string,
- // rrtype: "SRV",
- // ): Promise<SrvRecord[]>;
- // function __promisify__(
- // hostname: string,
- // rrtype: "TXT",
- // ): Promise<string[][]>;
- // function __promisify__(
- // hostname: string,
- // rrtype: string,
- // ): Promise<
- // | string[]
- // | MxRecord[]
- // | NaptrRecord[]
- // | SoaRecord
- // | SrvRecord[]
- // | string[][]
- // | AnyRecord[]
- // >;
- // }
+ export function resolve(
+ hostname: string,
+ rrtype: "A",
+ callback: (err: ErrnoException | null, addresses: string[]) => void,
+ ): void;
+ export function resolve(
+ hostname: string,
+ rrtype: "AAAA",
+ callback: (err: ErrnoException | null, addresses: string[]) => void,
+ ): void;
+ export function resolve(
+ hostname: string,
+ rrtype: "ANY",
+ callback: (
+ err: ErrnoException | null,
+ addresses: AnyRecord[],
+ ) => void,
+ ): void;
+ export function resolve(
+ hostname: string,
+ rrtype: "CNAME",
+ callback: (err: ErrnoException | null, addresses: string[]) => void,
+ ): void;
+ export function resolve(
+ hostname: string,
+ rrtype: "MX",
+ callback: (
+ err: ErrnoException | null,
+ addresses: MxRecord[],
+ ) => void,
+ ): void;
+ export function resolve(
+ hostname: string,
+ rrtype: "NAPTR",
+ callback: (
+ err: ErrnoException | null,
+ addresses: NaptrRecord[],
+ ) => void,
+ ): void;
+ export function resolve(
+ hostname: string,
+ rrtype: "NS",
+ callback: (err: ErrnoException | null, addresses: string[]) => void,
+ ): void;
+ export function resolve(
+ hostname: string,
+ rrtype: "PTR",
+ callback: (err: ErrnoException | null, addresses: string[]) => void,
+ ): void;
+ export function resolve(
+ hostname: string,
+ rrtype: "SOA",
+ callback: (err: ErrnoException | null, addresses: SoaRecord) => void,
+ ): void;
+ export function resolve(
+ hostname: string,
+ rrtype: "SRV",
+ callback: (
+ err: ErrnoException | null,
+ addresses: SrvRecord[],
+ ) => void,
+ ): void;
+ export function resolve(
+ hostname: string,
+ rrtype: "TXT",
+ callback: (
+ err: ErrnoException | null,
+ addresses: string[][],
+ ) => void,
+ ): void;
+ export function resolve(
+ hostname: string,
+ rrtype: string,
+ callback: (
+ err: ErrnoException | null,
+ addresses:
+ | string[]
+ | MxRecord[]
+ | NaptrRecord[]
+ | SoaRecord
+ | SrvRecord[]
+ | string[][]
+ | AnyRecord[],
+ ) => void,
+ ): void;
+ export namespace resolve {
+ function __promisify__(
+ hostname: string,
+ rrtype?: "A" | "AAAA" | "CNAME" | "NS" | "PTR",
+ ): Promise<string[]>;
+ function __promisify__(
+ hostname: string,
+ rrtype: "ANY",
+ ): Promise<AnyRecord[]>;
+ function __promisify__(hostname: string, rrtype: "MX"): Promise<MxRecord[]>;
+ function __promisify__(
+ hostname: string,
+ rrtype: "NAPTR",
+ ): Promise<NaptrRecord[]>;
+ function __promisify__(hostname: string, rrtype: "SOA"): Promise<SoaRecord>;
+ function __promisify__(
+ hostname: string,
+ rrtype: "SRV",
+ ): Promise<SrvRecord[]>;
+ function __promisify__(
+ hostname: string,
+ rrtype: "TXT",
+ ): Promise<string[][]>;
+ function __promisify__(
+ hostname: string,
+ rrtype: string,
+ ): Promise<
+ | string[]
+ | MxRecord[]
+ | NaptrRecord[]
+ | SoaRecord
+ | SrvRecord[]
+ | string[][]
+ | AnyRecord[]
+ >;
+ }
/**
* Uses the DNS protocol to resolve a IPv4 addresses (`A` records) for the`hostname`. The `addresses` argument passed to the `callback` function
* will contain an array of IPv4 addresses (e.g.`['74.125.79.104', '74.125.79.105', '74.125.79.106']`).
@@ -512,38 +512,38 @@ declare module "dns" {
* will contain an array of canonical name records available for the `hostname`(e.g. `['bar.example.com']`).
* @since v0.3.2
*/
- // export function resolveCname(
- // hostname: string,
- // callback: (err: ErrnoException | null, addresses: string[]) => void,
- // ): void;
- // export namespace resolveCname {
- // function __promisify__(hostname: string): Promise<string[]>;
- // }
+ export function resolveCname(
+ hostname: string,
+ callback: (err: ErrnoException | null, addresses: string[]) => void,
+ ): void;
+ export namespace resolveCname {
+ function __promisify__(hostname: string): Promise<string[]>;
+ }
/**
* Uses the DNS protocol to resolve `CAA` records for the `hostname`. The`addresses` argument passed to the `callback` function
* will contain an array of certification authority authorization records
* available for the `hostname` (e.g. `[{critical: 0, iodef: 'mailto:pki@example.com'}, {critical: 128, issue: 'pki.example.com'}]`).
* @since v15.0.0, v14.17.0
*/
- // export function resolveCaa(
- // hostname: string,
- // callback: (err: ErrnoException | null, records: CaaRecord[]) => void,
- // ): void;
- // export namespace resolveCaa {
- // function __promisify__(hostname: string): Promise<CaaRecord[]>;
- // }
+ export function resolveCaa(
+ hostname: string,
+ callback: (err: ErrnoException | null, records: CaaRecord[]) => void,
+ ): void;
+ export namespace resolveCaa {
+ function __promisify__(hostname: string): Promise<CaaRecord[]>;
+ }
/**
* Uses the DNS protocol to resolve mail exchange records (`MX` records) for the`hostname`. The `addresses` argument passed to the `callback` function will
* contain an array of objects containing both a `priority` and `exchange`property (e.g. `[{priority: 10, exchange: 'mx.example.com'}, ...]`).
* @since v0.1.27
*/
- // export function resolveMx(
- // hostname: string,
- // callback: (err: ErrnoException | null, addresses: MxRecord[]) => void,
- // ): void;
- // export namespace resolveMx {
- // function __promisify__(hostname: string): Promise<MxRecord[]>;
- // }
+ export function resolveMx(
+ hostname: string,
+ callback: (err: ErrnoException | null, addresses: MxRecord[]) => void,
+ ): void;
+ export namespace resolveMx {
+ function __promisify__(hostname: string): Promise<MxRecord[]>;
+ }
/**
* Uses the DNS protocol to resolve regular expression based records (`NAPTR`records) for the `hostname`. The `addresses` argument passed to the `callback`function will contain an array of
* objects with the following properties:
@@ -567,37 +567,37 @@ declare module "dns" {
* ```
* @since v0.9.12
*/
- // export function resolveNaptr(
- // hostname: string,
- // callback: (err: ErrnoException | null, addresses: NaptrRecord[]) => void,
- // ): void;
- // export namespace resolveNaptr {
- // function __promisify__(hostname: string): Promise<NaptrRecord[]>;
- // }
+ export function resolveNaptr(
+ hostname: string,
+ callback: (err: ErrnoException | null, addresses: NaptrRecord[]) => void,
+ ): void;
+ export namespace resolveNaptr {
+ function __promisify__(hostname: string): Promise<NaptrRecord[]>;
+ }
/**
* Uses the DNS protocol to resolve name server records (`NS` records) for the`hostname`. The `addresses` argument passed to the `callback` function will
* contain an array of name server records available for `hostname`(e.g. `['ns1.example.com', 'ns2.example.com']`).
* @since v0.1.90
*/
- // export function resolveNs(
- // hostname: string,
- // callback: (err: ErrnoException | null, addresses: string[]) => void,
- // ): void;
- // export namespace resolveNs {
- // function __promisify__(hostname: string): Promise<string[]>;
- // }
+ export function resolveNs(
+ hostname: string,
+ callback: (err: ErrnoException | null, addresses: string[]) => void,
+ ): void;
+ export namespace resolveNs {
+ function __promisify__(hostname: string): Promise<string[]>;
+ }
/**
* Uses the DNS protocol to resolve pointer records (`PTR` records) for the`hostname`. The `addresses` argument passed to the `callback` function will
* be an array of strings containing the reply records.
* @since v6.0.0
*/
- // export function resolvePtr(
- // hostname: string,
- // callback: (err: ErrnoException | null, addresses: string[]) => void,
- // ): void;
- // export namespace resolvePtr {
- // function __promisify__(hostname: string): Promise<string[]>;
- // }
+ export function resolvePtr(
+ hostname: string,
+ callback: (err: ErrnoException | null, addresses: string[]) => void,
+ ): void;
+ export namespace resolvePtr {
+ function __promisify__(hostname: string): Promise<string[]>;
+ }
/**
* Uses the DNS protocol to resolve a start of authority record (`SOA` record) for
* the `hostname`. The `address` argument passed to the `callback` function will
@@ -624,13 +624,13 @@ declare module "dns" {
* ```
* @since v0.11.10
*/
- // export function resolveSoa(
- // hostname: string,
- // callback: (err: ErrnoException | null, address: SoaRecord) => void,
- // ): void;
- // export namespace resolveSoa {
- // function __promisify__(hostname: string): Promise<SoaRecord>;
- // }
+ export function resolveSoa(
+ hostname: string,
+ callback: (err: ErrnoException | null, address: SoaRecord) => void,
+ ): void;
+ export namespace resolveSoa {
+ function __promisify__(hostname: string): Promise<SoaRecord>;
+ }
/**
* Uses the DNS protocol to resolve service records (`SRV` records) for the`hostname`. The `addresses` argument passed to the `callback` function will
* be an array of objects with the following properties:
@@ -664,13 +664,13 @@ declare module "dns" {
* treated separately.
* @since v0.1.27
*/
- // export function resolveTxt(
- // hostname: string,
- // callback: (err: ErrnoException | null, addresses: string[][]) => void,
- // ): void;
- // export namespace resolveTxt {
- // function __promisify__(hostname: string): Promise<string[][]>;
- // }
+ export function resolveTxt(
+ hostname: string,
+ callback: (err: ErrnoException | null, addresses: string[][]) => void,
+ ): void;
+ export namespace resolveTxt {
+ function __promisify__(hostname: string): Promise<string[][]>;
+ }
/**
* Uses the DNS protocol to resolve all records (also known as `ANY` or `*` query).
* The `ret` argument passed to the `callback` function will be an array containing
@@ -861,14 +861,14 @@ declare module "dns" {
resolve4: typeof resolve4;
resolve6: typeof resolve6;
// resolveAny: typeof resolveAny;
- // resolveCname: typeof resolveCname;
- // resolveMx: typeof resolveMx;
- // resolveNaptr: typeof resolveNaptr;
- // resolveNs: typeof resolveNs;
- // resolvePtr: typeof resolvePtr;
- // resolveSoa: typeof resolveSoa;
+ resolveCname: typeof resolveCname;
+ resolveMx: typeof resolveMx;
+ resolveNaptr: typeof resolveNaptr;
+ resolveNs: typeof resolveNs;
+ resolvePtr: typeof resolvePtr;
+ resolveSoa: typeof resolveSoa;
resolveSrv: typeof resolveSrv;
- // resolveTxt: typeof resolveTxt;
+ resolveTxt: typeof resolveTxt;
// reverse: typeof reverse;
/**
* The resolver instance will send its requests from the specified IP address.
diff --git a/packages/bun-types/dns/promises.d.ts b/packages/bun-types/dns/promises.d.ts
index 2b84f2c0f..7f5faad75 100644
--- a/packages/bun-types/dns/promises.d.ts
+++ b/packages/bun-types/dns/promises.d.ts
@@ -10,11 +10,11 @@ declare module "dns/promises" {
LookupOneOptions,
LookupAllOptions,
LookupOptions,
- // AnyRecord,
- // CaaRecord,
- // MxRecord,
- // NaptrRecord,
- // SoaRecord,
+ AnyRecord,
+ CaaRecord,
+ MxRecord,
+ NaptrRecord,
+ SoaRecord,
SrvRecord,
ResolveWithTtlOptions,
RecordWithTtl,
@@ -134,30 +134,30 @@ declare module "dns/promises" {
* @param [rrtype='A'] Resource record type.
*/
function resolve(hostname: string): Promise<string[]>;
- // function resolve(hostname: string, rrtype: "A"): Promise<string[]>;
- // function resolve(hostname: string, rrtype: "AAAA"): Promise<string[]>;
- // function resolve(hostname: string, rrtype: "ANY"): Promise<AnyRecord[]>;
- // function resolve(hostname: string, rrtype: "CAA"): Promise<CaaRecord[]>;
- // function resolve(hostname: string, rrtype: "CNAME"): Promise<string[]>;
- // function resolve(hostname: string, rrtype: "MX"): Promise<MxRecord[]>;
- // function resolve(hostname: string, rrtype: "NAPTR"): Promise<NaptrRecord[]>;
- // function resolve(hostname: string, rrtype: "NS"): Promise<string[]>;
- // function resolve(hostname: string, rrtype: "PTR"): Promise<string[]>;
- // function resolve(hostname: string, rrtype: "SOA"): Promise<SoaRecord>;
+ function resolve(hostname: string, rrtype: "A"): Promise<string[]>;
+ function resolve(hostname: string, rrtype: "AAAA"): Promise<string[]>;
+ function resolve(hostname: string, rrtype: "ANY"): Promise<AnyRecord[]>;
+ function resolve(hostname: string, rrtype: "CAA"): Promise<CaaRecord[]>;
+ function resolve(hostname: string, rrtype: "CNAME"): Promise<string[]>;
+ function resolve(hostname: string, rrtype: "MX"): Promise<MxRecord[]>;
+ function resolve(hostname: string, rrtype: "NAPTR"): Promise<NaptrRecord[]>;
+ function resolve(hostname: string, rrtype: "NS"): Promise<string[]>;
+ function resolve(hostname: string, rrtype: "PTR"): Promise<string[]>;
+ function resolve(hostname: string, rrtype: "SOA"): Promise<SoaRecord>;
function resolveSrv(hostname: string): Promise<SrvRecord[]>;
- // function resolve(hostname: string, rrtype: "TXT"): Promise<string[][]>;
- // function resolve(
- // hostname: string,
- // rrtype: string,
- // ): Promise<
- // | string[]
- // | MxRecord[]
- // | NaptrRecord[]
- // | SoaRecord
- // | SrvRecord[]
- // | string[][]
- // | AnyRecord[]
- // >;
+ function resolve(hostname: string, rrtype: "TXT"): Promise<string[][]>;
+ function resolve(
+ hostname: string,
+ rrtype: string,
+ ): Promise<
+ | string[]
+ | MxRecord[]
+ | NaptrRecord[]
+ | SoaRecord
+ | SrvRecord[]
+ | string[][]
+ | AnyRecord[]
+ >;
/**
* Uses the DNS protocol to resolve IPv4 addresses (`A` records) for the`hostname`. On success, the `Promise` is resolved with an array of IPv4
* addresses (e.g. `['74.125.79.104', '74.125.79.105', '74.125.79.106']`).
@@ -223,20 +223,20 @@ declare module "dns/promises" {
* certification authority authorization records available for the `hostname`(e.g. `[{critical: 0, iodef: 'mailto:pki@example.com'},{critical: 128, issue: 'pki.example.com'}]`).
* @since v15.0.0, v14.17.0
*/
- // function resolveCaa(hostname: string): Promise<CaaRecord[]>;
+ function resolveCaa(hostname: string): Promise<CaaRecord[]>;
/**
* Uses the DNS protocol to resolve `CNAME` records for the `hostname`. On success,
* the `Promise` is resolved with an array of canonical name records available for
* the `hostname` (e.g. `['bar.example.com']`).
* @since v10.6.0
*/
- // function resolveCname(hostname: string): Promise<string[]>;
+ function resolveCname(hostname: string): Promise<string[]>;
/**
* Uses the DNS protocol to resolve mail exchange records (`MX` records) for the`hostname`. On success, the `Promise` is resolved with an array of objects
* containing both a `priority` and `exchange` property (e.g.`[{priority: 10, exchange: 'mx.example.com'}, ...]`).
* @since v10.6.0
*/
- // function resolveMx(hostname: string): Promise<MxRecord[]>;
+ function resolveMx(hostname: string): Promise<MxRecord[]>;
/**
* Uses the DNS protocol to resolve regular expression based records (`NAPTR`records) for the `hostname`. On success, the `Promise` is resolved with an array
* of objects with the following properties:
@@ -260,19 +260,19 @@ declare module "dns/promises" {
* ```
* @since v10.6.0
*/
- // function resolveNaptr(hostname: string): Promise<NaptrRecord[]>;
+ function resolveNaptr(hostname: string): Promise<NaptrRecord[]>;
/**
* Uses the DNS protocol to resolve name server records (`NS` records) for the`hostname`. On success, the `Promise` is resolved with an array of name server
* records available for `hostname` (e.g.`['ns1.example.com', 'ns2.example.com']`).
* @since v10.6.0
*/
- // function resolveNs(hostname: string): Promise<string[]>;
+ function resolveNs(hostname: string): Promise<string[]>;
/**
* Uses the DNS protocol to resolve pointer records (`PTR` records) for the`hostname`. On success, the `Promise` is resolved with an array of strings
* containing the reply records.
* @since v10.6.0
*/
- // function resolvePtr(hostname: string): Promise<string[]>;
+ function resolvePtr(hostname: string): Promise<string[]>;
/**
* Uses the DNS protocol to resolve a start of authority record (`SOA` record) for
* the `hostname`. On success, the `Promise` is resolved with an object with the
@@ -299,7 +299,7 @@ declare module "dns/promises" {
* ```
* @since v10.6.0
*/
- // function resolveSoa(hostname: string): Promise<SoaRecord>;
+ function resolveSoa(hostname: string): Promise<SoaRecord>;
/**
* Uses the DNS protocol to resolve service records (`SRV` records) for the`hostname`. On success, the `Promise` is resolved with an array of objects with
* the following properties:
@@ -327,7 +327,7 @@ declare module "dns/promises" {
* treated separately.
* @since v10.6.0
*/
- // function resolveTxt(hostname: string): Promise<string[][]>;
+ function resolveTxt(hostname: string): Promise<string[][]>;
/**
* Performs a reverse DNS query that resolves an IPv4 or IPv6 address to an
* array of host names.
@@ -384,14 +384,14 @@ declare module "dns/promises" {
resolve4: typeof resolve4;
resolve6: typeof resolve6;
// resolveAny: typeof resolveAny;
- // resolveCname: typeof resolveCname;
- // resolveMx: typeof resolveMx;
- // resolveNaptr: typeof resolveNaptr;
- // resolveNs: typeof resolveNs;
- // resolvePtr: typeof resolvePtr;
- // resolveSoa: typeof resolveSoa;
+ resolveCname: typeof resolveCname;
+ resolveMx: typeof resolveMx;
+ resolveNaptr: typeof resolveNaptr;
+ resolveNs: typeof resolveNs;
+ resolvePtr: typeof resolvePtr;
+ resolveSoa: typeof resolveSoa;
resolveSrv: typeof resolveSrv;
- // resolveTxt: typeof resolveTxt;
+ resolveTxt: typeof resolveTxt;
// reverse: typeof reverse;
// setLocalAddress(ipv4?: string, ipv6?: string): void;
// setServers: typeof setServers;
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);
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index 58497cad4..fb429340f 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -2172,7 +2172,16 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionPerformMicrotask, (JSGlobalObject * globalObj
}
extern "C" EncodedJSValue Bun__DNSResolver__lookup(JSGlobalObject*, JSC::CallFrame*);
+extern "C" EncodedJSValue Bun__DNSResolver__resolve(JSGlobalObject*, JSC::CallFrame*);
extern "C" EncodedJSValue Bun__DNSResolver__resolveSrv(JSGlobalObject*, JSC::CallFrame*);
+extern "C" EncodedJSValue Bun__DNSResolver__resolveTxt(JSGlobalObject*, JSC::CallFrame*);
+extern "C" EncodedJSValue Bun__DNSResolver__resolveSoa(JSGlobalObject*, JSC::CallFrame*);
+extern "C" EncodedJSValue Bun__DNSResolver__resolveNaptr(JSGlobalObject*, JSC::CallFrame*);
+extern "C" EncodedJSValue Bun__DNSResolver__resolveMx(JSGlobalObject*, JSC::CallFrame*);
+extern "C" EncodedJSValue Bun__DNSResolver__resolveCaa(JSGlobalObject*, JSC::CallFrame*);
+extern "C" EncodedJSValue Bun__DNSResolver__resolveNs(JSGlobalObject*, JSC::CallFrame*);
+extern "C" EncodedJSValue Bun__DNSResolver__resolvePtr(JSGlobalObject*, JSC::CallFrame*);
+extern "C" EncodedJSValue Bun__DNSResolver__resolveCname(JSGlobalObject*, JSC::CallFrame*);
JSC_DEFINE_HOST_FUNCTION(jsFunctionPerformMicrotaskVariadic, (JSGlobalObject * globalObject, CallFrame* callframe))
{
@@ -3325,8 +3334,26 @@ void GlobalObject::installAPIGlobals(JSClassRef* globals, int count, JSC::VM& vm
JSC::JSObject* dnsObject = JSC::constructEmptyObject(this);
dnsObject->putDirectNativeFunction(vm, this, JSC::Identifier::fromString(vm, "lookup"_s), 2, Bun__DNSResolver__lookup, ImplementationVisibility::Public, NoIntrinsic,
JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0);
+ dnsObject->putDirectNativeFunction(vm, this, JSC::Identifier::fromString(vm, "resolve"_s), 2, Bun__DNSResolver__resolve, ImplementationVisibility::Public, NoIntrinsic,
+ JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0);
dnsObject->putDirectNativeFunction(vm, this, JSC::Identifier::fromString(vm, "resolveSrv"_s), 2, Bun__DNSResolver__resolveSrv, ImplementationVisibility::Public, NoIntrinsic,
JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0);
+ dnsObject->putDirectNativeFunction(vm, this, JSC::Identifier::fromString(vm, "resolveTxt"_s), 2, Bun__DNSResolver__resolveTxt, ImplementationVisibility::Public, NoIntrinsic,
+ JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0);
+ dnsObject->putDirectNativeFunction(vm, this, JSC::Identifier::fromString(vm, "resolveSoa"_s), 2, Bun__DNSResolver__resolveSoa, ImplementationVisibility::Public, NoIntrinsic,
+ JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0);
+ dnsObject->putDirectNativeFunction(vm, this, JSC::Identifier::fromString(vm, "resolveNaptr"_s), 2, Bun__DNSResolver__resolveNaptr, ImplementationVisibility::Public, NoIntrinsic,
+ JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0);
+ dnsObject->putDirectNativeFunction(vm, this, JSC::Identifier::fromString(vm, "resolveMx"_s), 2, Bun__DNSResolver__resolveMx, ImplementationVisibility::Public, NoIntrinsic,
+ JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0);
+ dnsObject->putDirectNativeFunction(vm, this, JSC::Identifier::fromString(vm, "resolveCaa"_s), 2, Bun__DNSResolver__resolveCaa, ImplementationVisibility::Public, NoIntrinsic,
+ JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0);
+ dnsObject->putDirectNativeFunction(vm, this, JSC::Identifier::fromString(vm, "resolveNs"_s), 2, Bun__DNSResolver__resolveNs, ImplementationVisibility::Public, NoIntrinsic,
+ JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0);
+ dnsObject->putDirectNativeFunction(vm, this, JSC::Identifier::fromString(vm, "resolvePtr"_s), 2, Bun__DNSResolver__resolvePtr, ImplementationVisibility::Public, NoIntrinsic,
+ JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0);
+ dnsObject->putDirectNativeFunction(vm, this, JSC::Identifier::fromString(vm, "resolveCname"_s), 2, Bun__DNSResolver__resolveCname, ImplementationVisibility::Public, NoIntrinsic,
+ JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0);
object->putDirect(vm, PropertyName(identifier), dnsObject, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | 0);
}
diff --git a/src/bun.js/node-dns.exports.js b/src/bun.js/node-dns.exports.js
index 864edfdbb..0bcc915cd 100644
--- a/src/bun.js/node-dns.exports.js
+++ b/src/bun.js/node-dns.exports.js
@@ -40,6 +40,128 @@ function resolveSrv(hostname, callback) {
);
}
+
+function resolveTxt(hostname, callback) {
+ if (typeof callback != "function") {
+ throw new TypeError("callback must be a function");
+ }
+
+ dns.resolveTxt(hostname, callback).then(
+ (results) => {
+ callback(null, results);
+ },
+ (error) => {
+ callback(error);
+ },
+ );
+}
+
+function resolveSoa(hostname, callback) {
+ if (typeof callback != "function") {
+ throw new TypeError("callback must be a function");
+ }
+
+ dns.resolveSoa(hostname, callback).then(
+ (results) => {
+ callback(null, results);
+ },
+ (error) => {
+ callback(error);
+ },
+ );
+}
+
+function resolveNaptr(hostname, callback) {
+ if (typeof callback != "function") {
+ throw new TypeError("callback must be a function");
+ }
+
+ dns.resolveNaptr(hostname, callback).then(
+ (results) => {
+ callback(null, results);
+ },
+ (error) => {
+ callback(error);
+ },
+ );
+}
+
+function resolveMx(hostname, callback) {
+ if (typeof callback != "function") {
+ throw new TypeError("callback must be a function");
+ }
+
+ dns.resolveMx(hostname, callback).then(
+ (results) => {
+ callback(null, results);
+ },
+ (error) => {
+ callback(error);
+ },
+ );
+
+}
+
+function resolveCaa(hostname, callback) {
+ if (typeof callback != "function") {
+ throw new TypeError("callback must be a function");
+ }
+
+ dns.resolveCaa(hostname, callback).then(
+ (results) => {
+ callback(null, results);
+ },
+ (error) => {
+ callback(error);
+ },
+ );
+}
+
+function resolveNs(hostname, callback) {
+ if (typeof callback != "function") {
+ throw new TypeError("callback must be a function");
+ }
+
+ dns.resolveNs(hostname, callback).then(
+ (results) => {
+ callback(null, results);
+ },
+ (error) => {
+ callback(error);
+ },
+ );
+}
+
+function resolvePtr(hostname, callback) {
+ if (typeof callback != "function") {
+ throw new TypeError("callback must be a function");
+ }
+
+ dns.resolvePtr(hostname, callback).then(
+ (results) => {
+ callback(null, results);
+ },
+ (error) => {
+ callback(error);
+ },
+ );
+}
+
+function resolveCname(hostname, callback) {
+ if (typeof callback != "function") {
+ throw new TypeError("callback must be a function");
+ }
+
+ dns.resolveCname(hostname, callback).then(
+ (results) => {
+ callback(null, results);
+ },
+ (error) => {
+ callback(error);
+ },
+ );
+}
+
function lookupService(address, port, callback) {
if (typeof callback != "function") {
throw new TypeError("callback must be a function");
@@ -49,9 +171,9 @@ function lookupService(address, port, callback) {
}
var InternalResolver = class Resolver {
- constructor(options) {}
+ constructor(options) { }
- cancel() {}
+ cancel() { }
getServers() {
return [];
@@ -66,13 +188,22 @@ var InternalResolver = class Resolver {
throw new TypeError("callback must be a function");
}
- dns.lookup(hostname).then(
- (addresses) => {
- callback(
- null,
- hostname,
- addresses.map(({ address }) => address),
- );
+ dns.resolve(hostname).then(
+ (results) => {
+ switch (rrtype?.toLowerCase()) {
+ case 'a':
+ case 'aaaa':
+ callback(
+ null,
+ hostname,
+ results.map(({ address }) => address),
+ );
+ break;
+ default:
+ callback(null, results);
+ break;
+ }
+
},
(error) => {
callback(error);
@@ -129,27 +260,79 @@ var InternalResolver = class Resolver {
}
resolveCname(hostname, callback) {
- callback(null, []);
+ if (typeof callback != "function") {
+ throw new TypeError("callback must be a function");
+ }
+
+ dns.resolveCname(hostname, callback).then(
+ (results) => {
+ callback(null, results);
+ },
+ (error) => {
+ callback(error);
+ },
+ );
}
resolveMx(hostname, callback) {
- callback(null, []);
+ if (typeof callback != "function") {
+ throw new TypeError("callback must be a function");
+ }
+
+ dns.resolveMx(hostname, callback).then(
+ (results) => {
+ callback(null, results);
+ },
+ (error) => {
+ callback(error);
+ },
+ );
+
}
resolveNaptr(hostname, callback) {
- callback(null, []);
+ if (typeof callback != "function") {
+ throw new TypeError("callback must be a function");
+ }
+
+ dns.resolveNaptr(hostname, callback).then(
+ (results) => {
+ callback(null, results);
+ },
+ (error) => {
+ callback(error);
+ },
+ );
}
resolveNs(hostname, callback) {
- callback(null, []);
+ if (typeof callback != "function") {
+ throw new TypeError("callback must be a function");
+ }
+
+ dns.resolveNs(hostname, callback).then(
+ (results) => {
+ callback(null, results);
+ },
+ (error) => {
+ callback(error);
+ },
+ );
}
resolvePtr(hostname, callback) {
- callback(null, []);
- }
+ if (typeof callback != "function") {
+ throw new TypeError("callback must be a function");
+ }
- resolveSoa(hostname, callback) {
- callback(null, []);
+ dns.resolvePtr(hostname, callback).then(
+ (results) => {
+ callback(null, results);
+ },
+ (error) => {
+ callback(error);
+ },
+ );
}
resolveSrv(hostname, callback) {
@@ -168,20 +351,88 @@ var InternalResolver = class Resolver {
}
resolveCaa(hostname, callback) {
- callback(null, []);
+ if (typeof callback != "function") {
+ throw new TypeError("callback must be a function");
+ }
+
+ dns.resolveCaa(hostname, callback).then(
+ (results) => {
+ callback(null, results);
+ },
+ (error) => {
+ callback(error);
+ },
+ );
}
resolveTxt(hostname, callback) {
- callback(null, []);
+ if (typeof callback != "function") {
+ throw new TypeError("callback must be a function");
+ }
+
+ dns.resolveTxt(hostname, callback).then(
+ (results) => {
+ callback(null, results);
+ },
+ (error) => {
+ callback(error);
+ },
+ );
+ }
+ resolveSoa(hostname, callback) {
+ if (typeof callback != "function") {
+ throw new TypeError("callback must be a function");
+ }
+
+ dns.resolveSoa(hostname, callback).then(
+ (results) => {
+ callback(null, results);
+ },
+ (error) => {
+ callback(error);
+ },
+ );
}
reverse(ip, callback) {
callback(null, []);
}
- setServers(servers) {}
+ setServers(servers) { }
};
+function resolve(hostname, rrtype, callback) {
+ if (typeof rrtype == "function") {
+ callback = rrtype;
+ }
+
+ if (typeof callback != "function") {
+ throw new TypeError("callback must be a function");
+ }
+
+ dns.resolve(hostname).then(
+ (results) => {
+ switch (rrtype?.toLowerCase()) {
+ case 'a':
+ case 'aaaa':
+ callback(
+ null,
+ hostname,
+ results.map(({ address }) => address),
+ );
+ break;
+ default:
+ callback(null, results);
+ break;
+ }
+
+ },
+ (error) => {
+ callback(error);
+ },
+ );
+}
+
function Resolver(options) {
return new InternalResolver(options);
}
@@ -205,8 +456,8 @@ export var {
resolveTxt,
} = InternalResolver.prototype;
-function setDefaultResultOrder() {}
-function setServers() {}
+function setDefaultResultOrder() { }
+function setServers() { }
const promisifyLookup = (res) => {
res.sort((a, b) => a.family - b.family);
@@ -214,6 +465,21 @@ const promisifyLookup = (res) => {
return { address, family };
};
+const promisifyResolve = (rrtype) => {
+ switch (rrtype?.toLowerCase()) {
+ case 'a':
+ case 'aaaa':
+ return (res) => {
+
+ res.sort((a, b) => a.family - b.family);
+ const [{ address, family }] = res;
+ return { address, family };
+ };
+ default:
+ return (res) => res;
+ }
+}
+
// promisified versions
export const promises = {
lookup(domain, options) {
@@ -225,7 +491,7 @@ export const promises = {
},
resolve(hostname, rrtype) {
- return dns.lookup(hostname);
+ return dns.resolve(hostname, rrtype).then(promisifyResolve);
},
resolve4(hostname, options) {
@@ -239,18 +505,43 @@ export const promises = {
resolveSrv(hostname) {
return dns.resolveSrv(hostname);
},
+ resolveTxt(hostname) {
+ return dns.resolveTxt(hostname);
+ },
+ resolveSoa(hostname) {
+ return dns.resolveSoa(hostname);
+ },
+ resolveNaptr(hostname) {
+ return dns.resolveNaptr(hostname);
+ },
+
+ resolveMx(hostname) {
+ return dns.resolveMx(hostname);
+ },
+ resolveCaa(hostname) {
+ return dns.resolveCaa(hostname);
+ },
+ resolveNs(hostname) {
+ return dns.resolveNs(hostname);
+ },
+ resolvePtr(hostname) {
+ return dns.resolvePtr(hostname);
+ },
+ resolveCname(hostname) {
+ return dns.resolveCname(hostname);
+ },
Resolver: class Resolver {
- constructor(options) {}
+ constructor(options) { }
- cancel() {}
+ cancel() { }
getServers() {
return [];
}
resolve(hostname, rrtype) {
- return dns.lookup(hostname);
+ return dns.resolve(hostname, rrtype).then(promisifyResolve);
}
resolve4(hostname, options) {
@@ -266,27 +557,27 @@ export const promises = {
}
resolveCname(hostname) {
- return Promise.resolve([]);
+ return dns.resolveCname(hostname);
}
resolveMx(hostname) {
- return Promise.resolve([]);
+ return dns.resolveMx(hostname);
}
resolveNaptr(hostname) {
- return Promise.resolve([]);
+ return dns.resolveNaptr(hostname);
}
resolveNs(hostname) {
- return Promise.resolve([]);
+ return dns.resolveNs(hostname);
}
resolvePtr(hostname) {
- return Promise.resolve([]);
+ return dns.resolvePtr(hostname);
}
resolveSoa(hostname) {
- return Promise.resolve([]);
+ return dns.resolveSoa(hostname);
}
resolveSrv(hostname) {
@@ -294,30 +585,22 @@ export const promises = {
}
resolveCaa(hostname) {
- return Promise.resolve([]);
+ return dns.resolveCaa(hostname);
}
resolveTxt(hostname) {
- return Promise.resolve([]);
+ return dns.resolveTxt(hostname);
}
reverse(ip) {
return Promise.resolve([]);
}
- setServers(servers) {}
+ setServers(servers) { }
},
};
for (const key of [
"resolveAny",
- "resolveCname",
- "resolveCaa",
- "resolveMx",
- "resolveNaptr",
- "resolveNs",
- "resolvePtr",
- "resolveSoa",
- "resolveTxt",
"reverse",
]) {
promises[key] = () => Promise.resolve(undefined);
@@ -369,12 +652,12 @@ const exports = {
resolveCname,
resolveCaa,
resolveMx,
- resolveNaptr,
resolveNs,
resolvePtr,
resolveSoa,
resolveSrv,
resolveTxt,
+ resolveNaptr,
promises,
[Symbol.for("CommonJS")]: 0,
};
diff --git a/src/bun.js/webcore/encoding.zig b/src/bun.js/webcore/encoding.zig
index 4f30aadae..4dc5d0bd0 100644
--- a/src/bun.js/webcore/encoding.zig
+++ b/src/bun.js/webcore/encoding.zig
@@ -860,14 +860,12 @@ pub const Encoder = struct {
switch (comptime encoding) {
JSC.Node.Encoding.buffer => {
-
const written = @min(len, to_len);
@memcpy(to, input, written);
return @intCast(i64, written);
},
.latin1, .ascii => {
-
const written = @min(len, to_len);
@memcpy(to, input, written);
@@ -899,7 +897,6 @@ pub const Encoder = struct {
var written = strings.copyLatin1IntoUTF16([]align(1) u16, output, []const u8, buf).written;
return written * 2;
-
}
},
@@ -908,7 +905,6 @@ pub const Encoder = struct {
},
JSC.Node.Encoding.base64url => {
-
var slice = strings.trim(input[0..len], "\r\n\t " ++ [_]u8{std.ascii.control_code.vt});
if (slice.len == 0)
return 0;
@@ -948,7 +944,7 @@ pub const Encoder = struct {
},
JSC.Node.Encoding.hex => {
- return len / 2;
+ return len / 2;
},
JSC.Node.Encoding.base64, JSC.Node.Encoding.base64url => {
@@ -972,12 +968,12 @@ pub const Encoder = struct {
},
// string is already encoded, just need to copy the data
JSC.Node.Encoding.ucs2, JSC.Node.Encoding.utf16le => {
- var bytes_input_len = len * 2;
- var written = @min(bytes_input_len, to_len);
+ const bytes_input_len = len * 2;
+ const written = @min(bytes_input_len, to_len);
if (written < 2) return 0;
- var fixed_len = (written/2) * 2;
- var input_u8 = @ptrCast([*] const u8, input);
+ const fixed_len = (written / 2) * 2;
+ const input_u8 = @ptrCast([*]const u8, input);
strings.copyU16IntoU8(to[0..written], []const u8, input_u8[0..fixed_len]);
return @intCast(i64, written);
},
diff --git a/src/deps/c_ares.zig b/src/deps/c_ares.zig
index bb7bda5db..c3e452772 100644
--- a/src/deps/c_ares.zig
+++ b/src/deps/c_ares.zig
@@ -1,6 +1,7 @@
const c = @import("std").c;
const std = @import("std");
const bun = @import("bun");
+const strings = bun.strings;
const iovec = @import("std").os.iovec;
const struct_in_addr = std.os.sockaddr.in;
const struct_sockaddr = std.os.sockaddr;
@@ -16,13 +17,13 @@ pub const NSClass = enum(c_int) {
/// Cookie.
ns_c_invalid = 0,
/// Internet.
- ns_c_in = 1,
+ ns_c_in = 1,
/// unallocated/unsupported.
- ns_c_2 = 2,
+ ns_c_2 = 2,
/// MIT Chaos-net.
- ns_c_chaos = 3,
+ ns_c_chaos = 3,
/// MIT Hesiod.
- ns_c_hs = 4,
+ ns_c_hs = 4,
/// Query class values which do not appear in resource records
/// for prereq. sections in update requests
ns_c_none = 254,
@@ -172,7 +173,102 @@ pub const Options = extern struct {
resolvconf_path: ?[*:0]u8 = null,
hosts_path: ?[*:0]u8 = null,
};
-pub const struct_hostent = opaque {};
+pub const struct_hostent = extern struct {
+ h_name: [*c]u8,
+ h_aliases: [*c][*c]u8,
+ h_addrtype: c_int,
+ h_length: c_int,
+ h_addr_list: [*c][*c]u8,
+
+ const JSC = bun.JSC;
+
+ pub fn toJSReponse(this: *struct_hostent, _: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime lookup_name: []const u8) JSC.JSValue {
+
+ // A cname lookup always returns a single record but we follow the common API here.
+ if (comptime strings.eqlComptime(lookup_name, "cname")) {
+ if(this.h_name != null){
+ const array = JSC.JSValue.createEmptyArray(globalThis, 1);
+ const h_name_len = bun.len(this.h_name);
+ const h_name_slice = this.h_name[0..h_name_len];
+ array.putIndex(globalThis, 0, JSC.ZigString.fromUTF8(h_name_slice).toValueGC(globalThis));
+ return array;
+ }
+ return JSC.JSValue.createEmptyArray(globalThis, 0);
+ } else {
+ if (this.h_aliases == null){
+ return JSC.JSValue.createEmptyArray(globalThis, 0);
+ }
+
+ var count: u32 = 0;
+ while (this.h_aliases[count] != null) {
+ count += 1;
+ }
+
+ const array = JSC.JSValue.createEmptyArray(globalThis, count);
+ count = 0;
+
+ while (this.h_aliases[count]) |alias| {
+ const alias_len = bun.len(alias);
+ const alias_slice = alias[0..alias_len];
+ array.putIndex(globalThis, count, JSC.ZigString.fromUTF8(alias_slice).toValueGC(globalThis));
+ count += 1;
+ }
+
+ return array;
+ }
+ }
+
+ pub fn Callback(comptime Type: type) type {
+ return fn (*Type, status: ?Error, timeouts: i32, results: ?*struct_hostent) void;
+ }
+
+ pub fn callbackWrapper(
+ comptime lookup_name: []const u8,
+ comptime Type: type,
+ comptime function: Callback(Type),
+ ) ares_callback {
+ return &struct {
+ pub fn handle(ctx: ?*anyopaque, status: c_int, timeouts: c_int, buffer: [*c]u8, buffer_length: c_int) callconv(.C) void {
+ var this = bun.cast(*Type, ctx.?);
+ if (status != ARES_SUCCESS) {
+ function(this, Error.get(status), timeouts, null);
+ return;
+ }
+
+ var start: [*c]struct_hostent = undefined;
+ if (comptime strings.eqlComptime(lookup_name, "ns")) {
+ var result = ares_parse_ns_reply(buffer, buffer_length, &start);
+ if (result != ARES_SUCCESS) {
+ function(this, Error.get(result), timeouts, null);
+ return;
+ }
+ function(this, null, timeouts, start);
+ } else if (comptime strings.eqlComptime(lookup_name, "ptr")) {
+ var result = ares_parse_ptr_reply(buffer, buffer_length, null, 0, std.os.AF.INET, &start);
+ if (result != ARES_SUCCESS) {
+ function(this, Error.get(result), timeouts, null);
+ return;
+ }
+ function(this, null, timeouts, start);
+ } else if (comptime strings.eqlComptime(lookup_name, "cname")) {
+ var addrttls: [256]struct_ares_addrttl = undefined;
+ var naddrttls: i32 = 256;
+
+ var result = ares_parse_a_reply(buffer, buffer_length, &start, &addrttls, &naddrttls);
+ if (result != ARES_SUCCESS) {
+ function(this, Error.get(result), timeouts, null);
+ return;
+ }
+ function(this, null, timeouts, start);
+ }
+ }
+ }.handle;
+ }
+
+ pub fn deinit(this: *struct_hostent) void {
+ ares_free_hostent(this);
+ }
+};
pub const struct_timeval = opaque {};
pub const struct_Channeldata = opaque {};
pub const AddrInfo_cname = extern struct {
@@ -413,7 +509,7 @@ pub const Channel = opaque {
ares_getaddrinfo(this, host_ptr, port_ptr, hints_, AddrInfo.callbackWrapper(Type, callback), ctx);
}
- pub fn resolveSrv(this: *Channel, name: []const u8, comptime Type: type, ctx: *Type, comptime callback: struct_ares_srv_reply.Callback(Type)) void {
+ pub fn resolve(this: *Channel, name: []const u8, comptime lookup_name: []const u8, comptime Type: type, ctx: *Type, comptime cares_type: type, comptime callback: cares_type.Callback(Type)) void {
var name_buf: [1024]u8 = undefined;
const name_ptr: ?[*:0]const u8 = brk: {
if (name.len == 0 or name.len >= 1023) {
@@ -425,7 +521,8 @@ pub const Channel = opaque {
break :brk name_buf[0..len :0];
};
- ares_query(this, name_ptr, NSClass.ns_c_in, NSType.ns_t_srv, struct_ares_srv_reply.callbackWrapper(Type, callback), ctx);
+ const field_name = comptime std.fmt.comptimePrint("ns_t_{s}", .{lookup_name});
+ ares_query(this, name_ptr, NSClass.ns_c_in, @field(NSType, field_name), cares_type.callbackWrapper(lookup_name, Type, callback), ctx);
}
pub inline fn process(this: *Channel, fd: i32, readable: bool, writable: bool) void {
@@ -519,12 +616,85 @@ pub const struct_ares_addr6ttl = extern struct {
ttl: c_int,
};
pub const struct_ares_caa_reply = extern struct {
- next: [*c]struct_ares_caa_reply,
+ next: ?*struct_ares_caa_reply,
critical: c_int,
property: [*c]u8,
plength: usize,
value: [*c]u8,
length: usize,
+
+ const JSC = bun.JSC;
+
+ pub fn toJSReponse(this: *struct_ares_caa_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
+ var stack = std.heap.stackFallback(2048, parent_allocator);
+ var arena = std.heap.ArenaAllocator.init(stack.get());
+ defer arena.deinit();
+
+ var allocator = arena.allocator();
+ var count: usize = 0;
+ var caa: ?*struct_ares_caa_reply = this;
+ while (caa != null) : (caa = caa.?.next) {
+ count += 1;
+ }
+
+ const array = JSC.JSValue.createEmptyArray(globalThis, count);
+
+ caa = this;
+ var i: u32 = 0;
+ while (caa != null) {
+ var node = caa.?;
+ array.putIndex(globalThis, i, node.toJS(globalThis, allocator));
+ caa = node.next;
+ i += 1;
+ }
+
+ return array;
+ }
+
+ pub fn toJS(this: *struct_ares_caa_reply, globalThis: *JSC.JSGlobalObject, _: std.mem.Allocator) JSC.JSValue {
+ var obj = JSC.JSValue.createEmptyObject(globalThis, 2);
+
+ obj.put(globalThis, JSC.ZigString.static("critical"), JSC.JSValue.jsNumber(this.critical));
+
+ const property = this.property[0..this.plength];
+ const value = this.value[0..this.length];
+ const property_str = JSC.ZigString.fromUTF8(property);
+ obj.put(globalThis, &property_str, JSC.ZigString.fromUTF8(value).toValueGC(globalThis));
+
+ return obj;
+ }
+
+ pub fn Callback(comptime Type: type) type {
+ return fn (*Type, status: ?Error, timeouts: i32, results: ?*struct_ares_caa_reply) void;
+ }
+
+ pub fn callbackWrapper(
+ comptime _: []const u8,
+ comptime Type: type,
+ comptime function: Callback(Type),
+ ) ares_callback {
+ return &struct {
+ pub fn handle(ctx: ?*anyopaque, status: c_int, timeouts: c_int, buffer: [*c]u8, buffer_length: c_int) callconv(.C) void {
+ var this = bun.cast(*Type, ctx.?);
+ if (status != ARES_SUCCESS) {
+ function(this, Error.get(status), timeouts, null);
+ return;
+ }
+
+ var start: [*c]struct_ares_caa_reply = undefined;
+ var result = ares_parse_caa_reply(buffer, buffer_length, &start);
+ if (result != ARES_SUCCESS) {
+ function(this, Error.get(result), timeouts, null);
+ return;
+ }
+ function(this, null, timeouts, start);
+ }
+ }.handle;
+ }
+
+ pub fn deinit(this: *struct_ares_caa_reply) void {
+ ares_free_data(this);
+ }
};
pub const struct_ares_srv_reply = extern struct {
next: ?*struct_ares_srv_reply,
@@ -534,7 +704,7 @@ pub const struct_ares_srv_reply = extern struct {
port: c_ushort,
const JSC = bun.JSC;
- pub fn toJSArray(this: *struct_ares_srv_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject) JSC.JSValue {
+ pub fn toJSReponse(this: *struct_ares_srv_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
var stack = std.heap.stackFallback(2048, parent_allocator);
var arena = std.heap.ArenaAllocator.init(stack.get());
defer arena.deinit();
@@ -545,7 +715,7 @@ pub const struct_ares_srv_reply = extern struct {
while (srv != null) : (srv = srv.?.next) {
count += 1;
}
-
+
const array = JSC.JSValue.createEmptyArray(globalThis, count);
srv = this;
@@ -561,7 +731,7 @@ pub const struct_ares_srv_reply = extern struct {
}
pub fn toJS(this: *struct_ares_srv_reply, globalThis: *JSC.JSGlobalObject, _: std.mem.Allocator) JSC.JSValue {
- var obj = JSC.JSValue.createEmptyObject(globalThis, 4);
+ const obj = JSC.JSValue.createEmptyObject(globalThis, 4);
// {
// priority: 10,
// weight: 5,
@@ -573,9 +743,8 @@ pub const struct_ares_srv_reply = extern struct {
obj.put(globalThis, JSC.ZigString.static("weight"), JSC.JSValue.jsNumber(this.weight));
obj.put(globalThis, JSC.ZigString.static("port"), JSC.JSValue.jsNumber(this.port));
-
const len = bun.len(this.host);
- var host = this.host[0..len];
+ const host = this.host[0..len];
obj.put(globalThis, JSC.ZigString.static("name"), JSC.ZigString.fromUTF8(host).toValueGC(globalThis));
return obj;
@@ -586,6 +755,7 @@ pub const struct_ares_srv_reply = extern struct {
}
pub fn callbackWrapper(
+ comptime _: []const u8,
comptime Type: type,
comptime function: Callback(Type),
) ares_callback {
@@ -613,14 +783,152 @@ pub const struct_ares_srv_reply = extern struct {
}
};
pub const struct_ares_mx_reply = extern struct {
- next: [*c]struct_ares_mx_reply,
+ next: ?*struct_ares_mx_reply,
host: [*c]u8,
priority: c_ushort,
+
+ const JSC = bun.JSC;
+
+ pub fn toJSReponse(this: *struct_ares_mx_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
+ var stack = std.heap.stackFallback(2048, parent_allocator);
+ var arena = std.heap.ArenaAllocator.init(stack.get());
+ defer arena.deinit();
+
+ var allocator = arena.allocator();
+ var count: usize = 0;
+ var mx: ?*struct_ares_mx_reply = this;
+ while (mx != null) : (mx = mx.?.next) {
+ count += 1;
+ }
+
+ const array = JSC.JSValue.createEmptyArray(globalThis, count);
+
+ mx = this;
+ var i: u32 = 0;
+ while (mx != null) {
+ var node = mx.?;
+ array.putIndex(globalThis, i, node.toJS(globalThis, allocator));
+ mx = node.next;
+ i += 1;
+ }
+
+ return array;
+ }
+
+ pub fn toJS(this: *struct_ares_mx_reply, globalThis: *JSC.JSGlobalObject, _: std.mem.Allocator) JSC.JSValue {
+ const obj = JSC.JSValue.createEmptyObject(globalThis, 2);
+ obj.put(globalThis, JSC.ZigString.static("priority"), JSC.JSValue.jsNumber(this.priority));
+
+ const host_len = bun.len(this.host);
+ const host = this.host[0..host_len];
+ obj.put(globalThis, JSC.ZigString.static("exchange"), JSC.ZigString.fromUTF8(host).toValueGC(globalThis));
+
+ return obj;
+ }
+
+ pub fn Callback(comptime Type: type) type {
+ return fn (*Type, status: ?Error, timeouts: i32, results: ?*struct_ares_mx_reply) void;
+ }
+
+ pub fn callbackWrapper(
+ comptime _: []const u8,
+ comptime Type: type,
+ comptime function: Callback(Type),
+ ) ares_callback {
+ return &struct {
+ pub fn handle(ctx: ?*anyopaque, status: c_int, timeouts: c_int, buffer: [*c]u8, buffer_length: c_int) callconv(.C) void {
+ var this = bun.cast(*Type, ctx.?);
+ if (status != ARES_SUCCESS) {
+ function(this, Error.get(status), timeouts, null);
+ return;
+ }
+
+ var start: [*c]struct_ares_mx_reply = undefined;
+ var result = ares_parse_mx_reply(buffer, buffer_length, &start);
+ if (result != ARES_SUCCESS) {
+ function(this, Error.get(result), timeouts, null);
+ return;
+ }
+ function(this, null, timeouts, start);
+ }
+ }.handle;
+ }
+
+ pub fn deinit(this: *struct_ares_mx_reply) void {
+ ares_free_data(this);
+ }
};
pub const struct_ares_txt_reply = extern struct {
- next: [*c]struct_ares_txt_reply,
+ next: ?*struct_ares_txt_reply,
txt: [*c]u8,
length: usize,
+
+ const JSC = bun.JSC;
+
+ pub fn toJSReponse(this: *struct_ares_txt_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
+ var stack = std.heap.stackFallback(2048, parent_allocator);
+ var arena = std.heap.ArenaAllocator.init(stack.get());
+ defer arena.deinit();
+
+ var allocator = arena.allocator();
+ var count: usize = 0;
+ var txt: ?*struct_ares_txt_reply = this;
+ while (txt != null) : (txt = txt.?.next) {
+ count += 1;
+ }
+
+ const array = JSC.JSValue.createEmptyArray(globalThis, count);
+
+ txt = this;
+ var i: u32 = 0;
+ while (txt != null) {
+ var node = txt.?;
+ array.putIndex(globalThis, i, node.toJS(globalThis, allocator));
+ txt = node.next;
+ i += 1;
+ }
+
+ return array;
+ }
+
+ pub fn toJS(this: *struct_ares_txt_reply, globalThis: *JSC.JSGlobalObject, _: std.mem.Allocator) JSC.JSValue {
+ const array = JSC.JSValue.createEmptyArray(globalThis, 1);
+ const value = this.txt[0..this.length];
+ array.putIndex(globalThis, 0, JSC.ZigString.fromUTF8(value).toValueGC(globalThis));
+ return array;
+ }
+
+ pub fn Callback(comptime Type: type) type {
+ return fn (*Type, status: ?Error, timeouts: i32, results: ?*struct_ares_txt_reply) void;
+ }
+
+ pub fn callbackWrapper(
+ comptime _: []const u8,
+ comptime Type: type,
+ comptime function: Callback(Type),
+ ) ares_callback {
+ return &struct {
+ pub fn handleTxt(ctx: ?*anyopaque, status: c_int, timeouts: c_int, buffer: [*c]u8, buffer_length: c_int) callconv(.C) void {
+ var this = bun.cast(*Type, ctx.?);
+ if (status != ARES_SUCCESS) {
+ function(this, Error.get(status), timeouts, null);
+ return;
+ }
+
+ var srv_start: [*c]struct_ares_txt_reply = undefined;
+ var result = ares_parse_txt_reply(buffer, buffer_length, &srv_start);
+ if (result != ARES_SUCCESS) {
+ function(this, Error.get(result), timeouts, null);
+ return;
+ }
+ function(this, null, timeouts, srv_start);
+ }
+ }.handleTxt;
+ }
+
+ pub fn deinit(this: *struct_ares_txt_reply) void {
+ ares_free_data(this);
+ }
};
pub const struct_ares_txt_ext = extern struct {
next: [*c]struct_ares_txt_ext,
@@ -629,13 +937,98 @@ pub const struct_ares_txt_ext = extern struct {
record_start: u8,
};
pub const struct_ares_naptr_reply = extern struct {
- next: [*c]struct_ares_naptr_reply,
+ next: ?*struct_ares_naptr_reply,
flags: [*c]u8,
service: [*c]u8,
regexp: [*c]u8,
replacement: [*c]u8,
order: c_ushort,
preference: c_ushort,
+
+ const JSC = bun.JSC;
+
+ pub fn toJSReponse(this: *struct_ares_naptr_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
+ var stack = std.heap.stackFallback(2048, parent_allocator);
+ var arena = std.heap.ArenaAllocator.init(stack.get());
+ defer arena.deinit();
+
+ var allocator = arena.allocator();
+ var count: usize = 0;
+ var naptr: ?*struct_ares_naptr_reply = this;
+ while (naptr != null) : (naptr = naptr.?.next) {
+ count += 1;
+ }
+
+ const array = JSC.JSValue.createEmptyArray(globalThis, count);
+
+ naptr = this;
+ var i: u32 = 0;
+ while (naptr != null) {
+ var node = naptr.?;
+ array.putIndex(globalThis, i, node.toJS(globalThis, allocator));
+ naptr = node.next;
+ i += 1;
+ }
+
+ return array;
+ }
+
+ pub fn toJS(this: *struct_ares_naptr_reply, globalThis: *JSC.JSGlobalObject, _: std.mem.Allocator) JSC.JSValue {
+ const obj = JSC.JSValue.createEmptyObject(globalThis, 6);
+
+ obj.put(globalThis, JSC.ZigString.static("preference"), JSC.JSValue.jsNumber(this.preference));
+ obj.put(globalThis, JSC.ZigString.static("order"), JSC.JSValue.jsNumber(this.order));
+
+ const flags_len = bun.len(this.flags);
+ const flags = this.flags[0..flags_len];
+ obj.put(globalThis, JSC.ZigString.static("flags"), JSC.ZigString.fromUTF8(flags).toValueGC(globalThis));
+
+ const service_len = bun.len(this.service);
+ const service = this.service[0..service_len];
+ obj.put(globalThis, JSC.ZigString.static("service"), JSC.ZigString.fromUTF8(service).toValueGC(globalThis));
+
+ const regexp_len = bun.len(this.regexp);
+ const regexp = this.regexp[0..regexp_len];
+ obj.put(globalThis, JSC.ZigString.static("regexp"), JSC.ZigString.fromUTF8(regexp).toValueGC(globalThis));
+
+ const replacement_len = bun.len(this.replacement);
+ const replacement = this.replacement[0..replacement_len];
+ obj.put(globalThis, JSC.ZigString.static("replacement"), JSC.ZigString.fromUTF8(replacement).toValueGC(globalThis));
+
+ return obj;
+ }
+
+ pub fn Callback(comptime Type: type) type {
+ return fn (*Type, status: ?Error, timeouts: i32, results: ?*struct_ares_naptr_reply) void;
+ }
+
+ pub fn callbackWrapper(
+ comptime _: []const u8,
+ comptime Type: type,
+ comptime function: Callback(Type),
+ ) ares_callback {
+ return &struct {
+ pub fn handleNaptr(ctx: ?*anyopaque, status: c_int, timeouts: c_int, buffer: [*c]u8, buffer_length: c_int) callconv(.C) void {
+ var this = bun.cast(*Type, ctx.?);
+ if (status != ARES_SUCCESS) {
+ function(this, Error.get(status), timeouts, null);
+ return;
+ }
+
+ var naptr_start: [*c]struct_ares_naptr_reply = undefined;
+ var result = ares_parse_naptr_reply(buffer, buffer_length, &naptr_start);
+ if (result != ARES_SUCCESS) {
+ function(this, Error.get(result), timeouts, null);
+ return;
+ }
+ function(this, null, timeouts, naptr_start);
+ }
+ }.handleNaptr;
+ }
+
+ pub fn deinit(this: *struct_ares_naptr_reply) void {
+ ares_free_data(this);
+ }
};
pub const struct_ares_soa_reply = extern struct {
nsname: [*c]u8,
@@ -645,6 +1038,70 @@ pub const struct_ares_soa_reply = extern struct {
retry: c_uint,
expire: c_uint,
minttl: c_uint,
+
+ const JSC = bun.JSC;
+
+ pub fn toJSReponse(this: *struct_ares_soa_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
+ var stack = std.heap.stackFallback(2048, parent_allocator);
+ var arena = std.heap.ArenaAllocator.init(stack.get());
+ defer arena.deinit();
+
+ var allocator = arena.allocator();
+
+ return this.toJS(globalThis, allocator);
+ }
+
+ pub fn toJS(this: *struct_ares_soa_reply, globalThis: *JSC.JSGlobalObject, _: std.mem.Allocator) JSC.JSValue {
+ const obj = JSC.JSValue.createEmptyObject(globalThis, 7);
+
+ obj.put(globalThis, JSC.ZigString.static("serial"), JSC.JSValue.jsNumber(this.serial));
+ obj.put(globalThis, JSC.ZigString.static("refresh"), JSC.JSValue.jsNumber(this.refresh));
+ obj.put(globalThis, JSC.ZigString.static("retry"), JSC.JSValue.jsNumber(this.retry));
+ obj.put(globalThis, JSC.ZigString.static("expire"), JSC.JSValue.jsNumber(this.expire));
+ obj.put(globalThis, JSC.ZigString.static("minttl"), JSC.JSValue.jsNumber(this.minttl));
+
+ const nsname_len = bun.len(this.nsname);
+ const nsname = this.nsname[0..nsname_len];
+ obj.put(globalThis, JSC.ZigString.static("nsname"), JSC.ZigString.fromUTF8(nsname).toValueGC(globalThis));
+
+ const hostmaster_len = bun.len(this.hostmaster);
+ const hostmaster = this.hostmaster[0..hostmaster_len];
+ obj.put(globalThis, JSC.ZigString.static("hostmaster"), JSC.ZigString.fromUTF8(hostmaster).toValueGC(globalThis));
+
+ return obj;
+ }
+
+ pub fn Callback(comptime Type: type) type {
+ return fn (*Type, status: ?Error, timeouts: i32, results: ?*struct_ares_soa_reply) void;
+ }
+
+ pub fn callbackWrapper(
+ comptime _: []const u8,
+ comptime Type: type,
+ comptime function: Callback(Type),
+ ) ares_callback {
+ return &struct {
+ pub fn handleSoa(ctx: ?*anyopaque, status: c_int, timeouts: c_int, buffer: [*c]u8, buffer_length: c_int) callconv(.C) void {
+ var this = bun.cast(*Type, ctx.?);
+ if (status != ARES_SUCCESS) {
+ function(this, Error.get(status), timeouts, null);
+ return;
+ }
+
+ var soa_start: [*c]struct_ares_soa_reply = undefined;
+ var result = ares_parse_soa_reply(buffer, buffer_length, &soa_start);
+ if (result != ARES_SUCCESS) {
+ function(this, Error.get(result), timeouts, null);
+ return;
+ }
+ function(this, null, timeouts, soa_start);
+ }
+ }.handleSoa;
+ }
+
+ pub fn deinit(this: *struct_ares_soa_reply) void {
+ ares_free_data(this);
+ }
};
pub const struct_ares_uri_reply = extern struct {
next: [*c]struct_ares_uri_reply,
diff --git a/src/deps/uws b/src/deps/uws
-Subproject a076c28a37ae2ffbcb4e2cec023056b13ba0518
+Subproject 665680ca11e09649b96e665a5eb97edc65cbb65
diff --git a/test/bun.js/node-dns.test.js b/test/bun.js/node-dns.test.js
index 287645bd9..b3ee09d48 100644
--- a/test/bun.js/node-dns.test.js
+++ b/test/bun.js/node-dns.test.js
@@ -9,30 +9,18 @@ test("it exists", () => {
expect(dns.resolve).toBeDefined();
expect(dns.resolve4).toBeDefined();
expect(dns.resolve6).toBeDefined();
+ expect(dns.resolveSrv).toBeDefined();
+ expect(dns.resolveTxt).toBeDefined();
+ expect(dns.resolveSoa).toBeDefined();
+ expect(dns.resolveNaptr).toBeDefined();
+ expect(dns.resolveMx).toBeDefined();
+ expect(dns.resolveCaa).toBeDefined();
+ expect(dns.resolveNs).toBeDefined();
+ expect(dns.resolvePtr).toBeDefined();
+ expect(dns.resolveCname).toBeDefined();
});
-test("dns.lookup (localhost)", (done) => {
- dns.lookup("localhost", (err, address, family) => {
- expect(err).toBeNull();
- if (family === 6) {
- expect(address).toBe("::1");
- } else {
- expect(address).toBe("127.0.0.1");
- }
-
- done(err);
- });
-});
-
-test("dns.lookup (example.com)", (done) => {
- dns.lookup("example.com", (err, address, family) => {
- expect(err).toBeNull();
- expect(typeof address).toBe("string");
- done(err);
- });
-});
-
-//TODO: use a bun.sh SRV for testing
+// //TODO: use a bun.sh SRV for testing
test("dns.resolveSrv (_test._tcp.test.socketify.dev)", (done) => {
dns.resolveSrv("_test._tcp.test.socketify.dev", (err, results) => {
expect(err).toBeNull();
@@ -51,4 +39,116 @@ test("dns.resolveSrv (_test._tcp.invalid.localhost)", (done) => {
expect(results).toBeUndefined(true);
done();
});
+});
+
+test("dns.resolveTxt (txt.socketify.dev)", (done) => {
+ dns.resolveTxt("txt.socketify.dev", (err, results) => {
+ expect(err).toBeNull();
+ expect(results instanceof Array).toBe(true);
+ expect(results[0][0]).toBe("bun_test;test");
+ done(err);
+ });
+});
+
+
+test("dns.resolveSoa (bun.sh)", (done) => {
+ dns.resolveSoa("bun.sh", (err, result) => {
+ expect(err).toBeNull();
+
+ expect(result.serial).toBe(2295878541);
+ expect(result.refresh).toBe(10000);
+ expect(result.retry).toBe(2400);
+ expect(result.expire).toBe(604800);
+ expect(result.minttl).toBe(3600);
+ expect(result.nsname).toBe("hans.ns.cloudflare.com");
+ expect(result.hostmaster).toBe("dns.cloudflare.com");
+
+ done(err);
+ });
+});
+
+test("dns.resolveNaptr (naptr.socketify.dev)", (done) => {
+ dns.resolveNaptr("naptr.socketify.dev", (err, results) => {
+ expect(err).toBeNull();
+ expect(results instanceof Array).toBe(true);
+ expect(results[0].flags).toBe('S');
+ expect(results[0].service).toBe('test');
+ expect(results[0].regexp).toBe('');
+ expect(results[0].replacement).toBe('');
+ expect(results[0].order).toBe(1);
+ expect(results[0].preference).toBe(12);
+ done(err);
+ });
+});
+
+test("dns.resolveCaa (caa.socketify.dev)", (done) => {
+ dns.resolveCaa("caa.socketify.dev", (err, results) => {
+ expect(err).toBeNull();
+ expect(results instanceof Array).toBe(true);
+ expect(results[0].critical).toBe(0);
+ expect(results[0].issue).toBe('bun.sh');
+ done(err);
+ });
+});
+
+
+test("dns.resolveMx (bun.sh)", (done) => {
+ dns.resolveMx("bun.sh", (err, results) => {
+ expect(err).toBeNull();
+ expect(results instanceof Array).toBe(true);
+ expect(results[0].priority).toBe(10);
+ expect(results[0].exchange).toBe('eforward1.registrar-servers.com');
+ done(err);
+ });
+});
+
+
+
+test("dns.resolveNs (bun.sh) ", (done) => {
+ dns.resolveNs("bun.sh", (err, results) => {
+ expect(err).toBeNull();
+ expect(results instanceof Array).toBe(true);
+ expect(results[0]).toBe('hans.ns.cloudflare.com');
+ done(err);
+ });
+});
+
+test("dns.resolvePtr (ptr.socketify.dev)", (done) => {
+ dns.resolvePtr("ptr.socketify.dev", (err, results) => {
+ expect(err).toBeNull();
+ expect(results instanceof Array).toBe(true);
+ expect(results[0]).toBe('bun.sh');
+ done(err);
+ });
+});
+
+test("dns.resolveCname (cname.socketify.dev)", (done) => {
+ dns.resolveCname("cname.socketify.dev", (err, results) => {
+ expect(err).toBeNull();
+ expect(results instanceof Array).toBe(true);
+ expect(results[0]).toBe('bun.sh');
+ done(err);
+ });
+});
+
+
+test("dns.lookup (example.com)", (done) => {
+ dns.lookup("example.com", (err, address, family) => {
+ expect(err).toBeNull();
+ expect(typeof address).toBe("string");
+ done(err);
+ });
+});
+
+test("dns.lookup (localhost)", (done) => {
+ dns.lookup("localhost", (err, address, family) => {
+ expect(err).toBeNull();
+ if (family === 6) {
+ expect(address).toBe("::1");
+ } else {
+ expect(address).toBe("127.0.0.1");
+ }
+
+ done(err);
+ });
}); \ No newline at end of file