11cb0ef41Sopenharmony_ci'use strict' 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciconst Readable = require('./readable') 41cb0ef41Sopenharmony_ciconst { 51cb0ef41Sopenharmony_ci InvalidArgumentError, 61cb0ef41Sopenharmony_ci RequestAbortedError 71cb0ef41Sopenharmony_ci} = require('../core/errors') 81cb0ef41Sopenharmony_ciconst util = require('../core/util') 91cb0ef41Sopenharmony_ciconst { getResolveErrorBodyCallback } = require('./util') 101cb0ef41Sopenharmony_ciconst { AsyncResource } = require('async_hooks') 111cb0ef41Sopenharmony_ciconst { addSignal, removeSignal } = require('./abort-signal') 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_ciclass RequestHandler extends AsyncResource { 141cb0ef41Sopenharmony_ci constructor (opts, callback) { 151cb0ef41Sopenharmony_ci if (!opts || typeof opts !== 'object') { 161cb0ef41Sopenharmony_ci throw new InvalidArgumentError('invalid opts') 171cb0ef41Sopenharmony_ci } 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ci const { signal, method, opaque, body, onInfo, responseHeaders, throwOnError, highWaterMark } = opts 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_ci try { 221cb0ef41Sopenharmony_ci if (typeof callback !== 'function') { 231cb0ef41Sopenharmony_ci throw new InvalidArgumentError('invalid callback') 241cb0ef41Sopenharmony_ci } 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci if (highWaterMark && (typeof highWaterMark !== 'number' || highWaterMark < 0)) { 271cb0ef41Sopenharmony_ci throw new InvalidArgumentError('invalid highWaterMark') 281cb0ef41Sopenharmony_ci } 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_ci if (signal && typeof signal.on !== 'function' && typeof signal.addEventListener !== 'function') { 311cb0ef41Sopenharmony_ci throw new InvalidArgumentError('signal must be an EventEmitter or EventTarget') 321cb0ef41Sopenharmony_ci } 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ci if (method === 'CONNECT') { 351cb0ef41Sopenharmony_ci throw new InvalidArgumentError('invalid method') 361cb0ef41Sopenharmony_ci } 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ci if (onInfo && typeof onInfo !== 'function') { 391cb0ef41Sopenharmony_ci throw new InvalidArgumentError('invalid onInfo callback') 401cb0ef41Sopenharmony_ci } 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ci super('UNDICI_REQUEST') 431cb0ef41Sopenharmony_ci } catch (err) { 441cb0ef41Sopenharmony_ci if (util.isStream(body)) { 451cb0ef41Sopenharmony_ci util.destroy(body.on('error', util.nop), err) 461cb0ef41Sopenharmony_ci } 471cb0ef41Sopenharmony_ci throw err 481cb0ef41Sopenharmony_ci } 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci this.responseHeaders = responseHeaders || null 511cb0ef41Sopenharmony_ci this.opaque = opaque || null 521cb0ef41Sopenharmony_ci this.callback = callback 531cb0ef41Sopenharmony_ci this.res = null 541cb0ef41Sopenharmony_ci this.abort = null 551cb0ef41Sopenharmony_ci this.body = body 561cb0ef41Sopenharmony_ci this.trailers = {} 571cb0ef41Sopenharmony_ci this.context = null 581cb0ef41Sopenharmony_ci this.onInfo = onInfo || null 591cb0ef41Sopenharmony_ci this.throwOnError = throwOnError 601cb0ef41Sopenharmony_ci this.highWaterMark = highWaterMark 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_ci if (util.isStream(body)) { 631cb0ef41Sopenharmony_ci body.on('error', (err) => { 641cb0ef41Sopenharmony_ci this.onError(err) 651cb0ef41Sopenharmony_ci }) 661cb0ef41Sopenharmony_ci } 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ci addSignal(this, signal) 691cb0ef41Sopenharmony_ci } 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_ci onConnect (abort, context) { 721cb0ef41Sopenharmony_ci if (!this.callback) { 731cb0ef41Sopenharmony_ci throw new RequestAbortedError() 741cb0ef41Sopenharmony_ci } 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ci this.abort = abort 771cb0ef41Sopenharmony_ci this.context = context 781cb0ef41Sopenharmony_ci } 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_ci onHeaders (statusCode, rawHeaders, resume, statusMessage) { 811cb0ef41Sopenharmony_ci const { callback, opaque, abort, context, responseHeaders, highWaterMark } = this 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci const headers = responseHeaders === 'raw' ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders) 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_ci if (statusCode < 200) { 861cb0ef41Sopenharmony_ci if (this.onInfo) { 871cb0ef41Sopenharmony_ci this.onInfo({ statusCode, headers }) 881cb0ef41Sopenharmony_ci } 891cb0ef41Sopenharmony_ci return 901cb0ef41Sopenharmony_ci } 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci const parsedHeaders = responseHeaders === 'raw' ? util.parseHeaders(rawHeaders) : headers 931cb0ef41Sopenharmony_ci const contentType = parsedHeaders['content-type'] 941cb0ef41Sopenharmony_ci const body = new Readable({ resume, abort, contentType, highWaterMark }) 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci this.callback = null 971cb0ef41Sopenharmony_ci this.res = body 981cb0ef41Sopenharmony_ci if (callback !== null) { 991cb0ef41Sopenharmony_ci if (this.throwOnError && statusCode >= 400) { 1001cb0ef41Sopenharmony_ci this.runInAsyncScope(getResolveErrorBodyCallback, null, 1011cb0ef41Sopenharmony_ci { callback, body, contentType, statusCode, statusMessage, headers } 1021cb0ef41Sopenharmony_ci ) 1031cb0ef41Sopenharmony_ci } else { 1041cb0ef41Sopenharmony_ci this.runInAsyncScope(callback, null, null, { 1051cb0ef41Sopenharmony_ci statusCode, 1061cb0ef41Sopenharmony_ci headers, 1071cb0ef41Sopenharmony_ci trailers: this.trailers, 1081cb0ef41Sopenharmony_ci opaque, 1091cb0ef41Sopenharmony_ci body, 1101cb0ef41Sopenharmony_ci context 1111cb0ef41Sopenharmony_ci }) 1121cb0ef41Sopenharmony_ci } 1131cb0ef41Sopenharmony_ci } 1141cb0ef41Sopenharmony_ci } 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ci onData (chunk) { 1171cb0ef41Sopenharmony_ci const { res } = this 1181cb0ef41Sopenharmony_ci return res.push(chunk) 1191cb0ef41Sopenharmony_ci } 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_ci onComplete (trailers) { 1221cb0ef41Sopenharmony_ci const { res } = this 1231cb0ef41Sopenharmony_ci 1241cb0ef41Sopenharmony_ci removeSignal(this) 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci util.parseHeaders(trailers, this.trailers) 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ci res.push(null) 1291cb0ef41Sopenharmony_ci } 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ci onError (err) { 1321cb0ef41Sopenharmony_ci const { res, callback, body, opaque } = this 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ci removeSignal(this) 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_ci if (callback) { 1371cb0ef41Sopenharmony_ci // TODO: Does this need queueMicrotask? 1381cb0ef41Sopenharmony_ci this.callback = null 1391cb0ef41Sopenharmony_ci queueMicrotask(() => { 1401cb0ef41Sopenharmony_ci this.runInAsyncScope(callback, null, err, { opaque }) 1411cb0ef41Sopenharmony_ci }) 1421cb0ef41Sopenharmony_ci } 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_ci if (res) { 1451cb0ef41Sopenharmony_ci this.res = null 1461cb0ef41Sopenharmony_ci // Ensure all queued handlers are invoked before destroying res. 1471cb0ef41Sopenharmony_ci queueMicrotask(() => { 1481cb0ef41Sopenharmony_ci util.destroy(res, err) 1491cb0ef41Sopenharmony_ci }) 1501cb0ef41Sopenharmony_ci } 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_ci if (body) { 1531cb0ef41Sopenharmony_ci this.body = null 1541cb0ef41Sopenharmony_ci util.destroy(body, err) 1551cb0ef41Sopenharmony_ci } 1561cb0ef41Sopenharmony_ci } 1571cb0ef41Sopenharmony_ci} 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_cifunction request (opts, callback) { 1601cb0ef41Sopenharmony_ci if (callback === undefined) { 1611cb0ef41Sopenharmony_ci return new Promise((resolve, reject) => { 1621cb0ef41Sopenharmony_ci request.call(this, opts, (err, data) => { 1631cb0ef41Sopenharmony_ci return err ? reject(err) : resolve(data) 1641cb0ef41Sopenharmony_ci }) 1651cb0ef41Sopenharmony_ci }) 1661cb0ef41Sopenharmony_ci } 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_ci try { 1691cb0ef41Sopenharmony_ci this.dispatch(opts, new RequestHandler(opts, callback)) 1701cb0ef41Sopenharmony_ci } catch (err) { 1711cb0ef41Sopenharmony_ci if (typeof callback !== 'function') { 1721cb0ef41Sopenharmony_ci throw err 1731cb0ef41Sopenharmony_ci } 1741cb0ef41Sopenharmony_ci const opaque = opts && opts.opaque 1751cb0ef41Sopenharmony_ci queueMicrotask(() => callback(err, { opaque })) 1761cb0ef41Sopenharmony_ci } 1771cb0ef41Sopenharmony_ci} 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_cimodule.exports = request 1801cb0ef41Sopenharmony_cimodule.exports.RequestHandler = RequestHandler 181