@jsenv/server 11.0.0 → 12.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/main.js +2 -4
- package/package.json +26 -32
- package/src/cors/plugin_cors.js +1 -3
- package/src/internal/memoize.js +24 -0
- package/src/internal/server-polyglot.js +10 -10
- package/src/plugin_request_waiting_check.js +0 -2
- package/src/service_composition/routing.js +35 -0
- package/src/service_composition/service_composition.js +1 -21
- package/src/sse/createSSERoom.js +16 -0
- package/src/startServer.js +65 -43
package/README.md
CHANGED
|
@@ -70,7 +70,10 @@ const notFoundService = (request) => {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
const server = await startServer({
|
|
73
|
-
requestToResponse: composeServices(
|
|
73
|
+
requestToResponse: composeServices({
|
|
74
|
+
index: indexService,
|
|
75
|
+
otherwise: notFoundService,
|
|
76
|
+
}),
|
|
74
77
|
})
|
|
75
78
|
|
|
76
79
|
const fetch = await import("node-fetch")
|
|
@@ -89,8 +92,8 @@ import { startServer } from "@jsenv/server"
|
|
|
89
92
|
|
|
90
93
|
await startServer({
|
|
91
94
|
protocol: "https",
|
|
92
|
-
|
|
93
|
-
|
|
95
|
+
certificate: readFileSyncAsString("./server.crt"),
|
|
96
|
+
privateKey: readFileSyncAsString("./server.key"),
|
|
94
97
|
allowHttpRequestOnHttps: true,
|
|
95
98
|
requestToResponse: (request) => {
|
|
96
99
|
const clientUsesHttp = request.origin.startsWith("http:")
|
package/main.js
CHANGED
|
@@ -5,10 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
export { startServer } from "./src/startServer.js"
|
|
8
|
-
export {
|
|
9
|
-
|
|
10
|
-
composeServicesWithTiming,
|
|
11
|
-
} from "./src/service_composition/service_composition.js"
|
|
8
|
+
export { composeServices } from "./src/service_composition/service_composition.js"
|
|
9
|
+
export { setupRoutes } from "./src/service_composition/routing.js"
|
|
12
10
|
export { jsenvServerInternalErrorToResponse } from "./src/jsenvServerInternalErrorToResponse.js"
|
|
13
11
|
export { readRequestBody } from "./src/readRequestBody.js"
|
|
14
12
|
export { fetchFileSystem } from "./src/fetch_filesystem.js"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/server",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "12.2.1",
|
|
4
4
|
"description": "Write your Node.js server using pure functions",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"url": "https://github.com/jsenv/server"
|
|
14
14
|
},
|
|
15
15
|
"engines": {
|
|
16
|
-
"node": ">=
|
|
16
|
+
"node": ">=16.12.0"
|
|
17
17
|
},
|
|
18
18
|
"publishConfig": {
|
|
19
19
|
"access": "public"
|
|
@@ -25,52 +25,46 @@
|
|
|
25
25
|
},
|
|
26
26
|
"./*": "./*"
|
|
27
27
|
},
|
|
28
|
+
"main": "./main.js",
|
|
28
29
|
"files": [
|
|
29
30
|
"/src/",
|
|
30
31
|
"/main.js"
|
|
31
32
|
],
|
|
32
33
|
"scripts": {
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"test": "node
|
|
34
|
+
"importmap": "node ./script/importmap/importmap.mjs",
|
|
35
|
+
"eslint": "node ./node_modules/eslint/bin/eslint.js . --ext=.js,.mjs",
|
|
36
|
+
"performance": "node --expose-gc ./script/performance/performance.mjs --log",
|
|
37
|
+
"test": "node ./script/test/test.mjs",
|
|
37
38
|
"test-with-coverage": "npm run test -- --coverage",
|
|
38
39
|
"generate-html-snapshots": "node ./test/internal_error/generate_html_snapshot_files.mjs",
|
|
39
|
-
"prettier
|
|
40
|
-
"prettier-format-stage": "npm run prettier-format -- --staged",
|
|
41
|
-
"prettier-check": "npm run prettier-format -- --dry-run",
|
|
40
|
+
"prettier": "prettier --write .",
|
|
42
41
|
"certificate-authority-install": "node ./script/certificate/certificate_authority_install.mjs",
|
|
43
|
-
"playwright-install": "npx playwright install-deps && npx playwright install"
|
|
44
|
-
"prepublishOnly": "node ./script/publish/remove_postinstall.mjs",
|
|
45
|
-
"postpublish": "node ./script/publish/restore_postinstall.mjs"
|
|
42
|
+
"playwright-install": "npx playwright install-deps && npx playwright install"
|
|
46
43
|
},
|
|
47
44
|
"dependencies": {
|
|
48
|
-
"@jsenv/abort": "4.1.
|
|
45
|
+
"@jsenv/abort": "4.1.2",
|
|
49
46
|
"@jsenv/logger": "4.0.1",
|
|
50
47
|
"@jsenv/url-meta": "6.0.1",
|
|
51
|
-
"node-fetch": "2.6.2"
|
|
48
|
+
"node-fetch": "2.6.2",
|
|
49
|
+
"path-to-regexp": "6.2.0"
|
|
52
50
|
},
|
|
53
51
|
"devDependencies": {
|
|
54
|
-
"@
|
|
55
|
-
"@
|
|
56
|
-
"@jsenv/
|
|
57
|
-
"@jsenv/
|
|
58
|
-
"@jsenv/core": "23.7.1",
|
|
59
|
-
"@jsenv/eslint-config": "16.0.8",
|
|
60
|
-
"@jsenv/filesystem": "2.5.1",
|
|
52
|
+
"@jsenv/assert": "2.4.0",
|
|
53
|
+
"@jsenv/core": "24.5.0",
|
|
54
|
+
"@jsenv/eslint-config": "16.0.9",
|
|
55
|
+
"@jsenv/filesystem": "2.6.0",
|
|
61
56
|
"@jsenv/github-release-package": "1.2.3",
|
|
62
|
-
"@jsenv/https-local": "1.0.
|
|
63
|
-
"@jsenv/importmap-eslint-resolver": "5.1
|
|
64
|
-
"@jsenv/importmap-node-module": "
|
|
57
|
+
"@jsenv/https-local": "1.0.3",
|
|
58
|
+
"@jsenv/importmap-eslint-resolver": "5.2.1",
|
|
59
|
+
"@jsenv/importmap-node-module": "4.0.1",
|
|
65
60
|
"@jsenv/package-publish": "1.6.2",
|
|
66
61
|
"@jsenv/performance-impact": "2.2.1",
|
|
67
|
-
"
|
|
68
|
-
"eslint": "
|
|
69
|
-
"eslint-plugin-import": "2.25.2",
|
|
62
|
+
"eslint": "8.4.1",
|
|
63
|
+
"eslint-plugin-import": "2.25.3",
|
|
70
64
|
"eventsource": "1.1.0",
|
|
71
|
-
"fastify": "3.
|
|
72
|
-
"fastify-static": "4.
|
|
73
|
-
"playwright": "1.
|
|
74
|
-
"prettier": "2.
|
|
65
|
+
"fastify": "3.25.0",
|
|
66
|
+
"fastify-static": "4.5.0",
|
|
67
|
+
"playwright": "1.17.1",
|
|
68
|
+
"prettier": "2.5.1"
|
|
75
69
|
}
|
|
76
|
-
}
|
|
70
|
+
}
|
package/src/cors/plugin_cors.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { urlToOrigin } from "@jsenv/filesystem"
|
|
2
|
-
|
|
3
1
|
export const jsenvAccessControlAllowedHeaders = ["x-requested-with"]
|
|
4
2
|
|
|
5
3
|
export const jsenvAccessControlAllowedMethods = [
|
|
@@ -107,7 +105,7 @@ const generateAccessControlHeaders = ({
|
|
|
107
105
|
allowedOriginArray.push(headers.origin)
|
|
108
106
|
vary.push("origin")
|
|
109
107
|
} else if ("referer" in headers) {
|
|
110
|
-
allowedOriginArray.push(
|
|
108
|
+
allowedOriginArray.push(new URL(headers.referer).origin)
|
|
111
109
|
vary.push("referer")
|
|
112
110
|
} else {
|
|
113
111
|
allowedOriginArray.push("*")
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export const memoize = (compute) => {
|
|
2
|
+
let memoized = false
|
|
3
|
+
let memoizedValue
|
|
4
|
+
|
|
5
|
+
const fnWithMemoization = (...args) => {
|
|
6
|
+
if (memoized) {
|
|
7
|
+
return memoizedValue
|
|
8
|
+
}
|
|
9
|
+
// if compute is recursive wait for it to be fully done before storing the value
|
|
10
|
+
// so set memoized boolean after the call
|
|
11
|
+
memoizedValue = compute(...args)
|
|
12
|
+
memoized = true
|
|
13
|
+
return memoizedValue
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
fnWithMemoization.forget = () => {
|
|
17
|
+
const value = memoizedValue
|
|
18
|
+
memoized = false
|
|
19
|
+
memoizedValue = undefined
|
|
20
|
+
return value
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return fnWithMemoization
|
|
24
|
+
}
|
|
@@ -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
|
|
|
@@ -16,8 +16,6 @@ export const pluginRequestWaitingCheck = ({
|
|
|
16
16
|
} = {}) => {
|
|
17
17
|
return {
|
|
18
18
|
plugin_request_waiting_check: {
|
|
19
|
-
init: () => {},
|
|
20
|
-
|
|
21
19
|
onRequest: (request, { logger }) => {
|
|
22
20
|
const timeout = setTimeout(
|
|
23
21
|
() => requestWaitingCallback({ request, logger, requestWaitingMs }),
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { createRequire } from "node:module"
|
|
2
|
+
|
|
3
|
+
const require = createRequire(import.meta.url)
|
|
4
|
+
|
|
5
|
+
export const setupRoutes = (routes) => {
|
|
6
|
+
const { match } = require("path-to-regexp")
|
|
7
|
+
|
|
8
|
+
const candidates = Object.keys(routes).map((pathPattern) => {
|
|
9
|
+
const applyPatternMatching = match(pathPattern, {
|
|
10
|
+
decode: decodeURIComponent,
|
|
11
|
+
})
|
|
12
|
+
return {
|
|
13
|
+
applyPatternMatching,
|
|
14
|
+
requestHandler: routes[pathPattern],
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
return (request, { pushResponse, redirectRequest }) => {
|
|
19
|
+
let result
|
|
20
|
+
const found = candidates.find((candidate) => {
|
|
21
|
+
result = candidate.applyPatternMatching(request.pathname)
|
|
22
|
+
return Boolean(result)
|
|
23
|
+
})
|
|
24
|
+
if (found) {
|
|
25
|
+
return found.requestHandler(
|
|
26
|
+
{
|
|
27
|
+
...request,
|
|
28
|
+
routeParams: result.params,
|
|
29
|
+
},
|
|
30
|
+
{ pushResponse, redirectRequest },
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
return null
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -2,27 +2,7 @@ import { timeFunction } from "@jsenv/server/src/server_timing/timing_measure.js"
|
|
|
2
2
|
import { composeTwoResponses } from "@jsenv/server/src/internal/response_composition.js"
|
|
3
3
|
import { applyRedirectionToRequest } from "@jsenv/server/src/internal/request_factory.js"
|
|
4
4
|
|
|
5
|
-
export const composeServices = (
|
|
6
|
-
return (request, { pushResponse }) => {
|
|
7
|
-
const redirectRequest = (requestRedirection) => {
|
|
8
|
-
request = applyRedirectionToRequest(request, requestRedirection)
|
|
9
|
-
return null
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
return firstOperationMatching({
|
|
13
|
-
array: callbacks,
|
|
14
|
-
start: (callback) => callback(request, { pushResponse, redirectRequest }),
|
|
15
|
-
predicate: (returnValue) => {
|
|
16
|
-
if (returnValue === null || typeof returnValue !== "object") {
|
|
17
|
-
return false
|
|
18
|
-
}
|
|
19
|
-
return true
|
|
20
|
-
},
|
|
21
|
-
})
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export const composeServicesWithTiming = (namedServices) => {
|
|
5
|
+
export const composeServices = (namedServices) => {
|
|
26
6
|
return async (request, { pushResponse }) => {
|
|
27
7
|
const redirectRequest = (requestRedirection) => {
|
|
28
8
|
request = applyRedirectionToRequest(request, requestRedirection)
|
package/src/sse/createSSERoom.js
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
// https://www.html5rocks.com/en/tutorials/eventsource/basics/
|
|
9
9
|
export const createSSERoom = ({
|
|
10
10
|
logLevel,
|
|
11
|
+
effect = () => {},
|
|
11
12
|
// do not keep process alive because of rooms, something else must keep it alive
|
|
12
13
|
keepProcessAlive = false,
|
|
13
14
|
keepaliveDuration = 30 * 1000,
|
|
@@ -29,6 +30,7 @@ export const createSSERoom = ({
|
|
|
29
30
|
let previousEventId = 0
|
|
30
31
|
let opened = false
|
|
31
32
|
let interval
|
|
33
|
+
let cleanupEffect = CLEANUP_NOOP
|
|
32
34
|
|
|
33
35
|
const join = (request) => {
|
|
34
36
|
// should we ensure a given request can join a room only once?
|
|
@@ -56,6 +58,14 @@ export const createSSERoom = ({
|
|
|
56
58
|
next,
|
|
57
59
|
complete,
|
|
58
60
|
}
|
|
61
|
+
if (clients.size === 0) {
|
|
62
|
+
const effectReturnValue = effect()
|
|
63
|
+
if (typeof effectReturnValue === "function") {
|
|
64
|
+
cleanupEffect = effectReturnValue
|
|
65
|
+
} else {
|
|
66
|
+
cleanupEffect = CLEANUP_NOOP
|
|
67
|
+
}
|
|
68
|
+
}
|
|
59
69
|
clients.add(client)
|
|
60
70
|
logger.debug(
|
|
61
71
|
`A client has joined. Number of client in room: ${clients.size}`,
|
|
@@ -101,6 +111,10 @@ export const createSSERoom = ({
|
|
|
101
111
|
|
|
102
112
|
return () => {
|
|
103
113
|
clients.delete(client)
|
|
114
|
+
if (clients.size === 0) {
|
|
115
|
+
cleanupEffect()
|
|
116
|
+
cleanupEffect = CLEANUP_NOOP
|
|
117
|
+
}
|
|
104
118
|
logger.debug(`A client left. Number of client in room: ${clients.size}`)
|
|
105
119
|
}
|
|
106
120
|
})
|
|
@@ -210,6 +224,8 @@ export const createSSERoom = ({
|
|
|
210
224
|
return room
|
|
211
225
|
}
|
|
212
226
|
|
|
227
|
+
const CLEANUP_NOOP = () => {}
|
|
228
|
+
|
|
213
229
|
const requestMap = new Map()
|
|
214
230
|
|
|
215
231
|
const connectRequestAndRoom = (request, room, roomObservable) => {
|
package/src/startServer.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import http from "node:http"
|
|
2
2
|
import cluster from "node:cluster"
|
|
3
|
-
import { memoize } from "@jsenv/filesystem"
|
|
4
3
|
import { createDetailedMessage, createLogger } from "@jsenv/logger"
|
|
5
4
|
import {
|
|
6
5
|
Abort,
|
|
@@ -23,6 +22,7 @@ import { listen, stopListening } from "./internal/listen.js"
|
|
|
23
22
|
import { composeTwoResponses } from "./internal/response_composition.js"
|
|
24
23
|
import { listenRequest } from "./internal/listenRequest.js"
|
|
25
24
|
import { listenServerConnectionError } from "./internal/listenServerConnectionError.js"
|
|
25
|
+
import { memoize } from "./internal/memoize.js"
|
|
26
26
|
import { jsenvServerInternalErrorToResponse } from "./jsenvServerInternalErrorToResponse.js"
|
|
27
27
|
import {
|
|
28
28
|
STOP_REASON_INTERNAL_ERROR,
|
|
@@ -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) => {
|
|
@@ -483,11 +460,15 @@ export const startServer = async ({
|
|
|
483
460
|
if (onRequest) {
|
|
484
461
|
const returnValue = onRequest(request, {
|
|
485
462
|
warn,
|
|
463
|
+
logger,
|
|
486
464
|
shortcircuitResponse,
|
|
487
465
|
redirectRequest,
|
|
488
466
|
})
|
|
489
467
|
if (returnValue) {
|
|
490
|
-
requestPlugins.push(
|
|
468
|
+
requestPlugins.push({
|
|
469
|
+
pluginName,
|
|
470
|
+
...returnValue,
|
|
471
|
+
})
|
|
491
472
|
}
|
|
492
473
|
}
|
|
493
474
|
})
|
|
@@ -496,10 +477,53 @@ export const startServer = async ({
|
|
|
496
477
|
: await generateResponseDescription({
|
|
497
478
|
requestToResponse,
|
|
498
479
|
request,
|
|
499
|
-
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
|
+
|
|
500
524
|
const requestChildNode = { logs: [], children: [] }
|
|
501
525
|
requestNode.children.push(requestChildNode)
|
|
502
|
-
|
|
526
|
+
await pushResponse(
|
|
503
527
|
{ path, method },
|
|
504
528
|
{
|
|
505
529
|
requestNode: requestChildNode,
|
|
@@ -700,8 +724,8 @@ const createNodeServer = async ({
|
|
|
700
724
|
protocol,
|
|
701
725
|
redirectHttpToHttps,
|
|
702
726
|
allowHttpRequestOnHttps,
|
|
703
|
-
|
|
704
|
-
|
|
727
|
+
certificate,
|
|
728
|
+
privateKey,
|
|
705
729
|
http2,
|
|
706
730
|
http1Allowed,
|
|
707
731
|
}) => {
|
|
@@ -711,8 +735,8 @@ const createNodeServer = async ({
|
|
|
711
735
|
|
|
712
736
|
if (redirectHttpToHttps || allowHttpRequestOnHttps) {
|
|
713
737
|
return createPolyglotServer({
|
|
714
|
-
|
|
715
|
-
|
|
738
|
+
certificate,
|
|
739
|
+
privateKey,
|
|
716
740
|
http2,
|
|
717
741
|
http1Allowed,
|
|
718
742
|
})
|
|
@@ -720,8 +744,8 @@ const createNodeServer = async ({
|
|
|
720
744
|
|
|
721
745
|
const { createServer } = await import("https")
|
|
722
746
|
return createServer({
|
|
723
|
-
cert:
|
|
724
|
-
key:
|
|
747
|
+
cert: certificate,
|
|
748
|
+
key: privateKey,
|
|
725
749
|
})
|
|
726
750
|
}
|
|
727
751
|
|
|
@@ -729,12 +753,10 @@ const generateResponseDescription = async ({
|
|
|
729
753
|
requestToResponse,
|
|
730
754
|
request,
|
|
731
755
|
pushResponse,
|
|
732
|
-
requestFactory,
|
|
733
756
|
}) => {
|
|
734
757
|
try {
|
|
735
758
|
const returnValue = await requestToResponse(request, {
|
|
736
759
|
pushResponse,
|
|
737
|
-
requestFactory,
|
|
738
760
|
})
|
|
739
761
|
return {
|
|
740
762
|
responseProperties: returnValue,
|