@statewalker/webrun-http-streams 0.1.0 → 0.2.1
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 +288 -11
- package/dist/bytes.d.ts +43 -0
- package/dist/bytes.d.ts.map +1 -0
- package/dist/codec-default.d.ts +7 -0
- package/dist/codec-default.d.ts.map +1 -0
- package/dist/duplex-site-builder.d.ts +3 -0
- package/dist/duplex-site-builder.d.ts.map +1 -1
- package/dist/envelope.d.ts +10 -10
- package/dist/envelope.d.ts.map +1 -1
- package/dist/fetch.d.ts +3 -2
- package/dist/fetch.d.ts.map +1 -1
- package/dist/http-data.d.ts +11 -7
- package/dist/http-data.d.ts.map +1 -1
- package/dist/http-error.d.ts.map +1 -1
- package/dist/http-stubs.d.ts +12 -0
- package/dist/http-stubs.d.ts.map +1 -1
- package/dist/http1/chunked.d.ts +18 -0
- package/dist/http1/chunked.d.ts.map +1 -0
- package/dist/http1/decode.d.ts +5 -0
- package/dist/http1/decode.d.ts.map +1 -0
- package/dist/http1/encode.d.ts +20 -0
- package/dist/http1/encode.d.ts.map +1 -0
- package/dist/http1/errors.d.ts +9 -0
- package/dist/http1/errors.d.ts.map +1 -0
- package/dist/http1/headers.d.ts +78 -0
- package/dist/http1/headers.d.ts.map +1 -0
- package/dist/http1/index.d.ts +18 -0
- package/dist/http1/index.d.ts.map +1 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1039 -137
- package/dist/message.d.ts +50 -0
- package/dist/message.d.ts.map +1 -0
- package/dist/request-streams.d.ts +52 -0
- package/dist/request-streams.d.ts.map +1 -0
- package/dist/sniff.d.ts +18 -0
- package/dist/sniff.d.ts.map +1 -0
- package/package.json +8 -6
- package/src/bytes.ts +157 -0
- package/src/codec-default.ts +13 -0
- package/src/duplex-site-builder.ts +9 -1
- package/src/envelope.ts +43 -34
- package/src/fetch.ts +130 -12
- package/src/http-data.ts +160 -17
- package/src/http-stubs.ts +72 -18
- package/src/http1/chunked.ts +89 -0
- package/src/http1/decode.ts +208 -0
- package/src/http1/encode.ts +181 -0
- package/src/http1/errors.ts +8 -0
- package/src/http1/headers.ts +263 -0
- package/src/http1/index.ts +40 -0
- package/src/index.ts +18 -0
- package/src/message.ts +62 -0
- package/src/request-streams.ts +75 -0
- package/src/sniff.ts +68 -0
package/src/sniff.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { ByteReader } from "./bytes.js";
|
|
2
|
+
import { HttpParseError } from "./http1/errors.js";
|
|
3
|
+
import type { ByteSource, MessageCodec } from "./message.js";
|
|
4
|
+
|
|
5
|
+
export type SniffingCodecOptions = {
|
|
6
|
+
/** Codec used for everything this peer writes. */
|
|
7
|
+
write: MessageCodec;
|
|
8
|
+
/** Codecs this peer accepts on read, tried in order. */
|
|
9
|
+
accept: MessageCodec[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Dispatches on byte 0. The formats are self-identifying — a JSON envelope
|
|
14
|
+
* always begins `{`, which is not a token character and so can never begin an
|
|
15
|
+
* HTTP start-line — so no negotiation handshake, magic prefix, or version byte
|
|
16
|
+
* is needed.
|
|
17
|
+
*
|
|
18
|
+
* This is what makes a mixed-version peer pair safe: readers accept either
|
|
19
|
+
* format, so the two ends can be upgraded in any order.
|
|
20
|
+
*/
|
|
21
|
+
export function newSniffingCodec(options: SniffingCodecOptions): MessageCodec {
|
|
22
|
+
const { write, accept } = options;
|
|
23
|
+
|
|
24
|
+
async function pick(input: ByteSource): Promise<{ codec: MessageCodec; input: ByteSource }> {
|
|
25
|
+
const reader = new ByteReader(input);
|
|
26
|
+
const first = await reader.peekByte();
|
|
27
|
+
if (first === undefined) {
|
|
28
|
+
throw new HttpParseError("sniff: stream ended before any bytes arrived");
|
|
29
|
+
}
|
|
30
|
+
const codec = accept.find((c) => c.sniff(first));
|
|
31
|
+
if (!codec) {
|
|
32
|
+
throw new HttpParseError(
|
|
33
|
+
`sniff: no accepted codec recognises a message starting with byte 0x${first
|
|
34
|
+
.toString(16)
|
|
35
|
+
.padStart(2, "0")}`,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
return { codec, input: reader.rest() };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
name: `sniff(write=${write.name}; accept=${accept.map((c) => c.name).join(",")})`,
|
|
43
|
+
sniff: (byte) => accept.some((c) => c.sniff(byte)),
|
|
44
|
+
encodeRequest: (env, body) => write.encodeRequest(env, body),
|
|
45
|
+
encodeResponse: (env, body, o) => write.encodeResponse(env, body, o),
|
|
46
|
+
decodeRequest: async (input) => {
|
|
47
|
+
const picked = await pick(input);
|
|
48
|
+
try {
|
|
49
|
+
const decoded = await picked.codec.decodeRequest(picked.input);
|
|
50
|
+
return { ...decoded, codec: picked.codec };
|
|
51
|
+
} catch (error) {
|
|
52
|
+
// Sniffing already told us which format the peer is speaking. Carry
|
|
53
|
+
// that on the error so a refusal can be answered in the peer's own
|
|
54
|
+
// format — otherwise a peer pinned to the legacy envelope receives its
|
|
55
|
+
// error response as HTTP/1.1, the same mismatch reply-in-kind avoids
|
|
56
|
+
// on the success path.
|
|
57
|
+
if (error !== null && typeof error === "object") {
|
|
58
|
+
(error as { codec?: MessageCodec }).codec = picked.codec;
|
|
59
|
+
}
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
decodeResponse: async (input, o) => {
|
|
64
|
+
const picked = await pick(input);
|
|
65
|
+
return picked.codec.decodeResponse(picked.input, o);
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|