webhoster 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +74 -58
- package/.github/copilot-instructions.md +100 -0
- package/.github/workflows/test-matrix.yml +37 -0
- package/.test/benchmark.js +28 -0
- package/.test/constants.js +4 -0
- package/{test → .test}/http2server.js +1 -1
- package/{test → .test}/httpserver.js +1 -1
- package/{test → .test}/index.js +178 -192
- package/.test/multipromise.js +32 -0
- package/{test → .test}/tls.js +3 -3
- package/{test → .test}/urlencoded.js +3 -0
- package/.vscode/launch.json +24 -3
- package/README.md +116 -90
- package/data/CookieObject.js +14 -14
- package/errata/socketio.js +6 -11
- package/examples/starter.js +11 -0
- package/helpers/HeadersParser.js +7 -8
- package/helpers/HttpListener.js +387 -42
- package/helpers/RequestHeaders.js +43 -36
- package/helpers/RequestReader.js +27 -26
- package/helpers/ResponseHeaders.js +47 -36
- package/jsconfig.json +1 -1
- package/lib/HttpHandler.js +447 -277
- package/lib/HttpRequest.js +383 -39
- package/lib/HttpResponse.js +316 -52
- package/lib/HttpTransaction.js +146 -0
- package/middleware/AutoHeadersMiddleware.js +73 -0
- package/middleware/CORSMiddleware.js +45 -47
- package/middleware/CaseInsensitiveHeadersMiddleware.js +5 -11
- package/middleware/ContentDecoderMiddleware.js +81 -35
- package/middleware/ContentEncoderMiddleware.js +179 -132
- package/middleware/ContentLengthMiddleware.js +66 -41
- package/middleware/ContentWriterMiddleware.js +5 -5
- package/middleware/HashMiddleware.js +68 -40
- package/middleware/HeadMethodMiddleware.js +24 -21
- package/middleware/MethodMiddleware.js +29 -36
- package/middleware/PathMiddleware.js +49 -66
- package/middleware/ReadFormData.js +99 -0
- package/middleware/SendJsonMiddleware.js +131 -0
- package/middleware/SendStringMiddleware.js +87 -0
- package/package.json +38 -29
- package/polyfill/FormData.js +164 -0
- package/rollup.config.js +0 -1
- package/scripts/test-all-sync.sh +6 -0
- package/scripts/test-all.sh +7 -0
- package/templates/starter.js +53 -0
- package/test/fixtures/stream.js +68 -0
- package/test/helpers/HttpListener/construct.js +18 -0
- package/test/helpers/HttpListener/customOptions.js +22 -0
- package/test/helpers/HttpListener/doubleCreate.js +40 -0
- package/test/helpers/HttpListener/events.js +77 -0
- package/test/helpers/HttpListener/http.js +31 -0
- package/test/helpers/HttpListener/http2.js +41 -0
- package/test/helpers/HttpListener/https.js +38 -0
- package/test/helpers/HttpListener/startAll.js +31 -0
- package/test/helpers/HttpListener/stopNotStarted.js +23 -0
- package/test/lib/HttpHandler/class.js +8 -0
- package/test/lib/HttpHandler/handleRequest.js +11 -0
- package/test/lib/HttpHandler/middleware.js +941 -0
- package/test/lib/HttpHandler/parse.js +41 -0
- package/test/lib/HttpRequest/class.js +8 -0
- package/test/lib/HttpRequest/downstream.js +171 -0
- package/test/lib/HttpRequest/properties.js +101 -0
- package/test/lib/HttpRequest/read.js +518 -0
- package/test/lib/HttpResponse/class.js +8 -0
- package/test/lib/HttpResponse/properties.js +59 -0
- package/test/lib/HttpResponse/send.js +275 -0
- package/test/lib/HttpTransaction/class.js +8 -0
- package/test/lib/HttpTransaction/ping.js +50 -0
- package/test/lib/HttpTransaction/push.js +89 -0
- package/test/middleware/SendJsonMiddleware.js +222 -0
- package/test/sanity.js +10 -0
- package/test/templates/starter.js +93 -0
- package/tsconfig.json +12 -0
- package/types/index.js +61 -34
- package/types/typings.d.ts +8 -9
- package/utils/AsyncObject.js +6 -3
- package/utils/CaseInsensitiveObject.js +2 -3
- package/utils/function.js +1 -7
- package/utils/headers.js +42 -0
- package/utils/qualityValues.js +1 -1
- package/utils/stream.js +4 -20
- package/index.cjs +0 -3190
- package/test/constants.js +0 -4
- /package/{test → .test}/cookietester.js +0 -0
package/{test → .test}/index.js
RENAMED
|
@@ -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
|
|
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({
|
|
33
|
-
if (
|
|
34
|
-
return
|
|
35
|
+
function redirectHttpsMiddleware({request,response}) {
|
|
36
|
+
if (request.protocol === 'https:') {
|
|
37
|
+
return true;
|
|
35
38
|
}
|
|
36
|
-
const url = new URL(
|
|
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
|
-
|
|
41
|
-
|
|
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(
|
|
48
|
+
function indexMiddleware(transaction) {
|
|
48
49
|
console.log('indexMiddleware');
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
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({
|
|
79
|
+
function largeMiddleware({request}) {
|
|
71
80
|
console.log('largeMiddleware');
|
|
72
|
-
|
|
73
|
-
res.headers['content-type'] = 'text/html';
|
|
81
|
+
request.headers['content-type'] = 'text/html';
|
|
74
82
|
let block = '';
|
|
75
|
-
const len = Number.parseInt(
|
|
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
|
-
|
|
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({
|
|
98
|
+
function chunkMiddleware({ request, response }) {
|
|
92
99
|
console.log('chunkMiddleware');
|
|
93
|
-
|
|
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).
|
|
103
|
+
block += `<pre>${Math.random().toString(36).slice(2, 18)}</pre><br>`;
|
|
98
104
|
}
|
|
99
|
-
const delay = Number.parseInt(
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
|
|
119
|
+
stream.write(block);
|
|
113
120
|
}, delay * 2);
|
|
114
121
|
timingFn(() => {
|
|
115
122
|
console.log('write3');
|
|
116
|
-
|
|
123
|
+
stream.write(/* html */ `
|
|
117
124
|
</body>
|
|
118
|
-
|
|
119
|
-
|
|
125
|
+
</html>
|
|
126
|
+
`);
|
|
120
127
|
}, delay * 3);
|
|
121
|
-
timingFn(() => {
|
|
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({
|
|
136
|
+
function plainTextMiddleware({ response }) {
|
|
127
137
|
console.log('plainTextMiddleware');
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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({
|
|
145
|
+
function blankMiddleware({ response }) {
|
|
137
146
|
console.log('blankMiddleware');
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
|
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
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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({
|
|
162
|
+
function corsTest({ response }) {
|
|
163
163
|
console.log('cors');
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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(
|
|
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
|
-
|
|
195
|
-
|
|
196
|
-
if (
|
|
197
|
-
|
|
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
|
-
|
|
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).
|
|
206
|
+
data += Math.random().toString(36).slice(2, 18);
|
|
207
207
|
}
|
|
208
208
|
console.log(data);
|
|
209
|
-
fetch('http://127.0.0.1:8080/
|
|
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(
|
|
217
|
+
resolve(HttpHandler.END);
|
|
218
218
|
}, 0);
|
|
219
219
|
});
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
+
ServerResponse
|
|
223
|
+
|
|
222
224
|
/** @type {MiddlewareFunction} */
|
|
223
|
-
function outputMiddleware({
|
|
224
|
-
const reqHeaders = new RequestHeaders(
|
|
225
|
-
console.log(
|
|
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',
|
|
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',
|
|
238
|
+
console.log('req.headers.cookie', request.headers.cookie);
|
|
237
239
|
|
|
238
|
-
const resHeaders = new ResponseHeaders(
|
|
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.
|
|
274
|
+
// res.statusCode = 200;
|
|
273
275
|
// resHeaders.mediaType = 'application/json';
|
|
274
|
-
|
|
276
|
+
return { now: new Date() };
|
|
275
277
|
}
|
|
276
278
|
|
|
277
279
|
/** @type {MiddlewareFunction} */
|
|
278
|
-
async function inputMiddleware({
|
|
280
|
+
async function inputMiddleware({ request, response }) {
|
|
279
281
|
console.log('inputMiddleware');
|
|
280
282
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
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
|
|
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
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
-
|
|
311
|
-
console.log('outputURLMiddleware',
|
|
312
|
-
|
|
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({
|
|
319
|
+
async function formPostMiddleware({ request, response }) {
|
|
319
320
|
console.log('formPostMiddleware');
|
|
320
|
-
|
|
321
|
+
/** @type {FormData} */
|
|
322
|
+
const value = await request.read();
|
|
321
323
|
const stringData = JSON.stringify(value);
|
|
322
|
-
|
|
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(
|
|
328
|
+
function getJSONMiddleware() {
|
|
329
329
|
console.log('getJSONMiddleware');
|
|
330
|
-
|
|
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 {
|
|
340
|
+
const { middleware, errorHandlers } = HttpHandler.defaultInstance;
|
|
340
341
|
// Conditional statement
|
|
341
|
-
|
|
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
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
//
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
const
|
|
372
|
-
middleware.
|
|
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'),
|
|
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
|
-
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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: ({
|
|
435
|
+
onError: ({ error }) => {
|
|
441
436
|
console.log('I catch and rethrow errors.');
|
|
442
|
-
throw
|
|
437
|
+
throw error;
|
|
443
438
|
},
|
|
444
439
|
},
|
|
445
440
|
{
|
|
446
|
-
onError: ({
|
|
447
|
-
console.warn('Caught exception. Allowing continue.',
|
|
448
|
-
return
|
|
441
|
+
onError: ({ error }) => {
|
|
442
|
+
console.warn('Caught exception. Allowing continue.', error);
|
|
443
|
+
return HttpHandler.CONTINUE;
|
|
449
444
|
},
|
|
450
445
|
},
|
|
451
|
-
|
|
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.
|
|
461
|
-
|
|
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
|
-
|
|
457
|
+
[
|
|
467
458
|
() => SHOULD_CRASH,
|
|
468
459
|
() => { throw new Error('Break not called!'); },
|
|
469
460
|
],
|
|
470
|
-
|
|
461
|
+
[
|
|
471
462
|
MethodMiddleware.GET,
|
|
472
463
|
new PathMiddleware('/cors.html'),
|
|
473
464
|
corsTest,
|
|
474
|
-
|
|
465
|
+
HttpHandler.END,
|
|
475
466
|
],
|
|
476
|
-
|
|
477
|
-
console.log('Unknown',
|
|
478
|
-
|
|
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({
|
|
474
|
+
onError({ error }) {
|
|
486
475
|
console.error('Uncaught exception');
|
|
487
|
-
console.error(
|
|
488
|
-
|
|
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
|
+
|
package/{test → .test}/tls.js
RENAMED
|
@@ -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
|
/**
|