@fedify/vocab-runtime 2.4.5-dev.2453 → 2.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/deno.json +5 -2
- package/dist/{docloader-BMHljyYb.d.cts → docloader-DOWjnNCz.d.cts} +4 -8
- package/dist/{docloader-BMHljyYb.d.ts → docloader-DOWjnNCz.d.ts} +4 -8
- package/dist/internal/jsonld-cache.cjs +1 -1
- package/dist/internal/jsonld-cache.d.cts +1 -1
- package/dist/internal/jsonld-cache.d.ts +1 -1
- package/dist/internal/jsonld-cache.js +1 -1
- package/dist/internal/portable-dereference.cjs +1 -1
- package/dist/internal/portable-dereference.d.cts +2 -2
- package/dist/internal/portable-dereference.d.ts +2 -2
- package/dist/internal/portable-dereference.js +1 -1
- package/dist/internal.cjs +6 -0
- package/dist/internal.d.cts +108 -0
- package/dist/internal.d.ts +108 -0
- package/dist/internal.js +3 -0
- package/dist/mod.cjs +104 -38
- package/dist/mod.d.cts +3 -336
- package/dist/mod.d.ts +4 -336
- package/dist/mod.js +104 -38
- package/dist/{portable-6Aj-7dZJ.d.cts → portable-CTnZWX7J.d.cts} +1 -1
- package/dist/{portable-nkTiqH0w.d.ts → portable-Cq-rhQgY.d.ts} +1 -1
- package/dist/public-fetch-Dvfvawei.cjs +527 -0
- package/dist/public-fetch-ziZ39L5I.js +510 -0
- package/dist/tests/{body-7TFr1l-z.cjs → body-BO79kuv1.cjs} +1 -1
- package/dist/tests/{body-BgPyhKpw.mjs → body-CUzCsDZ4.mjs} +1 -1
- package/dist/tests/body.test.cjs +1 -1
- package/dist/tests/body.test.mjs +1 -1
- package/dist/tests/decimal.test.cjs +3 -3
- package/dist/tests/decimal.test.mjs +3 -3
- package/dist/tests/{docloader-D89fiHaF.cjs → docloader-B79_YgeY.cjs} +111 -39
- package/dist/tests/{docloader-BlukyWHf.mjs → docloader-C5ZHGEfO.mjs} +106 -40
- package/dist/tests/docloader.test.cjs +531 -1293
- package/dist/tests/docloader.test.mjs +472 -1252
- package/dist/tests/esm-Ds-eHTfY.mjs +1229 -0
- package/dist/tests/esm-Q2tdh5f3.cjs +1215 -0
- package/dist/tests/internal/portable-dereference.test.cjs +3 -3
- package/dist/tests/internal/portable-dereference.test.mjs +3 -3
- package/dist/tests/{jsonld-cache-BEXiiM-V.cjs → jsonld-cache-DKIWKxEX.cjs} +1 -1
- package/dist/tests/{jsonld-cache-DFnWsLuZ.mjs → jsonld-cache-KH40z9_7.mjs} +1 -1
- package/dist/tests/jsonld-cache.test.cjs +2 -2
- package/dist/tests/jsonld-cache.test.mjs +2 -2
- package/dist/tests/node-BvS3AhZ2.cjs +89 -0
- package/dist/tests/node-Cg4pRuYy.mjs +84 -0
- package/dist/tests/pin-grant-CPrpk1l4.cjs +70 -0
- package/dist/tests/pin-grant-H5XhM1Xs.mjs +53 -0
- package/dist/tests/pin-grant.test.cjs +87 -0
- package/dist/tests/pin-grant.test.d.cts +1 -0
- package/dist/tests/pin-grant.test.d.mts +1 -0
- package/dist/tests/pin-grant.test.mjs +88 -0
- package/dist/tests/pinners/bun.test.cjs +166 -0
- package/dist/tests/pinners/bun.test.d.cts +1 -0
- package/dist/tests/pinners/bun.test.d.mts +1 -0
- package/dist/tests/pinners/bun.test.mjs +167 -0
- package/dist/tests/pinners/node.test.cjs +269 -0
- package/dist/tests/pinners/node.test.d.cts +1 -0
- package/dist/tests/pinners/node.test.d.mts +1 -0
- package/dist/tests/pinners/node.test.mjs +268 -0
- package/dist/tests/pinners/pinners.test.cjs +196 -0
- package/dist/tests/pinners/pinners.test.d.cts +1 -0
- package/dist/tests/pinners/pinners.test.d.mts +1 -0
- package/dist/tests/pinners/pinners.test.mjs +197 -0
- package/dist/tests/pinners/testdata/node-child.cjs +135 -0
- package/dist/tests/pinners/testdata/node-child.d.cts +1 -0
- package/dist/tests/pinners/testdata/node-child.d.mts +1 -0
- package/dist/tests/pinners/testdata/node-child.mjs +134 -0
- package/dist/tests/pinners-CJi9ZkYs.cjs +220 -0
- package/dist/tests/pinners-zSofbiy2.mjs +203 -0
- package/dist/tests/{portable-dereference-DmTYDy2p.mjs → portable-dereference-BHRE5Pkm.mjs} +2 -2
- package/dist/tests/{portable-dereference-qTLMqe2_.cjs → portable-dereference-mRHrC7PI.cjs} +2 -2
- package/dist/tests/{portable-media-4hfHamVH.mjs → portable-media-BpVpe1gj.mjs} +3 -3
- package/dist/tests/{portable-media-DH6pp6-g.cjs → portable-media-C3yY0W5E.cjs} +3 -3
- package/dist/tests/portable-media.test.cjs +1 -1
- package/dist/tests/portable-media.test.mjs +1 -1
- package/dist/tests/portable-workers.test.cjs +2 -2
- package/dist/tests/portable-workers.test.mjs +2 -2
- package/dist/tests/public-fetch-DNkPoks1.mjs +170 -0
- package/dist/tests/public-fetch-U822jbKB.cjs +186 -0
- package/dist/tests/public-fetch.test.cjs +1073 -0
- package/dist/tests/public-fetch.test.d.cts +1 -0
- package/dist/tests/public-fetch.test.d.mts +1 -0
- package/dist/tests/public-fetch.test.mjs +1074 -0
- package/dist/tests/{request--AMbrM1o.mjs → request-3AP-HBJ6.mjs} +1 -1
- package/dist/tests/{request-RH-Q21hI.cjs → request-BhopJTZd.cjs} +1 -1
- package/dist/tests/request.test.cjs +1 -1
- package/dist/tests/request.test.mjs +1 -1
- package/dist/tests/support-BmzI3dRJ.cjs +363 -0
- package/dist/tests/support-CiHDVJgh.mjs +272 -0
- package/dist/tests/{url-BNakuZ8k.cjs → url-Bdj-rTcC.cjs} +88 -12
- package/dist/tests/{url-DMxmp7ZG.mjs → url-COj5Q8mb.mjs} +65 -13
- package/dist/tests/url.test.cjs +4 -1
- package/dist/tests/url.test.mjs +4 -1
- package/dist/url-4EE56sNP.d.cts +352 -0
- package/dist/url-4EE56sNP.d.ts +352 -0
- package/dist/{url-DrGTR8yv.cjs → url-DIKZnaJv.cjs} +88 -12
- package/dist/{url-Dzyp-NsC.js → url-mWveR5GA.js} +65 -13
- package/package.json +14 -3
- package/src/docloader.test.ts +696 -48
- package/src/docloader.ts +186 -75
- package/src/internal.ts +13 -0
- package/src/pin-grant.test.ts +118 -0
- package/src/pin-grant.ts +99 -0
- package/src/pinners/bun.test.ts +278 -0
- package/src/pinners/bun.ts +223 -0
- package/src/pinners/mod.ts +59 -0
- package/src/pinners/node.test.ts +415 -0
- package/src/pinners/node.ts +144 -0
- package/src/pinners/pinners.test.ts +316 -0
- package/src/pinners/testdata/node-child.ts +147 -0
- package/src/pinners/testdata/proxy-child.ts +82 -0
- package/src/pinners/testdata/support.ts +343 -0
- package/src/pinners/testdata/tls-cert.pem +12 -0
- package/src/pinners/testdata/tls-child.ts +88 -0
- package/src/pinners/testdata/tls-key.pem +5 -0
- package/src/pinners/types.ts +48 -0
- package/src/public-fetch.test.ts +1286 -0
- package/src/public-fetch.ts +338 -0
- package/src/testdata/public-fetch-deno-worker.ts +74 -0
- package/src/url.test.ts +11 -0
- package/src/url.ts +113 -22
- package/tsdown.config.ts +7 -2
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
const require_pin_grant = require("../pin-grant-CPrpk1l4.cjs");
|
|
2
|
+
const require_pinners = require("../pinners-CJi9ZkYs.cjs");
|
|
3
|
+
const require_support = require("../support-BmzI3dRJ.cjs");
|
|
4
|
+
let node_assert = require("node:assert");
|
|
5
|
+
let _fedify_fixture = require("@fedify/fixture");
|
|
6
|
+
let node_fs = require("node:fs");
|
|
7
|
+
let node_https = require("node:https");
|
|
8
|
+
//#region src/pinners/bun.test.ts
|
|
9
|
+
(0, _fedify_fixture.test)("createBunPinner() falls back to the next address for GET and HEAD", { ignore: !require_support.isBun }, async () => {
|
|
10
|
+
if (!(await require_support.getLoopbackSupport()).ipv6) return;
|
|
11
|
+
const { server, port, requests } = await require_support.startRecordingServer();
|
|
12
|
+
try {
|
|
13
|
+
const pinner = require_pinners.createBunPinner(require_support.allowAll);
|
|
14
|
+
const url = new URL(`http://pinned-host.invalid:${port}/`);
|
|
15
|
+
const grant = require_pin_grant.issuePinGrant(url, [require_support.ipv6("::1"), require_support.ipv4("127.0.0.1")]);
|
|
16
|
+
(0, node_assert.deepStrictEqual)(await (await pinner.fetch(grant, new Request(url))).text(), "pinned");
|
|
17
|
+
(0, node_assert.deepStrictEqual)((await pinner.fetch(grant, new Request(url, { method: "HEAD" }))).status, 200);
|
|
18
|
+
(0, node_assert.deepStrictEqual)(requests.map(({ method, localAddress }) => [method, localAddress]), [["GET", "127.0.0.1"], ["HEAD", "127.0.0.1"]]);
|
|
19
|
+
} finally {
|
|
20
|
+
await require_support.closeServer(server);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
(0, _fedify_fixture.test)("createBunPinner() does not fall back for POST", { ignore: !require_support.isBun }, async () => {
|
|
24
|
+
if (!(await require_support.getLoopbackSupport()).ipv6) return;
|
|
25
|
+
const { server, port, requests } = await require_support.startRecordingServer();
|
|
26
|
+
try {
|
|
27
|
+
const pinner = require_pinners.createBunPinner(require_support.allowAll);
|
|
28
|
+
const url = new URL(`http://pinned-host.invalid:${port}/`);
|
|
29
|
+
const grant = require_pin_grant.issuePinGrant(url, [require_support.ipv6("::1"), require_support.ipv4("127.0.0.1")]);
|
|
30
|
+
await (0, node_assert.rejects)(() => pinner.fetch(grant, new Request(url, {
|
|
31
|
+
method: "POST",
|
|
32
|
+
body: "payload"
|
|
33
|
+
})));
|
|
34
|
+
(0, node_assert.deepStrictEqual)(requests, []);
|
|
35
|
+
} finally {
|
|
36
|
+
await require_support.closeServer(server);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
function runProxyChild(proxyEnv, httpPort, httpsPort) {
|
|
40
|
+
return require_support.runChild(require_support.resolveTestdata("proxy-child.ts", require("url").pathToFileURL(__filename).href), [String(httpPort), String(httpsPort)], proxyEnv);
|
|
41
|
+
}
|
|
42
|
+
function getBun() {
|
|
43
|
+
return globalThis.Bun;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Whether the current Bun refuses pinned requests to HTTPS servers on
|
|
47
|
+
* non-default ports, since it cannot verify their certificates against
|
|
48
|
+
* the original hostname.
|
|
49
|
+
*/
|
|
50
|
+
function refusesNonDefaultHttpsPorts() {
|
|
51
|
+
const bun = getBun();
|
|
52
|
+
return bun.semver.satisfies(bun.version, "<1.3.11");
|
|
53
|
+
}
|
|
54
|
+
(0, _fedify_fixture.test)("createBunPinner() bypasses environment proxies", { ignore: !require_support.isBun }, async (t) => {
|
|
55
|
+
const bun = getBun();
|
|
56
|
+
const honorsProxyFalse = bun.semver.satisfies(bun.version, ">=1.4.3");
|
|
57
|
+
const refusesHttps = refusesNonDefaultHttpsPorts();
|
|
58
|
+
for (const names of [[
|
|
59
|
+
"HTTP_PROXY",
|
|
60
|
+
"HTTPS_PROXY",
|
|
61
|
+
"ALL_PROXY"
|
|
62
|
+
], ["ALL_PROXY"]]) await t.step(names.join(", "), async () => {
|
|
63
|
+
const proxy = await require_support.startRecordingProxy();
|
|
64
|
+
const origin = await require_support.startRecordingServer();
|
|
65
|
+
const tls = await require_support.startCountingServer();
|
|
66
|
+
try {
|
|
67
|
+
const proxyUrl = `http://127.0.0.1:${proxy.port}`;
|
|
68
|
+
const output = await runProxyChild(Object.fromEntries(names.map((name) => [name, proxyUrl])), origin.port, tls.port);
|
|
69
|
+
const targets = JSON.stringify(proxy.targets);
|
|
70
|
+
(0, node_assert.deepStrictEqual)(output.version, bun.version);
|
|
71
|
+
(0, node_assert.ok)(proxy.targets.every((target) => !target.includes("pinned-host")), targets);
|
|
72
|
+
const proxyInEffect = output.control.body === "via-proxy";
|
|
73
|
+
if (names.length > 1 || honorsProxyFalse || proxyInEffect) {
|
|
74
|
+
(0, node_assert.deepStrictEqual)(output.control, {
|
|
75
|
+
status: 200,
|
|
76
|
+
body: "via-proxy"
|
|
77
|
+
});
|
|
78
|
+
(0, node_assert.ok)(proxy.targets.includes(`GET http://127.0.0.1:${origin.port}/control`), targets);
|
|
79
|
+
} else (0, node_assert.deepStrictEqual)(output.control, {
|
|
80
|
+
status: 200,
|
|
81
|
+
body: "pinned"
|
|
82
|
+
});
|
|
83
|
+
const pinnedTargets = proxy.targets.filter((target) => !target.endsWith("/control"));
|
|
84
|
+
if (honorsProxyFalse || !proxyInEffect) {
|
|
85
|
+
(0, node_assert.deepStrictEqual)(pinnedTargets, [], targets);
|
|
86
|
+
(0, node_assert.deepStrictEqual)(output.http, {
|
|
87
|
+
status: 200,
|
|
88
|
+
body: "pinned"
|
|
89
|
+
});
|
|
90
|
+
(0, node_assert.deepStrictEqual)(origin.requests.filter(({ url }) => url === "/pinned").map(({ host }) => host), [`pinned-host.invalid:${origin.port}`]);
|
|
91
|
+
(0, node_assert.deepStrictEqual)(tls.counter.connections, refusesHttps ? 0 : 1);
|
|
92
|
+
} else {
|
|
93
|
+
(0, node_assert.deepStrictEqual)(pinnedTargets, [`GET http://127.0.0.1:${origin.port}/pinned`, ...refusesHttps ? [] : [`CONNECT 127.0.0.1:${tls.port}`]]);
|
|
94
|
+
(0, node_assert.deepStrictEqual)(output.http, {
|
|
95
|
+
status: 200,
|
|
96
|
+
body: "via-proxy"
|
|
97
|
+
});
|
|
98
|
+
(0, node_assert.deepStrictEqual)(origin.requests, []);
|
|
99
|
+
(0, node_assert.deepStrictEqual)(tls.counter.connections, 0);
|
|
100
|
+
}
|
|
101
|
+
(0, node_assert.ok)(refusesHttps ? output.https.error?.startsWith("TypeError") : output.https.error != null, JSON.stringify(output.https));
|
|
102
|
+
(0, node_assert.deepStrictEqual)(output.warnings.length, honorsProxyFalse ? 0 : 1);
|
|
103
|
+
} finally {
|
|
104
|
+
await require_support.closeServer(proxy.server);
|
|
105
|
+
await require_support.closeServer(origin.server);
|
|
106
|
+
await require_support.closeServer(tls.server);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
(0, _fedify_fixture.test)("createBunPinner() verifies certificates on non-default ports", { ignore: !require_support.isBun }, async () => {
|
|
111
|
+
const bun = getBun();
|
|
112
|
+
const refuses = refusesNonDefaultHttpsPorts();
|
|
113
|
+
const certPath = require_support.resolveTestdata("tls-cert.pem", require("url").pathToFileURL(__filename).href);
|
|
114
|
+
const hosts = [];
|
|
115
|
+
const server = (0, node_https.createServer)({
|
|
116
|
+
cert: (0, node_fs.readFileSync)(certPath),
|
|
117
|
+
key: (0, node_fs.readFileSync)(require_support.resolveTestdata("tls-key.pem", require("url").pathToFileURL(__filename).href))
|
|
118
|
+
}, (req, res) => {
|
|
119
|
+
hosts.push(req.headers.host ?? "");
|
|
120
|
+
res.end(req.headers.host);
|
|
121
|
+
});
|
|
122
|
+
const port = await require_support.listen(server);
|
|
123
|
+
try {
|
|
124
|
+
const output = await require_support.runChild(require_support.resolveTestdata("tls-child.ts", require("url").pathToFileURL(__filename).href), [String(port)], { NODE_EXTRA_CA_CERTS: certPath });
|
|
125
|
+
(0, node_assert.deepStrictEqual)(output.version, bun.version);
|
|
126
|
+
const json = JSON.stringify(output.results);
|
|
127
|
+
if (refuses) {
|
|
128
|
+
(0, node_assert.ok)(output.results.every((result) => "error" in result && result.error.startsWith("TypeError")), json);
|
|
129
|
+
(0, node_assert.deepStrictEqual)(hosts, []);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
(0, node_assert.deepStrictEqual)(output.results, [
|
|
133
|
+
{
|
|
134
|
+
case: "pinned",
|
|
135
|
+
status: 200,
|
|
136
|
+
body: `pinned-host.invalid:${port}`
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
case: "unlisted",
|
|
140
|
+
error: "ERR_TLS_CERT_ALTNAME_INVALID"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
case: "unlisted-again",
|
|
144
|
+
error: "ERR_TLS_CERT_ALTNAME_INVALID"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
case: "alternate",
|
|
148
|
+
status: 200,
|
|
149
|
+
body: `alternate-host.invalid:${port}`
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
case: "signals",
|
|
153
|
+
status: 200,
|
|
154
|
+
body: `pinned-host.invalid:${port}`
|
|
155
|
+
}
|
|
156
|
+
], json);
|
|
157
|
+
(0, node_assert.deepStrictEqual)(hosts, [
|
|
158
|
+
`pinned-host.invalid:${port}`,
|
|
159
|
+
`alternate-host.invalid:${port}`,
|
|
160
|
+
`pinned-host.invalid:${port}`
|
|
161
|
+
]);
|
|
162
|
+
} finally {
|
|
163
|
+
await require_support.closeServer(server);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
//#endregion
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { t as issuePinGrant } from "../pin-grant-H5XhM1Xs.mjs";
|
|
2
|
+
import { r as createBunPinner } from "../pinners-zSofbiy2.mjs";
|
|
3
|
+
import { a as ipv6, d as resolveTestdata, f as runChild, h as startRecordingServer, i as ipv4, l as listen, m as startRecordingProxy, n as closeServer, p as startCountingServer, r as getLoopbackSupport, s as isBun, t as allowAll } from "../support-CiHDVJgh.mjs";
|
|
4
|
+
import { deepStrictEqual, ok, rejects } from "node:assert";
|
|
5
|
+
import { test } from "@fedify/fixture";
|
|
6
|
+
import { readFileSync } from "node:fs";
|
|
7
|
+
import { createServer } from "node:https";
|
|
8
|
+
//#region src/pinners/bun.test.ts
|
|
9
|
+
test("createBunPinner() falls back to the next address for GET and HEAD", { ignore: !isBun }, async () => {
|
|
10
|
+
if (!(await getLoopbackSupport()).ipv6) return;
|
|
11
|
+
const { server, port, requests } = await startRecordingServer();
|
|
12
|
+
try {
|
|
13
|
+
const pinner = createBunPinner(allowAll);
|
|
14
|
+
const url = new URL(`http://pinned-host.invalid:${port}/`);
|
|
15
|
+
const grant = issuePinGrant(url, [ipv6("::1"), ipv4("127.0.0.1")]);
|
|
16
|
+
deepStrictEqual(await (await pinner.fetch(grant, new Request(url))).text(), "pinned");
|
|
17
|
+
deepStrictEqual((await pinner.fetch(grant, new Request(url, { method: "HEAD" }))).status, 200);
|
|
18
|
+
deepStrictEqual(requests.map(({ method, localAddress }) => [method, localAddress]), [["GET", "127.0.0.1"], ["HEAD", "127.0.0.1"]]);
|
|
19
|
+
} finally {
|
|
20
|
+
await closeServer(server);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
test("createBunPinner() does not fall back for POST", { ignore: !isBun }, async () => {
|
|
24
|
+
if (!(await getLoopbackSupport()).ipv6) return;
|
|
25
|
+
const { server, port, requests } = await startRecordingServer();
|
|
26
|
+
try {
|
|
27
|
+
const pinner = createBunPinner(allowAll);
|
|
28
|
+
const url = new URL(`http://pinned-host.invalid:${port}/`);
|
|
29
|
+
const grant = issuePinGrant(url, [ipv6("::1"), ipv4("127.0.0.1")]);
|
|
30
|
+
await rejects(() => pinner.fetch(grant, new Request(url, {
|
|
31
|
+
method: "POST",
|
|
32
|
+
body: "payload"
|
|
33
|
+
})));
|
|
34
|
+
deepStrictEqual(requests, []);
|
|
35
|
+
} finally {
|
|
36
|
+
await closeServer(server);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
function runProxyChild(proxyEnv, httpPort, httpsPort) {
|
|
40
|
+
return runChild(resolveTestdata("proxy-child.ts", import.meta.url), [String(httpPort), String(httpsPort)], proxyEnv);
|
|
41
|
+
}
|
|
42
|
+
function getBun() {
|
|
43
|
+
return globalThis.Bun;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Whether the current Bun refuses pinned requests to HTTPS servers on
|
|
47
|
+
* non-default ports, since it cannot verify their certificates against
|
|
48
|
+
* the original hostname.
|
|
49
|
+
*/
|
|
50
|
+
function refusesNonDefaultHttpsPorts() {
|
|
51
|
+
const bun = getBun();
|
|
52
|
+
return bun.semver.satisfies(bun.version, "<1.3.11");
|
|
53
|
+
}
|
|
54
|
+
test("createBunPinner() bypasses environment proxies", { ignore: !isBun }, async (t) => {
|
|
55
|
+
const bun = getBun();
|
|
56
|
+
const honorsProxyFalse = bun.semver.satisfies(bun.version, ">=1.4.3");
|
|
57
|
+
const refusesHttps = refusesNonDefaultHttpsPorts();
|
|
58
|
+
for (const names of [[
|
|
59
|
+
"HTTP_PROXY",
|
|
60
|
+
"HTTPS_PROXY",
|
|
61
|
+
"ALL_PROXY"
|
|
62
|
+
], ["ALL_PROXY"]]) await t.step(names.join(", "), async () => {
|
|
63
|
+
const proxy = await startRecordingProxy();
|
|
64
|
+
const origin = await startRecordingServer();
|
|
65
|
+
const tls = await startCountingServer();
|
|
66
|
+
try {
|
|
67
|
+
const proxyUrl = `http://127.0.0.1:${proxy.port}`;
|
|
68
|
+
const output = await runProxyChild(Object.fromEntries(names.map((name) => [name, proxyUrl])), origin.port, tls.port);
|
|
69
|
+
const targets = JSON.stringify(proxy.targets);
|
|
70
|
+
deepStrictEqual(output.version, bun.version);
|
|
71
|
+
ok(proxy.targets.every((target) => !target.includes("pinned-host")), targets);
|
|
72
|
+
const proxyInEffect = output.control.body === "via-proxy";
|
|
73
|
+
if (names.length > 1 || honorsProxyFalse || proxyInEffect) {
|
|
74
|
+
deepStrictEqual(output.control, {
|
|
75
|
+
status: 200,
|
|
76
|
+
body: "via-proxy"
|
|
77
|
+
});
|
|
78
|
+
ok(proxy.targets.includes(`GET http://127.0.0.1:${origin.port}/control`), targets);
|
|
79
|
+
} else deepStrictEqual(output.control, {
|
|
80
|
+
status: 200,
|
|
81
|
+
body: "pinned"
|
|
82
|
+
});
|
|
83
|
+
const pinnedTargets = proxy.targets.filter((target) => !target.endsWith("/control"));
|
|
84
|
+
if (honorsProxyFalse || !proxyInEffect) {
|
|
85
|
+
deepStrictEqual(pinnedTargets, [], targets);
|
|
86
|
+
deepStrictEqual(output.http, {
|
|
87
|
+
status: 200,
|
|
88
|
+
body: "pinned"
|
|
89
|
+
});
|
|
90
|
+
deepStrictEqual(origin.requests.filter(({ url }) => url === "/pinned").map(({ host }) => host), [`pinned-host.invalid:${origin.port}`]);
|
|
91
|
+
deepStrictEqual(tls.counter.connections, refusesHttps ? 0 : 1);
|
|
92
|
+
} else {
|
|
93
|
+
deepStrictEqual(pinnedTargets, [`GET http://127.0.0.1:${origin.port}/pinned`, ...refusesHttps ? [] : [`CONNECT 127.0.0.1:${tls.port}`]]);
|
|
94
|
+
deepStrictEqual(output.http, {
|
|
95
|
+
status: 200,
|
|
96
|
+
body: "via-proxy"
|
|
97
|
+
});
|
|
98
|
+
deepStrictEqual(origin.requests, []);
|
|
99
|
+
deepStrictEqual(tls.counter.connections, 0);
|
|
100
|
+
}
|
|
101
|
+
ok(refusesHttps ? output.https.error?.startsWith("TypeError") : output.https.error != null, JSON.stringify(output.https));
|
|
102
|
+
deepStrictEqual(output.warnings.length, honorsProxyFalse ? 0 : 1);
|
|
103
|
+
} finally {
|
|
104
|
+
await closeServer(proxy.server);
|
|
105
|
+
await closeServer(origin.server);
|
|
106
|
+
await closeServer(tls.server);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
test("createBunPinner() verifies certificates on non-default ports", { ignore: !isBun }, async () => {
|
|
111
|
+
const bun = getBun();
|
|
112
|
+
const refuses = refusesNonDefaultHttpsPorts();
|
|
113
|
+
const certPath = resolveTestdata("tls-cert.pem", import.meta.url);
|
|
114
|
+
const hosts = [];
|
|
115
|
+
const server = createServer({
|
|
116
|
+
cert: readFileSync(certPath),
|
|
117
|
+
key: readFileSync(resolveTestdata("tls-key.pem", import.meta.url))
|
|
118
|
+
}, (req, res) => {
|
|
119
|
+
hosts.push(req.headers.host ?? "");
|
|
120
|
+
res.end(req.headers.host);
|
|
121
|
+
});
|
|
122
|
+
const port = await listen(server);
|
|
123
|
+
try {
|
|
124
|
+
const output = await runChild(resolveTestdata("tls-child.ts", import.meta.url), [String(port)], { NODE_EXTRA_CA_CERTS: certPath });
|
|
125
|
+
deepStrictEqual(output.version, bun.version);
|
|
126
|
+
const json = JSON.stringify(output.results);
|
|
127
|
+
if (refuses) {
|
|
128
|
+
ok(output.results.every((result) => "error" in result && result.error.startsWith("TypeError")), json);
|
|
129
|
+
deepStrictEqual(hosts, []);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
deepStrictEqual(output.results, [
|
|
133
|
+
{
|
|
134
|
+
case: "pinned",
|
|
135
|
+
status: 200,
|
|
136
|
+
body: `pinned-host.invalid:${port}`
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
case: "unlisted",
|
|
140
|
+
error: "ERR_TLS_CERT_ALTNAME_INVALID"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
case: "unlisted-again",
|
|
144
|
+
error: "ERR_TLS_CERT_ALTNAME_INVALID"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
case: "alternate",
|
|
148
|
+
status: 200,
|
|
149
|
+
body: `alternate-host.invalid:${port}`
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
case: "signals",
|
|
153
|
+
status: 200,
|
|
154
|
+
body: `pinned-host.invalid:${port}`
|
|
155
|
+
}
|
|
156
|
+
], json);
|
|
157
|
+
deepStrictEqual(hosts, [
|
|
158
|
+
`pinned-host.invalid:${port}`,
|
|
159
|
+
`alternate-host.invalid:${port}`,
|
|
160
|
+
`pinned-host.invalid:${port}`
|
|
161
|
+
]);
|
|
162
|
+
} finally {
|
|
163
|
+
await closeServer(server);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
//#endregion
|
|
167
|
+
export {};
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
const require_rolldown_runtime = require("../rolldown-runtime-emK7D4bc.cjs");
|
|
2
|
+
const require_pin_grant = require("../pin-grant-CPrpk1l4.cjs");
|
|
3
|
+
const require_url = require("../url-Bdj-rTcC.cjs");
|
|
4
|
+
const require_node = require("../node-BvS3AhZ2.cjs");
|
|
5
|
+
const require_public_fetch = require("../public-fetch-U822jbKB.cjs");
|
|
6
|
+
const require_support = require("../support-BmzI3dRJ.cjs");
|
|
7
|
+
let node_process = require("node:process");
|
|
8
|
+
node_process = require_rolldown_runtime.__toESM(node_process, 1);
|
|
9
|
+
let node_assert = require("node:assert");
|
|
10
|
+
let _fedify_fixture = require("@fedify/fixture");
|
|
11
|
+
let node_fs = require("node:fs");
|
|
12
|
+
let node_https = require("node:https");
|
|
13
|
+
//#region src/pinners/node.test.ts
|
|
14
|
+
/**
|
|
15
|
+
* Creates a Node.js pinner whose undici agent the test can also use
|
|
16
|
+
* directly, by injecting an `Agent` class that remembers its instance.
|
|
17
|
+
*/
|
|
18
|
+
async function createPinnerWithAgent(options) {
|
|
19
|
+
const undici = await import("undici");
|
|
20
|
+
const agents = [];
|
|
21
|
+
class Agent extends undici.Agent {
|
|
22
|
+
constructor(options) {
|
|
23
|
+
super(options);
|
|
24
|
+
agents.push(this);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const pinner = require_node.createNodePinner({
|
|
28
|
+
...options,
|
|
29
|
+
undici: { Agent }
|
|
30
|
+
});
|
|
31
|
+
(0, node_assert.strictEqual)(agents.length, 1);
|
|
32
|
+
return {
|
|
33
|
+
pinner,
|
|
34
|
+
agent: agents[0]
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Sends a request through the agent directly, without redeeming a grant.
|
|
39
|
+
*/
|
|
40
|
+
function fetchThrough(agent, url) {
|
|
41
|
+
return fetch(url, { dispatcher: agent });
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Whether the error is the failure of the agent's lookup to find a live
|
|
45
|
+
* grant for the hostname.
|
|
46
|
+
*/
|
|
47
|
+
function isNoValidatedAddress(error) {
|
|
48
|
+
return error instanceof TypeError && error.cause instanceof require_url.UrlError && error.cause.message.startsWith("No validated address to connect to:");
|
|
49
|
+
}
|
|
50
|
+
/** Responds without keeping the connection alive. */
|
|
51
|
+
function respondAndClose(_, res) {
|
|
52
|
+
res.setHeader("Connection", "close");
|
|
53
|
+
res.end("pinned");
|
|
54
|
+
}
|
|
55
|
+
(0, _fedify_fixture.test)("createNodePinner() checks IP literal hostnames before fetching", { ignore: !require_support.isNode }, async () => {
|
|
56
|
+
const { server, port, requests } = await require_support.startRecordingServer();
|
|
57
|
+
try {
|
|
58
|
+
const pinner = require_node.createNodePinner({
|
|
59
|
+
verifyAddress: require_url.assertPublicAddress,
|
|
60
|
+
undici: await import("undici")
|
|
61
|
+
});
|
|
62
|
+
const url = new URL(`http://127.0.0.1:${port}/`);
|
|
63
|
+
const grant = require_pin_grant.issuePinGrant(url, [require_support.ipv4("127.0.0.1")]);
|
|
64
|
+
await (0, node_assert.rejects)(() => pinner.fetch(grant, new Request(url)), require_url.UrlError);
|
|
65
|
+
(0, node_assert.deepStrictEqual)(requests, []);
|
|
66
|
+
} finally {
|
|
67
|
+
await require_support.closeServer(server);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
(0, _fedify_fixture.test)("createNodePinner() connects only for live grants", { ignore: !require_support.isNode }, async () => {
|
|
71
|
+
const { server, port, requests } = await require_support.startRecordingServer("127.0.0.1", respondAndClose);
|
|
72
|
+
try {
|
|
73
|
+
const { pinner, agent } = await createPinnerWithAgent(require_support.allowAll);
|
|
74
|
+
const url = new URL(`http://pinned-host.invalid:${port}/`);
|
|
75
|
+
await (0, node_assert.rejects)(() => fetchThrough(agent, url), isNoValidatedAddress);
|
|
76
|
+
const grant = require_pin_grant.issuePinGrant(url, [require_support.ipv4("127.0.0.1")]);
|
|
77
|
+
(0, node_assert.deepStrictEqual)(await (await pinner.fetch(grant, new Request(url))).text(), "pinned");
|
|
78
|
+
(0, node_assert.deepStrictEqual)(await (await fetchThrough(agent, url)).text(), "pinned");
|
|
79
|
+
await (0, node_assert.rejects)(() => fetchThrough(agent, `http://other-host.invalid:${port}/`), isNoValidatedAddress);
|
|
80
|
+
require_pin_grant.revokePinGrant(grant);
|
|
81
|
+
await (0, node_assert.rejects)(() => pinner.fetch(grant, new Request(url)), TypeError);
|
|
82
|
+
await (0, node_assert.rejects)(() => fetchThrough(agent, url), isNoValidatedAddress);
|
|
83
|
+
(0, node_assert.deepStrictEqual)(requests.length, 2);
|
|
84
|
+
} finally {
|
|
85
|
+
await require_support.closeServer(server);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
(0, _fedify_fixture.test)("createNodePinner() forgets released grants", { ignore: !require_support.isNode }, async () => {
|
|
89
|
+
const { server, port, requests } = await require_support.startRecordingServer("127.0.0.1", respondAndClose);
|
|
90
|
+
try {
|
|
91
|
+
const { pinner, agent } = await createPinnerWithAgent(require_support.allowAll);
|
|
92
|
+
const url = new URL(`http://pinned-host.invalid:${port}/`);
|
|
93
|
+
const grants = [require_pin_grant.issuePinGrant(url, [require_support.ipv4("127.0.0.1")]), require_pin_grant.issuePinGrant(url, [require_support.ipv4("127.0.0.1")])];
|
|
94
|
+
for (const grant of grants) (0, node_assert.deepStrictEqual)(await (await pinner.fetch(grant, new Request(url))).text(), "pinned");
|
|
95
|
+
await pinner.release(grants[0]);
|
|
96
|
+
(0, node_assert.deepStrictEqual)(await (await fetchThrough(agent, url)).text(), "pinned");
|
|
97
|
+
await pinner.release(grants[1]);
|
|
98
|
+
await (0, node_assert.rejects)(() => fetchThrough(agent, url), isNoValidatedAddress);
|
|
99
|
+
await pinner.release(grants[1]);
|
|
100
|
+
(0, node_assert.deepStrictEqual)(requests.length, 3);
|
|
101
|
+
} finally {
|
|
102
|
+
await require_support.closeServer(server);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
(0, _fedify_fixture.test)("createNodePinner() connects to the next address on failure", { ignore: !require_support.isNode }, async () => {
|
|
106
|
+
if (!(await require_support.getLoopbackSupport()).ipv6) return;
|
|
107
|
+
const { server, port, requests } = await require_support.startRecordingServer();
|
|
108
|
+
try {
|
|
109
|
+
const pinner = require_node.createNodePinner({
|
|
110
|
+
...require_support.allowAll,
|
|
111
|
+
undici: await import("undici")
|
|
112
|
+
});
|
|
113
|
+
const url = new URL(`http://pinned-host.invalid:${port}/`);
|
|
114
|
+
const grant = require_pin_grant.issuePinGrant(url, [require_support.ipv6("::1"), require_support.ipv4("127.0.0.1")]);
|
|
115
|
+
(0, node_assert.deepStrictEqual)(await (await pinner.fetch(grant, new Request(url))).text(), "pinned");
|
|
116
|
+
(0, node_assert.deepStrictEqual)(await (await pinner.fetch(grant, new Request(url, {
|
|
117
|
+
method: "POST",
|
|
118
|
+
body: "payload"
|
|
119
|
+
}))).text(), "pinned");
|
|
120
|
+
(0, node_assert.deepStrictEqual)(requests.map(({ method, localAddress }) => [method, localAddress]), [["GET", "127.0.0.1"], ["POST", "127.0.0.1"]]);
|
|
121
|
+
} finally {
|
|
122
|
+
await require_support.closeServer(server);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
/**
|
|
126
|
+
* Replaces the global `fetch()` while running the given function, as
|
|
127
|
+
* fetch-mock does, but returns the given responses as they are, while
|
|
128
|
+
* fetch-mock returns clones (tees) of them.
|
|
129
|
+
*/
|
|
130
|
+
async function withFetchStub(respond, fn) {
|
|
131
|
+
const original = globalThis.fetch;
|
|
132
|
+
globalThis.fetch = (_, init) => Promise.resolve(respond(init));
|
|
133
|
+
try {
|
|
134
|
+
return await fn();
|
|
135
|
+
} finally {
|
|
136
|
+
globalThis.fetch = original;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
(0, _fedify_fixture.test)("createNodePinner() forgets the grants of closed sessions", { ignore: !require_support.isNode }, async (t) => {
|
|
140
|
+
for (const cancelFails of [false, true]) await t.step(`cancelFails: ${cancelFails}`, async () => {
|
|
141
|
+
const checked = [];
|
|
142
|
+
const { pinner, agent } = await createPinnerWithAgent({ verifyAddress({ address }) {
|
|
143
|
+
checked.push(address);
|
|
144
|
+
throw new require_url.UrlError(`Refused for the test: ${address}`);
|
|
145
|
+
} });
|
|
146
|
+
const released = [];
|
|
147
|
+
const observed = {
|
|
148
|
+
supports: (url) => pinner.supports(url),
|
|
149
|
+
fetch: (grant, request, signal) => pinner.fetch(grant, request, signal),
|
|
150
|
+
async release(grant) {
|
|
151
|
+
released.push(grant);
|
|
152
|
+
await pinner.release(grant);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
const { openPublicFetch } = require_public_fetch.createPublicFetch({
|
|
156
|
+
pinner: () => Promise.resolve(observed),
|
|
157
|
+
lookup: () => Promise.reject(/* @__PURE__ */ new Error("Not used."))
|
|
158
|
+
});
|
|
159
|
+
const url = "http://pinned-host.invalid/";
|
|
160
|
+
const session = await openPublicFetch(url, { lookup: () => Promise.resolve([require_support.ipv4("8.8.8.8")]) });
|
|
161
|
+
const dispatchers = [];
|
|
162
|
+
let cancelled = 0;
|
|
163
|
+
const response = await withFetchStub((init) => {
|
|
164
|
+
dispatchers.push(init.dispatcher);
|
|
165
|
+
return new Response(new ReadableStream({ cancel() {
|
|
166
|
+
cancelled++;
|
|
167
|
+
if (cancelFails) throw new Error("Failed to cancel.");
|
|
168
|
+
} }));
|
|
169
|
+
}, () => session.fetch(url));
|
|
170
|
+
(0, node_assert.deepStrictEqual)(dispatchers, [agent]);
|
|
171
|
+
await (0, node_assert.rejects)(() => fetchThrough(agent, url), (error) => error instanceof TypeError && error.cause instanceof require_url.UrlError && error.cause.message === "Refused for the test: 8.8.8.8");
|
|
172
|
+
(0, node_assert.deepStrictEqual)(checked, ["8.8.8.8"]);
|
|
173
|
+
(0, node_assert.ok)(!response.bodyUsed);
|
|
174
|
+
await session.close();
|
|
175
|
+
(0, node_assert.deepStrictEqual)(cancelled, 1);
|
|
176
|
+
(0, node_assert.deepStrictEqual)(released.length, 1);
|
|
177
|
+
await (0, node_assert.rejects)(() => fetchThrough(agent, url), isNoValidatedAddress);
|
|
178
|
+
(0, node_assert.deepStrictEqual)(checked, ["8.8.8.8"]);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
(0, _fedify_fixture.test)("createNodePinner() bypasses environment proxies", { ignore: !require_support.isNode }, async (t) => {
|
|
182
|
+
const major = Number(node_process.default.versions.node.split(".")[0]);
|
|
183
|
+
const names = [
|
|
184
|
+
"HTTP_PROXY",
|
|
185
|
+
"HTTPS_PROXY",
|
|
186
|
+
"ALL_PROXY"
|
|
187
|
+
];
|
|
188
|
+
for (const useEnvProxy of [false, true]) await t.step(`NODE_USE_ENV_PROXY: ${useEnvProxy}`, async () => {
|
|
189
|
+
const proxy = await require_support.startRecordingProxy({ refuseTunnels: true });
|
|
190
|
+
const origin = await require_support.startRecordingServer();
|
|
191
|
+
const tls = await require_support.startCountingServer();
|
|
192
|
+
try {
|
|
193
|
+
const proxyUrl = `http://127.0.0.1:${proxy.port}`;
|
|
194
|
+
const output = await require_support.runChild(require_support.resolveCompiledTestdata("node-child.mjs", require("url").pathToFileURL(__filename).href), [
|
|
195
|
+
"proxy",
|
|
196
|
+
String(origin.port),
|
|
197
|
+
String(tls.port)
|
|
198
|
+
], {
|
|
199
|
+
...Object.fromEntries(names.map((name) => [name, proxyUrl])),
|
|
200
|
+
...useEnvProxy ? { NODE_USE_ENV_PROXY: "1" } : {}
|
|
201
|
+
});
|
|
202
|
+
const targets = JSON.stringify(proxy.targets);
|
|
203
|
+
(0, node_assert.deepStrictEqual)(output.version, node_process.default.version);
|
|
204
|
+
const controlTargets = [`GET http://127.0.0.1:${origin.port}/control`, `CONNECT 127.0.0.1:${origin.port}`];
|
|
205
|
+
if (useEnvProxy && major >= 24) (0, node_assert.ok)(proxy.targets.some((target) => controlTargets.includes(target)), targets);
|
|
206
|
+
(0, node_assert.deepStrictEqual)(proxy.targets.filter((target) => !controlTargets.includes(target)), [], targets);
|
|
207
|
+
(0, node_assert.deepStrictEqual)(output.http, {
|
|
208
|
+
status: 200,
|
|
209
|
+
body: "pinned"
|
|
210
|
+
});
|
|
211
|
+
(0, node_assert.deepStrictEqual)(origin.requests.filter(({ url }) => url === "/pinned").map(({ host }) => host), [`pinned-host.invalid:${origin.port}`]);
|
|
212
|
+
(0, node_assert.ok)(output.https.error != null, JSON.stringify(output.https));
|
|
213
|
+
(0, node_assert.deepStrictEqual)(tls.counter.connections, 1);
|
|
214
|
+
} finally {
|
|
215
|
+
await require_support.closeServer(proxy.server);
|
|
216
|
+
await require_support.closeServer(origin.server);
|
|
217
|
+
await require_support.closeServer(tls.server);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
(0, _fedify_fixture.test)("createNodePinner() verifies certificates against the hostname", { ignore: !require_support.isNode }, async () => {
|
|
222
|
+
const certPath = require_support.resolveTestdata("tls-cert.pem", require("url").pathToFileURL(__filename).href);
|
|
223
|
+
const hosts = [];
|
|
224
|
+
const server = (0, node_https.createServer)({
|
|
225
|
+
cert: (0, node_fs.readFileSync)(certPath),
|
|
226
|
+
key: (0, node_fs.readFileSync)(require_support.resolveTestdata("tls-key.pem", require("url").pathToFileURL(__filename).href))
|
|
227
|
+
}, (req, res) => {
|
|
228
|
+
hosts.push(req.headers.host ?? "");
|
|
229
|
+
res.end(req.headers.host);
|
|
230
|
+
});
|
|
231
|
+
const port = await require_support.listen(server);
|
|
232
|
+
try {
|
|
233
|
+
const output = await require_support.runChild(require_support.resolveCompiledTestdata("node-child.mjs", require("url").pathToFileURL(__filename).href), ["tls", String(port)], { NODE_EXTRA_CA_CERTS: certPath });
|
|
234
|
+
(0, node_assert.deepStrictEqual)(output.version, node_process.default.version);
|
|
235
|
+
(0, node_assert.deepStrictEqual)(output.results, [
|
|
236
|
+
{
|
|
237
|
+
case: "pinned",
|
|
238
|
+
status: 200,
|
|
239
|
+
body: `pinned-host.invalid:${port}`
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
case: "unlisted",
|
|
243
|
+
error: "ERR_TLS_CERT_ALTNAME_INVALID"
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
case: "unlisted-again",
|
|
247
|
+
error: "ERR_TLS_CERT_ALTNAME_INVALID"
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
case: "alternate",
|
|
251
|
+
status: 200,
|
|
252
|
+
body: `alternate-host.invalid:${port}`
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
case: "signals",
|
|
256
|
+
status: 200,
|
|
257
|
+
body: `pinned-host.invalid:${port}`
|
|
258
|
+
}
|
|
259
|
+
], JSON.stringify(output.results));
|
|
260
|
+
(0, node_assert.deepStrictEqual)(hosts, [
|
|
261
|
+
`pinned-host.invalid:${port}`,
|
|
262
|
+
`alternate-host.invalid:${port}`,
|
|
263
|
+
`pinned-host.invalid:${port}`
|
|
264
|
+
]);
|
|
265
|
+
} finally {
|
|
266
|
+
await require_support.closeServer(server);
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
//#endregion
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|