aboutsummaryrefslogtreecommitdiffstats
path: root/vanilla/node_modules/undici/lib/api/api-request.js
diff options
context:
space:
mode:
authorAdam Mathes <adam@adammathes.com>2026-02-13 21:34:48 -0800
committerAdam Mathes <adam@adammathes.com>2026-02-13 21:34:48 -0800
commit76cb9c2a39d477a64824a985ade40507e3bbade1 (patch)
tree41e997aa9c6f538d3a136af61dae9424db2005a9 /vanilla/node_modules/undici/lib/api/api-request.js
parent819a39a21ac992b1393244a4c283bbb125208c69 (diff)
downloadneko-76cb9c2a39d477a64824a985ade40507e3bbade1.tar.gz
neko-76cb9c2a39d477a64824a985ade40507e3bbade1.tar.bz2
neko-76cb9c2a39d477a64824a985ade40507e3bbade1.zip
feat(vanilla): add testing infrastructure and tests (NK-wjnczv)
Diffstat (limited to 'vanilla/node_modules/undici/lib/api/api-request.js')
-rw-r--r--vanilla/node_modules/undici/lib/api/api-request.js214
1 files changed, 214 insertions, 0 deletions
diff --git a/vanilla/node_modules/undici/lib/api/api-request.js b/vanilla/node_modules/undici/lib/api/api-request.js
new file mode 100644
index 0000000..f6d15f7
--- /dev/null
+++ b/vanilla/node_modules/undici/lib/api/api-request.js
@@ -0,0 +1,214 @@
+'use strict'
+
+const assert = require('node:assert')
+const { AsyncResource } = require('node:async_hooks')
+const { Readable } = require('./readable')
+const { InvalidArgumentError, RequestAbortedError } = require('../core/errors')
+const util = require('../core/util')
+
+function noop () {}
+
+class RequestHandler extends AsyncResource {
+ constructor (opts, callback) {
+ if (!opts || typeof opts !== 'object') {
+ throw new InvalidArgumentError('invalid opts')
+ }
+
+ const { signal, method, opaque, body, onInfo, responseHeaders, highWaterMark } = opts
+
+ try {
+ if (typeof callback !== 'function') {
+ throw new InvalidArgumentError('invalid callback')
+ }
+
+ if (highWaterMark && (typeof highWaterMark !== 'number' || highWaterMark < 0)) {
+ throw new InvalidArgumentError('invalid highWaterMark')
+ }
+
+ if (signal && typeof signal.on !== 'function' && typeof signal.addEventListener !== 'function') {
+ throw new InvalidArgumentError('signal must be an EventEmitter or EventTarget')
+ }
+
+ if (method === 'CONNECT') {
+ throw new InvalidArgumentError('invalid method')
+ }
+
+ if (onInfo && typeof onInfo !== 'function') {
+ throw new InvalidArgumentError('invalid onInfo callback')
+ }
+
+ super('UNDICI_REQUEST')
+ } catch (err) {
+ if (util.isStream(body)) {
+ util.destroy(body.on('error', noop), err)
+ }
+ throw err
+ }
+
+ this.method = method
+ this.responseHeaders = responseHeaders || null
+ this.opaque = opaque || null
+ this.callback = callback
+ this.res = null
+ this.abort = null
+ this.body = body
+ this.trailers = {}
+ this.context = null
+ this.onInfo = onInfo || null
+ this.highWaterMark = highWaterMark
+ this.reason = null
+ this.removeAbortListener = null
+
+ if (signal?.aborted) {
+ this.reason = signal.reason ?? new RequestAbortedError()
+ } else if (signal) {
+ this.removeAbortListener = util.addAbortListener(signal, () => {
+ this.reason = signal.reason ?? new RequestAbortedError()
+ if (this.res) {
+ util.destroy(this.res.on('error', noop), this.reason)
+ } else if (this.abort) {
+ this.abort(this.reason)
+ }
+ })
+ }
+ }
+
+ onConnect (abort, context) {
+ if (this.reason) {
+ abort(this.reason)
+ return
+ }
+
+ assert(this.callback)
+
+ this.abort = abort
+ this.context = context
+ }
+
+ onHeaders (statusCode, rawHeaders, resume, statusMessage) {
+ const { callback, opaque, abort, context, responseHeaders, highWaterMark } = this
+
+ const headers = responseHeaders === 'raw' ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders)
+
+ if (statusCode < 200) {
+ if (this.onInfo) {
+ this.onInfo({ statusCode, headers })
+ }
+ return
+ }
+
+ const parsedHeaders = responseHeaders === 'raw' ? util.parseHeaders(rawHeaders) : headers
+ const contentType = parsedHeaders['content-type']
+ const contentLength = parsedHeaders['content-length']
+ const res = new Readable({
+ resume,
+ abort,
+ contentType,
+ contentLength: this.method !== 'HEAD' && contentLength
+ ? Number(contentLength)
+ : null,
+ highWaterMark
+ })
+
+ if (this.removeAbortListener) {
+ res.on('close', this.removeAbortListener)
+ this.removeAbortListener = null
+ }
+
+ this.callback = null
+ this.res = res
+ if (callback !== null) {
+ try {
+ this.runInAsyncScope(callback, null, null, {
+ statusCode,
+ statusText: statusMessage,
+ headers,
+ trailers: this.trailers,
+ opaque,
+ body: res,
+ context
+ })
+ } catch (err) {
+ // If the callback throws synchronously, we need to handle it
+ // Remove reference to res to allow res being garbage collected
+ this.res = null
+
+ // Destroy the response stream
+ util.destroy(res.on('error', noop), err)
+
+ // Use queueMicrotask to re-throw the error so it reaches uncaughtException
+ queueMicrotask(() => {
+ throw err
+ })
+ }
+ }
+ }
+
+ onData (chunk) {
+ return this.res.push(chunk)
+ }
+
+ onComplete (trailers) {
+ util.parseHeaders(trailers, this.trailers)
+ this.res.push(null)
+ }
+
+ onError (err) {
+ const { res, callback, body, opaque } = this
+
+ if (callback) {
+ // TODO: Does this need queueMicrotask?
+ this.callback = null
+ queueMicrotask(() => {
+ this.runInAsyncScope(callback, null, err, { opaque })
+ })
+ }
+
+ if (res) {
+ this.res = null
+ // Ensure all queued handlers are invoked before destroying res.
+ queueMicrotask(() => {
+ util.destroy(res.on('error', noop), err)
+ })
+ }
+
+ if (body) {
+ this.body = null
+
+ if (util.isStream(body)) {
+ body.on('error', noop)
+ util.destroy(body, err)
+ }
+ }
+
+ if (this.removeAbortListener) {
+ this.removeAbortListener()
+ this.removeAbortListener = null
+ }
+ }
+}
+
+function request (opts, callback) {
+ if (callback === undefined) {
+ return new Promise((resolve, reject) => {
+ request.call(this, opts, (err, data) => {
+ return err ? reject(err) : resolve(data)
+ })
+ })
+ }
+
+ try {
+ const handler = new RequestHandler(opts, callback)
+
+ this.dispatch(opts, handler)
+ } catch (err) {
+ if (typeof callback !== 'function') {
+ throw err
+ }
+ const opaque = opts?.opaque
+ queueMicrotask(() => callback(err, { opaque }))
+ }
+}
+
+module.exports = request
+module.exports.RequestHandler = RequestHandler