deepv-code 1.0.182 → 1.0.185
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/bundle/dvcode.js +757 -753
- package/package.json +1 -1
- package/bundle/assets/help/README.md +0 -113
- package/bundle/assets/sounds/README.md +0 -74
- package/bundle/node_modules/undici/LICENSE +0 -21
- package/bundle/node_modules/undici/README.md +0 -472
- package/bundle/node_modules/undici/docs/docs/api/Agent.md +0 -83
- package/bundle/node_modules/undici/docs/docs/api/BalancedPool.md +0 -99
- package/bundle/node_modules/undici/docs/docs/api/CacheStorage.md +0 -30
- package/bundle/node_modules/undici/docs/docs/api/CacheStore.md +0 -151
- package/bundle/node_modules/undici/docs/docs/api/Client.md +0 -281
- package/bundle/node_modules/undici/docs/docs/api/ClientStats.md +0 -27
- package/bundle/node_modules/undici/docs/docs/api/Connector.md +0 -115
- package/bundle/node_modules/undici/docs/docs/api/ContentType.md +0 -57
- package/bundle/node_modules/undici/docs/docs/api/Cookies.md +0 -101
- package/bundle/node_modules/undici/docs/docs/api/Debug.md +0 -62
- package/bundle/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +0 -204
- package/bundle/node_modules/undici/docs/docs/api/Dispatcher.md +0 -1200
- package/bundle/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +0 -159
- package/bundle/node_modules/undici/docs/docs/api/Errors.md +0 -49
- package/bundle/node_modules/undici/docs/docs/api/EventSource.md +0 -45
- package/bundle/node_modules/undici/docs/docs/api/Fetch.md +0 -52
- package/bundle/node_modules/undici/docs/docs/api/H2CClient.md +0 -262
- package/bundle/node_modules/undici/docs/docs/api/MockAgent.md +0 -603
- package/bundle/node_modules/undici/docs/docs/api/MockCallHistory.md +0 -197
- package/bundle/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +0 -43
- package/bundle/node_modules/undici/docs/docs/api/MockClient.md +0 -77
- package/bundle/node_modules/undici/docs/docs/api/MockErrors.md +0 -12
- package/bundle/node_modules/undici/docs/docs/api/MockPool.md +0 -548
- package/bundle/node_modules/undici/docs/docs/api/Pool.md +0 -84
- package/bundle/node_modules/undici/docs/docs/api/PoolStats.md +0 -35
- package/bundle/node_modules/undici/docs/docs/api/ProxyAgent.md +0 -227
- package/bundle/node_modules/undici/docs/docs/api/RedirectHandler.md +0 -96
- package/bundle/node_modules/undici/docs/docs/api/RetryAgent.md +0 -45
- package/bundle/node_modules/undici/docs/docs/api/RetryHandler.md +0 -117
- package/bundle/node_modules/undici/docs/docs/api/Util.md +0 -25
- package/bundle/node_modules/undici/docs/docs/api/WebSocket.md +0 -85
- package/bundle/node_modules/undici/docs/docs/api/api-lifecycle.md +0 -91
- package/bundle/node_modules/undici/docs/docs/best-practices/client-certificate.md +0 -64
- package/bundle/node_modules/undici/docs/docs/best-practices/mocking-request.md +0 -190
- package/bundle/node_modules/undici/docs/docs/best-practices/proxy.md +0 -127
- package/bundle/node_modules/undici/docs/docs/best-practices/writing-tests.md +0 -20
- package/bundle/node_modules/undici/index-fetch.js +0 -35
- package/bundle/node_modules/undici/index.d.ts +0 -3
- package/bundle/node_modules/undici/index.js +0 -183
- package/bundle/node_modules/undici/lib/api/abort-signal.js +0 -59
- package/bundle/node_modules/undici/lib/api/api-connect.js +0 -110
- package/bundle/node_modules/undici/lib/api/api-pipeline.js +0 -252
- package/bundle/node_modules/undici/lib/api/api-request.js +0 -199
- package/bundle/node_modules/undici/lib/api/api-stream.js +0 -209
- package/bundle/node_modules/undici/lib/api/api-upgrade.js +0 -110
- package/bundle/node_modules/undici/lib/api/index.js +0 -7
- package/bundle/node_modules/undici/lib/api/readable.js +0 -558
- package/bundle/node_modules/undici/lib/api/util.js +0 -95
- package/bundle/node_modules/undici/lib/cache/memory-cache-store.js +0 -234
- package/bundle/node_modules/undici/lib/cache/sqlite-cache-store.js +0 -461
- package/bundle/node_modules/undici/lib/core/connect.js +0 -164
- package/bundle/node_modules/undici/lib/core/constants.js +0 -143
- package/bundle/node_modules/undici/lib/core/diagnostics.js +0 -196
- package/bundle/node_modules/undici/lib/core/errors.js +0 -244
- package/bundle/node_modules/undici/lib/core/request.js +0 -397
- package/bundle/node_modules/undici/lib/core/symbols.js +0 -68
- package/bundle/node_modules/undici/lib/core/tree.js +0 -160
- package/bundle/node_modules/undici/lib/core/util.js +0 -988
- package/bundle/node_modules/undici/lib/dispatcher/agent.js +0 -135
- package/bundle/node_modules/undici/lib/dispatcher/balanced-pool.js +0 -206
- package/bundle/node_modules/undici/lib/dispatcher/client-h1.js +0 -1615
- package/bundle/node_modules/undici/lib/dispatcher/client-h2.js +0 -798
- package/bundle/node_modules/undici/lib/dispatcher/client.js +0 -614
- package/bundle/node_modules/undici/lib/dispatcher/dispatcher-base.js +0 -161
- package/bundle/node_modules/undici/lib/dispatcher/dispatcher.js +0 -48
- package/bundle/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +0 -151
- package/bundle/node_modules/undici/lib/dispatcher/fixed-queue.js +0 -159
- package/bundle/node_modules/undici/lib/dispatcher/h2c-client.js +0 -122
- package/bundle/node_modules/undici/lib/dispatcher/pool-base.js +0 -191
- package/bundle/node_modules/undici/lib/dispatcher/pool.js +0 -118
- package/bundle/node_modules/undici/lib/dispatcher/proxy-agent.js +0 -275
- package/bundle/node_modules/undici/lib/dispatcher/retry-agent.js +0 -35
- package/bundle/node_modules/undici/lib/global.js +0 -32
- package/bundle/node_modules/undici/lib/handler/cache-handler.js +0 -448
- package/bundle/node_modules/undici/lib/handler/cache-revalidation-handler.js +0 -124
- package/bundle/node_modules/undici/lib/handler/decorator-handler.js +0 -67
- package/bundle/node_modules/undici/lib/handler/redirect-handler.js +0 -227
- package/bundle/node_modules/undici/lib/handler/retry-handler.js +0 -342
- package/bundle/node_modules/undici/lib/handler/unwrap-handler.js +0 -96
- package/bundle/node_modules/undici/lib/handler/wrap-handler.js +0 -95
- package/bundle/node_modules/undici/lib/interceptor/cache.js +0 -372
- package/bundle/node_modules/undici/lib/interceptor/dns.js +0 -432
- package/bundle/node_modules/undici/lib/interceptor/dump.js +0 -111
- package/bundle/node_modules/undici/lib/interceptor/redirect.js +0 -21
- package/bundle/node_modules/undici/lib/interceptor/response-error.js +0 -95
- package/bundle/node_modules/undici/lib/interceptor/retry.js +0 -19
- package/bundle/node_modules/undici/lib/llhttp/.gitkeep +0 -0
- package/bundle/node_modules/undici/lib/llhttp/constants.d.ts +0 -97
- package/bundle/node_modules/undici/lib/llhttp/constants.js +0 -498
- package/bundle/node_modules/undici/lib/llhttp/constants.js.map +0 -1
- package/bundle/node_modules/undici/lib/llhttp/llhttp-wasm.js +0 -15
- package/bundle/node_modules/undici/lib/llhttp/llhttp_simd-wasm.js +0 -15
- package/bundle/node_modules/undici/lib/llhttp/utils.d.ts +0 -2
- package/bundle/node_modules/undici/lib/llhttp/utils.js +0 -15
- package/bundle/node_modules/undici/lib/llhttp/utils.js.map +0 -1
- package/bundle/node_modules/undici/lib/mock/mock-agent.js +0 -224
- package/bundle/node_modules/undici/lib/mock/mock-call-history.js +0 -248
- package/bundle/node_modules/undici/lib/mock/mock-client.js +0 -64
- package/bundle/node_modules/undici/lib/mock/mock-errors.js +0 -19
- package/bundle/node_modules/undici/lib/mock/mock-interceptor.js +0 -209
- package/bundle/node_modules/undici/lib/mock/mock-pool.js +0 -64
- package/bundle/node_modules/undici/lib/mock/mock-symbols.js +0 -31
- package/bundle/node_modules/undici/lib/mock/mock-utils.js +0 -433
- package/bundle/node_modules/undici/lib/mock/pending-interceptors-formatter.js +0 -43
- package/bundle/node_modules/undici/lib/util/cache.js +0 -368
- package/bundle/node_modules/undici/lib/util/date.js +0 -259
- package/bundle/node_modules/undici/lib/util/stats.js +0 -32
- package/bundle/node_modules/undici/lib/util/timers.js +0 -423
- package/bundle/node_modules/undici/lib/web/cache/cache.js +0 -862
- package/bundle/node_modules/undici/lib/web/cache/cachestorage.js +0 -152
- package/bundle/node_modules/undici/lib/web/cache/util.js +0 -45
- package/bundle/node_modules/undici/lib/web/cookies/constants.js +0 -12
- package/bundle/node_modules/undici/lib/web/cookies/index.js +0 -199
- package/bundle/node_modules/undici/lib/web/cookies/parse.js +0 -322
- package/bundle/node_modules/undici/lib/web/cookies/util.js +0 -282
- package/bundle/node_modules/undici/lib/web/eventsource/eventsource-stream.js +0 -399
- package/bundle/node_modules/undici/lib/web/eventsource/eventsource.js +0 -484
- package/bundle/node_modules/undici/lib/web/eventsource/util.js +0 -37
- package/bundle/node_modules/undici/lib/web/fetch/LICENSE +0 -21
- package/bundle/node_modules/undici/lib/web/fetch/body.js +0 -532
- package/bundle/node_modules/undici/lib/web/fetch/constants.js +0 -131
- package/bundle/node_modules/undici/lib/web/fetch/data-url.js +0 -744
- package/bundle/node_modules/undici/lib/web/fetch/dispatcher-weakref.js +0 -46
- package/bundle/node_modules/undici/lib/web/fetch/formdata-parser.js +0 -501
- package/bundle/node_modules/undici/lib/web/fetch/formdata.js +0 -263
- package/bundle/node_modules/undici/lib/web/fetch/global.js +0 -40
- package/bundle/node_modules/undici/lib/web/fetch/headers.js +0 -719
- package/bundle/node_modules/undici/lib/web/fetch/index.js +0 -2258
- package/bundle/node_modules/undici/lib/web/fetch/request.js +0 -1099
- package/bundle/node_modules/undici/lib/web/fetch/response.js +0 -636
- package/bundle/node_modules/undici/lib/web/fetch/util.js +0 -1782
- package/bundle/node_modules/undici/lib/web/fetch/webidl.js +0 -740
- package/bundle/node_modules/undici/lib/web/websocket/connection.js +0 -325
- package/bundle/node_modules/undici/lib/web/websocket/constants.js +0 -126
- package/bundle/node_modules/undici/lib/web/websocket/events.js +0 -331
- package/bundle/node_modules/undici/lib/web/websocket/frame.js +0 -138
- package/bundle/node_modules/undici/lib/web/websocket/permessage-deflate.js +0 -70
- package/bundle/node_modules/undici/lib/web/websocket/receiver.js +0 -454
- package/bundle/node_modules/undici/lib/web/websocket/sender.js +0 -109
- package/bundle/node_modules/undici/lib/web/websocket/stream/websocketerror.js +0 -83
- package/bundle/node_modules/undici/lib/web/websocket/stream/websocketstream.js +0 -485
- package/bundle/node_modules/undici/lib/web/websocket/util.js +0 -338
- package/bundle/node_modules/undici/lib/web/websocket/websocket.js +0 -686
- package/bundle/node_modules/undici/package.json +0 -149
- package/bundle/node_modules/undici/scripts/strip-comments.js +0 -10
- package/bundle/node_modules/undici/types/README.md +0 -6
- package/bundle/node_modules/undici/types/agent.d.ts +0 -35
- package/bundle/node_modules/undici/types/api.d.ts +0 -43
- package/bundle/node_modules/undici/types/balanced-pool.d.ts +0 -29
- package/bundle/node_modules/undici/types/cache-interceptor.d.ts +0 -172
- package/bundle/node_modules/undici/types/cache.d.ts +0 -36
- package/bundle/node_modules/undici/types/client-stats.d.ts +0 -15
- package/bundle/node_modules/undici/types/client.d.ts +0 -110
- package/bundle/node_modules/undici/types/connector.d.ts +0 -34
- package/bundle/node_modules/undici/types/content-type.d.ts +0 -21
- package/bundle/node_modules/undici/types/cookies.d.ts +0 -30
- package/bundle/node_modules/undici/types/diagnostics-channel.d.ts +0 -66
- package/bundle/node_modules/undici/types/dispatcher.d.ts +0 -281
- package/bundle/node_modules/undici/types/env-http-proxy-agent.d.ts +0 -21
- package/bundle/node_modules/undici/types/errors.d.ts +0 -171
- package/bundle/node_modules/undici/types/eventsource.d.ts +0 -61
- package/bundle/node_modules/undici/types/fetch.d.ts +0 -210
- package/bundle/node_modules/undici/types/formdata.d.ts +0 -108
- package/bundle/node_modules/undici/types/global-dispatcher.d.ts +0 -9
- package/bundle/node_modules/undici/types/global-origin.d.ts +0 -7
- package/bundle/node_modules/undici/types/h2c-client.d.ts +0 -75
- package/bundle/node_modules/undici/types/handlers.d.ts +0 -15
- package/bundle/node_modules/undici/types/header.d.ts +0 -160
- package/bundle/node_modules/undici/types/index.d.ts +0 -75
- package/bundle/node_modules/undici/types/interceptors.d.ts +0 -34
- package/bundle/node_modules/undici/types/mock-agent.d.ts +0 -68
- package/bundle/node_modules/undici/types/mock-call-history.d.ts +0 -111
- package/bundle/node_modules/undici/types/mock-client.d.ts +0 -25
- package/bundle/node_modules/undici/types/mock-errors.d.ts +0 -12
- package/bundle/node_modules/undici/types/mock-interceptor.d.ts +0 -93
- package/bundle/node_modules/undici/types/mock-pool.d.ts +0 -25
- package/bundle/node_modules/undici/types/patch.d.ts +0 -29
- package/bundle/node_modules/undici/types/pool-stats.d.ts +0 -19
- package/bundle/node_modules/undici/types/pool.d.ts +0 -41
- package/bundle/node_modules/undici/types/proxy-agent.d.ts +0 -29
- package/bundle/node_modules/undici/types/readable.d.ts +0 -68
- package/bundle/node_modules/undici/types/retry-agent.d.ts +0 -8
- package/bundle/node_modules/undici/types/retry-handler.d.ts +0 -116
- package/bundle/node_modules/undici/types/util.d.ts +0 -18
- package/bundle/node_modules/undici/types/utility.d.ts +0 -7
- package/bundle/node_modules/undici/types/webidl.d.ts +0 -266
- package/bundle/node_modules/undici/types/websocket.d.ts +0 -184
|
@@ -1,1615 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
/* global WebAssembly */
|
|
4
|
-
|
|
5
|
-
const assert = require('node:assert')
|
|
6
|
-
const util = require('../core/util.js')
|
|
7
|
-
const { channels } = require('../core/diagnostics.js')
|
|
8
|
-
const timers = require('../util/timers.js')
|
|
9
|
-
const {
|
|
10
|
-
RequestContentLengthMismatchError,
|
|
11
|
-
ResponseContentLengthMismatchError,
|
|
12
|
-
RequestAbortedError,
|
|
13
|
-
HeadersTimeoutError,
|
|
14
|
-
HeadersOverflowError,
|
|
15
|
-
SocketError,
|
|
16
|
-
InformationalError,
|
|
17
|
-
BodyTimeoutError,
|
|
18
|
-
HTTPParserError,
|
|
19
|
-
ResponseExceededMaxSizeError
|
|
20
|
-
} = require('../core/errors.js')
|
|
21
|
-
const {
|
|
22
|
-
kUrl,
|
|
23
|
-
kReset,
|
|
24
|
-
kClient,
|
|
25
|
-
kParser,
|
|
26
|
-
kBlocking,
|
|
27
|
-
kRunning,
|
|
28
|
-
kPending,
|
|
29
|
-
kSize,
|
|
30
|
-
kWriting,
|
|
31
|
-
kQueue,
|
|
32
|
-
kNoRef,
|
|
33
|
-
kKeepAliveDefaultTimeout,
|
|
34
|
-
kHostHeader,
|
|
35
|
-
kPendingIdx,
|
|
36
|
-
kRunningIdx,
|
|
37
|
-
kError,
|
|
38
|
-
kPipelining,
|
|
39
|
-
kSocket,
|
|
40
|
-
kKeepAliveTimeoutValue,
|
|
41
|
-
kMaxHeadersSize,
|
|
42
|
-
kKeepAliveMaxTimeout,
|
|
43
|
-
kKeepAliveTimeoutThreshold,
|
|
44
|
-
kHeadersTimeout,
|
|
45
|
-
kBodyTimeout,
|
|
46
|
-
kStrictContentLength,
|
|
47
|
-
kMaxRequests,
|
|
48
|
-
kCounter,
|
|
49
|
-
kMaxResponseSize,
|
|
50
|
-
kOnError,
|
|
51
|
-
kResume,
|
|
52
|
-
kHTTPContext,
|
|
53
|
-
kClosed
|
|
54
|
-
} = require('../core/symbols.js')
|
|
55
|
-
|
|
56
|
-
const constants = require('../llhttp/constants.js')
|
|
57
|
-
const EMPTY_BUF = Buffer.alloc(0)
|
|
58
|
-
const FastBuffer = Buffer[Symbol.species]
|
|
59
|
-
const removeAllListeners = util.removeAllListeners
|
|
60
|
-
|
|
61
|
-
let extractBody
|
|
62
|
-
|
|
63
|
-
async function lazyllhttp () {
|
|
64
|
-
const llhttpWasmData = process.env.JEST_WORKER_ID ? require('../llhttp/llhttp-wasm.js') : undefined
|
|
65
|
-
|
|
66
|
-
let mod
|
|
67
|
-
try {
|
|
68
|
-
mod = await WebAssembly.compile(require('../llhttp/llhttp_simd-wasm.js'))
|
|
69
|
-
} catch (e) {
|
|
70
|
-
/* istanbul ignore next */
|
|
71
|
-
|
|
72
|
-
// We could check if the error was caused by the simd option not
|
|
73
|
-
// being enabled, but the occurring of this other error
|
|
74
|
-
// * https://github.com/emscripten-core/emscripten/issues/11495
|
|
75
|
-
// got me to remove that check to avoid breaking Node 12.
|
|
76
|
-
mod = await WebAssembly.compile(llhttpWasmData || require('../llhttp/llhttp-wasm.js'))
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return await WebAssembly.instantiate(mod, {
|
|
80
|
-
env: {
|
|
81
|
-
/**
|
|
82
|
-
* @param {number} p
|
|
83
|
-
* @param {number} at
|
|
84
|
-
* @param {number} len
|
|
85
|
-
* @returns {number}
|
|
86
|
-
*/
|
|
87
|
-
wasm_on_url: (p, at, len) => {
|
|
88
|
-
/* istanbul ignore next */
|
|
89
|
-
return 0
|
|
90
|
-
},
|
|
91
|
-
/**
|
|
92
|
-
* @param {number} p
|
|
93
|
-
* @param {number} at
|
|
94
|
-
* @param {number} len
|
|
95
|
-
* @returns {number}
|
|
96
|
-
*/
|
|
97
|
-
wasm_on_status: (p, at, len) => {
|
|
98
|
-
assert(currentParser.ptr === p)
|
|
99
|
-
const start = at - currentBufferPtr + currentBufferRef.byteOffset
|
|
100
|
-
return currentParser.onStatus(new FastBuffer(currentBufferRef.buffer, start, len))
|
|
101
|
-
},
|
|
102
|
-
/**
|
|
103
|
-
* @param {number} p
|
|
104
|
-
* @returns {number}
|
|
105
|
-
*/
|
|
106
|
-
wasm_on_message_begin: (p) => {
|
|
107
|
-
assert(currentParser.ptr === p)
|
|
108
|
-
return currentParser.onMessageBegin()
|
|
109
|
-
},
|
|
110
|
-
/**
|
|
111
|
-
* @param {number} p
|
|
112
|
-
* @param {number} at
|
|
113
|
-
* @param {number} len
|
|
114
|
-
* @returns {number}
|
|
115
|
-
*/
|
|
116
|
-
wasm_on_header_field: (p, at, len) => {
|
|
117
|
-
assert(currentParser.ptr === p)
|
|
118
|
-
const start = at - currentBufferPtr + currentBufferRef.byteOffset
|
|
119
|
-
return currentParser.onHeaderField(new FastBuffer(currentBufferRef.buffer, start, len))
|
|
120
|
-
},
|
|
121
|
-
/**
|
|
122
|
-
* @param {number} p
|
|
123
|
-
* @param {number} at
|
|
124
|
-
* @param {number} len
|
|
125
|
-
* @returns {number}
|
|
126
|
-
*/
|
|
127
|
-
wasm_on_header_value: (p, at, len) => {
|
|
128
|
-
assert(currentParser.ptr === p)
|
|
129
|
-
const start = at - currentBufferPtr + currentBufferRef.byteOffset
|
|
130
|
-
return currentParser.onHeaderValue(new FastBuffer(currentBufferRef.buffer, start, len))
|
|
131
|
-
},
|
|
132
|
-
/**
|
|
133
|
-
* @param {number} p
|
|
134
|
-
* @param {number} statusCode
|
|
135
|
-
* @param {0|1} upgrade
|
|
136
|
-
* @param {0|1} shouldKeepAlive
|
|
137
|
-
* @returns {number}
|
|
138
|
-
*/
|
|
139
|
-
wasm_on_headers_complete: (p, statusCode, upgrade, shouldKeepAlive) => {
|
|
140
|
-
assert(currentParser.ptr === p)
|
|
141
|
-
return currentParser.onHeadersComplete(statusCode, upgrade === 1, shouldKeepAlive === 1)
|
|
142
|
-
},
|
|
143
|
-
/**
|
|
144
|
-
* @param {number} p
|
|
145
|
-
* @param {number} at
|
|
146
|
-
* @param {number} len
|
|
147
|
-
* @returns {number}
|
|
148
|
-
*/
|
|
149
|
-
wasm_on_body: (p, at, len) => {
|
|
150
|
-
assert(currentParser.ptr === p)
|
|
151
|
-
const start = at - currentBufferPtr + currentBufferRef.byteOffset
|
|
152
|
-
return currentParser.onBody(new FastBuffer(currentBufferRef.buffer, start, len))
|
|
153
|
-
},
|
|
154
|
-
/**
|
|
155
|
-
* @param {number} p
|
|
156
|
-
* @returns {number}
|
|
157
|
-
*/
|
|
158
|
-
wasm_on_message_complete: (p) => {
|
|
159
|
-
assert(currentParser.ptr === p)
|
|
160
|
-
return currentParser.onMessageComplete()
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
})
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
let llhttpInstance = null
|
|
168
|
-
/**
|
|
169
|
-
* @type {Promise<WebAssembly.Instance>|null}
|
|
170
|
-
*/
|
|
171
|
-
let llhttpPromise = lazyllhttp()
|
|
172
|
-
llhttpPromise.catch()
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* @type {Parser|null}
|
|
176
|
-
*/
|
|
177
|
-
let currentParser = null
|
|
178
|
-
let currentBufferRef = null
|
|
179
|
-
/**
|
|
180
|
-
* @type {number}
|
|
181
|
-
*/
|
|
182
|
-
let currentBufferSize = 0
|
|
183
|
-
let currentBufferPtr = null
|
|
184
|
-
|
|
185
|
-
const USE_NATIVE_TIMER = 0
|
|
186
|
-
const USE_FAST_TIMER = 1
|
|
187
|
-
|
|
188
|
-
// Use fast timers for headers and body to take eventual event loop
|
|
189
|
-
// latency into account.
|
|
190
|
-
const TIMEOUT_HEADERS = 2 | USE_FAST_TIMER
|
|
191
|
-
const TIMEOUT_BODY = 4 | USE_FAST_TIMER
|
|
192
|
-
|
|
193
|
-
// Use native timers to ignore event loop latency for keep-alive
|
|
194
|
-
// handling.
|
|
195
|
-
const TIMEOUT_KEEP_ALIVE = 8 | USE_NATIVE_TIMER
|
|
196
|
-
|
|
197
|
-
class Parser {
|
|
198
|
-
/**
|
|
199
|
-
* @param {import('./client.js')} client
|
|
200
|
-
* @param {import('net').Socket} socket
|
|
201
|
-
* @param {*} llhttp
|
|
202
|
-
*/
|
|
203
|
-
constructor (client, socket, { exports }) {
|
|
204
|
-
this.llhttp = exports
|
|
205
|
-
this.ptr = this.llhttp.llhttp_alloc(constants.TYPE.RESPONSE)
|
|
206
|
-
this.client = client
|
|
207
|
-
/**
|
|
208
|
-
* @type {import('net').Socket}
|
|
209
|
-
*/
|
|
210
|
-
this.socket = socket
|
|
211
|
-
this.timeout = null
|
|
212
|
-
this.timeoutValue = null
|
|
213
|
-
this.timeoutType = null
|
|
214
|
-
this.statusCode = 0
|
|
215
|
-
this.statusText = ''
|
|
216
|
-
this.upgrade = false
|
|
217
|
-
this.headers = []
|
|
218
|
-
this.headersSize = 0
|
|
219
|
-
this.headersMaxSize = client[kMaxHeadersSize]
|
|
220
|
-
this.shouldKeepAlive = false
|
|
221
|
-
this.paused = false
|
|
222
|
-
this.resume = this.resume.bind(this)
|
|
223
|
-
|
|
224
|
-
this.bytesRead = 0
|
|
225
|
-
|
|
226
|
-
this.keepAlive = ''
|
|
227
|
-
this.contentLength = ''
|
|
228
|
-
this.connection = ''
|
|
229
|
-
this.maxResponseSize = client[kMaxResponseSize]
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
setTimeout (delay, type) {
|
|
233
|
-
// If the existing timer and the new timer are of different timer type
|
|
234
|
-
// (fast or native) or have different delay, we need to clear the existing
|
|
235
|
-
// timer and set a new one.
|
|
236
|
-
if (
|
|
237
|
-
delay !== this.timeoutValue ||
|
|
238
|
-
(type & USE_FAST_TIMER) ^ (this.timeoutType & USE_FAST_TIMER)
|
|
239
|
-
) {
|
|
240
|
-
// If a timeout is already set, clear it with clearTimeout of the fast
|
|
241
|
-
// timer implementation, as it can clear fast and native timers.
|
|
242
|
-
if (this.timeout) {
|
|
243
|
-
timers.clearTimeout(this.timeout)
|
|
244
|
-
this.timeout = null
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (delay) {
|
|
248
|
-
if (type & USE_FAST_TIMER) {
|
|
249
|
-
this.timeout = timers.setFastTimeout(onParserTimeout, delay, new WeakRef(this))
|
|
250
|
-
} else {
|
|
251
|
-
this.timeout = setTimeout(onParserTimeout, delay, new WeakRef(this))
|
|
252
|
-
this.timeout.unref()
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
this.timeoutValue = delay
|
|
257
|
-
} else if (this.timeout) {
|
|
258
|
-
// istanbul ignore else: only for jest
|
|
259
|
-
if (this.timeout.refresh) {
|
|
260
|
-
this.timeout.refresh()
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
this.timeoutType = type
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
resume () {
|
|
268
|
-
if (this.socket.destroyed || !this.paused) {
|
|
269
|
-
return
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
assert(this.ptr != null)
|
|
273
|
-
assert(currentParser === null)
|
|
274
|
-
|
|
275
|
-
this.llhttp.llhttp_resume(this.ptr)
|
|
276
|
-
|
|
277
|
-
assert(this.timeoutType === TIMEOUT_BODY)
|
|
278
|
-
if (this.timeout) {
|
|
279
|
-
// istanbul ignore else: only for jest
|
|
280
|
-
if (this.timeout.refresh) {
|
|
281
|
-
this.timeout.refresh()
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
this.paused = false
|
|
286
|
-
this.execute(this.socket.read() || EMPTY_BUF) // Flush parser.
|
|
287
|
-
this.readMore()
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
readMore () {
|
|
291
|
-
while (!this.paused && this.ptr) {
|
|
292
|
-
const chunk = this.socket.read()
|
|
293
|
-
if (chunk === null) {
|
|
294
|
-
break
|
|
295
|
-
}
|
|
296
|
-
this.execute(chunk)
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* @param {Buffer} chunk
|
|
302
|
-
*/
|
|
303
|
-
execute (chunk) {
|
|
304
|
-
assert(currentParser === null)
|
|
305
|
-
assert(this.ptr != null)
|
|
306
|
-
assert(!this.paused)
|
|
307
|
-
|
|
308
|
-
const { socket, llhttp } = this
|
|
309
|
-
|
|
310
|
-
// Allocate a new buffer if the current buffer is too small.
|
|
311
|
-
if (chunk.length > currentBufferSize) {
|
|
312
|
-
if (currentBufferPtr) {
|
|
313
|
-
llhttp.free(currentBufferPtr)
|
|
314
|
-
}
|
|
315
|
-
// Allocate a buffer that is a multiple of 4096 bytes.
|
|
316
|
-
currentBufferSize = Math.ceil(chunk.length / 4096) * 4096
|
|
317
|
-
currentBufferPtr = llhttp.malloc(currentBufferSize)
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
new Uint8Array(llhttp.memory.buffer, currentBufferPtr, currentBufferSize).set(chunk)
|
|
321
|
-
|
|
322
|
-
// Call `execute` on the wasm parser.
|
|
323
|
-
// We pass the `llhttp_parser` pointer address, the pointer address of buffer view data,
|
|
324
|
-
// and finally the length of bytes to parse.
|
|
325
|
-
// The return value is an error code or `constants.ERROR.OK`.
|
|
326
|
-
try {
|
|
327
|
-
let ret
|
|
328
|
-
|
|
329
|
-
try {
|
|
330
|
-
currentBufferRef = chunk
|
|
331
|
-
currentParser = this
|
|
332
|
-
ret = llhttp.llhttp_execute(this.ptr, currentBufferPtr, chunk.length)
|
|
333
|
-
/* eslint-disable-next-line no-useless-catch */
|
|
334
|
-
} catch (err) {
|
|
335
|
-
/* istanbul ignore next: difficult to make a test case for */
|
|
336
|
-
throw err
|
|
337
|
-
} finally {
|
|
338
|
-
currentParser = null
|
|
339
|
-
currentBufferRef = null
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
if (ret !== constants.ERROR.OK) {
|
|
343
|
-
const data = chunk.subarray(llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr)
|
|
344
|
-
|
|
345
|
-
if (ret === constants.ERROR.PAUSED_UPGRADE) {
|
|
346
|
-
this.onUpgrade(data)
|
|
347
|
-
} else if (ret === constants.ERROR.PAUSED) {
|
|
348
|
-
this.paused = true
|
|
349
|
-
socket.unshift(data)
|
|
350
|
-
} else {
|
|
351
|
-
const ptr = llhttp.llhttp_get_error_reason(this.ptr)
|
|
352
|
-
let message = ''
|
|
353
|
-
/* istanbul ignore else: difficult to make a test case for */
|
|
354
|
-
if (ptr) {
|
|
355
|
-
const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0)
|
|
356
|
-
message =
|
|
357
|
-
'Response does not match the HTTP/1.1 protocol (' +
|
|
358
|
-
Buffer.from(llhttp.memory.buffer, ptr, len).toString() +
|
|
359
|
-
')'
|
|
360
|
-
}
|
|
361
|
-
throw new HTTPParserError(message, constants.ERROR[ret], data)
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
} catch (err) {
|
|
365
|
-
util.destroy(socket, err)
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
destroy () {
|
|
370
|
-
assert(currentParser === null)
|
|
371
|
-
assert(this.ptr != null)
|
|
372
|
-
|
|
373
|
-
this.llhttp.llhttp_free(this.ptr)
|
|
374
|
-
this.ptr = null
|
|
375
|
-
|
|
376
|
-
this.timeout && timers.clearTimeout(this.timeout)
|
|
377
|
-
this.timeout = null
|
|
378
|
-
this.timeoutValue = null
|
|
379
|
-
this.timeoutType = null
|
|
380
|
-
|
|
381
|
-
this.paused = false
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* @param {Buffer} buf
|
|
386
|
-
* @returns {0}
|
|
387
|
-
*/
|
|
388
|
-
onStatus (buf) {
|
|
389
|
-
this.statusText = buf.toString()
|
|
390
|
-
return 0
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
/**
|
|
394
|
-
* @returns {0|-1}
|
|
395
|
-
*/
|
|
396
|
-
onMessageBegin () {
|
|
397
|
-
const { socket, client } = this
|
|
398
|
-
|
|
399
|
-
/* istanbul ignore next: difficult to make a test case for */
|
|
400
|
-
if (socket.destroyed) {
|
|
401
|
-
return -1
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
const request = client[kQueue][client[kRunningIdx]]
|
|
405
|
-
if (!request) {
|
|
406
|
-
return -1
|
|
407
|
-
}
|
|
408
|
-
request.onResponseStarted()
|
|
409
|
-
|
|
410
|
-
return 0
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
/**
|
|
414
|
-
* @param {Buffer} buf
|
|
415
|
-
* @returns {number}
|
|
416
|
-
*/
|
|
417
|
-
onHeaderField (buf) {
|
|
418
|
-
const len = this.headers.length
|
|
419
|
-
|
|
420
|
-
if ((len & 1) === 0) {
|
|
421
|
-
this.headers.push(buf)
|
|
422
|
-
} else {
|
|
423
|
-
this.headers[len - 1] = Buffer.concat([this.headers[len - 1], buf])
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
this.trackHeader(buf.length)
|
|
427
|
-
|
|
428
|
-
return 0
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
/**
|
|
432
|
-
* @param {Buffer} buf
|
|
433
|
-
* @returns {number}
|
|
434
|
-
*/
|
|
435
|
-
onHeaderValue (buf) {
|
|
436
|
-
let len = this.headers.length
|
|
437
|
-
|
|
438
|
-
if ((len & 1) === 1) {
|
|
439
|
-
this.headers.push(buf)
|
|
440
|
-
len += 1
|
|
441
|
-
} else {
|
|
442
|
-
this.headers[len - 1] = Buffer.concat([this.headers[len - 1], buf])
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
const key = this.headers[len - 2]
|
|
446
|
-
if (key.length === 10) {
|
|
447
|
-
const headerName = util.bufferToLowerCasedHeaderName(key)
|
|
448
|
-
if (headerName === 'keep-alive') {
|
|
449
|
-
this.keepAlive += buf.toString()
|
|
450
|
-
} else if (headerName === 'connection') {
|
|
451
|
-
this.connection += buf.toString()
|
|
452
|
-
}
|
|
453
|
-
} else if (key.length === 14 && util.bufferToLowerCasedHeaderName(key) === 'content-length') {
|
|
454
|
-
this.contentLength += buf.toString()
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
this.trackHeader(buf.length)
|
|
458
|
-
|
|
459
|
-
return 0
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
/**
|
|
463
|
-
* @param {number} len
|
|
464
|
-
*/
|
|
465
|
-
trackHeader (len) {
|
|
466
|
-
this.headersSize += len
|
|
467
|
-
if (this.headersSize >= this.headersMaxSize) {
|
|
468
|
-
util.destroy(this.socket, new HeadersOverflowError())
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
/**
|
|
473
|
-
* @param {Buffer} head
|
|
474
|
-
*/
|
|
475
|
-
onUpgrade (head) {
|
|
476
|
-
const { upgrade, client, socket, headers, statusCode } = this
|
|
477
|
-
|
|
478
|
-
assert(upgrade)
|
|
479
|
-
assert(client[kSocket] === socket)
|
|
480
|
-
assert(!socket.destroyed)
|
|
481
|
-
assert(!this.paused)
|
|
482
|
-
assert((headers.length & 1) === 0)
|
|
483
|
-
|
|
484
|
-
const request = client[kQueue][client[kRunningIdx]]
|
|
485
|
-
assert(request)
|
|
486
|
-
assert(request.upgrade || request.method === 'CONNECT')
|
|
487
|
-
|
|
488
|
-
this.statusCode = 0
|
|
489
|
-
this.statusText = ''
|
|
490
|
-
this.shouldKeepAlive = false
|
|
491
|
-
|
|
492
|
-
this.headers = []
|
|
493
|
-
this.headersSize = 0
|
|
494
|
-
|
|
495
|
-
socket.unshift(head)
|
|
496
|
-
|
|
497
|
-
socket[kParser].destroy()
|
|
498
|
-
socket[kParser] = null
|
|
499
|
-
|
|
500
|
-
socket[kClient] = null
|
|
501
|
-
socket[kError] = null
|
|
502
|
-
|
|
503
|
-
removeAllListeners(socket)
|
|
504
|
-
|
|
505
|
-
client[kSocket] = null
|
|
506
|
-
client[kHTTPContext] = null // TODO (fix): This is hacky...
|
|
507
|
-
client[kQueue][client[kRunningIdx]++] = null
|
|
508
|
-
client.emit('disconnect', client[kUrl], [client], new InformationalError('upgrade'))
|
|
509
|
-
|
|
510
|
-
try {
|
|
511
|
-
request.onUpgrade(statusCode, headers, socket)
|
|
512
|
-
} catch (err) {
|
|
513
|
-
util.destroy(socket, err)
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
client[kResume]()
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
/**
|
|
520
|
-
* @param {number} statusCode
|
|
521
|
-
* @param {boolean} upgrade
|
|
522
|
-
* @param {boolean} shouldKeepAlive
|
|
523
|
-
* @returns {number}
|
|
524
|
-
*/
|
|
525
|
-
onHeadersComplete (statusCode, upgrade, shouldKeepAlive) {
|
|
526
|
-
const { client, socket, headers, statusText } = this
|
|
527
|
-
|
|
528
|
-
/* istanbul ignore next: difficult to make a test case for */
|
|
529
|
-
if (socket.destroyed) {
|
|
530
|
-
return -1
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
const request = client[kQueue][client[kRunningIdx]]
|
|
534
|
-
|
|
535
|
-
/* istanbul ignore next: difficult to make a test case for */
|
|
536
|
-
if (!request) {
|
|
537
|
-
return -1
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
assert(!this.upgrade)
|
|
541
|
-
assert(this.statusCode < 200)
|
|
542
|
-
|
|
543
|
-
if (statusCode === 100) {
|
|
544
|
-
util.destroy(socket, new SocketError('bad response', util.getSocketInfo(socket)))
|
|
545
|
-
return -1
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
/* this can only happen if server is misbehaving */
|
|
549
|
-
if (upgrade && !request.upgrade) {
|
|
550
|
-
util.destroy(socket, new SocketError('bad upgrade', util.getSocketInfo(socket)))
|
|
551
|
-
return -1
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
assert(this.timeoutType === TIMEOUT_HEADERS)
|
|
555
|
-
|
|
556
|
-
this.statusCode = statusCode
|
|
557
|
-
this.shouldKeepAlive = (
|
|
558
|
-
shouldKeepAlive ||
|
|
559
|
-
// Override llhttp value which does not allow keepAlive for HEAD.
|
|
560
|
-
(request.method === 'HEAD' && !socket[kReset] && this.connection.toLowerCase() === 'keep-alive')
|
|
561
|
-
)
|
|
562
|
-
|
|
563
|
-
if (this.statusCode >= 200) {
|
|
564
|
-
const bodyTimeout = request.bodyTimeout != null
|
|
565
|
-
? request.bodyTimeout
|
|
566
|
-
: client[kBodyTimeout]
|
|
567
|
-
this.setTimeout(bodyTimeout, TIMEOUT_BODY)
|
|
568
|
-
} else if (this.timeout) {
|
|
569
|
-
// istanbul ignore else: only for jest
|
|
570
|
-
if (this.timeout.refresh) {
|
|
571
|
-
this.timeout.refresh()
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
if (request.method === 'CONNECT') {
|
|
576
|
-
assert(client[kRunning] === 1)
|
|
577
|
-
this.upgrade = true
|
|
578
|
-
return 2
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
if (upgrade) {
|
|
582
|
-
assert(client[kRunning] === 1)
|
|
583
|
-
this.upgrade = true
|
|
584
|
-
return 2
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
assert((this.headers.length & 1) === 0)
|
|
588
|
-
this.headers = []
|
|
589
|
-
this.headersSize = 0
|
|
590
|
-
|
|
591
|
-
if (this.shouldKeepAlive && client[kPipelining]) {
|
|
592
|
-
const keepAliveTimeout = this.keepAlive ? util.parseKeepAliveTimeout(this.keepAlive) : null
|
|
593
|
-
|
|
594
|
-
if (keepAliveTimeout != null) {
|
|
595
|
-
const timeout = Math.min(
|
|
596
|
-
keepAliveTimeout - client[kKeepAliveTimeoutThreshold],
|
|
597
|
-
client[kKeepAliveMaxTimeout]
|
|
598
|
-
)
|
|
599
|
-
if (timeout <= 0) {
|
|
600
|
-
socket[kReset] = true
|
|
601
|
-
} else {
|
|
602
|
-
client[kKeepAliveTimeoutValue] = timeout
|
|
603
|
-
}
|
|
604
|
-
} else {
|
|
605
|
-
client[kKeepAliveTimeoutValue] = client[kKeepAliveDefaultTimeout]
|
|
606
|
-
}
|
|
607
|
-
} else {
|
|
608
|
-
// Stop more requests from being dispatched.
|
|
609
|
-
socket[kReset] = true
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
const pause = request.onHeaders(statusCode, headers, this.resume, statusText) === false
|
|
613
|
-
|
|
614
|
-
if (request.aborted) {
|
|
615
|
-
return -1
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
if (request.method === 'HEAD') {
|
|
619
|
-
return 1
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
if (statusCode < 200) {
|
|
623
|
-
return 1
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
if (socket[kBlocking]) {
|
|
627
|
-
socket[kBlocking] = false
|
|
628
|
-
client[kResume]()
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
return pause ? constants.ERROR.PAUSED : 0
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
/**
|
|
635
|
-
* @param {Buffer} buf
|
|
636
|
-
* @returns {number}
|
|
637
|
-
*/
|
|
638
|
-
onBody (buf) {
|
|
639
|
-
const { client, socket, statusCode, maxResponseSize } = this
|
|
640
|
-
|
|
641
|
-
if (socket.destroyed) {
|
|
642
|
-
return -1
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
const request = client[kQueue][client[kRunningIdx]]
|
|
646
|
-
assert(request)
|
|
647
|
-
|
|
648
|
-
assert(this.timeoutType === TIMEOUT_BODY)
|
|
649
|
-
if (this.timeout) {
|
|
650
|
-
// istanbul ignore else: only for jest
|
|
651
|
-
if (this.timeout.refresh) {
|
|
652
|
-
this.timeout.refresh()
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
assert(statusCode >= 200)
|
|
657
|
-
|
|
658
|
-
if (maxResponseSize > -1 && this.bytesRead + buf.length > maxResponseSize) {
|
|
659
|
-
util.destroy(socket, new ResponseExceededMaxSizeError())
|
|
660
|
-
return -1
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
this.bytesRead += buf.length
|
|
664
|
-
|
|
665
|
-
if (request.onData(buf) === false) {
|
|
666
|
-
return constants.ERROR.PAUSED
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
return 0
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
/**
|
|
673
|
-
* @returns {number}
|
|
674
|
-
*/
|
|
675
|
-
onMessageComplete () {
|
|
676
|
-
const { client, socket, statusCode, upgrade, headers, contentLength, bytesRead, shouldKeepAlive } = this
|
|
677
|
-
|
|
678
|
-
if (socket.destroyed && (!statusCode || shouldKeepAlive)) {
|
|
679
|
-
return -1
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
if (upgrade) {
|
|
683
|
-
return 0
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
assert(statusCode >= 100)
|
|
687
|
-
assert((this.headers.length & 1) === 0)
|
|
688
|
-
|
|
689
|
-
const request = client[kQueue][client[kRunningIdx]]
|
|
690
|
-
assert(request)
|
|
691
|
-
|
|
692
|
-
this.statusCode = 0
|
|
693
|
-
this.statusText = ''
|
|
694
|
-
this.bytesRead = 0
|
|
695
|
-
this.contentLength = ''
|
|
696
|
-
this.keepAlive = ''
|
|
697
|
-
this.connection = ''
|
|
698
|
-
|
|
699
|
-
this.headers = []
|
|
700
|
-
this.headersSize = 0
|
|
701
|
-
|
|
702
|
-
if (statusCode < 200) {
|
|
703
|
-
return 0
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
/* istanbul ignore next: should be handled by llhttp? */
|
|
707
|
-
if (request.method !== 'HEAD' && contentLength && bytesRead !== parseInt(contentLength, 10)) {
|
|
708
|
-
util.destroy(socket, new ResponseContentLengthMismatchError())
|
|
709
|
-
return -1
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
request.onComplete(headers)
|
|
713
|
-
|
|
714
|
-
client[kQueue][client[kRunningIdx]++] = null
|
|
715
|
-
|
|
716
|
-
if (socket[kWriting]) {
|
|
717
|
-
assert(client[kRunning] === 0)
|
|
718
|
-
// Response completed before request.
|
|
719
|
-
util.destroy(socket, new InformationalError('reset'))
|
|
720
|
-
return constants.ERROR.PAUSED
|
|
721
|
-
} else if (!shouldKeepAlive) {
|
|
722
|
-
util.destroy(socket, new InformationalError('reset'))
|
|
723
|
-
return constants.ERROR.PAUSED
|
|
724
|
-
} else if (socket[kReset] && client[kRunning] === 0) {
|
|
725
|
-
// Destroy socket once all requests have completed.
|
|
726
|
-
// The request at the tail of the pipeline is the one
|
|
727
|
-
// that requested reset and no further requests should
|
|
728
|
-
// have been queued since then.
|
|
729
|
-
util.destroy(socket, new InformationalError('reset'))
|
|
730
|
-
return constants.ERROR.PAUSED
|
|
731
|
-
} else if (client[kPipelining] == null || client[kPipelining] === 1) {
|
|
732
|
-
// We must wait a full event loop cycle to reuse this socket to make sure
|
|
733
|
-
// that non-spec compliant servers are not closing the connection even if they
|
|
734
|
-
// said they won't.
|
|
735
|
-
setImmediate(() => client[kResume]())
|
|
736
|
-
} else {
|
|
737
|
-
client[kResume]()
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
return 0
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
function onParserTimeout (parser) {
|
|
745
|
-
const { socket, timeoutType, client, paused } = parser.deref()
|
|
746
|
-
|
|
747
|
-
/* istanbul ignore else */
|
|
748
|
-
if (timeoutType === TIMEOUT_HEADERS) {
|
|
749
|
-
if (!socket[kWriting] || socket.writableNeedDrain || client[kRunning] > 1) {
|
|
750
|
-
assert(!paused, 'cannot be paused while waiting for headers')
|
|
751
|
-
util.destroy(socket, new HeadersTimeoutError())
|
|
752
|
-
}
|
|
753
|
-
} else if (timeoutType === TIMEOUT_BODY) {
|
|
754
|
-
if (!paused) {
|
|
755
|
-
util.destroy(socket, new BodyTimeoutError())
|
|
756
|
-
}
|
|
757
|
-
} else if (timeoutType === TIMEOUT_KEEP_ALIVE) {
|
|
758
|
-
assert(client[kRunning] === 0 && client[kKeepAliveTimeoutValue])
|
|
759
|
-
util.destroy(socket, new InformationalError('socket idle timeout'))
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
/**
|
|
764
|
-
* @param {import ('./client.js')} client
|
|
765
|
-
* @param {import('net').Socket} socket
|
|
766
|
-
* @returns
|
|
767
|
-
*/
|
|
768
|
-
async function connectH1 (client, socket) {
|
|
769
|
-
client[kSocket] = socket
|
|
770
|
-
|
|
771
|
-
if (!llhttpInstance) {
|
|
772
|
-
const noop = () => {}
|
|
773
|
-
socket.on('error', noop)
|
|
774
|
-
llhttpInstance = await llhttpPromise
|
|
775
|
-
llhttpPromise = null
|
|
776
|
-
socket.off('error', noop)
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
if (socket.errored) {
|
|
780
|
-
throw socket.errored
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
if (socket.destroyed) {
|
|
784
|
-
throw new SocketError('destroyed')
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
socket[kNoRef] = false
|
|
788
|
-
socket[kWriting] = false
|
|
789
|
-
socket[kReset] = false
|
|
790
|
-
socket[kBlocking] = false
|
|
791
|
-
socket[kParser] = new Parser(client, socket, llhttpInstance)
|
|
792
|
-
|
|
793
|
-
util.addListener(socket, 'error', onHttpSocketError)
|
|
794
|
-
util.addListener(socket, 'readable', onHttpSocketReadable)
|
|
795
|
-
util.addListener(socket, 'end', onHttpSocketEnd)
|
|
796
|
-
util.addListener(socket, 'close', onHttpSocketClose)
|
|
797
|
-
|
|
798
|
-
socket[kClosed] = false
|
|
799
|
-
socket.on('close', onSocketClose)
|
|
800
|
-
|
|
801
|
-
return {
|
|
802
|
-
version: 'h1',
|
|
803
|
-
defaultPipelining: 1,
|
|
804
|
-
write (request) {
|
|
805
|
-
return writeH1(client, request)
|
|
806
|
-
},
|
|
807
|
-
resume () {
|
|
808
|
-
resumeH1(client)
|
|
809
|
-
},
|
|
810
|
-
/**
|
|
811
|
-
* @param {Error|undefined} err
|
|
812
|
-
* @param {() => void} callback
|
|
813
|
-
*/
|
|
814
|
-
destroy (err, callback) {
|
|
815
|
-
if (socket[kClosed]) {
|
|
816
|
-
queueMicrotask(callback)
|
|
817
|
-
} else {
|
|
818
|
-
socket.on('close', callback)
|
|
819
|
-
socket.destroy(err)
|
|
820
|
-
}
|
|
821
|
-
},
|
|
822
|
-
/**
|
|
823
|
-
* @returns {boolean}
|
|
824
|
-
*/
|
|
825
|
-
get destroyed () {
|
|
826
|
-
return socket.destroyed
|
|
827
|
-
},
|
|
828
|
-
/**
|
|
829
|
-
* @param {import('../core/request.js')} request
|
|
830
|
-
* @returns {boolean}
|
|
831
|
-
*/
|
|
832
|
-
busy (request) {
|
|
833
|
-
if (socket[kWriting] || socket[kReset] || socket[kBlocking]) {
|
|
834
|
-
return true
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
if (request) {
|
|
838
|
-
if (client[kRunning] > 0 && !request.idempotent) {
|
|
839
|
-
// Non-idempotent request cannot be retried.
|
|
840
|
-
// Ensure that no other requests are inflight and
|
|
841
|
-
// could cause failure.
|
|
842
|
-
return true
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
if (client[kRunning] > 0 && (request.upgrade || request.method === 'CONNECT')) {
|
|
846
|
-
// Don't dispatch an upgrade until all preceding requests have completed.
|
|
847
|
-
// A misbehaving server might upgrade the connection before all pipelined
|
|
848
|
-
// request has completed.
|
|
849
|
-
return true
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
if (client[kRunning] > 0 && util.bodyLength(request.body) !== 0 &&
|
|
853
|
-
(util.isStream(request.body) || util.isAsyncIterable(request.body) || util.isFormDataLike(request.body))) {
|
|
854
|
-
// Request with stream or iterator body can error while other requests
|
|
855
|
-
// are inflight and indirectly error those as well.
|
|
856
|
-
// Ensure this doesn't happen by waiting for inflight
|
|
857
|
-
// to complete before dispatching.
|
|
858
|
-
|
|
859
|
-
// Request with stream or iterator body cannot be retried.
|
|
860
|
-
// Ensure that no other requests are inflight and
|
|
861
|
-
// could cause failure.
|
|
862
|
-
return true
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
return false
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
function onHttpSocketError (err) {
|
|
872
|
-
assert(err.code !== 'ERR_TLS_CERT_ALTNAME_INVALID')
|
|
873
|
-
|
|
874
|
-
const parser = this[kParser]
|
|
875
|
-
|
|
876
|
-
// On Mac OS, we get an ECONNRESET even if there is a full body to be forwarded
|
|
877
|
-
// to the user.
|
|
878
|
-
if (err.code === 'ECONNRESET' && parser.statusCode && !parser.shouldKeepAlive) {
|
|
879
|
-
// We treat all incoming data so for as a valid response.
|
|
880
|
-
parser.onMessageComplete()
|
|
881
|
-
return
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
this[kError] = err
|
|
885
|
-
|
|
886
|
-
this[kClient][kOnError](err)
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
function onHttpSocketReadable () {
|
|
890
|
-
this[kParser]?.readMore()
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
function onHttpSocketEnd () {
|
|
894
|
-
const parser = this[kParser]
|
|
895
|
-
|
|
896
|
-
if (parser.statusCode && !parser.shouldKeepAlive) {
|
|
897
|
-
// We treat all incoming data so far as a valid response.
|
|
898
|
-
parser.onMessageComplete()
|
|
899
|
-
return
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
util.destroy(this, new SocketError('other side closed', util.getSocketInfo(this)))
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
function onHttpSocketClose () {
|
|
906
|
-
const parser = this[kParser]
|
|
907
|
-
|
|
908
|
-
if (parser) {
|
|
909
|
-
if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) {
|
|
910
|
-
// We treat all incoming data so far as a valid response.
|
|
911
|
-
parser.onMessageComplete()
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
this[kParser].destroy()
|
|
915
|
-
this[kParser] = null
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
const err = this[kError] || new SocketError('closed', util.getSocketInfo(this))
|
|
919
|
-
|
|
920
|
-
const client = this[kClient]
|
|
921
|
-
|
|
922
|
-
client[kSocket] = null
|
|
923
|
-
client[kHTTPContext] = null // TODO (fix): This is hacky...
|
|
924
|
-
|
|
925
|
-
if (client.destroyed) {
|
|
926
|
-
assert(client[kPending] === 0)
|
|
927
|
-
|
|
928
|
-
// Fail entire queue.
|
|
929
|
-
const requests = client[kQueue].splice(client[kRunningIdx])
|
|
930
|
-
for (let i = 0; i < requests.length; i++) {
|
|
931
|
-
const request = requests[i]
|
|
932
|
-
util.errorRequest(client, request, err)
|
|
933
|
-
}
|
|
934
|
-
} else if (client[kRunning] > 0 && err.code !== 'UND_ERR_INFO') {
|
|
935
|
-
// Fail head of pipeline.
|
|
936
|
-
const request = client[kQueue][client[kRunningIdx]]
|
|
937
|
-
client[kQueue][client[kRunningIdx]++] = null
|
|
938
|
-
|
|
939
|
-
util.errorRequest(client, request, err)
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
client[kPendingIdx] = client[kRunningIdx]
|
|
943
|
-
|
|
944
|
-
assert(client[kRunning] === 0)
|
|
945
|
-
|
|
946
|
-
client.emit('disconnect', client[kUrl], [client], err)
|
|
947
|
-
|
|
948
|
-
client[kResume]()
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
function onSocketClose () {
|
|
952
|
-
this[kClosed] = true
|
|
953
|
-
}
|
|
954
|
-
|
|
955
|
-
/**
|
|
956
|
-
* @param {import('./client.js')} client
|
|
957
|
-
*/
|
|
958
|
-
function resumeH1 (client) {
|
|
959
|
-
const socket = client[kSocket]
|
|
960
|
-
|
|
961
|
-
if (socket && !socket.destroyed) {
|
|
962
|
-
if (client[kSize] === 0) {
|
|
963
|
-
if (!socket[kNoRef] && socket.unref) {
|
|
964
|
-
socket.unref()
|
|
965
|
-
socket[kNoRef] = true
|
|
966
|
-
}
|
|
967
|
-
} else if (socket[kNoRef] && socket.ref) {
|
|
968
|
-
socket.ref()
|
|
969
|
-
socket[kNoRef] = false
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
if (client[kSize] === 0) {
|
|
973
|
-
if (socket[kParser].timeoutType !== TIMEOUT_KEEP_ALIVE) {
|
|
974
|
-
socket[kParser].setTimeout(client[kKeepAliveTimeoutValue], TIMEOUT_KEEP_ALIVE)
|
|
975
|
-
}
|
|
976
|
-
} else if (client[kRunning] > 0 && socket[kParser].statusCode < 200) {
|
|
977
|
-
if (socket[kParser].timeoutType !== TIMEOUT_HEADERS) {
|
|
978
|
-
const request = client[kQueue][client[kRunningIdx]]
|
|
979
|
-
const headersTimeout = request.headersTimeout != null
|
|
980
|
-
? request.headersTimeout
|
|
981
|
-
: client[kHeadersTimeout]
|
|
982
|
-
socket[kParser].setTimeout(headersTimeout, TIMEOUT_HEADERS)
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
// https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2
|
|
989
|
-
function shouldSendContentLength (method) {
|
|
990
|
-
return method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS' && method !== 'TRACE' && method !== 'CONNECT'
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
/**
|
|
994
|
-
* @param {import('./client.js')} client
|
|
995
|
-
* @param {import('../core/request.js')} request
|
|
996
|
-
* @returns
|
|
997
|
-
*/
|
|
998
|
-
function writeH1 (client, request) {
|
|
999
|
-
const { method, path, host, upgrade, blocking, reset } = request
|
|
1000
|
-
|
|
1001
|
-
let { body, headers, contentLength } = request
|
|
1002
|
-
|
|
1003
|
-
// https://tools.ietf.org/html/rfc7231#section-4.3.1
|
|
1004
|
-
// https://tools.ietf.org/html/rfc7231#section-4.3.2
|
|
1005
|
-
// https://tools.ietf.org/html/rfc7231#section-4.3.5
|
|
1006
|
-
|
|
1007
|
-
// Sending a payload body on a request that does not
|
|
1008
|
-
// expect it can cause undefined behavior on some
|
|
1009
|
-
// servers and corrupt connection state. Do not
|
|
1010
|
-
// re-use the connection for further requests.
|
|
1011
|
-
|
|
1012
|
-
const expectsPayload = (
|
|
1013
|
-
method === 'PUT' ||
|
|
1014
|
-
method === 'POST' ||
|
|
1015
|
-
method === 'PATCH' ||
|
|
1016
|
-
method === 'QUERY' ||
|
|
1017
|
-
method === 'PROPFIND' ||
|
|
1018
|
-
method === 'PROPPATCH'
|
|
1019
|
-
)
|
|
1020
|
-
|
|
1021
|
-
if (util.isFormDataLike(body)) {
|
|
1022
|
-
if (!extractBody) {
|
|
1023
|
-
extractBody = require('../web/fetch/body.js').extractBody
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
const [bodyStream, contentType] = extractBody(body)
|
|
1027
|
-
if (request.contentType == null) {
|
|
1028
|
-
headers.push('content-type', contentType)
|
|
1029
|
-
}
|
|
1030
|
-
body = bodyStream.stream
|
|
1031
|
-
contentLength = bodyStream.length
|
|
1032
|
-
} else if (util.isBlobLike(body) && request.contentType == null && body.type) {
|
|
1033
|
-
headers.push('content-type', body.type)
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
if (body && typeof body.read === 'function') {
|
|
1037
|
-
// Try to read EOF in order to get length.
|
|
1038
|
-
body.read(0)
|
|
1039
|
-
}
|
|
1040
|
-
|
|
1041
|
-
const bodyLength = util.bodyLength(body)
|
|
1042
|
-
|
|
1043
|
-
contentLength = bodyLength ?? contentLength
|
|
1044
|
-
|
|
1045
|
-
if (contentLength === null) {
|
|
1046
|
-
contentLength = request.contentLength
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
if (contentLength === 0 && !expectsPayload) {
|
|
1050
|
-
// https://tools.ietf.org/html/rfc7230#section-3.3.2
|
|
1051
|
-
// A user agent SHOULD NOT send a Content-Length header field when
|
|
1052
|
-
// the request message does not contain a payload body and the method
|
|
1053
|
-
// semantics do not anticipate such a body.
|
|
1054
|
-
|
|
1055
|
-
contentLength = null
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
// https://github.com/nodejs/undici/issues/2046
|
|
1059
|
-
// A user agent may send a Content-Length header with 0 value, this should be allowed.
|
|
1060
|
-
if (shouldSendContentLength(method) && contentLength > 0 && request.contentLength !== null && request.contentLength !== contentLength) {
|
|
1061
|
-
if (client[kStrictContentLength]) {
|
|
1062
|
-
util.errorRequest(client, request, new RequestContentLengthMismatchError())
|
|
1063
|
-
return false
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
process.emitWarning(new RequestContentLengthMismatchError())
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
|
-
const socket = client[kSocket]
|
|
1070
|
-
|
|
1071
|
-
/**
|
|
1072
|
-
* @param {Error} [err]
|
|
1073
|
-
* @returns {void}
|
|
1074
|
-
*/
|
|
1075
|
-
const abort = (err) => {
|
|
1076
|
-
if (request.aborted || request.completed) {
|
|
1077
|
-
return
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
util.errorRequest(client, request, err || new RequestAbortedError())
|
|
1081
|
-
|
|
1082
|
-
util.destroy(body)
|
|
1083
|
-
util.destroy(socket, new InformationalError('aborted'))
|
|
1084
|
-
}
|
|
1085
|
-
|
|
1086
|
-
try {
|
|
1087
|
-
request.onConnect(abort)
|
|
1088
|
-
} catch (err) {
|
|
1089
|
-
util.errorRequest(client, request, err)
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
if (request.aborted) {
|
|
1093
|
-
return false
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
if (method === 'HEAD') {
|
|
1097
|
-
// https://github.com/mcollina/undici/issues/258
|
|
1098
|
-
// Close after a HEAD request to interop with misbehaving servers
|
|
1099
|
-
// that may send a body in the response.
|
|
1100
|
-
|
|
1101
|
-
socket[kReset] = true
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
|
-
if (upgrade || method === 'CONNECT') {
|
|
1105
|
-
// On CONNECT or upgrade, block pipeline from dispatching further
|
|
1106
|
-
// requests on this connection.
|
|
1107
|
-
|
|
1108
|
-
socket[kReset] = true
|
|
1109
|
-
}
|
|
1110
|
-
|
|
1111
|
-
if (reset != null) {
|
|
1112
|
-
socket[kReset] = reset
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
if (client[kMaxRequests] && socket[kCounter]++ >= client[kMaxRequests]) {
|
|
1116
|
-
socket[kReset] = true
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
if (blocking) {
|
|
1120
|
-
socket[kBlocking] = true
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
let header = `${method} ${path} HTTP/1.1\r\n`
|
|
1124
|
-
|
|
1125
|
-
if (typeof host === 'string') {
|
|
1126
|
-
header += `host: ${host}\r\n`
|
|
1127
|
-
} else {
|
|
1128
|
-
header += client[kHostHeader]
|
|
1129
|
-
}
|
|
1130
|
-
|
|
1131
|
-
if (upgrade) {
|
|
1132
|
-
header += `connection: upgrade\r\nupgrade: ${upgrade}\r\n`
|
|
1133
|
-
} else if (client[kPipelining] && !socket[kReset]) {
|
|
1134
|
-
header += 'connection: keep-alive\r\n'
|
|
1135
|
-
} else {
|
|
1136
|
-
header += 'connection: close\r\n'
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
if (Array.isArray(headers)) {
|
|
1140
|
-
for (let n = 0; n < headers.length; n += 2) {
|
|
1141
|
-
const key = headers[n + 0]
|
|
1142
|
-
const val = headers[n + 1]
|
|
1143
|
-
|
|
1144
|
-
if (Array.isArray(val)) {
|
|
1145
|
-
for (let i = 0; i < val.length; i++) {
|
|
1146
|
-
header += `${key}: ${val[i]}\r\n`
|
|
1147
|
-
}
|
|
1148
|
-
} else {
|
|
1149
|
-
header += `${key}: ${val}\r\n`
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
|
-
if (channels.sendHeaders.hasSubscribers) {
|
|
1155
|
-
channels.sendHeaders.publish({ request, headers: header, socket })
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
|
-
/* istanbul ignore else: assertion */
|
|
1159
|
-
if (!body || bodyLength === 0) {
|
|
1160
|
-
writeBuffer(abort, null, client, request, socket, contentLength, header, expectsPayload)
|
|
1161
|
-
} else if (util.isBuffer(body)) {
|
|
1162
|
-
writeBuffer(abort, body, client, request, socket, contentLength, header, expectsPayload)
|
|
1163
|
-
} else if (util.isBlobLike(body)) {
|
|
1164
|
-
if (typeof body.stream === 'function') {
|
|
1165
|
-
writeIterable(abort, body.stream(), client, request, socket, contentLength, header, expectsPayload)
|
|
1166
|
-
} else {
|
|
1167
|
-
writeBlob(abort, body, client, request, socket, contentLength, header, expectsPayload)
|
|
1168
|
-
}
|
|
1169
|
-
} else if (util.isStream(body)) {
|
|
1170
|
-
writeStream(abort, body, client, request, socket, contentLength, header, expectsPayload)
|
|
1171
|
-
} else if (util.isIterable(body)) {
|
|
1172
|
-
writeIterable(abort, body, client, request, socket, contentLength, header, expectsPayload)
|
|
1173
|
-
} else {
|
|
1174
|
-
assert(false)
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
return true
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
/**
|
|
1181
|
-
* @param {AbortCallback} abort
|
|
1182
|
-
* @param {import('stream').Stream} body
|
|
1183
|
-
* @param {import('./client.js')} client
|
|
1184
|
-
* @param {import('../core/request.js')} request
|
|
1185
|
-
* @param {import('net').Socket} socket
|
|
1186
|
-
* @param {number} contentLength
|
|
1187
|
-
* @param {string} header
|
|
1188
|
-
* @param {boolean} expectsPayload
|
|
1189
|
-
*/
|
|
1190
|
-
function writeStream (abort, body, client, request, socket, contentLength, header, expectsPayload) {
|
|
1191
|
-
assert(contentLength !== 0 || client[kRunning] === 0, 'stream body cannot be pipelined')
|
|
1192
|
-
|
|
1193
|
-
let finished = false
|
|
1194
|
-
|
|
1195
|
-
const writer = new AsyncWriter({ abort, socket, request, contentLength, client, expectsPayload, header })
|
|
1196
|
-
|
|
1197
|
-
/**
|
|
1198
|
-
* @param {Buffer} chunk
|
|
1199
|
-
* @returns {void}
|
|
1200
|
-
*/
|
|
1201
|
-
const onData = function (chunk) {
|
|
1202
|
-
if (finished) {
|
|
1203
|
-
return
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
try {
|
|
1207
|
-
if (!writer.write(chunk) && this.pause) {
|
|
1208
|
-
this.pause()
|
|
1209
|
-
}
|
|
1210
|
-
} catch (err) {
|
|
1211
|
-
util.destroy(this, err)
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
/**
|
|
1216
|
-
* @returns {void}
|
|
1217
|
-
*/
|
|
1218
|
-
const onDrain = function () {
|
|
1219
|
-
if (finished) {
|
|
1220
|
-
return
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
if (body.resume) {
|
|
1224
|
-
body.resume()
|
|
1225
|
-
}
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1228
|
-
/**
|
|
1229
|
-
* @returns {void}
|
|
1230
|
-
*/
|
|
1231
|
-
const onClose = function () {
|
|
1232
|
-
// 'close' might be emitted *before* 'error' for
|
|
1233
|
-
// broken streams. Wait a tick to avoid this case.
|
|
1234
|
-
queueMicrotask(() => {
|
|
1235
|
-
// It's only safe to remove 'error' listener after
|
|
1236
|
-
// 'close'.
|
|
1237
|
-
body.removeListener('error', onFinished)
|
|
1238
|
-
})
|
|
1239
|
-
|
|
1240
|
-
if (!finished) {
|
|
1241
|
-
const err = new RequestAbortedError()
|
|
1242
|
-
queueMicrotask(() => onFinished(err))
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1246
|
-
/**
|
|
1247
|
-
* @param {Error} [err]
|
|
1248
|
-
* @returns
|
|
1249
|
-
*/
|
|
1250
|
-
const onFinished = function (err) {
|
|
1251
|
-
if (finished) {
|
|
1252
|
-
return
|
|
1253
|
-
}
|
|
1254
|
-
|
|
1255
|
-
finished = true
|
|
1256
|
-
|
|
1257
|
-
assert(socket.destroyed || (socket[kWriting] && client[kRunning] <= 1))
|
|
1258
|
-
|
|
1259
|
-
socket
|
|
1260
|
-
.off('drain', onDrain)
|
|
1261
|
-
.off('error', onFinished)
|
|
1262
|
-
|
|
1263
|
-
body
|
|
1264
|
-
.removeListener('data', onData)
|
|
1265
|
-
.removeListener('end', onFinished)
|
|
1266
|
-
.removeListener('close', onClose)
|
|
1267
|
-
|
|
1268
|
-
if (!err) {
|
|
1269
|
-
try {
|
|
1270
|
-
writer.end()
|
|
1271
|
-
} catch (er) {
|
|
1272
|
-
err = er
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1276
|
-
writer.destroy(err)
|
|
1277
|
-
|
|
1278
|
-
if (err && (err.code !== 'UND_ERR_INFO' || err.message !== 'reset')) {
|
|
1279
|
-
util.destroy(body, err)
|
|
1280
|
-
} else {
|
|
1281
|
-
util.destroy(body)
|
|
1282
|
-
}
|
|
1283
|
-
}
|
|
1284
|
-
|
|
1285
|
-
body
|
|
1286
|
-
.on('data', onData)
|
|
1287
|
-
.on('end', onFinished)
|
|
1288
|
-
.on('error', onFinished)
|
|
1289
|
-
.on('close', onClose)
|
|
1290
|
-
|
|
1291
|
-
if (body.resume) {
|
|
1292
|
-
body.resume()
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
|
-
socket
|
|
1296
|
-
.on('drain', onDrain)
|
|
1297
|
-
.on('error', onFinished)
|
|
1298
|
-
|
|
1299
|
-
if (body.errorEmitted ?? body.errored) {
|
|
1300
|
-
setImmediate(() => onFinished(body.errored))
|
|
1301
|
-
} else if (body.endEmitted ?? body.readableEnded) {
|
|
1302
|
-
setImmediate(() => onFinished(null))
|
|
1303
|
-
}
|
|
1304
|
-
|
|
1305
|
-
if (body.closeEmitted ?? body.closed) {
|
|
1306
|
-
setImmediate(onClose)
|
|
1307
|
-
}
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
/**
|
|
1311
|
-
* @typedef AbortCallback
|
|
1312
|
-
* @type {Function}
|
|
1313
|
-
* @param {Error} [err]
|
|
1314
|
-
* @returns {void}
|
|
1315
|
-
*/
|
|
1316
|
-
|
|
1317
|
-
/**
|
|
1318
|
-
* @param {AbortCallback} abort
|
|
1319
|
-
* @param {Uint8Array|null} body
|
|
1320
|
-
* @param {import('./client.js')} client
|
|
1321
|
-
* @param {import('../core/request.js')} request
|
|
1322
|
-
* @param {import('net').Socket} socket
|
|
1323
|
-
* @param {number} contentLength
|
|
1324
|
-
* @param {string} header
|
|
1325
|
-
* @param {boolean} expectsPayload
|
|
1326
|
-
* @returns {void}
|
|
1327
|
-
*/
|
|
1328
|
-
function writeBuffer (abort, body, client, request, socket, contentLength, header, expectsPayload) {
|
|
1329
|
-
try {
|
|
1330
|
-
if (!body) {
|
|
1331
|
-
if (contentLength === 0) {
|
|
1332
|
-
socket.write(`${header}content-length: 0\r\n\r\n`, 'latin1')
|
|
1333
|
-
} else {
|
|
1334
|
-
assert(contentLength === null, 'no body must not have content length')
|
|
1335
|
-
socket.write(`${header}\r\n`, 'latin1')
|
|
1336
|
-
}
|
|
1337
|
-
} else if (util.isBuffer(body)) {
|
|
1338
|
-
assert(contentLength === body.byteLength, 'buffer body must have content length')
|
|
1339
|
-
|
|
1340
|
-
socket.cork()
|
|
1341
|
-
socket.write(`${header}content-length: ${contentLength}\r\n\r\n`, 'latin1')
|
|
1342
|
-
socket.write(body)
|
|
1343
|
-
socket.uncork()
|
|
1344
|
-
request.onBodySent(body)
|
|
1345
|
-
|
|
1346
|
-
if (!expectsPayload && request.reset !== false) {
|
|
1347
|
-
socket[kReset] = true
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
request.onRequestSent()
|
|
1351
|
-
|
|
1352
|
-
client[kResume]()
|
|
1353
|
-
} catch (err) {
|
|
1354
|
-
abort(err)
|
|
1355
|
-
}
|
|
1356
|
-
}
|
|
1357
|
-
|
|
1358
|
-
/**
|
|
1359
|
-
* @param {AbortCallback} abort
|
|
1360
|
-
* @param {Blob} body
|
|
1361
|
-
* @param {import('./client.js')} client
|
|
1362
|
-
* @param {import('../core/request.js')} request
|
|
1363
|
-
* @param {import('net').Socket} socket
|
|
1364
|
-
* @param {number} contentLength
|
|
1365
|
-
* @param {string} header
|
|
1366
|
-
* @param {boolean} expectsPayload
|
|
1367
|
-
* @returns {Promise<void>}
|
|
1368
|
-
*/
|
|
1369
|
-
async function writeBlob (abort, body, client, request, socket, contentLength, header, expectsPayload) {
|
|
1370
|
-
assert(contentLength === body.size, 'blob body must have content length')
|
|
1371
|
-
|
|
1372
|
-
try {
|
|
1373
|
-
if (contentLength != null && contentLength !== body.size) {
|
|
1374
|
-
throw new RequestContentLengthMismatchError()
|
|
1375
|
-
}
|
|
1376
|
-
|
|
1377
|
-
const buffer = Buffer.from(await body.arrayBuffer())
|
|
1378
|
-
|
|
1379
|
-
socket.cork()
|
|
1380
|
-
socket.write(`${header}content-length: ${contentLength}\r\n\r\n`, 'latin1')
|
|
1381
|
-
socket.write(buffer)
|
|
1382
|
-
socket.uncork()
|
|
1383
|
-
|
|
1384
|
-
request.onBodySent(buffer)
|
|
1385
|
-
request.onRequestSent()
|
|
1386
|
-
|
|
1387
|
-
if (!expectsPayload && request.reset !== false) {
|
|
1388
|
-
socket[kReset] = true
|
|
1389
|
-
}
|
|
1390
|
-
|
|
1391
|
-
client[kResume]()
|
|
1392
|
-
} catch (err) {
|
|
1393
|
-
abort(err)
|
|
1394
|
-
}
|
|
1395
|
-
}
|
|
1396
|
-
|
|
1397
|
-
/**
|
|
1398
|
-
* @param {AbortCallback} abort
|
|
1399
|
-
* @param {Iterable} body
|
|
1400
|
-
* @param {import('./client.js')} client
|
|
1401
|
-
* @param {import('../core/request.js')} request
|
|
1402
|
-
* @param {import('net').Socket} socket
|
|
1403
|
-
* @param {number} contentLength
|
|
1404
|
-
* @param {string} header
|
|
1405
|
-
* @param {boolean} expectsPayload
|
|
1406
|
-
* @returns {Promise<void>}
|
|
1407
|
-
*/
|
|
1408
|
-
async function writeIterable (abort, body, client, request, socket, contentLength, header, expectsPayload) {
|
|
1409
|
-
assert(contentLength !== 0 || client[kRunning] === 0, 'iterator body cannot be pipelined')
|
|
1410
|
-
|
|
1411
|
-
let callback = null
|
|
1412
|
-
function onDrain () {
|
|
1413
|
-
if (callback) {
|
|
1414
|
-
const cb = callback
|
|
1415
|
-
callback = null
|
|
1416
|
-
cb()
|
|
1417
|
-
}
|
|
1418
|
-
}
|
|
1419
|
-
|
|
1420
|
-
const waitForDrain = () => new Promise((resolve, reject) => {
|
|
1421
|
-
assert(callback === null)
|
|
1422
|
-
|
|
1423
|
-
if (socket[kError]) {
|
|
1424
|
-
reject(socket[kError])
|
|
1425
|
-
} else {
|
|
1426
|
-
callback = resolve
|
|
1427
|
-
}
|
|
1428
|
-
})
|
|
1429
|
-
|
|
1430
|
-
socket
|
|
1431
|
-
.on('close', onDrain)
|
|
1432
|
-
.on('drain', onDrain)
|
|
1433
|
-
|
|
1434
|
-
const writer = new AsyncWriter({ abort, socket, request, contentLength, client, expectsPayload, header })
|
|
1435
|
-
try {
|
|
1436
|
-
// It's up to the user to somehow abort the async iterable.
|
|
1437
|
-
for await (const chunk of body) {
|
|
1438
|
-
if (socket[kError]) {
|
|
1439
|
-
throw socket[kError]
|
|
1440
|
-
}
|
|
1441
|
-
|
|
1442
|
-
if (!writer.write(chunk)) {
|
|
1443
|
-
await waitForDrain()
|
|
1444
|
-
}
|
|
1445
|
-
}
|
|
1446
|
-
|
|
1447
|
-
writer.end()
|
|
1448
|
-
} catch (err) {
|
|
1449
|
-
writer.destroy(err)
|
|
1450
|
-
} finally {
|
|
1451
|
-
socket
|
|
1452
|
-
.off('close', onDrain)
|
|
1453
|
-
.off('drain', onDrain)
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
class AsyncWriter {
|
|
1458
|
-
/**
|
|
1459
|
-
*
|
|
1460
|
-
* @param {object} arg
|
|
1461
|
-
* @param {AbortCallback} arg.abort
|
|
1462
|
-
* @param {import('net').Socket} arg.socket
|
|
1463
|
-
* @param {import('../core/request.js')} arg.request
|
|
1464
|
-
* @param {number} arg.contentLength
|
|
1465
|
-
* @param {import('./client.js')} arg.client
|
|
1466
|
-
* @param {boolean} arg.expectsPayload
|
|
1467
|
-
* @param {string} arg.header
|
|
1468
|
-
*/
|
|
1469
|
-
constructor ({ abort, socket, request, contentLength, client, expectsPayload, header }) {
|
|
1470
|
-
this.socket = socket
|
|
1471
|
-
this.request = request
|
|
1472
|
-
this.contentLength = contentLength
|
|
1473
|
-
this.client = client
|
|
1474
|
-
this.bytesWritten = 0
|
|
1475
|
-
this.expectsPayload = expectsPayload
|
|
1476
|
-
this.header = header
|
|
1477
|
-
this.abort = abort
|
|
1478
|
-
|
|
1479
|
-
socket[kWriting] = true
|
|
1480
|
-
}
|
|
1481
|
-
|
|
1482
|
-
/**
|
|
1483
|
-
* @param {Buffer} chunk
|
|
1484
|
-
* @returns
|
|
1485
|
-
*/
|
|
1486
|
-
write (chunk) {
|
|
1487
|
-
const { socket, request, contentLength, client, bytesWritten, expectsPayload, header } = this
|
|
1488
|
-
|
|
1489
|
-
if (socket[kError]) {
|
|
1490
|
-
throw socket[kError]
|
|
1491
|
-
}
|
|
1492
|
-
|
|
1493
|
-
if (socket.destroyed) {
|
|
1494
|
-
return false
|
|
1495
|
-
}
|
|
1496
|
-
|
|
1497
|
-
const len = Buffer.byteLength(chunk)
|
|
1498
|
-
if (!len) {
|
|
1499
|
-
return true
|
|
1500
|
-
}
|
|
1501
|
-
|
|
1502
|
-
// We should defer writing chunks.
|
|
1503
|
-
if (contentLength !== null && bytesWritten + len > contentLength) {
|
|
1504
|
-
if (client[kStrictContentLength]) {
|
|
1505
|
-
throw new RequestContentLengthMismatchError()
|
|
1506
|
-
}
|
|
1507
|
-
|
|
1508
|
-
process.emitWarning(new RequestContentLengthMismatchError())
|
|
1509
|
-
}
|
|
1510
|
-
|
|
1511
|
-
socket.cork()
|
|
1512
|
-
|
|
1513
|
-
if (bytesWritten === 0) {
|
|
1514
|
-
if (!expectsPayload && request.reset !== false) {
|
|
1515
|
-
socket[kReset] = true
|
|
1516
|
-
}
|
|
1517
|
-
|
|
1518
|
-
if (contentLength === null) {
|
|
1519
|
-
socket.write(`${header}transfer-encoding: chunked\r\n`, 'latin1')
|
|
1520
|
-
} else {
|
|
1521
|
-
socket.write(`${header}content-length: ${contentLength}\r\n\r\n`, 'latin1')
|
|
1522
|
-
}
|
|
1523
|
-
}
|
|
1524
|
-
|
|
1525
|
-
if (contentLength === null) {
|
|
1526
|
-
socket.write(`\r\n${len.toString(16)}\r\n`, 'latin1')
|
|
1527
|
-
}
|
|
1528
|
-
|
|
1529
|
-
this.bytesWritten += len
|
|
1530
|
-
|
|
1531
|
-
const ret = socket.write(chunk)
|
|
1532
|
-
|
|
1533
|
-
socket.uncork()
|
|
1534
|
-
|
|
1535
|
-
request.onBodySent(chunk)
|
|
1536
|
-
|
|
1537
|
-
if (!ret) {
|
|
1538
|
-
if (socket[kParser].timeout && socket[kParser].timeoutType === TIMEOUT_HEADERS) {
|
|
1539
|
-
// istanbul ignore else: only for jest
|
|
1540
|
-
if (socket[kParser].timeout.refresh) {
|
|
1541
|
-
socket[kParser].timeout.refresh()
|
|
1542
|
-
}
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
|
|
1546
|
-
return ret
|
|
1547
|
-
}
|
|
1548
|
-
|
|
1549
|
-
/**
|
|
1550
|
-
* @returns {void}
|
|
1551
|
-
*/
|
|
1552
|
-
end () {
|
|
1553
|
-
const { socket, contentLength, client, bytesWritten, expectsPayload, header, request } = this
|
|
1554
|
-
request.onRequestSent()
|
|
1555
|
-
|
|
1556
|
-
socket[kWriting] = false
|
|
1557
|
-
|
|
1558
|
-
if (socket[kError]) {
|
|
1559
|
-
throw socket[kError]
|
|
1560
|
-
}
|
|
1561
|
-
|
|
1562
|
-
if (socket.destroyed) {
|
|
1563
|
-
return
|
|
1564
|
-
}
|
|
1565
|
-
|
|
1566
|
-
if (bytesWritten === 0) {
|
|
1567
|
-
if (expectsPayload) {
|
|
1568
|
-
// https://tools.ietf.org/html/rfc7230#section-3.3.2
|
|
1569
|
-
// A user agent SHOULD send a Content-Length in a request message when
|
|
1570
|
-
// no Transfer-Encoding is sent and the request method defines a meaning
|
|
1571
|
-
// for an enclosed payload body.
|
|
1572
|
-
|
|
1573
|
-
socket.write(`${header}content-length: 0\r\n\r\n`, 'latin1')
|
|
1574
|
-
} else {
|
|
1575
|
-
socket.write(`${header}\r\n`, 'latin1')
|
|
1576
|
-
}
|
|
1577
|
-
} else if (contentLength === null) {
|
|
1578
|
-
socket.write('\r\n0\r\n\r\n', 'latin1')
|
|
1579
|
-
}
|
|
1580
|
-
|
|
1581
|
-
if (contentLength !== null && bytesWritten !== contentLength) {
|
|
1582
|
-
if (client[kStrictContentLength]) {
|
|
1583
|
-
throw new RequestContentLengthMismatchError()
|
|
1584
|
-
} else {
|
|
1585
|
-
process.emitWarning(new RequestContentLengthMismatchError())
|
|
1586
|
-
}
|
|
1587
|
-
}
|
|
1588
|
-
|
|
1589
|
-
if (socket[kParser].timeout && socket[kParser].timeoutType === TIMEOUT_HEADERS) {
|
|
1590
|
-
// istanbul ignore else: only for jest
|
|
1591
|
-
if (socket[kParser].timeout.refresh) {
|
|
1592
|
-
socket[kParser].timeout.refresh()
|
|
1593
|
-
}
|
|
1594
|
-
}
|
|
1595
|
-
|
|
1596
|
-
client[kResume]()
|
|
1597
|
-
}
|
|
1598
|
-
|
|
1599
|
-
/**
|
|
1600
|
-
* @param {Error} [err]
|
|
1601
|
-
* @returns {void}
|
|
1602
|
-
*/
|
|
1603
|
-
destroy (err) {
|
|
1604
|
-
const { socket, client, abort } = this
|
|
1605
|
-
|
|
1606
|
-
socket[kWriting] = false
|
|
1607
|
-
|
|
1608
|
-
if (err) {
|
|
1609
|
-
assert(client[kRunning] <= 1, 'pipeline should only contain this request')
|
|
1610
|
-
abort(err)
|
|
1611
|
-
}
|
|
1612
|
-
}
|
|
1613
|
-
}
|
|
1614
|
-
|
|
1615
|
-
module.exports = connectH1
|