@depup/undici 7.24.3-depup.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/LICENSE +21 -0
- package/README.md +25 -0
- package/changes.json +5 -0
- package/docs/docs/api/Agent.md +84 -0
- package/docs/docs/api/BalancedPool.md +99 -0
- package/docs/docs/api/CacheStorage.md +30 -0
- package/docs/docs/api/CacheStore.md +164 -0
- package/docs/docs/api/Client.md +285 -0
- package/docs/docs/api/ClientStats.md +27 -0
- package/docs/docs/api/Connector.md +115 -0
- package/docs/docs/api/ContentType.md +57 -0
- package/docs/docs/api/Cookies.md +101 -0
- package/docs/docs/api/Debug.md +62 -0
- package/docs/docs/api/DiagnosticsChannel.md +313 -0
- package/docs/docs/api/Dispatcher.md +1392 -0
- package/docs/docs/api/EnvHttpProxyAgent.md +159 -0
- package/docs/docs/api/Errors.md +49 -0
- package/docs/docs/api/EventSource.md +45 -0
- package/docs/docs/api/Fetch.md +52 -0
- package/docs/docs/api/GlobalInstallation.md +91 -0
- package/docs/docs/api/H2CClient.md +263 -0
- package/docs/docs/api/MockAgent.md +603 -0
- package/docs/docs/api/MockCallHistory.md +197 -0
- package/docs/docs/api/MockCallHistoryLog.md +43 -0
- package/docs/docs/api/MockClient.md +81 -0
- package/docs/docs/api/MockErrors.md +12 -0
- package/docs/docs/api/MockPool.md +555 -0
- package/docs/docs/api/Pool.md +84 -0
- package/docs/docs/api/PoolStats.md +35 -0
- package/docs/docs/api/ProxyAgent.md +229 -0
- package/docs/docs/api/RedirectHandler.md +96 -0
- package/docs/docs/api/RetryAgent.md +50 -0
- package/docs/docs/api/RetryHandler.md +118 -0
- package/docs/docs/api/RoundRobinPool.md +145 -0
- package/docs/docs/api/SnapshotAgent.md +616 -0
- package/docs/docs/api/Socks5ProxyAgent.md +274 -0
- package/docs/docs/api/Util.md +25 -0
- package/docs/docs/api/WebSocket.md +141 -0
- package/docs/docs/api/api-lifecycle.md +91 -0
- package/docs/docs/best-practices/client-certificate.md +64 -0
- package/docs/docs/best-practices/crawling.md +58 -0
- package/docs/docs/best-practices/mocking-request.md +190 -0
- package/docs/docs/best-practices/proxy.md +127 -0
- package/docs/docs/best-practices/undici-vs-builtin-fetch.md +137 -0
- package/docs/docs/best-practices/writing-tests.md +20 -0
- package/index-fetch.js +65 -0
- package/index.d.ts +3 -0
- package/index.js +234 -0
- package/lib/api/abort-signal.js +59 -0
- package/lib/api/api-connect.js +110 -0
- package/lib/api/api-pipeline.js +252 -0
- package/lib/api/api-request.js +214 -0
- package/lib/api/api-stream.js +209 -0
- package/lib/api/api-upgrade.js +111 -0
- package/lib/api/index.js +7 -0
- package/lib/api/readable.js +580 -0
- package/lib/cache/memory-cache-store.js +234 -0
- package/lib/cache/sqlite-cache-store.js +461 -0
- package/lib/core/connect.js +137 -0
- package/lib/core/constants.js +143 -0
- package/lib/core/diagnostics.js +225 -0
- package/lib/core/errors.js +477 -0
- package/lib/core/request.js +430 -0
- package/lib/core/socks5-client.js +407 -0
- package/lib/core/socks5-utils.js +203 -0
- package/lib/core/symbols.js +75 -0
- package/lib/core/tree.js +160 -0
- package/lib/core/util.js +972 -0
- package/lib/dispatcher/agent.js +158 -0
- package/lib/dispatcher/balanced-pool.js +219 -0
- package/lib/dispatcher/client-h1.js +1610 -0
- package/lib/dispatcher/client-h2.js +995 -0
- package/lib/dispatcher/client.js +654 -0
- package/lib/dispatcher/dispatcher-base.js +165 -0
- package/lib/dispatcher/dispatcher.js +48 -0
- package/lib/dispatcher/env-http-proxy-agent.js +146 -0
- package/lib/dispatcher/fixed-queue.js +135 -0
- package/lib/dispatcher/h2c-client.js +51 -0
- package/lib/dispatcher/pool-base.js +214 -0
- package/lib/dispatcher/pool.js +118 -0
- package/lib/dispatcher/proxy-agent.js +318 -0
- package/lib/dispatcher/retry-agent.js +35 -0
- package/lib/dispatcher/round-robin-pool.js +137 -0
- package/lib/dispatcher/socks5-proxy-agent.js +249 -0
- package/lib/encoding/index.js +33 -0
- package/lib/global.js +50 -0
- package/lib/handler/cache-handler.js +561 -0
- package/lib/handler/cache-revalidation-handler.js +124 -0
- package/lib/handler/decorator-handler.js +67 -0
- package/lib/handler/deduplication-handler.js +460 -0
- package/lib/handler/redirect-handler.js +238 -0
- package/lib/handler/retry-handler.js +394 -0
- package/lib/handler/unwrap-handler.js +100 -0
- package/lib/handler/wrap-handler.js +105 -0
- package/lib/interceptor/cache.js +495 -0
- package/lib/interceptor/decompress.js +259 -0
- package/lib/interceptor/deduplicate.js +117 -0
- package/lib/interceptor/dns.js +571 -0
- package/lib/interceptor/dump.js +112 -0
- package/lib/interceptor/redirect.js +21 -0
- package/lib/interceptor/response-error.js +95 -0
- package/lib/interceptor/retry.js +19 -0
- package/lib/llhttp/.gitkeep +0 -0
- package/lib/llhttp/constants.d.ts +195 -0
- package/lib/llhttp/constants.js +531 -0
- package/lib/llhttp/llhttp-wasm.js +15 -0
- package/lib/llhttp/llhttp_simd-wasm.js +15 -0
- package/lib/llhttp/utils.d.ts +2 -0
- package/lib/llhttp/utils.js +12 -0
- package/lib/mock/mock-agent.js +232 -0
- package/lib/mock/mock-call-history.js +248 -0
- package/lib/mock/mock-client.js +68 -0
- package/lib/mock/mock-errors.js +29 -0
- package/lib/mock/mock-interceptor.js +209 -0
- package/lib/mock/mock-pool.js +68 -0
- package/lib/mock/mock-symbols.js +31 -0
- package/lib/mock/mock-utils.js +480 -0
- package/lib/mock/pending-interceptors-formatter.js +43 -0
- package/lib/mock/snapshot-agent.js +353 -0
- package/lib/mock/snapshot-recorder.js +588 -0
- package/lib/mock/snapshot-utils.js +158 -0
- package/lib/util/cache.js +407 -0
- package/lib/util/date.js +653 -0
- package/lib/util/promise.js +28 -0
- package/lib/util/runtime-features.js +124 -0
- package/lib/util/stats.js +32 -0
- package/lib/util/timers.js +425 -0
- package/lib/web/cache/cache.js +864 -0
- package/lib/web/cache/cachestorage.js +152 -0
- package/lib/web/cache/util.js +45 -0
- package/lib/web/cookies/constants.js +12 -0
- package/lib/web/cookies/index.js +199 -0
- package/lib/web/cookies/parse.js +322 -0
- package/lib/web/cookies/util.js +282 -0
- package/lib/web/eventsource/eventsource-stream.js +399 -0
- package/lib/web/eventsource/eventsource.js +501 -0
- package/lib/web/eventsource/util.js +29 -0
- package/lib/web/fetch/LICENSE +21 -0
- package/lib/web/fetch/body.js +509 -0
- package/lib/web/fetch/constants.js +131 -0
- package/lib/web/fetch/data-url.js +596 -0
- package/lib/web/fetch/formdata-parser.js +575 -0
- package/lib/web/fetch/formdata.js +259 -0
- package/lib/web/fetch/global.js +40 -0
- package/lib/web/fetch/headers.js +719 -0
- package/lib/web/fetch/index.js +2378 -0
- package/lib/web/fetch/request.js +1115 -0
- package/lib/web/fetch/response.js +641 -0
- package/lib/web/fetch/util.js +1520 -0
- package/lib/web/infra/index.js +229 -0
- package/lib/web/subresource-integrity/Readme.md +9 -0
- package/lib/web/subresource-integrity/subresource-integrity.js +307 -0
- package/lib/web/webidl/index.js +1006 -0
- package/lib/web/websocket/connection.js +329 -0
- package/lib/web/websocket/constants.js +126 -0
- package/lib/web/websocket/events.js +331 -0
- package/lib/web/websocket/frame.js +133 -0
- package/lib/web/websocket/permessage-deflate.js +118 -0
- package/lib/web/websocket/receiver.js +450 -0
- package/lib/web/websocket/sender.js +109 -0
- package/lib/web/websocket/stream/websocketerror.js +104 -0
- package/lib/web/websocket/stream/websocketstream.js +497 -0
- package/lib/web/websocket/util.js +347 -0
- package/lib/web/websocket/websocket.js +739 -0
- package/package.json +163 -0
- package/scripts/strip-comments.js +10 -0
- package/types/README.md +6 -0
- package/types/agent.d.ts +32 -0
- package/types/api.d.ts +43 -0
- package/types/balanced-pool.d.ts +30 -0
- package/types/cache-interceptor.d.ts +179 -0
- package/types/cache.d.ts +36 -0
- package/types/client-stats.d.ts +15 -0
- package/types/client.d.ts +123 -0
- package/types/connector.d.ts +36 -0
- package/types/content-type.d.ts +21 -0
- package/types/cookies.d.ts +30 -0
- package/types/diagnostics-channel.d.ts +74 -0
- package/types/dispatcher.d.ts +279 -0
- package/types/env-http-proxy-agent.d.ts +22 -0
- package/types/errors.d.ts +177 -0
- package/types/eventsource.d.ts +66 -0
- package/types/fetch.d.ts +211 -0
- package/types/formdata.d.ts +108 -0
- package/types/global-dispatcher.d.ts +9 -0
- package/types/global-origin.d.ts +7 -0
- package/types/h2c-client.d.ts +73 -0
- package/types/handlers.d.ts +15 -0
- package/types/header.d.ts +160 -0
- package/types/index.d.ts +91 -0
- package/types/interceptors.d.ts +80 -0
- package/types/mock-agent.d.ts +68 -0
- package/types/mock-call-history.d.ts +111 -0
- package/types/mock-client.d.ts +27 -0
- package/types/mock-errors.d.ts +12 -0
- package/types/mock-interceptor.d.ts +94 -0
- package/types/mock-pool.d.ts +27 -0
- package/types/patch.d.ts +29 -0
- package/types/pool-stats.d.ts +19 -0
- package/types/pool.d.ts +41 -0
- package/types/proxy-agent.d.ts +29 -0
- package/types/readable.d.ts +68 -0
- package/types/retry-agent.d.ts +8 -0
- package/types/retry-handler.d.ts +125 -0
- package/types/round-robin-pool.d.ts +41 -0
- package/types/snapshot-agent.d.ts +109 -0
- package/types/socks5-proxy-agent.d.ts +25 -0
- package/types/util.d.ts +18 -0
- package/types/utility.d.ts +7 -0
- package/types/webidl.d.ts +347 -0
- package/types/websocket.d.ts +188 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const assert = require('node:assert')
|
|
4
|
+
const { AsyncResource } = require('node:async_hooks')
|
|
5
|
+
const { Readable } = require('./readable')
|
|
6
|
+
const { InvalidArgumentError, RequestAbortedError } = require('../core/errors')
|
|
7
|
+
const util = require('../core/util')
|
|
8
|
+
|
|
9
|
+
function noop () {}
|
|
10
|
+
|
|
11
|
+
class RequestHandler extends AsyncResource {
|
|
12
|
+
constructor (opts, callback) {
|
|
13
|
+
if (!opts || typeof opts !== 'object') {
|
|
14
|
+
throw new InvalidArgumentError('invalid opts')
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const { signal, method, opaque, body, onInfo, responseHeaders, highWaterMark } = opts
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
if (typeof callback !== 'function') {
|
|
21
|
+
throw new InvalidArgumentError('invalid callback')
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (highWaterMark && (typeof highWaterMark !== 'number' || highWaterMark < 0)) {
|
|
25
|
+
throw new InvalidArgumentError('invalid highWaterMark')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (signal && typeof signal.on !== 'function' && typeof signal.addEventListener !== 'function') {
|
|
29
|
+
throw new InvalidArgumentError('signal must be an EventEmitter or EventTarget')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (method === 'CONNECT') {
|
|
33
|
+
throw new InvalidArgumentError('invalid method')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (onInfo && typeof onInfo !== 'function') {
|
|
37
|
+
throw new InvalidArgumentError('invalid onInfo callback')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
super('UNDICI_REQUEST')
|
|
41
|
+
} catch (err) {
|
|
42
|
+
if (util.isStream(body)) {
|
|
43
|
+
util.destroy(body.on('error', noop), err)
|
|
44
|
+
}
|
|
45
|
+
throw err
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
this.method = method
|
|
49
|
+
this.responseHeaders = responseHeaders || null
|
|
50
|
+
this.opaque = opaque || null
|
|
51
|
+
this.callback = callback
|
|
52
|
+
this.res = null
|
|
53
|
+
this.abort = null
|
|
54
|
+
this.body = body
|
|
55
|
+
this.trailers = {}
|
|
56
|
+
this.context = null
|
|
57
|
+
this.onInfo = onInfo || null
|
|
58
|
+
this.highWaterMark = highWaterMark
|
|
59
|
+
this.reason = null
|
|
60
|
+
this.removeAbortListener = null
|
|
61
|
+
|
|
62
|
+
if (signal?.aborted) {
|
|
63
|
+
this.reason = signal.reason ?? new RequestAbortedError()
|
|
64
|
+
} else if (signal) {
|
|
65
|
+
this.removeAbortListener = util.addAbortListener(signal, () => {
|
|
66
|
+
this.reason = signal.reason ?? new RequestAbortedError()
|
|
67
|
+
if (this.res) {
|
|
68
|
+
util.destroy(this.res.on('error', noop), this.reason)
|
|
69
|
+
} else if (this.abort) {
|
|
70
|
+
this.abort(this.reason)
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
onConnect (abort, context) {
|
|
77
|
+
if (this.reason) {
|
|
78
|
+
abort(this.reason)
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
assert(this.callback)
|
|
83
|
+
|
|
84
|
+
this.abort = abort
|
|
85
|
+
this.context = context
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
onHeaders (statusCode, rawHeaders, resume, statusMessage) {
|
|
89
|
+
const { callback, opaque, abort, context, responseHeaders, highWaterMark } = this
|
|
90
|
+
|
|
91
|
+
const headers = responseHeaders === 'raw' ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders)
|
|
92
|
+
|
|
93
|
+
if (statusCode < 200) {
|
|
94
|
+
if (this.onInfo) {
|
|
95
|
+
this.onInfo({ statusCode, headers })
|
|
96
|
+
}
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const parsedHeaders = responseHeaders === 'raw' ? util.parseHeaders(rawHeaders) : headers
|
|
101
|
+
const contentType = parsedHeaders['content-type']
|
|
102
|
+
const contentLength = parsedHeaders['content-length']
|
|
103
|
+
const res = new Readable({
|
|
104
|
+
resume,
|
|
105
|
+
abort,
|
|
106
|
+
contentType,
|
|
107
|
+
contentLength: this.method !== 'HEAD' && contentLength
|
|
108
|
+
? Number(contentLength)
|
|
109
|
+
: null,
|
|
110
|
+
highWaterMark
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
if (this.removeAbortListener) {
|
|
114
|
+
res.on('close', this.removeAbortListener)
|
|
115
|
+
this.removeAbortListener = null
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
this.callback = null
|
|
119
|
+
this.res = res
|
|
120
|
+
if (callback !== null) {
|
|
121
|
+
try {
|
|
122
|
+
this.runInAsyncScope(callback, null, null, {
|
|
123
|
+
statusCode,
|
|
124
|
+
statusText: statusMessage,
|
|
125
|
+
headers,
|
|
126
|
+
trailers: this.trailers,
|
|
127
|
+
opaque,
|
|
128
|
+
body: res,
|
|
129
|
+
context
|
|
130
|
+
})
|
|
131
|
+
} catch (err) {
|
|
132
|
+
// If the callback throws synchronously, we need to handle it
|
|
133
|
+
// Remove reference to res to allow res being garbage collected
|
|
134
|
+
this.res = null
|
|
135
|
+
|
|
136
|
+
// Destroy the response stream
|
|
137
|
+
util.destroy(res.on('error', noop), err)
|
|
138
|
+
|
|
139
|
+
// Use queueMicrotask to re-throw the error so it reaches uncaughtException
|
|
140
|
+
queueMicrotask(() => {
|
|
141
|
+
throw err
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
onData (chunk) {
|
|
148
|
+
return this.res.push(chunk)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
onComplete (trailers) {
|
|
152
|
+
util.parseHeaders(trailers, this.trailers)
|
|
153
|
+
this.res.push(null)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
onError (err) {
|
|
157
|
+
const { res, callback, body, opaque } = this
|
|
158
|
+
|
|
159
|
+
if (callback) {
|
|
160
|
+
// TODO: Does this need queueMicrotask?
|
|
161
|
+
this.callback = null
|
|
162
|
+
queueMicrotask(() => {
|
|
163
|
+
this.runInAsyncScope(callback, null, err, { opaque })
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (res) {
|
|
168
|
+
this.res = null
|
|
169
|
+
// Ensure all queued handlers are invoked before destroying res.
|
|
170
|
+
queueMicrotask(() => {
|
|
171
|
+
util.destroy(res.on('error', noop), err)
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (body) {
|
|
176
|
+
this.body = null
|
|
177
|
+
|
|
178
|
+
if (util.isStream(body)) {
|
|
179
|
+
body.on('error', noop)
|
|
180
|
+
util.destroy(body, err)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (this.removeAbortListener) {
|
|
185
|
+
this.removeAbortListener()
|
|
186
|
+
this.removeAbortListener = null
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function request (opts, callback) {
|
|
192
|
+
if (callback === undefined) {
|
|
193
|
+
return new Promise((resolve, reject) => {
|
|
194
|
+
request.call(this, opts, (err, data) => {
|
|
195
|
+
return err ? reject(err) : resolve(data)
|
|
196
|
+
})
|
|
197
|
+
})
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
const handler = new RequestHandler(opts, callback)
|
|
202
|
+
|
|
203
|
+
this.dispatch(opts, handler)
|
|
204
|
+
} catch (err) {
|
|
205
|
+
if (typeof callback !== 'function') {
|
|
206
|
+
throw err
|
|
207
|
+
}
|
|
208
|
+
const opaque = opts?.opaque
|
|
209
|
+
queueMicrotask(() => callback(err, { opaque }))
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
module.exports = request
|
|
214
|
+
module.exports.RequestHandler = RequestHandler
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const assert = require('node:assert')
|
|
4
|
+
const { finished } = require('node:stream')
|
|
5
|
+
const { AsyncResource } = require('node:async_hooks')
|
|
6
|
+
const { InvalidArgumentError, InvalidReturnValueError } = require('../core/errors')
|
|
7
|
+
const util = require('../core/util')
|
|
8
|
+
const { addSignal, removeSignal } = require('./abort-signal')
|
|
9
|
+
|
|
10
|
+
function noop () {}
|
|
11
|
+
|
|
12
|
+
class StreamHandler extends AsyncResource {
|
|
13
|
+
constructor (opts, factory, callback) {
|
|
14
|
+
if (!opts || typeof opts !== 'object') {
|
|
15
|
+
throw new InvalidArgumentError('invalid opts')
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const { signal, method, opaque, body, onInfo, responseHeaders } = opts
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
if (typeof callback !== 'function') {
|
|
22
|
+
throw new InvalidArgumentError('invalid callback')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (typeof factory !== 'function') {
|
|
26
|
+
throw new InvalidArgumentError('invalid factory')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (signal && typeof signal.on !== 'function' && typeof signal.addEventListener !== 'function') {
|
|
30
|
+
throw new InvalidArgumentError('signal must be an EventEmitter or EventTarget')
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (method === 'CONNECT') {
|
|
34
|
+
throw new InvalidArgumentError('invalid method')
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (onInfo && typeof onInfo !== 'function') {
|
|
38
|
+
throw new InvalidArgumentError('invalid onInfo callback')
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
super('UNDICI_STREAM')
|
|
42
|
+
} catch (err) {
|
|
43
|
+
if (util.isStream(body)) {
|
|
44
|
+
util.destroy(body.on('error', noop), err)
|
|
45
|
+
}
|
|
46
|
+
throw err
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
this.responseHeaders = responseHeaders || null
|
|
50
|
+
this.opaque = opaque || null
|
|
51
|
+
this.factory = factory
|
|
52
|
+
this.callback = callback
|
|
53
|
+
this.res = null
|
|
54
|
+
this.abort = null
|
|
55
|
+
this.context = null
|
|
56
|
+
this.trailers = null
|
|
57
|
+
this.body = body
|
|
58
|
+
this.onInfo = onInfo || null
|
|
59
|
+
|
|
60
|
+
if (util.isStream(body)) {
|
|
61
|
+
body.on('error', (err) => {
|
|
62
|
+
this.onError(err)
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
addSignal(this, signal)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
onConnect (abort, context) {
|
|
70
|
+
if (this.reason) {
|
|
71
|
+
abort(this.reason)
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
assert(this.callback)
|
|
76
|
+
|
|
77
|
+
this.abort = abort
|
|
78
|
+
this.context = context
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
onHeaders (statusCode, rawHeaders, resume, statusMessage) {
|
|
82
|
+
const { factory, opaque, context, responseHeaders } = this
|
|
83
|
+
|
|
84
|
+
const headers = responseHeaders === 'raw' ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders)
|
|
85
|
+
|
|
86
|
+
if (statusCode < 200) {
|
|
87
|
+
if (this.onInfo) {
|
|
88
|
+
this.onInfo({ statusCode, headers })
|
|
89
|
+
}
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
this.factory = null
|
|
94
|
+
|
|
95
|
+
if (factory === null) {
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const res = this.runInAsyncScope(factory, null, {
|
|
100
|
+
statusCode,
|
|
101
|
+
headers,
|
|
102
|
+
opaque,
|
|
103
|
+
context
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
if (
|
|
107
|
+
!res ||
|
|
108
|
+
typeof res.write !== 'function' ||
|
|
109
|
+
typeof res.end !== 'function' ||
|
|
110
|
+
typeof res.on !== 'function'
|
|
111
|
+
) {
|
|
112
|
+
throw new InvalidReturnValueError('expected Writable')
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// TODO: Avoid finished. It registers an unnecessary amount of listeners.
|
|
116
|
+
finished(res, { readable: false }, (err) => {
|
|
117
|
+
const { callback, res, opaque, trailers, abort } = this
|
|
118
|
+
|
|
119
|
+
this.res = null
|
|
120
|
+
if (err || !res?.readable) {
|
|
121
|
+
util.destroy(res, err)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
this.callback = null
|
|
125
|
+
this.runInAsyncScope(callback, null, err || null, { opaque, trailers })
|
|
126
|
+
|
|
127
|
+
if (err) {
|
|
128
|
+
abort()
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
res.on('drain', resume)
|
|
133
|
+
|
|
134
|
+
this.res = res
|
|
135
|
+
|
|
136
|
+
const needDrain = res.writableNeedDrain !== undefined
|
|
137
|
+
? res.writableNeedDrain
|
|
138
|
+
: res._writableState?.needDrain
|
|
139
|
+
|
|
140
|
+
return needDrain !== true
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
onData (chunk) {
|
|
144
|
+
const { res } = this
|
|
145
|
+
|
|
146
|
+
return res ? res.write(chunk) : true
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
onComplete (trailers) {
|
|
150
|
+
const { res } = this
|
|
151
|
+
|
|
152
|
+
removeSignal(this)
|
|
153
|
+
|
|
154
|
+
if (!res) {
|
|
155
|
+
return
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
this.trailers = util.parseHeaders(trailers)
|
|
159
|
+
|
|
160
|
+
res.end()
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
onError (err) {
|
|
164
|
+
const { res, callback, opaque, body } = this
|
|
165
|
+
|
|
166
|
+
removeSignal(this)
|
|
167
|
+
|
|
168
|
+
this.factory = null
|
|
169
|
+
|
|
170
|
+
if (res) {
|
|
171
|
+
this.res = null
|
|
172
|
+
util.destroy(res, err)
|
|
173
|
+
} else if (callback) {
|
|
174
|
+
this.callback = null
|
|
175
|
+
queueMicrotask(() => {
|
|
176
|
+
this.runInAsyncScope(callback, null, err, { opaque })
|
|
177
|
+
})
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (body) {
|
|
181
|
+
this.body = null
|
|
182
|
+
util.destroy(body, err)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function stream (opts, factory, callback) {
|
|
188
|
+
if (callback === undefined) {
|
|
189
|
+
return new Promise((resolve, reject) => {
|
|
190
|
+
stream.call(this, opts, factory, (err, data) => {
|
|
191
|
+
return err ? reject(err) : resolve(data)
|
|
192
|
+
})
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
const handler = new StreamHandler(opts, factory, callback)
|
|
198
|
+
|
|
199
|
+
this.dispatch(opts, handler)
|
|
200
|
+
} catch (err) {
|
|
201
|
+
if (typeof callback !== 'function') {
|
|
202
|
+
throw err
|
|
203
|
+
}
|
|
204
|
+
const opaque = opts?.opaque
|
|
205
|
+
queueMicrotask(() => callback(err, { opaque }))
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
module.exports = stream
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { InvalidArgumentError, SocketError } = require('../core/errors')
|
|
4
|
+
const { AsyncResource } = require('node:async_hooks')
|
|
5
|
+
const assert = require('node:assert')
|
|
6
|
+
const util = require('../core/util')
|
|
7
|
+
const { kHTTP2Stream } = require('../core/symbols')
|
|
8
|
+
const { addSignal, removeSignal } = require('./abort-signal')
|
|
9
|
+
|
|
10
|
+
class UpgradeHandler extends AsyncResource {
|
|
11
|
+
constructor (opts, callback) {
|
|
12
|
+
if (!opts || typeof opts !== 'object') {
|
|
13
|
+
throw new InvalidArgumentError('invalid opts')
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (typeof callback !== 'function') {
|
|
17
|
+
throw new InvalidArgumentError('invalid callback')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const { signal, opaque, responseHeaders } = opts
|
|
21
|
+
|
|
22
|
+
if (signal && typeof signal.on !== 'function' && typeof signal.addEventListener !== 'function') {
|
|
23
|
+
throw new InvalidArgumentError('signal must be an EventEmitter or EventTarget')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
super('UNDICI_UPGRADE')
|
|
27
|
+
|
|
28
|
+
this.responseHeaders = responseHeaders || null
|
|
29
|
+
this.opaque = opaque || null
|
|
30
|
+
this.callback = callback
|
|
31
|
+
this.abort = null
|
|
32
|
+
this.context = null
|
|
33
|
+
|
|
34
|
+
addSignal(this, signal)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
onConnect (abort, context) {
|
|
38
|
+
if (this.reason) {
|
|
39
|
+
abort(this.reason)
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
assert(this.callback)
|
|
44
|
+
|
|
45
|
+
this.abort = abort
|
|
46
|
+
this.context = null
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
onHeaders () {
|
|
50
|
+
throw new SocketError('bad upgrade', null)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
onUpgrade (statusCode, rawHeaders, socket) {
|
|
54
|
+
assert(socket[kHTTP2Stream] === true ? statusCode === 200 : statusCode === 101)
|
|
55
|
+
|
|
56
|
+
const { callback, opaque, context } = this
|
|
57
|
+
|
|
58
|
+
removeSignal(this)
|
|
59
|
+
|
|
60
|
+
this.callback = null
|
|
61
|
+
const headers = this.responseHeaders === 'raw' ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders)
|
|
62
|
+
this.runInAsyncScope(callback, null, null, {
|
|
63
|
+
headers,
|
|
64
|
+
socket,
|
|
65
|
+
opaque,
|
|
66
|
+
context
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
onError (err) {
|
|
71
|
+
const { callback, opaque } = this
|
|
72
|
+
|
|
73
|
+
removeSignal(this)
|
|
74
|
+
|
|
75
|
+
if (callback) {
|
|
76
|
+
this.callback = null
|
|
77
|
+
queueMicrotask(() => {
|
|
78
|
+
this.runInAsyncScope(callback, null, err, { opaque })
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function upgrade (opts, callback) {
|
|
85
|
+
if (callback === undefined) {
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
upgrade.call(this, opts, (err, data) => {
|
|
88
|
+
return err ? reject(err) : resolve(data)
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const upgradeHandler = new UpgradeHandler(opts, callback)
|
|
95
|
+
const upgradeOpts = {
|
|
96
|
+
...opts,
|
|
97
|
+
method: opts.method || 'GET',
|
|
98
|
+
upgrade: opts.protocol || 'Websocket'
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
this.dispatch(upgradeOpts, upgradeHandler)
|
|
102
|
+
} catch (err) {
|
|
103
|
+
if (typeof callback !== 'function') {
|
|
104
|
+
throw err
|
|
105
|
+
}
|
|
106
|
+
const opaque = opts?.opaque
|
|
107
|
+
queueMicrotask(() => callback(err, { opaque }))
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
module.exports = upgrade
|
package/lib/api/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
module.exports.request = require('./api-request')
|
|
4
|
+
module.exports.stream = require('./api-stream')
|
|
5
|
+
module.exports.pipeline = require('./api-pipeline')
|
|
6
|
+
module.exports.upgrade = require('./api-upgrade')
|
|
7
|
+
module.exports.connect = require('./api-connect')
|