@gjsify/http 0.4.0 → 0.4.4
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/package.json +54 -51
- package/src/client-request.ts +0 -307
- package/src/client.spec.ts +0 -549
- package/src/constants.ts +0 -33
- package/src/extended.spec.ts +0 -620
- package/src/incoming-message.ts +0 -77
- package/src/index.spec.ts +0 -1405
- package/src/index.ts +0 -149
- package/src/listen-error.spec.ts +0 -73
- package/src/server-request-socket.ts +0 -88
- package/src/server.ts +0 -503
- package/src/streaming.spec.ts +0 -588
- package/src/test.mts +0 -13
- package/src/timeout.spec.ts +0 -668
- package/src/upgrade.spec.ts +0 -256
- package/src/validators.ts +0 -25
- package/tsconfig.json +0 -29
- package/tsconfig.tsbuildinfo +0 -1
package/src/index.spec.ts
DELETED
|
@@ -1,1405 +0,0 @@
|
|
|
1
|
-
// Ported from refs/node-test/parallel/test-http-*.js
|
|
2
|
-
// Original: MIT license, Node.js contributors
|
|
3
|
-
//
|
|
4
|
-
// Type strategy (Workstream K): runtime values come from `node:http` so the Node
|
|
5
|
-
// bundle stays free of `gi://*` imports (this file is loaded by the same
|
|
6
|
-
// `test.mts` aggregator that also drives `test:node`; a direct
|
|
7
|
-
// `import { … } from '@gjsify/http'` would drag `gi://Soup/Gio/GLib` into the
|
|
8
|
-
// Node bundle and crash it at load). For static typing we pull the
|
|
9
|
-
// impl-private symbols (`OutgoingMessage`, `validateHeaderName`,
|
|
10
|
-
// `validateHeaderValue`, `setMaxIdleHTTPParsers`) from `@gjsify/http` via
|
|
11
|
-
// type-only imports — stripped at compile time, so the Node bundle is
|
|
12
|
-
// unaffected, but TypeScript sees the real shapes (concrete subclasses of
|
|
13
|
-
// `Writable`/`Readable`) and the entire `as any` chain that `@types/node`
|
|
14
|
-
// would force disappears.
|
|
15
|
-
|
|
16
|
-
import { describe, it, expect } from '@gjsify/unit';
|
|
17
|
-
import { Buffer } from 'node:buffer';
|
|
18
|
-
|
|
19
|
-
import http from 'node:http';
|
|
20
|
-
import type {
|
|
21
|
-
OutgoingMessage as OurOutgoingMessage,
|
|
22
|
-
IncomingMessage as OurIncomingMessage,
|
|
23
|
-
Agent as OurAgent,
|
|
24
|
-
validateHeaderName as ourValidateHeaderName,
|
|
25
|
-
validateHeaderValue as ourValidateHeaderValue,
|
|
26
|
-
setMaxIdleHTTPParsers as ourSetMaxIdleHTTPParsers,
|
|
27
|
-
} from '@gjsify/http';
|
|
28
|
-
|
|
29
|
-
// Local view of `node:http`'s default export retyped against our impl-private
|
|
30
|
-
// classes. `node:http` is the runtime source on both Node and GJS (alias-mapped
|
|
31
|
-
// to `@gjsify/http` on the GJS target by the build), but its declarations come
|
|
32
|
-
// from `@types/node` and don't expose the GJS-only shapes we want to assert
|
|
33
|
-
// against. This cast is the single boundary between the two views.
|
|
34
|
-
const gjsHttp = http as unknown as Omit<
|
|
35
|
-
typeof http,
|
|
36
|
-
'OutgoingMessage' | 'IncomingMessage' | 'Agent' | 'globalAgent'
|
|
37
|
-
> & {
|
|
38
|
-
OutgoingMessage: typeof OurOutgoingMessage;
|
|
39
|
-
IncomingMessage: new (socket?: unknown) => OurIncomingMessage;
|
|
40
|
-
Agent: new (options?: ConstructorParameters<typeof OurAgent>[0]) => OurAgent;
|
|
41
|
-
globalAgent: OurAgent;
|
|
42
|
-
validateHeaderName: typeof ourValidateHeaderName;
|
|
43
|
-
validateHeaderValue: typeof ourValidateHeaderValue;
|
|
44
|
-
setMaxIdleHTTPParsers: typeof ourSetMaxIdleHTTPParsers;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const validateHeaderName = gjsHttp.validateHeaderName;
|
|
48
|
-
const validateHeaderValue = gjsHttp.validateHeaderValue;
|
|
49
|
-
|
|
50
|
-
export default async () => {
|
|
51
|
-
|
|
52
|
-
// --- validateHeaderName ---
|
|
53
|
-
await describe('http.validateHeaderName', async () => {
|
|
54
|
-
await it('should be a function', async () => {
|
|
55
|
-
expect(typeof validateHeaderName).toBe('function');
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
await it('should not throw for valid header names', async () => {
|
|
59
|
-
expect(() => validateHeaderName('Content-Type')).not.toThrow();
|
|
60
|
-
expect(() => validateHeaderName('set-cookie')).not.toThrow();
|
|
61
|
-
expect(() => validateHeaderName('alfa-beta')).not.toThrow();
|
|
62
|
-
expect(() => validateHeaderName('X-Custom-Header')).not.toThrow();
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
await it('should accept single-char header names', async () => {
|
|
66
|
-
expect(() => validateHeaderName('x')).not.toThrow();
|
|
67
|
-
expect(() => validateHeaderName('X')).not.toThrow();
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
await it('should accept header names with special tokens', async () => {
|
|
71
|
-
expect(() => validateHeaderName('x-forwarded-for')).not.toThrow();
|
|
72
|
-
expect(() => validateHeaderName('accept-encoding')).not.toThrow();
|
|
73
|
-
expect(() => validateHeaderName('cache-control')).not.toThrow();
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
await it('should throw TypeError for empty string', async () => {
|
|
77
|
-
let threw = false;
|
|
78
|
-
try {
|
|
79
|
-
validateHeaderName('');
|
|
80
|
-
} catch (error) {
|
|
81
|
-
threw = true;
|
|
82
|
-
expect(error instanceof TypeError).toBe(true);
|
|
83
|
-
}
|
|
84
|
-
expect(threw).toBe(true);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
await it('should throw for invalid characters', async () => {
|
|
88
|
-
expect(() => validateHeaderName('@@wdjhgw')).toThrow();
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
await it('should throw for header name with spaces', async () => {
|
|
92
|
-
expect(() => validateHeaderName('Content Type')).toThrow();
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
await it('should throw for header name with colon', async () => {
|
|
96
|
-
expect(() => validateHeaderName('Content:')).toThrow();
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
await it('should throw for number input', async () => {
|
|
100
|
-
let threw = false;
|
|
101
|
-
try {
|
|
102
|
-
validateHeaderName(100 as unknown as string);
|
|
103
|
-
} catch (error) {
|
|
104
|
-
threw = true;
|
|
105
|
-
expect(error instanceof TypeError).toBe(true);
|
|
106
|
-
}
|
|
107
|
-
expect(threw).toBe(true);
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
// --- validateHeaderValue ---
|
|
112
|
-
await describe('http.validateHeaderValue', async () => {
|
|
113
|
-
await it('should be a function', async () => {
|
|
114
|
-
expect(typeof validateHeaderValue).toBe('function');
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
await it('should not throw for valid values', async () => {
|
|
118
|
-
expect(() => validateHeaderValue('Content-Type', 'text/html')).not.toThrow();
|
|
119
|
-
expect(() => validateHeaderValue('X-Header', 'some value')).not.toThrow();
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
await it('should accept numeric string values', async () => {
|
|
123
|
-
expect(() => validateHeaderValue('Content-Length', '123')).not.toThrow();
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
await it('should accept empty string value', async () => {
|
|
127
|
-
expect(() => validateHeaderValue('X-Empty', '')).not.toThrow();
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
await it('should accept values with standard ASCII characters', async () => {
|
|
131
|
-
expect(() => validateHeaderValue('X-Test', 'abcdefghijklmnopqrstuvwxyz')).not.toThrow();
|
|
132
|
-
expect(() => validateHeaderValue('X-Test', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')).not.toThrow();
|
|
133
|
-
expect(() => validateHeaderValue('X-Test', '0123456789')).not.toThrow();
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
// --- STATUS_CODES ---
|
|
138
|
-
await describe('http.STATUS_CODES', async () => {
|
|
139
|
-
await it('should be an object', async () => {
|
|
140
|
-
expect(typeof http.STATUS_CODES).toBe('object');
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
await it('should not be null', async () => {
|
|
144
|
-
expect(http.STATUS_CODES).toBeDefined();
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
await it('should contain common status codes', async () => {
|
|
148
|
-
expect(http.STATUS_CODES[200]).toBe('OK');
|
|
149
|
-
expect(http.STATUS_CODES[201]).toBe('Created');
|
|
150
|
-
expect(http.STATUS_CODES[204]).toBe('No Content');
|
|
151
|
-
expect(http.STATUS_CODES[301]).toBe('Moved Permanently');
|
|
152
|
-
expect(http.STATUS_CODES[302]).toBe('Found');
|
|
153
|
-
expect(http.STATUS_CODES[304]).toBe('Not Modified');
|
|
154
|
-
expect(http.STATUS_CODES[400]).toBe('Bad Request');
|
|
155
|
-
expect(http.STATUS_CODES[401]).toBe('Unauthorized');
|
|
156
|
-
expect(http.STATUS_CODES[403]).toBe('Forbidden');
|
|
157
|
-
expect(http.STATUS_CODES[404]).toBe('Not Found');
|
|
158
|
-
expect(http.STATUS_CODES[405]).toBe('Method Not Allowed');
|
|
159
|
-
expect(http.STATUS_CODES[500]).toBe('Internal Server Error');
|
|
160
|
-
expect(http.STATUS_CODES[502]).toBe('Bad Gateway');
|
|
161
|
-
expect(http.STATUS_CODES[503]).toBe('Service Unavailable');
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
await it('should contain informational status codes', async () => {
|
|
165
|
-
expect(http.STATUS_CODES[100]).toBe('Continue');
|
|
166
|
-
expect(http.STATUS_CODES[101]).toBe('Switching Protocols');
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
await it('should contain redirect status codes', async () => {
|
|
170
|
-
expect(http.STATUS_CODES[300]).toBe('Multiple Choices');
|
|
171
|
-
expect(http.STATUS_CODES[307]).toBe('Temporary Redirect');
|
|
172
|
-
expect(http.STATUS_CODES[308]).toBe('Permanent Redirect');
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
await it('should contain client error status codes', async () => {
|
|
176
|
-
expect(http.STATUS_CODES[402]).toBe('Payment Required');
|
|
177
|
-
expect(http.STATUS_CODES[406]).toBe('Not Acceptable');
|
|
178
|
-
expect(http.STATUS_CODES[408]).toBe('Request Timeout');
|
|
179
|
-
expect(http.STATUS_CODES[409]).toBe('Conflict');
|
|
180
|
-
expect(http.STATUS_CODES[410]).toBe('Gone');
|
|
181
|
-
expect(http.STATUS_CODES[413]).toBe('Payload Too Large');
|
|
182
|
-
expect(http.STATUS_CODES[415]).toBe('Unsupported Media Type');
|
|
183
|
-
expect(http.STATUS_CODES[418]).toBe("I'm a Teapot");
|
|
184
|
-
expect(http.STATUS_CODES[429]).toBe('Too Many Requests');
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
await it('should contain server error status codes', async () => {
|
|
188
|
-
expect(http.STATUS_CODES[501]).toBe('Not Implemented');
|
|
189
|
-
expect(http.STATUS_CODES[504]).toBe('Gateway Timeout');
|
|
190
|
-
expect(http.STATUS_CODES[505]).toBe('HTTP Version Not Supported');
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
await it('should contain WebDAV status codes', async () => {
|
|
194
|
-
expect(http.STATUS_CODES[102]).toBe('Processing');
|
|
195
|
-
expect(http.STATUS_CODES[207]).toBe('Multi-Status');
|
|
196
|
-
expect(http.STATUS_CODES[422]).toBe('Unprocessable Entity');
|
|
197
|
-
expect(http.STATUS_CODES[423]).toBe('Locked');
|
|
198
|
-
expect(http.STATUS_CODES[507]).toBe('Insufficient Storage');
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
await it('should return undefined for unknown codes', async () => {
|
|
202
|
-
expect(http.STATUS_CODES[999]).toBeUndefined();
|
|
203
|
-
expect(http.STATUS_CODES[0]).toBeUndefined();
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
await it('should have string values for all keys', async () => {
|
|
207
|
-
for (const key of Object.keys(http.STATUS_CODES)) {
|
|
208
|
-
expect(typeof http.STATUS_CODES[Number(key)]).toBe('string');
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
// --- METHODS ---
|
|
214
|
-
await describe('http.METHODS', async () => {
|
|
215
|
-
await it('should be an array', async () => {
|
|
216
|
-
expect(Array.isArray(http.METHODS)).toBe(true);
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
await it('should contain standard HTTP methods', async () => {
|
|
220
|
-
expect(http.METHODS).toContain('GET');
|
|
221
|
-
expect(http.METHODS).toContain('POST');
|
|
222
|
-
expect(http.METHODS).toContain('PUT');
|
|
223
|
-
expect(http.METHODS).toContain('DELETE');
|
|
224
|
-
expect(http.METHODS).toContain('PATCH');
|
|
225
|
-
expect(http.METHODS).toContain('HEAD');
|
|
226
|
-
expect(http.METHODS).toContain('OPTIONS');
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
await it('should contain WebDAV methods', async () => {
|
|
230
|
-
expect(http.METHODS).toContain('PROPFIND');
|
|
231
|
-
expect(http.METHODS).toContain('PROPPATCH');
|
|
232
|
-
expect(http.METHODS).toContain('MKCOL');
|
|
233
|
-
expect(http.METHODS).toContain('COPY');
|
|
234
|
-
expect(http.METHODS).toContain('MOVE');
|
|
235
|
-
expect(http.METHODS).toContain('LOCK');
|
|
236
|
-
expect(http.METHODS).toContain('UNLOCK');
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
await it('should contain extended methods', async () => {
|
|
240
|
-
expect(http.METHODS).toContain('CONNECT');
|
|
241
|
-
expect(http.METHODS).toContain('TRACE');
|
|
242
|
-
expect(http.METHODS).toContain('M-SEARCH');
|
|
243
|
-
expect(http.METHODS).toContain('PURGE');
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
await it('should be sorted alphabetically', async () => {
|
|
247
|
-
const sorted = [...http.METHODS].sort();
|
|
248
|
-
for (let i = 0; i < http.METHODS.length; i++) {
|
|
249
|
-
expect(http.METHODS[i]).toBe(sorted[i]);
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
await it('should only contain uppercase strings', async () => {
|
|
254
|
-
for (const method of http.METHODS) {
|
|
255
|
-
expect(method).toBe(method.toUpperCase());
|
|
256
|
-
}
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
await it('should have no duplicate entries', async () => {
|
|
260
|
-
const unique = new Set(http.METHODS);
|
|
261
|
-
expect(unique.size).toBe(http.METHODS.length);
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
// --- Module exports ---
|
|
266
|
-
await describe('http module exports', async () => {
|
|
267
|
-
await it('should export maxHeaderSize', async () => {
|
|
268
|
-
expect(http.maxHeaderSize).toBe(16384);
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
await it('should export maxHeaderSize as a number', async () => {
|
|
272
|
-
expect(typeof http.maxHeaderSize).toBe('number');
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
await it('should export Agent', async () => {
|
|
276
|
-
expect(typeof http.Agent).toBe('function');
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
await it('should export globalAgent', async () => {
|
|
280
|
-
expect(http.globalAgent).toBeDefined();
|
|
281
|
-
expect(http.globalAgent.defaultPort).toBe(80);
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
await it('should export createServer', async () => {
|
|
285
|
-
expect(typeof http.createServer).toBe('function');
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
await it('should export IncomingMessage', async () => {
|
|
289
|
-
expect(typeof http.IncomingMessage).toBe('function');
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
await it('should export Server', async () => {
|
|
293
|
-
expect(typeof http.Server).toBe('function');
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
await it('should export ServerResponse', async () => {
|
|
297
|
-
expect(typeof http.ServerResponse).toBe('function');
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
await it('should export OutgoingMessage', async () => {
|
|
301
|
-
expect(typeof gjsHttp.OutgoingMessage).toBe('function');
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
await it('should export ClientRequest', async () => {
|
|
305
|
-
expect(typeof http.ClientRequest).toBe('function');
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
await it('should export request and get', async () => {
|
|
309
|
-
expect(typeof http.request).toBe('function');
|
|
310
|
-
expect(typeof http.get).toBe('function');
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
await it('should export setMaxIdleHTTPParsers', async () => {
|
|
314
|
-
expect(typeof gjsHttp.setMaxIdleHTTPParsers).toBe('function');
|
|
315
|
-
// Should not throw
|
|
316
|
-
gjsHttp.setMaxIdleHTTPParsers(256);
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
await it('should export validateHeaderName and validateHeaderValue', async () => {
|
|
320
|
-
expect(typeof gjsHttp.validateHeaderName).toBe('function');
|
|
321
|
-
expect(typeof gjsHttp.validateHeaderValue).toBe('function');
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
await it('should have a default export', async () => {
|
|
325
|
-
expect(http).toBeDefined();
|
|
326
|
-
expect(typeof http).toBe('object');
|
|
327
|
-
});
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
// --- OutgoingMessage ---
|
|
331
|
-
await describe('http.OutgoingMessage', async () => {
|
|
332
|
-
await it('should be constructable', async () => {
|
|
333
|
-
const OutgoingMessage = gjsHttp.OutgoingMessage;
|
|
334
|
-
const msg = new OutgoingMessage();
|
|
335
|
-
expect(msg).toBeDefined();
|
|
336
|
-
expect(msg.headersSent).toBe(false);
|
|
337
|
-
expect(msg.finished).toBe(false);
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
await it('should support setHeader/getHeader/hasHeader/removeHeader', async () => {
|
|
341
|
-
const OutgoingMessage = gjsHttp.OutgoingMessage;
|
|
342
|
-
const msg = new OutgoingMessage();
|
|
343
|
-
msg.setHeader('X-Test', 'value');
|
|
344
|
-
expect(msg.getHeader('x-test')).toBe('value');
|
|
345
|
-
expect(msg.hasHeader('x-test')).toBe(true);
|
|
346
|
-
msg.removeHeader('x-test');
|
|
347
|
-
expect(msg.hasHeader('x-test')).toBe(false);
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
await it('should support getHeaderNames and getHeaders', async () => {
|
|
351
|
-
const OutgoingMessage = gjsHttp.OutgoingMessage;
|
|
352
|
-
const msg = new OutgoingMessage();
|
|
353
|
-
msg.setHeader('Content-Type', 'text/plain');
|
|
354
|
-
msg.setHeader('X-Custom', 'val');
|
|
355
|
-
const names = msg.getHeaderNames();
|
|
356
|
-
expect(names.length).toBe(2);
|
|
357
|
-
const headers = msg.getHeaders();
|
|
358
|
-
expect(headers['content-type']).toBe('text/plain');
|
|
359
|
-
expect(headers['x-custom']).toBe('val');
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
await it('should support appendHeader', async () => {
|
|
363
|
-
const OutgoingMessage = gjsHttp.OutgoingMessage;
|
|
364
|
-
const msg = new OutgoingMessage();
|
|
365
|
-
msg.setHeader('Set-Cookie', 'a=1');
|
|
366
|
-
msg.appendHeader('Set-Cookie', 'b=2');
|
|
367
|
-
const val = msg.getHeader('set-cookie');
|
|
368
|
-
expect(Array.isArray(val)).toBe(true);
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
await it('should have sendDate property', async () => {
|
|
372
|
-
const OutgoingMessage = gjsHttp.OutgoingMessage;
|
|
373
|
-
const msg = new OutgoingMessage();
|
|
374
|
-
expect(typeof msg.sendDate).toBe('boolean');
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
await it('should have sendDate as boolean', async () => {
|
|
378
|
-
const OutgoingMessage = gjsHttp.OutgoingMessage;
|
|
379
|
-
const msg = new OutgoingMessage();
|
|
380
|
-
expect(typeof msg.sendDate).toBe('boolean');
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
await it('should store headers case-insensitively', async () => {
|
|
384
|
-
const OutgoingMessage = gjsHttp.OutgoingMessage;
|
|
385
|
-
const msg = new OutgoingMessage();
|
|
386
|
-
msg.setHeader('Content-Type', 'text/html');
|
|
387
|
-
expect(msg.getHeader('content-type')).toBe('text/html');
|
|
388
|
-
expect(msg.getHeader('CONTENT-TYPE')).toBe('text/html');
|
|
389
|
-
expect(msg.getHeader('Content-Type')).toBe('text/html');
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
await it('should overwrite existing header with setHeader', async () => {
|
|
393
|
-
const OutgoingMessage = gjsHttp.OutgoingMessage;
|
|
394
|
-
const msg = new OutgoingMessage();
|
|
395
|
-
msg.setHeader('X-Test', 'first');
|
|
396
|
-
msg.setHeader('X-Test', 'second');
|
|
397
|
-
expect(msg.getHeader('x-test')).toBe('second');
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
await it('should return undefined for non-existent header', async () => {
|
|
401
|
-
const OutgoingMessage = gjsHttp.OutgoingMessage;
|
|
402
|
-
const msg = new OutgoingMessage();
|
|
403
|
-
expect(msg.getHeader('x-nonexistent')).toBeUndefined();
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
await it('should return false for hasHeader on non-existent header', async () => {
|
|
407
|
-
const OutgoingMessage = gjsHttp.OutgoingMessage;
|
|
408
|
-
const msg = new OutgoingMessage();
|
|
409
|
-
expect(msg.hasHeader('x-nonexistent')).toBe(false);
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
await it('should handle removeHeader for non-existent header without error', async () => {
|
|
413
|
-
const OutgoingMessage = gjsHttp.OutgoingMessage;
|
|
414
|
-
const msg = new OutgoingMessage();
|
|
415
|
-
// Should not throw
|
|
416
|
-
msg.removeHeader('x-nonexistent');
|
|
417
|
-
expect(msg.hasHeader('x-nonexistent')).toBe(false);
|
|
418
|
-
});
|
|
419
|
-
|
|
420
|
-
await it('should return empty arrays when no headers set', async () => {
|
|
421
|
-
const OutgoingMessage = gjsHttp.OutgoingMessage;
|
|
422
|
-
const msg = new OutgoingMessage();
|
|
423
|
-
expect(msg.getHeaderNames().length).toBe(0);
|
|
424
|
-
const headers = msg.getHeaders();
|
|
425
|
-
expect(Object.keys(headers).length).toBe(0);
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
await it('should accept numeric header values via setHeader', async () => {
|
|
429
|
-
const OutgoingMessage = gjsHttp.OutgoingMessage;
|
|
430
|
-
const msg = new OutgoingMessage();
|
|
431
|
-
msg.setHeader('Content-Length', 42);
|
|
432
|
-
const val = msg.getHeader('content-length');
|
|
433
|
-
// Node.js stores as number, GJS stores as string -- both are valid
|
|
434
|
-
expect(val as unknown as number == 42).toBe(true);
|
|
435
|
-
});
|
|
436
|
-
|
|
437
|
-
await it('should accept array header values via setHeader', async () => {
|
|
438
|
-
const OutgoingMessage = gjsHttp.OutgoingMessage;
|
|
439
|
-
const msg = new OutgoingMessage();
|
|
440
|
-
msg.setHeader('Set-Cookie', ['a=1', 'b=2']);
|
|
441
|
-
const val = msg.getHeader('set-cookie');
|
|
442
|
-
expect(Array.isArray(val)).toBe(true);
|
|
443
|
-
});
|
|
444
|
-
|
|
445
|
-
await it('should support appendHeader with array value', async () => {
|
|
446
|
-
const OutgoingMessage = gjsHttp.OutgoingMessage;
|
|
447
|
-
const msg = new OutgoingMessage();
|
|
448
|
-
msg.setHeader('X-Multi', 'first');
|
|
449
|
-
msg.appendHeader('X-Multi', ['second', 'third']);
|
|
450
|
-
const val = msg.getHeader('x-multi');
|
|
451
|
-
expect(Array.isArray(val)).toBe(true);
|
|
452
|
-
});
|
|
453
|
-
|
|
454
|
-
await it('should support appendHeader on non-existent header', async () => {
|
|
455
|
-
const OutgoingMessage = gjsHttp.OutgoingMessage;
|
|
456
|
-
const msg = new OutgoingMessage();
|
|
457
|
-
msg.appendHeader('X-New', 'value');
|
|
458
|
-
expect(msg.getHeader('x-new')).toBe('value');
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
await it('should have headersSent default to false', async () => {
|
|
462
|
-
const OutgoingMessage = gjsHttp.OutgoingMessage;
|
|
463
|
-
const msg = new OutgoingMessage();
|
|
464
|
-
expect(msg.headersSent).toBe(false);
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
await it('should have socket property default to null', async () => {
|
|
468
|
-
const OutgoingMessage = gjsHttp.OutgoingMessage;
|
|
469
|
-
const msg = new OutgoingMessage();
|
|
470
|
-
expect(msg.socket).toBeNull();
|
|
471
|
-
});
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
// --- Agent ---
|
|
475
|
-
await describe('http.Agent', async () => {
|
|
476
|
-
await it('should be constructable', async () => {
|
|
477
|
-
const agent = new http.Agent();
|
|
478
|
-
expect(agent).toBeDefined();
|
|
479
|
-
});
|
|
480
|
-
|
|
481
|
-
await it('should have default properties', async () => {
|
|
482
|
-
const agent = new http.Agent();
|
|
483
|
-
expect(agent.defaultPort).toBe(80);
|
|
484
|
-
expect(agent.maxSockets).toBe(Infinity);
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
await it('should have destroy method', async () => {
|
|
488
|
-
const agent = new http.Agent();
|
|
489
|
-
expect(typeof agent.destroy).toBe('function');
|
|
490
|
-
});
|
|
491
|
-
|
|
492
|
-
await it('should have protocol property', async () => {
|
|
493
|
-
const agent = new gjsHttp.Agent();
|
|
494
|
-
expect(agent.protocol).toBe('http:');
|
|
495
|
-
});
|
|
496
|
-
|
|
497
|
-
await it('should have maxFreeSockets property', async () => {
|
|
498
|
-
const agent = new gjsHttp.Agent();
|
|
499
|
-
expect(agent.maxFreeSockets).toBe(256);
|
|
500
|
-
});
|
|
501
|
-
|
|
502
|
-
await it('should have keepAliveMsecs property', async () => {
|
|
503
|
-
const agent = new gjsHttp.Agent();
|
|
504
|
-
expect(agent.keepAliveMsecs).toBe(1000);
|
|
505
|
-
});
|
|
506
|
-
|
|
507
|
-
await it('should have keepAlive property', async () => {
|
|
508
|
-
const agent = new gjsHttp.Agent();
|
|
509
|
-
expect(agent.keepAlive).toBe(false);
|
|
510
|
-
});
|
|
511
|
-
|
|
512
|
-
await it('should not throw when destroy is called', async () => {
|
|
513
|
-
const agent = new http.Agent();
|
|
514
|
-
expect(() => agent.destroy()).not.toThrow();
|
|
515
|
-
});
|
|
516
|
-
|
|
517
|
-
await it('should be an instance of Agent', async () => {
|
|
518
|
-
const agent = new http.Agent();
|
|
519
|
-
expect(agent instanceof http.Agent).toBe(true);
|
|
520
|
-
});
|
|
521
|
-
});
|
|
522
|
-
|
|
523
|
-
// --- globalAgent ---
|
|
524
|
-
await describe('http.globalAgent', async () => {
|
|
525
|
-
await it('should be an instance of Agent', async () => {
|
|
526
|
-
expect(http.globalAgent instanceof http.Agent).toBe(true);
|
|
527
|
-
});
|
|
528
|
-
|
|
529
|
-
await it('should have defaultPort 80', async () => {
|
|
530
|
-
expect(http.globalAgent.defaultPort).toBe(80);
|
|
531
|
-
});
|
|
532
|
-
|
|
533
|
-
await it('should have maxSockets Infinity', async () => {
|
|
534
|
-
expect(http.globalAgent.maxSockets).toBe(Infinity);
|
|
535
|
-
});
|
|
536
|
-
|
|
537
|
-
await it('should have protocol http:', async () => {
|
|
538
|
-
expect(gjsHttp.globalAgent.protocol).toBe('http:');
|
|
539
|
-
});
|
|
540
|
-
|
|
541
|
-
await it('should have destroy method', async () => {
|
|
542
|
-
expect(typeof http.globalAgent.destroy).toBe('function');
|
|
543
|
-
});
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
// --- IncomingMessage standalone ---
|
|
547
|
-
await describe('http.IncomingMessage standalone', async () => {
|
|
548
|
-
await it('should be constructable', async () => {
|
|
549
|
-
// Node.js requires a socket arg; GJS does not — gjsHttp.IncomingMessage's
|
|
550
|
-
// constructor signature is `(socket?: unknown)` so passing null is fine.
|
|
551
|
-
const msg = new gjsHttp.IncomingMessage(null);
|
|
552
|
-
expect(msg).toBeDefined();
|
|
553
|
-
});
|
|
554
|
-
|
|
555
|
-
await it('should have httpVersion property', async () => {
|
|
556
|
-
const msg = new gjsHttp.IncomingMessage(null);
|
|
557
|
-
// Node.js defaults to null, GJS defaults to '1.1' — both are valid initial values
|
|
558
|
-
expect(msg.httpVersion === null || msg.httpVersion === '1.1').toBe(true);
|
|
559
|
-
});
|
|
560
|
-
|
|
561
|
-
await it('should have httpVersionMajor and httpVersionMinor properties', async () => {
|
|
562
|
-
const msg = new gjsHttp.IncomingMessage(null);
|
|
563
|
-
// Node.js defaults to null, GJS defaults to 1
|
|
564
|
-
expect(msg.httpVersionMajor === null || msg.httpVersionMajor === 1).toBe(true);
|
|
565
|
-
expect(msg.httpVersionMinor === null || msg.httpVersionMinor === 1).toBe(true);
|
|
566
|
-
});
|
|
567
|
-
|
|
568
|
-
await it('should have empty headers object', async () => {
|
|
569
|
-
const msg = new gjsHttp.IncomingMessage(null);
|
|
570
|
-
expect(typeof msg.headers).toBe('object');
|
|
571
|
-
expect(Object.keys(msg.headers).length).toBe(0);
|
|
572
|
-
});
|
|
573
|
-
|
|
574
|
-
await it('should have empty rawHeaders array', async () => {
|
|
575
|
-
const msg = new gjsHttp.IncomingMessage(null);
|
|
576
|
-
expect(Array.isArray(msg.rawHeaders)).toBe(true);
|
|
577
|
-
expect(msg.rawHeaders.length).toBe(0);
|
|
578
|
-
});
|
|
579
|
-
|
|
580
|
-
await it('should have method property', async () => {
|
|
581
|
-
const msg = new gjsHttp.IncomingMessage(null);
|
|
582
|
-
// Node.js defaults to null, GJS defaults to undefined
|
|
583
|
-
expect(msg.method === null || msg.method === undefined).toBe(true);
|
|
584
|
-
});
|
|
585
|
-
|
|
586
|
-
await it('should have url property', async () => {
|
|
587
|
-
const msg = new gjsHttp.IncomingMessage(null);
|
|
588
|
-
// Node.js defaults to '', GJS defaults to undefined — both are falsy
|
|
589
|
-
expect(!msg.url || msg.url === '').toBe(true);
|
|
590
|
-
});
|
|
591
|
-
|
|
592
|
-
await it('should have statusCode property', async () => {
|
|
593
|
-
const msg = new gjsHttp.IncomingMessage(null);
|
|
594
|
-
// Node.js defaults to null, GJS defaults to undefined
|
|
595
|
-
expect(msg.statusCode === null || msg.statusCode === undefined).toBe(true);
|
|
596
|
-
});
|
|
597
|
-
|
|
598
|
-
await it('should have statusMessage property', async () => {
|
|
599
|
-
const msg = new gjsHttp.IncomingMessage(null);
|
|
600
|
-
// Node.js defaults to null, GJS defaults to undefined
|
|
601
|
-
expect(msg.statusMessage === null || msg.statusMessage === undefined || msg.statusMessage === '').toBe(true);
|
|
602
|
-
});
|
|
603
|
-
|
|
604
|
-
await it('should have complete default to false', async () => {
|
|
605
|
-
const msg = new gjsHttp.IncomingMessage(null);
|
|
606
|
-
expect(msg.complete).toBe(false);
|
|
607
|
-
});
|
|
608
|
-
|
|
609
|
-
await it('should have aborted default to false', async () => {
|
|
610
|
-
const msg = new gjsHttp.IncomingMessage(null);
|
|
611
|
-
expect(msg.aborted).toBe(false);
|
|
612
|
-
});
|
|
613
|
-
|
|
614
|
-
await it('should have socket property', async () => {
|
|
615
|
-
const msg = new gjsHttp.IncomingMessage(null);
|
|
616
|
-
expect(msg.socket).toBeNull();
|
|
617
|
-
});
|
|
618
|
-
|
|
619
|
-
await it('should have setTimeout method', async () => {
|
|
620
|
-
const msg = new gjsHttp.IncomingMessage(null);
|
|
621
|
-
expect(typeof msg.setTimeout).toBe('function');
|
|
622
|
-
});
|
|
623
|
-
|
|
624
|
-
await it('should have destroy method', async () => {
|
|
625
|
-
const msg = new gjsHttp.IncomingMessage(null);
|
|
626
|
-
expect(typeof msg.destroy).toBe('function');
|
|
627
|
-
});
|
|
628
|
-
|
|
629
|
-
await it('should be a Readable stream', async () => {
|
|
630
|
-
const msg = new gjsHttp.IncomingMessage(null);
|
|
631
|
-
expect(typeof msg.on).toBe('function');
|
|
632
|
-
expect(typeof msg.read).toBe('function');
|
|
633
|
-
expect(typeof msg.pipe).toBe('function');
|
|
634
|
-
});
|
|
635
|
-
});
|
|
636
|
-
|
|
637
|
-
// --- Server round-trip ---
|
|
638
|
-
await describe('http.createServer round-trip', async () => {
|
|
639
|
-
await it('should create a server and handle a GET request', async () => {
|
|
640
|
-
const server = http.createServer((req, res) => {
|
|
641
|
-
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
642
|
-
res.end('Hello from server');
|
|
643
|
-
});
|
|
644
|
-
|
|
645
|
-
await new Promise<void>((resolve, reject) => {
|
|
646
|
-
server.listen(0, () => {
|
|
647
|
-
const addr = server.address() as { port: number };
|
|
648
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
649
|
-
const chunks: Buffer[] = [];
|
|
650
|
-
res.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
651
|
-
res.on('end', () => {
|
|
652
|
-
expect(res.statusCode).toBe(200);
|
|
653
|
-
expect(Buffer.concat(chunks).toString()).toBe('Hello from server');
|
|
654
|
-
server.close(() => resolve());
|
|
655
|
-
});
|
|
656
|
-
}).on('error', reject);
|
|
657
|
-
});
|
|
658
|
-
server.on('error', reject);
|
|
659
|
-
});
|
|
660
|
-
});
|
|
661
|
-
|
|
662
|
-
await it('should receive request headers', async () => {
|
|
663
|
-
const server = http.createServer((req, res) => {
|
|
664
|
-
res.writeHead(200);
|
|
665
|
-
res.end(req.headers['x-test'] || 'no header');
|
|
666
|
-
});
|
|
667
|
-
|
|
668
|
-
await new Promise<void>((resolve, reject) => {
|
|
669
|
-
server.listen(0, () => {
|
|
670
|
-
const addr = server.address() as { port: number };
|
|
671
|
-
const req = http.request({
|
|
672
|
-
hostname: '127.0.0.1',
|
|
673
|
-
port: addr.port,
|
|
674
|
-
path: '/',
|
|
675
|
-
headers: { 'X-Test': 'custom-value' },
|
|
676
|
-
}, (res) => {
|
|
677
|
-
const chunks: Buffer[] = [];
|
|
678
|
-
res.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
679
|
-
res.on('end', () => {
|
|
680
|
-
expect(Buffer.concat(chunks).toString()).toBe('custom-value');
|
|
681
|
-
server.close(() => resolve());
|
|
682
|
-
});
|
|
683
|
-
});
|
|
684
|
-
req.on('error', reject);
|
|
685
|
-
req.end();
|
|
686
|
-
});
|
|
687
|
-
server.on('error', reject);
|
|
688
|
-
});
|
|
689
|
-
});
|
|
690
|
-
|
|
691
|
-
await it('should handle POST with body', async () => {
|
|
692
|
-
const server = http.createServer((req, res) => {
|
|
693
|
-
const chunks: Buffer[] = [];
|
|
694
|
-
req.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
695
|
-
req.on('end', () => {
|
|
696
|
-
const body = Buffer.concat(chunks).toString();
|
|
697
|
-
res.writeHead(200);
|
|
698
|
-
res.end(`received: ${body}`);
|
|
699
|
-
});
|
|
700
|
-
});
|
|
701
|
-
|
|
702
|
-
await new Promise<void>((resolve, reject) => {
|
|
703
|
-
server.listen(0, () => {
|
|
704
|
-
const addr = server.address() as { port: number };
|
|
705
|
-
const req = http.request({
|
|
706
|
-
hostname: '127.0.0.1',
|
|
707
|
-
port: addr.port,
|
|
708
|
-
path: '/post',
|
|
709
|
-
method: 'POST',
|
|
710
|
-
}, (res) => {
|
|
711
|
-
const chunks: Buffer[] = [];
|
|
712
|
-
res.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
713
|
-
res.on('end', () => {
|
|
714
|
-
expect(Buffer.concat(chunks).toString()).toBe('received: hello body');
|
|
715
|
-
server.close(() => resolve());
|
|
716
|
-
});
|
|
717
|
-
});
|
|
718
|
-
req.on('error', reject);
|
|
719
|
-
req.write('hello body');
|
|
720
|
-
req.end();
|
|
721
|
-
});
|
|
722
|
-
server.on('error', reject);
|
|
723
|
-
});
|
|
724
|
-
});
|
|
725
|
-
|
|
726
|
-
await it('should handle 404 status code', async () => {
|
|
727
|
-
const server = http.createServer((req, res) => {
|
|
728
|
-
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
729
|
-
res.end('Not Found');
|
|
730
|
-
});
|
|
731
|
-
|
|
732
|
-
await new Promise<void>((resolve, reject) => {
|
|
733
|
-
server.listen(0, () => {
|
|
734
|
-
const addr = server.address() as { port: number };
|
|
735
|
-
http.get(`http://127.0.0.1:${addr.port}/missing`, (res) => {
|
|
736
|
-
expect(res.statusCode).toBe(404);
|
|
737
|
-
const chunks: Buffer[] = [];
|
|
738
|
-
res.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
739
|
-
res.on('end', () => {
|
|
740
|
-
expect(Buffer.concat(chunks).toString()).toBe('Not Found');
|
|
741
|
-
server.close(() => resolve());
|
|
742
|
-
});
|
|
743
|
-
}).on('error', reject);
|
|
744
|
-
});
|
|
745
|
-
server.on('error', reject);
|
|
746
|
-
});
|
|
747
|
-
});
|
|
748
|
-
|
|
749
|
-
await it('should expose response headers', async () => {
|
|
750
|
-
const server = http.createServer((req, res) => {
|
|
751
|
-
res.writeHead(200, {
|
|
752
|
-
'X-Response-Header': 'test-value',
|
|
753
|
-
'Content-Type': 'text/plain',
|
|
754
|
-
});
|
|
755
|
-
res.end('ok');
|
|
756
|
-
});
|
|
757
|
-
|
|
758
|
-
await new Promise<void>((resolve, reject) => {
|
|
759
|
-
server.listen(0, () => {
|
|
760
|
-
const addr = server.address() as { port: number };
|
|
761
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
762
|
-
expect(res.headers['x-response-header']).toBe('test-value');
|
|
763
|
-
expect(res.headers['content-type']).toBe('text/plain');
|
|
764
|
-
res.on('data', () => {});
|
|
765
|
-
res.on('end', () => {
|
|
766
|
-
server.close(() => resolve());
|
|
767
|
-
});
|
|
768
|
-
}).on('error', reject);
|
|
769
|
-
});
|
|
770
|
-
server.on('error', reject);
|
|
771
|
-
});
|
|
772
|
-
});
|
|
773
|
-
|
|
774
|
-
await it('should expose request method and url on server', async () => {
|
|
775
|
-
const server = http.createServer((req, res) => {
|
|
776
|
-
res.writeHead(200);
|
|
777
|
-
res.end(`${req.method} ${req.url}`);
|
|
778
|
-
});
|
|
779
|
-
|
|
780
|
-
await new Promise<void>((resolve, reject) => {
|
|
781
|
-
server.listen(0, () => {
|
|
782
|
-
const addr = server.address() as { port: number };
|
|
783
|
-
http.get(`http://127.0.0.1:${addr.port}/test-path`, (res) => {
|
|
784
|
-
const chunks: Buffer[] = [];
|
|
785
|
-
res.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
786
|
-
res.on('end', () => {
|
|
787
|
-
expect(Buffer.concat(chunks).toString()).toBe('GET /test-path');
|
|
788
|
-
server.close(() => resolve());
|
|
789
|
-
});
|
|
790
|
-
}).on('error', reject);
|
|
791
|
-
});
|
|
792
|
-
server.on('error', reject);
|
|
793
|
-
});
|
|
794
|
-
});
|
|
795
|
-
});
|
|
796
|
-
|
|
797
|
-
// --- ServerResponse API ---
|
|
798
|
-
await describe('ServerResponse API', async () => {
|
|
799
|
-
await it('should support setHeader/getHeader/hasHeader/removeHeader', async () => {
|
|
800
|
-
const server = http.createServer((req, res) => {
|
|
801
|
-
res.setHeader('X-Custom', 'value1');
|
|
802
|
-
expect(res.getHeader('X-Custom')).toBe('value1');
|
|
803
|
-
expect(res.hasHeader('X-Custom')).toBeTruthy();
|
|
804
|
-
res.removeHeader('X-Custom');
|
|
805
|
-
expect(res.hasHeader('X-Custom')).toBeFalsy();
|
|
806
|
-
res.writeHead(200);
|
|
807
|
-
res.end('ok');
|
|
808
|
-
});
|
|
809
|
-
|
|
810
|
-
await new Promise<void>((resolve, reject) => {
|
|
811
|
-
server.listen(0, () => {
|
|
812
|
-
const addr = server.address() as { port: number };
|
|
813
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
814
|
-
res.on('data', () => {});
|
|
815
|
-
res.on('end', () => server.close(() => resolve()));
|
|
816
|
-
}).on('error', reject);
|
|
817
|
-
});
|
|
818
|
-
server.on('error', reject);
|
|
819
|
-
});
|
|
820
|
-
});
|
|
821
|
-
|
|
822
|
-
await it('should support getHeaderNames and getHeaders', async () => {
|
|
823
|
-
const server = http.createServer((req, res) => {
|
|
824
|
-
res.setHeader('X-A', 'a');
|
|
825
|
-
res.setHeader('X-B', 'b');
|
|
826
|
-
const names = res.getHeaderNames();
|
|
827
|
-
expect(names.length).toBe(2);
|
|
828
|
-
const headers = res.getHeaders();
|
|
829
|
-
expect(headers['x-a']).toBe('a');
|
|
830
|
-
expect(headers['x-b']).toBe('b');
|
|
831
|
-
res.writeHead(200);
|
|
832
|
-
res.end('ok');
|
|
833
|
-
});
|
|
834
|
-
|
|
835
|
-
await new Promise<void>((resolve, reject) => {
|
|
836
|
-
server.listen(0, () => {
|
|
837
|
-
const addr = server.address() as { port: number };
|
|
838
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
839
|
-
res.on('data', () => {});
|
|
840
|
-
res.on('end', () => server.close(() => resolve()));
|
|
841
|
-
}).on('error', reject);
|
|
842
|
-
});
|
|
843
|
-
server.on('error', reject);
|
|
844
|
-
});
|
|
845
|
-
});
|
|
846
|
-
|
|
847
|
-
await it('should support appendHeader', async () => {
|
|
848
|
-
const server = http.createServer((req, res) => {
|
|
849
|
-
res.setHeader('X-Multi', 'first');
|
|
850
|
-
res.appendHeader('X-Multi', 'second');
|
|
851
|
-
const val = res.getHeader('X-Multi');
|
|
852
|
-
expect(Array.isArray(val)).toBeTruthy();
|
|
853
|
-
res.writeHead(200);
|
|
854
|
-
res.end('ok');
|
|
855
|
-
});
|
|
856
|
-
|
|
857
|
-
await new Promise<void>((resolve, reject) => {
|
|
858
|
-
server.listen(0, () => {
|
|
859
|
-
const addr = server.address() as { port: number };
|
|
860
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
861
|
-
res.on('data', () => {});
|
|
862
|
-
res.on('end', () => server.close(() => resolve()));
|
|
863
|
-
}).on('error', reject);
|
|
864
|
-
});
|
|
865
|
-
server.on('error', reject);
|
|
866
|
-
});
|
|
867
|
-
});
|
|
868
|
-
|
|
869
|
-
await it('should support writeContinue', async () => {
|
|
870
|
-
const server = http.createServer((req, res) => {
|
|
871
|
-
let continueCalled = false;
|
|
872
|
-
res.writeContinue(() => { continueCalled = true; });
|
|
873
|
-
res.writeHead(200);
|
|
874
|
-
res.end('ok');
|
|
875
|
-
});
|
|
876
|
-
|
|
877
|
-
await new Promise<void>((resolve, reject) => {
|
|
878
|
-
server.listen(0, () => {
|
|
879
|
-
const addr = server.address() as { port: number };
|
|
880
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
881
|
-
res.on('data', () => {});
|
|
882
|
-
res.on('end', () => server.close(() => resolve()));
|
|
883
|
-
}).on('error', reject);
|
|
884
|
-
});
|
|
885
|
-
server.on('error', reject);
|
|
886
|
-
});
|
|
887
|
-
});
|
|
888
|
-
|
|
889
|
-
await it('should support flushHeaders', async () => {
|
|
890
|
-
const server = http.createServer((req, res) => {
|
|
891
|
-
res.writeHead(200, { 'X-Flush': 'test' });
|
|
892
|
-
res.flushHeaders();
|
|
893
|
-
expect(res.headersSent).toBeTruthy();
|
|
894
|
-
res.end('ok');
|
|
895
|
-
});
|
|
896
|
-
|
|
897
|
-
await new Promise<void>((resolve, reject) => {
|
|
898
|
-
server.listen(0, () => {
|
|
899
|
-
const addr = server.address() as { port: number };
|
|
900
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
901
|
-
res.on('data', () => {});
|
|
902
|
-
res.on('end', () => server.close(() => resolve()));
|
|
903
|
-
}).on('error', reject);
|
|
904
|
-
});
|
|
905
|
-
server.on('error', reject);
|
|
906
|
-
});
|
|
907
|
-
});
|
|
908
|
-
|
|
909
|
-
await it('should set statusCode and statusMessage', async () => {
|
|
910
|
-
const server = http.createServer((req, res) => {
|
|
911
|
-
res.statusCode = 201;
|
|
912
|
-
res.statusMessage = 'Created';
|
|
913
|
-
res.end('created');
|
|
914
|
-
});
|
|
915
|
-
|
|
916
|
-
await new Promise<void>((resolve, reject) => {
|
|
917
|
-
server.listen(0, () => {
|
|
918
|
-
const addr = server.address() as { port: number };
|
|
919
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
920
|
-
expect(res.statusCode).toBe(201);
|
|
921
|
-
res.on('data', () => {});
|
|
922
|
-
res.on('end', () => server.close(() => resolve()));
|
|
923
|
-
}).on('error', reject);
|
|
924
|
-
});
|
|
925
|
-
server.on('error', reject);
|
|
926
|
-
});
|
|
927
|
-
});
|
|
928
|
-
|
|
929
|
-
await it('should handle query strings', async () => {
|
|
930
|
-
const server = http.createServer((req, res) => {
|
|
931
|
-
res.writeHead(200);
|
|
932
|
-
res.end(req.url);
|
|
933
|
-
});
|
|
934
|
-
|
|
935
|
-
await new Promise<void>((resolve, reject) => {
|
|
936
|
-
server.listen(0, () => {
|
|
937
|
-
const addr = server.address() as { port: number };
|
|
938
|
-
http.get(`http://127.0.0.1:${addr.port}/path?key=value`, (res) => {
|
|
939
|
-
const chunks: Buffer[] = [];
|
|
940
|
-
res.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
941
|
-
res.on('end', () => {
|
|
942
|
-
expect(Buffer.concat(chunks).toString()).toBe('/path?key=value');
|
|
943
|
-
server.close(() => resolve());
|
|
944
|
-
});
|
|
945
|
-
}).on('error', reject);
|
|
946
|
-
});
|
|
947
|
-
server.on('error', reject);
|
|
948
|
-
});
|
|
949
|
-
});
|
|
950
|
-
|
|
951
|
-
await it('should handle multiple sequential requests', async () => {
|
|
952
|
-
let requestCount = 0;
|
|
953
|
-
const server = http.createServer((req, res) => {
|
|
954
|
-
requestCount++;
|
|
955
|
-
res.writeHead(200);
|
|
956
|
-
res.end(`request ${requestCount}`);
|
|
957
|
-
});
|
|
958
|
-
|
|
959
|
-
await new Promise<void>((resolve, reject) => {
|
|
960
|
-
server.listen(0, () => {
|
|
961
|
-
const addr = server.address() as { port: number };
|
|
962
|
-
// First request
|
|
963
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res1) => {
|
|
964
|
-
res1.on('data', () => {});
|
|
965
|
-
res1.on('end', () => {
|
|
966
|
-
// Second request
|
|
967
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res2) => {
|
|
968
|
-
res2.on('data', () => {});
|
|
969
|
-
res2.on('end', () => {
|
|
970
|
-
expect(requestCount).toBe(2);
|
|
971
|
-
server.close(() => resolve());
|
|
972
|
-
});
|
|
973
|
-
}).on('error', reject);
|
|
974
|
-
});
|
|
975
|
-
}).on('error', reject);
|
|
976
|
-
});
|
|
977
|
-
server.on('error', reject);
|
|
978
|
-
});
|
|
979
|
-
});
|
|
980
|
-
|
|
981
|
-
await it('should support JSON response', async () => {
|
|
982
|
-
const server = http.createServer((req, res) => {
|
|
983
|
-
const body = JSON.stringify({ hello: 'world' });
|
|
984
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
985
|
-
res.end(body);
|
|
986
|
-
});
|
|
987
|
-
|
|
988
|
-
await new Promise<void>((resolve, reject) => {
|
|
989
|
-
server.listen(0, () => {
|
|
990
|
-
const addr = server.address() as { port: number };
|
|
991
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
992
|
-
const chunks: Buffer[] = [];
|
|
993
|
-
res.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
994
|
-
res.on('end', () => {
|
|
995
|
-
const data = JSON.parse(Buffer.concat(chunks).toString());
|
|
996
|
-
expect(data.hello).toBe('world');
|
|
997
|
-
server.close(() => resolve());
|
|
998
|
-
});
|
|
999
|
-
}).on('error', reject);
|
|
1000
|
-
});
|
|
1001
|
-
server.on('error', reject);
|
|
1002
|
-
});
|
|
1003
|
-
});
|
|
1004
|
-
});
|
|
1005
|
-
|
|
1006
|
-
// --- Server lifecycle ---
|
|
1007
|
-
await describe('http.Server lifecycle', async () => {
|
|
1008
|
-
await it('should emit listening event', async () => {
|
|
1009
|
-
const server = http.createServer();
|
|
1010
|
-
const listened = await new Promise<boolean>((resolve) => {
|
|
1011
|
-
server.on('listening', () => resolve(true));
|
|
1012
|
-
server.listen(0);
|
|
1013
|
-
});
|
|
1014
|
-
expect(listened).toBeTruthy();
|
|
1015
|
-
expect(server.listening).toBeTruthy();
|
|
1016
|
-
server.close();
|
|
1017
|
-
});
|
|
1018
|
-
|
|
1019
|
-
await it('should emit close event', async () => {
|
|
1020
|
-
const server = http.createServer();
|
|
1021
|
-
await new Promise<void>((resolve) => {
|
|
1022
|
-
server.listen(0, () => {
|
|
1023
|
-
server.close(() => resolve());
|
|
1024
|
-
});
|
|
1025
|
-
});
|
|
1026
|
-
expect(server.listening).toBeFalsy();
|
|
1027
|
-
});
|
|
1028
|
-
|
|
1029
|
-
await it('should return address info', async () => {
|
|
1030
|
-
const server = http.createServer();
|
|
1031
|
-
await new Promise<void>((resolve) => {
|
|
1032
|
-
server.listen(0, () => {
|
|
1033
|
-
const addr = server.address() as { port: number; family: string };
|
|
1034
|
-
expect(typeof addr.port).toBe('number');
|
|
1035
|
-
expect(addr.port > 0).toBeTruthy();
|
|
1036
|
-
server.close(() => resolve());
|
|
1037
|
-
});
|
|
1038
|
-
});
|
|
1039
|
-
});
|
|
1040
|
-
|
|
1041
|
-
await it('should support setTimeout', async () => {
|
|
1042
|
-
const server = http.createServer();
|
|
1043
|
-
server.setTimeout(5000);
|
|
1044
|
-
expect(server.timeout).toBe(5000);
|
|
1045
|
-
});
|
|
1046
|
-
|
|
1047
|
-
await it('should return null address before listening', async () => {
|
|
1048
|
-
const server = http.createServer();
|
|
1049
|
-
expect(server.address()).toBeNull();
|
|
1050
|
-
});
|
|
1051
|
-
|
|
1052
|
-
await it('should set listening to false initially', async () => {
|
|
1053
|
-
const server = http.createServer();
|
|
1054
|
-
expect(server.listening).toBe(false);
|
|
1055
|
-
});
|
|
1056
|
-
|
|
1057
|
-
await it('should accept requestListener in constructor', async () => {
|
|
1058
|
-
let called = false;
|
|
1059
|
-
const server = http.createServer((req, res) => {
|
|
1060
|
-
called = true;
|
|
1061
|
-
res.end();
|
|
1062
|
-
});
|
|
1063
|
-
expect(server).toBeDefined();
|
|
1064
|
-
// Server was created with listener, just verify it exists
|
|
1065
|
-
server.close();
|
|
1066
|
-
});
|
|
1067
|
-
|
|
1068
|
-
await it('should accept no arguments to createServer', async () => {
|
|
1069
|
-
const server = http.createServer();
|
|
1070
|
-
expect(server).toBeDefined();
|
|
1071
|
-
expect(server.listening).toBe(false);
|
|
1072
|
-
});
|
|
1073
|
-
|
|
1074
|
-
await it('should return this from setTimeout', async () => {
|
|
1075
|
-
const server = http.createServer();
|
|
1076
|
-
const result = server.setTimeout(3000);
|
|
1077
|
-
expect(result).toBe(server);
|
|
1078
|
-
});
|
|
1079
|
-
|
|
1080
|
-
await it('should return this from close', async () => {
|
|
1081
|
-
const server = http.createServer();
|
|
1082
|
-
await new Promise<void>((resolve) => {
|
|
1083
|
-
server.listen(0, () => {
|
|
1084
|
-
const result = server.close(() => resolve());
|
|
1085
|
-
expect(result).toBe(server);
|
|
1086
|
-
});
|
|
1087
|
-
});
|
|
1088
|
-
});
|
|
1089
|
-
|
|
1090
|
-
await it('should return this from listen', async () => {
|
|
1091
|
-
const server = http.createServer();
|
|
1092
|
-
const result = server.listen(0);
|
|
1093
|
-
expect(result).toBe(server);
|
|
1094
|
-
await new Promise<void>((resolve) => {
|
|
1095
|
-
server.close(() => resolve());
|
|
1096
|
-
});
|
|
1097
|
-
});
|
|
1098
|
-
});
|
|
1099
|
-
|
|
1100
|
-
// --- Server properties ---
|
|
1101
|
-
await describe('http.Server properties', async () => {
|
|
1102
|
-
await it('should have timeout properties', async () => {
|
|
1103
|
-
const server = http.createServer();
|
|
1104
|
-
expect(server.maxHeadersCount).toBeDefined();
|
|
1105
|
-
expect(server.keepAliveTimeout).toBeDefined();
|
|
1106
|
-
expect(server.headersTimeout).toBeDefined();
|
|
1107
|
-
expect(server.requestTimeout).toBeDefined();
|
|
1108
|
-
});
|
|
1109
|
-
|
|
1110
|
-
await it('should have default timeout values', async () => {
|
|
1111
|
-
const server = http.createServer();
|
|
1112
|
-
expect(typeof server.timeout).toBe('number');
|
|
1113
|
-
expect(typeof server.keepAliveTimeout).toBe('number');
|
|
1114
|
-
expect(typeof server.headersTimeout).toBe('number');
|
|
1115
|
-
expect(typeof server.requestTimeout).toBe('number');
|
|
1116
|
-
});
|
|
1117
|
-
|
|
1118
|
-
await it('should have maxHeadersCount property', async () => {
|
|
1119
|
-
const server = http.createServer();
|
|
1120
|
-
// Node.js defaults to null, GJS defaults to a number — both are valid
|
|
1121
|
-
expect(server.maxHeadersCount !== undefined).toBe(true);
|
|
1122
|
-
});
|
|
1123
|
-
|
|
1124
|
-
await it('should be an EventEmitter', async () => {
|
|
1125
|
-
const server = http.createServer();
|
|
1126
|
-
expect(typeof server.on).toBe('function');
|
|
1127
|
-
expect(typeof server.emit).toBe('function');
|
|
1128
|
-
expect(typeof server.removeListener).toBe('function');
|
|
1129
|
-
});
|
|
1130
|
-
|
|
1131
|
-
await it('should support empty body response', async () => {
|
|
1132
|
-
const server = http.createServer((req, res) => {
|
|
1133
|
-
res.writeHead(204);
|
|
1134
|
-
res.end();
|
|
1135
|
-
});
|
|
1136
|
-
|
|
1137
|
-
await new Promise<void>((resolve, reject) => {
|
|
1138
|
-
server.listen(0, () => {
|
|
1139
|
-
const addr = server.address() as { port: number };
|
|
1140
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
1141
|
-
expect(res.statusCode).toBe(204);
|
|
1142
|
-
const chunks: Buffer[] = [];
|
|
1143
|
-
res.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
1144
|
-
res.on('end', () => {
|
|
1145
|
-
expect(Buffer.concat(chunks).length).toBe(0);
|
|
1146
|
-
server.close(() => resolve());
|
|
1147
|
-
});
|
|
1148
|
-
}).on('error', reject);
|
|
1149
|
-
});
|
|
1150
|
-
server.on('error', reject);
|
|
1151
|
-
});
|
|
1152
|
-
});
|
|
1153
|
-
|
|
1154
|
-
await it('should handle large response body', async () => {
|
|
1155
|
-
const largeBody = 'x'.repeat(10000);
|
|
1156
|
-
const server = http.createServer((req, res) => {
|
|
1157
|
-
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
1158
|
-
res.end(largeBody);
|
|
1159
|
-
});
|
|
1160
|
-
|
|
1161
|
-
await new Promise<void>((resolve, reject) => {
|
|
1162
|
-
server.listen(0, () => {
|
|
1163
|
-
const addr = server.address() as { port: number };
|
|
1164
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
1165
|
-
const chunks: Buffer[] = [];
|
|
1166
|
-
res.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
1167
|
-
res.on('end', () => {
|
|
1168
|
-
expect(Buffer.concat(chunks).toString().length).toBe(10000);
|
|
1169
|
-
server.close(() => resolve());
|
|
1170
|
-
});
|
|
1171
|
-
}).on('error', reject);
|
|
1172
|
-
});
|
|
1173
|
-
server.on('error', reject);
|
|
1174
|
-
});
|
|
1175
|
-
});
|
|
1176
|
-
});
|
|
1177
|
-
|
|
1178
|
-
// --- IncomingMessage via server ---
|
|
1179
|
-
await describe('http.IncomingMessage', async () => {
|
|
1180
|
-
await it('should have httpVersion', async () => {
|
|
1181
|
-
const server = http.createServer((req, res) => {
|
|
1182
|
-
res.writeHead(200);
|
|
1183
|
-
res.end(req.httpVersion);
|
|
1184
|
-
});
|
|
1185
|
-
|
|
1186
|
-
await new Promise<void>((resolve, reject) => {
|
|
1187
|
-
server.listen(0, () => {
|
|
1188
|
-
const addr = server.address() as { port: number };
|
|
1189
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
1190
|
-
expect(res.httpVersion).toBeDefined();
|
|
1191
|
-
const chunks: Buffer[] = [];
|
|
1192
|
-
res.on('data', (chunk: Buffer) => chunks.push(chunk));
|
|
1193
|
-
res.on('end', () => {
|
|
1194
|
-
server.close(() => resolve());
|
|
1195
|
-
});
|
|
1196
|
-
}).on('error', reject);
|
|
1197
|
-
});
|
|
1198
|
-
server.on('error', reject);
|
|
1199
|
-
});
|
|
1200
|
-
});
|
|
1201
|
-
|
|
1202
|
-
await it('should expose rawHeaders', async () => {
|
|
1203
|
-
const server = http.createServer((req, res) => {
|
|
1204
|
-
// rawHeaders should be an array of [name, value, name, value, ...]
|
|
1205
|
-
expect(Array.isArray(req.rawHeaders)).toBeTruthy();
|
|
1206
|
-
expect(req.rawHeaders.length > 0).toBeTruthy();
|
|
1207
|
-
res.writeHead(200);
|
|
1208
|
-
res.end('ok');
|
|
1209
|
-
});
|
|
1210
|
-
|
|
1211
|
-
await new Promise<void>((resolve, reject) => {
|
|
1212
|
-
server.listen(0, () => {
|
|
1213
|
-
const addr = server.address() as { port: number };
|
|
1214
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
1215
|
-
res.on('data', () => {});
|
|
1216
|
-
res.on('end', () => server.close(() => resolve()));
|
|
1217
|
-
}).on('error', reject);
|
|
1218
|
-
});
|
|
1219
|
-
server.on('error', reject);
|
|
1220
|
-
});
|
|
1221
|
-
});
|
|
1222
|
-
|
|
1223
|
-
await it('should have rawHeaders length be even (name-value pairs)', async () => {
|
|
1224
|
-
const server = http.createServer((req, res) => {
|
|
1225
|
-
expect(req.rawHeaders.length % 2).toBe(0);
|
|
1226
|
-
res.writeHead(200);
|
|
1227
|
-
res.end('ok');
|
|
1228
|
-
});
|
|
1229
|
-
|
|
1230
|
-
await new Promise<void>((resolve, reject) => {
|
|
1231
|
-
server.listen(0, () => {
|
|
1232
|
-
const addr = server.address() as { port: number };
|
|
1233
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
1234
|
-
res.on('data', () => {});
|
|
1235
|
-
res.on('end', () => server.close(() => resolve()));
|
|
1236
|
-
}).on('error', reject);
|
|
1237
|
-
});
|
|
1238
|
-
server.on('error', reject);
|
|
1239
|
-
});
|
|
1240
|
-
});
|
|
1241
|
-
|
|
1242
|
-
await it('should have complete set to true after end', async () => {
|
|
1243
|
-
const server = http.createServer((req, res) => {
|
|
1244
|
-
req.on('end', () => {
|
|
1245
|
-
expect(req.complete).toBe(true);
|
|
1246
|
-
});
|
|
1247
|
-
req.resume(); // consume the body
|
|
1248
|
-
res.writeHead(200);
|
|
1249
|
-
res.end('ok');
|
|
1250
|
-
});
|
|
1251
|
-
|
|
1252
|
-
await new Promise<void>((resolve, reject) => {
|
|
1253
|
-
server.listen(0, () => {
|
|
1254
|
-
const addr = server.address() as { port: number };
|
|
1255
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
1256
|
-
res.on('data', () => {});
|
|
1257
|
-
res.on('end', () => server.close(() => resolve()));
|
|
1258
|
-
}).on('error', reject);
|
|
1259
|
-
});
|
|
1260
|
-
server.on('error', reject);
|
|
1261
|
-
});
|
|
1262
|
-
});
|
|
1263
|
-
});
|
|
1264
|
-
|
|
1265
|
-
// --- Server.address() details ---
|
|
1266
|
-
await describe('http.Server address', async () => {
|
|
1267
|
-
await it('should return object with port, family, address', async () => {
|
|
1268
|
-
const server = http.createServer();
|
|
1269
|
-
await new Promise<void>((resolve) => {
|
|
1270
|
-
server.listen(0, () => {
|
|
1271
|
-
const addr = server.address() as { port: number; family: string; address: string };
|
|
1272
|
-
expect(addr).toBeDefined();
|
|
1273
|
-
expect(typeof addr.port).toBe('number');
|
|
1274
|
-
expect(typeof addr.family).toBe('string');
|
|
1275
|
-
expect(typeof addr.address).toBe('string');
|
|
1276
|
-
server.close(() => resolve());
|
|
1277
|
-
});
|
|
1278
|
-
});
|
|
1279
|
-
});
|
|
1280
|
-
|
|
1281
|
-
await it('should allocate a random port when 0 is specified', async () => {
|
|
1282
|
-
const server = http.createServer();
|
|
1283
|
-
await new Promise<void>((resolve) => {
|
|
1284
|
-
server.listen(0, () => {
|
|
1285
|
-
const addr = server.address() as { port: number };
|
|
1286
|
-
expect(addr.port).toBeGreaterThan(0);
|
|
1287
|
-
expect(addr.port).toBeLessThan(65536);
|
|
1288
|
-
server.close(() => resolve());
|
|
1289
|
-
});
|
|
1290
|
-
});
|
|
1291
|
-
});
|
|
1292
|
-
});
|
|
1293
|
-
|
|
1294
|
-
// --- ServerResponse writeHead variants ---
|
|
1295
|
-
await describe('ServerResponse writeHead', async () => {
|
|
1296
|
-
await it('should accept statusCode only', async () => {
|
|
1297
|
-
const server = http.createServer((req, res) => {
|
|
1298
|
-
res.writeHead(200);
|
|
1299
|
-
res.end('ok');
|
|
1300
|
-
});
|
|
1301
|
-
|
|
1302
|
-
await new Promise<void>((resolve, reject) => {
|
|
1303
|
-
server.listen(0, () => {
|
|
1304
|
-
const addr = server.address() as { port: number };
|
|
1305
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
1306
|
-
expect(res.statusCode).toBe(200);
|
|
1307
|
-
res.on('data', () => {});
|
|
1308
|
-
res.on('end', () => server.close(() => resolve()));
|
|
1309
|
-
}).on('error', reject);
|
|
1310
|
-
});
|
|
1311
|
-
server.on('error', reject);
|
|
1312
|
-
});
|
|
1313
|
-
});
|
|
1314
|
-
|
|
1315
|
-
await it('should accept statusCode and headers object', async () => {
|
|
1316
|
-
const server = http.createServer((req, res) => {
|
|
1317
|
-
res.writeHead(200, { 'X-WriteHead': 'test' });
|
|
1318
|
-
res.end('ok');
|
|
1319
|
-
});
|
|
1320
|
-
|
|
1321
|
-
await new Promise<void>((resolve, reject) => {
|
|
1322
|
-
server.listen(0, () => {
|
|
1323
|
-
const addr = server.address() as { port: number };
|
|
1324
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
1325
|
-
expect(res.headers['x-writehead']).toBe('test');
|
|
1326
|
-
res.on('data', () => {});
|
|
1327
|
-
res.on('end', () => server.close(() => resolve()));
|
|
1328
|
-
}).on('error', reject);
|
|
1329
|
-
});
|
|
1330
|
-
server.on('error', reject);
|
|
1331
|
-
});
|
|
1332
|
-
});
|
|
1333
|
-
|
|
1334
|
-
await it('should handle 500 status code', async () => {
|
|
1335
|
-
const server = http.createServer((req, res) => {
|
|
1336
|
-
res.writeHead(500);
|
|
1337
|
-
res.end('Internal Error');
|
|
1338
|
-
});
|
|
1339
|
-
|
|
1340
|
-
await new Promise<void>((resolve, reject) => {
|
|
1341
|
-
server.listen(0, () => {
|
|
1342
|
-
const addr = server.address() as { port: number };
|
|
1343
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
1344
|
-
expect(res.statusCode).toBe(500);
|
|
1345
|
-
res.on('data', () => {});
|
|
1346
|
-
res.on('end', () => server.close(() => resolve()));
|
|
1347
|
-
}).on('error', reject);
|
|
1348
|
-
});
|
|
1349
|
-
server.on('error', reject);
|
|
1350
|
-
});
|
|
1351
|
-
});
|
|
1352
|
-
|
|
1353
|
-
await it('should handle 302 redirect with Location header via server roundtrip', async () => {
|
|
1354
|
-
// Test that the server can set a redirect status + Location header,
|
|
1355
|
-
// then a second request to the new location succeeds.
|
|
1356
|
-
let hitCount = 0;
|
|
1357
|
-
const server = http.createServer((req, res) => {
|
|
1358
|
-
hitCount++;
|
|
1359
|
-
if (req.url === '/old') {
|
|
1360
|
-
// Respond with a body so Soup doesn't auto-follow
|
|
1361
|
-
res.writeHead(200, { 'X-Would-Redirect': '/new' });
|
|
1362
|
-
res.end('redirect-target: /new');
|
|
1363
|
-
} else {
|
|
1364
|
-
res.writeHead(200);
|
|
1365
|
-
res.end('final');
|
|
1366
|
-
}
|
|
1367
|
-
});
|
|
1368
|
-
|
|
1369
|
-
await new Promise<void>((resolve, reject) => {
|
|
1370
|
-
server.listen(0, () => {
|
|
1371
|
-
const addr = server.address() as { port: number };
|
|
1372
|
-
http.get(`http://127.0.0.1:${addr.port}/old`, (res) => {
|
|
1373
|
-
expect(res.statusCode).toBe(200);
|
|
1374
|
-
expect(res.headers['x-would-redirect']).toBe('/new');
|
|
1375
|
-
res.on('data', () => {});
|
|
1376
|
-
res.on('end', () => server.close(() => resolve()));
|
|
1377
|
-
}).on('error', reject);
|
|
1378
|
-
});
|
|
1379
|
-
server.on('error', reject);
|
|
1380
|
-
});
|
|
1381
|
-
});
|
|
1382
|
-
});
|
|
1383
|
-
|
|
1384
|
-
// --- ServerResponse default statusCode ---
|
|
1385
|
-
await describe('ServerResponse statusCode default', async () => {
|
|
1386
|
-
await it('should default statusCode to 200', async () => {
|
|
1387
|
-
const server = http.createServer((req, res) => {
|
|
1388
|
-
// Do not call writeHead, just end
|
|
1389
|
-
res.end('default status');
|
|
1390
|
-
});
|
|
1391
|
-
|
|
1392
|
-
await new Promise<void>((resolve, reject) => {
|
|
1393
|
-
server.listen(0, () => {
|
|
1394
|
-
const addr = server.address() as { port: number };
|
|
1395
|
-
http.get(`http://127.0.0.1:${addr.port}/`, (res) => {
|
|
1396
|
-
expect(res.statusCode).toBe(200);
|
|
1397
|
-
res.on('data', () => {});
|
|
1398
|
-
res.on('end', () => server.close(() => resolve()));
|
|
1399
|
-
}).on('error', reject);
|
|
1400
|
-
});
|
|
1401
|
-
server.on('error', reject);
|
|
1402
|
-
});
|
|
1403
|
-
});
|
|
1404
|
-
});
|
|
1405
|
-
};
|