@c9up/ream 0.2.28 → 0.2.30
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/README.md +5 -6
- package/dist/Codemods.d.ts +24 -0
- package/dist/Codemods.d.ts.map +1 -1
- package/dist/Codemods.js +211 -1
- package/dist/Codemods.js.map +1 -1
- package/dist/HttpKernel.d.ts.map +1 -1
- package/dist/HttpKernel.js +17 -5
- package/dist/HttpKernel.js.map +1 -1
- package/dist/Ignitor.d.ts +15 -2
- package/dist/Ignitor.d.ts.map +1 -1
- package/dist/Ignitor.js +33 -23
- package/dist/Ignitor.js.map +1 -1
- package/dist/bodyparser/BodyParserMiddleware.d.ts +4 -4
- package/dist/bodyparser/BodyParserMiddleware.d.ts.map +1 -1
- package/dist/bodyparser/BodyParserMiddleware.js +41 -11
- package/dist/bodyparser/BodyParserMiddleware.js.map +1 -1
- package/dist/bodyparser/MultipartFile.d.ts +21 -15
- package/dist/bodyparser/MultipartFile.d.ts.map +1 -1
- package/dist/bodyparser/MultipartFile.js +40 -58
- package/dist/bodyparser/MultipartFile.js.map +1 -1
- package/dist/bodyparser/parseSize.d.ts +7 -4
- package/dist/bodyparser/parseSize.d.ts.map +1 -1
- package/dist/bodyparser/parseSize.js +12 -17
- package/dist/bodyparser/parseSize.js.map +1 -1
- package/dist/bodyparser/qsParse.d.ts +20 -1
- package/dist/bodyparser/qsParse.d.ts.map +1 -1
- package/dist/bodyparser/qsParse.js +78 -25
- package/dist/bodyparser/qsParse.js.map +1 -1
- package/dist/codemods/source.d.ts +57 -0
- package/dist/codemods/source.d.ts.map +1 -0
- package/dist/codemods/source.js +282 -0
- package/dist/codemods/source.js.map +1 -0
- package/dist/console/prompts.d.ts.map +1 -1
- package/dist/console/prompts.js +3 -1
- package/dist/console/prompts.js.map +1 -1
- package/dist/container/Container.d.ts.map +1 -1
- package/dist/container/Container.js +61 -71
- package/dist/container/Container.js.map +1 -1
- package/dist/events/Emitter.d.ts +12 -0
- package/dist/events/Emitter.d.ts.map +1 -1
- package/dist/events/Emitter.js +36 -9
- package/dist/events/Emitter.js.map +1 -1
- package/dist/events/helix/helpers.d.ts.map +1 -1
- package/dist/events/helix/helpers.js +19 -9
- package/dist/events/helix/helpers.js.map +1 -1
- package/dist/graphql/GraphQLEngine.d.ts +8 -0
- package/dist/graphql/GraphQLEngine.d.ts.map +1 -1
- package/dist/graphql/GraphQLEngine.js +79 -12
- package/dist/graphql/GraphQLEngine.js.map +1 -1
- package/dist/helpers/MessageBuilder.d.ts +4 -2
- package/dist/helpers/MessageBuilder.d.ts.map +1 -1
- package/dist/helpers/MessageBuilder.js +4 -2
- package/dist/helpers/MessageBuilder.js.map +1 -1
- package/dist/helpers/errors.d.ts +11 -0
- package/dist/helpers/errors.d.ts.map +1 -0
- package/dist/helpers/errors.js +17 -0
- package/dist/helpers/errors.js.map +1 -0
- package/dist/helpers/napi-loader.d.ts.map +1 -1
- package/dist/helpers/napi-loader.js +3 -2
- package/dist/helpers/napi-loader.js.map +1 -1
- package/dist/http/Exception.d.ts +14 -1
- package/dist/http/Exception.d.ts.map +1 -1
- package/dist/http/Exception.js +10 -2
- package/dist/http/Exception.js.map +1 -1
- package/dist/http/HttpContext.d.ts +31 -2
- package/dist/http/HttpContext.d.ts.map +1 -1
- package/dist/http/HttpContext.js +12 -5
- package/dist/http/HttpContext.js.map +1 -1
- package/dist/http/RedirectBuilder.d.ts +9 -3
- package/dist/http/RedirectBuilder.d.ts.map +1 -1
- package/dist/http/RedirectBuilder.js +43 -37
- package/dist/http/RedirectBuilder.js.map +1 -1
- package/dist/http/Request.d.ts +42 -17
- package/dist/http/Request.d.ts.map +1 -1
- package/dist/http/Request.js +80 -58
- package/dist/http/Request.js.map +1 -1
- package/dist/http/Response.d.ts +7 -4
- package/dist/http/Response.d.ts.map +1 -1
- package/dist/http/Response.js +14 -6
- package/dist/http/Response.js.map +1 -1
- package/dist/http/SseStream.js +6 -7
- package/dist/http/SseStream.js.map +1 -1
- package/dist/http/permissions.d.ts +25 -0
- package/dist/http/permissions.d.ts.map +1 -0
- package/dist/http/permissions.js +38 -0
- package/dist/http/permissions.js.map +1 -0
- package/dist/http-client/HttpClient.d.ts +111 -0
- package/dist/http-client/HttpClient.d.ts.map +1 -0
- package/dist/http-client/HttpClient.js +386 -0
- package/dist/http-client/HttpClient.js.map +1 -0
- package/dist/http-client/addresses.d.ts +14 -0
- package/dist/http-client/addresses.d.ts.map +1 -0
- package/dist/http-client/addresses.js +57 -0
- package/dist/http-client/addresses.js.map +1 -0
- package/dist/http-client/fake.d.ts +50 -0
- package/dist/http-client/fake.d.ts.map +1 -0
- package/dist/http-client/fake.js +95 -0
- package/dist/http-client/fake.js.map +1 -0
- package/dist/http-client/index.d.ts +7 -0
- package/dist/http-client/index.d.ts.map +1 -0
- package/dist/http-client/index.js +7 -0
- package/dist/http-client/index.js.map +1 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware/Pipeline.d.ts.map +1 -1
- package/dist/middleware/Pipeline.js +6 -3
- package/dist/middleware/Pipeline.js.map +1 -1
- package/dist/native/generated.d.ts +93 -36
- package/dist/native/generated.d.ts.map +1 -1
- package/dist/profiler/Profiler.d.ts.map +1 -1
- package/dist/profiler/Profiler.js +4 -1
- package/dist/profiler/Profiler.js.map +1 -1
- package/dist/profiler/client.generated.d.ts +5 -0
- package/dist/profiler/client.generated.d.ts.map +1 -0
- package/dist/profiler/client.generated.js +6 -0
- package/dist/profiler/client.generated.js.map +1 -0
- package/dist/profiler/collectors.d.ts +92 -13
- package/dist/profiler/collectors.d.ts.map +1 -1
- package/dist/profiler/collectors.js +106 -19
- package/dist/profiler/collectors.js.map +1 -1
- package/dist/profiler/endpoint.d.ts +2 -1
- package/dist/profiler/endpoint.d.ts.map +1 -1
- package/dist/profiler/endpoint.js +25 -1
- package/dist/profiler/endpoint.js.map +1 -1
- package/dist/profiler/index.d.ts +8 -4
- package/dist/profiler/index.d.ts.map +1 -1
- package/dist/profiler/index.js +11 -4
- package/dist/profiler/index.js.map +1 -1
- package/dist/profiler/middleware.d.ts.map +1 -1
- package/dist/profiler/middleware.js +76 -10
- package/dist/profiler/middleware.js.map +1 -1
- package/dist/profiler/preview.d.ts +17 -0
- package/dist/profiler/preview.d.ts.map +1 -0
- package/dist/profiler/preview.js +100 -0
- package/dist/profiler/preview.js.map +1 -0
- package/dist/profiler/toolbar.d.ts +15 -23
- package/dist/profiler/toolbar.d.ts.map +1 -1
- package/dist/profiler/toolbar.js +25 -91
- package/dist/profiler/toolbar.js.map +1 -1
- package/dist/profiler/types.d.ts +6 -1
- package/dist/profiler/types.d.ts.map +1 -1
- package/dist/router/Router.d.ts +6 -0
- package/dist/router/Router.d.ts.map +1 -1
- package/dist/router/Router.js +115 -12
- package/dist/router/Router.js.map +1 -1
- package/dist/rpc/RpcProvider.d.ts +6 -0
- package/dist/rpc/RpcProvider.d.ts.map +1 -1
- package/dist/rpc/RpcProvider.js +4 -1
- package/dist/rpc/RpcProvider.js.map +1 -1
- package/dist/rpc/RpcRouter.d.ts +27 -14
- package/dist/rpc/RpcRouter.d.ts.map +1 -1
- package/dist/rpc/RpcRouter.js +97 -40
- package/dist/rpc/RpcRouter.js.map +1 -1
- package/dist/scheduler/Scheduler.js +1 -1
- package/dist/scheduler/Scheduler.js.map +1 -1
- package/dist/scheduler/locks/RedisLockBackend.d.ts.map +1 -1
- package/dist/scheduler/locks/RedisLockBackend.js +13 -2
- package/dist/scheduler/locks/RedisLockBackend.js.map +1 -1
- package/dist/security/CookieSigner.d.ts.map +1 -1
- package/dist/security/CookieSigner.js +32 -8
- package/dist/security/CookieSigner.js.map +1 -1
- package/dist/security/SignedUrl.d.ts.map +1 -1
- package/dist/security/SignedUrl.js +16 -19
- package/dist/security/SignedUrl.js.map +1 -1
- package/dist/server/Server.d.ts +44 -12
- package/dist/server/Server.d.ts.map +1 -1
- package/dist/server/Server.js +31 -10
- package/dist/server/Server.js.map +1 -1
- package/dist/server/nativeGrpc.d.ts +27 -0
- package/dist/server/nativeGrpc.d.ts.map +1 -0
- package/dist/server/nativeGrpc.js +47 -0
- package/dist/server/nativeGrpc.js.map +1 -0
- package/dist/server/nativeLimits.d.ts +57 -0
- package/dist/server/nativeLimits.d.ts.map +1 -0
- package/dist/server/nativeLimits.js +75 -0
- package/dist/server/nativeLimits.js.map +1 -0
- package/dist/session/Session.d.ts +12 -0
- package/dist/session/Session.d.ts.map +1 -1
- package/dist/session/Session.js +13 -4
- package/dist/session/Session.js.map +1 -1
- package/dist/session/SessionMiddleware.d.ts.map +1 -1
- package/dist/session/SessionMiddleware.js +28 -9
- package/dist/session/SessionMiddleware.js.map +1 -1
- package/dist/session/config.d.ts +5 -0
- package/dist/session/config.d.ts.map +1 -1
- package/dist/session/config.js +8 -0
- package/dist/session/config.js.map +1 -1
- package/dist/session/drivers/MemoryDriver.d.ts.map +1 -1
- package/dist/session/drivers/MemoryDriver.js +26 -7
- package/dist/session/drivers/MemoryDriver.js.map +1 -1
- package/dist/session/errors.d.ts +17 -0
- package/dist/session/errors.d.ts.map +1 -1
- package/dist/session/errors.js +21 -0
- package/dist/session/errors.js.map +1 -1
- package/dist/session/templateTags.d.ts +14 -0
- package/dist/session/templateTags.d.ts.map +1 -1
- package/dist/session/templateTags.js +45 -17
- package/dist/session/templateTags.js.map +1 -1
- package/dist/storage/StaticMiddleware.d.ts.map +1 -1
- package/dist/storage/StaticMiddleware.js +49 -27
- package/dist/storage/StaticMiddleware.js.map +1 -1
- package/dist/testing/ApiResponse.d.ts.map +1 -1
- package/dist/testing/ApiResponse.js +7 -1
- package/dist/testing/ApiResponse.js.map +1 -1
- package/dist/testing/TestClient.d.ts.map +1 -1
- package/dist/testing/TestClient.js +16 -4
- package/dist/testing/TestClient.js.map +1 -1
- package/dist/utils/Macroable.d.ts +1 -1
- package/dist/utils/Macroable.js +2 -2
- package/dist/utils/Macroable.js.map +1 -1
- package/events.darwin-arm64.node +0 -0
- package/events.darwin-x64.node +0 -0
- package/events.linux-arm64-gnu.node +0 -0
- package/events.linux-x64-gnu.node +0 -0
- package/events.win32-x64-msvc.node +0 -0
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +11 -3
- package/scheduler.darwin-arm64.node +0 -0
- package/scheduler.darwin-x64.node +0 -0
- package/scheduler.linux-arm64-gnu.node +0 -0
- package/scheduler.linux-x64-gnu.node +0 -0
- package/scheduler.win32-x64-msvc.node +0 -0
- package/src/Codemods.ts +314 -3
- package/src/HttpKernel.ts +18 -7
- package/src/Ignitor.ts +58 -26
- package/src/bodyparser/BodyParserMiddleware.ts +45 -16
- package/src/bodyparser/MultipartFile.ts +46 -67
- package/src/bodyparser/parseSize.ts +17 -17
- package/src/bodyparser/qsParse.ts +96 -26
- package/src/codemods/source.ts +303 -0
- package/src/console/prompts.ts +3 -1
- package/src/container/Container.ts +97 -81
- package/src/events/Emitter.ts +37 -10
- package/src/events/helix/helpers.ts +24 -19
- package/src/graphql/GraphQLEngine.ts +91 -14
- package/src/helpers/MessageBuilder.ts +4 -2
- package/src/helpers/errors.ts +16 -0
- package/src/helpers/napi-loader.ts +3 -2
- package/src/http/Exception.ts +17 -2
- package/src/http/HttpContext.ts +34 -5
- package/src/http/RedirectBuilder.ts +51 -37
- package/src/http/Request.ts +102 -58
- package/src/http/Response.ts +15 -7
- package/src/http/SseStream.ts +6 -7
- package/src/http/permissions.ts +47 -0
- package/src/http-client/HttpClient.ts +505 -0
- package/src/http-client/addresses.ts +58 -0
- package/src/http-client/fake.ts +141 -0
- package/src/http-client/index.ts +21 -0
- package/src/index.ts +6 -1
- package/src/middleware/Pipeline.ts +7 -3
- package/src/native/generated.ts +106 -48
- package/src/profiler/Profiler.ts +4 -1
- package/src/profiler/client/toolbar.css +595 -0
- package/src/profiler/client/toolbar.js +1299 -0
- package/src/profiler/client.generated.ts +7 -0
- package/src/profiler/collectors.ts +156 -19
- package/src/profiler/endpoint.ts +27 -1
- package/src/profiler/index.ts +17 -3
- package/src/profiler/middleware.ts +74 -9
- package/src/profiler/preview.ts +104 -0
- package/src/profiler/toolbar.ts +28 -91
- package/src/profiler/types.ts +6 -1
- package/src/router/Router.ts +136 -13
- package/src/rpc/RpcProvider.ts +10 -1
- package/src/rpc/RpcRouter.ts +129 -45
- package/src/scheduler/Scheduler.ts +1 -1
- package/src/scheduler/locks/RedisLockBackend.ts +12 -4
- package/src/security/CookieSigner.ts +30 -8
- package/src/security/SignedUrl.ts +18 -17
- package/src/server/Server.ts +60 -12
- package/src/server/nativeGrpc.ts +59 -0
- package/src/server/nativeLimits.ts +111 -0
- package/src/session/Session.ts +29 -4
- package/src/session/SessionMiddleware.ts +30 -10
- package/src/session/config.ts +7 -0
- package/src/session/drivers/MemoryDriver.ts +26 -7
- package/src/session/errors.ts +31 -0
- package/src/session/templateTags.ts +57 -0
- package/src/storage/StaticMiddleware.ts +46 -27
- package/src/testing/ApiResponse.ts +7 -1
- package/src/testing/TestClient.ts +14 -5
- package/src/utils/Macroable.ts +2 -2
- package/scripts/build-napi-types.mjs +0 -69
- package/scripts/copy-napi.mjs +0 -121
- package/scripts/generate-mime.mjs +0 -119
- package/scripts/generate-napi-types.mjs +0 -187
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outbound HTTP for server code that calls a URL it does not fully control —
|
|
3
|
+
* a customer's domain, a webhook target, a CMS the user pointed the app at.
|
|
4
|
+
*
|
|
5
|
+
* `fetch` connects wherever DNS says. A domain that resolves to `10.0.0.5`,
|
|
6
|
+
* `127.0.0.1` or `169.254.169.254` makes the server read its own network on
|
|
7
|
+
* the attacker's behalf (SSRF). Checking the address before the call is not
|
|
8
|
+
* enough: a DNS answer can change between the check and the connection
|
|
9
|
+
* (rebinding). So the check runs AT CONNECT TIME, inside the `lookup` of the
|
|
10
|
+
* client's own agents — the address that is checked is the address the
|
|
11
|
+
* socket connects to. The agents belong to this client alone, so a pooled
|
|
12
|
+
* socket opened by other code is never reused.
|
|
13
|
+
*
|
|
14
|
+
* Also bounded: one deadline for the whole exchange (redirects included), a
|
|
15
|
+
* maximum response size, and a few redirects, to the same host by default.
|
|
16
|
+
* Every failure is an {@link HttpClientError} with a `reason`.
|
|
17
|
+
*
|
|
18
|
+
* No AdonisJS counterpart: the framework ships no outbound client.
|
|
19
|
+
*/
|
|
20
|
+
import { lookup as dnsLookup } from 'node:dns';
|
|
21
|
+
import http from 'node:http';
|
|
22
|
+
import https from 'node:https';
|
|
23
|
+
import { isIP } from 'node:net';
|
|
24
|
+
import { ReamError } from '../errors/ReamError.js';
|
|
25
|
+
import { isPublicAddress } from './addresses.js';
|
|
26
|
+
const CODES = {
|
|
27
|
+
invalidUrl: 'E_HTTP_CLIENT_INVALID_URL',
|
|
28
|
+
privateAddress: 'E_HTTP_CLIENT_PRIVATE_ADDRESS',
|
|
29
|
+
unreachable: 'E_HTTP_CLIENT_UNREACHABLE',
|
|
30
|
+
timedOut: 'E_HTTP_CLIENT_TIMED_OUT',
|
|
31
|
+
tooLarge: 'E_HTTP_CLIENT_TOO_LARGE',
|
|
32
|
+
redirect: 'E_HTTP_CLIENT_REDIRECT_REFUSED',
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* A failed outbound request. A `ReamError`, not an HTTP `Exception`: left
|
|
36
|
+
* uncaught in a handler it answers a generic 500 and its message, which names
|
|
37
|
+
* hosts and addresses, never reaches the client.
|
|
38
|
+
*/
|
|
39
|
+
export class HttpClientError extends ReamError {
|
|
40
|
+
reason;
|
|
41
|
+
/** The target, without its query string (which may carry credentials). */
|
|
42
|
+
url;
|
|
43
|
+
constructor(reason, url, message, cause) {
|
|
44
|
+
const shown = describeUrl(url);
|
|
45
|
+
super(CODES[reason], message, { context: { url: shown } });
|
|
46
|
+
this.name = 'HttpClientError';
|
|
47
|
+
this.reason = reason;
|
|
48
|
+
this.url = shown;
|
|
49
|
+
if (cause !== undefined)
|
|
50
|
+
this.cause = cause;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** A complete response, its body read and bounded. */
|
|
54
|
+
export class HttpResponse {
|
|
55
|
+
status;
|
|
56
|
+
headers;
|
|
57
|
+
/** The URL that answered, after redirects. */
|
|
58
|
+
url;
|
|
59
|
+
body;
|
|
60
|
+
constructor(status, headers, url, body) {
|
|
61
|
+
this.status = status;
|
|
62
|
+
this.headers = headers;
|
|
63
|
+
this.url = url;
|
|
64
|
+
this.body = body;
|
|
65
|
+
}
|
|
66
|
+
/** A 2xx status. */
|
|
67
|
+
get ok() {
|
|
68
|
+
return this.status >= 200 && this.status < 300;
|
|
69
|
+
}
|
|
70
|
+
/** A header's first value; names are case-insensitive. */
|
|
71
|
+
header(name) {
|
|
72
|
+
const value = this.headers[name.toLowerCase()];
|
|
73
|
+
return Array.isArray(value) ? value[0] : value;
|
|
74
|
+
}
|
|
75
|
+
text() {
|
|
76
|
+
return this.body.toString('utf8');
|
|
77
|
+
}
|
|
78
|
+
/** The body parsed as JSON — `unknown` until the caller validates it. */
|
|
79
|
+
json() {
|
|
80
|
+
return JSON.parse(this.text());
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const DEFAULT_TIMEOUT = 10_000;
|
|
84
|
+
const DEFAULT_MAX_RESPONSE_BYTES = 5 * 1024 * 1024;
|
|
85
|
+
const DEFAULT_MAX_REDIRECTS = 3;
|
|
86
|
+
const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
|
|
87
|
+
/** Headers that must not follow a redirect to another host. */
|
|
88
|
+
const CREDENTIAL_HEADERS = ['authorization', 'cookie', 'proxy-authorization'];
|
|
89
|
+
export class HttpClient {
|
|
90
|
+
#timeout;
|
|
91
|
+
#maxResponseBytes;
|
|
92
|
+
#maxRedirects;
|
|
93
|
+
#crossHostRedirects;
|
|
94
|
+
#headers;
|
|
95
|
+
#allowHosts;
|
|
96
|
+
#guardedAgents;
|
|
97
|
+
#exemptAgents;
|
|
98
|
+
constructor(options = {}) {
|
|
99
|
+
this.#timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
100
|
+
this.#maxResponseBytes = options.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;
|
|
101
|
+
this.#maxRedirects = options.maxRedirects ?? DEFAULT_MAX_REDIRECTS;
|
|
102
|
+
this.#crossHostRedirects = options.crossHostRedirects ?? false;
|
|
103
|
+
this.#headers = {
|
|
104
|
+
'user-agent': options.userAgent ?? '@c9up/ream',
|
|
105
|
+
...lowercaseKeys(options.headers ?? {}),
|
|
106
|
+
};
|
|
107
|
+
this.#allowHosts = new Set((options.allowHosts ?? []).map((entry) => entry.toLowerCase()));
|
|
108
|
+
}
|
|
109
|
+
get(url, options = {}) {
|
|
110
|
+
return this.request(url, { ...options, method: 'GET' });
|
|
111
|
+
}
|
|
112
|
+
post(url, options = {}) {
|
|
113
|
+
return this.request(url, { ...options, method: 'POST' });
|
|
114
|
+
}
|
|
115
|
+
put(url, options = {}) {
|
|
116
|
+
return this.request(url, { ...options, method: 'PUT' });
|
|
117
|
+
}
|
|
118
|
+
patch(url, options = {}) {
|
|
119
|
+
return this.request(url, { ...options, method: 'PATCH' });
|
|
120
|
+
}
|
|
121
|
+
delete(url, options = {}) {
|
|
122
|
+
return this.request(url, { ...options, method: 'DELETE' });
|
|
123
|
+
}
|
|
124
|
+
/** Send a request, following redirects within the client's rules. */
|
|
125
|
+
async request(input, options = {}) {
|
|
126
|
+
let url = parseTarget(input);
|
|
127
|
+
let method = (options.method ?? 'GET').toUpperCase();
|
|
128
|
+
let headers = {
|
|
129
|
+
...this.#headers,
|
|
130
|
+
...lowercaseKeys(options.headers ?? {}),
|
|
131
|
+
};
|
|
132
|
+
let body = encodeBody(options, headers);
|
|
133
|
+
const maxResponseBytes = options.maxResponseBytes ?? this.#maxResponseBytes;
|
|
134
|
+
const timeout = options.timeout ?? this.#timeout;
|
|
135
|
+
const deadline = new AbortController();
|
|
136
|
+
const timer = setTimeout(() => {
|
|
137
|
+
deadline.abort(new HttpClientError('timedOut', url, `No complete response within ${timeout} ms.`));
|
|
138
|
+
}, timeout);
|
|
139
|
+
const signal = options.signal
|
|
140
|
+
? AbortSignal.any([deadline.signal, options.signal])
|
|
141
|
+
: deadline.signal;
|
|
142
|
+
try {
|
|
143
|
+
for (let redirects = 0;; redirects++) {
|
|
144
|
+
this.#assertAddressLiteralAllowed(url);
|
|
145
|
+
if (body !== undefined)
|
|
146
|
+
headers['content-length'] = String(body.length);
|
|
147
|
+
const response = await this.send({ url, method, headers, body, signal, maxResponseBytes });
|
|
148
|
+
if (response.body.length > maxResponseBytes) {
|
|
149
|
+
throw new HttpClientError('tooLarge', url, `Response exceeds ${maxResponseBytes} bytes.`);
|
|
150
|
+
}
|
|
151
|
+
const location = response.header('location');
|
|
152
|
+
if (!REDIRECT_STATUSES.has(response.status) || location === undefined)
|
|
153
|
+
return response;
|
|
154
|
+
if (this.#maxRedirects === 0)
|
|
155
|
+
return response;
|
|
156
|
+
if (redirects >= this.#maxRedirects) {
|
|
157
|
+
throw new HttpClientError('redirect', url, `More than ${this.#maxRedirects} redirects.`);
|
|
158
|
+
}
|
|
159
|
+
const next = parseTarget(location, url);
|
|
160
|
+
if (url.protocol === 'https:' && next.protocol === 'http:') {
|
|
161
|
+
throw new HttpClientError('redirect', next, 'Refused a redirect from https to http.');
|
|
162
|
+
}
|
|
163
|
+
if (next.host !== url.host) {
|
|
164
|
+
if (!this.#crossHostRedirects) {
|
|
165
|
+
throw new HttpClientError('redirect', next, `Refused a redirect from ${url.host} to another host (${next.host}).`);
|
|
166
|
+
}
|
|
167
|
+
headers = withoutKeys(headers, CREDENTIAL_HEADERS);
|
|
168
|
+
}
|
|
169
|
+
// What browsers and fetch do: a 303 always becomes a GET, and a
|
|
170
|
+
// 301/302 does when it answered a POST. 307/308 keep method and body.
|
|
171
|
+
const becomesGet = response.status === 303 ||
|
|
172
|
+
((response.status === 301 || response.status === 302) && method === 'POST');
|
|
173
|
+
if (becomesGet && method !== 'HEAD') {
|
|
174
|
+
method = 'GET';
|
|
175
|
+
body = undefined;
|
|
176
|
+
headers = withoutKeys(headers, ['content-type', 'content-length']);
|
|
177
|
+
}
|
|
178
|
+
url = next;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
// An abort from the deadline surfaces as whatever the transport threw;
|
|
183
|
+
// the deadline's own error says what happened.
|
|
184
|
+
if (deadline.signal.aborted && deadline.signal.reason instanceof HttpClientError) {
|
|
185
|
+
throw deadline.signal.reason;
|
|
186
|
+
}
|
|
187
|
+
throw error;
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
clearTimeout(timer);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Put one request on the wire and read its response, bounded. Redirects are
|
|
195
|
+
* not followed here. Overridden by the test fake.
|
|
196
|
+
*/
|
|
197
|
+
send(request) {
|
|
198
|
+
const { url, method, headers, body, signal, maxResponseBytes } = request;
|
|
199
|
+
const agents = this.#agentsFor(url);
|
|
200
|
+
const transport = url.protocol === 'https:' ? https : http;
|
|
201
|
+
const agent = url.protocol === 'https:' ? agents.https : agents.http;
|
|
202
|
+
return new Promise((resolve, reject) => {
|
|
203
|
+
let settled = false;
|
|
204
|
+
const fail = (error) => {
|
|
205
|
+
if (settled)
|
|
206
|
+
return;
|
|
207
|
+
settled = true;
|
|
208
|
+
signal.removeEventListener('abort', onAbort);
|
|
209
|
+
req.destroy();
|
|
210
|
+
reject(toClientError(error, url, signal));
|
|
211
|
+
};
|
|
212
|
+
const onAbort = () => fail(signal.reason);
|
|
213
|
+
const req = transport.request(url, { method, headers, agent }, (res) => {
|
|
214
|
+
const declared = Number(res.headers['content-length']);
|
|
215
|
+
if (Number.isFinite(declared) && declared > maxResponseBytes) {
|
|
216
|
+
fail(new HttpClientError('tooLarge', url, `Response exceeds ${maxResponseBytes} bytes.`));
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const chunks = [];
|
|
220
|
+
let received = 0;
|
|
221
|
+
res.on('data', (chunk) => {
|
|
222
|
+
received += chunk.length;
|
|
223
|
+
if (received > maxResponseBytes) {
|
|
224
|
+
fail(new HttpClientError('tooLarge', url, `Response exceeds ${maxResponseBytes} bytes.`));
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
chunks.push(chunk);
|
|
228
|
+
});
|
|
229
|
+
res.on('error', fail);
|
|
230
|
+
res.on('close', () => {
|
|
231
|
+
if (!res.complete)
|
|
232
|
+
fail(new Error('The response was cut short.'));
|
|
233
|
+
});
|
|
234
|
+
res.on('end', () => {
|
|
235
|
+
if (settled)
|
|
236
|
+
return;
|
|
237
|
+
settled = true;
|
|
238
|
+
signal.removeEventListener('abort', onAbort);
|
|
239
|
+
resolve(new HttpResponse(res.statusCode ?? 0, copyHeaders(res.headers), url.href, Buffer.concat(chunks)));
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
req.on('error', fail);
|
|
243
|
+
if (signal.aborted) {
|
|
244
|
+
fail(signal.reason);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
248
|
+
req.end(body);
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
/** Release the pooled connections. The client stays usable; new ones are opened on demand. */
|
|
252
|
+
close() {
|
|
253
|
+
for (const agents of [this.#guardedAgents, this.#exemptAgents]) {
|
|
254
|
+
agents?.http.destroy();
|
|
255
|
+
agents?.https.destroy();
|
|
256
|
+
}
|
|
257
|
+
this.#guardedAgents = undefined;
|
|
258
|
+
this.#exemptAgents = undefined;
|
|
259
|
+
}
|
|
260
|
+
#isExempt(url) {
|
|
261
|
+
if (this.#allowHosts.size === 0)
|
|
262
|
+
return false;
|
|
263
|
+
const port = url.port || (url.protocol === 'https:' ? '443' : '80');
|
|
264
|
+
const hostname = url.hostname.toLowerCase();
|
|
265
|
+
return this.#allowHosts.has(hostname) || this.#allowHosts.has(`${hostname}:${port}`);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* An address written in the URL is never looked up, so the connect-time
|
|
269
|
+
* check does not see it: it is judged here, on every hop.
|
|
270
|
+
*/
|
|
271
|
+
#assertAddressLiteralAllowed(url) {
|
|
272
|
+
const address = url.hostname.replace(/^\[|\]$/g, '');
|
|
273
|
+
if (isIP(address) === 0 || this.#isExempt(url))
|
|
274
|
+
return;
|
|
275
|
+
if (!isPublicAddress(address)) {
|
|
276
|
+
throw new HttpClientError('privateAddress', url, `${address} is not a public address.`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
#agentsFor(url) {
|
|
280
|
+
if (this.#isExempt(url)) {
|
|
281
|
+
this.#exemptAgents ??= {
|
|
282
|
+
http: new http.Agent({ keepAlive: true }),
|
|
283
|
+
https: new https.Agent({ keepAlive: true }),
|
|
284
|
+
};
|
|
285
|
+
return this.#exemptAgents;
|
|
286
|
+
}
|
|
287
|
+
this.#guardedAgents ??= {
|
|
288
|
+
http: new http.Agent({ keepAlive: true, lookup: publicOnlyLookup }),
|
|
289
|
+
https: new https.Agent({ keepAlive: true, lookup: publicOnlyLookup }),
|
|
290
|
+
};
|
|
291
|
+
return this.#guardedAgents;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* `dns.lookup`, refusing the connection when ANY address the name resolves
|
|
296
|
+
* to is not public — a name that answers both a public and a private address
|
|
297
|
+
* is a rebinding setup, not a choice to make on the attacker's behalf.
|
|
298
|
+
*/
|
|
299
|
+
const publicOnlyLookup = (hostname, options, callback) => {
|
|
300
|
+
dnsLookup(hostname, { ...options, all: true }, (error, addresses) => {
|
|
301
|
+
if (error) {
|
|
302
|
+
callback(error, '');
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const refused = addresses.find((entry) => !isPublicAddress(entry.address));
|
|
306
|
+
const [first] = addresses;
|
|
307
|
+
if (refused !== undefined || first === undefined) {
|
|
308
|
+
callback(new HttpClientError('privateAddress', `http://${hostname}`, `${hostname} resolves to ${refused?.address ?? 'no address'}, which is not a public address.`), '');
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (options.all)
|
|
312
|
+
callback(null, addresses);
|
|
313
|
+
else
|
|
314
|
+
callback(null, first.address, first.family);
|
|
315
|
+
});
|
|
316
|
+
};
|
|
317
|
+
function parseTarget(input, base) {
|
|
318
|
+
let url;
|
|
319
|
+
try {
|
|
320
|
+
url = new URL(input, base);
|
|
321
|
+
}
|
|
322
|
+
catch (error) {
|
|
323
|
+
throw new HttpClientError('invalidUrl', String(input), 'Not a valid URL.', error);
|
|
324
|
+
}
|
|
325
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
|
326
|
+
throw new HttpClientError('invalidUrl', url, `Only http and https URLs are allowed, not ${url.protocol}`);
|
|
327
|
+
}
|
|
328
|
+
if (url.username !== '' || url.password !== '') {
|
|
329
|
+
throw new HttpClientError('invalidUrl', url, 'Credentials in the URL are refused; send a header.');
|
|
330
|
+
}
|
|
331
|
+
return url;
|
|
332
|
+
}
|
|
333
|
+
function encodeBody(options, headers) {
|
|
334
|
+
if (options.json !== undefined) {
|
|
335
|
+
headers['content-type'] ??= 'application/json';
|
|
336
|
+
return Buffer.from(JSON.stringify(options.json), 'utf8');
|
|
337
|
+
}
|
|
338
|
+
if (options.body === undefined)
|
|
339
|
+
return undefined;
|
|
340
|
+
return typeof options.body === 'string'
|
|
341
|
+
? Buffer.from(options.body, 'utf8')
|
|
342
|
+
: Buffer.from(options.body);
|
|
343
|
+
}
|
|
344
|
+
function toClientError(error, url, signal) {
|
|
345
|
+
if (error instanceof HttpClientError)
|
|
346
|
+
return error;
|
|
347
|
+
// An abort the caller asked for is theirs to recognise: hand back its reason.
|
|
348
|
+
if (signal.aborted && error === signal.reason)
|
|
349
|
+
return error;
|
|
350
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
351
|
+
return new HttpClientError('unreachable', url, `Could not reach ${url.host}: ${message}`, error);
|
|
352
|
+
}
|
|
353
|
+
function lowercaseKeys(headers) {
|
|
354
|
+
const out = {};
|
|
355
|
+
for (const [name, value] of Object.entries(headers))
|
|
356
|
+
out[name.toLowerCase()] = value;
|
|
357
|
+
return out;
|
|
358
|
+
}
|
|
359
|
+
function withoutKeys(headers, names) {
|
|
360
|
+
const out = {};
|
|
361
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
362
|
+
if (!names.includes(name))
|
|
363
|
+
out[name] = value;
|
|
364
|
+
}
|
|
365
|
+
return out;
|
|
366
|
+
}
|
|
367
|
+
function copyHeaders(headers) {
|
|
368
|
+
const out = {};
|
|
369
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
370
|
+
if (value !== undefined)
|
|
371
|
+
out[name] = value;
|
|
372
|
+
}
|
|
373
|
+
return out;
|
|
374
|
+
}
|
|
375
|
+
function describeUrl(url) {
|
|
376
|
+
if (typeof url === 'string') {
|
|
377
|
+
try {
|
|
378
|
+
return describeUrl(new URL(url));
|
|
379
|
+
}
|
|
380
|
+
catch {
|
|
381
|
+
return url.split('?')[0] ?? url;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return `${url.origin}${url.pathname}`;
|
|
385
|
+
}
|
|
386
|
+
//# sourceMappingURL=HttpClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpClient.js","sourceRoot":"","sources":["../../src/http-client/HttpClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,UAAU,CAAA;AAC9C,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,KAAK,MAAM,YAAY,CAAA;AAC9B,OAAO,EAAE,IAAI,EAAuB,MAAM,UAAU,CAAA;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAWhD,MAAM,KAAK,GAAsC;IAC/C,UAAU,EAAE,2BAA2B;IACvC,cAAc,EAAE,+BAA+B;IAC/C,WAAW,EAAE,2BAA2B;IACxC,QAAQ,EAAE,yBAAyB;IACnC,QAAQ,EAAE,yBAAyB;IACnC,QAAQ,EAAE,gCAAgC;CAC3C,CAAA;AAED;;;;GAIG;AACH,MAAM,OAAO,eAAgB,SAAQ,SAAS;IACnC,MAAM,CAAmB;IAClC,0EAA0E;IACjE,GAAG,CAAQ;IAEpB,YAAY,MAAyB,EAAE,GAAiB,EAAE,OAAe,EAAE,KAAe;QACxF,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAA;QAC9B,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,CAAA;QAC1D,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAA;QAC7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,GAAG,GAAG,KAAK,CAAA;QAChB,IAAI,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;IAC7C,CAAC;CACF;AAgDD,sDAAsD;AACtD,MAAM,OAAO,YAAY;IACd,MAAM,CAAQ;IACd,OAAO,CAA6C;IAC7D,8CAA8C;IACrC,GAAG,CAAQ;IACX,IAAI,CAAQ;IAErB,YACE,MAAc,EACd,OAA0C,EAC1C,GAAW,EACX,IAAY;QAEZ,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAClB,CAAC;IAED,oBAAoB;IACpB,IAAI,EAAE;QACJ,OAAO,IAAI,CAAC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG,CAAA;IAChD,CAAC;IAED,0DAA0D;IAC1D,MAAM,CAAC,IAAY;QACjB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;QAC9C,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;IAChD,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IACnC,CAAC;IAED,yEAAyE;IACzE,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;IAChC,CAAC;CACF;AAED,MAAM,eAAe,GAAG,MAAM,CAAA;AAC9B,MAAM,0BAA0B,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAA;AAClD,MAAM,qBAAqB,GAAG,CAAC,CAAA;AAC/B,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;AAC5D,+DAA+D;AAC/D,MAAM,kBAAkB,GAAG,CAAC,eAAe,EAAE,QAAQ,EAAE,qBAAqB,CAAC,CAAA;AAE7E,MAAM,OAAO,UAAU;IACZ,QAAQ,CAAQ;IAChB,iBAAiB,CAAQ;IACzB,aAAa,CAAQ;IACrB,mBAAmB,CAAS;IAC5B,QAAQ,CAAwB;IAChC,WAAW,CAAqB;IACzC,cAAc,CAA2C;IACzD,aAAa,CAA2C;IAExD,YAAY,UAA6B,EAAE;QACzC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,IAAI,eAAe,CAAA;QAClD,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,IAAI,0BAA0B,CAAA;QAC/E,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,YAAY,IAAI,qBAAqB,CAAA;QAClE,IAAI,CAAC,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,IAAI,KAAK,CAAA;QAC9D,IAAI,CAAC,QAAQ,GAAG;YACd,YAAY,EAAE,OAAO,CAAC,SAAS,IAAI,YAAY;YAC/C,GAAG,aAAa,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;SACxC,CAAA;QACD,IAAI,CAAC,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAA;IAC5F,CAAC;IAED,GAAG,CAAC,GAAiB,EAAE,UAA8C,EAAE;QACrE,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;IACzD,CAAC;IAED,IAAI,CAAC,GAAiB,EAAE,UAA8C,EAAE;QACtE,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;IAC1D,CAAC;IAED,GAAG,CAAC,GAAiB,EAAE,UAA8C,EAAE;QACrE,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;IACzD,CAAC;IAED,KAAK,CACH,GAAiB,EACjB,UAA8C,EAAE;QAEhD,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;IAC3D,CAAC;IAED,MAAM,CACJ,GAAiB,EACjB,UAA8C,EAAE;QAEhD,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA;IAC5D,CAAC;IAED,qEAAqE;IACrE,KAAK,CAAC,OAAO,CAAC,KAAmB,EAAE,UAA8B,EAAE;QACjE,IAAI,GAAG,GAAG,WAAW,CAAC,KAAK,CAAC,CAAA;QAC5B,IAAI,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,CAAA;QACpD,IAAI,OAAO,GAA2B;YACpC,GAAG,IAAI,CAAC,QAAQ;YAChB,GAAG,aAAa,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;SACxC,CAAA;QACD,IAAI,IAAI,GAAG,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QACvC,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,IAAI,CAAC,iBAAiB,CAAA;QAE3E,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAA;QAChD,MAAM,QAAQ,GAAG,IAAI,eAAe,EAAE,CAAA;QACtC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,QAAQ,CAAC,KAAK,CACZ,IAAI,eAAe,CAAC,UAAU,EAAE,GAAG,EAAE,+BAA+B,OAAO,MAAM,CAAC,CACnF,CAAA;QACH,CAAC,EAAE,OAAO,CAAC,CAAA;QACX,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM;YAC3B,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YACpD,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAA;QAEnB,IAAI,CAAC;YACH,KAAK,IAAI,SAAS,GAAG,CAAC,GAAI,SAAS,EAAE,EAAE,CAAC;gBACtC,IAAI,CAAC,4BAA4B,CAAC,GAAG,CAAC,CAAA;gBACtC,IAAI,IAAI,KAAK,SAAS;oBAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;gBACvE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAA;gBAC1F,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;oBAC5C,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,GAAG,EAAE,oBAAoB,gBAAgB,SAAS,CAAC,CAAA;gBAC3F,CAAC;gBAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;gBAC5C,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,QAAQ,KAAK,SAAS;oBAAE,OAAO,QAAQ,CAAA;gBACtF,IAAI,IAAI,CAAC,aAAa,KAAK,CAAC;oBAAE,OAAO,QAAQ,CAAA;gBAC7C,IAAI,SAAS,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;oBACpC,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,GAAG,EAAE,aAAa,IAAI,CAAC,aAAa,aAAa,CAAC,CAAA;gBAC1F,CAAC;gBAED,MAAM,IAAI,GAAG,WAAW,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;gBACvC,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,IAAI,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;oBAC3D,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,IAAI,EAAE,wCAAwC,CAAC,CAAA;gBACvF,CAAC;gBACD,IAAI,IAAI,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,EAAE,CAAC;oBAC3B,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC;wBAC9B,MAAM,IAAI,eAAe,CACvB,UAAU,EACV,IAAI,EACJ,2BAA2B,GAAG,CAAC,IAAI,qBAAqB,IAAI,CAAC,IAAI,IAAI,CACtE,CAAA;oBACH,CAAC;oBACD,OAAO,GAAG,WAAW,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAA;gBACpD,CAAC;gBACD,gEAAgE;gBAChE,sEAAsE;gBACtE,MAAM,UAAU,GACd,QAAQ,CAAC,MAAM,KAAK,GAAG;oBACvB,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,CAAC,IAAI,MAAM,KAAK,MAAM,CAAC,CAAA;gBAC7E,IAAI,UAAU,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;oBACpC,MAAM,GAAG,KAAK,CAAA;oBACd,IAAI,GAAG,SAAS,CAAA;oBAChB,OAAO,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC,CAAA;gBACpE,CAAC;gBACD,GAAG,GAAG,IAAI,CAAA;YACZ,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,uEAAuE;YACvE,+CAA+C;YAC/C,IAAI,QAAQ,CAAC,MAAM,CAAC,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,YAAY,eAAe,EAAE,CAAC;gBACjF,MAAM,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAA;YAC9B,CAAC;YACD,MAAM,KAAK,CAAA;QACb,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,KAAK,CAAC,CAAA;QACrB,CAAC;IACH,CAAC;IAED;;;OAGG;IACO,IAAI,CAAC,OAAwB;QACrC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAA;QACxE,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;QACnC,MAAM,SAAS,GAAG,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA;QAC1D,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAA;QAEpE,OAAO,IAAI,OAAO,CAAe,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnD,IAAI,OAAO,GAAG,KAAK,CAAA;YACnB,MAAM,IAAI,GAAG,CAAC,KAAc,EAAQ,EAAE;gBACpC,IAAI,OAAO;oBAAE,OAAM;gBACnB,OAAO,GAAG,IAAI,CAAA;gBACd,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;gBAC5C,GAAG,CAAC,OAAO,EAAE,CAAA;gBACb,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAA;YAC3C,CAAC,CAAA;YACD,MAAM,OAAO,GAAG,GAAS,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YAE/C,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE;gBACrE,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAA;gBACtD,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,gBAAgB,EAAE,CAAC;oBAC7D,IAAI,CAAC,IAAI,eAAe,CAAC,UAAU,EAAE,GAAG,EAAE,oBAAoB,gBAAgB,SAAS,CAAC,CAAC,CAAA;oBACzF,OAAM;gBACR,CAAC;gBACD,MAAM,MAAM,GAAa,EAAE,CAAA;gBAC3B,IAAI,QAAQ,GAAG,CAAC,CAAA;gBAChB,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;oBAC/B,QAAQ,IAAI,KAAK,CAAC,MAAM,CAAA;oBACxB,IAAI,QAAQ,GAAG,gBAAgB,EAAE,CAAC;wBAChC,IAAI,CACF,IAAI,eAAe,CAAC,UAAU,EAAE,GAAG,EAAE,oBAAoB,gBAAgB,SAAS,CAAC,CACpF,CAAA;wBACD,OAAM;oBACR,CAAC;oBACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;gBACpB,CAAC,CAAC,CAAA;gBACF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;gBACrB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;oBACnB,IAAI,CAAC,GAAG,CAAC,QAAQ;wBAAE,IAAI,CAAC,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAA;gBACnE,CAAC,CAAC,CAAA;gBACF,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;oBACjB,IAAI,OAAO;wBAAE,OAAM;oBACnB,OAAO,GAAG,IAAI,CAAA;oBACd,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;oBAC5C,OAAO,CACL,IAAI,YAAY,CACd,GAAG,CAAC,UAAU,IAAI,CAAC,EACnB,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,EACxB,GAAG,CAAC,IAAI,EACR,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CACtB,CACF,CAAA;gBACH,CAAC,CAAC,CAAA;YACJ,CAAC,CAAC,CAAA;YACF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;YACrB,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;gBACnB,OAAM;YACR,CAAC;YACD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;YACzD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACf,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,8FAA8F;IAC9F,KAAK;QACH,KAAK,MAAM,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;YAC/D,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,CAAA;YACtB,MAAM,EAAE,KAAK,CAAC,OAAO,EAAE,CAAA;QACzB,CAAC;QACD,IAAI,CAAC,cAAc,GAAG,SAAS,CAAA;QAC/B,IAAI,CAAC,aAAa,GAAG,SAAS,CAAA;IAChC,CAAC;IAED,SAAS,CAAC,GAAQ;QAChB,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,KAAK,CAAA;QAC7C,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QACnE,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAA;QAC3C,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,QAAQ,IAAI,IAAI,EAAE,CAAC,CAAA;IACtF,CAAC;IAED;;;OAGG;IACH,4BAA4B,CAAC,GAAQ;QACnC,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;QACpD,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;YAAE,OAAM;QACtD,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,eAAe,CAAC,gBAAgB,EAAE,GAAG,EAAE,GAAG,OAAO,2BAA2B,CAAC,CAAA;QACzF,CAAC;IACH,CAAC;IAED,UAAU,CAAC,GAAQ;QACjB,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,aAAa,KAAK;gBACrB,IAAI,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;gBACzC,KAAK,EAAE,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;aAC5C,CAAA;YACD,OAAO,IAAI,CAAC,aAAa,CAAA;QAC3B,CAAC;QACD,IAAI,CAAC,cAAc,KAAK;YACtB,IAAI,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;YACnE,KAAK,EAAE,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;SACtE,CAAA;QACD,OAAO,IAAI,CAAC,cAAc,CAAA;IAC5B,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,gBAAgB,GAAmB,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE;IACvE,SAAS,CAAC,QAAQ,EAAE,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE;QAClE,IAAI,KAAK,EAAE,CAAC;YACV,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;YACnB,OAAM;QACR,CAAC;QACD,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAA;QAC1E,MAAM,CAAC,KAAK,CAAC,GAAG,SAAS,CAAA;QACzB,IAAI,OAAO,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACjD,QAAQ,CACN,IAAI,eAAe,CACjB,gBAAgB,EAChB,UAAU,QAAQ,EAAE,EACpB,GAAG,QAAQ,gBAAgB,OAAO,EAAE,OAAO,IAAI,YAAY,kCAAkC,CAC9F,EACD,EAAE,CACH,CAAA;YACD,OAAM;QACR,CAAC;QACD,IAAI,OAAO,CAAC,GAAG;YAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;;YACrC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;IAClD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,SAAS,WAAW,CAAC,KAAmB,EAAE,IAAU;IAClD,IAAI,GAAQ,CAAA;IACZ,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;IAC5B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,eAAe,CAAC,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,kBAAkB,EAAE,KAAK,CAAC,CAAA;IACnF,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1D,MAAM,IAAI,eAAe,CACvB,YAAY,EACZ,GAAG,EACH,6CAA6C,GAAG,CAAC,QAAQ,EAAE,CAC5D,CAAA;IACH,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,EAAE,CAAC;QAC/C,MAAM,IAAI,eAAe,CACvB,YAAY,EACZ,GAAG,EACH,oDAAoD,CACrD,CAAA;IACH,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,SAAS,UAAU,CACjB,OAA2B,EAC3B,OAA+B;IAE/B,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,CAAC,cAAc,CAAC,KAAK,kBAAkB,CAAA;QAC9C,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAA;IAC1D,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IAChD,OAAO,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ;QACrC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;QACnC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;AAC/B,CAAC;AAED,SAAS,aAAa,CAAC,KAAc,EAAE,GAAQ,EAAE,MAAmB;IAClE,IAAI,KAAK,YAAY,eAAe;QAAE,OAAO,KAAK,CAAA;IAClD,8EAA8E;IAC9E,IAAI,MAAM,CAAC,OAAO,IAAI,KAAK,KAAK,MAAM,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IAC3D,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACtE,OAAO,IAAI,eAAe,CAAC,aAAa,EAAE,GAAG,EAAE,mBAAmB,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,EAAE,KAAK,CAAC,CAAA;AAClG,CAAC;AAED,SAAS,aAAa,CAAC,OAA+B;IACpD,MAAM,GAAG,GAA2B,EAAE,CAAA;IACtC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,GAAG,KAAK,CAAA;IACpF,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,SAAS,WAAW,CAClB,OAA+B,EAC/B,KAAwB;IAExB,MAAM,GAAG,GAA2B,EAAE,CAAA;IACtC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACpD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAA;IAC9C,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,SAAS,WAAW,CAAC,OAAiC;IACpD,MAAM,GAAG,GAAsC,EAAE,CAAA;IACjD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACpD,IAAI,KAAK,KAAK,SAAS;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAA;IAC5C,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,SAAS,WAAW,CAAC,GAAiB;IACpC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,OAAO,WAAW,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAA;QACjC,CAAC;IACH,CAAC;IACD,OAAO,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAA;AACvC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which addresses an outbound request may connect to.
|
|
3
|
+
*
|
|
4
|
+
* Everything that is not a globally routable unicast address is refused:
|
|
5
|
+
* loopback, private and shared ranges, link-local (the cloud metadata
|
|
6
|
+
* endpoint `169.254.169.254` lives there), documentation and benchmarking
|
|
7
|
+
* ranges, multicast, and the IPv6 transition prefixes that tunnel to an IPv4
|
|
8
|
+
* address (IPv4-compatible, NAT64, 6to4, Teredo) — through those, a "public" IPv6 address can
|
|
9
|
+
* still reach `10.0.0.5`. An IPv4-mapped IPv6 address (`::ffff:10.0.0.5`) is
|
|
10
|
+
* judged by the IPv4 rules.
|
|
11
|
+
*/
|
|
12
|
+
/** True for a globally routable unicast address; false for anything else, including a non-address. */
|
|
13
|
+
export declare function isPublicAddress(address: string): boolean;
|
|
14
|
+
//# sourceMappingURL=addresses.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"addresses.d.ts","sourceRoot":"","sources":["../../src/http-client/addresses.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA0CH,sGAAsG;AACtG,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAIxD"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which addresses an outbound request may connect to.
|
|
3
|
+
*
|
|
4
|
+
* Everything that is not a globally routable unicast address is refused:
|
|
5
|
+
* loopback, private and shared ranges, link-local (the cloud metadata
|
|
6
|
+
* endpoint `169.254.169.254` lives there), documentation and benchmarking
|
|
7
|
+
* ranges, multicast, and the IPv6 transition prefixes that tunnel to an IPv4
|
|
8
|
+
* address (IPv4-compatible, NAT64, 6to4, Teredo) — through those, a "public" IPv6 address can
|
|
9
|
+
* still reach `10.0.0.5`. An IPv4-mapped IPv6 address (`::ffff:10.0.0.5`) is
|
|
10
|
+
* judged by the IPv4 rules.
|
|
11
|
+
*/
|
|
12
|
+
import { BlockList, isIP } from 'node:net';
|
|
13
|
+
const NON_PUBLIC_V4 = [
|
|
14
|
+
['0.0.0.0', 8], // "this network"
|
|
15
|
+
['10.0.0.0', 8], // private
|
|
16
|
+
['100.64.0.0', 10], // carrier-grade NAT
|
|
17
|
+
['127.0.0.0', 8], // loopback
|
|
18
|
+
['169.254.0.0', 16], // link-local, cloud metadata
|
|
19
|
+
['172.16.0.0', 12], // private
|
|
20
|
+
['192.0.0.0', 24], // IETF protocol assignments
|
|
21
|
+
['192.0.2.0', 24], // TEST-NET-1
|
|
22
|
+
['192.88.99.0', 24], // 6to4 relay anycast
|
|
23
|
+
['192.168.0.0', 16], // private
|
|
24
|
+
['198.18.0.0', 15], // benchmarking
|
|
25
|
+
['198.51.100.0', 24], // TEST-NET-2
|
|
26
|
+
['203.0.113.0', 24], // TEST-NET-3
|
|
27
|
+
['224.0.0.0', 4], // multicast
|
|
28
|
+
['240.0.0.0', 4], // reserved, broadcast
|
|
29
|
+
];
|
|
30
|
+
const NON_PUBLIC_V6 = [
|
|
31
|
+
['::', 128], // unspecified
|
|
32
|
+
['::1', 128], // loopback
|
|
33
|
+
['::', 96], // IPv4-compatible (deprecated), embeds an IPv4 address
|
|
34
|
+
['64:ff9b::', 96], // NAT64, embeds an IPv4 address
|
|
35
|
+
['64:ff9b:1::', 48], // local-use NAT64
|
|
36
|
+
['100::', 64], // discard
|
|
37
|
+
['2001::', 23], // IETF protocol assignments, Teredo included
|
|
38
|
+
['2001:db8::', 32], // documentation
|
|
39
|
+
['2002::', 16], // 6to4, embeds an IPv4 address
|
|
40
|
+
['fc00::', 7], // unique local
|
|
41
|
+
['fe80::', 10], // link-local
|
|
42
|
+
['fec0::', 10], // site-local (deprecated)
|
|
43
|
+
['ff00::', 8], // multicast
|
|
44
|
+
];
|
|
45
|
+
const nonPublic = new BlockList();
|
|
46
|
+
for (const [network, prefix] of NON_PUBLIC_V4)
|
|
47
|
+
nonPublic.addSubnet(network, prefix, 'ipv4');
|
|
48
|
+
for (const [network, prefix] of NON_PUBLIC_V6)
|
|
49
|
+
nonPublic.addSubnet(network, prefix, 'ipv6');
|
|
50
|
+
/** True for a globally routable unicast address; false for anything else, including a non-address. */
|
|
51
|
+
export function isPublicAddress(address) {
|
|
52
|
+
const family = isIP(address);
|
|
53
|
+
if (family === 0)
|
|
54
|
+
return false;
|
|
55
|
+
return !nonPublic.check(address, family === 4 ? 'ipv4' : 'ipv6');
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=addresses.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"addresses.js","sourceRoot":"","sources":["../../src/http-client/addresses.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAE1C,MAAM,aAAa,GAA6C;IAC9D,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,iBAAiB;IACjC,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,UAAU;IAC3B,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,oBAAoB;IACxC,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,WAAW;IAC7B,CAAC,aAAa,EAAE,EAAE,CAAC,EAAE,6BAA6B;IAClD,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,UAAU;IAC9B,CAAC,WAAW,EAAE,EAAE,CAAC,EAAE,4BAA4B;IAC/C,CAAC,WAAW,EAAE,EAAE,CAAC,EAAE,aAAa;IAChC,CAAC,aAAa,EAAE,EAAE,CAAC,EAAE,qBAAqB;IAC1C,CAAC,aAAa,EAAE,EAAE,CAAC,EAAE,UAAU;IAC/B,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,eAAe;IACnC,CAAC,cAAc,EAAE,EAAE,CAAC,EAAE,aAAa;IACnC,CAAC,aAAa,EAAE,EAAE,CAAC,EAAE,aAAa;IAClC,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,YAAY;IAC9B,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,sBAAsB;CACzC,CAAA;AAED,MAAM,aAAa,GAA6C;IAC9D,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,cAAc;IAC3B,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,WAAW;IACzB,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,uDAAuD;IACnE,CAAC,WAAW,EAAE,EAAE,CAAC,EAAE,gCAAgC;IACnD,CAAC,aAAa,EAAE,EAAE,CAAC,EAAE,kBAAkB;IACvC,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,UAAU;IACzB,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,6CAA6C;IAC7D,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,gBAAgB;IACpC,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,+BAA+B;IAC/C,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,eAAe;IAC9B,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,aAAa;IAC7B,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,0BAA0B;IAC1C,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,YAAY;CAC5B,CAAA;AAED,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAA;AACjC,KAAK,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,aAAa;IAAE,SAAS,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAC3F,KAAK,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,aAAa;IAAE,SAAS,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAE3F,sGAAsG;AACtG,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,CAAA;IAC5B,IAAI,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAC9B,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;AAClE,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An {@link HttpClient} that never touches the network, for tests.
|
|
3
|
+
*
|
|
4
|
+
* It is a real client with the transport swapped: URL validation, the
|
|
5
|
+
* address-literal rule, the size limit and the redirect policy all still
|
|
6
|
+
* apply, so a test sees the same refusals production would. Only the wire is
|
|
7
|
+
* replaced — canned responses in, recorded requests out.
|
|
8
|
+
*
|
|
9
|
+
* const http = fakeHttp()
|
|
10
|
+
* http.on('GET', 'https://cms.example.com/api/posts', { json: [{ id: 1 }] })
|
|
11
|
+
* await new CmsReader(http).posts()
|
|
12
|
+
* expect(http.requests).toHaveLength(1)
|
|
13
|
+
*/
|
|
14
|
+
import { HttpClient, type HttpClientOptions, HttpResponse, type OutgoingRequest } from './HttpClient.js';
|
|
15
|
+
/** What a faked endpoint answers. */
|
|
16
|
+
export interface FakeResponse {
|
|
17
|
+
/** Default 200. */
|
|
18
|
+
status?: number;
|
|
19
|
+
headers?: Record<string, string | string[]>;
|
|
20
|
+
body?: string | Uint8Array;
|
|
21
|
+
/** Serialised as the body, with `content-type: application/json`. */
|
|
22
|
+
json?: unknown;
|
|
23
|
+
}
|
|
24
|
+
/** A request the fake received. */
|
|
25
|
+
export interface RecordedRequest {
|
|
26
|
+
method: string;
|
|
27
|
+
url: string;
|
|
28
|
+
headers: Readonly<Record<string, string>>;
|
|
29
|
+
body: Buffer | undefined;
|
|
30
|
+
}
|
|
31
|
+
/** An exact URL (with or without its query string), a pattern, or a predicate. */
|
|
32
|
+
export type FakeMatcher = string | RegExp | ((request: RecordedRequest) => boolean);
|
|
33
|
+
export declare class FakeHttpClient extends HttpClient {
|
|
34
|
+
#private;
|
|
35
|
+
/** Every request sent, in order — redirect hops included. */
|
|
36
|
+
readonly requests: RecordedRequest[];
|
|
37
|
+
/**
|
|
38
|
+
* Answer `method` + `match` with `response`. The most recent matching
|
|
39
|
+
* registration wins, so a test can override a default set up earlier.
|
|
40
|
+
*/
|
|
41
|
+
on(method: string, match: FakeMatcher, response: FakeResponse | ((request: RecordedRequest) => FakeResponse)): this;
|
|
42
|
+
/** Answer `match` whatever the method. */
|
|
43
|
+
onAny(match: FakeMatcher, response: FakeResponse | ((request: RecordedRequest) => FakeResponse)): this;
|
|
44
|
+
/** Forget the registered responses and the recorded requests. */
|
|
45
|
+
reset(): void;
|
|
46
|
+
protected send(request: OutgoingRequest): Promise<HttpResponse>;
|
|
47
|
+
}
|
|
48
|
+
/** A fresh {@link FakeHttpClient}, with the same options a real client takes. */
|
|
49
|
+
export declare function fakeHttp(options?: HttpClientOptions): FakeHttpClient;
|
|
50
|
+
//# sourceMappingURL=fake.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake.d.ts","sourceRoot":"","sources":["../../src/http-client/fake.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,UAAU,EAEV,KAAK,iBAAiB,EACtB,YAAY,EACZ,KAAK,eAAe,EACrB,MAAM,iBAAiB,CAAA;AAExB,qCAAqC;AACrC,MAAM,WAAW,YAAY;IAC3B,mBAAmB;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAA;IAC3C,IAAI,CAAC,EAAE,MAAM,GAAG,UAAU,CAAA;IAC1B,qEAAqE;IACrE,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED,mCAAmC;AACnC,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACzC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;CACzB;AAED,kFAAkF;AAClF,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,CAAA;AAQnF,qBAAa,cAAe,SAAQ,UAAU;;IAC5C,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAK;IAGzC;;;OAGG;IACH,EAAE,CACA,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,YAAY,GAAG,CAAC,CAAC,OAAO,EAAE,eAAe,KAAK,YAAY,CAAC,GACpE,IAAI;IAKP,0CAA0C;IAC1C,KAAK,CACH,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,YAAY,GAAG,CAAC,CAAC,OAAO,EAAE,eAAe,KAAK,YAAY,CAAC,GACpE,IAAI;IAKP,iEAAiE;IACjE,KAAK,IAAI,IAAI;cAKY,IAAI,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC;CA+C/E;AAQD,iFAAiF;AACjF,wBAAgB,QAAQ,CAAC,OAAO,GAAE,iBAAsB,GAAG,cAAc,CAExE"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An {@link HttpClient} that never touches the network, for tests.
|
|
3
|
+
*
|
|
4
|
+
* It is a real client with the transport swapped: URL validation, the
|
|
5
|
+
* address-literal rule, the size limit and the redirect policy all still
|
|
6
|
+
* apply, so a test sees the same refusals production would. Only the wire is
|
|
7
|
+
* replaced — canned responses in, recorded requests out.
|
|
8
|
+
*
|
|
9
|
+
* const http = fakeHttp()
|
|
10
|
+
* http.on('GET', 'https://cms.example.com/api/posts', { json: [{ id: 1 }] })
|
|
11
|
+
* await new CmsReader(http).posts()
|
|
12
|
+
* expect(http.requests).toHaveLength(1)
|
|
13
|
+
*/
|
|
14
|
+
import { HttpClient, HttpClientError, HttpResponse, } from './HttpClient.js';
|
|
15
|
+
export class FakeHttpClient extends HttpClient {
|
|
16
|
+
/** Every request sent, in order — redirect hops included. */
|
|
17
|
+
requests = [];
|
|
18
|
+
#routes = [];
|
|
19
|
+
/**
|
|
20
|
+
* Answer `method` + `match` with `response`. The most recent matching
|
|
21
|
+
* registration wins, so a test can override a default set up earlier.
|
|
22
|
+
*/
|
|
23
|
+
on(method, match, response) {
|
|
24
|
+
this.#routes.push({ method: method.toUpperCase(), match, respond: response });
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
/** Answer `match` whatever the method. */
|
|
28
|
+
onAny(match, response) {
|
|
29
|
+
this.#routes.push({ method: undefined, match, respond: response });
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
/** Forget the registered responses and the recorded requests. */
|
|
33
|
+
reset() {
|
|
34
|
+
this.#routes.length = 0;
|
|
35
|
+
this.requests.length = 0;
|
|
36
|
+
}
|
|
37
|
+
async send(request) {
|
|
38
|
+
const recorded = {
|
|
39
|
+
method: request.method,
|
|
40
|
+
url: request.url.href,
|
|
41
|
+
headers: { ...request.headers },
|
|
42
|
+
body: request.body,
|
|
43
|
+
};
|
|
44
|
+
this.requests.push(recorded);
|
|
45
|
+
const route = this.#latestRoute(recorded, request.url);
|
|
46
|
+
if (route === undefined) {
|
|
47
|
+
throw new HttpClientError('unreachable', request.url, `No fake response for ${recorded.method} ${recorded.url}.`);
|
|
48
|
+
}
|
|
49
|
+
const answer = typeof route.respond === 'function' ? route.respond(recorded) : route.respond;
|
|
50
|
+
const headers = {};
|
|
51
|
+
const given = answer.headers ?? {};
|
|
52
|
+
for (const [name, value] of Object.entries(given)) {
|
|
53
|
+
headers[name.toLowerCase()] = value;
|
|
54
|
+
}
|
|
55
|
+
let body;
|
|
56
|
+
if (answer.json !== undefined) {
|
|
57
|
+
headers['content-type'] ??= 'application/json';
|
|
58
|
+
body = Buffer.from(JSON.stringify(answer.json), 'utf8');
|
|
59
|
+
}
|
|
60
|
+
else if (answer.body === undefined) {
|
|
61
|
+
body = Buffer.alloc(0);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
body =
|
|
65
|
+
typeof answer.body === 'string'
|
|
66
|
+
? Buffer.from(answer.body, 'utf8')
|
|
67
|
+
: Buffer.from(answer.body);
|
|
68
|
+
}
|
|
69
|
+
return new HttpResponse(answer.status ?? 200, headers, request.url.href, body);
|
|
70
|
+
}
|
|
71
|
+
#latestRoute(request, url) {
|
|
72
|
+
for (let i = this.#routes.length - 1; i >= 0; i--) {
|
|
73
|
+
const candidate = this.#routes[i];
|
|
74
|
+
if (candidate === undefined)
|
|
75
|
+
continue;
|
|
76
|
+
if (candidate.method !== undefined && candidate.method !== request.method)
|
|
77
|
+
continue;
|
|
78
|
+
if (matches(candidate.match, request, url))
|
|
79
|
+
return candidate;
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function matches(match, request, url) {
|
|
85
|
+
if (typeof match === 'function')
|
|
86
|
+
return match(request);
|
|
87
|
+
if (match instanceof RegExp)
|
|
88
|
+
return match.test(request.url);
|
|
89
|
+
return match === url.href || match === `${url.origin}${url.pathname}`;
|
|
90
|
+
}
|
|
91
|
+
/** A fresh {@link FakeHttpClient}, with the same options a real client takes. */
|
|
92
|
+
export function fakeHttp(options = {}) {
|
|
93
|
+
return new FakeHttpClient(options);
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=fake.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake.js","sourceRoot":"","sources":["../../src/http-client/fake.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,UAAU,EACV,eAAe,EAEf,YAAY,GAEb,MAAM,iBAAiB,CAAA;AA6BxB,MAAM,OAAO,cAAe,SAAQ,UAAU;IAC5C,6DAA6D;IACpD,QAAQ,GAAsB,EAAE,CAAA;IAChC,OAAO,GAAgB,EAAE,CAAA;IAElC;;;OAGG;IACH,EAAE,CACA,MAAc,EACd,KAAkB,EAClB,QAAqE;QAErE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAA;QAC7E,OAAO,IAAI,CAAA;IACb,CAAC;IAED,0CAA0C;IAC1C,KAAK,CACH,KAAkB,EAClB,QAAqE;QAErE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAA;QAClE,OAAO,IAAI,CAAA;IACb,CAAC;IAED,iEAAiE;IACjE,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAA;QACvB,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAA;IAC1B,CAAC;IAEkB,KAAK,CAAC,IAAI,CAAC,OAAwB;QACpD,MAAM,QAAQ,GAAoB;YAChC,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI;YACrB,OAAO,EAAE,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE;YAC/B,IAAI,EAAE,OAAO,CAAC,IAAI;SACnB,CAAA;QACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAE5B,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,CAAA;QACtD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,IAAI,eAAe,CACvB,aAAa,EACb,OAAO,CAAC,GAAG,EACX,wBAAwB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,GAAG,GAAG,CAC3D,CAAA;QACH,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,KAAK,CAAC,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAA;QAC5F,MAAM,OAAO,GAAsC,EAAE,CAAA;QACrD,MAAM,KAAK,GAAsC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAA;QACrE,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAClD,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,GAAG,KAAK,CAAA;QACrC,CAAC;QACD,IAAI,IAAY,CAAA;QAChB,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO,CAAC,cAAc,CAAC,KAAK,kBAAkB,CAAA;YAC9C,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAA;QACzD,CAAC;aAAM,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACrC,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QACxB,CAAC;aAAM,CAAC;YACN,IAAI;gBACF,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ;oBAC7B,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC;oBAClC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QAChC,CAAC;QACD,OAAO,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,IAAI,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAChF,CAAC;IAED,YAAY,CAAC,OAAwB,EAAE,GAAQ;QAC7C,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;YACjC,IAAI,SAAS,KAAK,SAAS;gBAAE,SAAQ;YACrC,IAAI,SAAS,CAAC,MAAM,KAAK,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM;gBAAE,SAAQ;YACnF,IAAI,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC;gBAAE,OAAO,SAAS,CAAA;QAC9D,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;CACF;AAED,SAAS,OAAO,CAAC,KAAkB,EAAE,OAAwB,EAAE,GAAQ;IACrE,IAAI,OAAO,KAAK,KAAK,UAAU;QAAE,OAAO,KAAK,CAAC,OAAO,CAAC,CAAA;IACtD,IAAI,KAAK,YAAY,MAAM;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAC3D,OAAO,KAAK,KAAK,GAAG,CAAC,IAAI,IAAI,KAAK,KAAK,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAA;AACvE,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,QAAQ,CAAC,UAA6B,EAAE;IACtD,OAAO,IAAI,cAAc,CAAC,OAAO,CAAC,CAAA;AACpC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@c9up/ream/http-client` — outbound HTTP with an SSRF guard, and its test fake.
|
|
3
|
+
*/
|
|
4
|
+
export { isPublicAddress } from './addresses.js';
|
|
5
|
+
export { FakeHttpClient, type FakeMatcher, type FakeResponse, fakeHttp, type RecordedRequest, } from './fake.js';
|
|
6
|
+
export { HttpClient, HttpClientError, type HttpClientFailure, type HttpClientOptions, type HttpRequestOptions, HttpResponse, type OutgoingRequest, } from './HttpClient.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|