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.
- package/README.md +4 -4
- package/data/CookieObject.js +1 -1
- package/{types/index.js → data/custom-types.js} +1 -1
- package/{types/typings.d.ts → data/middleware.d.ts} +1 -1
- package/helpers/RequestReader.js +1 -1
- package/helpers/ResponseHeaders.js +9 -10
- package/lib/HttpHandler.js +4 -4
- package/lib/HttpRequest.js +2 -2
- package/lib/HttpResponse.js +2 -2
- package/lib/HttpTransaction.js +2 -2
- package/middleware/AutoHeadersMiddleware.js +2 -2
- package/middleware/CORSMiddleware.js +3 -3
- package/middleware/CaseInsensitiveHeadersMiddleware.js +2 -2
- package/middleware/ContentDecoderMiddleware.js +1 -1
- package/middleware/ContentEncoderMiddleware.js +2 -2
- package/middleware/ContentLengthMiddleware.js +2 -2
- package/middleware/HashMiddleware.js +2 -2
- package/middleware/HeadMethodMiddleware.js +3 -3
- package/middleware/MethodMiddleware.js +3 -3
- package/middleware/PathMiddleware.js +4 -4
- package/middleware/ReadFormData.js +1 -1
- package/middleware/SendJsonMiddleware.js +4 -4
- package/middleware/SendStringMiddleware.js +3 -3
- package/package.json +21 -4
- package/templates/starter.js +2 -2
- package/types/data/CookieObject.d.ts +34 -0
- package/types/data/CookieObject.d.ts.map +1 -0
- package/types/data/custom-types.d.ts +111 -0
- package/types/data/custom-types.d.ts.map +1 -0
- package/types/errata/socketio.d.ts +11 -0
- package/types/errata/socketio.d.ts.map +1 -0
- package/types/examples/starter.d.ts +2 -0
- package/types/examples/starter.d.ts.map +1 -0
- package/types/helpers/HeadersParser.d.ts +27 -0
- package/types/helpers/HeadersParser.d.ts.map +1 -0
- package/types/helpers/HttpListener.d.ts +84 -0
- package/types/helpers/HttpListener.d.ts.map +1 -0
- package/types/helpers/RequestHeaders.d.ts +25 -0
- package/types/helpers/RequestHeaders.d.ts.map +1 -0
- package/types/helpers/RequestReader.d.ts +52 -0
- package/types/helpers/RequestReader.d.ts.map +1 -0
- package/types/helpers/ResponseHeaders.d.ts +126 -0
- package/types/helpers/ResponseHeaders.d.ts.map +1 -0
- package/types/helpers/index.d.ts +6 -0
- package/types/helpers/index.d.ts.map +1 -0
- package/types/lib/HttpHandler.d.ts +79 -0
- package/types/lib/HttpHandler.d.ts.map +1 -0
- package/types/lib/HttpRequest.d.ts +175 -0
- package/types/lib/HttpRequest.d.ts.map +1 -0
- package/types/lib/HttpResponse.d.ts +117 -0
- package/types/lib/HttpResponse.d.ts.map +1 -0
- package/types/lib/HttpTransaction.d.ts +114 -0
- package/types/lib/HttpTransaction.d.ts.map +1 -0
- package/types/middleware/AutoHeadersMiddleware.d.ts +27 -0
- package/types/middleware/AutoHeadersMiddleware.d.ts.map +1 -0
- package/types/middleware/CORSMiddleware.d.ts +65 -0
- package/types/middleware/CORSMiddleware.d.ts.map +1 -0
- package/types/middleware/CaseInsensitiveHeadersMiddleware.d.ts +27 -0
- package/types/middleware/CaseInsensitiveHeadersMiddleware.d.ts.map +1 -0
- package/types/middleware/ContentDecoderMiddleware.d.ts +17 -0
- package/types/middleware/ContentDecoderMiddleware.d.ts.map +1 -0
- package/types/middleware/ContentEncoderMiddleware.d.ts +48 -0
- package/types/middleware/ContentEncoderMiddleware.d.ts.map +1 -0
- package/types/middleware/ContentLengthMiddleware.d.ts +38 -0
- package/types/middleware/ContentLengthMiddleware.d.ts.map +1 -0
- package/types/middleware/HashMiddleware.d.ts +28 -0
- package/types/middleware/HashMiddleware.d.ts.map +1 -0
- package/types/middleware/HeadMethodMiddleware.d.ts +12 -0
- package/types/middleware/HeadMethodMiddleware.d.ts.map +1 -0
- package/types/middleware/MethodMiddleware.d.ts +40 -0
- package/types/middleware/MethodMiddleware.d.ts.map +1 -0
- package/types/middleware/PathMiddleware.d.ts +81 -0
- package/types/middleware/PathMiddleware.d.ts.map +1 -0
- package/types/middleware/ReadFormData.d.ts +7 -0
- package/types/middleware/ReadFormData.d.ts.map +1 -0
- package/types/middleware/SendJsonMiddleware.d.ts +51 -0
- package/types/middleware/SendJsonMiddleware.d.ts.map +1 -0
- package/types/middleware/SendStringMiddleware.d.ts +35 -0
- package/types/middleware/SendStringMiddleware.d.ts.map +1 -0
- package/types/templates/starter.d.ts +15 -0
- package/types/templates/starter.d.ts.map +1 -0
- package/types/utils/AsyncObject.d.ts +38 -0
- package/types/utils/AsyncObject.d.ts.map +1 -0
- package/types/utils/CaseInsensitiveObject.d.ts +9 -0
- package/types/utils/CaseInsensitiveObject.d.ts.map +1 -0
- package/types/utils/function.d.ts +2 -0
- package/types/utils/function.d.ts.map +1 -0
- package/types/utils/headers.d.ts +7 -0
- package/types/utils/headers.d.ts.map +1 -0
- package/types/utils/qualityValues.d.ts +12 -0
- package/types/utils/qualityValues.d.ts.map +1 -0
- package/types/utils/stream.d.ts +6 -0
- package/types/utils/stream.d.ts.map +1 -0
- package/utils/headers.js +1 -1
- package/.eslintrc.json +0 -96
- package/.github/FUNDING.yml +0 -4
- package/.github/copilot-instructions.md +0 -100
- package/.github/workflows/publish.yml +0 -29
- package/.github/workflows/test-matrix.yml +0 -37
- package/.test/benchmark.js +0 -28
- package/.test/constants.js +0 -4
- package/.test/cookietester.js +0 -19
- package/.test/http2server.js +0 -35
- package/.test/httpserver.js +0 -32
- package/.test/index.js +0 -498
- package/.test/multipromise.js +0 -32
- package/.test/tls.js +0 -75
- package/.test/urlencoded.js +0 -54
- package/.vscode/launch.json +0 -35
- package/.vscode/settings.json +0 -5
- package/CHANGELOG.md +0 -10
- package/CODE_OF_CONDUCT.md +0 -76
- package/errata/index.js +0 -1
- package/examples/starter.js +0 -11
- package/index.js +0 -4
- package/jsconfig.json +0 -12
- package/lib/index.js +0 -3
- package/middleware/ContentReaderMiddleware.js +0 -249
- package/middleware/ContentWriterMiddleware.js +0 -161
- package/middleware/SendHeadersMiddleware.js +0 -47
- package/middleware/index.js +0 -11
- package/polyfill/FormData.js +0 -164
- package/rollup.config.js +0 -8
- package/scripts/check-teapot.mjs +0 -40
- package/scripts/test-all-sync.sh +0 -6
- package/scripts/test-all.sh +0 -7
- package/test/fixtures/stream.js +0 -68
- package/test/helpers/HttpListener/construct.js +0 -18
- package/test/helpers/HttpListener/customOptions.js +0 -22
- package/test/helpers/HttpListener/doubleCreate.js +0 -40
- package/test/helpers/HttpListener/events.js +0 -77
- package/test/helpers/HttpListener/http.js +0 -31
- package/test/helpers/HttpListener/http2.js +0 -41
- package/test/helpers/HttpListener/https.js +0 -38
- package/test/helpers/HttpListener/startAll.js +0 -31
- package/test/helpers/HttpListener/stopNotStarted.js +0 -23
- package/test/lib/HttpHandler/class.js +0 -8
- package/test/lib/HttpHandler/handleRequest.js +0 -11
- package/test/lib/HttpHandler/middleware.js +0 -941
- package/test/lib/HttpHandler/parse.js +0 -41
- package/test/lib/HttpRequest/class.js +0 -8
- package/test/lib/HttpRequest/downstream.js +0 -171
- package/test/lib/HttpRequest/properties.js +0 -101
- package/test/lib/HttpRequest/read.js +0 -518
- package/test/lib/HttpResponse/async-iterable-middleware.js +0 -37
- package/test/lib/HttpResponse/async-iterable.js +0 -31
- package/test/lib/HttpResponse/class.js +0 -8
- package/test/lib/HttpResponse/properties.js +0 -59
- package/test/lib/HttpResponse/send.js +0 -275
- package/test/lib/HttpTransaction/class.js +0 -8
- package/test/lib/HttpTransaction/ping.js +0 -50
- package/test/lib/HttpTransaction/push.js +0 -89
- package/test/middleware/SendJsonMiddleware.js +0 -222
- package/test/sanity.js +0 -10
- package/test/templates/error-teapot.js +0 -47
- package/test/templates/starter.js +0 -93
- package/tsconfig.json +0 -30
package/.test/cookietester.js
DELETED
|
@@ -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
|
-
});
|
package/.test/http2server.js
DELETED
|
@@ -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
|
-
}
|
package/.test/httpserver.js
DELETED
|
@@ -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.'));
|
package/.test/multipromise.js
DELETED
|
@@ -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
|
-
}
|