aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/node_modules/undici/lib/api
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/undici/lib/api')
-rw-r--r--node_modules/undici/lib/api/abort-signal.js7
-rw-r--r--node_modules/undici/lib/api/api-connect.js14
-rw-r--r--node_modules/undici/lib/api/api-pipeline.js18
-rw-r--r--node_modules/undici/lib/api/api-request.js84
-rw-r--r--node_modules/undici/lib/api/api-stream.js22
-rw-r--r--node_modules/undici/lib/api/api-upgrade.js19
-rw-r--r--node_modules/undici/lib/api/readable.js229
-rw-r--r--node_modules/undici/lib/api/util.js97
8 files changed, 323 insertions, 167 deletions
diff --git a/node_modules/undici/lib/api/abort-signal.js b/node_modules/undici/lib/api/abort-signal.js
index 2985c1e..2afe747 100644
--- a/node_modules/undici/lib/api/abort-signal.js
+++ b/node_modules/undici/lib/api/abort-signal.js
@@ -6,13 +6,16 @@ const kSignal = Symbol('kSignal')
function abort (self) {
if (self.abort) {
- self.abort()
+ self.abort(self[kSignal]?.reason)
} else {
- self.onError(new RequestAbortedError())
+ self.reason = self[kSignal]?.reason ?? new RequestAbortedError()
}
+ removeSignal(self)
}
function addSignal (self, signal) {
+ self.reason = null
+
self[kSignal] = null
self[kListener] = null
diff --git a/node_modules/undici/lib/api/api-connect.js b/node_modules/undici/lib/api/api-connect.js
index fd2b6ad..f9dbbf6 100644
--- a/node_modules/undici/lib/api/api-connect.js
+++ b/node_modules/undici/lib/api/api-connect.js
@@ -1,7 +1,8 @@
'use strict'
-const { AsyncResource } = require('async_hooks')
-const { InvalidArgumentError, RequestAbortedError, SocketError } = require('../core/errors')
+const assert = require('node:assert')
+const { AsyncResource } = require('node:async_hooks')
+const { InvalidArgumentError, SocketError } = require('../core/errors')
const util = require('../core/util')
const { addSignal, removeSignal } = require('./abort-signal')
@@ -32,10 +33,13 @@ class ConnectHandler extends AsyncResource {
}
onConnect (abort, context) {
- if (!this.callback) {
- throw new RequestAbortedError()
+ if (this.reason) {
+ abort(this.reason)
+ return
}
+ assert(this.callback)
+
this.abort = abort
this.context = context
}
@@ -96,7 +100,7 @@ function connect (opts, callback) {
if (typeof callback !== 'function') {
throw err
}
- const opaque = opts && opts.opaque
+ const opaque = opts?.opaque
queueMicrotask(() => callback(err, { opaque }))
}
}
diff --git a/node_modules/undici/lib/api/api-pipeline.js b/node_modules/undici/lib/api/api-pipeline.js
index af4a180..e64b329 100644
--- a/node_modules/undici/lib/api/api-pipeline.js
+++ b/node_modules/undici/lib/api/api-pipeline.js
@@ -4,16 +4,16 @@ const {
Readable,
Duplex,
PassThrough
-} = require('stream')
+} = require('node:stream')
const {
InvalidArgumentError,
InvalidReturnValueError,
RequestAbortedError
} = require('../core/errors')
const util = require('../core/util')
-const { AsyncResource } = require('async_hooks')
+const { AsyncResource } = require('node:async_hooks')
const { addSignal, removeSignal } = require('./abort-signal')
-const assert = require('assert')
+const assert = require('node:assert')
const kResume = Symbol('resume')
@@ -100,7 +100,7 @@ class PipelineHandler extends AsyncResource {
read: () => {
const { body } = this
- if (body && body.resume) {
+ if (body?.resume) {
body.resume()
}
},
@@ -147,12 +147,14 @@ class PipelineHandler extends AsyncResource {
onConnect (abort, context) {
const { ret, res } = this
- assert(!res, 'pipeline cannot be retried')
-
- if (ret.destroyed) {
- throw new RequestAbortedError()
+ if (this.reason) {
+ abort(this.reason)
+ return
}
+ assert(!res, 'pipeline cannot be retried')
+ assert(!ret.destroyed)
+
this.abort = abort
this.context = context
}
diff --git a/node_modules/undici/lib/api/api-request.js b/node_modules/undici/lib/api/api-request.js
index d4281ce..be17d62 100644
--- a/node_modules/undici/lib/api/api-request.js
+++ b/node_modules/undici/lib/api/api-request.js
@@ -1,14 +1,11 @@
'use strict'
-const Readable = require('./readable')
-const {
- InvalidArgumentError,
- RequestAbortedError
-} = require('../core/errors')
+const assert = require('node:assert')
+const { Readable } = require('./readable')
+const { InvalidArgumentError, RequestAbortedError } = require('../core/errors')
const util = require('../core/util')
const { getResolveErrorBodyCallback } = require('./util')
-const { AsyncResource } = require('async_hooks')
-const { addSignal, removeSignal } = require('./abort-signal')
+const { AsyncResource } = require('node:async_hooks')
class RequestHandler extends AsyncResource {
constructor (opts, callback) {
@@ -47,6 +44,7 @@ class RequestHandler extends AsyncResource {
throw err
}
+ this.method = method
this.responseHeaders = responseHeaders || null
this.opaque = opaque || null
this.callback = callback
@@ -58,6 +56,9 @@ class RequestHandler extends AsyncResource {
this.onInfo = onInfo || null
this.throwOnError = throwOnError
this.highWaterMark = highWaterMark
+ this.signal = signal
+ this.reason = null
+ this.removeAbortListener = null
if (util.isStream(body)) {
body.on('error', (err) => {
@@ -65,14 +66,36 @@ class RequestHandler extends AsyncResource {
})
}
- addSignal(this, signal)
+ if (this.signal) {
+ if (this.signal.aborted) {
+ this.reason = this.signal.reason ?? new RequestAbortedError()
+ } else {
+ this.removeAbortListener = util.addAbortListener(this.signal, () => {
+ this.reason = this.signal.reason ?? new RequestAbortedError()
+ if (this.res) {
+ util.destroy(this.res.on('error', util.nop), this.reason)
+ } else if (this.abort) {
+ this.abort(this.reason)
+ }
+
+ if (this.removeAbortListener) {
+ this.res?.off('close', this.removeAbortListener)
+ this.removeAbortListener()
+ this.removeAbortListener = null
+ }
+ })
+ }
+ }
}
onConnect (abort, context) {
- if (!this.callback) {
- throw new RequestAbortedError()
+ if (this.reason) {
+ abort(this.reason)
+ return
}
+ assert(this.callback)
+
this.abort = abort
this.context = context
}
@@ -91,14 +114,27 @@ class RequestHandler extends AsyncResource {
const parsedHeaders = responseHeaders === 'raw' ? util.parseHeaders(rawHeaders) : headers
const contentType = parsedHeaders['content-type']
- const body = new Readable({ resume, abort, contentType, highWaterMark })
+ 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.callback = null
- this.res = body
+ this.res = res
if (callback !== null) {
if (this.throwOnError && statusCode >= 400) {
this.runInAsyncScope(getResolveErrorBodyCallback, null,
- { callback, body, contentType, statusCode, statusMessage, headers }
+ { callback, body: res, contentType, statusCode, statusMessage, headers }
)
} else {
this.runInAsyncScope(callback, null, null, {
@@ -106,7 +142,7 @@ class RequestHandler extends AsyncResource {
headers,
trailers: this.trailers,
opaque,
- body,
+ body: res,
context
})
}
@@ -114,25 +150,17 @@ class RequestHandler extends AsyncResource {
}
onData (chunk) {
- const { res } = this
- return res.push(chunk)
+ return this.res.push(chunk)
}
onComplete (trailers) {
- const { res } = this
-
- removeSignal(this)
-
util.parseHeaders(trailers, this.trailers)
-
- res.push(null)
+ this.res.push(null)
}
onError (err) {
const { res, callback, body, opaque } = this
- removeSignal(this)
-
if (callback) {
// TODO: Does this need queueMicrotask?
this.callback = null
@@ -153,6 +181,12 @@ class RequestHandler extends AsyncResource {
this.body = null
util.destroy(body, err)
}
+
+ if (this.removeAbortListener) {
+ res?.off('close', this.removeAbortListener)
+ this.removeAbortListener()
+ this.removeAbortListener = null
+ }
}
}
@@ -171,7 +205,7 @@ function request (opts, callback) {
if (typeof callback !== 'function') {
throw err
}
- const opaque = opts && opts.opaque
+ const opaque = opts?.opaque
queueMicrotask(() => callback(err, { opaque }))
}
}
diff --git a/node_modules/undici/lib/api/api-stream.js b/node_modules/undici/lib/api/api-stream.js
index c571a6f..fba2266 100644
--- a/node_modules/undici/lib/api/api-stream.js
+++ b/node_modules/undici/lib/api/api-stream.js
@@ -1,14 +1,11 @@
'use strict'
-const { finished, PassThrough } = require('stream')
-const {
- InvalidArgumentError,
- InvalidReturnValueError,
- RequestAbortedError
-} = require('../core/errors')
+const assert = require('node:assert')
+const { finished, PassThrough } = require('node:stream')
+const { InvalidArgumentError, InvalidReturnValueError } = require('../core/errors')
const util = require('../core/util')
const { getResolveErrorBodyCallback } = require('./util')
-const { AsyncResource } = require('async_hooks')
+const { AsyncResource } = require('node:async_hooks')
const { addSignal, removeSignal } = require('./abort-signal')
class StreamHandler extends AsyncResource {
@@ -70,10 +67,13 @@ class StreamHandler extends AsyncResource {
}
onConnect (abort, context) {
- if (!this.callback) {
- throw new RequestAbortedError()
+ if (this.reason) {
+ abort(this.reason)
+ return
}
+ assert(this.callback)
+
this.abort = abort
this.context = context
}
@@ -148,7 +148,7 @@ class StreamHandler extends AsyncResource {
const needDrain = res.writableNeedDrain !== undefined
? res.writableNeedDrain
- : res._writableState && res._writableState.needDrain
+ : res._writableState?.needDrain
return needDrain !== true
}
@@ -212,7 +212,7 @@ function stream (opts, factory, callback) {
if (typeof callback !== 'function') {
throw err
}
- const opaque = opts && opts.opaque
+ const opaque = opts?.opaque
queueMicrotask(() => callback(err, { opaque }))
}
}
diff --git a/node_modules/undici/lib/api/api-upgrade.js b/node_modules/undici/lib/api/api-upgrade.js
index ef783e8..7effcf2 100644
--- a/node_modules/undici/lib/api/api-upgrade.js
+++ b/node_modules/undici/lib/api/api-upgrade.js
@@ -1,10 +1,10 @@
'use strict'
-const { InvalidArgumentError, RequestAbortedError, SocketError } = require('../core/errors')
-const { AsyncResource } = require('async_hooks')
+const { InvalidArgumentError, SocketError } = require('../core/errors')
+const { AsyncResource } = require('node:async_hooks')
const util = require('../core/util')
const { addSignal, removeSignal } = require('./abort-signal')
-const assert = require('assert')
+const assert = require('node:assert')
class UpgradeHandler extends AsyncResource {
constructor (opts, callback) {
@@ -34,10 +34,13 @@ class UpgradeHandler extends AsyncResource {
}
onConnect (abort, context) {
- if (!this.callback) {
- throw new RequestAbortedError()
+ if (this.reason) {
+ abort(this.reason)
+ return
}
+ assert(this.callback)
+
this.abort = abort
this.context = null
}
@@ -47,9 +50,9 @@ class UpgradeHandler extends AsyncResource {
}
onUpgrade (statusCode, rawHeaders, socket) {
- const { callback, opaque, context } = this
+ assert(statusCode === 101)
- assert.strictEqual(statusCode, 101)
+ const { callback, opaque, context } = this
removeSignal(this)
@@ -97,7 +100,7 @@ function upgrade (opts, callback) {
if (typeof callback !== 'function') {
throw err
}
- const opaque = opts && opts.opaque
+ const opaque = opts?.opaque
queueMicrotask(() => callback(err, { opaque }))
}
}
diff --git a/node_modules/undici/lib/api/readable.js b/node_modules/undici/lib/api/readable.js
index 5269dfa..47fbf3e 100644
--- a/node_modules/undici/lib/api/readable.js
+++ b/node_modules/undici/lib/api/readable.js
@@ -2,27 +2,27 @@
'use strict'
-const assert = require('assert')
-const { Readable } = require('stream')
-const { RequestAbortedError, NotSupportedError, InvalidArgumentError } = require('../core/errors')
+const assert = require('node:assert')
+const { Readable } = require('node:stream')
+const { RequestAbortedError, NotSupportedError, InvalidArgumentError, AbortError } = require('../core/errors')
const util = require('../core/util')
-const { ReadableStreamFrom, toUSVString } = require('../core/util')
-
-let Blob
+const { ReadableStreamFrom } = require('../core/util')
const kConsume = Symbol('kConsume')
const kReading = Symbol('kReading')
const kBody = Symbol('kBody')
-const kAbort = Symbol('abort')
+const kAbort = Symbol('kAbort')
const kContentType = Symbol('kContentType')
+const kContentLength = Symbol('kContentLength')
const noop = () => {}
-module.exports = class BodyReadable extends Readable {
+class BodyReadable extends Readable {
constructor ({
resume,
abort,
contentType = '',
+ contentLength,
highWaterMark = 64 * 1024 // Same as nodejs fs streams.
}) {
super({
@@ -37,6 +37,7 @@ module.exports = class BodyReadable extends Readable {
this[kConsume] = null
this[kBody] = null
this[kContentType] = contentType
+ this[kContentLength] = contentLength
// Is stream being consumed through Readable API?
// This is an optimization so that we avoid checking
@@ -46,11 +47,6 @@ module.exports = class BodyReadable extends Readable {
}
destroy (err) {
- if (this.destroyed) {
- // Node < 16
- return this
- }
-
if (!err && !this._readableState.endEmitted) {
err = new RequestAbortedError()
}
@@ -62,15 +58,18 @@ module.exports = class BodyReadable extends Readable {
return super.destroy(err)
}
- emit (ev, ...args) {
- if (ev === 'data') {
- // Node < 16.7
- this._readableState.dataEmitted = true
- } else if (ev === 'error') {
- // Node < 16
- this._readableState.errorEmitted = true
+ _destroy (err, callback) {
+ // Workaround for Node "bug". If the stream is destroyed in same
+ // tick as it is created, then a user who is waiting for a
+ // promise (i.e micro tick) for installing a 'error' listener will
+ // never get a chance and will always encounter an unhandled exception.
+ if (!this[kReading]) {
+ setImmediate(() => {
+ callback(err)
+ })
+ } else {
+ callback(err)
}
- return super.emit(ev, ...args)
}
on (ev, ...args) {
@@ -100,7 +99,7 @@ module.exports = class BodyReadable extends Readable {
}
push (chunk) {
- if (this[kConsume] && chunk !== null && this.readableLength === 0) {
+ if (this[kConsume] && chunk !== null) {
consumePush(this[kConsume], chunk)
return this[kReading] ? super.push(chunk) : true
}
@@ -122,6 +121,11 @@ module.exports = class BodyReadable extends Readable {
return consume(this, 'blob')
}
+ // https://fetch.spec.whatwg.org/#dom-body-bytes
+ async bytes () {
+ return consume(this, 'bytes')
+ }
+
// https://fetch.spec.whatwg.org/#dom-body-arraybuffer
async arrayBuffer () {
return consume(this, 'arrayBuffer')
@@ -151,37 +155,35 @@ module.exports = class BodyReadable extends Readable {
return this[kBody]
}
- dump (opts) {
- let limit = opts && Number.isFinite(opts.limit) ? opts.limit : 262144
- const signal = opts && opts.signal
+ async dump (opts) {
+ let limit = Number.isFinite(opts?.limit) ? opts.limit : 128 * 1024
+ const signal = opts?.signal
- if (signal) {
- try {
- if (typeof signal !== 'object' || !('aborted' in signal)) {
- throw new InvalidArgumentError('signal must be an AbortSignal')
- }
- util.throwIfAborted(signal)
- } catch (err) {
- return Promise.reject(err)
- }
+ if (signal != null && (typeof signal !== 'object' || !('aborted' in signal))) {
+ throw new InvalidArgumentError('signal must be an AbortSignal')
}
- if (this.closed) {
- return Promise.resolve(null)
+ signal?.throwIfAborted()
+
+ if (this._readableState.closeEmitted) {
+ return null
}
- return new Promise((resolve, reject) => {
- const signalListenerCleanup = signal
- ? util.addAbortListener(signal, () => {
- this.destroy()
- })
- : noop
+ return await new Promise((resolve, reject) => {
+ if (this[kContentLength] > limit) {
+ this.destroy(new AbortError())
+ }
+
+ const onAbort = () => {
+ this.destroy(signal.reason ?? new AbortError())
+ }
+ signal?.addEventListener('abort', onAbort)
this
.on('close', function () {
- signalListenerCleanup()
- if (signal && signal.aborted) {
- reject(signal.reason || Object.assign(new Error('The operation was aborted'), { name: 'AbortError' }))
+ signal?.removeEventListener('abort', onAbort)
+ if (signal?.aborted) {
+ reject(signal.reason ?? new AbortError())
} else {
resolve(null)
}
@@ -210,33 +212,46 @@ function isUnusable (self) {
}
async function consume (stream, type) {
- if (isUnusable(stream)) {
- throw new TypeError('unusable')
- }
-
assert(!stream[kConsume])
return new Promise((resolve, reject) => {
- stream[kConsume] = {
- type,
- stream,
- resolve,
- reject,
- length: 0,
- body: []
- }
-
- stream
- .on('error', function (err) {
- consumeFinish(this[kConsume], err)
- })
- .on('close', function () {
- if (this[kConsume].body !== null) {
- consumeFinish(this[kConsume], new RequestAbortedError())
+ if (isUnusable(stream)) {
+ const rState = stream._readableState
+ if (rState.destroyed && rState.closeEmitted === false) {
+ stream
+ .on('error', err => {
+ reject(err)
+ })
+ .on('close', () => {
+ reject(new TypeError('unusable'))
+ })
+ } else {
+ reject(rState.errored ?? new TypeError('unusable'))
+ }
+ } else {
+ queueMicrotask(() => {
+ stream[kConsume] = {
+ type,
+ stream,
+ resolve,
+ reject,
+ length: 0,
+ body: []
}
- })
- process.nextTick(consumeStart, stream[kConsume])
+ stream
+ .on('error', function (err) {
+ consumeFinish(this[kConsume], err)
+ })
+ .on('close', function () {
+ if (this[kConsume].body !== null) {
+ consumeFinish(this[kConsume], new RequestAbortedError())
+ }
+ })
+
+ consumeStart(stream[kConsume])
+ })
+ }
})
}
@@ -247,8 +262,16 @@ function consumeStart (consume) {
const { _readableState: state } = consume.stream
- for (const chunk of state.buffer) {
- consumePush(consume, chunk)
+ if (state.bufferIndex) {
+ const start = state.bufferIndex
+ const end = state.buffer.length
+ for (let n = start; n < end; n++) {
+ consumePush(consume, state.buffer[n])
+ }
+ } else {
+ for (const chunk of state.buffer) {
+ consumePush(consume, chunk)
+ }
}
if (state.endEmitted) {
@@ -266,29 +289,67 @@ function consumeStart (consume) {
}
}
+/**
+ * @param {Buffer[]} chunks
+ * @param {number} length
+ */
+function chunksDecode (chunks, length) {
+ if (chunks.length === 0 || length === 0) {
+ return ''
+ }
+ const buffer = chunks.length === 1 ? chunks[0] : Buffer.concat(chunks, length)
+ const bufferLength = buffer.length
+
+ // Skip BOM.
+ const start =
+ bufferLength > 2 &&
+ buffer[0] === 0xef &&
+ buffer[1] === 0xbb &&
+ buffer[2] === 0xbf
+ ? 3
+ : 0
+ return buffer.utf8Slice(start, bufferLength)
+}
+
+/**
+ * @param {Buffer[]} chunks
+ * @param {number} length
+ * @returns {Uint8Array}
+ */
+function chunksConcat (chunks, length) {
+ if (chunks.length === 0 || length === 0) {
+ return new Uint8Array(0)
+ }
+ if (chunks.length === 1) {
+ // fast-path
+ return new Uint8Array(chunks[0])
+ }
+ const buffer = new Uint8Array(Buffer.allocUnsafeSlow(length).buffer)
+
+ let offset = 0
+ for (let i = 0; i < chunks.length; ++i) {
+ const chunk = chunks[i]
+ buffer.set(chunk, offset)
+ offset += chunk.length
+ }
+
+ return buffer
+}
+
function consumeEnd (consume) {
const { type, body, resolve, stream, length } = consume
try {
if (type === 'text') {
- resolve(toUSVString(Buffer.concat(body)))
+ resolve(chunksDecode(body, length))
} else if (type === 'json') {
- resolve(JSON.parse(Buffer.concat(body)))
+ resolve(JSON.parse(chunksDecode(body, length)))
} else if (type === 'arrayBuffer') {
- const dst = new Uint8Array(length)
-
- let pos = 0
- for (const buf of body) {
- dst.set(buf, pos)
- pos += buf.byteLength
- }
-
- resolve(dst.buffer)
+ resolve(chunksConcat(body, length).buffer)
} else if (type === 'blob') {
- if (!Blob) {
- Blob = require('buffer').Blob
- }
resolve(new Blob(body, { type: stream[kContentType] }))
+ } else if (type === 'bytes') {
+ resolve(chunksConcat(body, length))
}
consumeFinish(consume)
@@ -320,3 +381,5 @@ function consumeFinish (consume, err) {
consume.length = 0
consume.body = null
}
+
+module.exports = { Readable: BodyReadable, chunksDecode }
diff --git a/node_modules/undici/lib/api/util.js b/node_modules/undici/lib/api/util.js
index bffd702..2f983bf 100644
--- a/node_modules/undici/lib/api/util.js
+++ b/node_modules/undici/lib/api/util.js
@@ -1,46 +1,93 @@
-const assert = require('assert')
+const assert = require('node:assert')
const {
ResponseStatusCodeError
} = require('../core/errors')
-const { toUSVString } = require('../core/util')
+
+const { chunksDecode } = require('./readable')
+const CHUNK_LIMIT = 128 * 1024
async function getResolveErrorBodyCallback ({ callback, body, contentType, statusCode, statusMessage, headers }) {
assert(body)
let chunks = []
- let limit = 0
+ let length = 0
- for await (const chunk of body) {
- chunks.push(chunk)
- limit += chunk.length
- if (limit > 128 * 1024) {
- chunks = null
- break
+ try {
+ for await (const chunk of body) {
+ chunks.push(chunk)
+ length += chunk.length
+ if (length > CHUNK_LIMIT) {
+ chunks = []
+ length = 0
+ break
+ }
}
+ } catch {
+ chunks = []
+ length = 0
+ // Do nothing....
}
- if (statusCode === 204 || !contentType || !chunks) {
- process.nextTick(callback, new ResponseStatusCodeError(`Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`, statusCode, headers))
+ const message = `Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`
+
+ if (statusCode === 204 || !contentType || !length) {
+ queueMicrotask(() => callback(new ResponseStatusCodeError(message, statusCode, headers)))
return
}
- try {
- if (contentType.startsWith('application/json')) {
- const payload = JSON.parse(toUSVString(Buffer.concat(chunks)))
- process.nextTick(callback, new ResponseStatusCodeError(`Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`, statusCode, headers, payload))
- return
- }
+ const stackTraceLimit = Error.stackTraceLimit
+ Error.stackTraceLimit = 0
+ let payload
- if (contentType.startsWith('text/')) {
- const payload = toUSVString(Buffer.concat(chunks))
- process.nextTick(callback, new ResponseStatusCodeError(`Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`, statusCode, headers, payload))
- return
+ try {
+ if (isContentTypeApplicationJson(contentType)) {
+ payload = JSON.parse(chunksDecode(chunks, length))
+ } else if (isContentTypeText(contentType)) {
+ payload = chunksDecode(chunks, length)
}
- } catch (err) {
- // Process in a fallback if error
+ } catch {
+ // process in a callback to avoid throwing in the microtask queue
+ } finally {
+ Error.stackTraceLimit = stackTraceLimit
}
+ queueMicrotask(() => callback(new ResponseStatusCodeError(message, statusCode, headers, payload)))
+}
- process.nextTick(callback, new ResponseStatusCodeError(`Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ''}`, statusCode, headers))
+const isContentTypeApplicationJson = (contentType) => {
+ return (
+ contentType.length > 15 &&
+ contentType[11] === '/' &&
+ contentType[0] === 'a' &&
+ contentType[1] === 'p' &&
+ contentType[2] === 'p' &&
+ contentType[3] === 'l' &&
+ contentType[4] === 'i' &&
+ contentType[5] === 'c' &&
+ contentType[6] === 'a' &&
+ contentType[7] === 't' &&
+ contentType[8] === 'i' &&
+ contentType[9] === 'o' &&
+ contentType[10] === 'n' &&
+ contentType[12] === 'j' &&
+ contentType[13] === 's' &&
+ contentType[14] === 'o' &&
+ contentType[15] === 'n'
+ )
}
-module.exports = { getResolveErrorBodyCallback }
+const isContentTypeText = (contentType) => {
+ return (
+ contentType.length > 4 &&
+ contentType[4] === '/' &&
+ contentType[0] === 't' &&
+ contentType[1] === 'e' &&
+ contentType[2] === 'x' &&
+ contentType[3] === 't'
+ )
+}
+
+module.exports = {
+ getResolveErrorBodyCallback,
+ isContentTypeApplicationJson,
+ isContentTypeText
+}