@noodleseed/one 0.21.0 → 0.23.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/dist/commands/author-loop.d.ts.map +1 -1
- package/dist/commands/author-loop.js +2 -2
- package/dist/commands/author-loop.js.map +1 -1
- package/dist/commands/catalog-dispatch.d.ts.map +1 -1
- package/dist/commands/catalog-dispatch.js +21 -2
- package/dist/commands/catalog-dispatch.js.map +1 -1
- package/dist/commands/deploy-ops.d.ts.map +1 -1
- package/dist/commands/deploy-ops.js +28 -11
- package/dist/commands/deploy-ops.js.map +1 -1
- package/dist/first-run.d.ts +11 -0
- package/dist/first-run.d.ts.map +1 -1
- package/dist/first-run.js +19 -4
- package/dist/first-run.js.map +1 -1
- package/dist/project-scaffold-templates.d.ts +11 -0
- package/dist/project-scaffold-templates.d.ts.map +1 -0
- package/dist/project-scaffold-templates.js +359 -0
- package/dist/project-scaffold-templates.js.map +1 -0
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +1 -323
- package/dist/project.js.map +1 -1
- package/dist/react.d.ts +2 -2
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +1 -1
- package/dist/react.js.map +1 -1
- package/dist/validate.d.ts +12 -0
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +11 -0
- package/dist/validate.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/curated/hook-notes.d.ts.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/curated/hook-notes.js +2 -1
- package/node_modules/@noodle-borg/agent-kit/dist/curated/hook-notes.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.d.ts.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js +1 -0
- package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/skill-content.d.ts.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/skill-content.js +6 -9
- package/node_modules/@noodle-borg/agent-kit/dist/skill-content.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
- package/node_modules/@noodle-borg/authoring/dist/index.d.ts +3 -3
- package/node_modules/@noodle-borg/authoring/dist/index.d.ts.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/index.js +1 -1
- package/node_modules/@noodle-borg/authoring/dist/index.js.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react/bridge.d.ts +9 -1
- package/node_modules/@noodle-borg/authoring/dist/react/bridge.d.ts.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react/bridge.js +11 -1
- package/node_modules/@noodle-borg/authoring/dist/react/bridge.js.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react/components.d.ts +306 -9
- package/node_modules/@noodle-borg/authoring/dist/react/components.d.ts.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react/components.js +63 -11
- package/node_modules/@noodle-borg/authoring/dist/react/components.js.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react/hooks.d.ts +2 -0
- package/node_modules/@noodle-borg/authoring/dist/react/hooks.d.ts.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react/hooks.js +11 -0
- package/node_modules/@noodle-borg/authoring/dist/react/hooks.js.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react/index.d.ts +7 -3
- package/node_modules/@noodle-borg/authoring/dist/react/index.d.ts.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react/index.js +4 -2
- package/node_modules/@noodle-borg/authoring/dist/react/index.js.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react/native-components.d.ts +1159 -0
- package/node_modules/@noodle-borg/authoring/dist/react/native-components.d.ts.map +1 -0
- package/node_modules/@noodle-borg/authoring/dist/react/native-components.js +66 -0
- package/node_modules/@noodle-borg/authoring/dist/react/native-components.js.map +1 -0
- package/node_modules/@noodle-borg/authoring/dist/react/semantic-components.d.ts +2618 -0
- package/node_modules/@noodle-borg/authoring/dist/react/semantic-components.d.ts.map +1 -0
- package/node_modules/@noodle-borg/authoring/dist/react/semantic-components.js +110 -0
- package/node_modules/@noodle-borg/authoring/dist/react/semantic-components.js.map +1 -0
- package/node_modules/@noodle-borg/authoring/dist/react.d.ts +2 -2
- package/node_modules/@noodle-borg/authoring/dist/react.d.ts.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react.js +1 -1
- package/node_modules/@noodle-borg/authoring/dist/react.js.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/recording.d.ts +1 -1
- package/node_modules/@noodle-borg/authoring/dist/recording.d.ts.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/recording.js +14 -1
- package/node_modules/@noodle-borg/authoring/dist/recording.js.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/server.d.ts +25 -2
- package/node_modules/@noodle-borg/authoring/dist/server.d.ts.map +1 -1
- package/node_modules/@noodle-borg/authoring/dist/server.js +7 -3
- package/node_modules/@noodle-borg/authoring/dist/server.js.map +1 -1
- package/node_modules/@noodle-borg/compiler/dist/compile.d.ts.map +1 -1
- package/node_modules/@noodle-borg/compiler/dist/compile.js +20 -8
- package/node_modules/@noodle-borg/compiler/dist/compile.js.map +1 -1
- package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts +2 -0
- package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts.map +1 -1
- package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js +6 -0
- package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js.map +1 -1
- package/node_modules/@noodle-borg/connector-http/package.json +1 -1
- package/node_modules/@noodle-borg/protocol/dist/mapping.d.ts.map +1 -1
- package/node_modules/@noodle-borg/protocol/dist/mapping.js +8 -0
- package/node_modules/@noodle-borg/protocol/dist/mapping.js.map +1 -1
- package/node_modules/hono/dist/adapter/aws-lambda/handler.js +15 -21
- package/node_modules/hono/dist/adapter/bun/websocket.js +3 -1
- package/node_modules/hono/dist/adapter/lambda-edge/handler.js +8 -2
- package/node_modules/hono/dist/cjs/adapter/aws-lambda/handler.js +15 -21
- package/node_modules/hono/dist/cjs/adapter/bun/websocket.js +3 -1
- package/node_modules/hono/dist/cjs/adapter/lambda-edge/handler.js +8 -2
- package/node_modules/hono/dist/cjs/helper/css/common.js +3 -1
- package/node_modules/hono/dist/cjs/helper/css/index.js +9 -1
- package/node_modules/hono/dist/cjs/jsx/base.js +8 -14
- package/node_modules/hono/dist/cjs/jsx/components.js +41 -21
- package/node_modules/hono/dist/cjs/jsx/context.js +131 -5
- package/node_modules/hono/dist/cjs/jsx/streaming.js +9 -7
- package/node_modules/hono/dist/cjs/middleware/cors/index.js +2 -5
- package/node_modules/hono/dist/cjs/middleware/serve-static/index.js +2 -2
- package/node_modules/hono/dist/cjs/utils/body.js +12 -4
- package/node_modules/hono/dist/cjs/utils/buffer.js +2 -1
- package/node_modules/hono/dist/cjs/validator/validator.js +3 -3
- package/node_modules/hono/dist/helper/css/common.js +3 -1
- package/node_modules/hono/dist/helper/css/index.js +9 -1
- package/node_modules/hono/dist/jsx/base.js +15 -15
- package/node_modules/hono/dist/jsx/components.js +42 -22
- package/node_modules/hono/dist/jsx/context.js +129 -5
- package/node_modules/hono/dist/jsx/streaming.js +10 -8
- package/node_modules/hono/dist/middleware/cors/index.js +2 -5
- package/node_modules/hono/dist/middleware/serve-static/index.js +2 -2
- package/node_modules/hono/dist/types/adapter/aws-lambda/handler.d.ts +1 -1
- package/node_modules/hono/dist/types/jsx/base.d.ts +1 -3
- package/node_modules/hono/dist/types/jsx/context.d.ts +39 -0
- package/node_modules/hono/dist/types/middleware/context-storage/index.d.ts +2 -2
- package/node_modules/hono/dist/types/utils/body.d.ts +1 -1
- package/node_modules/hono/dist/utils/body.js +12 -4
- package/node_modules/hono/dist/utils/buffer.js +2 -1
- package/node_modules/hono/dist/validator/validator.js +3 -3
- package/node_modules/hono/package.json +9 -10
- package/node_modules/tailwindcss/dist/chunk-HMCCH6MG.mjs +1 -0
- package/node_modules/tailwindcss/dist/default-theme.mjs +1 -1
- package/node_modules/tailwindcss/dist/lib.js +13 -13
- package/node_modules/tailwindcss/dist/lib.mjs +18 -18
- package/node_modules/tailwindcss/package.json +2 -2
- package/node_modules/undici/README.md +3 -2
- package/node_modules/undici/docs/docs/api/Agent.md +248 -44
- package/node_modules/undici/docs/docs/api/BalancedPool.md +246 -48
- package/node_modules/undici/docs/docs/api/CacheStorage.md +171 -13
- package/node_modules/undici/docs/docs/api/CacheStore.md +294 -98
- package/node_modules/undici/docs/docs/api/Client.md +365 -178
- package/node_modules/undici/docs/docs/api/ClientStats.md +80 -14
- package/node_modules/undici/docs/docs/api/Connector.md +118 -36
- package/node_modules/undici/docs/docs/api/ContentType.md +65 -25
- package/node_modules/undici/docs/docs/api/Cookies.md +125 -47
- package/node_modules/undici/docs/docs/api/Debug.md +34 -18
- package/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +364 -164
- package/node_modules/undici/docs/docs/api/Dispatcher.md +479 -1093
- package/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +101 -87
- package/node_modules/undici/docs/docs/api/Errors.md +503 -40
- package/node_modules/undici/docs/docs/api/EventSource.md +294 -32
- package/node_modules/undici/docs/docs/api/Fetch.md +680 -31
- package/node_modules/undici/docs/docs/api/GlobalInstallation.md +78 -98
- package/node_modules/undici/docs/docs/api/H2CClient.md +298 -176
- package/node_modules/undici/docs/docs/api/Interceptors.md +355 -0
- package/node_modules/undici/docs/docs/api/MockAgent.md +314 -322
- package/node_modules/undici/docs/docs/api/MockCallHistory.md +272 -98
- package/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +189 -26
- package/node_modules/undici/docs/docs/api/MockClient.md +151 -33
- package/node_modules/undici/docs/docs/api/MockErrors.md +56 -5
- package/node_modules/undici/docs/docs/api/MockPool.md +299 -263
- package/node_modules/undici/docs/docs/api/Pool.md +235 -43
- package/node_modules/undici/docs/docs/api/PoolStats.md +119 -13
- package/node_modules/undici/docs/docs/api/ProxyAgent.md +179 -160
- package/node_modules/undici/docs/docs/api/RedirectHandler.md +238 -63
- package/node_modules/undici/docs/docs/api/RetryAgent.md +113 -26
- package/node_modules/undici/docs/docs/api/RetryHandler.md +161 -77
- package/node_modules/undici/docs/docs/api/RoundRobinPool.md +166 -72
- package/node_modules/undici/docs/docs/api/SnapshotAgent.md +264 -542
- package/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +162 -186
- package/node_modules/undici/docs/docs/api/Util.md +68 -11
- package/node_modules/undici/docs/docs/api/WebSocket.md +475 -80
- package/node_modules/undici/docs/docs/api/api-lifecycle.md +100 -32
- package/node_modules/undici/docs/docs/best-practices/client-certificate.md +2 -0
- package/node_modules/undici/docs/docs/best-practices/crawling.md +3 -1
- package/node_modules/undici/docs/docs/best-practices/migrating-from-v7-to-v8.md +6 -4
- package/node_modules/undici/docs/docs/best-practices/mocking-request.md +9 -7
- package/node_modules/undici/docs/docs/best-practices/proxy.md +3 -1
- package/node_modules/undici/docs/docs/best-practices/undici-vs-builtin-fetch.md +10 -8
- package/node_modules/undici/docs/docs/best-practices/writing-tests.md +2 -0
- package/node_modules/undici/docs/docs/{GettingStarted.md → getting-started.md} +22 -19
- package/node_modules/undici/docs/docs/index.md +779 -0
- package/node_modules/undici/docs/docs/site.json +125 -0
- package/node_modules/undici/docs/docs/type-map.json +79 -0
- package/node_modules/undici/lib/api/api-request.js +7 -1
- package/node_modules/undici/lib/api/readable.js +47 -2
- package/node_modules/undici/lib/core/errors.js +20 -0
- package/node_modules/undici/lib/core/request.js +1 -1
- package/node_modules/undici/lib/core/util.js +24 -1
- package/node_modules/undici/lib/dispatcher/client-h1.js +92 -1
- package/node_modules/undici/lib/dispatcher/client-h2.js +322 -118
- package/node_modules/undici/lib/dispatcher/client.js +6 -2
- package/node_modules/undici/lib/dispatcher/dispatcher-base.js +1 -0
- package/node_modules/undici/lib/dispatcher/proxy-agent.js +42 -7
- package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +4 -2
- package/node_modules/undici/lib/handler/redirect-handler.js +1 -0
- package/node_modules/undici/lib/handler/retry-handler.js +57 -19
- package/node_modules/undici/lib/util/cache.js +8 -2
- package/node_modules/undici/lib/web/cookies/parse.js +20 -27
- package/node_modules/undici/lib/web/cookies/util.js +1 -1
- package/node_modules/undici/lib/web/eventsource/eventsource.js +7 -18
- package/node_modules/undici/lib/web/eventsource/util.js +32 -1
- package/node_modules/undici/lib/web/fetch/body.js +43 -0
- package/node_modules/undici/lib/web/fetch/constants.js +1 -1
- package/node_modules/undici/lib/web/fetch/index.js +11 -2
- package/node_modules/undici/lib/web/fetch/request.js +1 -0
- package/node_modules/undici/lib/web/fetch/util.js +4 -1
- package/node_modules/undici/lib/web/websocket/receiver.js +20 -3
- package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +8 -1
- package/node_modules/undici/lib/web/websocket/websocket.js +3 -1
- package/node_modules/undici/package.json +1 -1
- package/node_modules/undici/types/client.d.ts +6 -1
- package/node_modules/undici/types/cookies.d.ts +1 -1
- package/node_modules/undici/types/errors.d.ts +10 -0
- package/node_modules/undici/types/fetch.d.ts +1 -0
- package/node_modules/undici/types/handlers.d.ts +2 -0
- package/node_modules/undici/types/proxy-agent.d.ts +7 -0
- package/package.json +8 -6
- package/react/styles.css +851 -0
- package/react/styles.source.css +850 -0
- package/node_modules/hono/dist/tsconfig.build.tsbuildinfo +0 -1
- package/node_modules/tailwindcss/dist/chunk-XVOTX5KS.mjs +0 -1
|
@@ -35,6 +35,7 @@ const {
|
|
|
35
35
|
kSize,
|
|
36
36
|
kHTTPContext,
|
|
37
37
|
kClosed,
|
|
38
|
+
kKeepAliveDefaultTimeout,
|
|
38
39
|
kHeadersTimeout,
|
|
39
40
|
kBodyTimeout,
|
|
40
41
|
kEnableConnectProtocol,
|
|
@@ -152,17 +153,38 @@ function requeueUnsentRequest (client, request) {
|
|
|
152
153
|
client[kQueue].splice(client[kPendingIdx] + 1, 0, request)
|
|
153
154
|
}
|
|
154
155
|
|
|
156
|
+
function completeRequest (client, request, resetPendingIdx = false) {
|
|
157
|
+
const queue = client[kQueue]
|
|
158
|
+
const runningIdx = client[kRunningIdx]
|
|
159
|
+
|
|
160
|
+
// In-order completion: advance the running index instead of splicing.
|
|
161
|
+
// The client's resume loop compacts the queue once the index grows.
|
|
162
|
+
if (runningIdx < client[kPendingIdx] && queue[runningIdx] === request) {
|
|
163
|
+
client[kRunningIdx] = runningIdx + 1
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const index = queue.indexOf(request, runningIdx)
|
|
168
|
+
|
|
169
|
+
if (index === -1 || index >= client[kPendingIdx]) {
|
|
170
|
+
return
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
queue.splice(index, 1)
|
|
174
|
+
client[kPendingIdx]--
|
|
175
|
+
|
|
176
|
+
if (resetPendingIdx && client[kPendingIdx] < client[kRunningIdx]) {
|
|
177
|
+
client[kPendingIdx] = client[kRunningIdx]
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
155
181
|
function canRetryRequestAfterGoAway (request) {
|
|
156
182
|
const { body } = request
|
|
157
183
|
|
|
158
184
|
return body == null || util.isBuffer(body) || util.isBlobLike(body)
|
|
159
185
|
}
|
|
160
186
|
|
|
161
|
-
function
|
|
162
|
-
const stream = request[kRequestStream]
|
|
163
|
-
|
|
164
|
-
clearRequestStream(request)
|
|
165
|
-
|
|
187
|
+
function closeStream (stream, code = NGHTTP2_REFUSED_STREAM) {
|
|
166
188
|
if (stream != null && !stream.destroyed && !stream.closed) {
|
|
167
189
|
try {
|
|
168
190
|
stream.close(code)
|
|
@@ -170,6 +192,14 @@ function closeRequestStream (request, code = NGHTTP2_REFUSED_STREAM) {
|
|
|
170
192
|
}
|
|
171
193
|
}
|
|
172
194
|
|
|
195
|
+
function detachRequestStreamForClose (request) {
|
|
196
|
+
const stream = request[kRequestStream]
|
|
197
|
+
|
|
198
|
+
clearRequestStream(request)
|
|
199
|
+
|
|
200
|
+
return stream
|
|
201
|
+
}
|
|
202
|
+
|
|
173
203
|
function connectH2 (client, socket) {
|
|
174
204
|
client[kSocket] = socket
|
|
175
205
|
|
|
@@ -191,6 +221,12 @@ function connectH2 (client, socket) {
|
|
|
191
221
|
session[kClient] = client
|
|
192
222
|
session[kSocket] = socket
|
|
193
223
|
session[kHTTP2SessionState] = {
|
|
224
|
+
idleTimeout: null,
|
|
225
|
+
// Sockets start out ref'd. Session ref/unref proxies to the socket, so a
|
|
226
|
+
// single cached flag lets us skip redundant uv ref/unref calls, provided
|
|
227
|
+
// every ref/unref of the session or its socket goes through
|
|
228
|
+
// refH2Session/unrefH2Session.
|
|
229
|
+
refed: true,
|
|
194
230
|
ping: {
|
|
195
231
|
interval: client[kPingInterval] === 0 ? null : setInterval(onHttp2SendPing, client[kPingInterval], session).unref()
|
|
196
232
|
}
|
|
@@ -217,7 +253,7 @@ function connectH2 (client, socket) {
|
|
|
217
253
|
// TODO (@metcoder95): implement SETTINGS support
|
|
218
254
|
// util.addListener(session, 'localSettings', onHttp2RemoteSettings)
|
|
219
255
|
|
|
220
|
-
session
|
|
256
|
+
unrefH2Session(session)
|
|
221
257
|
|
|
222
258
|
client[kHTTP2Session] = session
|
|
223
259
|
socket[kHTTP2Session] = session
|
|
@@ -279,10 +315,10 @@ function connectH2 (client, socket) {
|
|
|
279
315
|
if (client[kRunning] > 0) {
|
|
280
316
|
// We are already processing requests
|
|
281
317
|
|
|
282
|
-
//
|
|
283
|
-
//
|
|
284
|
-
//
|
|
285
|
-
|
|
318
|
+
// Unlike HTTP/1.1 pipelining, HTTP/2 multiplexes requests on
|
|
319
|
+
// independent streams, so non-idempotent requests can be dispatched
|
|
320
|
+
// concurrently. Retry eligibility is handled by stream/session error
|
|
321
|
+
// handling instead of by serializing all non-idempotent requests.
|
|
286
322
|
// Don't dispatch an upgrade until all preceding requests have completed.
|
|
287
323
|
// Possibly, we do not have remote settings confirmed yet.
|
|
288
324
|
if ((request.upgrade === 'websocket' || request.method === 'CONNECT') && session[kRemoteSettings] === false) return true
|
|
@@ -306,20 +342,89 @@ function connectH2 (client, socket) {
|
|
|
306
342
|
}
|
|
307
343
|
}
|
|
308
344
|
|
|
345
|
+
// Session ref/unref proxies to the underlying socket, so refH2Session and
|
|
346
|
+
// unrefH2Session cover both and can skip the call when the cached ref state
|
|
347
|
+
// already matches.
|
|
348
|
+
function refH2Session (session) {
|
|
349
|
+
const state = session[kHTTP2SessionState]
|
|
350
|
+
|
|
351
|
+
if (state.refed === false) {
|
|
352
|
+
state.refed = true
|
|
353
|
+
session.ref()
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function unrefH2Session (session) {
|
|
358
|
+
const state = session[kHTTP2SessionState]
|
|
359
|
+
|
|
360
|
+
if (state.refed === true) {
|
|
361
|
+
state.refed = false
|
|
362
|
+
session.unref()
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
309
366
|
function resumeH2 (client) {
|
|
310
367
|
const socket = client[kSocket]
|
|
368
|
+
const session = client[kHTTP2Session]
|
|
311
369
|
|
|
312
370
|
if (socket?.destroyed === false) {
|
|
313
371
|
if (client[kSize] === 0 || client[kMaxConcurrentStreams] === 0) {
|
|
314
|
-
|
|
315
|
-
client[kHTTP2Session].unref()
|
|
372
|
+
unrefH2Session(session)
|
|
316
373
|
} else {
|
|
317
|
-
|
|
318
|
-
client[kHTTP2Session].ref()
|
|
374
|
+
refH2Session(session)
|
|
319
375
|
}
|
|
376
|
+
|
|
377
|
+
if (client[kSize] === 0 && session[kOpenStreams] === 0) {
|
|
378
|
+
setHttp2IdleTimeout(session)
|
|
379
|
+
} else {
|
|
380
|
+
clearHttp2IdleTimeout(session)
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function clearHttp2IdleTimeout (session) {
|
|
386
|
+
const state = session[kHTTP2SessionState]
|
|
387
|
+
|
|
388
|
+
if (state?.idleTimeout != null) {
|
|
389
|
+
clearTimeout(state.idleTimeout)
|
|
390
|
+
state.idleTimeout = null
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function setHttp2IdleTimeout (session) {
|
|
395
|
+
const client = session[kClient]
|
|
396
|
+
|
|
397
|
+
if (client[kHTTP2Session] !== session || session.closed || session.destroyed) {
|
|
398
|
+
return
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (session[kOpenStreams] !== 0 || client[kSize] !== 0) {
|
|
402
|
+
clearHttp2IdleTimeout(session)
|
|
403
|
+
return
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const state = session[kHTTP2SessionState]
|
|
407
|
+
if (state.idleTimeout == null) {
|
|
408
|
+
state.idleTimeout = setTimeout(onHttp2SessionIdleTimeout, client[kKeepAliveDefaultTimeout], session).unref()
|
|
320
409
|
}
|
|
321
410
|
}
|
|
322
411
|
|
|
412
|
+
function onHttp2SessionIdleTimeout (session) {
|
|
413
|
+
const client = session[kClient]
|
|
414
|
+
const socket = session[kSocket]
|
|
415
|
+
const state = session[kHTTP2SessionState]
|
|
416
|
+
|
|
417
|
+
state.idleTimeout = null
|
|
418
|
+
|
|
419
|
+
if (client[kHTTP2Session] !== session || session[kOpenStreams] !== 0 || client[kSize] !== 0 || session.closed || session.destroyed) {
|
|
420
|
+
return
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const err = new InformationalError('socket idle timeout')
|
|
424
|
+
socket[kError] = err
|
|
425
|
+
util.destroy(socket, err)
|
|
426
|
+
}
|
|
427
|
+
|
|
323
428
|
function applyConnectionWindowSize (connectionWindowSize) {
|
|
324
429
|
try {
|
|
325
430
|
if (typeof this.setLocalWindowSize === 'function') {
|
|
@@ -380,11 +485,20 @@ function onHttp2SessionError (err) {
|
|
|
380
485
|
assert(err.code !== 'ERR_TLS_CERT_ALTNAME_INVALID')
|
|
381
486
|
|
|
382
487
|
this[kSocket][kError] = err
|
|
488
|
+
|
|
489
|
+
if (this[kReceivedGoAway]) {
|
|
490
|
+
return
|
|
491
|
+
}
|
|
492
|
+
|
|
383
493
|
this[kClient][kOnError](err)
|
|
384
494
|
}
|
|
385
495
|
|
|
386
496
|
function onHttp2FrameError (type, code, id) {
|
|
387
497
|
if (id === 0) {
|
|
498
|
+
if (this[kReceivedGoAway]) {
|
|
499
|
+
return
|
|
500
|
+
}
|
|
501
|
+
|
|
388
502
|
const err = new InformationalError(`HTTP/2: "frameError" received - type ${type}, code ${code}`)
|
|
389
503
|
this[kSocket][kError] = err
|
|
390
504
|
this[kClient][kOnError](err)
|
|
@@ -418,12 +532,16 @@ function onHttp2SessionGoAway (errorCode, lastStreamID) {
|
|
|
418
532
|
const previousPendingIdx = client[kPendingIdx]
|
|
419
533
|
const pendingIdx = getGoAwayPendingIdx(client, lastStreamID)
|
|
420
534
|
const retriableRequests = []
|
|
535
|
+
const streamsToClose = []
|
|
421
536
|
|
|
537
|
+
// Closing one stream after GOAWAY can synchronously emit frameError on
|
|
538
|
+
// sibling streams. Detach all affected requests first so those errors do
|
|
539
|
+
// not fail requests that are about to be requeued.
|
|
422
540
|
for (let i = pendingIdx; i < previousPendingIdx; i++) {
|
|
423
541
|
const request = client[kQueue][i]
|
|
424
542
|
|
|
425
543
|
if (request != null) {
|
|
426
|
-
|
|
544
|
+
streamsToClose.push(detachRequestStreamForClose(request))
|
|
427
545
|
|
|
428
546
|
if (canRetryRequestAfterGoAway(request)) {
|
|
429
547
|
retriableRequests.push(request)
|
|
@@ -433,6 +551,10 @@ function onHttp2SessionGoAway (errorCode, lastStreamID) {
|
|
|
433
551
|
}
|
|
434
552
|
}
|
|
435
553
|
|
|
554
|
+
for (let i = 0; i < streamsToClose.length; i++) {
|
|
555
|
+
closeStream(streamsToClose[i])
|
|
556
|
+
}
|
|
557
|
+
|
|
436
558
|
if (pendingIdx !== previousPendingIdx) {
|
|
437
559
|
const remainingPendingRequests = client[kQueue].slice(previousPendingIdx)
|
|
438
560
|
client[kQueue].length = pendingIdx
|
|
@@ -445,6 +567,8 @@ function onHttp2SessionGoAway (errorCode, lastStreamID) {
|
|
|
445
567
|
client[kHTTP2Session] = null
|
|
446
568
|
}
|
|
447
569
|
|
|
570
|
+
clearHttp2IdleTimeout(this)
|
|
571
|
+
|
|
448
572
|
if (!this.closed && !this.destroyed) {
|
|
449
573
|
this.close()
|
|
450
574
|
}
|
|
@@ -467,6 +591,8 @@ function onHttp2SessionClose () {
|
|
|
467
591
|
client[kHTTP2Session] = null
|
|
468
592
|
}
|
|
469
593
|
|
|
594
|
+
clearHttp2IdleTimeout(this)
|
|
595
|
+
|
|
470
596
|
if (state.ping.interval != null) {
|
|
471
597
|
clearInterval(state.ping.interval)
|
|
472
598
|
state.ping.interval = null
|
|
@@ -479,7 +605,9 @@ function onHttp2SessionClose () {
|
|
|
479
605
|
const requests = client[kQueue].splice(client[kRunningIdx])
|
|
480
606
|
for (let i = 0; i < requests.length; i++) {
|
|
481
607
|
const request = requests[i]
|
|
482
|
-
|
|
608
|
+
if (request != null) {
|
|
609
|
+
util.errorRequest(client, request, err)
|
|
610
|
+
}
|
|
483
611
|
}
|
|
484
612
|
}
|
|
485
613
|
}
|
|
@@ -522,6 +650,10 @@ function onHttp2SocketError (err) {
|
|
|
522
650
|
|
|
523
651
|
this[kError] = err
|
|
524
652
|
|
|
653
|
+
if (this[kHTTP2Session]?.[kReceivedGoAway]) {
|
|
654
|
+
return
|
|
655
|
+
}
|
|
656
|
+
|
|
525
657
|
this[kClient][kOnError](err)
|
|
526
658
|
}
|
|
527
659
|
|
|
@@ -541,7 +673,8 @@ function closeStreamSession (stream) {
|
|
|
541
673
|
stream[kHTTP2Session] = null
|
|
542
674
|
session[kOpenStreams] -= 1
|
|
543
675
|
if (session[kOpenStreams] === 0) {
|
|
544
|
-
session
|
|
676
|
+
unrefH2Session(session)
|
|
677
|
+
setHttp2IdleTimeout(session)
|
|
545
678
|
}
|
|
546
679
|
}
|
|
547
680
|
|
|
@@ -565,12 +698,10 @@ function onRequestStreamClose () {
|
|
|
565
698
|
|
|
566
699
|
if (state.pendingEnd && !state.request.aborted && !state.request.completed) {
|
|
567
700
|
state.request.onResponseEnd(state.trailers || {})
|
|
568
|
-
|
|
701
|
+
finalizeRequest(state)
|
|
569
702
|
}
|
|
570
703
|
}
|
|
571
704
|
|
|
572
|
-
this.off('data', onData)
|
|
573
|
-
this.off('error', noop)
|
|
574
705
|
closeStreamSession(this)
|
|
575
706
|
this[kRequestStreamState] = null
|
|
576
707
|
}
|
|
@@ -693,7 +824,7 @@ function onUpgradeResponse (headers, _flags) {
|
|
|
693
824
|
|
|
694
825
|
removeUpgradeStreamListeners(stream)
|
|
695
826
|
detachRequestFromStream(request)
|
|
696
|
-
|
|
827
|
+
finalizeRequest(state)
|
|
697
828
|
}
|
|
698
829
|
|
|
699
830
|
function setupUpgradeStream (stream, state) {
|
|
@@ -711,16 +842,56 @@ function setupUpgradeStream (stream, state) {
|
|
|
711
842
|
stream.on('timeout', onUpgradeStreamTimeout)
|
|
712
843
|
stream.once('close', onUpgradeStreamClose)
|
|
713
844
|
|
|
845
|
+
clearHttp2IdleTimeout(session)
|
|
714
846
|
++session[kOpenStreams]
|
|
715
847
|
stream.setTimeout(headersTimeout)
|
|
716
848
|
}
|
|
717
849
|
|
|
850
|
+
function finalizeRequest (state, resetPendingIdx = false) {
|
|
851
|
+
if (state.requestFinalized) {
|
|
852
|
+
return
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
state.requestFinalized = true
|
|
856
|
+
completeRequest(state.client, state.request, resetPendingIdx)
|
|
857
|
+
|
|
858
|
+
state.client[kResume]()
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
function openStream (client, request, session, abort, headers, options) {
|
|
862
|
+
try {
|
|
863
|
+
return session.request(headers, options)
|
|
864
|
+
} catch (err) {
|
|
865
|
+
// A GOAWAY'd session rejects new streams, same as an invalid session:
|
|
866
|
+
// reset and requeue on a fresh connection rather than the destroy + abort
|
|
867
|
+
// below, whose destroy(socket, err) can crash via an unhandled 'error'.
|
|
868
|
+
if (err?.code === 'ERR_HTTP2_INVALID_SESSION' || err?.code === 'ERR_HTTP2_GOAWAY_SESSION') {
|
|
869
|
+
const wrappedErr = new SocketError(err.message, util.getSocketInfo(session[kSocket]))
|
|
870
|
+
wrappedErr.cause = err
|
|
871
|
+
session[kError] = wrappedErr
|
|
872
|
+
resetHttp2Session(session, wrappedErr)
|
|
873
|
+
requeueUnsentRequest(client, request)
|
|
874
|
+
|
|
875
|
+
return null
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
const wrappedErr = new InformationalError(err.message, { cause: err })
|
|
879
|
+
session[kError] = wrappedErr
|
|
880
|
+
session[kSocket][kError] = wrappedErr
|
|
881
|
+
|
|
882
|
+
session.destroy(wrappedErr)
|
|
883
|
+
util.destroy(session[kSocket], wrappedErr)
|
|
884
|
+
abort(wrappedErr)
|
|
885
|
+
|
|
886
|
+
return null
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
718
890
|
function writeH2 (client, request) {
|
|
719
891
|
const headersTimeout = request.headersTimeout ?? client[kHeadersTimeout]
|
|
720
892
|
const bodyTimeout = request.bodyTimeout ?? client[kBodyTimeout]
|
|
721
893
|
const session = client[kHTTP2Session]
|
|
722
894
|
const { method, path, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request
|
|
723
|
-
let { body } = request
|
|
724
895
|
|
|
725
896
|
if (upgrade != null && upgrade !== 'websocket') {
|
|
726
897
|
util.errorRequest(client, request, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`))
|
|
@@ -729,26 +900,28 @@ function writeH2 (client, request) {
|
|
|
729
900
|
|
|
730
901
|
const headers = buildRequestHeaders(reqHeaders)
|
|
731
902
|
|
|
732
|
-
/** @type {import('node:http2').ClientHttp2Stream} */
|
|
733
|
-
let stream = null
|
|
734
|
-
|
|
735
903
|
headers[HTTP2_HEADER_AUTHORITY] = host || client[kHostAuthority]
|
|
736
904
|
headers[HTTP2_HEADER_METHOD] = method
|
|
737
905
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
906
|
+
// Single pre-shaped state object shared by all stream event handlers.
|
|
907
|
+
// All fields are declared up-front so the object keeps a stable hidden
|
|
908
|
+
// class for the whole request lifetime.
|
|
909
|
+
const state = {
|
|
910
|
+
abort: null,
|
|
911
|
+
body: request.body,
|
|
912
|
+
client,
|
|
913
|
+
contentLength: null,
|
|
914
|
+
expectsPayload: false,
|
|
915
|
+
request,
|
|
916
|
+
headersTimeout,
|
|
917
|
+
bodyTimeout,
|
|
918
|
+
requestFinalized: false,
|
|
919
|
+
responseReceived: false,
|
|
920
|
+
bodySent: false,
|
|
921
|
+
pendingEnd: false,
|
|
922
|
+
trailers: null,
|
|
923
|
+
session,
|
|
924
|
+
stream: null
|
|
752
925
|
}
|
|
753
926
|
|
|
754
927
|
const abort = (err, resetPendingIdx = false) => {
|
|
@@ -760,47 +933,39 @@ function writeH2 (client, request) {
|
|
|
760
933
|
|
|
761
934
|
util.errorRequest(client, request, err)
|
|
762
935
|
|
|
763
|
-
if (stream != null) {
|
|
936
|
+
if (state.stream != null) {
|
|
764
937
|
clearRequestStream(request)
|
|
765
938
|
|
|
766
|
-
// On Abort, we close the stream to send RST_STREAM frame
|
|
939
|
+
// On Abort, we close the stream to send RST_STREAM frame.
|
|
940
|
+
const stream = state.stream
|
|
767
941
|
stream.close()
|
|
768
942
|
|
|
943
|
+
// close() alone leaves cleanup waiting on the 'close' event; on a busy,
|
|
944
|
+
// long-lived multiplexed session that event can fail to fire, leaving the
|
|
945
|
+
// native Http2Stream (and the whole request graph it pins) alive for the
|
|
946
|
+
// session's life. Destroy the stream to release the handle
|
|
947
|
+
// deterministically, but defer it by a setImmediate so the RST_STREAM
|
|
948
|
+
// frame queued by close() gets a chance to be written first.
|
|
949
|
+
setImmediate(() => {
|
|
950
|
+
if (!stream.destroyed) {
|
|
951
|
+
util.destroy(stream)
|
|
952
|
+
}
|
|
953
|
+
})
|
|
954
|
+
|
|
769
955
|
// We move the running index to the next request
|
|
770
956
|
client[kOnError](err)
|
|
771
|
-
finalizeRequest(resetPendingIdx)
|
|
957
|
+
finalizeRequest(state, resetPendingIdx)
|
|
772
958
|
}
|
|
773
959
|
|
|
774
960
|
// We do not destroy the socket as we can continue using the session
|
|
775
961
|
// the stream gets destroyed and the session remains to create new streams
|
|
776
|
-
util.destroy(body, err)
|
|
962
|
+
util.destroy(state.body, err)
|
|
777
963
|
}
|
|
778
964
|
|
|
779
|
-
|
|
780
|
-
try {
|
|
781
|
-
return session.request(headers, options)
|
|
782
|
-
} catch (err) {
|
|
783
|
-
if (err?.code === 'ERR_HTTP2_INVALID_SESSION') {
|
|
784
|
-
const wrappedErr = new SocketError(err.message, util.getSocketInfo(session[kSocket]))
|
|
785
|
-
wrappedErr.cause = err
|
|
786
|
-
session[kError] = wrappedErr
|
|
787
|
-
resetHttp2Session(session, wrappedErr)
|
|
788
|
-
requeueUnsentRequest(client, request)
|
|
789
|
-
|
|
790
|
-
return null
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
const wrappedErr = new InformationalError(err.message, { cause: err })
|
|
794
|
-
session[kError] = wrappedErr
|
|
795
|
-
session[kSocket][kError] = wrappedErr
|
|
796
|
-
|
|
797
|
-
session.destroy(wrappedErr)
|
|
798
|
-
util.destroy(session[kSocket], wrappedErr)
|
|
799
|
-
abort(wrappedErr)
|
|
965
|
+
state.abort = abort
|
|
800
966
|
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
}
|
|
967
|
+
/** @type {import('node:http2').ClientHttp2Stream} */
|
|
968
|
+
let stream = null
|
|
804
969
|
|
|
805
970
|
try {
|
|
806
971
|
// We are already connected, streams are pending.
|
|
@@ -815,24 +980,13 @@ function writeH2 (client, request) {
|
|
|
815
980
|
}
|
|
816
981
|
|
|
817
982
|
if (upgrade || method === 'CONNECT') {
|
|
818
|
-
session
|
|
819
|
-
|
|
820
|
-
const upgradeState = {
|
|
821
|
-
abort,
|
|
822
|
-
finalizeRequest,
|
|
823
|
-
request,
|
|
824
|
-
headersTimeout,
|
|
825
|
-
bodyTimeout,
|
|
826
|
-
responseReceived: false,
|
|
827
|
-
session,
|
|
828
|
-
stream: null
|
|
829
|
-
}
|
|
983
|
+
refH2Session(session)
|
|
830
984
|
|
|
831
985
|
if (upgrade === 'websocket') {
|
|
832
986
|
// We cannot upgrade to websocket if extended CONNECT protocol is not supported
|
|
833
987
|
if (session[kEnableConnectProtocol] === false) {
|
|
834
988
|
util.errorRequest(client, request, new InformationalError('HTTP/2: Extended CONNECT protocol not supported by server'))
|
|
835
|
-
session
|
|
989
|
+
unrefH2Session(session)
|
|
836
990
|
return false
|
|
837
991
|
}
|
|
838
992
|
|
|
@@ -850,12 +1004,12 @@ function writeH2 (client, request) {
|
|
|
850
1004
|
headers[HTTP2_HEADER_SCHEME] = protocol === 'http:' ? 'http' : 'https'
|
|
851
1005
|
}
|
|
852
1006
|
|
|
853
|
-
stream =
|
|
1007
|
+
stream = openStream(client, request, session, abort, headers, { endStream: false, signal })
|
|
854
1008
|
if (stream == null) {
|
|
855
|
-
session
|
|
1009
|
+
unrefH2Session(session)
|
|
856
1010
|
return false
|
|
857
1011
|
}
|
|
858
|
-
setupUpgradeStream(stream,
|
|
1012
|
+
setupUpgradeStream(stream, state)
|
|
859
1013
|
return true
|
|
860
1014
|
}
|
|
861
1015
|
|
|
@@ -864,12 +1018,12 @@ function writeH2 (client, request) {
|
|
|
864
1018
|
// will create a new stream. We trigger a request to create the stream and wait until
|
|
865
1019
|
// `ready` event is triggered
|
|
866
1020
|
// We disabled endStream to allow the user to write to the stream
|
|
867
|
-
stream =
|
|
1021
|
+
stream = openStream(client, request, session, abort, headers, { endStream: false, signal })
|
|
868
1022
|
if (stream == null) {
|
|
869
|
-
session
|
|
1023
|
+
unrefH2Session(session)
|
|
870
1024
|
return false
|
|
871
1025
|
}
|
|
872
|
-
setupUpgradeStream(stream,
|
|
1026
|
+
setupUpgradeStream(stream, state)
|
|
873
1027
|
|
|
874
1028
|
return true
|
|
875
1029
|
}
|
|
@@ -897,6 +1051,8 @@ function writeH2 (client, request) {
|
|
|
897
1051
|
method === 'PROPPATCH'
|
|
898
1052
|
)
|
|
899
1053
|
|
|
1054
|
+
let body = state.body
|
|
1055
|
+
|
|
900
1056
|
if (body && typeof body.read === 'function') {
|
|
901
1057
|
// Try to read EOF in order to get length.
|
|
902
1058
|
body.read(0)
|
|
@@ -943,7 +1099,7 @@ function writeH2 (client, request) {
|
|
|
943
1099
|
headers[HTTP2_HEADER_CONTENT_LENGTH] = `${contentLength}`
|
|
944
1100
|
}
|
|
945
1101
|
|
|
946
|
-
session
|
|
1102
|
+
refH2Session(session)
|
|
947
1103
|
|
|
948
1104
|
if (channels.sendHeaders.hasSubscribers) {
|
|
949
1105
|
let header = ''
|
|
@@ -955,26 +1111,16 @@ function writeH2 (client, request) {
|
|
|
955
1111
|
|
|
956
1112
|
// TODO(metcoder95): add support for sending trailers
|
|
957
1113
|
const shouldEndStream = body === null || contentLength === 0
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
contentLength,
|
|
963
|
-
expectsPayload,
|
|
964
|
-
finalizeRequest,
|
|
965
|
-
request,
|
|
966
|
-
headersTimeout,
|
|
967
|
-
bodyTimeout,
|
|
968
|
-
responseReceived: false,
|
|
969
|
-
session,
|
|
970
|
-
stream: null
|
|
971
|
-
}
|
|
1114
|
+
|
|
1115
|
+
state.body = body
|
|
1116
|
+
state.contentLength = contentLength
|
|
1117
|
+
state.expectsPayload = expectsPayload
|
|
972
1118
|
|
|
973
1119
|
if (expectContinue) {
|
|
974
1120
|
headers[HTTP2_HEADER_EXPECT] = '100-continue'
|
|
975
1121
|
}
|
|
976
1122
|
|
|
977
|
-
stream =
|
|
1123
|
+
stream = openStream(client, request, session, abort, headers, { endStream: shouldEndStream, signal })
|
|
978
1124
|
if (stream == null) {
|
|
979
1125
|
return false
|
|
980
1126
|
}
|
|
@@ -983,23 +1129,32 @@ function writeH2 (client, request) {
|
|
|
983
1129
|
state.stream = stream
|
|
984
1130
|
|
|
985
1131
|
// Increment counter as we have new streams open
|
|
1132
|
+
clearHttp2IdleTimeout(session)
|
|
986
1133
|
++session[kOpenStreams]
|
|
987
|
-
|
|
1134
|
+
|
|
1135
|
+
if (headersTimeout) {
|
|
1136
|
+
stream.setTimeout(headersTimeout)
|
|
1137
|
+
}
|
|
988
1138
|
|
|
989
1139
|
stream[kHTTP2Session] = session
|
|
990
|
-
stream.
|
|
1140
|
+
stream.on('close', onRequestStreamClose)
|
|
991
1141
|
|
|
992
1142
|
bindRequestToStream(request, stream, releaseRequestStream)
|
|
993
1143
|
if (expectContinue) {
|
|
994
1144
|
stream.once('continue', writeBodyH2)
|
|
995
1145
|
}
|
|
996
|
-
|
|
997
|
-
stream
|
|
998
|
-
|
|
999
|
-
stream.
|
|
1146
|
+
// The handlers below either remove themselves on first invocation or
|
|
1147
|
+
// become unreachable once the stream closes, so plain `on` avoids the
|
|
1148
|
+
// per-listener `once` wrapper allocation.
|
|
1149
|
+
stream.on('response', onResponse)
|
|
1150
|
+
stream.on('end', onEnd)
|
|
1151
|
+
stream.on('error', onError)
|
|
1152
|
+
stream.on('frameError', onFrameError)
|
|
1000
1153
|
stream.on('aborted', onAborted)
|
|
1001
|
-
|
|
1002
|
-
|
|
1154
|
+
if (headersTimeout || bodyTimeout) {
|
|
1155
|
+
stream.on('timeout', onTimeout)
|
|
1156
|
+
}
|
|
1157
|
+
stream.on('trailers', onTrailers)
|
|
1003
1158
|
|
|
1004
1159
|
if (!expectContinue) {
|
|
1005
1160
|
writeBodyH2.call(stream)
|
|
@@ -1037,16 +1192,24 @@ function releaseRequestStream (stream) {
|
|
|
1037
1192
|
detachRequestFromStream(request)
|
|
1038
1193
|
}
|
|
1039
1194
|
|
|
1040
|
-
|
|
1041
|
-
|
|
1195
|
+
// A closed or destroyed stream cannot emit further events; leaving the
|
|
1196
|
+
// listeners in place saves the removal scans (they are collected with
|
|
1197
|
+
// the stream). All handlers bail out when the stream state is gone.
|
|
1042
1198
|
if (!stream.destroyed && !stream.closed) {
|
|
1199
|
+
removeRequestStreamListeners(stream)
|
|
1043
1200
|
stream.once('error', noop)
|
|
1044
1201
|
}
|
|
1045
1202
|
}
|
|
1046
1203
|
|
|
1047
1204
|
function onData (chunk) {
|
|
1048
1205
|
const stream = this
|
|
1049
|
-
const
|
|
1206
|
+
const state = stream[kRequestStreamState]
|
|
1207
|
+
|
|
1208
|
+
if (state == null) {
|
|
1209
|
+
return
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
const { request } = state
|
|
1050
1213
|
|
|
1051
1214
|
if (request.aborted || request.completed) {
|
|
1052
1215
|
return
|
|
@@ -1060,22 +1223,40 @@ function onData (chunk) {
|
|
|
1060
1223
|
function onResponse (headers) {
|
|
1061
1224
|
const stream = this
|
|
1062
1225
|
const state = stream[kRequestStreamState]
|
|
1226
|
+
|
|
1227
|
+
if (state == null) {
|
|
1228
|
+
return
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1063
1231
|
const { request } = state
|
|
1064
1232
|
|
|
1065
1233
|
stream.off('response', onResponse)
|
|
1066
1234
|
|
|
1235
|
+
// Final response received while still awaiting 100 (Continue): the body won't
|
|
1236
|
+
// be sent, so close our half or the stream stays open and never completes.
|
|
1237
|
+
if (state.body != null && !state.bodySent && !stream.writableEnded) {
|
|
1238
|
+
stream.removeListener('continue', writeBodyH2)
|
|
1239
|
+
stream.end()
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1067
1242
|
const statusCode = headers[HTTP2_HEADER_STATUS]
|
|
1068
1243
|
delete headers[HTTP2_HEADER_STATUS]
|
|
1069
1244
|
request.onResponseStarted()
|
|
1070
1245
|
state.responseReceived = true
|
|
1071
|
-
|
|
1246
|
+
|
|
1247
|
+
if (state.headersTimeout || state.bodyTimeout) {
|
|
1248
|
+
stream.setTimeout(state.bodyTimeout)
|
|
1249
|
+
}
|
|
1072
1250
|
|
|
1073
1251
|
// Due to the stream nature, it is possible we face a race condition
|
|
1074
1252
|
// where the stream has been assigned, but the request has been aborted
|
|
1075
|
-
//
|
|
1076
|
-
//
|
|
1077
|
-
//
|
|
1078
|
-
|
|
1253
|
+
// or already completed and headers hasn't been received yet. A late
|
|
1254
|
+
// 'response' delivered after completion would call request.onResponseStart
|
|
1255
|
+
// post-completion, tripping its `assert(!this.completed)` (an uncatchable
|
|
1256
|
+
// throw on the http2 event tick). Guard `completed` here as onEnd/onTrailers
|
|
1257
|
+
// already do; best effort is to release the stream immediately as there's
|
|
1258
|
+
// no value to keep it open.
|
|
1259
|
+
if (request.aborted || request.completed) {
|
|
1079
1260
|
releaseRequestStream(stream)
|
|
1080
1261
|
return
|
|
1081
1262
|
}
|
|
@@ -1090,6 +1271,11 @@ function onResponse (headers) {
|
|
|
1090
1271
|
function onEnd () {
|
|
1091
1272
|
const stream = this
|
|
1092
1273
|
const state = stream[kRequestStreamState]
|
|
1274
|
+
|
|
1275
|
+
if (state == null) {
|
|
1276
|
+
return
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1093
1279
|
const { request } = state
|
|
1094
1280
|
|
|
1095
1281
|
stream.off('end', onEnd)
|
|
@@ -1113,6 +1299,10 @@ function onError (err) {
|
|
|
1113
1299
|
const stream = this
|
|
1114
1300
|
const state = stream[kRequestStreamState]
|
|
1115
1301
|
|
|
1302
|
+
if (state == null) {
|
|
1303
|
+
return
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1116
1306
|
stream.off('error', onError)
|
|
1117
1307
|
state.abort(err)
|
|
1118
1308
|
}
|
|
@@ -1121,6 +1311,10 @@ function onFrameError (type, code) {
|
|
|
1121
1311
|
const stream = this
|
|
1122
1312
|
const state = stream[kRequestStreamState]
|
|
1123
1313
|
|
|
1314
|
+
if (state == null) {
|
|
1315
|
+
return
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1124
1318
|
stream.off('frameError', onFrameError)
|
|
1125
1319
|
state.abort(new InformationalError(`HTTP/2: "frameError" received - type ${type}, code ${code}`))
|
|
1126
1320
|
}
|
|
@@ -1133,6 +1327,10 @@ function onTimeout () {
|
|
|
1133
1327
|
const stream = this
|
|
1134
1328
|
const state = stream[kRequestStreamState]
|
|
1135
1329
|
|
|
1330
|
+
if (state == null) {
|
|
1331
|
+
return
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1136
1334
|
// Remove self so timeout doesn't fire again after we handle it
|
|
1137
1335
|
stream.off('timeout', onTimeout)
|
|
1138
1336
|
|
|
@@ -1145,6 +1343,11 @@ function onTimeout () {
|
|
|
1145
1343
|
function onTrailers (trailers) {
|
|
1146
1344
|
const stream = this
|
|
1147
1345
|
const state = stream[kRequestStreamState]
|
|
1346
|
+
|
|
1347
|
+
if (state == null) {
|
|
1348
|
+
return
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1148
1351
|
const { request } = state
|
|
1149
1352
|
|
|
1150
1353
|
stream.off('trailers', onTrailers)
|
|
@@ -1161,6 +1364,7 @@ function onTrailers (trailers) {
|
|
|
1161
1364
|
function writeBodyH2 () {
|
|
1162
1365
|
const stream = this
|
|
1163
1366
|
const state = stream[kRequestStreamState]
|
|
1367
|
+
state.bodySent = true
|
|
1164
1368
|
const { abort, body, client, contentLength, expectsPayload, request } = state
|
|
1165
1369
|
|
|
1166
1370
|
if (!body || contentLength === 0) {
|