@gjsify/http2 0.1.0
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 +25 -0
- package/lib/esm/index.js +575 -0
- package/lib/types/index.d.ts +636 -0
- package/package.json +41 -0
- package/src/index.spec.ts +265 -0
- package/src/index.ts +631 -0
- package/src/test.mts +3 -0
- package/tsconfig.json +31 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
// Ported from refs/node-test/parallel/test-http2-*.js
|
|
2
|
+
// Original: MIT license, Node.js contributors
|
|
3
|
+
|
|
4
|
+
import { describe, it, expect } from '@gjsify/unit';
|
|
5
|
+
import http2 from 'node:http2';
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
constants,
|
|
9
|
+
getDefaultSettings,
|
|
10
|
+
getPackedSettings,
|
|
11
|
+
getUnpackedSettings,
|
|
12
|
+
sensitiveHeaders,
|
|
13
|
+
createServer,
|
|
14
|
+
createSecureServer,
|
|
15
|
+
connect,
|
|
16
|
+
Http2ServerRequest,
|
|
17
|
+
Http2ServerResponse,
|
|
18
|
+
} = http2;
|
|
19
|
+
|
|
20
|
+
export default async () => {
|
|
21
|
+
// --- Constants ---
|
|
22
|
+
|
|
23
|
+
await describe('http2.constants', async () => {
|
|
24
|
+
await it('should export constants object', async () => {
|
|
25
|
+
expect(constants).toBeDefined();
|
|
26
|
+
expect(typeof constants).toBe('object');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
await it('should have NGHTTP2 error codes', async () => {
|
|
30
|
+
expect(constants.NGHTTP2_NO_ERROR).toBe(0x00);
|
|
31
|
+
expect(constants.NGHTTP2_PROTOCOL_ERROR).toBe(0x01);
|
|
32
|
+
expect(constants.NGHTTP2_INTERNAL_ERROR).toBe(0x02);
|
|
33
|
+
expect(constants.NGHTTP2_FLOW_CONTROL_ERROR).toBe(0x03);
|
|
34
|
+
expect(constants.NGHTTP2_SETTINGS_TIMEOUT).toBe(0x04);
|
|
35
|
+
expect(constants.NGHTTP2_STREAM_CLOSED).toBe(0x05);
|
|
36
|
+
expect(constants.NGHTTP2_FRAME_SIZE_ERROR).toBe(0x06);
|
|
37
|
+
expect(constants.NGHTTP2_REFUSED_STREAM).toBe(0x07);
|
|
38
|
+
expect(constants.NGHTTP2_CANCEL).toBe(0x08);
|
|
39
|
+
expect(constants.NGHTTP2_COMPRESSION_ERROR).toBe(0x09);
|
|
40
|
+
expect(constants.NGHTTP2_CONNECT_ERROR).toBe(0x0a);
|
|
41
|
+
expect(constants.NGHTTP2_ENHANCE_YOUR_CALM).toBe(0x0b);
|
|
42
|
+
expect(constants.NGHTTP2_INADEQUATE_SECURITY).toBe(0x0c);
|
|
43
|
+
expect(constants.NGHTTP2_HTTP_1_1_REQUIRED).toBe(0x0d);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
await it('should have session type constants', async () => {
|
|
47
|
+
expect(constants.NGHTTP2_SESSION_SERVER).toBe(0);
|
|
48
|
+
expect(constants.NGHTTP2_SESSION_CLIENT).toBe(1);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
await it('should have stream state constants', async () => {
|
|
52
|
+
expect(constants.NGHTTP2_STREAM_STATE_IDLE).toBe(1);
|
|
53
|
+
expect(constants.NGHTTP2_STREAM_STATE_OPEN).toBe(2);
|
|
54
|
+
expect(constants.NGHTTP2_STREAM_STATE_RESERVED_LOCAL).toBe(3);
|
|
55
|
+
expect(constants.NGHTTP2_STREAM_STATE_RESERVED_REMOTE).toBe(4);
|
|
56
|
+
expect(constants.NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL).toBe(5);
|
|
57
|
+
expect(constants.NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE).toBe(6);
|
|
58
|
+
expect(constants.NGHTTP2_STREAM_STATE_CLOSED).toBe(7);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
await it('should have settings ID constants', async () => {
|
|
62
|
+
expect(constants.NGHTTP2_SETTINGS_HEADER_TABLE_SIZE).toBe(0x01);
|
|
63
|
+
expect(constants.NGHTTP2_SETTINGS_ENABLE_PUSH).toBe(0x02);
|
|
64
|
+
expect(constants.NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS).toBe(0x03);
|
|
65
|
+
expect(constants.NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE).toBe(0x04);
|
|
66
|
+
expect(constants.NGHTTP2_SETTINGS_MAX_FRAME_SIZE).toBe(0x05);
|
|
67
|
+
expect(constants.NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE).toBe(0x06);
|
|
68
|
+
expect(constants.NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL).toBe(0x08);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
await it('should have default settings value constants', async () => {
|
|
72
|
+
expect(constants.DEFAULT_SETTINGS_HEADER_TABLE_SIZE).toBe(4096);
|
|
73
|
+
expect(constants.DEFAULT_SETTINGS_ENABLE_PUSH).toBe(1);
|
|
74
|
+
expect(constants.DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE).toBe(65535);
|
|
75
|
+
expect(constants.DEFAULT_SETTINGS_MAX_FRAME_SIZE).toBe(16384);
|
|
76
|
+
expect(constants.DEFAULT_SETTINGS_MAX_HEADER_LIST_SIZE).toBe(65535);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
await it('should have frame flag constants', async () => {
|
|
80
|
+
expect(constants.NGHTTP2_FLAG_NONE).toBe(0);
|
|
81
|
+
expect(constants.NGHTTP2_FLAG_END_STREAM).toBe(0x01);
|
|
82
|
+
expect(constants.NGHTTP2_FLAG_END_HEADERS).toBe(0x04);
|
|
83
|
+
expect(constants.NGHTTP2_FLAG_PADDED).toBe(0x08);
|
|
84
|
+
expect(constants.NGHTTP2_FLAG_PRIORITY).toBe(0x20);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
await it('should have HTTP/2 pseudo-header constants', async () => {
|
|
88
|
+
expect(constants.HTTP2_HEADER_STATUS).toBe(':status');
|
|
89
|
+
expect(constants.HTTP2_HEADER_METHOD).toBe(':method');
|
|
90
|
+
expect(constants.HTTP2_HEADER_PATH).toBe(':path');
|
|
91
|
+
expect(constants.HTTP2_HEADER_AUTHORITY).toBe(':authority');
|
|
92
|
+
expect(constants.HTTP2_HEADER_SCHEME).toBe(':scheme');
|
|
93
|
+
expect(constants.HTTP2_HEADER_PROTOCOL).toBe(':protocol');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
await it('should have standard HTTP header constants', async () => {
|
|
97
|
+
expect(constants.HTTP2_HEADER_CONTENT_TYPE).toBe('content-type');
|
|
98
|
+
expect(constants.HTTP2_HEADER_CONTENT_LENGTH).toBe('content-length');
|
|
99
|
+
expect(constants.HTTP2_HEADER_ACCEPT).toBe('accept');
|
|
100
|
+
expect(constants.HTTP2_HEADER_AUTHORIZATION).toBe('authorization');
|
|
101
|
+
expect(constants.HTTP2_HEADER_CACHE_CONTROL).toBe('cache-control');
|
|
102
|
+
expect(constants.HTTP2_HEADER_COOKIE).toBe('cookie');
|
|
103
|
+
expect(constants.HTTP2_HEADER_SET_COOKIE).toBe('set-cookie');
|
|
104
|
+
expect(constants.HTTP2_HEADER_USER_AGENT).toBe('user-agent');
|
|
105
|
+
expect(constants.HTTP2_HEADER_HOST).toBe('host');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
await it('should have HTTP method constants', async () => {
|
|
109
|
+
expect(constants.HTTP2_METHOD_GET).toBe('GET');
|
|
110
|
+
expect(constants.HTTP2_METHOD_POST).toBe('POST');
|
|
111
|
+
expect(constants.HTTP2_METHOD_PUT).toBe('PUT');
|
|
112
|
+
expect(constants.HTTP2_METHOD_DELETE).toBe('DELETE');
|
|
113
|
+
expect(constants.HTTP2_METHOD_PATCH).toBe('PATCH');
|
|
114
|
+
expect(constants.HTTP2_METHOD_HEAD).toBe('HEAD');
|
|
115
|
+
expect(constants.HTTP2_METHOD_OPTIONS).toBe('OPTIONS');
|
|
116
|
+
expect(constants.HTTP2_METHOD_CONNECT).toBe('CONNECT');
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
await it('should have HTTP status code constants', async () => {
|
|
120
|
+
expect(constants.HTTP_STATUS_CONTINUE).toBe(100);
|
|
121
|
+
expect(constants.HTTP_STATUS_OK).toBe(200);
|
|
122
|
+
expect(constants.HTTP_STATUS_CREATED).toBe(201);
|
|
123
|
+
expect(constants.HTTP_STATUS_NO_CONTENT).toBe(204);
|
|
124
|
+
expect(constants.HTTP_STATUS_MOVED_PERMANENTLY).toBe(301);
|
|
125
|
+
expect(constants.HTTP_STATUS_NOT_FOUND).toBe(404);
|
|
126
|
+
expect(constants.HTTP_STATUS_TEAPOT).toBe(418);
|
|
127
|
+
expect(constants.HTTP_STATUS_INTERNAL_SERVER_ERROR).toBe(500);
|
|
128
|
+
expect(constants.HTTP_STATUS_BAD_GATEWAY).toBe(502);
|
|
129
|
+
expect(constants.HTTP_STATUS_SERVICE_UNAVAILABLE).toBe(503);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
await it('should have frame size constraint constants', async () => {
|
|
133
|
+
expect(constants.MAX_MAX_FRAME_SIZE).toBe(16777215);
|
|
134
|
+
expect(constants.MIN_MAX_FRAME_SIZE).toBe(16384);
|
|
135
|
+
expect(constants.MAX_INITIAL_WINDOW_SIZE).toBe(2147483647);
|
|
136
|
+
expect(constants.NGHTTP2_DEFAULT_WEIGHT).toBe(16);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// --- Settings ---
|
|
141
|
+
|
|
142
|
+
await describe('http2.getDefaultSettings', async () => {
|
|
143
|
+
await it('should return an object with default settings', async () => {
|
|
144
|
+
const settings = getDefaultSettings();
|
|
145
|
+
expect(settings).toBeDefined();
|
|
146
|
+
expect(typeof settings).toBe('object');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
await it('should have headerTableSize = 4096', async () => {
|
|
150
|
+
expect(getDefaultSettings().headerTableSize).toBe(4096);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
await it('should have enablePush = true', async () => {
|
|
154
|
+
expect(getDefaultSettings().enablePush).toBe(true);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
await it('should have initialWindowSize = 65535', async () => {
|
|
158
|
+
expect(getDefaultSettings().initialWindowSize).toBe(65535);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
await it('should have maxFrameSize = 16384', async () => {
|
|
162
|
+
expect(getDefaultSettings().maxFrameSize).toBe(16384);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
await it('should have enableConnectProtocol = false', async () => {
|
|
166
|
+
expect(getDefaultSettings().enableConnectProtocol).toBe(false);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
await describe('http2.getPackedSettings / getUnpackedSettings', async () => {
|
|
171
|
+
await it('getPackedSettings should return Uint8Array', async () => {
|
|
172
|
+
const packed = getPackedSettings({ headerTableSize: 4096 });
|
|
173
|
+
expect(packed instanceof Uint8Array).toBe(true);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
await it('getPackedSettings with no args should return empty', async () => {
|
|
177
|
+
const packed = getPackedSettings();
|
|
178
|
+
expect(packed.byteLength).toBe(0);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
await it('getPackedSettings should encode one setting as 6 bytes', async () => {
|
|
182
|
+
const packed = getPackedSettings({ headerTableSize: 4096 });
|
|
183
|
+
expect(packed.byteLength).toBe(6);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
await it('getPackedSettings should encode multiple settings', async () => {
|
|
187
|
+
const packed = getPackedSettings({
|
|
188
|
+
headerTableSize: 4096,
|
|
189
|
+
enablePush: true,
|
|
190
|
+
maxFrameSize: 32768,
|
|
191
|
+
});
|
|
192
|
+
expect(packed.byteLength).toBe(18);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
await it('round-trip should preserve settings', async () => {
|
|
196
|
+
const original = {
|
|
197
|
+
headerTableSize: 8192,
|
|
198
|
+
enablePush: false,
|
|
199
|
+
maxConcurrentStreams: 100,
|
|
200
|
+
initialWindowSize: 32768,
|
|
201
|
+
maxFrameSize: 32768,
|
|
202
|
+
};
|
|
203
|
+
const packed = getPackedSettings(original);
|
|
204
|
+
const unpacked = getUnpackedSettings(packed);
|
|
205
|
+
expect(unpacked.headerTableSize).toBe(8192);
|
|
206
|
+
expect(unpacked.enablePush).toBe(false);
|
|
207
|
+
expect(unpacked.maxConcurrentStreams).toBe(100);
|
|
208
|
+
expect(unpacked.initialWindowSize).toBe(32768);
|
|
209
|
+
expect(unpacked.maxFrameSize).toBe(32768);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
await it('getUnpackedSettings should throw on invalid length', async () => {
|
|
213
|
+
let threw = false;
|
|
214
|
+
try {
|
|
215
|
+
getUnpackedSettings(new Uint8Array(7));
|
|
216
|
+
} catch {
|
|
217
|
+
threw = true;
|
|
218
|
+
}
|
|
219
|
+
expect(threw).toBe(true);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// --- sensitiveHeaders ---
|
|
224
|
+
|
|
225
|
+
await describe('http2.sensitiveHeaders', async () => {
|
|
226
|
+
await it('should be a symbol', async () => {
|
|
227
|
+
expect(typeof sensitiveHeaders).toBe('symbol');
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// --- Factory functions ---
|
|
232
|
+
|
|
233
|
+
await describe('http2 factory functions', async () => {
|
|
234
|
+
await it('createServer should be a function', async () => {
|
|
235
|
+
expect(typeof createServer).toBe('function');
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
await it('createSecureServer should be a function', async () => {
|
|
239
|
+
expect(typeof createSecureServer).toBe('function');
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
await it('connect should be a function', async () => {
|
|
243
|
+
expect(typeof connect).toBe('function');
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Note: createServer/createSecureServer/connect work on Node.js but throw on GJS.
|
|
247
|
+
// Testing the throw behavior would be platform-specific.
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// --- Class exports ---
|
|
251
|
+
|
|
252
|
+
await describe('http2 class exports', async () => {
|
|
253
|
+
await it('should export Http2ServerRequest', async () => {
|
|
254
|
+
expect(typeof Http2ServerRequest).toBe('function');
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
await it('should export Http2ServerResponse', async () => {
|
|
258
|
+
expect(typeof Http2ServerResponse).toBe('function');
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// Note: Http2Session, Http2Stream, ServerHttp2Session are exported differently
|
|
262
|
+
// on Node.js (named exports) vs our implementation (default export).
|
|
263
|
+
// Testing export availability would be platform-specific.
|
|
264
|
+
});
|
|
265
|
+
};
|