Implement Resolver.cancel()

This commit is contained in:
Kai Tamkun
2024-12-19 16:57:11 -08:00
parent 19d11e843d
commit 29dec6e5a2
5 changed files with 65 additions and 3 deletions

View File

@@ -3043,6 +3043,13 @@ pub const DNSResolver = struct {
return resolver.toJS(globalThis);
}
pub fn cancel(this: *DNSResolver, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue {
_ = callframe;
const channel = try this.getChannelOrError(globalThis);
c_ares.ares_cancel(channel);
return .undefined;
}
// Resolves the given address and port into a host name and service using the operating system's underlying getnameinfo implementation.
// If address is not a valid IP address, a TypeError will be thrown. The port will be coerced to a number.
// If it is not a legal port, a TypeError will be thrown.

View File

@@ -58,6 +58,7 @@ BUN_DECLARE_HOST_FUNCTION(Bun__DNS__lookupService);
BUN_DECLARE_HOST_FUNCTION(Bun__DNS__prefetch);
BUN_DECLARE_HOST_FUNCTION(Bun__DNS__getCacheStats);
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__new);
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__cancel);
BUN_DECLARE_HOST_FUNCTION(Bun__fetch);
BUN_DECLARE_HOST_FUNCTION(Bun__fetchPreconnect);
BUN_DECLARE_HOST_FUNCTION(Bun__randomUUIDv7);
@@ -378,7 +379,7 @@ static JSValue constructDNSObject(VM& vm, JSObject* bunObject)
JSC::PropertyAttribute::DontDelete | 0);
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "getCacheStats"_s), 0, Bun__DNS__getCacheStats, ImplementationVisibility::Public, NoIntrinsic,
JSC::PropertyAttribute::DontDelete | 0);
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "newResolver"_s), 0, Bun__DNSResolver__new, ImplementationVisibility::Public, NoIntrinsic,
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "newResolver"_s), 1, Bun__DNSResolver__new, ImplementationVisibility::Public, NoIntrinsic,
JSC::PropertyAttribute::DontDelete | 0);
dnsObject->putDirect(vm, JSC::Identifier::fromString(vm, "ADDRCONFIG"_s), jsNumber(AI_ADDRCONFIG),
JSC::PropertyAttribute::DontDelete | 0);

View File

@@ -57,6 +57,10 @@ export default [
fn: "resolveCname",
length: 1,
},
cancel: {
fn: "cancel",
length: 0,
},
},
}),
define({

View File

@@ -274,7 +274,9 @@ var InternalResolver = class Resolver {
this.#resolver = this._handle = dns.newResolver(options);
}
cancel() {}
cancel() {
this.#resolver.cancel();
}
static #getResolver(object) {
return #resolver in object ? object.#resolver : dns;
@@ -751,7 +753,9 @@ const promises = {
this.#resolver = this._handle = dns.newResolver(options);
}
cancel() {}
cancel() {
this.#resolver.cancel();
}
static #getResolver(object) {
return #resolver in object ? object.#resolver : dns;

View File

@@ -0,0 +1,46 @@
'use strict';
const common = require('../common');
const { Resolver } = require('dns');
const assert = require('assert');
const dgram = require('dgram');
const server = dgram.createSocket('udp4');
const resolver = new Resolver();
const desiredQueries = 11;
let finishedQueries = 0;
server.bind(0, common.mustCall(async () => {
resolver.setServers([`127.0.0.1:${server.address().port}`]);
const callback = common.mustCall((err, res) => {
assert.strictEqual(err.code, 'ECANCELLED');
assert.strictEqual(err.syscall, 'queryA');
assert.strictEqual(err.hostname, `example${finishedQueries}.org`);
finishedQueries++;
if (finishedQueries === desiredQueries) {
server.close();
}
}, desiredQueries);
const next = (...args) => {
callback(...args);
server.once('message', () => {
resolver.cancel();
});
// Multiple queries
for (let i = 1; i < desiredQueries; i++) {
resolver.resolve4(`example${i}.org`, callback);
}
};
server.once('message', () => {
resolver.cancel();
});
// Single query
resolver.resolve4('example0.org', next);
}));