11cb0ef41Sopenharmony_ci'use strict'
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst { InvalidArgumentError, RequestAbortedError, SocketError } = require('../core/errors')
41cb0ef41Sopenharmony_ciconst { AsyncResource } = require('async_hooks')
51cb0ef41Sopenharmony_ciconst util = require('../core/util')
61cb0ef41Sopenharmony_ciconst { addSignal, removeSignal } = require('./abort-signal')
71cb0ef41Sopenharmony_ciconst assert = require('assert')
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ciclass UpgradeHandler extends AsyncResource {
101cb0ef41Sopenharmony_ci  constructor (opts, callback) {
111cb0ef41Sopenharmony_ci    if (!opts || typeof opts !== 'object') {
121cb0ef41Sopenharmony_ci      throw new InvalidArgumentError('invalid opts')
131cb0ef41Sopenharmony_ci    }
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ci    if (typeof callback !== 'function') {
161cb0ef41Sopenharmony_ci      throw new InvalidArgumentError('invalid callback')
171cb0ef41Sopenharmony_ci    }
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ci    const { signal, opaque, responseHeaders } = opts
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ci    if (signal && typeof signal.on !== 'function' && typeof signal.addEventListener !== 'function') {
221cb0ef41Sopenharmony_ci      throw new InvalidArgumentError('signal must be an EventEmitter or EventTarget')
231cb0ef41Sopenharmony_ci    }
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci    super('UNDICI_UPGRADE')
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ci    this.responseHeaders = responseHeaders || null
281cb0ef41Sopenharmony_ci    this.opaque = opaque || null
291cb0ef41Sopenharmony_ci    this.callback = callback
301cb0ef41Sopenharmony_ci    this.abort = null
311cb0ef41Sopenharmony_ci    this.context = null
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci    addSignal(this, signal)
341cb0ef41Sopenharmony_ci  }
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ci  onConnect (abort, context) {
371cb0ef41Sopenharmony_ci    if (!this.callback) {
381cb0ef41Sopenharmony_ci      throw new RequestAbortedError()
391cb0ef41Sopenharmony_ci    }
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci    this.abort = abort
421cb0ef41Sopenharmony_ci    this.context = null
431cb0ef41Sopenharmony_ci  }
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci  onHeaders () {
461cb0ef41Sopenharmony_ci    throw new SocketError('bad upgrade', null)
471cb0ef41Sopenharmony_ci  }
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci  onUpgrade (statusCode, rawHeaders, socket) {
501cb0ef41Sopenharmony_ci    const { callback, opaque, context } = this
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci    assert.strictEqual(statusCode, 101)
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci    removeSignal(this)
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci    this.callback = null
571cb0ef41Sopenharmony_ci    const headers = this.responseHeaders === 'raw' ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders)
581cb0ef41Sopenharmony_ci    this.runInAsyncScope(callback, null, null, {
591cb0ef41Sopenharmony_ci      headers,
601cb0ef41Sopenharmony_ci      socket,
611cb0ef41Sopenharmony_ci      opaque,
621cb0ef41Sopenharmony_ci      context
631cb0ef41Sopenharmony_ci    })
641cb0ef41Sopenharmony_ci  }
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci  onError (err) {
671cb0ef41Sopenharmony_ci    const { callback, opaque } = this
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci    removeSignal(this)
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci    if (callback) {
721cb0ef41Sopenharmony_ci      this.callback = null
731cb0ef41Sopenharmony_ci      queueMicrotask(() => {
741cb0ef41Sopenharmony_ci        this.runInAsyncScope(callback, null, err, { opaque })
751cb0ef41Sopenharmony_ci      })
761cb0ef41Sopenharmony_ci    }
771cb0ef41Sopenharmony_ci  }
781cb0ef41Sopenharmony_ci}
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_cifunction upgrade (opts, callback) {
811cb0ef41Sopenharmony_ci  if (callback === undefined) {
821cb0ef41Sopenharmony_ci    return new Promise((resolve, reject) => {
831cb0ef41Sopenharmony_ci      upgrade.call(this, opts, (err, data) => {
841cb0ef41Sopenharmony_ci        return err ? reject(err) : resolve(data)
851cb0ef41Sopenharmony_ci      })
861cb0ef41Sopenharmony_ci    })
871cb0ef41Sopenharmony_ci  }
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci  try {
901cb0ef41Sopenharmony_ci    const upgradeHandler = new UpgradeHandler(opts, callback)
911cb0ef41Sopenharmony_ci    this.dispatch({
921cb0ef41Sopenharmony_ci      ...opts,
931cb0ef41Sopenharmony_ci      method: opts.method || 'GET',
941cb0ef41Sopenharmony_ci      upgrade: opts.protocol || 'Websocket'
951cb0ef41Sopenharmony_ci    }, upgradeHandler)
961cb0ef41Sopenharmony_ci  } catch (err) {
971cb0ef41Sopenharmony_ci    if (typeof callback !== 'function') {
981cb0ef41Sopenharmony_ci      throw err
991cb0ef41Sopenharmony_ci    }
1001cb0ef41Sopenharmony_ci    const opaque = opts && opts.opaque
1011cb0ef41Sopenharmony_ci    queueMicrotask(() => callback(err, { opaque }))
1021cb0ef41Sopenharmony_ci  }
1031cb0ef41Sopenharmony_ci}
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_cimodule.exports = upgrade
106