webhoster 0.1.1 → 0.3.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.
Files changed (87) hide show
  1. package/.eslintrc.json +74 -58
  2. package/.github/copilot-instructions.md +100 -0
  3. package/.github/workflows/test-matrix.yml +37 -0
  4. package/.test/benchmark.js +28 -0
  5. package/.test/constants.js +4 -0
  6. package/{test → .test}/http2server.js +1 -1
  7. package/{test → .test}/httpserver.js +1 -1
  8. package/{test → .test}/index.js +178 -192
  9. package/.test/multipromise.js +32 -0
  10. package/{test → .test}/tls.js +3 -3
  11. package/{test → .test}/urlencoded.js +3 -0
  12. package/.vscode/launch.json +24 -3
  13. package/README.md +116 -90
  14. package/data/CookieObject.js +14 -14
  15. package/errata/socketio.js +6 -11
  16. package/examples/starter.js +11 -0
  17. package/helpers/HeadersParser.js +7 -8
  18. package/helpers/HttpListener.js +387 -42
  19. package/helpers/RequestHeaders.js +43 -36
  20. package/helpers/RequestReader.js +27 -26
  21. package/helpers/ResponseHeaders.js +47 -36
  22. package/jsconfig.json +1 -1
  23. package/lib/HttpHandler.js +447 -277
  24. package/lib/HttpRequest.js +383 -39
  25. package/lib/HttpResponse.js +316 -52
  26. package/lib/HttpTransaction.js +146 -0
  27. package/middleware/AutoHeadersMiddleware.js +73 -0
  28. package/middleware/CORSMiddleware.js +45 -47
  29. package/middleware/CaseInsensitiveHeadersMiddleware.js +5 -11
  30. package/middleware/ContentDecoderMiddleware.js +81 -35
  31. package/middleware/ContentEncoderMiddleware.js +179 -132
  32. package/middleware/ContentLengthMiddleware.js +66 -41
  33. package/middleware/ContentWriterMiddleware.js +5 -5
  34. package/middleware/HashMiddleware.js +68 -40
  35. package/middleware/HeadMethodMiddleware.js +24 -21
  36. package/middleware/MethodMiddleware.js +29 -36
  37. package/middleware/PathMiddleware.js +49 -66
  38. package/middleware/ReadFormData.js +99 -0
  39. package/middleware/SendJsonMiddleware.js +131 -0
  40. package/middleware/SendStringMiddleware.js +87 -0
  41. package/package.json +38 -29
  42. package/polyfill/FormData.js +164 -0
  43. package/rollup.config.js +0 -1
  44. package/scripts/check-teapot.mjs +40 -0
  45. package/scripts/test-all-sync.sh +6 -0
  46. package/scripts/test-all.sh +7 -0
  47. package/templates/starter.js +55 -0
  48. package/test/fixtures/stream.js +68 -0
  49. package/test/helpers/HttpListener/construct.js +18 -0
  50. package/test/helpers/HttpListener/customOptions.js +22 -0
  51. package/test/helpers/HttpListener/doubleCreate.js +40 -0
  52. package/test/helpers/HttpListener/events.js +77 -0
  53. package/test/helpers/HttpListener/http.js +31 -0
  54. package/test/helpers/HttpListener/http2.js +41 -0
  55. package/test/helpers/HttpListener/https.js +38 -0
  56. package/test/helpers/HttpListener/startAll.js +31 -0
  57. package/test/helpers/HttpListener/stopNotStarted.js +23 -0
  58. package/test/lib/HttpHandler/class.js +8 -0
  59. package/test/lib/HttpHandler/handleRequest.js +11 -0
  60. package/test/lib/HttpHandler/middleware.js +941 -0
  61. package/test/lib/HttpHandler/parse.js +41 -0
  62. package/test/lib/HttpRequest/class.js +8 -0
  63. package/test/lib/HttpRequest/downstream.js +171 -0
  64. package/test/lib/HttpRequest/properties.js +101 -0
  65. package/test/lib/HttpRequest/read.js +518 -0
  66. package/test/lib/HttpResponse/class.js +8 -0
  67. package/test/lib/HttpResponse/properties.js +59 -0
  68. package/test/lib/HttpResponse/send.js +275 -0
  69. package/test/lib/HttpTransaction/class.js +8 -0
  70. package/test/lib/HttpTransaction/ping.js +50 -0
  71. package/test/lib/HttpTransaction/push.js +89 -0
  72. package/test/middleware/SendJsonMiddleware.js +222 -0
  73. package/test/sanity.js +10 -0
  74. package/test/templates/error-teapot.js +47 -0
  75. package/test/templates/starter.js +93 -0
  76. package/tsconfig.json +12 -0
  77. package/types/index.js +61 -34
  78. package/types/typings.d.ts +8 -9
  79. package/utils/AsyncObject.js +6 -3
  80. package/utils/CaseInsensitiveObject.js +2 -3
  81. package/utils/function.js +1 -7
  82. package/utils/headers.js +42 -0
  83. package/utils/qualityValues.js +1 -1
  84. package/utils/stream.js +4 -20
  85. package/index.cjs +0 -3190
  86. package/test/constants.js +0 -4
  87. /package/{test → .test}/cookietester.js +0 -0
@@ -1,27 +1,30 @@
1
+ // @ts-check
2
+
1
3
  /* eslint-disable no-console */
2
4
 
3
- import { existsSync, readFileSync } from 'fs';
5
+ import { existsSync, readFileSync } from 'node:fs';
4
6
 
5
7
  import HttpListener from '../helpers/HttpListener.js';
6
8
  import RequestHeaders from '../helpers/RequestHeaders.js';
7
9
  import ResponseHeaders from '../helpers/ResponseHeaders.js';
8
10
  import HttpHandler from '../lib/HttpHandler.js';
11
+ import AutoHeadersMiddleware from '../middleware/AutoHeadersMiddleware.js';
9
12
  import CORSMiddleware from '../middleware/CORSMiddleware.js';
10
13
  import ContentDecoderMiddleware from '../middleware/ContentDecoderMiddleware.js';
11
14
  import ContentEncoderMiddleware from '../middleware/ContentEncoderMiddleware.js';
12
15
  import ContentLengthMiddleware from '../middleware/ContentLengthMiddleware.js';
13
- import ContentReaderMiddleware from '../middleware/ContentReaderMiddleware.js';
14
- import ContentWriterMiddleware from '../middleware/ContentWriterMiddleware.js';
15
16
  import HashMiddleware from '../middleware/HashMiddleware.js';
16
17
  import HeadMethodMiddleware from '../middleware/HeadMethodMiddleware.js';
17
18
  import MethodMiddleware from '../middleware/MethodMiddleware.js';
18
19
  import PathMiddleware from '../middleware/PathMiddleware.js';
19
- import SendHeadersMiddleware from '../middleware/SendHeadersMiddleware.js';
20
+ import SendJsonMiddleware from '../middleware/SendJsonMiddleware.js';
21
+ import SendStringMiddleware from '../middleware/SendStringMiddleware.js';
20
22
 
21
23
  import {
22
24
  HTTPS_HOST, HTTPS_PORT, HTTP_HOST, HTTP_PORT,
23
25
  } from './constants.js';
24
26
  import * as tls from './tls.js';
27
+ import { ServerResponse } from 'node:http';
25
28
 
26
29
  /** @typedef {import('../types').MiddlewareFunction} MiddlewareFunction */
27
30
 
@@ -29,30 +32,27 @@ import * as tls from './tls.js';
29
32
  * Redirect to HTTPS/2
30
33
  * @type {MiddlewareFunction}
31
34
  */
32
- function redirectHttpsMiddleware({ req, res }) {
33
- if (req.url.protocol !== 'http:') {
34
- return null;
35
+ function redirectHttpsMiddleware({request,response}) {
36
+ if (request.protocol === 'https:') {
37
+ return true;
35
38
  }
36
- const url = new URL(req.url.href);
39
+ const url = new URL(request.url);
37
40
  url.protocol = 'https:';
38
41
  url.port = HTTPS_PORT.toString(10);
39
42
  const Location = url.href;
40
- res.status = 301;
41
- res.headers.location = Location;
42
- res.sendHeaders();
43
- return 'end';
43
+ response.headers.location = Location;
44
+ return 301;
44
45
  }
45
46
 
46
47
  /** @type {MiddlewareFunction} */
47
- function indexMiddleware({ res }) {
48
+ function indexMiddleware(transaction) {
48
49
  console.log('indexMiddleware');
49
- res.status = 200;
50
- res.headers['content-type'] = 'text/html';
51
- if (res.canPushPath) {
52
- res.pushPath('/script.js').catch(console.error);
53
- res.pushPath('/fake.png').catch(console.error);
50
+ transaction.response.headers['content-type'] = 'text/html';
51
+ if (transaction.canPushPath) {
52
+ transaction.pushPath('/script.js').catch(console.error);
53
+ transaction.pushPath('/fake.png').catch(console.error);
54
54
  }
55
- res.stream.end(/* html */ `
55
+ return /* html */ `
56
56
  <html>
57
57
  <head><script src="script.js"></script></head>
58
58
  </body>
@@ -60,110 +60,110 @@ function indexMiddleware({ res }) {
60
60
  <img src="fake.png"/>
61
61
  <form action="form" method="POST"><input name="field"><input type="submit" value="POST"></form>
62
62
  <form action="form" method="GET"><input name="field"><input type="submit" value="GET"></form>
63
+ <ul>
64
+ <li><a href="/cors.html">/cors.html</a></li>
65
+ <li><a href="/large.html">/large.html</a></li>
66
+ <li><a href="/chunk.html">/chunk.html</a></li>
67
+ <li><a href="/blank.html">/blank.html</a></li>
68
+ <li><a href="/nocontent.html">/nocontent.html</a></li>
69
+ <li><a href="/gzip.html">/gzip.html</a></li>
70
+ <li><a href="/plaintext.html">/plaintext.html</a></li>
71
+ <li><a href="/get.json">/get.json</a></li>
72
+ </ul>
63
73
  </body>
64
74
  </html>
65
- `);
66
- return 'end';
75
+ `;
67
76
  }
68
77
 
69
78
  /** @type {MiddlewareFunction} */
70
- function largeMiddleware({ req, res }) {
79
+ function largeMiddleware({request}) {
71
80
  console.log('largeMiddleware');
72
- res.status = 200;
73
- res.headers['content-type'] = 'text/html';
81
+ request.headers['content-type'] = 'text/html';
74
82
  let block = '';
75
- const len = Number.parseInt(req.url.searchParams.get('lines'), 10) || 10000;
83
+ const len = Number.parseInt(request.searchParams.get('lines'), 10) || 10_000;
76
84
  for (let i = 0; i < len; i += 1) {
77
85
  block += `<pre>${i.toString(36)}</pre><br>`;
78
86
  }
79
- res.stream.end(/* html */ `
87
+ return /* html */ `
80
88
  <html>
81
89
  <head></head>
82
90
  </body>
83
91
  ${block}
84
92
  </body>
85
93
  </html>
86
- `);
87
- return 'end';
94
+ `;
88
95
  }
89
96
 
90
97
  /** @type {MiddlewareFunction} */
91
- function chunkMiddleware({ req, res }) {
98
+ function chunkMiddleware({ request, response }) {
92
99
  console.log('chunkMiddleware');
93
- res.status = 200;
94
- res.headers['content-type'] = 'text/html';
100
+ response.headers['content-type'] = 'text/html';
95
101
  let block = '';
96
102
  for (let i = 0; i < 1000; i += 1) {
97
- block += `<pre>${Math.random().toString(36).substr(2, 16)}</pre><br>`;
103
+ block += `<pre>${Math.random().toString(36).slice(2, 18)}</pre><br>`;
98
104
  }
99
- const delay = Number.parseInt(req.url.searchParams.get('delay'), 10) || 0;
105
+ const delay = Number.parseInt(request.searchParams.get('delay'), 10) || 0;
106
+ let stream = response.getPipeline();
100
107
  return new Promise((resolve) => {
101
108
  const timingFn = delay ? setTimeout : process.nextTick;
102
109
  timingFn(() => {
103
110
  console.log('write1');
104
- res.stream.write(/* html */ `
105
- <html>
106
- <head></head>
107
- </body>
108
- `);
111
+ stream.write(/* html */ `
112
+ <html>
113
+ <head></head>
114
+ </body>
115
+ `);
109
116
  }, delay);
110
117
  timingFn(() => {
111
118
  console.log('write2');
112
- res.stream.write(block);
119
+ stream.write(block);
113
120
  }, delay * 2);
114
121
  timingFn(() => {
115
122
  console.log('write3');
116
- res.stream.write(/* html */ `
123
+ stream.write(/* html */ `
117
124
  </body>
118
- </html>
119
- `);
125
+ </html>
126
+ `);
120
127
  }, delay * 3);
121
- timingFn(() => { resolve('end'); }, delay * 4);
128
+ timingFn(() => {
129
+ stream.end();
130
+ resolve(HttpHandler.END);
131
+ }, delay * 4);
122
132
  });
123
133
  }
124
134
 
125
135
  /** @type {MiddlewareFunction} */
126
- function plainTextMiddleware({ res }) {
136
+ function plainTextMiddleware({ response }) {
127
137
  console.log('plainTextMiddleware');
128
- res.status = 200;
129
- res.headers['content-type'] = 'text/html';
130
- res.headers['content-encoding'] = 'identity';
131
- res.stream.end('This is always in plaintext');
132
- return 'end';
138
+ response.status = 200;
139
+ response.headers['content-type'] = 'text/html';
140
+ response.headers['content-encoding'] = 'identity';
141
+ return 'This is always in plaintext';
133
142
  }
134
143
 
135
144
  /** @type {MiddlewareFunction} */
136
- function blankMiddleware({ res }) {
145
+ function blankMiddleware({ response }) {
137
146
  console.log('blankMiddleware');
138
- res.status = 200;
139
- res.headers['content-type'] = 'text/html';
140
- res.stream.end();
141
- return 'end';
147
+ response.headers['content-type'] = 'text/html';
148
+ response.headers['content-length'] = '0';
149
+ return 200;
142
150
  }
143
151
 
144
152
  /** @type {MiddlewareFunction} */
145
- function noContentMiddleware({ res }) {
146
- console.log('noContentMiddleware');
147
- res.status = 204;
148
- return 'end';
149
- }
150
-
151
- /** @type {MiddlewareFunction} */
152
- function gzipMiddleware({ res }) {
153
+ function gzipMiddleware({ response }) {
153
154
  console.log('gzipMiddleware');
154
- res.status = 200;
155
- res.headers['content-type'] = 'text/html';
156
- res.headers['content-encoding'] = 'gzip';
157
- res.stream.end('This is always compressed with gzip.');
158
- return 'end';
155
+ response.statusCode = 200;
156
+ response.headers['content-type'] = 'text/html';
157
+ response.headers['content-encoding'] = 'gzip';
158
+ return 'This is always compressed with gzip.';
159
159
  }
160
160
 
161
161
  /** @type {MiddlewareFunction} */
162
- function corsTest({ res }) {
162
+ function corsTest({ response }) {
163
163
  console.log('cors');
164
- res.status = 200;
165
- res.headers['content-type'] = 'text/html';
166
- res.stream.end(/* html */ `
164
+ response.statusCode = 200;
165
+ response.headers['content-type'] = 'text/html';
166
+ return /* html */ `
167
167
  <html>
168
168
  <head>
169
169
  <script type="text/javascript">
@@ -181,32 +181,32 @@ function corsTest({ res }) {
181
181
  ${new Date()}
182
182
  </body>
183
183
  </html>
184
- `);
185
- return 'end';
184
+ `;
186
185
  }
187
186
 
188
187
  /** @type {MiddlewareFunction} */
189
- function scriptMiddleware({ res }) {
188
+ function scriptMiddleware(transaction) {
189
+ const response = transaction.response;
190
190
  console.log('scriptMiddleware');
191
191
  console.log('Holding script');
192
192
  return new Promise((resolve) => {
193
193
  setTimeout(() => {
194
- res.status = 200;
195
- res.headers['content-type'] = 'text/javascript';
196
- if (res.canPushPath) {
197
- res.pushPath('/fake.js').catch(console.error);
194
+ response.statusCode = 200;
195
+ response.headers['content-type'] = 'text/javascript';
196
+ if (transaction.canPushPath) {
197
+ transaction.pushPath('/fake.js').catch(console.error);
198
198
  } else {
199
199
  console.log('RIP Push');
200
200
  }
201
201
  console.log('Releasing script');
202
- res.stream.end(/* js */ `
202
+ response.end(/* js */ `
203
203
  console.log('hello');
204
204
  let data = '';
205
205
  for(let i = 0; i < 10 ; i++) {
206
- data += Math.random().toString(36).substr(2, 16);
206
+ data += Math.random().toString(36).slice(2, 18);
207
207
  }
208
208
  console.log(data);
209
- fetch('http://127.0.0.1:8080/input.json', {
209
+ fetch('http://127.0.0.1:8080/echo.json', {
210
210
  method: 'POST',
211
211
  body: JSON.stringify({data}),
212
212
  headers: [['Content-Type', 'application/json']],
@@ -214,17 +214,19 @@ function scriptMiddleware({ res }) {
214
214
  .then((response) => console.log('match', response.data === data))
215
215
  .catch(console.error);
216
216
  `);
217
- resolve('end');
217
+ resolve(HttpHandler.END);
218
218
  }, 0);
219
219
  });
220
220
  }
221
221
 
222
+ ServerResponse
223
+
222
224
  /** @type {MiddlewareFunction} */
223
- function outputMiddleware({ req, res }) {
224
- const reqHeaders = new RequestHeaders(req);
225
- console.log(req.headers.cookie);
225
+ function outputMiddleware({ request, response }) {
226
+ const reqHeaders = new RequestHeaders(request);
227
+ console.log(request.headers.cookie);
226
228
  console.log('reqHeaders.cookieEntries.test', reqHeaders.cookieEntries.test);
227
- console.log('req.headers.cookie', req.headers.cookie);
229
+ console.log('req.headers.cookie', request.headers.cookie);
228
230
  console.log('reqHeaders.cookies.get("test")', reqHeaders.cookies.get('test'));
229
231
  console.log('reqHeaders.cookies.all("test")', reqHeaders.cookies.all('test'));
230
232
  console.log('reqHeaders.cookieEntries.test?.[0]', reqHeaders.cookieEntries.test?.[0]);
@@ -233,9 +235,9 @@ function outputMiddleware({ req, res }) {
233
235
  console.log('reqHeaders.cookieEntries.test4', reqHeaders.cookieEntries.test4);
234
236
  console.log("'test' in reqHeaders.cookieEntries", 'test' in reqHeaders.cookieEntries);
235
237
  console.log("'test4' in reqHeaders.cookieEntries", 'test4' in reqHeaders.cookieEntries);
236
- console.log('req.headers.cookie', req.headers.cookie);
238
+ console.log('req.headers.cookie', request.headers.cookie);
237
239
 
238
- const resHeaders = new ResponseHeaders(res);
240
+ const resHeaders = new ResponseHeaders(response);
239
241
  resHeaders.cookies.set({
240
242
  name: 'test',
241
243
  value: Date.now().toString(),
@@ -269,107 +271,100 @@ function outputMiddleware({ req, res }) {
269
271
  resHeaders.cookies.set('=blankname;path=/');
270
272
  resHeaders.cookies.set('quotedblank=""');
271
273
  resHeaders.cookieEntries.forEach((c) => console.log(c.toString()));
272
- res.status = 200;
274
+ // res.statusCode = 200;
273
275
  // resHeaders.mediaType = 'application/json';
274
- res.stream.end({ now: new Date() });
276
+ return { now: new Date() };
275
277
  }
276
278
 
277
279
  /** @type {MiddlewareFunction} */
278
- async function inputMiddleware({ req, res }) {
280
+ async function inputMiddleware({ request, response }) {
279
281
  console.log('inputMiddleware');
280
282
 
281
- return new Promise((resolve) => {
282
- console.log('stalled processing for 1000ms');
283
- setTimeout(async () => {
284
- res.status = 200;
285
- // Pipe it back and read at the same time
286
- req.stream.pipe(res.stream);
287
- const { value } = await req.stream[Symbol.asyncIterator]().next();
288
- console.log('got input.json', typeof value, value);
289
- resolve('end');
290
- }, 0);
291
- });
283
+ console.log('stalled processing for 1000ms');
284
+ // await new Promise((resolve) => setTimeout(resolve, 1000));
285
+ response.statusCode = 200;
286
+ console.log('reading post data from input.json');
287
+ // Pipe it back and read at the same time
288
+ request.stream.pipe(response.getPipeline());
289
+ // res.pipeFrom(req.stream);
290
+ const value = await request.read();
291
+ console.log('got input.json', typeof value, value);
292
+ return HttpHandler.END;
292
293
  }
293
294
 
294
295
  /** @type {MiddlewareFunction} */
295
- async function formGetMiddleware({ req, res }) {
296
+ async function echoMiddleware({ request, response }) {
297
+ console.log('echoMiddleware');
298
+ return request.stream;
299
+ }
300
+
301
+ /** @type {MiddlewareFunction} */
302
+ async function formGetMiddleware({ request, response }) {
296
303
  console.log('formGetMiddleware');
297
304
 
298
- return new Promise((resolve) => {
299
- console.log('stalled processing for 1000ms');
300
- setTimeout(async () => {
301
- const values = Object.fromEntries(req.url.searchParams.entries());
302
- res.status = 200;
303
- res.stream.end(values);
304
- resolve('end');
305
- }, 1000);
306
- });
305
+ console.log('stalled processing for 1000ms');
306
+ await new Promise((resolve) => setTimeout(resolve, 1000));
307
+ const data = Object.fromEntries(request.searchParams.entries());
308
+ console.log('returning', data);
309
+ return response.send(data);
307
310
  }
308
311
 
309
312
  /** @type {MiddlewareFunction} */
310
- async function outputURLMiddleware({ req, res }) {
311
- console.log('outputURLMiddleware', req.locals.path);
312
- res.status = 200;
313
- res.stream.end(req.url.pathname);
314
- return 'end';
313
+ function outputURLMiddleware({ request, response, state }) {
314
+ console.log('outputURLMiddleware', state.path);
315
+ return response.code(200).end(request.pathname);
315
316
  }
316
317
 
317
318
  /** @type {MiddlewareFunction} */
318
- async function formPostMiddleware({ req, res }) {
319
+ async function formPostMiddleware({ request, response }) {
319
320
  console.log('formPostMiddleware');
320
- const { value } = await req.stream[Symbol.asyncIterator]().next();
321
+ /** @type {FormData} */
322
+ const value = await request.read();
321
323
  const stringData = JSON.stringify(value);
322
- res.status = 200;
323
- res.stream.end(`type: ${req.headers['content-type']}\n${stringData.toString()}}`);
324
- return 'end';
324
+ return `type: ${request.headers['content-type']}\n${stringData.toString()}`;
325
325
  }
326
326
 
327
327
  /** @type {MiddlewareFunction} */
328
- function getJSONMiddleware({ res }) {
328
+ function getJSONMiddleware() {
329
329
  console.log('getJSONMiddleware');
330
- res.status = 200;
331
- res.stream.end({ now: new Date() });
332
- return 'end';
330
+ return { now: new Date() };
333
331
  }
334
332
 
335
333
  const USE_HTTPS_REDIRECT = false;
336
334
  const SHOULD_CRASH = false;
337
335
 
336
+ /**
337
+ *
338
+ */
338
339
  function setupHandler() {
339
- const { preprocessors, middleware, errorHandlers } = HttpHandler.defaultInstance;
340
+ const { middleware, errorHandlers } = HttpHandler.defaultInstance;
340
341
  // Conditional statement
341
- preprocessors.push(USE_HTTPS_REDIRECT ? redirectHttpsMiddleware : null);
342
- const middlewareObject = {
343
- // Discard body content
344
- headMethod: new HeadMethodMiddleware(),
345
- // Send headers automatically
346
- sendHeaders: new SendHeadersMiddleware(),
347
- // Calculate length of anything after
348
- contentLength: new ContentLengthMiddleware(),
342
+ middleware.push(USE_HTTPS_REDIRECT ? redirectHttpsMiddleware : null);
343
+ const middlewareObject = new Set([
349
344
  // Allow Cross-Origin Resource Sharing
350
- cors: new CORSMiddleware({
351
- allowOrigin: ['http://localhost:8080', 'https://localhost:8443'],
352
- }),
353
- // Hash anything after
354
- hash: new HashMiddleware(),
355
- // Compress anything after
356
- contentEncoder: new ContentEncoderMiddleware(),
357
- // Convert Objects and Strings to Buffer
358
- contentWriter: new ContentWriterMiddleware({ setCharset: true, setJSON: true }),
359
-
360
- // Automatically decodes content
361
- contentDecoder: new ContentDecoderMiddleware(),
362
- // Automatically reads text, JSON, and form-url-encoded from requests
363
- contentReader: new ContentReaderMiddleware({
364
- buildString: true,
365
- defaultMediaType: 'application/json',
366
- parseJSON: true,
367
- formURLEncodedFormat: 'object',
368
- }),
369
- };
370
- preprocessors.push(middlewareObject);
371
- const mapTest = new Map();
372
- middleware.add(mapTest);
345
+ new CORSMiddleware({ allowOrigin: ['http://localhost:8080', 'https://localhost:8443'] }),
346
+
347
+ new ContentDecoderMiddleware(), // Automatically decodes content
348
+
349
+ new SendJsonMiddleware({
350
+ defaultCharset: 'utf-8',
351
+ setCharset: true,
352
+ setMediaType: true,
353
+ }), // Auto converts objects to JSON
354
+ new SendStringMiddleware({
355
+ defaultCharset: 'utf-8',
356
+ setCharset: true,
357
+ }), // Auto converts strings to buffer
358
+ new ContentEncoderMiddleware(), // Compress anything after
359
+ new HashMiddleware(), // Hash anything after
360
+ new ContentLengthMiddleware(), // Calculate length of anything after
361
+ new AutoHeadersMiddleware(), // Send headers automatically
362
+ new HeadMethodMiddleware(), // Discard body content
363
+
364
+ ]);
365
+ middleware.push(middlewareObject);
366
+ const setTest = new Set();
367
+ middleware.push(setTest);
373
368
  /** @type {any} */
374
369
  const getMiddlewareArray = [
375
370
  MethodMiddleware.GET,
@@ -377,20 +372,20 @@ function setupHandler() {
377
372
  [new PathMiddleware('/large.html'), largeMiddleware],
378
373
  [new PathMiddleware('/chunk.html'), chunkMiddleware],
379
374
  [new PathMiddleware('/blank.html'), blankMiddleware],
380
- [new PathMiddleware('/nocontent.html'), noContentMiddleware],
375
+ [new PathMiddleware('/nocontent.html'), 204],
381
376
  [new PathMiddleware('/gzip.html'), gzipMiddleware],
382
377
  [new PathMiddleware('/plaintext.html'), plainTextMiddleware],
383
378
  [new PathMiddleware('/get.json'), getJSONMiddleware],
384
379
  [new PathMiddleware('/form'), formGetMiddleware],
385
380
  ];
386
- mapTest.set('gets', getMiddlewareArray);
381
+ setTest.add(getMiddlewareArray);
387
382
  // Modify after insertion
388
383
  getMiddlewareArray.push(
389
384
  [new PathMiddleware({ path: '/script.js' }), scriptMiddleware],
390
385
  );
391
386
  // Add terminator middleware
392
387
  getMiddlewareArray.push(
393
- [new PathMiddleware({ path: /\/output.json$/ }), outputMiddleware, 'end'],
388
+ [new PathMiddleware({ path: /\/output.json$/ }), outputMiddleware],
394
389
  );
395
390
 
396
391
  // Predefined Route
@@ -402,7 +397,7 @@ function setupHandler() {
402
397
  ];
403
398
 
404
399
  // Automatic Path Routing
405
- middleware.add([
400
+ middleware.push([
406
401
  MethodMiddleware.GET,
407
402
  [new PathMiddleware({ path: /^(\/subpath)\/?.*/, subPath: true }), [
408
403
  [new PathMiddleware('/'), outputURLMiddleware],
@@ -425,73 +420,64 @@ function setupHandler() {
425
420
  ]);
426
421
 
427
422
  // Add error handler
428
- middleware.add([MethodMiddleware.GET,
423
+ middleware.push([MethodMiddleware.GET,
429
424
  new PathMiddleware('/error'),
430
425
  function throwError() {
431
426
  throw new Error('unexpected error!');
432
427
  }]);
433
- middleware.add([
428
+ middleware.push([
434
429
  MethodMiddleware.GET,
435
430
  new PathMiddleware('/catch'),
436
431
  function throwError() {
437
432
  throw new Error('EXCEPTION!');
438
433
  },
439
434
  {
440
- onError: ({ err }) => {
435
+ onError: ({ error }) => {
441
436
  console.log('I catch and rethrow errors.');
442
- throw new Error(err);
437
+ throw error;
443
438
  },
444
439
  },
445
440
  {
446
- onError: ({ err }) => {
447
- console.warn('Caught exception. Allowing continue.', err);
448
- return Promise.resolve('continue');
441
+ onError: ({ error }) => {
442
+ console.warn('Caught exception. Allowing continue.', error);
443
+ return HttpHandler.CONTINUE;
449
444
  },
450
445
  },
451
- function responseAfterError({ res }) {
452
- res.status = 200;
453
- res.stream.end('Error was caught.');
454
- return 'end';
455
- },
456
-
446
+ 'Error was caught.'
457
447
  ]);
458
448
 
459
449
  // Inline middleware and filter adding
460
- middleware.add({
461
- myPostMiddlewares: [
450
+ middleware.push(
451
+ [
462
452
  MethodMiddleware.POST,
463
453
  [new PathMiddleware('/input.json'), inputMiddleware],
454
+ [new PathMiddleware('/echo.json'), echoMiddleware],
464
455
  [new PathMiddleware('/form'), formPostMiddleware],
465
456
  ],
466
- inlineFilter: [
457
+ [
467
458
  () => SHOULD_CRASH,
468
459
  () => { throw new Error('Break not called!'); },
469
460
  ],
470
- corsTest: [
461
+ [
471
462
  MethodMiddleware.GET,
472
463
  new PathMiddleware('/cors.html'),
473
464
  corsTest,
474
- 'end',
465
+ HttpHandler.END,
475
466
  ],
476
- unknownFile({ req, res }) {
477
- console.log('Unknown', req.url.toString());
478
- res.status = 404;
479
- res.stream.end();
480
- return 'end';
467
+ ({ request }) => {
468
+ console.log('Unknown', request.url);
469
+ return 404;
481
470
  },
482
- });
471
+ );
483
472
 
484
473
  errorHandlers.push({
485
- onError({ res, err }) {
474
+ onError({ error }) {
486
475
  console.error('Uncaught exception');
487
- console.error(err);
488
- res.status = 500;
489
- res.stream.end();
490
- return 'end';
476
+ console.error(error);
477
+ return 500;
491
478
  },
492
479
  });
493
480
  console.dir([
494
- preprocessors,
495
481
  middleware,
496
482
  errorHandlers,
497
483
  ], { colors: true, depth: null });
@@ -0,0 +1,32 @@
1
+ const promises = [];
2
+
3
+ async function waitAndLogPromise() {
4
+ const p = (async() => {
5
+ console.log('The promise is running');
6
+ await new Promise((r) => setTimeout(r, 5000));
7
+ console.log('The promise is completed');
8
+ });
9
+ let runningPromise = p();
10
+ console.log('pushing p');
11
+ promises.push(runningPromise);
12
+ console.log('waiting for p');
13
+ await runningPromise;
14
+ }
15
+
16
+ setTimeout(async () => {
17
+ console.log('external pre. start');
18
+ await Promise.all(promises);
19
+ console.log('external pre. finished resolved');
20
+ }, 100)
21
+
22
+ setTimeout(async () => {
23
+ console.log('external post. start');
24
+ await Promise.all(promises);
25
+ console.log('external post. finished resolved');
26
+ }, 8000)
27
+
28
+
29
+ console.log('waitAndLogPromise - start');
30
+ await waitAndLogPromise();
31
+ console.log('waitAndLogPromise - end');
32
+
@@ -1,8 +1,8 @@
1
- import { createSecureContext } from 'tls';
1
+ import { createSecureContext } from 'node:tls';
2
2
 
3
3
  import x509 from '@fidm/x509';
4
4
 
5
- /** @typedef {import('tls').SecureContext} SecureContext
5
+ /** @typedef {import('tls').SecureContext} SecureContext */
6
6
  /** @typedef {import('tls').TlsOptions} TlsOptions */
7
7
 
8
8
  /**
@@ -34,7 +34,7 @@ export function setup(defaultTlsOptions) {
34
34
  */
35
35
  function checkCommonName(commonName, serverName) {
36
36
  if (!commonName || !serverName) return false;
37
- return RegExp(`^${commonName.replace('.', '\\.').replace('*', '.*')}$`, 'i').test(serverName);
37
+ return new RegExp(`^${commonName.replace('.', '\\.').replace('*', '.*')}$`, 'i').test(serverName);
38
38
  }
39
39
 
40
40
  /**