@melra/http-runtime 0.3.0-alpha.12 → 0.3.0-alpha.14
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/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +41 -25
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -11,10 +11,11 @@ export interface HttpRuntimeOptions extends NetworkPolicy {
|
|
|
11
11
|
* One governed HTTP call.
|
|
12
12
|
*
|
|
13
13
|
* The interesting part is which socket opens. `assertSafeDestination` resolves
|
|
14
|
-
* the name and checks every answer, then this connects
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* the name and checks every answer, then this connects through a `lookup` that
|
|
15
|
+
* answers only with those checked addresses, never by resolving the name again
|
|
16
|
+
* — the same pinning `PinningProxy` does for the browser, and for the same
|
|
17
|
+
* reason: a resolver that answers public once and private the second time
|
|
18
|
+
* would otherwise make the check meaningless. TLS still verifies the name.
|
|
18
19
|
*/
|
|
19
20
|
export declare class HttpRuntime {
|
|
20
21
|
private readonly options;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACvD;;;OAGG;IACH,WAAW,CAAC,EAAE,gBAAgB,CAAC;CAChC;AAED
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACvD;;;OAGG;IACH,WAAW,CAAC,EAAE,gBAAgB,CAAC;CAChC;AAED;;;;;;;;;GASG;AACH,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,kBAAkB;IAElD,OAAO,CACX,SAAS,EAAE,aAAa,EACxB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CA4JpC"}
|
package/dist/index.js
CHANGED
|
@@ -8,10 +8,11 @@ import { assertSafeDestination, classifyOperation, } from "@melra/policy-core";
|
|
|
8
8
|
* One governed HTTP call.
|
|
9
9
|
*
|
|
10
10
|
* The interesting part is which socket opens. `assertSafeDestination` resolves
|
|
11
|
-
* the name and checks every answer, then this connects
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* the name and checks every answer, then this connects through a `lookup` that
|
|
12
|
+
* answers only with those checked addresses, never by resolving the name again
|
|
13
|
+
* — the same pinning `PinningProxy` does for the browser, and for the same
|
|
14
|
+
* reason: a resolver that answers public once and private the second time
|
|
15
|
+
* would otherwise make the check meaningless. TLS still verifies the name.
|
|
15
16
|
*/
|
|
16
17
|
export class HttpRuntime {
|
|
17
18
|
options;
|
|
@@ -19,24 +20,28 @@ export class HttpRuntime {
|
|
|
19
20
|
this.options = options;
|
|
20
21
|
}
|
|
21
22
|
async execute(operation, signal) {
|
|
22
|
-
const { url,
|
|
23
|
+
const { url, host, lookup } = await assertSafeDestination(operation.url, this.options);
|
|
23
24
|
// Checked here and not only in the router: the destination check above is
|
|
24
25
|
// an await, and a cancel that lands inside that window would otherwise be
|
|
25
26
|
// lost and the request would go out anyway.
|
|
26
|
-
|
|
27
|
+
const cancelled = () => signal?.aborted === true;
|
|
28
|
+
if (cancelled())
|
|
27
29
|
throw new Error("task_cancelled");
|
|
28
30
|
const secure = url.protocol === "https:";
|
|
29
31
|
const send = secure ? httpsRequest : httpRequest;
|
|
30
|
-
// Brokered against the
|
|
31
|
-
//
|
|
32
|
-
// credential scoped
|
|
33
|
-
// will actually talk to.
|
|
32
|
+
// Brokered against the host that was *checked*: the name, or an IPv6
|
|
33
|
+
// literal without the brackets `URL.hostname` keeps, so `[::1]` and a
|
|
34
|
+
// credential scoped to `::1` are the same host.
|
|
34
35
|
const { capability, target } = classifyOperation(operation);
|
|
35
36
|
const brokered = await this.options.credentials?.headersFor({
|
|
36
|
-
host
|
|
37
|
+
host,
|
|
37
38
|
capability,
|
|
38
39
|
target,
|
|
39
40
|
});
|
|
41
|
+
// Again: reading a credential from a file is an await too, and the abort
|
|
42
|
+
// listener below only hears an abort that comes after it is added.
|
|
43
|
+
if (cancelled())
|
|
44
|
+
throw new Error("task_cancelled");
|
|
40
45
|
const headers = {
|
|
41
46
|
// Lowercased before the merge, or `Authorization: guess` from the caller
|
|
42
47
|
// and `authorization: <secret>` from the broker are two distinct keys and
|
|
@@ -48,8 +53,7 @@ export class HttpRuntime {
|
|
|
48
53
|
// Last, so a caller cannot name the same header and have its own value
|
|
49
54
|
// ride out under a credential's name.
|
|
50
55
|
...brokered?.headers,
|
|
51
|
-
//
|
|
52
|
-
// the far end even though the socket was opened to a literal address.
|
|
56
|
+
// The URL's authority exactly as the caller wrote it.
|
|
53
57
|
host: url.host,
|
|
54
58
|
...(operation.idempotencyKey === undefined
|
|
55
59
|
? {}
|
|
@@ -58,17 +62,15 @@ export class HttpRuntime {
|
|
|
58
62
|
if (operation.content !== undefined) {
|
|
59
63
|
headers["content-length"] = String(Buffer.byteLength(operation.content));
|
|
60
64
|
}
|
|
65
|
+
let deadline;
|
|
61
66
|
return await new Promise((resolve, reject) => {
|
|
62
67
|
const call = send({
|
|
63
|
-
host
|
|
68
|
+
host,
|
|
69
|
+
lookup,
|
|
64
70
|
port: url.port === "" ? (secure ? 443 : 80) : Number(url.port),
|
|
65
71
|
method: operation.method,
|
|
66
72
|
path: `${url.pathname}${url.search}`,
|
|
67
73
|
headers,
|
|
68
|
-
// TLS is validated against the name the caller asked for, not the
|
|
69
|
-
// address the socket went to, or pinning would break every https URL.
|
|
70
|
-
...(secure ? { servername: url.hostname } : {}),
|
|
71
|
-
timeout: operation.timeoutMs,
|
|
72
74
|
// A fresh connection per effect, never one from Node's keep-alive
|
|
73
75
|
// pool. A pooled socket the server has already closed takes the whole
|
|
74
76
|
// request and then resets, and below that reads as "the far end may
|
|
@@ -92,6 +94,14 @@ export class HttpRuntime {
|
|
|
92
94
|
chunks.push(chunk);
|
|
93
95
|
});
|
|
94
96
|
const finish = () => {
|
|
97
|
+
// The headers arrived, so the request did too: a body cut off
|
|
98
|
+
// before its end is an answer that stopped, not a call that never
|
|
99
|
+
// happened, and only `outcomeUnknown` says so. Stopping at the
|
|
100
|
+
// size cap is the one deliberate exception.
|
|
101
|
+
if (!response.complete && !truncated) {
|
|
102
|
+
reject(outcomeUnknown("http_response_incomplete"));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
95
105
|
const status = response.statusCode ?? 0;
|
|
96
106
|
resolve({
|
|
97
107
|
// The far end's own word, which is all HTTP can offer. A caller
|
|
@@ -126,7 +136,7 @@ export class HttpRuntime {
|
|
|
126
136
|
};
|
|
127
137
|
response.on("end", finish);
|
|
128
138
|
response.on("close", finish);
|
|
129
|
-
response.on("error", reject);
|
|
139
|
+
response.on("error", (error) => reject(outcomeUnknown(error.message)));
|
|
130
140
|
});
|
|
131
141
|
// Whether the request made it out. A socket error before this is a
|
|
132
142
|
// request that never happened; after it, the far end may have done the
|
|
@@ -134,19 +144,25 @@ export class HttpRuntime {
|
|
|
134
144
|
// `bytesWritten` is not the signal — it counts headers buffered on a
|
|
135
145
|
// socket that never connected, so ECONNREFUSED reports a nonzero count.
|
|
136
146
|
const failed = (error) => {
|
|
147
|
+
// When every pinned address refuses, Node reports one AggregateError
|
|
148
|
+
// with an empty message; the per-address errors say what happened.
|
|
149
|
+
if (error instanceof AggregateError && error.message === "") {
|
|
150
|
+
error = new Error(error.errors.map((inner) => inner.message).join("; "));
|
|
151
|
+
}
|
|
137
152
|
reject(call.writableFinished ? outcomeUnknown(error.message) : error);
|
|
138
153
|
};
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
call
|
|
142
|
-
|
|
143
|
-
|
|
154
|
+
// One deadline for the whole exchange. Node's own `timeout` only notices
|
|
155
|
+
// a socket that goes quiet, so a server sending a byte at a time held the
|
|
156
|
+
// call, and any verification or reconciliation waiting on it, for as
|
|
157
|
+
// long as it liked.
|
|
158
|
+
deadline = setTimeout(() => call.destroy(new Error("http_timeout")), operation.timeoutMs);
|
|
159
|
+
deadline.unref();
|
|
144
160
|
call.on("error", failed);
|
|
145
161
|
signal?.addEventListener("abort", () => call.destroy(new Error("task_cancelled")), { once: true });
|
|
146
162
|
if (operation.content !== undefined)
|
|
147
163
|
call.write(operation.content);
|
|
148
164
|
call.end();
|
|
149
|
-
});
|
|
165
|
+
}).finally(() => clearTimeout(deadline));
|
|
150
166
|
}
|
|
151
167
|
}
|
|
152
168
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,sCAAsC;AAEtC,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,YAAY,CAAC;AAGrD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EACL,qBAAqB,EACrB,iBAAiB,GAGlB,MAAM,oBAAoB,CAAC;AAU5B
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@melra/http-runtime",
|
|
3
|
-
"version": "0.3.0-alpha.
|
|
3
|
+
"version": "0.3.0-alpha.14",
|
|
4
4
|
"description": "HTTP/API reference effect adapter for the MELRA kernel.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"dist"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@melra/policy-core": "0.3.0-alpha.
|
|
25
|
-
"@melra/protocol": "0.3.0-alpha.
|
|
24
|
+
"@melra/policy-core": "0.3.0-alpha.14",
|
|
25
|
+
"@melra/protocol": "0.3.0-alpha.14"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
28
|
"build": "tsc -p tsconfig.json",
|