webhoster 0.3.3 → 0.3.5

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 (157) hide show
  1. package/README.md +4 -4
  2. package/data/CookieObject.js +1 -1
  3. package/{types/index.js → data/custom-types.js} +1 -1
  4. package/{types/typings.d.ts → data/middleware.d.ts} +1 -1
  5. package/helpers/RequestReader.js +1 -1
  6. package/helpers/ResponseHeaders.js +9 -10
  7. package/lib/HttpHandler.js +4 -4
  8. package/lib/HttpRequest.js +2 -2
  9. package/lib/HttpResponse.js +2 -2
  10. package/lib/HttpTransaction.js +2 -2
  11. package/middleware/AutoHeadersMiddleware.js +2 -2
  12. package/middleware/CORSMiddleware.js +3 -3
  13. package/middleware/CaseInsensitiveHeadersMiddleware.js +2 -2
  14. package/middleware/ContentDecoderMiddleware.js +1 -1
  15. package/middleware/ContentEncoderMiddleware.js +2 -2
  16. package/middleware/ContentLengthMiddleware.js +2 -2
  17. package/middleware/HashMiddleware.js +2 -2
  18. package/middleware/HeadMethodMiddleware.js +3 -3
  19. package/middleware/MethodMiddleware.js +3 -3
  20. package/middleware/PathMiddleware.js +4 -4
  21. package/middleware/ReadFormData.js +1 -1
  22. package/middleware/SendJsonMiddleware.js +4 -4
  23. package/middleware/SendStringMiddleware.js +3 -3
  24. package/package.json +21 -4
  25. package/templates/starter.js +2 -2
  26. package/types/data/CookieObject.d.ts +34 -0
  27. package/types/data/CookieObject.d.ts.map +1 -0
  28. package/types/data/custom-types.d.ts +111 -0
  29. package/types/data/custom-types.d.ts.map +1 -0
  30. package/types/errata/socketio.d.ts +11 -0
  31. package/types/errata/socketio.d.ts.map +1 -0
  32. package/types/examples/starter.d.ts +2 -0
  33. package/types/examples/starter.d.ts.map +1 -0
  34. package/types/helpers/HeadersParser.d.ts +27 -0
  35. package/types/helpers/HeadersParser.d.ts.map +1 -0
  36. package/types/helpers/HttpListener.d.ts +84 -0
  37. package/types/helpers/HttpListener.d.ts.map +1 -0
  38. package/types/helpers/RequestHeaders.d.ts +25 -0
  39. package/types/helpers/RequestHeaders.d.ts.map +1 -0
  40. package/types/helpers/RequestReader.d.ts +52 -0
  41. package/types/helpers/RequestReader.d.ts.map +1 -0
  42. package/types/helpers/ResponseHeaders.d.ts +126 -0
  43. package/types/helpers/ResponseHeaders.d.ts.map +1 -0
  44. package/types/helpers/index.d.ts +6 -0
  45. package/types/helpers/index.d.ts.map +1 -0
  46. package/types/lib/HttpHandler.d.ts +79 -0
  47. package/types/lib/HttpHandler.d.ts.map +1 -0
  48. package/types/lib/HttpRequest.d.ts +175 -0
  49. package/types/lib/HttpRequest.d.ts.map +1 -0
  50. package/types/lib/HttpResponse.d.ts +117 -0
  51. package/types/lib/HttpResponse.d.ts.map +1 -0
  52. package/types/lib/HttpTransaction.d.ts +114 -0
  53. package/types/lib/HttpTransaction.d.ts.map +1 -0
  54. package/types/middleware/AutoHeadersMiddleware.d.ts +27 -0
  55. package/types/middleware/AutoHeadersMiddleware.d.ts.map +1 -0
  56. package/types/middleware/CORSMiddleware.d.ts +65 -0
  57. package/types/middleware/CORSMiddleware.d.ts.map +1 -0
  58. package/types/middleware/CaseInsensitiveHeadersMiddleware.d.ts +27 -0
  59. package/types/middleware/CaseInsensitiveHeadersMiddleware.d.ts.map +1 -0
  60. package/types/middleware/ContentDecoderMiddleware.d.ts +17 -0
  61. package/types/middleware/ContentDecoderMiddleware.d.ts.map +1 -0
  62. package/types/middleware/ContentEncoderMiddleware.d.ts +48 -0
  63. package/types/middleware/ContentEncoderMiddleware.d.ts.map +1 -0
  64. package/types/middleware/ContentLengthMiddleware.d.ts +38 -0
  65. package/types/middleware/ContentLengthMiddleware.d.ts.map +1 -0
  66. package/types/middleware/HashMiddleware.d.ts +28 -0
  67. package/types/middleware/HashMiddleware.d.ts.map +1 -0
  68. package/types/middleware/HeadMethodMiddleware.d.ts +12 -0
  69. package/types/middleware/HeadMethodMiddleware.d.ts.map +1 -0
  70. package/types/middleware/MethodMiddleware.d.ts +40 -0
  71. package/types/middleware/MethodMiddleware.d.ts.map +1 -0
  72. package/types/middleware/PathMiddleware.d.ts +81 -0
  73. package/types/middleware/PathMiddleware.d.ts.map +1 -0
  74. package/types/middleware/ReadFormData.d.ts +7 -0
  75. package/types/middleware/ReadFormData.d.ts.map +1 -0
  76. package/types/middleware/SendJsonMiddleware.d.ts +51 -0
  77. package/types/middleware/SendJsonMiddleware.d.ts.map +1 -0
  78. package/types/middleware/SendStringMiddleware.d.ts +35 -0
  79. package/types/middleware/SendStringMiddleware.d.ts.map +1 -0
  80. package/types/templates/starter.d.ts +15 -0
  81. package/types/templates/starter.d.ts.map +1 -0
  82. package/types/utils/AsyncObject.d.ts +38 -0
  83. package/types/utils/AsyncObject.d.ts.map +1 -0
  84. package/types/utils/CaseInsensitiveObject.d.ts +9 -0
  85. package/types/utils/CaseInsensitiveObject.d.ts.map +1 -0
  86. package/types/utils/function.d.ts +2 -0
  87. package/types/utils/function.d.ts.map +1 -0
  88. package/types/utils/headers.d.ts +7 -0
  89. package/types/utils/headers.d.ts.map +1 -0
  90. package/types/utils/qualityValues.d.ts +12 -0
  91. package/types/utils/qualityValues.d.ts.map +1 -0
  92. package/types/utils/stream.d.ts +6 -0
  93. package/types/utils/stream.d.ts.map +1 -0
  94. package/utils/headers.js +1 -1
  95. package/.eslintrc.json +0 -96
  96. package/.github/FUNDING.yml +0 -4
  97. package/.github/copilot-instructions.md +0 -100
  98. package/.github/workflows/publish.yml +0 -29
  99. package/.github/workflows/test-matrix.yml +0 -37
  100. package/.test/benchmark.js +0 -28
  101. package/.test/constants.js +0 -4
  102. package/.test/cookietester.js +0 -19
  103. package/.test/http2server.js +0 -35
  104. package/.test/httpserver.js +0 -32
  105. package/.test/index.js +0 -498
  106. package/.test/multipromise.js +0 -32
  107. package/.test/tls.js +0 -75
  108. package/.test/urlencoded.js +0 -54
  109. package/.vscode/launch.json +0 -35
  110. package/.vscode/settings.json +0 -5
  111. package/CHANGELOG.md +0 -10
  112. package/CODE_OF_CONDUCT.md +0 -76
  113. package/errata/index.js +0 -1
  114. package/examples/starter.js +0 -11
  115. package/index.js +0 -4
  116. package/jsconfig.json +0 -12
  117. package/lib/index.js +0 -3
  118. package/middleware/ContentReaderMiddleware.js +0 -249
  119. package/middleware/ContentWriterMiddleware.js +0 -161
  120. package/middleware/SendHeadersMiddleware.js +0 -47
  121. package/middleware/index.js +0 -11
  122. package/polyfill/FormData.js +0 -164
  123. package/rollup.config.js +0 -8
  124. package/scripts/check-teapot.mjs +0 -40
  125. package/scripts/test-all-sync.sh +0 -6
  126. package/scripts/test-all.sh +0 -7
  127. package/test/fixtures/stream.js +0 -68
  128. package/test/helpers/HttpListener/construct.js +0 -18
  129. package/test/helpers/HttpListener/customOptions.js +0 -22
  130. package/test/helpers/HttpListener/doubleCreate.js +0 -40
  131. package/test/helpers/HttpListener/events.js +0 -77
  132. package/test/helpers/HttpListener/http.js +0 -31
  133. package/test/helpers/HttpListener/http2.js +0 -41
  134. package/test/helpers/HttpListener/https.js +0 -38
  135. package/test/helpers/HttpListener/startAll.js +0 -31
  136. package/test/helpers/HttpListener/stopNotStarted.js +0 -23
  137. package/test/lib/HttpHandler/class.js +0 -8
  138. package/test/lib/HttpHandler/handleRequest.js +0 -11
  139. package/test/lib/HttpHandler/middleware.js +0 -941
  140. package/test/lib/HttpHandler/parse.js +0 -41
  141. package/test/lib/HttpRequest/class.js +0 -8
  142. package/test/lib/HttpRequest/downstream.js +0 -171
  143. package/test/lib/HttpRequest/properties.js +0 -101
  144. package/test/lib/HttpRequest/read.js +0 -518
  145. package/test/lib/HttpResponse/async-iterable-middleware.js +0 -37
  146. package/test/lib/HttpResponse/async-iterable.js +0 -31
  147. package/test/lib/HttpResponse/class.js +0 -8
  148. package/test/lib/HttpResponse/properties.js +0 -59
  149. package/test/lib/HttpResponse/send.js +0 -275
  150. package/test/lib/HttpTransaction/class.js +0 -8
  151. package/test/lib/HttpTransaction/ping.js +0 -50
  152. package/test/lib/HttpTransaction/push.js +0 -89
  153. package/test/middleware/SendJsonMiddleware.js +0 -222
  154. package/test/sanity.js +0 -10
  155. package/test/templates/error-teapot.js +0 -47
  156. package/test/templates/starter.js +0 -93
  157. package/tsconfig.json +0 -30
@@ -1,19 +0,0 @@
1
- import CookieObject from '../data/CookieObject.js';
2
-
3
- [
4
- 'id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT',
5
- 'id=a3fWa; Max-Age=2592000',
6
- 'qwerty=219ffwef9w0f; Domain=somecompany.co.uk',
7
- 'sessionId=e8bb43229de9; Domain=foo.example.com',
8
- '__Secure-ID=123; Secure; Domain=example.com',
9
- '__Host-ID=123; Secure; Path=/',
10
- 'test="abc1234";',
11
- 'random',
12
- ].forEach((cookie) => {
13
- const handler = new CookieObject(cookie);
14
- const rebuilt = new CookieObject(handler.toJSON());
15
- console.log(cookie);
16
- console.log(rebuilt.toString());
17
- console.dir(handler);
18
- console.dir(rebuilt);
19
- });
@@ -1,35 +0,0 @@
1
- import http2 from 'node:http2';
2
-
3
- import { HTTPS_HOST, HTTPS_PORT } from './constants.js';
4
-
5
- /** @type {http2.Http2SecureServer} */
6
- let http2Server = null;
7
-
8
- /**
9
- * @param {http2.SecureServerOptions} [options]
10
- * @return {Promise<http2.Http2SecureServer>}
11
- */
12
- export function start(options = {}) {
13
- return new Promise((resolve, reject) => {
14
- http2Server = http2.createSecureServer(options);
15
- http2Server.listen(HTTPS_PORT, HTTPS_HOST, () => resolve(http2Server));
16
- http2Server.addListener('error', reject);
17
- });
18
- }
19
-
20
- /** @return {Promise<void>} */
21
- export function stop() {
22
- return new Promise((resolve, reject) => {
23
- if (!http2Server) {
24
- resolve();
25
- return;
26
- }
27
- http2Server.close((err) => {
28
- if (err) {
29
- reject(err);
30
- return;
31
- }
32
- resolve();
33
- });
34
- });
35
- }
@@ -1,32 +0,0 @@
1
- import http from 'node:http';
2
-
3
- import { HTTP_HOST, HTTP_PORT } from './constants.js';
4
-
5
- /** @type {http.Server} */
6
- let httpServer = null;
7
-
8
- /** @return {Promise<http.Server>} */
9
- export function start() {
10
- return new Promise((resolve, reject) => {
11
- httpServer = http.createServer();
12
- httpServer.listen(HTTP_PORT, HTTP_HOST, () => resolve(httpServer));
13
- httpServer.addListener('error', reject);
14
- });
15
- }
16
-
17
- /** @return {Promise<void>} */
18
- export function stop() {
19
- return new Promise((resolve, reject) => {
20
- if (!httpServer) {
21
- resolve();
22
- return;
23
- }
24
- httpServer.close((err) => {
25
- if (err) {
26
- reject(err);
27
- return;
28
- }
29
- resolve();
30
- });
31
- });
32
- }
package/.test/index.js DELETED
@@ -1,498 +0,0 @@
1
- // @ts-check
2
-
3
- /* eslint-disable no-console */
4
-
5
- import { existsSync, readFileSync } from 'node:fs';
6
-
7
- import HttpListener from '../helpers/HttpListener.js';
8
- import RequestHeaders from '../helpers/RequestHeaders.js';
9
- import ResponseHeaders from '../helpers/ResponseHeaders.js';
10
- import HttpHandler from '../lib/HttpHandler.js';
11
- import AutoHeadersMiddleware from '../middleware/AutoHeadersMiddleware.js';
12
- import CORSMiddleware from '../middleware/CORSMiddleware.js';
13
- import ContentDecoderMiddleware from '../middleware/ContentDecoderMiddleware.js';
14
- import ContentEncoderMiddleware from '../middleware/ContentEncoderMiddleware.js';
15
- import ContentLengthMiddleware from '../middleware/ContentLengthMiddleware.js';
16
- import HashMiddleware from '../middleware/HashMiddleware.js';
17
- import HeadMethodMiddleware from '../middleware/HeadMethodMiddleware.js';
18
- import MethodMiddleware from '../middleware/MethodMiddleware.js';
19
- import PathMiddleware from '../middleware/PathMiddleware.js';
20
- import SendJsonMiddleware from '../middleware/SendJsonMiddleware.js';
21
- import SendStringMiddleware from '../middleware/SendStringMiddleware.js';
22
-
23
- import {
24
- HTTPS_HOST, HTTPS_PORT, HTTP_HOST, HTTP_PORT,
25
- } from './constants.js';
26
- import * as tls from './tls.js';
27
- import { ServerResponse } from 'node:http';
28
-
29
- /** @typedef {import('../types').MiddlewareFunction} MiddlewareFunction */
30
-
31
- /**
32
- * Redirect to HTTPS/2
33
- * @type {MiddlewareFunction}
34
- */
35
- function redirectHttpsMiddleware({request,response}) {
36
- if (request.protocol === 'https:') {
37
- return true;
38
- }
39
- const url = new URL(request.url);
40
- url.protocol = 'https:';
41
- url.port = HTTPS_PORT.toString(10);
42
- const Location = url.href;
43
- response.headers.location = Location;
44
- return 301;
45
- }
46
-
47
- /** @type {MiddlewareFunction} */
48
- function indexMiddleware(transaction) {
49
- console.log('indexMiddleware');
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
- }
55
- return /* html */ `
56
- <html>
57
- <head><script src="script.js"></script></head>
58
- </body>
59
- ${new Date()}
60
- <img src="fake.png"/>
61
- <form action="form" method="POST"><input name="field"><input type="submit" value="POST"></form>
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>
73
- </body>
74
- </html>
75
- `;
76
- }
77
-
78
- /** @type {MiddlewareFunction} */
79
- function largeMiddleware({request}) {
80
- console.log('largeMiddleware');
81
- request.headers['content-type'] = 'text/html';
82
- let block = '';
83
- const len = Number.parseInt(request.searchParams.get('lines'), 10) || 10_000;
84
- for (let i = 0; i < len; i += 1) {
85
- block += `<pre>${i.toString(36)}</pre><br>`;
86
- }
87
- return /* html */ `
88
- <html>
89
- <head></head>
90
- </body>
91
- ${block}
92
- </body>
93
- </html>
94
- `;
95
- }
96
-
97
- /** @type {MiddlewareFunction} */
98
- function chunkMiddleware({ request, response }) {
99
- console.log('chunkMiddleware');
100
- response.headers['content-type'] = 'text/html';
101
- let block = '';
102
- for (let i = 0; i < 1000; i += 1) {
103
- block += `<pre>${Math.random().toString(36).slice(2, 18)}</pre><br>`;
104
- }
105
- const delay = Number.parseInt(request.searchParams.get('delay'), 10) || 0;
106
- let stream = response.getPipeline();
107
- return new Promise((resolve) => {
108
- const timingFn = delay ? setTimeout : process.nextTick;
109
- timingFn(() => {
110
- console.log('write1');
111
- stream.write(/* html */ `
112
- <html>
113
- <head></head>
114
- </body>
115
- `);
116
- }, delay);
117
- timingFn(() => {
118
- console.log('write2');
119
- stream.write(block);
120
- }, delay * 2);
121
- timingFn(() => {
122
- console.log('write3');
123
- stream.write(/* html */ `
124
- </body>
125
- </html>
126
- `);
127
- }, delay * 3);
128
- timingFn(() => {
129
- stream.end();
130
- resolve(HttpHandler.END);
131
- }, delay * 4);
132
- });
133
- }
134
-
135
- /** @type {MiddlewareFunction} */
136
- function plainTextMiddleware({ response }) {
137
- console.log('plainTextMiddleware');
138
- response.status = 200;
139
- response.headers['content-type'] = 'text/html';
140
- response.headers['content-encoding'] = 'identity';
141
- return 'This is always in plaintext';
142
- }
143
-
144
- /** @type {MiddlewareFunction} */
145
- function blankMiddleware({ response }) {
146
- console.log('blankMiddleware');
147
- response.headers['content-type'] = 'text/html';
148
- response.headers['content-length'] = '0';
149
- return 200;
150
- }
151
-
152
- /** @type {MiddlewareFunction} */
153
- function gzipMiddleware({ response }) {
154
- console.log('gzipMiddleware');
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
- }
160
-
161
- /** @type {MiddlewareFunction} */
162
- function corsTest({ response }) {
163
- console.log('cors');
164
- response.statusCode = 200;
165
- response.headers['content-type'] = 'text/html';
166
- return /* html */ `
167
- <html>
168
- <head>
169
- <script type="text/javascript">
170
- fetch('http://127.0.0.1:8080/input.json', {
171
- headers: [['Content-Type', '']],
172
- method: 'POST', body: JSON.stringify({test: 'content'}),
173
- })
174
- .then((response) => response.json())
175
- .then(console.log)
176
- .catch(console.error);
177
- </script>
178
- </head>
179
- </body>
180
- <h1>CORS TEST</h1>
181
- ${new Date()}
182
- </body>
183
- </html>
184
- `;
185
- }
186
-
187
- /** @type {MiddlewareFunction} */
188
- function scriptMiddleware(transaction) {
189
- const response = transaction.response;
190
- console.log('scriptMiddleware');
191
- console.log('Holding script');
192
- return new Promise((resolve) => {
193
- setTimeout(() => {
194
- response.statusCode = 200;
195
- response.headers['content-type'] = 'text/javascript';
196
- if (transaction.canPushPath) {
197
- transaction.pushPath('/fake.js').catch(console.error);
198
- } else {
199
- console.log('RIP Push');
200
- }
201
- console.log('Releasing script');
202
- response.end(/* js */ `
203
- console.log('hello');
204
- let data = '';
205
- for(let i = 0; i < 10 ; i++) {
206
- data += Math.random().toString(36).slice(2, 18);
207
- }
208
- console.log(data);
209
- fetch('http://127.0.0.1:8080/echo.json', {
210
- method: 'POST',
211
- body: JSON.stringify({data}),
212
- headers: [['Content-Type', 'application/json']],
213
- }).then((response) => response.json())
214
- .then((response) => console.log('match', response.data === data))
215
- .catch(console.error);
216
- `);
217
- resolve(HttpHandler.END);
218
- }, 0);
219
- });
220
- }
221
-
222
- ServerResponse
223
-
224
- /** @type {MiddlewareFunction} */
225
- function outputMiddleware({ request, response }) {
226
- const reqHeaders = new RequestHeaders(request);
227
- console.log(request.headers.cookie);
228
- console.log('reqHeaders.cookieEntries.test', reqHeaders.cookieEntries.test);
229
- console.log('req.headers.cookie', request.headers.cookie);
230
- console.log('reqHeaders.cookies.get("test")', reqHeaders.cookies.get('test'));
231
- console.log('reqHeaders.cookies.all("test")', reqHeaders.cookies.all('test'));
232
- console.log('reqHeaders.cookieEntries.test?.[0]', reqHeaders.cookieEntries.test?.[0]);
233
- console.log('reqHeaders.cookieEntries.test?.[1]', reqHeaders.cookieEntries.test?.[1]);
234
- console.log('reqHeaders.cookieEntries.test2?.[0]', reqHeaders.cookieEntries.test2?.[0]);
235
- console.log('reqHeaders.cookieEntries.test4', reqHeaders.cookieEntries.test4);
236
- console.log("'test' in reqHeaders.cookieEntries", 'test' in reqHeaders.cookieEntries);
237
- console.log("'test4' in reqHeaders.cookieEntries", 'test4' in reqHeaders.cookieEntries);
238
- console.log('req.headers.cookie', request.headers.cookie);
239
-
240
- const resHeaders = new ResponseHeaders(response);
241
- resHeaders.cookies.set({
242
- name: 'test',
243
- value: Date.now().toString(),
244
- });
245
- resHeaders.cookies.set({ name: 'test2', value: Date.now().toString() });
246
- resHeaders.cookies.set(`test3=${Date.now()}`);
247
- resHeaders.cookies.set('test=newtest;Path=/test/*');
248
- const testCookieObject = resHeaders.cookies.get('test');
249
- testCookieObject.value = 'replaced';
250
- resHeaders.cookies.expire('test4');
251
- console.log('all', JSON.stringify(resHeaders.cookies.findAll(), null, 2));
252
- resHeaders.cookies.expireAll('test');
253
- resHeaders.cookieEntries.forEach((c) => console.log(c.toString()));
254
- console.log('wiping');
255
- resHeaders.cookieEntries.splice(0, resHeaders.cookieEntries.length);
256
- resHeaders.cookieEntries.forEach((c) => console.log(c.toString()));
257
- console.log('pushing 1 ');
258
- const held = resHeaders.cookies.set(`held=${Date.now()}`);
259
- resHeaders.cookies.remove(held);
260
- resHeaders.cookieEntries.forEach((c) => console.log(c.toString()));
261
- console.log('modifying held');
262
- held.secure = true;
263
- // console.log('unshifting 1 ');
264
- // resHeaders.cookieEntries.unshift(new CookieObject(`unshift=${Date.now()}`));
265
- resHeaders.cookieEntries.forEach((c) => console.log(c.toString()));
266
- console.log('putting back');
267
- resHeaders.cookieEntries.unshift(held);
268
- resHeaders.cookieEntries.forEach((c) => console.log(c.toString()));
269
- resHeaders.cookies.set('novalue=');
270
- resHeaders.cookies.set('noname');
271
- resHeaders.cookies.set('=blankname;path=/');
272
- resHeaders.cookies.set('quotedblank=""');
273
- resHeaders.cookieEntries.forEach((c) => console.log(c.toString()));
274
- // res.statusCode = 200;
275
- // resHeaders.mediaType = 'application/json';
276
- return { now: new Date() };
277
- }
278
-
279
- /** @type {MiddlewareFunction} */
280
- async function inputMiddleware({ request, response }) {
281
- console.log('inputMiddleware');
282
-
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;
293
- }
294
-
295
- /** @type {MiddlewareFunction} */
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 }) {
303
- console.log('formGetMiddleware');
304
-
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);
310
- }
311
-
312
- /** @type {MiddlewareFunction} */
313
- function outputURLMiddleware({ request, response, state }) {
314
- console.log('outputURLMiddleware', state.path);
315
- return response.code(200).end(request.pathname);
316
- }
317
-
318
- /** @type {MiddlewareFunction} */
319
- async function formPostMiddleware({ request, response }) {
320
- console.log('formPostMiddleware');
321
- /** @type {FormData} */
322
- const value = await request.read();
323
- const stringData = JSON.stringify(value);
324
- return `type: ${request.headers['content-type']}\n${stringData.toString()}`;
325
- }
326
-
327
- /** @type {MiddlewareFunction} */
328
- function getJSONMiddleware() {
329
- console.log('getJSONMiddleware');
330
- return { now: new Date() };
331
- }
332
-
333
- const USE_HTTPS_REDIRECT = false;
334
- const SHOULD_CRASH = false;
335
-
336
- /**
337
- *
338
- */
339
- function setupHandler() {
340
- const { middleware, errorHandlers } = HttpHandler.defaultInstance;
341
- // Conditional statement
342
- middleware.push(USE_HTTPS_REDIRECT ? redirectHttpsMiddleware : null);
343
- const middlewareObject = new Set([
344
- // Allow Cross-Origin Resource Sharing
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);
368
- /** @type {any} */
369
- const getMiddlewareArray = [
370
- MethodMiddleware.GET,
371
- [new PathMiddleware(/^\/(index.html?)?$/), indexMiddleware],
372
- [new PathMiddleware('/large.html'), largeMiddleware],
373
- [new PathMiddleware('/chunk.html'), chunkMiddleware],
374
- [new PathMiddleware('/blank.html'), blankMiddleware],
375
- [new PathMiddleware('/nocontent.html'), 204],
376
- [new PathMiddleware('/gzip.html'), gzipMiddleware],
377
- [new PathMiddleware('/plaintext.html'), plainTextMiddleware],
378
- [new PathMiddleware('/get.json'), getJSONMiddleware],
379
- [new PathMiddleware('/form'), formGetMiddleware],
380
- ];
381
- setTest.add(getMiddlewareArray);
382
- // Modify after insertion
383
- getMiddlewareArray.push(
384
- [new PathMiddleware({ path: '/script.js' }), scriptMiddleware],
385
- );
386
- // Add terminator middleware
387
- getMiddlewareArray.push(
388
- [new PathMiddleware({ path: /\/output.json$/ }), outputMiddleware],
389
- );
390
-
391
- // Predefined Route
392
- const route = [
393
- [new PathMiddleware('/'), outputURLMiddleware],
394
- [new PathMiddleware('/foo'), outputURLMiddleware],
395
- [new PathMiddleware('/bar'), outputURLMiddleware],
396
- [new PathMiddleware('/baz'), outputURLMiddleware],
397
- ];
398
-
399
- // Automatic Path Routing
400
- middleware.push([
401
- MethodMiddleware.GET,
402
- [new PathMiddleware({ path: /^(\/subpath)\/?.*/, subPath: true }), [
403
- [new PathMiddleware('/'), outputURLMiddleware],
404
- [new PathMiddleware('/foo'), outputURLMiddleware],
405
- [new PathMiddleware('/bar'), outputURLMiddleware],
406
- ]],
407
- [PathMiddleware.SUBPATH('/subpath2'), [
408
- [new PathMiddleware('/'), outputURLMiddleware],
409
- [new PathMiddleware('/foo'), outputURLMiddleware],
410
- [new PathMiddleware('/baz'), outputURLMiddleware],
411
- ]],
412
- [PathMiddleware.SUBPATH('/subpath3'), route],
413
- [PathMiddleware.SUBPATH('/foo'), [
414
- [new PathMiddleware('/'), outputURLMiddleware],
415
- [PathMiddleware.SUBPATH('/bar'), [
416
- [new PathMiddleware('/'), outputURLMiddleware],
417
- [PathMiddleware.SUBPATH('/baz'), route],
418
- ]],
419
- ]],
420
- ]);
421
-
422
- // Add error handler
423
- middleware.push([MethodMiddleware.GET,
424
- new PathMiddleware('/error'),
425
- function throwError() {
426
- throw new Error('unexpected error!');
427
- }]);
428
- middleware.push([
429
- MethodMiddleware.GET,
430
- new PathMiddleware('/catch'),
431
- function throwError() {
432
- throw new Error('EXCEPTION!');
433
- },
434
- {
435
- onError: ({ error }) => {
436
- console.log('I catch and rethrow errors.');
437
- throw error;
438
- },
439
- },
440
- {
441
- onError: ({ error }) => {
442
- console.warn('Caught exception. Allowing continue.', error);
443
- return HttpHandler.CONTINUE;
444
- },
445
- },
446
- 'Error was caught.'
447
- ]);
448
-
449
- // Inline middleware and filter adding
450
- middleware.push(
451
- [
452
- MethodMiddleware.POST,
453
- [new PathMiddleware('/input.json'), inputMiddleware],
454
- [new PathMiddleware('/echo.json'), echoMiddleware],
455
- [new PathMiddleware('/form'), formPostMiddleware],
456
- ],
457
- [
458
- () => SHOULD_CRASH,
459
- () => { throw new Error('Break not called!'); },
460
- ],
461
- [
462
- MethodMiddleware.GET,
463
- new PathMiddleware('/cors.html'),
464
- corsTest,
465
- HttpHandler.END,
466
- ],
467
- ({ request }) => {
468
- console.log('Unknown', request.url);
469
- return 404;
470
- },
471
- );
472
-
473
- errorHandlers.push({
474
- onError({ error }) {
475
- console.error('Uncaught exception');
476
- console.error(error);
477
- return 500;
478
- },
479
- });
480
- console.dir([
481
- middleware,
482
- errorHandlers,
483
- ], { colors: true, depth: null });
484
- }
485
-
486
- const listener = new HttpListener({
487
- insecureHost: HTTP_HOST,
488
- insecurePort: HTTP_PORT,
489
- secureHost: HTTPS_HOST,
490
- securePort: HTTPS_PORT,
491
- tlsOptions: tls.setup({
492
- key: existsSync('./certificates/localhost-privkey.pem') && readFileSync('./certificates/localhost-privkey.pem'),
493
- cert: existsSync('./certificates/localhost-privkey.pem') && readFileSync('./certificates/localhost-cert.pem'),
494
- }),
495
- });
496
-
497
- setupHandler();
498
- listener.startAll().then(() => console.log('Ready.'));
@@ -1,32 +0,0 @@
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
-
package/.test/tls.js DELETED
@@ -1,75 +0,0 @@
1
- import { createSecureContext } from 'node:tls';
2
-
3
- import x509 from '@fidm/x509';
4
-
5
- /** @typedef {import('tls').SecureContext} SecureContext */
6
- /** @typedef {import('tls').TlsOptions} TlsOptions */
7
-
8
- /**
9
- * @callback SNICallback
10
- * @param {Error} err
11
- * @param {SecureContext} ctx
12
- * @return {void}
13
- */
14
-
15
- /** @type {Map<string, SecureContext>} */
16
- const contexts = new Map();
17
-
18
- /** @type {Map<string, TlsOptions>} */
19
- export const contextOptions = new Map();
20
-
21
- /**
22
- * @param {TlsOptions} defaultTlsOptions
23
- * @return {TlsOptions}
24
- */
25
- export function setup(defaultTlsOptions) {
26
- contextOptions.set('default', defaultTlsOptions);
27
- return defaultTlsOptions;
28
- }
29
-
30
- /**
31
- * @param {string} commonName
32
- * @param {string} serverName
33
- * @return {boolean}
34
- */
35
- function checkCommonName(commonName, serverName) {
36
- if (!commonName || !serverName) return false;
37
- return new RegExp(`^${commonName.replace('.', '\\.').replace('*', '.*')}$`, 'i').test(serverName);
38
- }
39
-
40
- /**
41
- * @param {string} servername
42
- * @param {SNICallback} cb
43
- * @return {void}
44
- */
45
- export function SNICallback(servername, cb) {
46
- const hasContext = contexts.has(servername);
47
- if (hasContext) {
48
- console.debug('Resuing context created for:', servername);
49
- cb(null, contexts.get(servername));
50
- return;
51
- }
52
- const options = [...contextOptions.values()].find((ctx) => {
53
- if (!ctx.cert) return false;
54
- const buffer = (typeof ctx.cert === 'string') ? Buffer.from(ctx.cert) : ctx.cert;
55
- const cert = x509.Certificate.fromPEM(buffer);
56
- // Check expired
57
- if (!cert.validTo || new Date() > cert.validTo) return false;
58
- // Check not ready
59
- if (!cert.validFrom || new Date() < cert.validFrom) return false;
60
- if (!cert || !cert.subject) return false;
61
- if (checkCommonName(cert.subject.commonName, servername)) return true;
62
- if (!cert.dnsNames) return false;
63
- return cert.dnsNames.some((/** @type {string} */ name) => checkCommonName(name, servername));
64
- });
65
- let context = null;
66
- if (options) {
67
- context = createSecureContext(options);
68
- console.debug('Context created for:', servername);
69
- } else {
70
- console.warn('Unknown servername:', servername);
71
- // Pick any?
72
- }
73
- contexts.set(servername, context);
74
- cb(null, context);
75
- }