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