@jsenv/server 12.1.0 → 12.2.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/README.md +2 -2
- package/package.json +5 -7
- package/src/internal/server-polyglot.js +10 -10
- package/src/startServer.js +63 -40
package/README.md
CHANGED
|
@@ -92,8 +92,8 @@ import { startServer } from "@jsenv/server"
|
|
|
92
92
|
|
|
93
93
|
await startServer({
|
|
94
94
|
protocol: "https",
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
certificate: readFileSyncAsString("./server.crt"),
|
|
96
|
+
privateKey: readFileSyncAsString("./server.key"),
|
|
97
97
|
allowHttpRequestOnHttps: true,
|
|
98
98
|
requestToResponse: (request) => {
|
|
99
99
|
const clientUsesHttp = request.origin.startsWith("http:")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/server",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.2.0",
|
|
4
4
|
"description": "Write your Node.js server using pure functions",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -31,15 +31,14 @@
|
|
|
31
31
|
"/main.js"
|
|
32
32
|
],
|
|
33
33
|
"scripts": {
|
|
34
|
-
"eslint-check": "node ./node_modules/eslint/bin/eslint.js . --ext=.js,.mjs",
|
|
35
34
|
"importmap-generate": "node ./script/importmap/generate_importmap.mjs",
|
|
36
35
|
"measure-performances": "node --expose-gc ./script/performance/generate_performance_report.mjs --log",
|
|
37
|
-
"test": "node
|
|
36
|
+
"test": "node ./script/test/test.mjs",
|
|
38
37
|
"test-with-coverage": "npm run test -- --coverage",
|
|
39
38
|
"generate-html-snapshots": "node ./test/internal_error/generate_html_snapshot_files.mjs",
|
|
40
|
-
"
|
|
41
|
-
"prettier-
|
|
42
|
-
"prettier-
|
|
39
|
+
"eslint-check": "node ./node_modules/eslint/bin/eslint.js . --ext=.js,.mjs",
|
|
40
|
+
"prettier-check": "prettier --check .",
|
|
41
|
+
"prettier-write": "prettier --write .",
|
|
43
42
|
"certificate-authority-install": "node ./script/certificate/certificate_authority_install.mjs",
|
|
44
43
|
"playwright-install": "npx playwright install-deps && npx playwright install",
|
|
45
44
|
"prepublishOnly": "node ./script/publish/remove_postinstall.mjs",
|
|
@@ -63,7 +62,6 @@
|
|
|
63
62
|
"@jsenv/importmap-node-module": "2.7.1",
|
|
64
63
|
"@jsenv/package-publish": "1.6.2",
|
|
65
64
|
"@jsenv/performance-impact": "2.2.1",
|
|
66
|
-
"@jsenv/prettier-check-project": "5.6.1",
|
|
67
65
|
"eslint": "8.2.0",
|
|
68
66
|
"eslint-plugin-import": "2.25.3",
|
|
69
67
|
"eventsource": "1.1.0",
|
|
@@ -11,13 +11,13 @@ import { listenEvent } from "./listenEvent.js"
|
|
|
11
11
|
export const createPolyglotServer = async ({
|
|
12
12
|
http2 = false,
|
|
13
13
|
http1Allowed = true,
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
certificate,
|
|
15
|
+
privateKey,
|
|
16
16
|
}) => {
|
|
17
17
|
const httpServer = http.createServer()
|
|
18
18
|
const tlsServer = await createSecureServer({
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
certificate,
|
|
20
|
+
privateKey,
|
|
21
21
|
http2,
|
|
22
22
|
http1Allowed,
|
|
23
23
|
})
|
|
@@ -63,24 +63,24 @@ export const createPolyglotServer = async ({
|
|
|
63
63
|
// The async part is just to lazyly import "http2" or "https"
|
|
64
64
|
// so that these module are parsed only if used.
|
|
65
65
|
const createSecureServer = async ({
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
certificate,
|
|
67
|
+
privateKey,
|
|
68
68
|
http2,
|
|
69
69
|
http1Allowed,
|
|
70
70
|
}) => {
|
|
71
71
|
if (http2) {
|
|
72
72
|
const { createSecureServer } = await import("http2")
|
|
73
73
|
return createSecureServer({
|
|
74
|
-
cert:
|
|
75
|
-
key:
|
|
74
|
+
cert: certificate,
|
|
75
|
+
key: privateKey,
|
|
76
76
|
allowHTTP1: http1Allowed,
|
|
77
77
|
})
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
const { createServer } = await import("https")
|
|
81
81
|
return createServer({
|
|
82
|
-
cert:
|
|
83
|
-
key:
|
|
82
|
+
cert: certificate,
|
|
83
|
+
key: privateKey,
|
|
84
84
|
})
|
|
85
85
|
}
|
|
86
86
|
|
package/src/startServer.js
CHANGED
|
@@ -47,8 +47,8 @@ export const startServer = async ({
|
|
|
47
47
|
ip = "0.0.0.0", // will it work on windows ? https://github.com/nodejs/node/issues/14900
|
|
48
48
|
port = 0, // assign a random available port
|
|
49
49
|
portHint,
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
privateKey,
|
|
51
|
+
certificate,
|
|
52
52
|
|
|
53
53
|
// when inside a worker, we should not try to stop server on SIGINT
|
|
54
54
|
// otherwise it can create an EPIPE error while primary process tries
|
|
@@ -74,11 +74,11 @@ export const startServer = async ({
|
|
|
74
74
|
throw new Error(`protocol must be http or https, got ${protocol}`)
|
|
75
75
|
}
|
|
76
76
|
if (protocol === "https") {
|
|
77
|
-
if (!
|
|
78
|
-
throw new Error(`missing
|
|
77
|
+
if (!certificate) {
|
|
78
|
+
throw new Error(`missing certificate for https server`)
|
|
79
79
|
}
|
|
80
|
-
if (!
|
|
81
|
-
throw new Error(`missing
|
|
80
|
+
if (!privateKey) {
|
|
81
|
+
throw new Error(`missing privateKey for https server`)
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
if (http2 && protocol !== "https") {
|
|
@@ -134,8 +134,8 @@ export const startServer = async ({
|
|
|
134
134
|
protocol,
|
|
135
135
|
redirectHttpToHttps,
|
|
136
136
|
allowHttpRequestOnHttps,
|
|
137
|
-
|
|
138
|
-
|
|
137
|
+
certificate,
|
|
138
|
+
privateKey,
|
|
139
139
|
http2,
|
|
140
140
|
http1Allowed,
|
|
141
141
|
})
|
|
@@ -332,29 +332,6 @@ export const startServer = async ({
|
|
|
332
332
|
const pushResponse = async ({ path, method }, { requestNode }) => {
|
|
333
333
|
const http2Stream = nodeResponse.stream
|
|
334
334
|
|
|
335
|
-
if (typeof path !== "string" || path[0] !== "/") {
|
|
336
|
-
addRequestLog(requestNode, {
|
|
337
|
-
type: "warn",
|
|
338
|
-
value: `pushResponse call ignored because path is invalid (must be a string starting with "/", found ${path})`,
|
|
339
|
-
})
|
|
340
|
-
return
|
|
341
|
-
}
|
|
342
|
-
if (!request.http2) {
|
|
343
|
-
addRequestLog(requestNode, {
|
|
344
|
-
type: "warn",
|
|
345
|
-
value: `pushResponse call ignored because request is not http2`,
|
|
346
|
-
})
|
|
347
|
-
return
|
|
348
|
-
}
|
|
349
|
-
const canPushStream = testCanPushStream(http2Stream)
|
|
350
|
-
if (!canPushStream.can) {
|
|
351
|
-
addRequestLog(requestNode, {
|
|
352
|
-
type: "debug",
|
|
353
|
-
value: `Ignoring call to pushResponse because ${canPushStream.reason}`,
|
|
354
|
-
})
|
|
355
|
-
return
|
|
356
|
-
}
|
|
357
|
-
|
|
358
335
|
// being able to push a stream is nice to have
|
|
359
336
|
// so when it fails it's not critical
|
|
360
337
|
const onPushStreamError = (e) => {
|
|
@@ -488,7 +465,10 @@ export const startServer = async ({
|
|
|
488
465
|
redirectRequest,
|
|
489
466
|
})
|
|
490
467
|
if (returnValue) {
|
|
491
|
-
requestPlugins.push(
|
|
468
|
+
requestPlugins.push({
|
|
469
|
+
pluginName,
|
|
470
|
+
...returnValue,
|
|
471
|
+
})
|
|
492
472
|
}
|
|
493
473
|
}
|
|
494
474
|
})
|
|
@@ -497,10 +477,53 @@ export const startServer = async ({
|
|
|
497
477
|
: await generateResponseDescription({
|
|
498
478
|
requestToResponse,
|
|
499
479
|
request,
|
|
500
|
-
pushResponse: ({ path, method }) => {
|
|
480
|
+
pushResponse: async ({ path, method }) => {
|
|
481
|
+
if (typeof path !== "string" || path[0] !== "/") {
|
|
482
|
+
addRequestLog(requestNode, {
|
|
483
|
+
type: "warn",
|
|
484
|
+
value: `response push ignored because path is invalid (must be a string starting with "/", found ${path})`,
|
|
485
|
+
})
|
|
486
|
+
return
|
|
487
|
+
}
|
|
488
|
+
if (!request.http2) {
|
|
489
|
+
addRequestLog(requestNode, {
|
|
490
|
+
type: "warn",
|
|
491
|
+
value: `response push ignored because request is not http2`,
|
|
492
|
+
})
|
|
493
|
+
return
|
|
494
|
+
}
|
|
495
|
+
const canPushStream = testCanPushStream(nodeResponse.stream)
|
|
496
|
+
if (!canPushStream.can) {
|
|
497
|
+
addRequestLog(requestNode, {
|
|
498
|
+
type: "debug",
|
|
499
|
+
value: `response push ignored because ${canPushStream.reason}`,
|
|
500
|
+
})
|
|
501
|
+
return
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
let prevented = false
|
|
505
|
+
const prevent = () => {
|
|
506
|
+
prevented = true
|
|
507
|
+
}
|
|
508
|
+
const preventedByPlugin = requestPlugins.find((requestPlugin) => {
|
|
509
|
+
const { onPushResponse } = requestPlugin
|
|
510
|
+
if (!onPushResponse) {
|
|
511
|
+
return false
|
|
512
|
+
}
|
|
513
|
+
onPushResponse({ path, method }, { prevent })
|
|
514
|
+
return prevented
|
|
515
|
+
})
|
|
516
|
+
if (prevented) {
|
|
517
|
+
addRequestLog(requestNode, {
|
|
518
|
+
type: "debug",
|
|
519
|
+
value: `response push prevented by "${preventedByPlugin.pluginName}" plugin`,
|
|
520
|
+
})
|
|
521
|
+
return
|
|
522
|
+
}
|
|
523
|
+
|
|
501
524
|
const requestChildNode = { logs: [], children: [] }
|
|
502
525
|
requestNode.children.push(requestChildNode)
|
|
503
|
-
|
|
526
|
+
await pushResponse(
|
|
504
527
|
{ path, method },
|
|
505
528
|
{
|
|
506
529
|
requestNode: requestChildNode,
|
|
@@ -701,8 +724,8 @@ const createNodeServer = async ({
|
|
|
701
724
|
protocol,
|
|
702
725
|
redirectHttpToHttps,
|
|
703
726
|
allowHttpRequestOnHttps,
|
|
704
|
-
|
|
705
|
-
|
|
727
|
+
certificate,
|
|
728
|
+
privateKey,
|
|
706
729
|
http2,
|
|
707
730
|
http1Allowed,
|
|
708
731
|
}) => {
|
|
@@ -712,8 +735,8 @@ const createNodeServer = async ({
|
|
|
712
735
|
|
|
713
736
|
if (redirectHttpToHttps || allowHttpRequestOnHttps) {
|
|
714
737
|
return createPolyglotServer({
|
|
715
|
-
|
|
716
|
-
|
|
738
|
+
certificate,
|
|
739
|
+
privateKey,
|
|
717
740
|
http2,
|
|
718
741
|
http1Allowed,
|
|
719
742
|
})
|
|
@@ -721,8 +744,8 @@ const createNodeServer = async ({
|
|
|
721
744
|
|
|
722
745
|
const { createServer } = await import("https")
|
|
723
746
|
return createServer({
|
|
724
|
-
cert:
|
|
725
|
-
key:
|
|
747
|
+
cert: certificate,
|
|
748
|
+
key: privateKey,
|
|
726
749
|
})
|
|
727
750
|
}
|
|
728
751
|
|