mirror of
https://github.com/oven-sh/bun
synced 2026-02-26 03:27:23 +01:00
Compare commits
119 Commits
claude/fas
...
kai/dns-te
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f984829df | ||
|
|
f5b37a8f8c | ||
|
|
14b43f1ae4 | ||
|
|
b306c29c01 | ||
|
|
887ba186a7 | ||
|
|
5611f2561a | ||
|
|
493e34c992 | ||
|
|
0fe347a0e2 | ||
|
|
c7f68bfe75 | ||
|
|
a1a2c618ea | ||
|
|
f143598ca6 | ||
|
|
95d0601935 | ||
|
|
e5017b2301 | ||
|
|
1c2cc7bd73 | ||
|
|
b283bc5317 | ||
|
|
2c71326168 | ||
|
|
200639de08 | ||
|
|
9bd562d5d6 | ||
|
|
bcfd17c89a | ||
|
|
6b40b21649 | ||
|
|
832b43edc9 | ||
|
|
d9aaeecd2b | ||
|
|
444c220f9e | ||
|
|
4c1a233238 | ||
|
|
a6c13ce72c | ||
|
|
84ddb9697e | ||
|
|
381fa5ba5d | ||
|
|
78c6048294 | ||
|
|
7e3cb6fc58 | ||
|
|
80a3a730eb | ||
|
|
c8b431cff2 | ||
|
|
2b1ac64193 | ||
|
|
394a69970e | ||
|
|
7031e822ec | ||
|
|
032a05df21 | ||
|
|
c786922c61 | ||
|
|
74a6c066d8 | ||
|
|
a79111a5ed | ||
|
|
07d0aa26f4 | ||
|
|
6c1bef6827 | ||
|
|
29dec6e5a2 | ||
|
|
19d11e843d | ||
|
|
98f5e749dd | ||
|
|
47eb157922 | ||
|
|
15d49610b3 | ||
|
|
b197c767d3 | ||
|
|
547cf84a97 | ||
|
|
0ccdc5482d | ||
|
|
b58e1df84a | ||
|
|
fbbaeac8a6 | ||
|
|
00a56c7b58 | ||
|
|
dca054123c | ||
|
|
24634a10d0 | ||
|
|
845ba7e4a4 | ||
|
|
541825043b | ||
|
|
b42d914ea1 | ||
|
|
e161d054f2 | ||
|
|
361fa58b4c | ||
|
|
e7153af2ad | ||
|
|
57ea50da4f | ||
|
|
d9bce21a29 | ||
|
|
2c1cf4e62b | ||
|
|
7ac1067060 | ||
|
|
c933ec0865 | ||
|
|
ae08844a44 | ||
|
|
e5c1d5315c | ||
|
|
696e2e2f13 | ||
|
|
b22037a13e | ||
|
|
003381f2c9 | ||
|
|
9cc5374244 | ||
|
|
219c067b69 | ||
|
|
d8043f9a5c | ||
|
|
f2063ffe87 | ||
|
|
291c035adf | ||
|
|
60330a810e | ||
|
|
b4504e6469 | ||
|
|
2bbbbef7c8 | ||
|
|
350ceb1c50 | ||
|
|
547f069580 | ||
|
|
a6c5bafe01 | ||
|
|
6db95a891a | ||
|
|
3bf6fe9384 | ||
|
|
041887e814 | ||
|
|
fe364ca0a4 | ||
|
|
197c3db868 | ||
|
|
c99f8ae2ee | ||
|
|
59f521d477 | ||
|
|
dfb47d846f | ||
|
|
e08573eb06 | ||
|
|
79395dac0c | ||
|
|
a8f3bf2b3a | ||
|
|
cfd6f7c164 | ||
|
|
97a63fbe3f | ||
|
|
ad57ced58d | ||
|
|
897d4a5ec3 | ||
|
|
e20d0082d5 | ||
|
|
517bc28da8 | ||
|
|
0d3be0aca0 | ||
|
|
a9de84c1e9 | ||
|
|
2462dc33c9 | ||
|
|
3e3941797b | ||
|
|
b8205e0b70 | ||
|
|
52002a1088 | ||
|
|
18fee6090c | ||
|
|
0b509dbf89 | ||
|
|
aa61b7bd1d | ||
|
|
bdf1db838a | ||
|
|
26f99caac3 | ||
|
|
7997556699 | ||
|
|
1c12cbb561 | ||
|
|
bcfa11d4e6 | ||
|
|
de67a6fa9e | ||
|
|
614a6abdff | ||
|
|
2bdf9d63e6 | ||
|
|
22fa28f102 | ||
|
|
8215e18a1a | ||
|
|
e052252c63 | ||
|
|
ed7d361b4c | ||
|
|
18d3bda19a |
@@ -72,6 +72,24 @@ $ bun install --yarn
|
||||
print = "yarn"
|
||||
```
|
||||
|
||||
### Text-based lockfile
|
||||
|
||||
Bun v1.1.39 introduced `bun.lock`, a JSONC formatted lockfile. `bun.lock` is human-readable and git-diffable without configuration, at [no cost to performance](https://bun.sh/blog/bun-lock-text-lockfile#cached-bun-install-gets-30-faster).
|
||||
|
||||
To generate the lockfile, use `--save-text-lockfile` with `bun install`. You can do this for new projects and existing projects already using `bun.lockb` (resolutions will be preserved).
|
||||
|
||||
```bash
|
||||
$ bun install --save-text-lockfile
|
||||
$ head -n3 bun.lock
|
||||
{
|
||||
"lockfileVersion": 0,
|
||||
"workspaces": {
|
||||
```
|
||||
|
||||
Once `bun.lock` is generated, Bun will use it for all subsequent installs and updates through commands that read and modify the lockfile. If both lockfiles exist, `bun.lock` will be choosen over `bun.lockb`.
|
||||
|
||||
Bun v1.2.0 will switch the default lockfile format to `bun.lock`.
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
### Text-based lockfile
|
||||
|
||||
4
packages/bun-types/bun.d.ts
vendored
4
packages/bun-types/bun.d.ts
vendored
@@ -1034,6 +1034,10 @@ declare module "bun" {
|
||||
errors: number;
|
||||
totalCount: number;
|
||||
};
|
||||
|
||||
ADDRCONFIG: number;
|
||||
ALL: number;
|
||||
V4MAPPED: number;
|
||||
};
|
||||
|
||||
interface DNSLookup {
|
||||
|
||||
@@ -49,6 +49,13 @@ const spawnTimeout = 5_000;
|
||||
const testTimeout = 3 * 60_000;
|
||||
const integrationTimeout = 5 * 60_000;
|
||||
|
||||
function getNodeParallelTestTimeout(testPath) {
|
||||
if (testPath.includes("test-dns")) {
|
||||
return 45_000;
|
||||
}
|
||||
return 10_000;
|
||||
}
|
||||
|
||||
const { values: options, positionals: filters } = parseArgs({
|
||||
allowPositionals: true,
|
||||
options: {
|
||||
@@ -251,7 +258,7 @@ async function runTests() {
|
||||
const { ok, error, stdout } = await spawnBun(execPath, {
|
||||
cwd: cwd,
|
||||
args: [title],
|
||||
timeout: 10_000,
|
||||
timeout: getNodeParallelTestTimeout(title),
|
||||
env: {
|
||||
FORCE_COLOR: "0",
|
||||
},
|
||||
|
||||
@@ -10,6 +10,7 @@ const Async = @import("async");
|
||||
const uv = bun.windows.libuv;
|
||||
const StatWatcherScheduler = @import("../node/node_fs_stat_watcher.zig").StatWatcherScheduler;
|
||||
const Timer = @This();
|
||||
const DNSResolver = @import("./bun/dns_resolver.zig").DNSResolver;
|
||||
|
||||
/// TimeoutMap is map of i32 to nullable Timeout structs
|
||||
/// i32 is exposed to JavaScript and can be used with clearTimeout, clearInterval, etc.
|
||||
@@ -730,6 +731,7 @@ pub const EventLoopTimer = struct {
|
||||
TestRunner,
|
||||
StatWatcherScheduler,
|
||||
UpgradedDuplex,
|
||||
DNSResolver,
|
||||
WindowsNamedPipe,
|
||||
PostgresSQLConnectionTimeout,
|
||||
PostgresSQLConnectionMaxLifetime,
|
||||
@@ -741,6 +743,7 @@ pub const EventLoopTimer = struct {
|
||||
.TestRunner => JSC.Jest.TestRunner,
|
||||
.StatWatcherScheduler => StatWatcherScheduler,
|
||||
.UpgradedDuplex => uws.UpgradedDuplex,
|
||||
.DNSResolver => DNSResolver,
|
||||
.WindowsNamedPipe => uws.WindowsNamedPipe,
|
||||
.PostgresSQLConnectionTimeout => JSC.Postgres.PostgresSQLConnection,
|
||||
.PostgresSQLConnectionMaxLifetime => JSC.Postgres.PostgresSQLConnection,
|
||||
@@ -754,6 +757,7 @@ pub const EventLoopTimer = struct {
|
||||
UpgradedDuplex,
|
||||
PostgresSQLConnectionTimeout,
|
||||
PostgresSQLConnectionMaxLifetime,
|
||||
DNSResolver,
|
||||
|
||||
pub fn Type(comptime T: Tag) type {
|
||||
return switch (T) {
|
||||
@@ -764,6 +768,7 @@ pub const EventLoopTimer = struct {
|
||||
.UpgradedDuplex => uws.UpgradedDuplex,
|
||||
.PostgresSQLConnectionTimeout => JSC.Postgres.PostgresSQLConnection,
|
||||
.PostgresSQLConnectionMaxLifetime => JSC.Postgres.PostgresSQLConnection,
|
||||
.DNSResolver => DNSResolver,
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -841,6 +846,10 @@ pub const EventLoopTimer = struct {
|
||||
return .disarm;
|
||||
}
|
||||
|
||||
if (comptime t.Type() == DNSResolver) {
|
||||
return container.checkTimeouts(now, vm);
|
||||
}
|
||||
|
||||
return container.callback(container);
|
||||
},
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -34,22 +34,32 @@
|
||||
#include "ErrorCode.h"
|
||||
#include "GeneratedBunObject.h"
|
||||
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__lookup);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__resolve);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__resolveSrv);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__resolveTxt);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__resolveSoa);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__resolveNaptr);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__resolveMx);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__resolveCaa);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__resolveNs);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__resolvePtr);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__resolveCname);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__getServers);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__reverse);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__lookupService);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__prefetch);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__getCacheStats);
|
||||
#ifdef WIN32
|
||||
#include <ws2def.h>
|
||||
#else
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNS__lookup);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNS__resolve);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNS__resolveSrv);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNS__resolveTxt);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNS__resolveSoa);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNS__resolveNaptr);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNS__resolveMx);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNS__resolveCaa);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNS__resolveNs);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNS__resolvePtr);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNS__resolveCname);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNS__resolveAny);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNS__getServers);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNS__setServers);
|
||||
BUN_DECLARE_HOST_FUNCTION(Bun__DNS__reverse);
|
||||
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);
|
||||
@@ -336,37 +346,47 @@ static JSValue constructDNSObject(VM& vm, JSObject* bunObject)
|
||||
{
|
||||
JSGlobalObject* globalObject = bunObject->globalObject();
|
||||
JSC::JSObject* dnsObject = JSC::constructEmptyObject(globalObject);
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "lookup"_s), 2, Bun__DNSResolver__lookup, ImplementationVisibility::Public, NoIntrinsic,
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "lookup"_s), 2, Bun__DNS__lookup, ImplementationVisibility::Public, NoIntrinsic,
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, vm.propertyNames->resolve, 2, Bun__DNSResolver__resolve, ImplementationVisibility::Public, NoIntrinsic,
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, vm.propertyNames->resolve, 2, Bun__DNS__resolve, ImplementationVisibility::Public, NoIntrinsic,
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveSrv"_s), 2, Bun__DNSResolver__resolveSrv, ImplementationVisibility::Public, NoIntrinsic,
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveSrv"_s), 2, Bun__DNS__resolveSrv, ImplementationVisibility::Public, NoIntrinsic,
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveTxt"_s), 2, Bun__DNSResolver__resolveTxt, ImplementationVisibility::Public, NoIntrinsic,
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveTxt"_s), 2, Bun__DNS__resolveTxt, ImplementationVisibility::Public, NoIntrinsic,
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveSoa"_s), 2, Bun__DNSResolver__resolveSoa, ImplementationVisibility::Public, NoIntrinsic,
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveSoa"_s), 2, Bun__DNS__resolveSoa, ImplementationVisibility::Public, NoIntrinsic,
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveNaptr"_s), 2, Bun__DNSResolver__resolveNaptr, ImplementationVisibility::Public, NoIntrinsic,
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveNaptr"_s), 2, Bun__DNS__resolveNaptr, ImplementationVisibility::Public, NoIntrinsic,
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveMx"_s), 2, Bun__DNSResolver__resolveMx, ImplementationVisibility::Public, NoIntrinsic,
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveMx"_s), 2, Bun__DNS__resolveMx, ImplementationVisibility::Public, NoIntrinsic,
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveCaa"_s), 2, Bun__DNSResolver__resolveCaa, ImplementationVisibility::Public, NoIntrinsic,
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveCaa"_s), 2, Bun__DNS__resolveCaa, ImplementationVisibility::Public, NoIntrinsic,
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveNs"_s), 2, Bun__DNSResolver__resolveNs, ImplementationVisibility::Public, NoIntrinsic,
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveNs"_s), 2, Bun__DNS__resolveNs, ImplementationVisibility::Public, NoIntrinsic,
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolvePtr"_s), 2, Bun__DNSResolver__resolvePtr, ImplementationVisibility::Public, NoIntrinsic,
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolvePtr"_s), 2, Bun__DNS__resolvePtr, ImplementationVisibility::Public, NoIntrinsic,
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveCname"_s), 2, Bun__DNSResolver__resolveCname, ImplementationVisibility::Public, NoIntrinsic,
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveCname"_s), 2, Bun__DNS__resolveCname, ImplementationVisibility::Public, NoIntrinsic,
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "getServers"_s), 2, Bun__DNSResolver__getServers, ImplementationVisibility::Public, NoIntrinsic,
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "resolveAny"_s), 2, Bun__DNS__resolveAny, ImplementationVisibility::Public, NoIntrinsic,
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "reverse"_s), 2, Bun__DNSResolver__reverse, ImplementationVisibility::Public, NoIntrinsic,
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "getServers"_s), 2, Bun__DNS__getServers, ImplementationVisibility::Public, NoIntrinsic,
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "lookupService"_s), 2, Bun__DNSResolver__lookupService, ImplementationVisibility::Public, NoIntrinsic,
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "setServers"_s), 2, Bun__DNS__setServers, ImplementationVisibility::Public, NoIntrinsic,
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "prefetch"_s), 2, Bun__DNSResolver__prefetch, ImplementationVisibility::Public, NoIntrinsic,
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "reverse"_s), 2, Bun__DNS__reverse, ImplementationVisibility::Public, NoIntrinsic,
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "getCacheStats"_s), 0, Bun__DNSResolver__getCacheStats, ImplementationVisibility::Public, NoIntrinsic,
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "lookupService"_s), 2, Bun__DNS__lookupService, ImplementationVisibility::Public, NoIntrinsic,
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
dnsObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "prefetch"_s), 2, Bun__DNS__prefetch, ImplementationVisibility::Public, NoIntrinsic,
|
||||
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->putDirect(vm, JSC::Identifier::fromString(vm, "ADDRCONFIG"_s), jsNumber(AI_ADDRCONFIG),
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
dnsObject->putDirect(vm, JSC::Identifier::fromString(vm, "ALL"_s), jsNumber(AI_ALL),
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
dnsObject->putDirect(vm, JSC::Identifier::fromString(vm, "V4MAPPED"_s), jsNumber(AI_V4MAPPED),
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
return dnsObject;
|
||||
}
|
||||
|
||||
@@ -1149,6 +1149,24 @@ JSC_DEFINE_HOST_FUNCTION(Process_emitWarning, (JSGlobalObject * lexicalGlobalObj
|
||||
return err;
|
||||
})();
|
||||
|
||||
if (callFrame->argumentCount() > 1) {
|
||||
auto clientData = WebCore::clientData(vm);
|
||||
JSValue arg1 = callFrame->uncheckedArgument(1);
|
||||
if (arg1.isString()) {
|
||||
errorInstance->putDirect(vm, vm.propertyNames->name, arg1, JSC::PropertyAttribute::DontEnum | 0);
|
||||
if (callFrame->argumentCount() > 2) {
|
||||
if (JSValue arg2 = callFrame->uncheckedArgument(2); arg2.isString()) {
|
||||
errorInstance->putDirect(vm, clientData->builtinNames().codePublicName(), arg2, JSC::PropertyAttribute::DontEnum | 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: handle `options` and `ctor` parameters
|
||||
}
|
||||
|
||||
if (!errorInstance->hasProperty(lexicalGlobalObject, vm.propertyNames->name)) {
|
||||
errorInstance->putDirect(vm, vm.propertyNames->name, jsString(vm, String("warn"_s)), JSC::PropertyAttribute::DontEnum | 0);
|
||||
}
|
||||
|
||||
auto ident = Identifier::fromString(vm, "warning"_s);
|
||||
if (process->wrapped().hasEventListeners(ident)) {
|
||||
JSC::MarkedArgumentBuffer args;
|
||||
|
||||
@@ -811,6 +811,16 @@ JSC_DEFINE_HOST_FUNCTION(Bun::jsFunctionMakeErrorWithCode, (JSC::JSGlobalObject
|
||||
|
||||
return JSValue::encode(ERR_INVALID_ARG_TYPE(scope, globalObject, arg0, arg1, arg2));
|
||||
}
|
||||
|
||||
case Bun::ErrorCode::ERR_INVALID_IP_ADDRESS: {
|
||||
JSValue arg0 = callFrame->argument(1);
|
||||
|
||||
auto param = arg0.toWTFString(globalObject);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
return JSValue::encode(createError(globalObject, ErrorCode::ERR_INVALID_IP_ADDRESS, makeString("Invalid IP address: "_s, param)));
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ export default [
|
||||
["ERR_SCRIPT_EXECUTION_TIMEOUT", Error, "Error"],
|
||||
["ERR_SCRIPT_EXECUTION_INTERRUPTED", Error, "Error"],
|
||||
["ERR_UNHANDLED_ERROR", Error],
|
||||
["ERR_INVALID_IP_ADDRESS", TypeError, "TypeError"],
|
||||
|
||||
// Bun-specific
|
||||
["ERR_FORMDATA_PARSE_ERROR", TypeError],
|
||||
@@ -62,6 +63,9 @@ export default [
|
||||
// Console
|
||||
["ERR_CONSOLE_WRITABLE_STREAM", TypeError, "TypeError"],
|
||||
|
||||
// DNS
|
||||
["ERR_DNS_SET_SERVERS_FAILED", Error],
|
||||
|
||||
// NET
|
||||
["ERR_SOCKET_CLOSED_BEFORE_CONNECTION", Error],
|
||||
["ERR_SOCKET_CLOSED", Error],
|
||||
|
||||
@@ -1981,6 +1981,12 @@ JSC__JSValue SystemError__toErrorInstance(const SystemError* arg0,
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
}
|
||||
|
||||
if (err.hostname.tag != BunStringTag::Empty) {
|
||||
JSC::JSValue hostname = Bun::toJS(globalObject, err.hostname);
|
||||
result->putDirect(vm, names.hostnamePublicName(), hostname,
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
}
|
||||
|
||||
result->putDirect(vm, names.errnoPublicName(), JSC::JSValue(err.errno_),
|
||||
JSC::PropertyAttribute::DontDelete | 0);
|
||||
|
||||
|
||||
@@ -1711,6 +1711,7 @@ pub const SystemError = extern struct {
|
||||
message: String = String.empty,
|
||||
path: String = String.empty,
|
||||
syscall: String = String.empty,
|
||||
hostname: String = String.empty,
|
||||
fd: bun.FileDescriptor = bun.toFD(-1),
|
||||
|
||||
pub fn Maybe(comptime Result: type) type {
|
||||
@@ -1735,6 +1736,7 @@ pub const SystemError = extern struct {
|
||||
this.code.deref();
|
||||
this.message.deref();
|
||||
this.syscall.deref();
|
||||
this.hostname.deref();
|
||||
}
|
||||
|
||||
pub fn ref(this: *SystemError) void {
|
||||
@@ -1742,15 +1744,11 @@ pub const SystemError = extern struct {
|
||||
this.code.ref();
|
||||
this.message.ref();
|
||||
this.syscall.ref();
|
||||
this.hostname.ref();
|
||||
}
|
||||
|
||||
pub fn toErrorInstance(this: *const SystemError, global: *JSGlobalObject) JSValue {
|
||||
defer {
|
||||
this.path.deref();
|
||||
this.code.deref();
|
||||
this.message.deref();
|
||||
this.syscall.deref();
|
||||
}
|
||||
defer this.deref();
|
||||
|
||||
return shim.cppFn("toErrorInstance", .{ this, global });
|
||||
}
|
||||
@@ -1775,12 +1773,7 @@ pub const SystemError = extern struct {
|
||||
/// implementing follows this convention. It is exclusively used
|
||||
/// to match the error code that `node:os` throws.
|
||||
pub fn toErrorInstanceWithInfoObject(this: *const SystemError, global: *JSGlobalObject) JSValue {
|
||||
defer {
|
||||
this.path.deref();
|
||||
this.code.deref();
|
||||
this.message.deref();
|
||||
this.syscall.deref();
|
||||
}
|
||||
defer this.deref();
|
||||
|
||||
return SystemError__toErrorInstanceWithInfoObject(this, global);
|
||||
}
|
||||
@@ -3116,6 +3109,16 @@ pub const JSGlobalObject = opaque {
|
||||
return this.throwValue(this.createInvalidArgumentType(name_, field, typename));
|
||||
}
|
||||
|
||||
pub fn throwInvalidArgumentValue(
|
||||
this: *JSGlobalObject,
|
||||
argname: []const u8,
|
||||
value: JSValue,
|
||||
) bun.JSError {
|
||||
var formatter = JSC.ConsoleObject.Formatter{ .globalThis = this };
|
||||
defer formatter.deinit();
|
||||
return this.ERR_INVALID_ARG_VALUE("The \"{s}\" argument is invalid. Received {}", .{ argname, value.toFmt(&formatter) }).throw();
|
||||
}
|
||||
|
||||
pub fn throwInvalidArgumentTypeValue(
|
||||
this: *JSGlobalObject,
|
||||
argname: []const u8,
|
||||
@@ -3123,6 +3126,7 @@ pub const JSGlobalObject = opaque {
|
||||
value: JSValue,
|
||||
) bun.JSError {
|
||||
var formatter = JSC.ConsoleObject.Formatter{ .globalThis = this };
|
||||
defer formatter.deinit();
|
||||
return this.ERR_INVALID_ARG_TYPE("The \"{s}\" argument must be of type {s}. Received {}", .{ argname, typename, value.toFmt(&formatter) }).throw();
|
||||
}
|
||||
|
||||
@@ -4203,6 +4207,25 @@ pub const JSValue = enum(i64) {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn toPortNumber(this: JSValue, global: *JSGlobalObject) bun.JSError!u16 {
|
||||
if (this.isNumber()) {
|
||||
// const double = try this.toNumber(global);
|
||||
const double = this.coerceToDouble(global);
|
||||
if (std.math.isNan(double)) {
|
||||
return JSC.Error.ERR_SOCKET_BAD_PORT.throw(global, "Invalid port number", .{});
|
||||
}
|
||||
|
||||
const port = this.to(i64);
|
||||
if (0 <= port and port <= 65535) {
|
||||
return @as(u16, @truncate(@max(0, port)));
|
||||
} else {
|
||||
return JSC.Error.ERR_SOCKET_BAD_PORT.throw(global, "Port number out of range: {d}", .{port});
|
||||
}
|
||||
}
|
||||
|
||||
return JSC.Error.ERR_SOCKET_BAD_PORT.throw(global, "Invalid port number", .{});
|
||||
}
|
||||
|
||||
pub fn isInstanceOf(this: JSValue, global: *JSGlobalObject, constructor: JSValue) bool {
|
||||
if (!this.isCell())
|
||||
return false;
|
||||
@@ -6796,6 +6819,7 @@ pub fn toJSHostFunction(comptime Function: JSHostZigFunction) JSC.JSHostFunction
|
||||
if (value != .zero) {
|
||||
if (globalThis.hasException()) {
|
||||
var formatter = JSC.ConsoleObject.Formatter{ .globalThis = globalThis };
|
||||
defer formatter.deinit();
|
||||
bun.Output.prettyErrorln(
|
||||
\\<r><red>Assertion failed<r>: Native function returned a non-zero JSValue while an exception is pending
|
||||
\\
|
||||
|
||||
@@ -77,4 +77,5 @@ pub const Classes = struct {
|
||||
pub const NativeZlib = JSC.API.NativeZlib;
|
||||
pub const NativeBrotli = JSC.API.NativeBrotli;
|
||||
pub const FrameworkFileSystemRouter = bun.bake.FrameworkRouter.JSFrameworkRouter;
|
||||
pub const DNSResolver = JSC.DNS.DNSResolver;
|
||||
};
|
||||
|
||||
@@ -124,6 +124,7 @@ typedef struct SystemError {
|
||||
BunString message;
|
||||
BunString path;
|
||||
BunString syscall;
|
||||
BunString hostname;
|
||||
int fd;
|
||||
} SystemError;
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@ const PendingResolution = @import("../resolver/resolver.zig").PendingResolution;
|
||||
const ThreadSafeFunction = JSC.napi.ThreadSafeFunction;
|
||||
const PackageManager = @import("../install/install.zig").PackageManager;
|
||||
const IPC = @import("ipc.zig");
|
||||
const DNSResolver = @import("api/bun/dns_resolver.zig").DNSResolver;
|
||||
pub const GenericWatcher = @import("../watcher.zig");
|
||||
|
||||
const ModuleLoader = JSC.ModuleLoader;
|
||||
@@ -790,6 +791,7 @@ pub const VirtualMachine = struct {
|
||||
unhandled_pending_rejection_to_capture: ?*JSC.JSValue = null,
|
||||
standalone_module_graph: ?*bun.StandaloneModuleGraph = null,
|
||||
smol: bool = false,
|
||||
dns_result_order: DNSResolver.Order = .verbatim,
|
||||
|
||||
hot_reload: bun.CLI.Command.HotReload = .none,
|
||||
jsc: *JSC.VM = undefined,
|
||||
@@ -1967,6 +1969,7 @@ pub const VirtualMachine = struct {
|
||||
env_loader: ?*DotEnv.Loader = null,
|
||||
store_fd: bool = false,
|
||||
smol: bool = false,
|
||||
dns_result_order: DNSResolver.Order = .verbatim,
|
||||
|
||||
// --print needs the result from evaluating the main module
|
||||
eval: bool = false,
|
||||
@@ -2060,6 +2063,7 @@ pub const VirtualMachine = struct {
|
||||
vm.regular_event_loop.virtual_machine = vm;
|
||||
vm.jsc = vm.global.vm();
|
||||
vm.smol = opts.smol;
|
||||
vm.dns_result_order = opts.dns_result_order;
|
||||
|
||||
if (opts.smol)
|
||||
is_smol_mode = opts.smol;
|
||||
|
||||
@@ -924,36 +924,36 @@ JSC_DEFINE_HOST_FUNCTION(functionPercentAvailableMemoryInUse, (JSGlobalObject *
|
||||
// clang-format off
|
||||
/* Source for BunJSCModuleTable.lut.h
|
||||
@begin BunJSCModuleTable
|
||||
callerSourceOrigin functionCallerSourceOrigin Function 0
|
||||
jscDescribe functionDescribe Function 0
|
||||
jscDescribeArray functionDescribeArray Function 0
|
||||
drainMicrotasks functionDrainMicrotasks Function 0
|
||||
edenGC functionEdenGC Function 0
|
||||
fullGC functionFullGC Function 0
|
||||
gcAndSweep functionGCAndSweep Function 0
|
||||
getRandomSeed functionGetRandomSeed Function 0
|
||||
heapSize functionHeapSize Function 0
|
||||
heapStats functionMemoryUsageStatistics Function 0
|
||||
startSamplingProfiler functionStartSamplingProfiler Function 0
|
||||
samplingProfilerStackTraces functionSamplingProfilerStackTraces Function 0
|
||||
noInline functionNeverInlineFunction Function 0
|
||||
isRope functionIsRope Function 0
|
||||
memoryUsage functionCreateMemoryFootprint Function 0
|
||||
noFTL functionNoFTL Function 0
|
||||
noOSRExitFuzzing functionNoOSRExitFuzzing Function 0
|
||||
numberOfDFGCompiles functionNumberOfDFGCompiles Function 0
|
||||
optimizeNextInvocation functionOptimizeNextInvocation Function 0
|
||||
releaseWeakRefs functionReleaseWeakRefs Function 0
|
||||
reoptimizationRetryCount functionReoptimizationRetryCount Function 0
|
||||
setRandomSeed functionSetRandomSeed Function 0
|
||||
startRemoteDebugger functionStartRemoteDebugger Function 0
|
||||
totalCompileTime functionTotalCompileTime Function 0
|
||||
getProtectedObjects functionGetProtectedObjects Function 0
|
||||
generateHeapSnapshotForDebugging functionGenerateHeapSnapshotForDebugging Function 0
|
||||
profile functionRunProfiler Function 0
|
||||
setTimeZone functionSetTimeZone Function 0
|
||||
serialize functionSerialize Function 0
|
||||
deserialize functionDeserialize Function 0
|
||||
callerSourceOrigin functionCallerSourceOrigin Function 0
|
||||
jscDescribe functionDescribe Function 0
|
||||
jscDescribeArray functionDescribeArray Function 0
|
||||
drainMicrotasks functionDrainMicrotasks Function 0
|
||||
edenGC functionEdenGC Function 0
|
||||
fullGC functionFullGC Function 0
|
||||
gcAndSweep functionGCAndSweep Function 0
|
||||
getRandomSeed functionGetRandomSeed Function 0
|
||||
heapSize functionHeapSize Function 0
|
||||
heapStats functionMemoryUsageStatistics Function 0
|
||||
startSamplingProfiler functionStartSamplingProfiler Function 0
|
||||
samplingProfilerStackTraces functionSamplingProfilerStackTraces Function 0
|
||||
noInline functionNeverInlineFunction Function 0
|
||||
isRope functionIsRope Function 0
|
||||
memoryUsage functionCreateMemoryFootprint Function 0
|
||||
noFTL functionNoFTL Function 0
|
||||
noOSRExitFuzzing functionNoOSRExitFuzzing Function 0
|
||||
numberOfDFGCompiles functionNumberOfDFGCompiles Function 0
|
||||
optimizeNextInvocation functionOptimizeNextInvocation Function 0
|
||||
releaseWeakRefs functionReleaseWeakRefs Function 0
|
||||
reoptimizationRetryCount functionReoptimizationRetryCount Function 0
|
||||
setRandomSeed functionSetRandomSeed Function 0
|
||||
startRemoteDebugger functionStartRemoteDebugger Function 0
|
||||
totalCompileTime functionTotalCompileTime Function 0
|
||||
getProtectedObjects functionGetProtectedObjects Function 0
|
||||
generateHeapSnapshotForDebugging functionGenerateHeapSnapshotForDebugging Function 0
|
||||
profile functionRunProfiler Function 0
|
||||
setTimeZone functionSetTimeZone Function 0
|
||||
serialize functionSerialize Function 0
|
||||
deserialize functionDeserialize Function 0
|
||||
estimateShallowMemoryUsageOf functionEstimateDirectMemoryUsageOf Function 1
|
||||
percentAvailableMemoryInUse functionPercentAvailableMemoryInUse Function 0
|
||||
@end
|
||||
|
||||
@@ -1,6 +1,80 @@
|
||||
import { define } from "../../codegen/class-definitions";
|
||||
|
||||
export default [
|
||||
define({
|
||||
name: "DNSResolver",
|
||||
construct: false,
|
||||
noConstructor: true,
|
||||
finalize: true,
|
||||
configurable: false,
|
||||
klass: {},
|
||||
proto: {
|
||||
setServers: {
|
||||
fn: "setServers",
|
||||
length: 1,
|
||||
},
|
||||
getServers: {
|
||||
fn: "getServers",
|
||||
length: 0,
|
||||
},
|
||||
resolve: {
|
||||
fn: "resolve",
|
||||
length: 3,
|
||||
},
|
||||
resolveSrv: {
|
||||
fn: "resolveSrv",
|
||||
length: 1,
|
||||
},
|
||||
resolveTxt: {
|
||||
fn: "resolveTxt",
|
||||
length: 1,
|
||||
},
|
||||
resolveSoa: {
|
||||
fn: "resolveSoa",
|
||||
length: 1,
|
||||
},
|
||||
resolveNaptr: {
|
||||
fn: "resolveNaptr",
|
||||
length: 1,
|
||||
},
|
||||
resolveMx: {
|
||||
fn: "resolveMx",
|
||||
length: 1,
|
||||
},
|
||||
resolveCaa: {
|
||||
fn: "resolveCaa",
|
||||
length: 1,
|
||||
},
|
||||
resolveNs: {
|
||||
fn: "resolveNs",
|
||||
length: 1,
|
||||
},
|
||||
resolvePtr: {
|
||||
fn: "resolvePtr",
|
||||
length: 1,
|
||||
},
|
||||
resolveCname: {
|
||||
fn: "resolveCname",
|
||||
length: 1,
|
||||
},
|
||||
resolveAny: {
|
||||
fn: "resolveAny",
|
||||
length: 1,
|
||||
},
|
||||
setLocalAddress: {
|
||||
fn: "setLocalAddress",
|
||||
length: 1,
|
||||
},
|
||||
cancel: {
|
||||
fn: "cancel",
|
||||
length: 0,
|
||||
},
|
||||
reverse: {
|
||||
fn: "reverse",
|
||||
length: 1,
|
||||
},
|
||||
},
|
||||
}),
|
||||
define({
|
||||
name: "FSWatcher",
|
||||
construct: false,
|
||||
|
||||
@@ -422,6 +422,7 @@ pub fn spawnIPCContext(rare: *RareData, vm: *JSC.VirtualMachine) *uws.SocketCont
|
||||
pub fn globalDNSResolver(rare: *RareData, vm: *JSC.VirtualMachine) *JSC.DNS.DNSResolver {
|
||||
if (rare.global_dns_data == null) {
|
||||
rare.global_dns_data = JSC.DNS.GlobalData.init(vm.allocator, vm);
|
||||
rare.global_dns_data.?.resolver.ref(); // live forever
|
||||
}
|
||||
|
||||
return &rare.global_dns_data.?.resolver;
|
||||
|
||||
@@ -30,6 +30,7 @@ const which = @import("which.zig").which;
|
||||
const JSC = bun.JSC;
|
||||
const AsyncHTTP = bun.http.AsyncHTTP;
|
||||
const Arena = @import("./mimalloc_arena.zig").Arena;
|
||||
const DNSResolver = @import("bun.js/api/bun/dns_resolver.zig").DNSResolver;
|
||||
|
||||
const OpaqueWrap = JSC.OpaqueWrap;
|
||||
const VirtualMachine = JSC.VirtualMachine;
|
||||
@@ -199,6 +200,7 @@ pub const Run = struct {
|
||||
.smol = ctx.runtime_options.smol,
|
||||
.eval = ctx.runtime_options.eval.eval_and_print,
|
||||
.debugger = ctx.runtime_options.debugger,
|
||||
.dns_result_order = DNSResolver.Order.fromStringOrDie(ctx.runtime_options.dns_result_order),
|
||||
.is_main_thread = true,
|
||||
},
|
||||
),
|
||||
|
||||
@@ -231,7 +231,8 @@ pub const Arguments = struct {
|
||||
clap.parseParam("--conditions <STR>... Pass custom conditions to resolve") catch unreachable,
|
||||
clap.parseParam("--fetch-preconnect <STR>... Preconnect to a URL while code is loading") catch unreachable,
|
||||
clap.parseParam("--max-http-header-size <INT> Set the maximum size of HTTP headers in bytes. Default is 16KiB") catch unreachable,
|
||||
clap.parseParam("--expose-internals Expose internals used for testing Bun itself. Usage of these APIs are completely unsupported.") catch unreachable,
|
||||
clap.parseParam("--expose-internals Expose internals used for testing Bun itself. Usage of these APIs is completely unsupported.") catch unreachable,
|
||||
clap.parseParam("--dns-result-order <STR> Set the default order of DNS lookup results. Valid orders: verbatim (default), ipv4first, ipv6first") catch unreachable,
|
||||
};
|
||||
|
||||
const auto_or_run_params = [_]ParamType{
|
||||
@@ -755,6 +756,10 @@ pub const Arguments = struct {
|
||||
ctx.runtime_options.smol = args.flag("--smol");
|
||||
ctx.runtime_options.preconnect = args.options("--fetch-preconnect");
|
||||
|
||||
if (args.option("--dns-result-order")) |order| {
|
||||
ctx.runtime_options.dns_result_order = order;
|
||||
}
|
||||
|
||||
if (args.option("--inspect")) |inspect_flag| {
|
||||
ctx.runtime_options.debugger = if (inspect_flag.len == 0)
|
||||
Command.Debugger{ .enable = .{} }
|
||||
@@ -1479,6 +1484,7 @@ pub const Command = struct {
|
||||
eval_and_print: bool = false,
|
||||
} = .{},
|
||||
preconnect: []const []const u8 = &[_][]const u8{},
|
||||
dns_result_order: []const u8 = "verbatim",
|
||||
};
|
||||
|
||||
var global_cli_ctx: Context = undefined;
|
||||
|
||||
@@ -192,6 +192,7 @@ pub const Options = extern struct {
|
||||
evsys: ares_evsys_t = 0,
|
||||
server_failover_opts: struct_ares_server_failover_options = @import("std").mem.zeroes(struct_ares_server_failover_options),
|
||||
};
|
||||
|
||||
pub const struct_hostent = extern struct {
|
||||
h_name: [*c]u8,
|
||||
h_aliases: [*c][*c]u8,
|
||||
@@ -200,39 +201,34 @@ pub const struct_hostent = extern struct {
|
||||
h_addr_list: [*c][*c]u8,
|
||||
|
||||
pub fn toJSResponse(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).toJS(globalThis));
|
||||
return array;
|
||||
}
|
||||
return JSC.JSValue.createEmptyArray(globalThis, 0);
|
||||
} else {
|
||||
if (this.h_aliases == null) {
|
||||
// A cname lookup always returns a single record but we follow the common API here.
|
||||
if (this.h_name == 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).toJS(globalThis));
|
||||
count += 1;
|
||||
}
|
||||
|
||||
return array;
|
||||
return bun.String.toJSArray(globalThis, &[_]bun.String{bun.String.fromUTF8(this.h_name[0..bun.len(this.h_name)])});
|
||||
}
|
||||
|
||||
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).toJS(globalThis));
|
||||
count += 1;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
pub fn Callback(comptime Type: type) type {
|
||||
@@ -269,7 +265,17 @@ pub const struct_hostent = extern struct {
|
||||
}
|
||||
|
||||
var start: [*c]struct_hostent = undefined;
|
||||
if (comptime strings.eqlComptime(lookup_name, "ns")) {
|
||||
if (comptime strings.eqlComptime(lookup_name, "cname")) {
|
||||
var addrttls: [256]struct_ares_addrttl = undefined;
|
||||
var naddrttls: i32 = 256;
|
||||
|
||||
const 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);
|
||||
} else if (comptime strings.eqlComptime(lookup_name, "ns")) {
|
||||
const result = ares_parse_ns_reply(buffer, buffer_length, &start);
|
||||
if (result != ARES_SUCCESS) {
|
||||
function(this, Error.get(result), timeouts, null);
|
||||
@@ -283,16 +289,8 @@ pub const struct_hostent = extern struct {
|
||||
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;
|
||||
|
||||
const 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);
|
||||
} else {
|
||||
@compileError(std.fmt.comptimePrint("Unsupported struct_hostent record type: {s}", .{lookup_name}));
|
||||
}
|
||||
}
|
||||
}.handle;
|
||||
@@ -303,6 +301,129 @@ pub const struct_hostent = extern struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const hostent_with_ttls = struct {
|
||||
hostent: *struct_hostent,
|
||||
ttls: [256]c_int = [_]c_int{-1} ** 256,
|
||||
|
||||
pub fn toJSResponse(this: *hostent_with_ttls, _: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime lookup_name: []const u8) JSC.JSValue {
|
||||
if (comptime strings.eqlComptime(lookup_name, "a") or strings.eqlComptime(lookup_name, "aaaa")) {
|
||||
if (this.hostent.h_addr_list == null) {
|
||||
return JSC.JSValue.createEmptyArray(globalThis, 0);
|
||||
}
|
||||
|
||||
var count: u32 = 0;
|
||||
while (this.hostent.h_addr_list[count] != null) {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
const array = JSC.JSValue.createEmptyArray(globalThis, count);
|
||||
count = 0;
|
||||
|
||||
const addressKey = JSC.ZigString.static("address").withEncoding();
|
||||
const ttlKey = JSC.ZigString.static("ttl").withEncoding();
|
||||
|
||||
while (this.hostent.h_addr_list[count]) |addr| : (count += 1) {
|
||||
const addrString = (if (this.hostent.h_addrtype == AF.INET6)
|
||||
bun.dns.addressToJS(&std.net.Address.initIp6(addr[0..16].*, 0, 0, 0), globalThis)
|
||||
else
|
||||
bun.dns.addressToJS(&std.net.Address.initIp4(addr[0..4].*, 0), globalThis)) catch return globalThis.throwOutOfMemoryValue();
|
||||
|
||||
const ttl: ?c_int = if (count < this.ttls.len) this.ttls[count] else null;
|
||||
const resultObject = JSC.JSValue.createObject2(globalThis, &addressKey, &ttlKey, addrString, if (ttl) |val| JSC.jsNumber(val) else .undefined);
|
||||
array.putIndex(globalThis, count, resultObject);
|
||||
}
|
||||
|
||||
return array;
|
||||
} else {
|
||||
@compileError(std.fmt.comptimePrint("Unsupported hostent_with_ttls record type: {s}", .{lookup_name}));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn Callback(comptime Type: type) type {
|
||||
return fn (*Type, status: ?Error, timeouts: i32, results: ?*hostent_with_ttls) void;
|
||||
}
|
||||
|
||||
pub fn hostCallbackWrapper(
|
||||
comptime Type: type,
|
||||
comptime function: Callback(Type),
|
||||
) ares_host_callback {
|
||||
return &struct {
|
||||
pub fn handle(ctx: ?*anyopaque, status: c_int, timeouts: c_int, hostent: ?*hostent_with_ttls) callconv(.C) void {
|
||||
const this = bun.cast(*Type, ctx.?);
|
||||
if (status != ARES_SUCCESS) {
|
||||
function(this, Error.get(status), timeouts, null);
|
||||
return;
|
||||
}
|
||||
function(this, null, timeouts, hostent);
|
||||
}
|
||||
}.handle;
|
||||
}
|
||||
|
||||
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 {
|
||||
const this = bun.cast(*Type, ctx.?);
|
||||
if (status != ARES_SUCCESS) {
|
||||
function(this, Error.get(status), timeouts, null);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (parse(lookup_name, buffer, buffer_length)) {
|
||||
.result => |result| function(this, null, timeouts, result),
|
||||
.err => |err| function(this, err, timeouts, null),
|
||||
}
|
||||
}
|
||||
}.handle;
|
||||
}
|
||||
|
||||
pub fn parse(comptime lookup_name: []const u8, buffer: [*c]u8, buffer_length: c_int) JSC.Node.Maybe(*hostent_with_ttls, Error) {
|
||||
var start: ?*struct_hostent = null;
|
||||
|
||||
if (comptime strings.eqlComptime(lookup_name, "a")) {
|
||||
var addrttls: [256]struct_ares_addrttl = undefined;
|
||||
var naddrttls: c_int = 256;
|
||||
|
||||
const result = ares_parse_a_reply(buffer, buffer_length, &start, &addrttls, &naddrttls);
|
||||
if (result != ARES_SUCCESS) {
|
||||
return .{ .err = Error.get(result).? };
|
||||
}
|
||||
var with_ttls = bun.default_allocator.create(hostent_with_ttls) catch bun.outOfMemory();
|
||||
with_ttls.hostent = start.?;
|
||||
for (addrttls[0..@intCast(naddrttls)], 0..) |ttl, i| {
|
||||
with_ttls.ttls[i] = ttl.ttl;
|
||||
}
|
||||
return .{ .result = with_ttls };
|
||||
}
|
||||
|
||||
if (comptime strings.eqlComptime(lookup_name, "aaaa")) {
|
||||
var addr6ttls: [256]struct_ares_addr6ttl = undefined;
|
||||
var naddr6ttls: c_int = 256;
|
||||
|
||||
const result = ares_parse_aaaa_reply(buffer, buffer_length, &start, &addr6ttls, &naddr6ttls);
|
||||
if (result != ARES_SUCCESS) {
|
||||
return .{ .err = Error.get(result).? };
|
||||
}
|
||||
var with_ttls = bun.default_allocator.create(hostent_with_ttls) catch bun.outOfMemory();
|
||||
with_ttls.hostent = start.?;
|
||||
for (addr6ttls[0..@intCast(naddr6ttls)], 0..) |ttl, i| {
|
||||
with_ttls.ttls[i] = ttl.ttl;
|
||||
}
|
||||
return .{ .result = with_ttls };
|
||||
}
|
||||
|
||||
@compileError(std.fmt.comptimePrint("Unsupported hostent_with_ttls record type: {s}", .{lookup_name}));
|
||||
}
|
||||
|
||||
pub fn deinit(this: *hostent_with_ttls) void {
|
||||
this.hostent.deinit();
|
||||
bun.default_allocator.destroy(this);
|
||||
}
|
||||
};
|
||||
|
||||
pub const struct_nameinfo = extern struct {
|
||||
node: [*c]u8,
|
||||
service: [*c]u8,
|
||||
@@ -351,7 +472,7 @@ pub const struct_nameinfo = extern struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const struct_timeval = opaque {};
|
||||
pub const struct_timeval = std.posix.timeval;
|
||||
pub const struct_Channeldata = opaque {};
|
||||
pub const AddrInfo_cname = extern struct {
|
||||
ttl: c_int,
|
||||
@@ -389,10 +510,7 @@ pub const AddrInfo = extern struct {
|
||||
globalThis: *JSC.JSGlobalObject,
|
||||
) JSC.JSValue {
|
||||
var node = addr_info.node orelse return JSC.JSValue.createEmptyArray(globalThis, 0);
|
||||
const array = JSC.JSValue.createEmptyArray(
|
||||
globalThis,
|
||||
node.count(),
|
||||
);
|
||||
const array = JSC.JSValue.createEmptyArray(globalThis, node.count());
|
||||
|
||||
{
|
||||
var j: u32 = 0;
|
||||
@@ -462,8 +580,13 @@ pub const AddrInfo_hints = extern struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const ChannelOptions = struct {
|
||||
timeout: ?i32 = null,
|
||||
tries: ?i32 = null,
|
||||
};
|
||||
|
||||
pub const Channel = opaque {
|
||||
pub fn init(comptime Container: type, this: *Container) ?Error {
|
||||
pub fn init(comptime Container: type, this: *Container, options: ChannelOptions) ?Error {
|
||||
var channel: *Channel = undefined;
|
||||
|
||||
libraryInit();
|
||||
@@ -483,8 +606,8 @@ pub const Channel = opaque {
|
||||
opts.flags = ARES_FLAG_NOCHECKRESP;
|
||||
opts.sock_state_cb = &SockStateWrap.onSockState;
|
||||
opts.sock_state_cb_data = @as(*anyopaque, @ptrCast(this));
|
||||
opts.timeout = -1;
|
||||
opts.tries = 4;
|
||||
opts.timeout = options.timeout orelse -1;
|
||||
opts.tries = options.tries orelse 4;
|
||||
|
||||
const optmask: c_int =
|
||||
ARES_OPT_FLAGS | ARES_OPT_TIMEOUTMS |
|
||||
@@ -499,6 +622,10 @@ pub const Channel = opaque {
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn deinit(this: *Channel) void {
|
||||
ares_destroy(this);
|
||||
}
|
||||
|
||||
///
|
||||
///The ares_getaddrinfo function initiates a host query by name on the name service channel identified by channel. The name and service parameters give the hostname and service as NULL-terminated C strings. The hints parameter is an ares_addrinfo_hints structure:
|
||||
///
|
||||
@@ -719,6 +846,7 @@ pub extern fn ares_create_query(name: [*c]const u8, dnsclass: c_int, @"type": c_
|
||||
pub extern fn ares_mkquery(name: [*c]const u8, dnsclass: c_int, @"type": c_int, id: c_ushort, rd: c_int, buf: [*c][*c]u8, buflen: [*c]c_int) c_int;
|
||||
pub extern fn ares_expand_name(encoded: [*c]const u8, abuf: [*c]const u8, alen: c_int, s: [*c][*c]u8, enclen: [*c]c_long) c_int;
|
||||
pub extern fn ares_expand_string(encoded: [*c]const u8, abuf: [*c]const u8, alen: c_int, s: [*c][*c]u8, enclen: [*c]c_long) c_int;
|
||||
pub extern fn ares_queue_active_queries(channel: *const Channel) usize;
|
||||
const union_unnamed_2 = extern union {
|
||||
_S6_u8: [16]u8,
|
||||
};
|
||||
@@ -726,7 +854,7 @@ pub const struct_ares_in6_addr = extern struct {
|
||||
_S6_un: union_unnamed_2,
|
||||
};
|
||||
pub const struct_ares_addrttl = extern struct {
|
||||
ipaddr: struct_in_addr,
|
||||
ipaddr: u32,
|
||||
ttl: c_int,
|
||||
};
|
||||
pub const struct_ares_addr6ttl = extern struct {
|
||||
@@ -1009,6 +1137,28 @@ pub const struct_ares_txt_reply = extern struct {
|
||||
return array;
|
||||
}
|
||||
|
||||
pub fn toJSForAny(this: *struct_ares_txt_reply, _: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
|
||||
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) : (txt = txt.?.next) {
|
||||
var node = txt.?;
|
||||
array.putIndex(globalThis, i, JSC.ZigString.fromUTF8(node.txt[0..node.length]).toJS(globalThis));
|
||||
i += 1;
|
||||
}
|
||||
|
||||
return JSC.JSObject.create(.{
|
||||
.entries = array,
|
||||
}, globalThis).toJS();
|
||||
}
|
||||
|
||||
pub fn Callback(comptime Type: type) type {
|
||||
return fn (*Type, status: ?Error, timeouts: i32, results: ?*struct_ares_txt_reply) void;
|
||||
}
|
||||
@@ -1218,6 +1368,207 @@ pub const struct_ares_uri_reply = extern struct {
|
||||
uri: [*c]u8,
|
||||
ttl: c_int,
|
||||
};
|
||||
|
||||
pub const struct_any_reply = struct {
|
||||
a_reply: ?*hostent_with_ttls = null,
|
||||
aaaa_reply: ?*hostent_with_ttls = null,
|
||||
mx_reply: ?*struct_ares_mx_reply = null,
|
||||
ns_reply: ?*struct_hostent = null,
|
||||
txt_reply: ?*struct_ares_txt_reply = null,
|
||||
srv_reply: ?*struct_ares_srv_reply = null,
|
||||
ptr_reply: ?*struct_hostent = null,
|
||||
naptr_reply: ?*struct_ares_naptr_reply = null,
|
||||
soa_reply: ?*struct_ares_soa_reply = null,
|
||||
caa_reply: ?*struct_ares_caa_reply = null,
|
||||
|
||||
pub fn toJSResponse(this: *struct_any_reply, parent_allocator: std.mem.Allocator, globalThis: *JSC.JSGlobalObject, comptime _: []const u8) JSC.JSValue {
|
||||
var stack = std.heap.stackFallback(2048, parent_allocator);
|
||||
var arena = bun.ArenaAllocator.init(stack.get());
|
||||
defer arena.deinit();
|
||||
|
||||
const allocator = arena.allocator();
|
||||
|
||||
return this.toJS(globalThis, allocator);
|
||||
}
|
||||
|
||||
fn append(globalThis: *JSC.JSGlobalObject, array: JSC.JSValue, i: *u32, response: JSC.JSValue, comptime lookup_name: []const u8) void {
|
||||
const transformed = if (response.isString())
|
||||
JSC.JSObject.create(.{
|
||||
.value = response,
|
||||
}, globalThis).toJS()
|
||||
else blk: {
|
||||
bun.assert(response.isObject());
|
||||
break :blk response;
|
||||
};
|
||||
|
||||
var upper = comptime lookup_name[0..lookup_name.len].*;
|
||||
inline for (&upper) |*char| {
|
||||
char.* = std.ascii.toUpper(char.*);
|
||||
}
|
||||
|
||||
transformed.put(globalThis, "type", bun.String.ascii(&upper).toJS(globalThis));
|
||||
array.putIndex(globalThis, i.*, transformed);
|
||||
i.* += 1;
|
||||
}
|
||||
|
||||
fn appendAll(globalThis: *JSC.JSGlobalObject, allocator: std.mem.Allocator, array: JSC.JSValue, i: *u32, reply: anytype, comptime lookup_name: []const u8) void {
|
||||
const response: JSC.JSValue = if (comptime @hasDecl(@TypeOf(reply.*), "toJSForAny"))
|
||||
reply.toJSForAny(allocator, globalThis, lookup_name)
|
||||
else
|
||||
reply.toJSResponse(allocator, globalThis, lookup_name);
|
||||
|
||||
if (response.isArray()) {
|
||||
var iterator = response.arrayIterator(globalThis);
|
||||
while (iterator.next()) |item| {
|
||||
append(globalThis, array, i, item, lookup_name);
|
||||
}
|
||||
} else {
|
||||
append(globalThis, array, i, response, lookup_name);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toJS(this: *struct_any_reply, globalThis: *JSC.JSGlobalObject, allocator: std.mem.Allocator) JSC.JSValue {
|
||||
const array = JSC.JSValue.createEmptyArray(globalThis, blk: {
|
||||
var len: usize = 0;
|
||||
inline for (comptime @typeInfo(struct_any_reply).Struct.fields) |field| {
|
||||
if (comptime std.mem.endsWith(u8, field.name, "_reply")) {
|
||||
len += @intFromBool(@field(this, field.name) != null);
|
||||
}
|
||||
}
|
||||
break :blk len;
|
||||
});
|
||||
|
||||
var i: u32 = 0;
|
||||
|
||||
inline for (comptime @typeInfo(struct_any_reply).Struct.fields) |field| {
|
||||
if (comptime std.mem.endsWith(u8, field.name, "_reply")) {
|
||||
if (@field(this, field.name)) |reply| {
|
||||
const lookup_name = comptime field.name[0 .. field.name.len - "_reply".len];
|
||||
appendAll(globalThis, allocator, array, &i, reply, lookup_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
pub fn Callback(comptime Type: type) type {
|
||||
return fn (*Type, status: ?Error, timeouts: i32, results: ?*struct_any_reply) void;
|
||||
}
|
||||
|
||||
pub fn callbackWrapper(
|
||||
comptime _: []const u8,
|
||||
comptime Type: type,
|
||||
comptime function: Callback(Type),
|
||||
) ares_callback {
|
||||
return &struct {
|
||||
pub fn handleAny(ctx: ?*anyopaque, status: c_int, timeouts: c_int, buffer: [*c]u8, buffer_length: c_int) callconv(.C) void {
|
||||
const this = bun.cast(*Type, ctx.?);
|
||||
if (status != ARES_SUCCESS) {
|
||||
function(this, Error.get(status), timeouts, null);
|
||||
return;
|
||||
}
|
||||
|
||||
var any_success = false;
|
||||
var last_error: ?c_int = null;
|
||||
var reply = bun.default_allocator.create(struct_any_reply) catch bun.outOfMemory();
|
||||
reply.* = .{};
|
||||
|
||||
switch (hostent_with_ttls.parse("a", buffer, buffer_length)) {
|
||||
.result => |result| {
|
||||
reply.a_reply = result;
|
||||
any_success = true;
|
||||
},
|
||||
.err => |err| last_error = @intFromEnum(err),
|
||||
}
|
||||
|
||||
switch (hostent_with_ttls.parse("aaaa", buffer, buffer_length)) {
|
||||
.result => |result| {
|
||||
reply.aaaa_reply = result;
|
||||
any_success = true;
|
||||
},
|
||||
.err => |err| last_error = @intFromEnum(err),
|
||||
}
|
||||
|
||||
var result = ares_parse_mx_reply(buffer, buffer_length, &reply.mx_reply);
|
||||
if (result == ARES_SUCCESS) {
|
||||
any_success = true;
|
||||
} else {
|
||||
last_error = result;
|
||||
}
|
||||
|
||||
result = ares_parse_ns_reply(buffer, buffer_length, &reply.ns_reply);
|
||||
if (result == ARES_SUCCESS) {
|
||||
any_success = true;
|
||||
} else {
|
||||
last_error = result;
|
||||
}
|
||||
|
||||
result = ares_parse_txt_reply(buffer, buffer_length, &reply.txt_reply);
|
||||
if (result == ARES_SUCCESS) {
|
||||
any_success = true;
|
||||
} else {
|
||||
last_error = result;
|
||||
}
|
||||
|
||||
result = ares_parse_srv_reply(buffer, buffer_length, &reply.srv_reply);
|
||||
if (result == ARES_SUCCESS) {
|
||||
any_success = true;
|
||||
} else {
|
||||
last_error = result;
|
||||
}
|
||||
|
||||
result = ares_parse_ptr_reply(buffer, buffer_length, null, 0, AF.INET, &reply.ptr_reply);
|
||||
if (result == ARES_SUCCESS) {
|
||||
any_success = true;
|
||||
} else {
|
||||
last_error = result;
|
||||
}
|
||||
|
||||
result = ares_parse_naptr_reply(buffer, buffer_length, &reply.naptr_reply);
|
||||
if (result == ARES_SUCCESS) {
|
||||
any_success = true;
|
||||
} else {
|
||||
last_error = result;
|
||||
}
|
||||
|
||||
result = ares_parse_soa_reply(buffer, buffer_length, &reply.soa_reply);
|
||||
if (result == ARES_SUCCESS) {
|
||||
any_success = true;
|
||||
} else {
|
||||
last_error = result;
|
||||
}
|
||||
|
||||
result = ares_parse_caa_reply(buffer, buffer_length, &reply.caa_reply);
|
||||
if (result == ARES_SUCCESS) {
|
||||
any_success = true;
|
||||
} else {
|
||||
last_error = result;
|
||||
}
|
||||
|
||||
if (!any_success) {
|
||||
reply.deinit();
|
||||
function(this, Error.get(last_error.?), timeouts, null);
|
||||
return;
|
||||
}
|
||||
|
||||
function(this, null, timeouts, reply);
|
||||
}
|
||||
}.handleAny;
|
||||
}
|
||||
|
||||
pub fn deinit(this: *struct_any_reply) void {
|
||||
inline for (@typeInfo(struct_any_reply).Struct.fields) |field| {
|
||||
if (comptime std.mem.endsWith(u8, field.name, "_reply")) {
|
||||
if (@field(this, field.name)) |reply| {
|
||||
reply.deinit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bun.default_allocator.destroy(this);
|
||||
}
|
||||
};
|
||||
pub extern fn ares_parse_a_reply(abuf: [*c]const u8, alen: c_int, host: [*c]?*struct_hostent, addrttls: [*c]struct_ares_addrttl, naddrttls: [*c]c_int) c_int;
|
||||
pub extern fn ares_parse_aaaa_reply(abuf: [*c]const u8, alen: c_int, host: [*c]?*struct_hostent, addrttls: [*c]struct_ares_addr6ttl, naddrttls: [*c]c_int) c_int;
|
||||
pub extern fn ares_parse_caa_reply(abuf: [*c]const u8, alen: c_int, caa_out: [*c][*c]struct_ares_caa_reply) c_int;
|
||||
@@ -1288,6 +1639,7 @@ pub const ARES_ELOADIPHLPAPI = 22;
|
||||
pub const ARES_EADDRGETNETWORKPARAMS = 23;
|
||||
pub const ARES_ECANCELLED = 24;
|
||||
pub const ARES_ESERVICE = 25;
|
||||
pub const ARES_ENOSERVER = 26;
|
||||
|
||||
pub const Error = enum(i32) {
|
||||
ENODATA = ARES_ENODATA,
|
||||
@@ -1315,25 +1667,105 @@ pub const Error = enum(i32) {
|
||||
EADDRGETNETWORKPARAMS = ARES_EADDRGETNETWORKPARAMS,
|
||||
ECANCELLED = ARES_ECANCELLED,
|
||||
ESERVICE = ARES_ESERVICE,
|
||||
ENOSERVER = ARES_ENOSERVER,
|
||||
|
||||
const Deferred = struct {
|
||||
errno: Error,
|
||||
syscall: []const u8,
|
||||
hostname: ?bun.String,
|
||||
promise: JSC.JSPromise.Strong,
|
||||
|
||||
pub usingnamespace bun.New(@This());
|
||||
|
||||
pub fn init(errno: Error, syscall: []const u8, hostname: ?bun.String, promise: JSC.JSPromise.Strong) *Deferred {
|
||||
return Deferred.new(.{
|
||||
.errno = errno,
|
||||
.syscall = syscall,
|
||||
.hostname = hostname,
|
||||
.promise = promise,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn reject(this: *Deferred, globalThis: *JSC.JSGlobalObject) void {
|
||||
const system_error = JSC.SystemError{
|
||||
.errno = @intFromEnum(this.errno),
|
||||
.code = bun.String.static(this.errno.code()),
|
||||
.message = if (this.hostname) |hostname| bun.String.createFormat("{s} {s} {s}", .{ this.syscall, this.errno.code()[4..], hostname }) catch bun.outOfMemory() else bun.String.empty,
|
||||
.syscall = bun.String.createUTF8(this.syscall),
|
||||
.hostname = this.hostname orelse bun.String.empty,
|
||||
};
|
||||
|
||||
const instance = system_error.toErrorInstance(globalThis);
|
||||
instance.put(globalThis, "name", bun.String.static("DNSException").toJS(globalThis));
|
||||
|
||||
this.promise.reject(globalThis, instance);
|
||||
this.hostname = null;
|
||||
this.deinit();
|
||||
}
|
||||
|
||||
pub fn rejectLater(this: *Deferred, globalThis: *JSC.JSGlobalObject) void {
|
||||
const Context = struct {
|
||||
deferred: *Deferred,
|
||||
globalThis: *JSC.JSGlobalObject,
|
||||
pub fn callback(context: *@This()) void {
|
||||
context.deferred.reject(context.globalThis);
|
||||
}
|
||||
};
|
||||
|
||||
const context = bun.default_allocator.create(Context) catch bun.outOfMemory();
|
||||
context.deferred = this;
|
||||
context.globalThis = globalThis;
|
||||
// TODO(@heimskr): new custom Task type
|
||||
globalThis.bunVM().enqueueTask(JSC.ManagedTask.New(Context, Context.callback).init(context));
|
||||
}
|
||||
|
||||
pub fn deinit(this: *@This()) void {
|
||||
if (this.hostname) |hostname| {
|
||||
hostname.deref();
|
||||
}
|
||||
this.promise.deinit();
|
||||
this.destroy();
|
||||
}
|
||||
};
|
||||
|
||||
pub fn toDeferred(this: Error, syscall: []const u8, hostname: ?[]const u8, promise: *JSC.JSPromise.Strong) *Deferred {
|
||||
const host_string: ?bun.String = if (hostname) |host|
|
||||
bun.String.createUTF8(host)
|
||||
else
|
||||
null;
|
||||
defer promise.* = .{};
|
||||
return Deferred.init(this, syscall, host_string, promise.*);
|
||||
}
|
||||
|
||||
pub fn toJS(this: Error, globalThis: *JSC.JSGlobalObject) JSC.JSValue {
|
||||
const error_value = globalThis.createErrorInstance("{s}", .{this.label()});
|
||||
error_value.put(
|
||||
globalThis,
|
||||
JSC.ZigString.static("name"),
|
||||
bun.String.static("DNSException").toJS(globalThis),
|
||||
);
|
||||
error_value.put(
|
||||
globalThis,
|
||||
JSC.ZigString.static("code"),
|
||||
JSC.ZigString.init(this.code()).toJS(globalThis),
|
||||
);
|
||||
error_value.put(
|
||||
globalThis,
|
||||
JSC.ZigString.static("errno"),
|
||||
JSC.jsNumber(@intFromEnum(this)),
|
||||
);
|
||||
return error_value;
|
||||
const instance = (JSC.SystemError{
|
||||
.errno = @intFromEnum(this),
|
||||
.code = bun.String.static(this.code()),
|
||||
}).toErrorInstance(globalThis);
|
||||
instance.put(globalThis, "name", bun.String.static("DNSException").toJS(globalThis));
|
||||
return instance;
|
||||
}
|
||||
|
||||
pub fn toJSWithSyscall(this: Error, globalThis: *JSC.JSGlobalObject, comptime syscall: []const u8) JSC.JSValue {
|
||||
const instance = (JSC.SystemError{
|
||||
.errno = @intFromEnum(this),
|
||||
.code = bun.String.static(this.code()),
|
||||
.syscall = bun.String.static((syscall ++ "\x00")[0..syscall.len :0]),
|
||||
}).toErrorInstance(globalThis);
|
||||
instance.put(globalThis, "name", bun.String.static("DNSException").toJS(globalThis));
|
||||
return instance;
|
||||
}
|
||||
|
||||
pub fn toJSWithSyscallAndHostname(this: Error, globalThis: *JSC.JSGlobalObject, comptime syscall: []const u8, hostname: []const u8) JSC.JSValue {
|
||||
const instance = (JSC.SystemError{
|
||||
.errno = @intFromEnum(this),
|
||||
.code = bun.String.static(this.code()),
|
||||
.message = bun.String.createFormat("{s} {s} {s}", .{ syscall, this.code()[4..], hostname }) catch bun.outOfMemory(),
|
||||
.syscall = bun.String.static((syscall ++ "\x00")[0..syscall.len :0]),
|
||||
.hostname = bun.String.createUTF8(hostname),
|
||||
}).toErrorInstance(globalThis);
|
||||
instance.put(globalThis, "name", bun.String.static("DNSException").toJS(globalThis));
|
||||
return instance;
|
||||
}
|
||||
|
||||
pub fn initEAI(rc: i32) ?Error {
|
||||
@@ -1422,6 +1854,7 @@ pub const Error = enum(i32) {
|
||||
.{ .EADDRGETNETWORKPARAMS, "DNS_EADDRGETNETWORKPARAMS" },
|
||||
.{ .ECANCELLED, "DNS_ECANCELLED" },
|
||||
.{ .ESERVICE, "DNS_ESERVICE" },
|
||||
.{ .ENOSERVER, "DNS_ENOSERVER" },
|
||||
});
|
||||
|
||||
pub const label = bun.enumMap(Error, .{
|
||||
@@ -1450,6 +1883,7 @@ pub const Error = enum(i32) {
|
||||
.{ .EADDRGETNETWORKPARAMS, "EADDRGETNETWORKPARAMS" },
|
||||
.{ .ECANCELLED, "DNS query cancelled" },
|
||||
.{ .ESERVICE, "Service not available" },
|
||||
.{ .ENOSERVER, "No DNS servers were configured" },
|
||||
});
|
||||
|
||||
pub fn get(rc: i32) ?Error {
|
||||
@@ -1460,8 +1894,8 @@ pub const Error = enum(i32) {
|
||||
|
||||
return switch (rc) {
|
||||
0 => null,
|
||||
1...ARES_ESERVICE => @as(Error, @enumFromInt(rc)),
|
||||
-ARES_ESERVICE...-1 => @as(Error, @enumFromInt(-rc)),
|
||||
1...ARES_ENOSERVER => @as(Error, @enumFromInt(rc)),
|
||||
-ARES_ENOSERVER...-1 => @as(Error, @enumFromInt(-rc)),
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,6 +3,12 @@ const std = @import("std");
|
||||
const JSC = bun.JSC;
|
||||
const JSValue = JSC.JSValue;
|
||||
|
||||
const netdb = if (bun.Environment.isWindows) .{
|
||||
.AI_V4MAPPED = @as(c_int, 2048),
|
||||
.AI_ADDRCONFIG = @as(c_int, 1024),
|
||||
.AI_ALL = @as(c_int, 256),
|
||||
} else @cImport(@cInclude("netdb.h"));
|
||||
|
||||
pub const GetAddrInfo = struct {
|
||||
name: []const u8 = "",
|
||||
port: u16 = 0,
|
||||
@@ -95,6 +101,9 @@ pub const GetAddrInfo = struct {
|
||||
return error.InvalidFlags;
|
||||
|
||||
options.flags = flags.coerce(i32, globalObject);
|
||||
|
||||
if (options.flags & ~(netdb.AI_ALL | netdb.AI_ADDRCONFIG | netdb.AI_V4MAPPED) != 0)
|
||||
return error.InvalidFlags;
|
||||
}
|
||||
|
||||
return options;
|
||||
|
||||
@@ -818,7 +818,7 @@ pub const Stringifier = struct {
|
||||
any = true;
|
||||
}
|
||||
try writer.writeAll(
|
||||
\\ "os":
|
||||
\\ "os":
|
||||
);
|
||||
try Negatable(Npm.OperatingSystem).toJson(meta.os, writer);
|
||||
}
|
||||
@@ -830,7 +830,7 @@ pub const Stringifier = struct {
|
||||
any = true;
|
||||
}
|
||||
try writer.writeAll(
|
||||
\\ "cpu":
|
||||
\\ "cpu":
|
||||
);
|
||||
try Negatable(Npm.Architecture).toJson(meta.arch, writer);
|
||||
}
|
||||
|
||||
@@ -913,6 +913,7 @@ pub const Tree = struct {
|
||||
// 1 (return hoisted) - de-duplicate (skip) the package
|
||||
// 2 (return id) - move the package to the top directory
|
||||
// 3 (return dependency_loop) - leave the package at the same (relative) directory
|
||||
// 4 (replace) - replace the existing (same name) parent dependency
|
||||
fn hoistDependency(
|
||||
this: *Tree,
|
||||
comptime as_defined: bool,
|
||||
|
||||
@@ -354,7 +354,7 @@ Socket.prototype.bind = function (port_, address_ /* , callback */) {
|
||||
family,
|
||||
});
|
||||
},
|
||||
error: (_socket, error) => {
|
||||
error: error => {
|
||||
this.emit("error", error);
|
||||
},
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
BIN
test/bun.lockb
BIN
test/bun.lockb
Binary file not shown.
@@ -220,8 +220,6 @@ test("dns.resolveNs (empty string) ", () => {
|
||||
dns.resolveNs("", (err, results) => {
|
||||
try {
|
||||
expect(err).toBeNull();
|
||||
console.log("resolveNs:", results);
|
||||
|
||||
expect(results instanceof Array).toBe(true);
|
||||
// root servers
|
||||
expect(results.sort()).toStrictEqual(
|
||||
@@ -254,7 +252,6 @@ test("dns.resolvePtr (ptr.socketify.dev)", () => {
|
||||
dns.resolvePtr("ptr.socketify.dev", (err, results) => {
|
||||
try {
|
||||
expect(err).toBeNull();
|
||||
console.log("resolvePtr:", results);
|
||||
expect(results instanceof Array).toBe(true);
|
||||
expect(results[0]).toBe("bun.sh");
|
||||
resolve();
|
||||
@@ -270,7 +267,6 @@ test("dns.resolveCname (cname.socketify.dev)", () => {
|
||||
dns.resolveCname("cname.socketify.dev", (err, results) => {
|
||||
try {
|
||||
expect(err).toBeNull();
|
||||
console.log("resolveCname:", results);
|
||||
expect(results instanceof Array).toBe(true);
|
||||
expect(results[0]).toBe("bun.sh");
|
||||
resolve();
|
||||
@@ -427,7 +423,7 @@ describe("test invalid arguments", () => {
|
||||
}).toThrow("Expected address to be a non-empty string for 'lookupService'.");
|
||||
expect(() => {
|
||||
dns.lookupService("google.com", 443, (err, hostname, service) => {});
|
||||
}).toThrow("Expected address to be a invalid address for 'lookupService'.");
|
||||
}).toThrow('The "address" argument is invalid. Received google.com');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -486,7 +482,7 @@ describe("dns.lookupService", () => {
|
||||
["1.1.1.1", 80, ["one.one.one.one", "http"]],
|
||||
["1.1.1.1", 443, ["one.one.one.one", "https"]],
|
||||
])("promises.lookupService(%s, %d)", async (address, port, expected) => {
|
||||
const [hostname, service] = await dns.promises.lookupService(address, port);
|
||||
const { hostname, service } = await dns.promises.lookupService(address, port);
|
||||
expect(hostname).toStrictEqual(expected[0]);
|
||||
expect(service).toStrictEqual(expected[1]);
|
||||
});
|
||||
|
||||
@@ -15,6 +15,7 @@ const types = {
|
||||
TXT: 16,
|
||||
ANY: 255,
|
||||
CAA: 257,
|
||||
SRV: 33,
|
||||
};
|
||||
|
||||
const classes = {
|
||||
|
||||
28
test/js/node/test/parallel/test-dns-cancel-reverse-lookup.js
Normal file
28
test/js/node/test/parallel/test-dns-cancel-reverse-lookup.js
Normal file
@@ -0,0 +1,28 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const dnstools = require('../common/dns');
|
||||
const { Resolver } = require('dns');
|
||||
const assert = require('assert');
|
||||
const dgram = require('dgram');
|
||||
|
||||
const server = dgram.createSocket('udp4');
|
||||
const resolver = new Resolver();
|
||||
|
||||
server.bind(0, common.mustCall(() => {
|
||||
resolver.setServers([`127.0.0.1:${server.address().port}`]);
|
||||
resolver.reverse('123.45.67.89', common.mustCall((err, res) => {
|
||||
assert.strictEqual(err.code, 'ECANCELLED');
|
||||
assert.strictEqual(err.syscall, 'getHostByAddr');
|
||||
assert.strictEqual(err.hostname, '123.45.67.89');
|
||||
server.close();
|
||||
}));
|
||||
}));
|
||||
|
||||
server.on('message', common.mustCall((msg, { address, port }) => {
|
||||
const parsed = dnstools.parseDNSPacket(msg);
|
||||
const domain = parsed.questions[0].domain;
|
||||
assert.strictEqual(domain, '89.67.45.123.in-addr.arpa');
|
||||
|
||||
// Do not send a reply.
|
||||
resolver.cancel();
|
||||
}));
|
||||
@@ -0,0 +1,59 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const { promises: dnsPromises } = require('dns');
|
||||
const assert = require('assert');
|
||||
const dgram = require('dgram');
|
||||
|
||||
const server = dgram.createSocket('udp4');
|
||||
const resolver = new dnsPromises.Resolver();
|
||||
|
||||
server.bind(0, common.mustCall(async () => {
|
||||
resolver.setServers([`127.0.0.1:${server.address().port}`]);
|
||||
|
||||
// Single promise
|
||||
{
|
||||
server.once('message', () => {
|
||||
resolver.cancel();
|
||||
});
|
||||
|
||||
const hostname = 'example0.org';
|
||||
|
||||
await assert.rejects(
|
||||
resolver.resolve4(hostname),
|
||||
{
|
||||
code: 'ECANCELLED',
|
||||
syscall: 'queryA',
|
||||
hostname
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Multiple promises
|
||||
{
|
||||
server.once('message', () => {
|
||||
resolver.cancel();
|
||||
});
|
||||
|
||||
const assertions = [];
|
||||
const assertionCount = 10;
|
||||
|
||||
for (let i = 1; i <= assertionCount; i++) {
|
||||
const hostname = `example${i}.org`;
|
||||
|
||||
assertions.push(
|
||||
assert.rejects(
|
||||
resolver.resolve4(hostname),
|
||||
{
|
||||
code: 'ECANCELLED',
|
||||
syscall: 'queryA',
|
||||
hostname: hostname
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
await Promise.all(assertions);
|
||||
}
|
||||
|
||||
server.close();
|
||||
}));
|
||||
46
test/js/node/test/parallel/test-dns-channel-cancel.js
Normal file
46
test/js/node/test/parallel/test-dns-channel-cancel.js
Normal 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);
|
||||
}));
|
||||
53
test/js/node/test/parallel/test-dns-channel-timeout.js
Normal file
53
test/js/node/test/parallel/test-dns-channel-timeout.js
Normal file
@@ -0,0 +1,53 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const dgram = require('dgram');
|
||||
const dns = require('dns');
|
||||
|
||||
for (const ctor of [dns.Resolver, dns.promises.Resolver]) {
|
||||
for (const timeout of [null, true, false, '', '2']) {
|
||||
assert.throws(() => new ctor({ timeout }), {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError',
|
||||
});
|
||||
}
|
||||
|
||||
for (const timeout of [-2, 4.2, 2 ** 31]) {
|
||||
assert.throws(() => new ctor({ timeout }), {
|
||||
code: 'ERR_OUT_OF_RANGE',
|
||||
name: 'RangeError',
|
||||
});
|
||||
}
|
||||
|
||||
for (const timeout of [-1, 0, 1]) new ctor({ timeout }); // OK
|
||||
}
|
||||
|
||||
for (const timeout of [0, 1, 2]) {
|
||||
const server = dgram.createSocket('udp4');
|
||||
server.bind(0, '127.0.0.1', common.mustCall(() => {
|
||||
const resolver = new dns.Resolver({ timeout });
|
||||
resolver.setServers([`127.0.0.1:${server.address().port}`]);
|
||||
resolver.resolve4('nodejs.org', common.mustCall((err) => {
|
||||
assert.throws(() => { throw err; }, {
|
||||
code: 'ETIMEOUT',
|
||||
name: /^(DNSException|Error)$/,
|
||||
});
|
||||
server.close();
|
||||
}));
|
||||
}));
|
||||
}
|
||||
|
||||
for (const timeout of [0, 1, 2]) {
|
||||
const server = dgram.createSocket('udp4');
|
||||
server.bind(0, '127.0.0.1', common.mustCall(() => {
|
||||
const resolver = new dns.promises.Resolver({ timeout });
|
||||
resolver.setServers([`127.0.0.1:${server.address().port}`]);
|
||||
resolver.resolve4('nodejs.org').catch(common.mustCall((err) => {
|
||||
assert.throws(() => { throw err; }, {
|
||||
code: 'ETIMEOUT',
|
||||
name: /^(DNSException|Error)$/,
|
||||
});
|
||||
server.close();
|
||||
}));
|
||||
}));
|
||||
}
|
||||
51
test/js/node/test/parallel/test-dns-default-order-ipv4.js
Normal file
51
test/js/node/test/parallel/test-dns-default-order-ipv4.js
Normal file
@@ -0,0 +1,51 @@
|
||||
// Flags: --dns-result-order=ipv4first
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const { promisify } = require('util');
|
||||
|
||||
// Test that --dns-result-order=ipv4first works as expected.
|
||||
|
||||
if (!process.execArgv.includes("--dns-result-order=ipv4first")) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const originalLookup = Bun.dns.lookup;
|
||||
const calls = [];
|
||||
Bun.dns.lookup = common.mustCallAtLeast((...args) => {
|
||||
calls.push(args);
|
||||
return originalLookup(...args);
|
||||
}, 1);
|
||||
|
||||
const dns = require('dns');
|
||||
const dnsPromises = dns.promises;
|
||||
|
||||
// We want to test the parameter of ipv4first only so that we
|
||||
// ignore possible errors here.
|
||||
function allowFailed(fn) {
|
||||
return fn.catch((_err) => {
|
||||
//
|
||||
});
|
||||
}
|
||||
|
||||
(async () => {
|
||||
let callsLength = 0;
|
||||
const checkParameter = (expected) => {
|
||||
assert.strictEqual(calls.length, callsLength + 1);
|
||||
const { order } = calls[callsLength][1];
|
||||
assert.strictEqual(order, expected);
|
||||
callsLength += 1;
|
||||
};
|
||||
|
||||
await allowFailed(promisify(dns.lookup)('example.org'));
|
||||
checkParameter('ipv4first');
|
||||
|
||||
await allowFailed(dnsPromises.lookup('example.org'));
|
||||
checkParameter('ipv4first');
|
||||
|
||||
await allowFailed(promisify(dns.lookup)('example.org', {}));
|
||||
checkParameter('ipv4first');
|
||||
|
||||
await allowFailed(dnsPromises.lookup('example.org', {}));
|
||||
checkParameter('ipv4first');
|
||||
})().then(common.mustCall());
|
||||
51
test/js/node/test/parallel/test-dns-default-order-ipv6.js
Normal file
51
test/js/node/test/parallel/test-dns-default-order-ipv6.js
Normal file
@@ -0,0 +1,51 @@
|
||||
// Flags: --dns-result-order=ipv6first
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const { promisify } = require('util');
|
||||
|
||||
// Test that --dns-result-order=ipv6first works as expected.
|
||||
|
||||
if (!process.execArgv.includes("--dns-result-order=ipv6first")) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const originalLookup = Bun.dns.lookup;
|
||||
const calls = [];
|
||||
Bun.dns.lookup = common.mustCallAtLeast((...args) => {
|
||||
calls.push(args);
|
||||
return originalLookup(...args);
|
||||
}, 1);
|
||||
|
||||
const dns = require('dns');
|
||||
const dnsPromises = dns.promises;
|
||||
|
||||
// We want to test the parameter of ipv6first only so that we
|
||||
// ignore possible errors here.
|
||||
function allowFailed(fn) {
|
||||
return fn.catch((_err) => {
|
||||
//
|
||||
});
|
||||
}
|
||||
|
||||
(async () => {
|
||||
let callsLength = 0;
|
||||
const checkParameter = (expected) => {
|
||||
assert.strictEqual(calls.length, callsLength + 1);
|
||||
const { order } = calls[callsLength][1];
|
||||
assert.strictEqual(order, expected);
|
||||
callsLength += 1;
|
||||
};
|
||||
|
||||
await allowFailed(promisify(dns.lookup)('example.org'));
|
||||
checkParameter('ipv6first');
|
||||
|
||||
await allowFailed(dnsPromises.lookup('example.org'));
|
||||
checkParameter('ipv6first');
|
||||
|
||||
await allowFailed(promisify(dns.lookup)('example.org', {}));
|
||||
checkParameter('ipv6first');
|
||||
|
||||
await allowFailed(dnsPromises.lookup('example.org', {}));
|
||||
checkParameter('ipv6first');
|
||||
})().then(common.mustCall());
|
||||
@@ -0,0 +1,55 @@
|
||||
// Flags: --dns-result-order=verbatim
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const { promisify } = require('util');
|
||||
|
||||
const originalLookup = Bun.dns.lookup;
|
||||
const calls = [];
|
||||
Bun.dns.lookup = common.mustCallAtLeast((...args) => {
|
||||
calls.push(args);
|
||||
return originalLookup(...args);
|
||||
}, 1);
|
||||
|
||||
const dns = require('dns');
|
||||
const dnsPromises = dns.promises;
|
||||
|
||||
// We want to test the parameter of verbatim only so that we
|
||||
// ignore possible errors here.
|
||||
function allowFailed(fn) {
|
||||
return fn.catch((_err) => {
|
||||
//
|
||||
});
|
||||
}
|
||||
|
||||
(async () => {
|
||||
let callsLength = 0;
|
||||
const checkParameter = (expected) => {
|
||||
assert.strictEqual(calls.length, callsLength + 1);
|
||||
const { order } = calls[callsLength][1];
|
||||
assert.strictEqual(order, expected);
|
||||
callsLength += 1;
|
||||
};
|
||||
|
||||
await allowFailed(promisify(dns.lookup)('example.org'));
|
||||
checkParameter("verbatim");
|
||||
|
||||
await allowFailed(dnsPromises.lookup('example.org'));
|
||||
checkParameter("verbatim");
|
||||
|
||||
await allowFailed(promisify(dns.lookup)('example.org', {}));
|
||||
checkParameter("verbatim");
|
||||
|
||||
await allowFailed(dnsPromises.lookup('example.org', {}));
|
||||
checkParameter("verbatim");
|
||||
|
||||
await allowFailed(
|
||||
promisify(dns.lookup)('example.org', { order: 'ipv4first' })
|
||||
);
|
||||
checkParameter("ipv4first");
|
||||
|
||||
await allowFailed(
|
||||
promisify(dns.lookup)('example.org', { order: 'ipv6first' })
|
||||
);
|
||||
checkParameter("ipv6first");
|
||||
})().then(common.mustCall());
|
||||
11
test/js/node/test/parallel/test-dns-get-server.js
Normal file
11
test/js/node/test/parallel/test-dns-get-server.js
Normal file
@@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
const { Resolver } = require('dns');
|
||||
|
||||
const resolver = new Resolver();
|
||||
assert(resolver.getServers().length > 0);
|
||||
|
||||
resolver._handle.getServers = common.mustCall();
|
||||
assert.strictEqual(resolver.getServers().length, 0);
|
||||
@@ -0,0 +1,44 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
Bun.dns.lookup = hostname => {
|
||||
throw Object.assign(new Error('Out of memory'), {
|
||||
name: 'DNSException',
|
||||
code: 'ENOMEM',
|
||||
syscall: 'getaddrinfo',
|
||||
hostname,
|
||||
});
|
||||
};
|
||||
|
||||
// This test ensures that dns.lookup issues a DeprecationWarning
|
||||
// when invalid options type is given
|
||||
|
||||
const dnsPromises = require('dns/promises');
|
||||
|
||||
common.expectWarning({
|
||||
// 'internal/test/binding': [
|
||||
// 'These APIs are for internal testing only. Do not use them.',
|
||||
// ],
|
||||
});
|
||||
|
||||
assert.throws(() => {
|
||||
dnsPromises.lookup('127.0.0.1', { hints: '-1' });
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError'
|
||||
});
|
||||
assert.throws(() => dnsPromises.lookup('127.0.0.1', { hints: -1 }),
|
||||
{ code: 'ERR_INVALID_ARG_VALUE' });
|
||||
assert.throws(() => dnsPromises.lookup('127.0.0.1', { family: '6' }),
|
||||
{ code: 'ERR_INVALID_ARG_VALUE' });
|
||||
assert.throws(() => dnsPromises.lookup('127.0.0.1', { all: 'true' }),
|
||||
{ code: 'ERR_INVALID_ARG_TYPE' });
|
||||
assert.throws(() => dnsPromises.lookup('127.0.0.1', { verbatim: 'true' }),
|
||||
{ code: 'ERR_INVALID_ARG_TYPE' });
|
||||
assert.throws(() => dnsPromises.lookup('127.0.0.1', { order: 'true' }),
|
||||
{ code: 'ERR_INVALID_ARG_VALUE' });
|
||||
assert.throws(() => dnsPromises.lookup('127.0.0.1', '6'),
|
||||
{ code: 'ERR_INVALID_ARG_TYPE' });
|
||||
assert.throws(() => dnsPromises.lookup('localhost'),
|
||||
{ code: 'ENOMEM' });
|
||||
214
test/js/node/test/parallel/test-dns-lookup.js
Normal file
214
test/js/node/test/parallel/test-dns-lookup.js
Normal file
@@ -0,0 +1,214 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
// Stub `getaddrinfo` to *always* error. This has to be done before we load the
|
||||
// `dns` module to guarantee that the `dns` module uses the stub.
|
||||
Bun.dns.lookup = (hostname) => Promise.reject(Object.assign(new Error('Out of memory'), { code: 'ENOMEM', hostname }));
|
||||
|
||||
const dns = require('dns');
|
||||
const dnsPromises = dns.promises;
|
||||
|
||||
{
|
||||
const err = {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError',
|
||||
message: /^The "hostname" argument must be of type string\. Received( type number|: "number")/
|
||||
};
|
||||
|
||||
assert.throws(() => dns.lookup(1, {}), err);
|
||||
assert.throws(() => dnsPromises.lookup(1, {}), err);
|
||||
}
|
||||
|
||||
// This also verifies different expectWarning notations.
|
||||
common.expectWarning({
|
||||
// For 'internal/test/binding' module.
|
||||
// 'internal/test/binding': [
|
||||
// 'These APIs are for internal testing only. Do not use them.',
|
||||
// ],
|
||||
// For calling `dns.lookup` with falsy `hostname`.
|
||||
'DeprecationWarning': {
|
||||
DEP0118: 'The provided hostname "false" is not a valid ' +
|
||||
'hostname, and is supported in the dns module solely for compatibility.'
|
||||
}
|
||||
});
|
||||
|
||||
assert.throws(() => {
|
||||
dns.lookup(false, 'cb');
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError'
|
||||
});
|
||||
|
||||
assert.throws(() => {
|
||||
dns.lookup(false, 'options', 'cb');
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError'
|
||||
});
|
||||
|
||||
{
|
||||
const err = {
|
||||
code: 'ERR_INVALID_ARG_VALUE',
|
||||
name: 'TypeError',
|
||||
message: /The (argument 'hints'|"hints" option) is invalid\. Received:? 100/
|
||||
};
|
||||
const options = {
|
||||
hints: 100,
|
||||
family: 0,
|
||||
all: false
|
||||
};
|
||||
|
||||
assert.throws(() => { dnsPromises.lookup(false, options); }, err);
|
||||
assert.throws(() => {
|
||||
dns.lookup(false, options, common.mustNotCall());
|
||||
}, err);
|
||||
}
|
||||
|
||||
{
|
||||
const family = 20;
|
||||
const err = {
|
||||
code: 'ERR_INVALID_ARG_VALUE',
|
||||
name: 'TypeError',
|
||||
message: /^The (property 'options.family' must be one of: 0, 4, 6|"family" option must be one of 0, 4 or 6)\. Received:? 20$/
|
||||
};
|
||||
const options = {
|
||||
hints: 0,
|
||||
family,
|
||||
all: false
|
||||
};
|
||||
|
||||
assert.throws(() => { dnsPromises.lookup(false, options); }, err);
|
||||
assert.throws(() => {
|
||||
dns.lookup(false, options, common.mustNotCall());
|
||||
}, err);
|
||||
}
|
||||
|
||||
[1, 0n, 1n, '', '0', Symbol(), true, false, {}, [], () => {}]
|
||||
.forEach((family) => {
|
||||
const err = { code: 'ERR_INVALID_ARG_VALUE' };
|
||||
const options = { family };
|
||||
assert.throws(() => { dnsPromises.lookup(false, options); }, err);
|
||||
assert.throws(() => {
|
||||
dns.lookup(false, options, common.mustNotCall());
|
||||
}, err);
|
||||
});
|
||||
[0n, 1n, '', '0', Symbol(), true, false].forEach((family) => {
|
||||
const err = { code: 'ERR_INVALID_ARG_TYPE' };
|
||||
assert.throws(() => { dnsPromises.lookup(false, family); }, err);
|
||||
assert.throws(() => {
|
||||
dns.lookup(false, family, common.mustNotCall());
|
||||
}, err);
|
||||
});
|
||||
assert.throws(() => dnsPromises.lookup(false, () => {}),
|
||||
{ code: 'ERR_INVALID_ARG_TYPE' });
|
||||
|
||||
[0n, 1n, '', '0', Symbol(), true, false, {}, [], () => {}].forEach((hints) => {
|
||||
const err = { code: 'ERR_INVALID_ARG_TYPE' };
|
||||
const options = { hints };
|
||||
assert.throws(() => { dnsPromises.lookup(false, options); }, err);
|
||||
assert.throws(() => {
|
||||
dns.lookup(false, options, common.mustNotCall());
|
||||
}, err);
|
||||
});
|
||||
|
||||
[0, 1, 0n, 1n, '', '0', Symbol(), {}, [], () => {}].forEach((all) => {
|
||||
const err = { code: 'ERR_INVALID_ARG_TYPE' };
|
||||
const options = { all };
|
||||
assert.throws(() => { dnsPromises.lookup(false, options); }, err);
|
||||
assert.throws(() => {
|
||||
dns.lookup(false, options, common.mustNotCall());
|
||||
}, err);
|
||||
});
|
||||
|
||||
[0, 1, 0n, 1n, '', '0', Symbol(), {}, [], () => {}].forEach((verbatim) => {
|
||||
const err = { code: 'ERR_INVALID_ARG_TYPE' };
|
||||
const options = { verbatim };
|
||||
assert.throws(() => { dnsPromises.lookup(false, options); }, err);
|
||||
assert.throws(() => {
|
||||
dns.lookup(false, options, common.mustNotCall());
|
||||
}, err);
|
||||
});
|
||||
|
||||
[0, 1, 0n, 1n, '', '0', Symbol(), {}, [], () => {}].forEach((order) => {
|
||||
const err = { code: 'ERR_INVALID_ARG_VALUE' };
|
||||
const options = { order };
|
||||
assert.throws(() => { dnsPromises.lookup(false, options); }, err);
|
||||
assert.throws(() => {
|
||||
dns.lookup(false, options, common.mustNotCall());
|
||||
}, err);
|
||||
});
|
||||
|
||||
(async function() {
|
||||
let res;
|
||||
|
||||
res = await dnsPromises.lookup(false, {
|
||||
hints: 0,
|
||||
family: 0,
|
||||
all: true
|
||||
});
|
||||
assert.deepStrictEqual(res, []);
|
||||
|
||||
res = await dnsPromises.lookup('127.0.0.1', {
|
||||
hints: 0,
|
||||
family: 4,
|
||||
all: true
|
||||
});
|
||||
assert.deepStrictEqual(res, [{ address: '127.0.0.1', family: 4 }]);
|
||||
|
||||
res = await dnsPromises.lookup('127.0.0.1', {
|
||||
hints: 0,
|
||||
family: 4,
|
||||
all: false
|
||||
});
|
||||
assert.deepStrictEqual(res, { address: '127.0.0.1', family: 4 });
|
||||
})().then(common.mustCall());
|
||||
|
||||
dns.lookup(false, {
|
||||
hints: 0,
|
||||
family: 0,
|
||||
all: true
|
||||
}, common.mustSucceed((result, addressType) => {
|
||||
assert.deepStrictEqual(result, []);
|
||||
assert.strictEqual(addressType, undefined);
|
||||
}));
|
||||
|
||||
dns.lookup('127.0.0.1', {
|
||||
hints: 0,
|
||||
family: 4,
|
||||
all: true
|
||||
}, common.mustSucceed((result, addressType) => {
|
||||
assert.deepStrictEqual(result, [{
|
||||
address: '127.0.0.1',
|
||||
family: 4
|
||||
}]);
|
||||
assert.strictEqual(addressType, undefined);
|
||||
}));
|
||||
|
||||
dns.lookup('127.0.0.1', {
|
||||
hints: 0,
|
||||
family: 4,
|
||||
all: false
|
||||
}, common.mustSucceed((result, addressType) => {
|
||||
assert.strictEqual(result, '127.0.0.1');
|
||||
assert.strictEqual(addressType, 4);
|
||||
}));
|
||||
|
||||
let tickValue = 0;
|
||||
|
||||
// Should fail due to stub.
|
||||
dns.lookup('example.com', common.mustCall((error, result, addressType) => {
|
||||
assert(error);
|
||||
assert.strictEqual(tickValue, 1);
|
||||
assert.strictEqual(error.code, 'ENOMEM');
|
||||
const descriptor = Object.getOwnPropertyDescriptor(error, 'message');
|
||||
// The error message should be non-enumerable.
|
||||
assert.strictEqual(descriptor.enumerable, false);
|
||||
}));
|
||||
|
||||
// Make sure that the error callback is called on next tick.
|
||||
tickValue = 1;
|
||||
|
||||
// Should fail due to stub.
|
||||
assert.rejects(dnsPromises.lookup('example.com'),
|
||||
{ code: 'ENOMEM', hostname: 'example.com' }).then(common.mustCall());
|
||||
@@ -0,0 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
|
||||
const assert = require('assert');
|
||||
const dnsPromises = require('dns').promises;
|
||||
|
||||
dnsPromises.lookupService('127.0.0.1', 22).then(common.mustCall((result) => {
|
||||
assert(['ssh', '22'].includes(result.service));
|
||||
assert.strictEqual(typeof result.hostname, 'string');
|
||||
assert.notStrictEqual(result.hostname.length, 0);
|
||||
}));
|
||||
|
||||
// Use an IP from the RFC 5737 test range to cause an error.
|
||||
// Refs: https://tools.ietf.org/html/rfc5737
|
||||
assert.rejects(
|
||||
() => dnsPromises.lookupService('192.0.2.1', 22),
|
||||
{ code: /^(?:ENOTFOUND|EAI_AGAIN)$/ }
|
||||
).then(common.mustCall());
|
||||
28
test/js/node/test/parallel/test-dns-lookupService.js
Normal file
28
test/js/node/test/parallel/test-dns-lookupService.js
Normal file
@@ -0,0 +1,28 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
// Stub `getnameinfo` to *always* error.
|
||||
Bun.dns.lookupService = (addr, port) => {
|
||||
throw Object.assign(new Error(`getnameinfo ENOENT ${addr}`), {code: 'ENOENT', syscall: 'getnameinfo'});
|
||||
};
|
||||
|
||||
const dns = require('dns');
|
||||
|
||||
assert.throws(
|
||||
() => dns.lookupService('127.0.0.1', 80, common.mustNotCall()),
|
||||
{
|
||||
code: 'ENOENT',
|
||||
message: 'getnameinfo ENOENT 127.0.0.1',
|
||||
syscall: 'getnameinfo'
|
||||
}
|
||||
);
|
||||
|
||||
assert.rejects(
|
||||
dns.promises.lookupService('127.0.0.1', 80),
|
||||
{
|
||||
code: 'ENOENT',
|
||||
message: 'getnameinfo ENOENT 127.0.0.1',
|
||||
syscall: 'getnameinfo'
|
||||
}
|
||||
).then(common.mustCall());
|
||||
52
test/js/node/test/parallel/test-dns-multi-channel.js
Normal file
52
test/js/node/test/parallel/test-dns-multi-channel.js
Normal file
@@ -0,0 +1,52 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const dnstools = require('../common/dns');
|
||||
const { Resolver } = require('dns');
|
||||
const assert = require('assert');
|
||||
const dgram = require('dgram');
|
||||
|
||||
const servers = [
|
||||
{
|
||||
socket: dgram.createSocket('udp4'),
|
||||
reply: { type: 'A', address: '1.2.3.4', ttl: 123, domain: 'example.org' }
|
||||
},
|
||||
{
|
||||
socket: dgram.createSocket('udp4'),
|
||||
reply: { type: 'A', address: '5.6.7.8', ttl: 123, domain: 'example.org' }
|
||||
},
|
||||
];
|
||||
|
||||
let waiting = servers.length;
|
||||
for (const { socket, reply } of servers) {
|
||||
socket.on('message', common.mustCall((msg, { address, port }) => {
|
||||
const parsed = dnstools.parseDNSPacket(msg);
|
||||
const domain = parsed.questions[0].domain;
|
||||
assert.strictEqual(domain, 'example.org');
|
||||
|
||||
socket.send(dnstools.writeDNSPacket({
|
||||
id: parsed.id,
|
||||
questions: parsed.questions,
|
||||
answers: [reply],
|
||||
}), port, address);
|
||||
}));
|
||||
|
||||
socket.bind(0, common.mustCall(() => {
|
||||
if (--waiting === 0) ready();
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
function ready() {
|
||||
const resolvers = servers.map((server) => ({
|
||||
server,
|
||||
resolver: new Resolver()
|
||||
}));
|
||||
|
||||
for (const { server: { socket, reply }, resolver } of resolvers) {
|
||||
resolver.setServers([`127.0.0.1:${socket.address().port}`]);
|
||||
resolver.resolve4('example.org', common.mustSucceed((res) => {
|
||||
assert.deepStrictEqual(res, [reply.address]);
|
||||
socket.close();
|
||||
}));
|
||||
}
|
||||
}
|
||||
33
test/js/node/test/parallel/test-dns-promises-exists.js
Normal file
33
test/js/node/test/parallel/test-dns-promises-exists.js
Normal file
@@ -0,0 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
require('../common');
|
||||
const assert = require('assert');
|
||||
const dnsPromises = require('dns/promises');
|
||||
const dns = require('dns');
|
||||
|
||||
assert.strictEqual(dnsPromises, dns.promises);
|
||||
|
||||
assert.strictEqual(dnsPromises.NODATA, dns.NODATA);
|
||||
assert.strictEqual(dnsPromises.FORMERR, dns.FORMERR);
|
||||
assert.strictEqual(dnsPromises.SERVFAIL, dns.SERVFAIL);
|
||||
assert.strictEqual(dnsPromises.NOTFOUND, dns.NOTFOUND);
|
||||
assert.strictEqual(dnsPromises.NOTIMP, dns.NOTIMP);
|
||||
assert.strictEqual(dnsPromises.REFUSED, dns.REFUSED);
|
||||
assert.strictEqual(dnsPromises.BADQUERY, dns.BADQUERY);
|
||||
assert.strictEqual(dnsPromises.BADNAME, dns.BADNAME);
|
||||
assert.strictEqual(dnsPromises.BADFAMILY, dns.BADFAMILY);
|
||||
assert.strictEqual(dnsPromises.BADRESP, dns.BADRESP);
|
||||
assert.strictEqual(dnsPromises.CONNREFUSED, dns.CONNREFUSED);
|
||||
assert.strictEqual(dnsPromises.TIMEOUT, dns.TIMEOUT);
|
||||
assert.strictEqual(dnsPromises.EOF, dns.EOF);
|
||||
assert.strictEqual(dnsPromises.FILE, dns.FILE);
|
||||
assert.strictEqual(dnsPromises.NOMEM, dns.NOMEM);
|
||||
assert.strictEqual(dnsPromises.DESTRUCTION, dns.DESTRUCTION);
|
||||
assert.strictEqual(dnsPromises.BADSTR, dns.BADSTR);
|
||||
assert.strictEqual(dnsPromises.BADFLAGS, dns.BADFLAGS);
|
||||
assert.strictEqual(dnsPromises.NONAME, dns.NONAME);
|
||||
assert.strictEqual(dnsPromises.BADHINTS, dns.BADHINTS);
|
||||
assert.strictEqual(dnsPromises.NOTINITIALIZED, dns.NOTINITIALIZED);
|
||||
assert.strictEqual(dnsPromises.LOADIPHLPAPI, dns.LOADIPHLPAPI);
|
||||
assert.strictEqual(dnsPromises.ADDRGETNETWORKPARAMS, dns.ADDRGETNETWORKPARAMS);
|
||||
assert.strictEqual(dnsPromises.CANCELLED, dns.CANCELLED);
|
||||
15
test/js/node/test/parallel/test-dns-resolve-promises.js
Normal file
15
test/js/node/test/parallel/test-dns-resolve-promises.js
Normal file
@@ -0,0 +1,15 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const dnsPromises = require('dns').promises;
|
||||
|
||||
Bun.dns.resolve = (hostname, rrtype) => Promise.reject({code: 'EPERM', syscall: 'query' + rrtype[0].toUpperCase() + rrtype.substr(1), hostname});
|
||||
|
||||
assert.rejects(
|
||||
dnsPromises.resolve('example.org'),
|
||||
{
|
||||
code: 'EPERM',
|
||||
syscall: 'queryA',
|
||||
hostname: 'example.org'
|
||||
}
|
||||
).then(common.mustCall());
|
||||
@@ -0,0 +1,55 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const dnstools = require('../common/dns');
|
||||
const dns = require('dns');
|
||||
const assert = require('assert');
|
||||
const dgram = require('dgram');
|
||||
const dnsPromises = dns.promises;
|
||||
|
||||
const server = dgram.createSocket('udp4');
|
||||
const resolver = new dns.Resolver({ timeout: 100, tries: 1 });
|
||||
const resolverPromises = new dnsPromises.Resolver({ timeout: 100, tries: 1 });
|
||||
|
||||
server.on('message', common.mustCallAtLeast((msg, { address, port }) => {
|
||||
const parsed = dnstools.parseDNSPacket(msg);
|
||||
const domain = parsed.questions[0].domain;
|
||||
|
||||
assert.strictEqual(domain, 'example.org');
|
||||
|
||||
const buf = dnstools.writeDNSPacket({
|
||||
id: parsed.id,
|
||||
questions: parsed.questions,
|
||||
answers: { type: 'A', address: '1.2.3.4', ttl: 123, domain },
|
||||
});
|
||||
// Overwrite the # of answers with 2, which is incorrect. The response is
|
||||
// discarded in c-ares >= 1.21.0. This is the reason why a small timeout is
|
||||
// used in the `Resolver` constructor. See
|
||||
// https://github.com/nodejs/node/pull/50743#issue-1994909204
|
||||
buf.writeUInt16LE(2, 6);
|
||||
server.send(buf, port, address);
|
||||
}, 2));
|
||||
|
||||
server.bind(0, common.mustCall(async () => {
|
||||
const address = server.address();
|
||||
resolver.setServers([`127.0.0.1:${address.port}`]);
|
||||
resolverPromises.setServers([`127.0.0.1:${address.port}`]);
|
||||
|
||||
resolverPromises.resolveAny('example.org')
|
||||
.then(common.mustNotCall())
|
||||
.catch(common.expectsError({
|
||||
// May return EBADRESP or ETIMEOUT
|
||||
code: /^(?:EBADRESP|ETIMEOUT)$/,
|
||||
syscall: 'queryAny',
|
||||
hostname: 'example.org'
|
||||
}));
|
||||
|
||||
resolver.resolveAny('example.org', common.mustCall((err) => {
|
||||
assert.notStrictEqual(err.code, 'SUCCESS');
|
||||
assert.strictEqual(err.syscall, 'queryAny');
|
||||
assert.strictEqual(err.hostname, 'example.org');
|
||||
const descriptor = Object.getOwnPropertyDescriptor(err, 'message');
|
||||
// The error message should be non-enumerable.
|
||||
assert.strictEqual(descriptor.enumerable, false);
|
||||
server.close();
|
||||
}));
|
||||
}));
|
||||
69
test/js/node/test/parallel/test-dns-resolveany.js
Normal file
69
test/js/node/test/parallel/test-dns-resolveany.js
Normal file
@@ -0,0 +1,69 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const dnstools = require('../common/dns');
|
||||
const dns = require('dns');
|
||||
const assert = require('assert');
|
||||
const dgram = require('dgram');
|
||||
const dnsPromises = dns.promises;
|
||||
|
||||
const answers = [
|
||||
{ type: 'A', address: '1.2.3.4', ttl: 123 },
|
||||
{ type: 'AAAA', address: '::42', ttl: 123 },
|
||||
{ type: 'MX', priority: 42, exchange: 'foobar.com', ttl: 124 },
|
||||
{ type: 'NS', value: 'foobar.org', ttl: 457 },
|
||||
{ type: 'TXT', entries: [ 'v=spf1 ~all xyz\0foo' ] },
|
||||
{ type: 'PTR', value: 'baz.org', ttl: 987 },
|
||||
{
|
||||
type: 'SOA',
|
||||
nsname: 'ns1.example.com',
|
||||
hostmaster: 'admin.example.com',
|
||||
serial: 156696742,
|
||||
refresh: 900,
|
||||
retry: 900,
|
||||
expire: 1800,
|
||||
minttl: 60
|
||||
},
|
||||
{
|
||||
type: 'CAA',
|
||||
critical: 128,
|
||||
issue: 'platynum.ch'
|
||||
},
|
||||
];
|
||||
|
||||
const server = dgram.createSocket('udp4');
|
||||
|
||||
server.on('message', common.mustCall((msg, { address, port }) => {
|
||||
const parsed = dnstools.parseDNSPacket(msg);
|
||||
const domain = parsed.questions[0].domain;
|
||||
assert.strictEqual(domain, 'example.org');
|
||||
|
||||
server.send(dnstools.writeDNSPacket({
|
||||
id: parsed.id,
|
||||
questions: parsed.questions,
|
||||
answers: answers.map((answer) => Object.assign({ domain }, answer)),
|
||||
}), port, address);
|
||||
}, 2));
|
||||
|
||||
server.bind(0, common.mustCall(async () => {
|
||||
const address = server.address();
|
||||
dns.setServers([`127.0.0.1:${address.port}`]);
|
||||
|
||||
validateResults(await dnsPromises.resolveAny('example.org'));
|
||||
|
||||
dns.resolveAny('example.org', common.mustSucceed((res) => {
|
||||
validateResults(res);
|
||||
server.close();
|
||||
}));
|
||||
}));
|
||||
|
||||
function validateResults(res) {
|
||||
// TTL values are only provided for A and AAAA entries.
|
||||
assert.deepStrictEqual(res.map(maybeRedactTTL), answers.map(maybeRedactTTL));
|
||||
}
|
||||
|
||||
function maybeRedactTTL(r) {
|
||||
const ret = { ...r };
|
||||
if (!['A', 'AAAA'].includes(r.type))
|
||||
delete ret.ttl;
|
||||
return ret;
|
||||
}
|
||||
55
test/js/node/test/parallel/test-dns-resolvens-typeerror.js
Normal file
55
test/js/node/test/parallel/test-dns-resolvens-typeerror.js
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
'use strict';
|
||||
require('../common');
|
||||
|
||||
// This test ensures `dns.resolveNs()` does not raise a C++-land assertion error
|
||||
// and throw a JavaScript TypeError instead.
|
||||
// Issue https://github.com/nodejs/node-v0.x-archive/issues/7070
|
||||
|
||||
const assert = require('assert');
|
||||
const dns = require('dns');
|
||||
const dnsPromises = dns.promises;
|
||||
|
||||
assert.throws(
|
||||
() => dnsPromises.resolveNs([]), // bad name
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError',
|
||||
message: /^(The "(host)?name" argument must be of type string|Expected hostname to be a string)/
|
||||
}
|
||||
);
|
||||
assert.throws(
|
||||
() => dns.resolveNs([]), // bad name
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError',
|
||||
message: /^(The "(host)?name" argument must be of type string|Expected hostname to be a string)/
|
||||
}
|
||||
);
|
||||
assert.throws(
|
||||
() => dns.resolveNs(''), // bad callback
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError'
|
||||
}
|
||||
);
|
||||
108
test/js/node/test/parallel/test-dns-set-default-order.js
Normal file
108
test/js/node/test/parallel/test-dns-set-default-order.js
Normal file
@@ -0,0 +1,108 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const { promisify } = require('util');
|
||||
|
||||
// Test that `dns.setDefaultResultOrder()` and
|
||||
// `dns.promises.setDefaultResultOrder()` work as expected.
|
||||
|
||||
const originalLookup = Bun.dns.lookup;
|
||||
const calls = [];
|
||||
Bun.dns.lookup = common.mustCallAtLeast((...args) => {
|
||||
calls.push(args);
|
||||
return originalLookup(...args);
|
||||
}, 1);
|
||||
|
||||
const dns = require('dns');
|
||||
const dnsPromises = dns.promises;
|
||||
|
||||
// We want to test the parameter of order only so that we
|
||||
// ignore possible errors here.
|
||||
function allowFailed(fn) {
|
||||
return fn.catch((_err) => {
|
||||
//
|
||||
});
|
||||
}
|
||||
|
||||
assert.throws(() => dns.setDefaultResultOrder('my_order'), {
|
||||
code: 'ERR_INVALID_ARG_VALUE',
|
||||
});
|
||||
assert.throws(() => dns.promises.setDefaultResultOrder('my_order'), {
|
||||
code: 'ERR_INVALID_ARG_VALUE',
|
||||
});
|
||||
assert.throws(() => dns.setDefaultResultOrder(4), {
|
||||
code: 'ERR_INVALID_ARG_VALUE',
|
||||
});
|
||||
assert.throws(() => dns.promises.setDefaultResultOrder(4), {
|
||||
code: 'ERR_INVALID_ARG_VALUE',
|
||||
});
|
||||
|
||||
(async () => {
|
||||
let callsLength = 0;
|
||||
const checkParameter = (expected) => {
|
||||
assert.strictEqual(calls.length, callsLength + 1);
|
||||
const { order } = calls[callsLength][1];
|
||||
assert.strictEqual(order, expected);
|
||||
callsLength += 1;
|
||||
};
|
||||
|
||||
dns.setDefaultResultOrder('verbatim');
|
||||
await allowFailed(promisify(dns.lookup)('example.org'));
|
||||
checkParameter('verbatim');
|
||||
await allowFailed(dnsPromises.lookup('example.org'));
|
||||
checkParameter('verbatim');
|
||||
await allowFailed(promisify(dns.lookup)('example.org', {}));
|
||||
checkParameter('verbatim');
|
||||
await allowFailed(dnsPromises.lookup('example.org', {}));
|
||||
checkParameter('verbatim');
|
||||
|
||||
dns.setDefaultResultOrder('ipv4first');
|
||||
await allowFailed(promisify(dns.lookup)('example.org'));
|
||||
checkParameter('ipv4first');
|
||||
await allowFailed(dnsPromises.lookup('example.org'));
|
||||
checkParameter('ipv4first');
|
||||
await allowFailed(promisify(dns.lookup)('example.org', {}));
|
||||
checkParameter('ipv4first');
|
||||
await allowFailed(dnsPromises.lookup('example.org', {}));
|
||||
checkParameter('ipv4first');
|
||||
|
||||
dns.setDefaultResultOrder('ipv6first');
|
||||
await allowFailed(promisify(dns.lookup)('example.org'));
|
||||
checkParameter('ipv6first');
|
||||
await allowFailed(dnsPromises.lookup('example.org'));
|
||||
checkParameter('ipv6first');
|
||||
await allowFailed(promisify(dns.lookup)('example.org', {}));
|
||||
checkParameter('ipv6first');
|
||||
await allowFailed(dnsPromises.lookup('example.org', {}));
|
||||
checkParameter('ipv6first');
|
||||
|
||||
dns.promises.setDefaultResultOrder('verbatim');
|
||||
await allowFailed(promisify(dns.lookup)('example.org'));
|
||||
checkParameter('verbatim');
|
||||
await allowFailed(dnsPromises.lookup('example.org'));
|
||||
checkParameter('verbatim');
|
||||
await allowFailed(promisify(dns.lookup)('example.org', {}));
|
||||
checkParameter('verbatim');
|
||||
await allowFailed(dnsPromises.lookup('example.org', {}));
|
||||
checkParameter('verbatim');
|
||||
|
||||
dns.promises.setDefaultResultOrder('ipv4first');
|
||||
await allowFailed(promisify(dns.lookup)('example.org'));
|
||||
checkParameter('ipv4first');
|
||||
await allowFailed(dnsPromises.lookup('example.org'));
|
||||
checkParameter('ipv4first');
|
||||
await allowFailed(promisify(dns.lookup)('example.org', {}));
|
||||
checkParameter('ipv4first');
|
||||
await allowFailed(dnsPromises.lookup('example.org', {}));
|
||||
checkParameter('ipv4first');
|
||||
|
||||
dns.promises.setDefaultResultOrder('ipv6first');
|
||||
await allowFailed(promisify(dns.lookup)('example.org'));
|
||||
checkParameter('ipv6first');
|
||||
await allowFailed(dnsPromises.lookup('example.org'));
|
||||
checkParameter('ipv6first');
|
||||
await allowFailed(promisify(dns.lookup)('example.org', {}));
|
||||
checkParameter('ipv6first');
|
||||
await allowFailed(dnsPromises.lookup('example.org', {}));
|
||||
checkParameter('ipv6first');
|
||||
})().then(common.mustCall());
|
||||
40
test/js/node/test/parallel/test-dns-setlocaladdress.js
Normal file
40
test/js/node/test/parallel/test-dns-setlocaladdress.js
Normal file
@@ -0,0 +1,40 @@
|
||||
'use strict';
|
||||
require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
const dns = require('dns');
|
||||
const resolver = new dns.Resolver();
|
||||
const promiseResolver = new dns.promises.Resolver();
|
||||
|
||||
// Verifies that setLocalAddress succeeds with IPv4 and IPv6 addresses
|
||||
{
|
||||
resolver.setLocalAddress('127.0.0.1');
|
||||
resolver.setLocalAddress('::1');
|
||||
resolver.setLocalAddress('127.0.0.1', '::1');
|
||||
promiseResolver.setLocalAddress('127.0.0.1', '::1');
|
||||
}
|
||||
|
||||
// Verify that setLocalAddress throws if called with an invalid address
|
||||
{
|
||||
assert.throws(() => {
|
||||
resolver.setLocalAddress('127.0.0.1', '127.0.0.1');
|
||||
}, Error);
|
||||
assert.throws(() => {
|
||||
resolver.setLocalAddress('::1', '::1');
|
||||
}, Error);
|
||||
assert.throws(() => {
|
||||
resolver.setLocalAddress('bad');
|
||||
}, Error);
|
||||
assert.throws(() => {
|
||||
resolver.setLocalAddress(123);
|
||||
}, { code: 'ERR_INVALID_ARG_TYPE' });
|
||||
assert.throws(() => {
|
||||
resolver.setLocalAddress('127.0.0.1', 42);
|
||||
}, { code: 'ERR_INVALID_ARG_TYPE' });
|
||||
assert.throws(() => {
|
||||
resolver.setLocalAddress();
|
||||
}, Error);
|
||||
assert.throws(() => {
|
||||
promiseResolver.setLocalAddress();
|
||||
}, Error);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
|
||||
const assert = require('assert');
|
||||
const dns = require('dns');
|
||||
|
||||
const localhost = [ '127.0.0.1' ];
|
||||
|
||||
{
|
||||
// Fix https://github.com/nodejs/node/issues/14734
|
||||
|
||||
{
|
||||
const resolver = new dns.Resolver();
|
||||
resolver.resolve('localhost', common.mustCall());
|
||||
|
||||
assert.throws(resolver.setServers.bind(resolver, localhost), {
|
||||
code: 'ERR_DNS_SET_SERVERS_FAILED',
|
||||
message: /[Tt]here are pending queries/
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
dns.resolve('localhost', common.mustCall());
|
||||
|
||||
// should not throw
|
||||
dns.setServers(localhost);
|
||||
}
|
||||
}
|
||||
117
test/js/node/test/parallel/test-dns-setservers-type-check.js
Normal file
117
test/js/node/test/parallel/test-dns-setservers-type-check.js
Normal file
@@ -0,0 +1,117 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const { addresses } = require('../common/internet');
|
||||
const assert = require('assert');
|
||||
const dns = require('dns');
|
||||
const resolver = new dns.promises.Resolver();
|
||||
const dnsPromises = dns.promises;
|
||||
const promiseResolver = new dns.promises.Resolver();
|
||||
|
||||
{
|
||||
[
|
||||
null,
|
||||
undefined,
|
||||
Number(addresses.DNS4_SERVER),
|
||||
addresses.DNS4_SERVER,
|
||||
{
|
||||
address: addresses.DNS4_SERVER
|
||||
},
|
||||
].forEach((val) => {
|
||||
const errObj = {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError',
|
||||
message: /^The "servers" argument must be an instance of Array\./
|
||||
};
|
||||
assert.throws(
|
||||
() => {
|
||||
dns.setServers(val);
|
||||
}, errObj
|
||||
);
|
||||
assert.throws(
|
||||
() => {
|
||||
resolver.setServers(val);
|
||||
}, errObj
|
||||
);
|
||||
assert.throws(
|
||||
() => {
|
||||
dnsPromises.setServers(val);
|
||||
}, errObj
|
||||
);
|
||||
assert.throws(
|
||||
() => {
|
||||
promiseResolver.setServers(val);
|
||||
}, errObj
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
[
|
||||
[null],
|
||||
[undefined],
|
||||
[Number(addresses.DNS4_SERVER)],
|
||||
[
|
||||
{
|
||||
address: addresses.DNS4_SERVER
|
||||
},
|
||||
],
|
||||
].forEach((val) => {
|
||||
const errObj = {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError',
|
||||
message: /^The "servers\[0\]" argument must be of type string\./
|
||||
};
|
||||
assert.throws(
|
||||
() => {
|
||||
dns.setServers(val);
|
||||
}, errObj
|
||||
);
|
||||
assert.throws(
|
||||
() => {
|
||||
resolver.setServers(val);
|
||||
}, errObj
|
||||
);
|
||||
assert.throws(
|
||||
() => {
|
||||
dnsPromises.setServers(val);
|
||||
}, errObj
|
||||
);
|
||||
assert.throws(
|
||||
() => {
|
||||
promiseResolver.setServers(val);
|
||||
}, errObj
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// This test for 'dns/promises'
|
||||
{
|
||||
const {
|
||||
setServers
|
||||
} = require('dns/promises');
|
||||
|
||||
// This should not throw any error.
|
||||
(async () => {
|
||||
setServers([ '127.0.0.1' ]);
|
||||
})().then(common.mustCall());
|
||||
|
||||
[
|
||||
[null],
|
||||
[undefined],
|
||||
[Number(addresses.DNS4_SERVER)],
|
||||
[
|
||||
{
|
||||
address: addresses.DNS4_SERVER
|
||||
},
|
||||
],
|
||||
].forEach((val) => {
|
||||
const errObj = {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError',
|
||||
message: /^The "servers\[0\]" argument must be of type string\./
|
||||
};
|
||||
assert.throws(() => {
|
||||
setServers(val);
|
||||
}, errObj);
|
||||
});
|
||||
}
|
||||
461
test/js/node/test/parallel/test-dns.js
Normal file
461
test/js/node/test/parallel/test-dns.js
Normal file
@@ -0,0 +1,461 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const dnstools = require('../common/dns');
|
||||
const assert = require('assert');
|
||||
|
||||
const dns = require('dns');
|
||||
const dnsPromises = dns.promises;
|
||||
const dgram = require('dgram');
|
||||
|
||||
const existing = dns.getServers();
|
||||
assert(existing.length > 0);
|
||||
|
||||
// Verify that setServers() handles arrays with holes and other oddities
|
||||
{
|
||||
const servers = [];
|
||||
|
||||
servers[0] = '127.0.0.1';
|
||||
servers[2] = '0.0.0.0';
|
||||
dns.setServers(servers);
|
||||
|
||||
assert.deepStrictEqual(dns.getServers(), ['127.0.0.1', '0.0.0.0']);
|
||||
}
|
||||
|
||||
{
|
||||
const servers = ['127.0.0.1', '192.168.1.1'];
|
||||
|
||||
servers[3] = '127.1.0.1';
|
||||
servers[4] = '127.1.0.1';
|
||||
servers[5] = '127.1.1.1';
|
||||
|
||||
Object.defineProperty(servers, 2, {
|
||||
enumerable: true,
|
||||
get: () => {
|
||||
servers.length = 3;
|
||||
return '0.0.0.0';
|
||||
}
|
||||
});
|
||||
|
||||
dns.setServers(servers);
|
||||
assert.deepStrictEqual(dns.getServers(), [
|
||||
'127.0.0.1',
|
||||
'192.168.1.1',
|
||||
'0.0.0.0',
|
||||
]);
|
||||
}
|
||||
|
||||
{
|
||||
// Various invalidities, all of which should throw a clean error.
|
||||
const invalidServers = [
|
||||
' ',
|
||||
'\n',
|
||||
'\0',
|
||||
'1'.repeat(3 * 4),
|
||||
// Check for REDOS issues.
|
||||
':'.repeat(100000),
|
||||
'['.repeat(100000),
|
||||
'['.repeat(100000) + ']'.repeat(100000) + 'a',
|
||||
];
|
||||
invalidServers.forEach((serv) => {
|
||||
assert.throws(
|
||||
() => {
|
||||
dns.setServers([serv]);
|
||||
},
|
||||
{
|
||||
name: 'TypeError',
|
||||
code: 'ERR_INVALID_IP_ADDRESS'
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const goog = [
|
||||
'8.8.8.8',
|
||||
'8.8.4.4',
|
||||
];
|
||||
dns.setServers(goog);
|
||||
assert.deepStrictEqual(dns.getServers(), goog);
|
||||
assert.throws(() => dns.setServers(['foobar']), {
|
||||
code: 'ERR_INVALID_IP_ADDRESS',
|
||||
name: 'TypeError',
|
||||
message: 'Invalid IP address: foobar'
|
||||
});
|
||||
assert.throws(() => dns.setServers(['127.0.0.1:va']), {
|
||||
code: 'ERR_INVALID_IP_ADDRESS',
|
||||
name: 'TypeError',
|
||||
message: 'Invalid IP address: 127.0.0.1:va'
|
||||
});
|
||||
assert.deepStrictEqual(dns.getServers(), goog);
|
||||
|
||||
const goog6 = [
|
||||
'2001:4860:4860::8888',
|
||||
'2001:4860:4860::8844',
|
||||
];
|
||||
dns.setServers(goog6);
|
||||
assert.deepStrictEqual(dns.getServers(), goog6);
|
||||
|
||||
goog6.push('4.4.4.4');
|
||||
dns.setServers(goog6);
|
||||
assert.deepStrictEqual(dns.getServers(), goog6);
|
||||
|
||||
const ports = [
|
||||
'4.4.4.4:53',
|
||||
'[2001:4860:4860::8888]:53',
|
||||
'103.238.225.181:666',
|
||||
'[fe80::483a:5aff:fee6:1f04]:666',
|
||||
'[fe80::483a:5aff:fee6:1f04]',
|
||||
];
|
||||
const portsExpected = [
|
||||
'4.4.4.4',
|
||||
'2001:4860:4860::8888',
|
||||
'103.238.225.181:666',
|
||||
'[fe80::483a:5aff:fee6:1f04]:666',
|
||||
'fe80::483a:5aff:fee6:1f04',
|
||||
];
|
||||
dns.setServers(ports);
|
||||
assert.deepStrictEqual(dns.getServers(), portsExpected);
|
||||
|
||||
dns.setServers([]);
|
||||
assert.deepStrictEqual(dns.getServers(), []);
|
||||
|
||||
{
|
||||
const errObj = {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError',
|
||||
message: /The "rrtype" argument must be of type string\. Received( an instance of Array|: \[\]|: "object")$/
|
||||
};
|
||||
assert.throws(() => {
|
||||
dns.resolve('example.com', [], common.mustNotCall());
|
||||
}, errObj);
|
||||
assert.throws(() => {
|
||||
dnsPromises.resolve('example.com', []);
|
||||
}, errObj);
|
||||
}
|
||||
{
|
||||
const errObj = {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError',
|
||||
message: /The "(host)?name" argument must be of type string\. Received:? undefined$/
|
||||
};
|
||||
assert.throws(() => {
|
||||
dnsPromises.resolve();
|
||||
}, errObj);
|
||||
}
|
||||
|
||||
// dns.lookup should accept only falsey and string values
|
||||
{
|
||||
const errorReg = {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError',
|
||||
message: /^The "hostname" argument must be of type string\. Received:? .*|^Expected hostname to be a string/
|
||||
};
|
||||
|
||||
assert.throws(() => dns.lookup({}, common.mustNotCall()), errorReg);
|
||||
|
||||
assert.throws(() => dns.lookup([], common.mustNotCall()), errorReg);
|
||||
|
||||
assert.throws(() => dns.lookup(true, common.mustNotCall()), errorReg);
|
||||
|
||||
assert.throws(() => dns.lookup(1, common.mustNotCall()), errorReg);
|
||||
|
||||
assert.throws(() => dns.lookup(common.mustNotCall(), common.mustNotCall()),
|
||||
errorReg);
|
||||
|
||||
assert.throws(() => dnsPromises.lookup({}), errorReg);
|
||||
assert.throws(() => dnsPromises.lookup([]), errorReg);
|
||||
assert.throws(() => dnsPromises.lookup(true), errorReg);
|
||||
assert.throws(() => dnsPromises.lookup(1), errorReg);
|
||||
assert.throws(() => dnsPromises.lookup(common.mustNotCall()), errorReg);
|
||||
}
|
||||
|
||||
// dns.lookup should accept falsey values
|
||||
{
|
||||
const checkCallback = (err, address, family) => {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(address, null);
|
||||
assert.strictEqual(family, 4);
|
||||
};
|
||||
|
||||
['', null, undefined, 0, NaN].forEach(async (value) => {
|
||||
const res = await dnsPromises.lookup(value);
|
||||
assert.deepStrictEqual(res, { address: null, family: 4 });
|
||||
dns.lookup(value, common.mustCall(checkCallback));
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
// Make sure that dns.lookup throws if hints does not represent a valid flag.
|
||||
// (dns.V4MAPPED | dns.ADDRCONFIG | dns.ALL) + 1 is invalid because:
|
||||
// - it's different from dns.V4MAPPED and dns.ADDRCONFIG and dns.ALL.
|
||||
// - it's different from any subset of them bitwise ored.
|
||||
// - it's different from 0.
|
||||
// - it's an odd number different than 1, and thus is invalid, because
|
||||
// flags are either === 1 or even.
|
||||
const hints = (dns.V4MAPPED | dns.ADDRCONFIG | dns.ALL) + 1;
|
||||
const err = {
|
||||
code: 'ERR_INVALID_ARG_VALUE',
|
||||
name: 'TypeError',
|
||||
message: /The (argument 'hints'|"hints" option) is invalid\. Received:? \d+/
|
||||
};
|
||||
|
||||
assert.throws(() => {
|
||||
dnsPromises.lookup('nodejs.org', { hints });
|
||||
}, err);
|
||||
assert.throws(() => {
|
||||
dns.lookup('nodejs.org', { hints }, common.mustNotCall());
|
||||
}, err);
|
||||
}
|
||||
|
||||
assert.throws(() => dns.lookup('nodejs.org'), {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError'
|
||||
});
|
||||
|
||||
assert.throws(() => dns.lookup('nodejs.org', 4), {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError'
|
||||
});
|
||||
|
||||
assert.throws(() => dns.lookup('', {
|
||||
family: 'nodejs.org',
|
||||
hints: dns.ADDRCONFIG | dns.V4MAPPED | dns.ALL,
|
||||
}), {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError'
|
||||
});
|
||||
|
||||
dns.lookup('', { family: 4, hints: 0 }, common.mustCall());
|
||||
|
||||
dns.lookup('', {
|
||||
family: 6,
|
||||
hints: dns.ADDRCONFIG
|
||||
}, common.mustCall());
|
||||
|
||||
dns.lookup('', { hints: dns.V4MAPPED }, common.mustCall());
|
||||
|
||||
dns.lookup('', {
|
||||
hints: dns.ADDRCONFIG | dns.V4MAPPED
|
||||
}, common.mustCall());
|
||||
|
||||
dns.lookup('', {
|
||||
hints: dns.ALL
|
||||
}, common.mustCall());
|
||||
|
||||
dns.lookup('', {
|
||||
hints: dns.V4MAPPED | dns.ALL
|
||||
}, common.mustCall());
|
||||
|
||||
dns.lookup('', {
|
||||
hints: dns.ADDRCONFIG | dns.V4MAPPED | dns.ALL
|
||||
}, common.mustCall());
|
||||
|
||||
dns.lookup('', {
|
||||
hints: dns.ADDRCONFIG | dns.V4MAPPED | dns.ALL,
|
||||
family: 'IPv4'
|
||||
}, common.mustCall());
|
||||
|
||||
dns.lookup('', {
|
||||
hints: dns.ADDRCONFIG | dns.V4MAPPED | dns.ALL,
|
||||
family: 'IPv6'
|
||||
}, common.mustCall());
|
||||
|
||||
(async function() {
|
||||
await dnsPromises.lookup('', { family: 4, hints: 0 });
|
||||
await dnsPromises.lookup('', { family: 6, hints: dns.ADDRCONFIG });
|
||||
await dnsPromises.lookup('', { hints: dns.V4MAPPED });
|
||||
await dnsPromises.lookup('', { hints: dns.ADDRCONFIG | dns.V4MAPPED });
|
||||
await dnsPromises.lookup('', { hints: dns.ALL });
|
||||
await dnsPromises.lookup('', { hints: dns.V4MAPPED | dns.ALL });
|
||||
await dnsPromises.lookup('', {
|
||||
hints: dns.ADDRCONFIG | dns.V4MAPPED | dns.ALL
|
||||
});
|
||||
await dnsPromises.lookup('', { order: 'verbatim' });
|
||||
})().then(common.mustCall());
|
||||
|
||||
{
|
||||
const err = {
|
||||
code: 'ERR_MISSING_ARGS',
|
||||
name: 'TypeError',
|
||||
message: 'The "address", "port", and "callback" arguments must be ' +
|
||||
'specified'
|
||||
};
|
||||
|
||||
assert.throws(() => dns.lookupService('0.0.0.0'), err);
|
||||
err.message = 'The "address" and "port" arguments must be specified';
|
||||
assert.throws(() => dnsPromises.lookupService('0.0.0.0'), err);
|
||||
}
|
||||
|
||||
{
|
||||
const invalidAddress = 'fasdfdsaf';
|
||||
const err = {
|
||||
code: 'ERR_INVALID_ARG_VALUE',
|
||||
name: 'TypeError',
|
||||
message: /The (argument 'address'|"address" argument) is invalid\. Received/
|
||||
};
|
||||
|
||||
assert.throws(() => {
|
||||
dnsPromises.lookupService(invalidAddress, 0);
|
||||
}, err);
|
||||
|
||||
assert.throws(() => {
|
||||
dns.lookupService(invalidAddress, 0, common.mustNotCall());
|
||||
}, err);
|
||||
}
|
||||
|
||||
const portErr = (port) => {
|
||||
const err = {
|
||||
code: 'ERR_SOCKET_BAD_PORT',
|
||||
name: 'RangeError'
|
||||
};
|
||||
|
||||
assert.throws(() => {
|
||||
dnsPromises.lookupService('0.0.0.0', port);
|
||||
}, err);
|
||||
|
||||
assert.throws(() => {
|
||||
dns.lookupService('0.0.0.0', port, common.mustNotCall());
|
||||
}, err);
|
||||
};
|
||||
[null, undefined, 65538, 'test', NaN, Infinity, Symbol(), 0n, true, false, '', () => {}, {}].forEach(portErr);
|
||||
|
||||
assert.throws(() => {
|
||||
dns.lookupService('0.0.0.0', 80, null);
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError'
|
||||
});
|
||||
|
||||
{
|
||||
dns.resolveMx('foo.onion', function(err) {
|
||||
assert.strictEqual(err.code, 'ENOTFOUND');
|
||||
assert.strictEqual(err.syscall, 'queryMx');
|
||||
assert.strictEqual(err.hostname, 'foo.onion');
|
||||
assert.strictEqual(err.message, 'queryMx ENOTFOUND foo.onion');
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
const cases = [
|
||||
// { method: 'resolveAny',
|
||||
// answers: [
|
||||
// { type: 'A', address: '1.2.3.4', ttl: 0 },
|
||||
// { type: 'AAAA', address: '::42', ttl: 0 },
|
||||
// { type: 'MX', priority: 42, exchange: 'foobar.com', ttl: 0 },
|
||||
// { type: 'NS', value: 'foobar.org', ttl: 0 },
|
||||
// { type: 'PTR', value: 'baz.org', ttl: 0 },
|
||||
// {
|
||||
// type: 'SOA',
|
||||
// nsname: 'ns1.example.com',
|
||||
// hostmaster: 'admin.example.com',
|
||||
// serial: 3210987654,
|
||||
// refresh: 900,
|
||||
// retry: 900,
|
||||
// expire: 1800,
|
||||
// minttl: 3333333333
|
||||
// },
|
||||
// ] },
|
||||
|
||||
{ method: 'resolve4',
|
||||
options: { ttl: true },
|
||||
answers: [ { type: 'A', address: '1.2.3.4', ttl: 0 } ] },
|
||||
|
||||
{ method: 'resolve6',
|
||||
options: { ttl: true },
|
||||
answers: [ { type: 'AAAA', address: '::42', ttl: 0 } ] },
|
||||
|
||||
{ method: 'resolveSoa',
|
||||
answers: [
|
||||
{
|
||||
type: 'SOA',
|
||||
nsname: 'ns1.example.com',
|
||||
hostmaster: 'admin.example.com',
|
||||
serial: 3210987654,
|
||||
refresh: 900,
|
||||
retry: 900,
|
||||
expire: 1800,
|
||||
minttl: 3333333333
|
||||
},
|
||||
] },
|
||||
];
|
||||
|
||||
const server = dgram.createSocket('udp4');
|
||||
|
||||
server.on('message', common.mustCallAtLeast((msg, { address, port }) => {
|
||||
const parsed = dnstools.parseDNSPacket(msg);
|
||||
const domain = parsed.questions[0].domain;
|
||||
assert.strictEqual(domain, 'example.org');
|
||||
|
||||
server.send(dnstools.writeDNSPacket({
|
||||
id: parsed.id,
|
||||
questions: parsed.questions,
|
||||
answers: cases[0].answers.map(
|
||||
(answer) => Object.assign({ domain }, answer)
|
||||
),
|
||||
}), port, address);
|
||||
}, cases.length * 2 - 1));
|
||||
|
||||
server.bind(0, common.mustCall(() => {
|
||||
const address = server.address();
|
||||
dns.setServers([`127.0.0.1:${address.port}`]);
|
||||
|
||||
function validateResults(res) {
|
||||
if (!Array.isArray(res))
|
||||
res = [res];
|
||||
|
||||
assert.deepStrictEqual(res.map(tweakEntry),
|
||||
cases[0].answers.map(tweakEntry));
|
||||
}
|
||||
|
||||
function tweakEntry(r) {
|
||||
const ret = { ...r };
|
||||
|
||||
const { method } = cases[0];
|
||||
|
||||
// TTL values are only provided for A and AAAA entries.
|
||||
if (!['A', 'AAAA'].includes(ret.type) && !/^resolve(4|6)?$/.test(method))
|
||||
delete ret.ttl;
|
||||
|
||||
if (method !== 'resolveAny')
|
||||
delete ret.type;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
(async function nextCase() {
|
||||
if (cases.length === 0)
|
||||
return server.close();
|
||||
|
||||
const { method, options } = cases[0];
|
||||
|
||||
validateResults(await dnsPromises[method]('example.org', options));
|
||||
|
||||
dns[method]('example.org', ...(options? [options] : []), common.mustSucceed((res) => {
|
||||
validateResults(res);
|
||||
cases.shift();
|
||||
nextCase();
|
||||
}));
|
||||
})().then(common.mustCall());
|
||||
|
||||
}));
|
||||
}
|
||||
Reference in New Issue
Block a user