api-connect.js 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. 'use strict'
  2. const { InvalidArgumentError, RequestAbortedError, SocketError } = require('../core/errors')
  3. const { AsyncResource } = require('async_hooks')
  4. const util = require('../core/util')
  5. const { addSignal, removeSignal } = require('./abort-signal')
  6. class ConnectHandler extends AsyncResource {
  7. constructor (opts, callback) {
  8. if (!opts || typeof opts !== 'object') {
  9. throw new InvalidArgumentError('invalid opts')
  10. }
  11. if (typeof callback !== 'function') {
  12. throw new InvalidArgumentError('invalid callback')
  13. }
  14. const { signal, opaque, responseHeaders } = opts
  15. if (signal && typeof signal.on !== 'function' && typeof signal.addEventListener !== 'function') {
  16. throw new InvalidArgumentError('signal must be an EventEmitter or EventTarget')
  17. }
  18. super('UNDICI_CONNECT')
  19. this.opaque = opaque || null
  20. this.responseHeaders = responseHeaders || null
  21. this.callback = callback
  22. this.abort = null
  23. addSignal(this, signal)
  24. }
  25. onConnect (abort, context) {
  26. if (!this.callback) {
  27. throw new RequestAbortedError()
  28. }
  29. this.abort = abort
  30. this.context = context
  31. }
  32. onHeaders () {
  33. throw new SocketError('bad connect', null)
  34. }
  35. onUpgrade (statusCode, rawHeaders, socket) {
  36. const { callback, opaque, context } = this
  37. removeSignal(this)
  38. this.callback = null
  39. const headers = this.responseHeaders === 'raw' ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders)
  40. this.runInAsyncScope(callback, null, null, {
  41. statusCode,
  42. headers,
  43. socket,
  44. opaque,
  45. context
  46. })
  47. }
  48. onError (err) {
  49. const { callback, opaque } = this
  50. removeSignal(this)
  51. if (callback) {
  52. this.callback = null
  53. queueMicrotask(() => {
  54. this.runInAsyncScope(callback, null, err, { opaque })
  55. })
  56. }
  57. }
  58. }
  59. function connect (opts, callback) {
  60. if (callback === undefined) {
  61. return new Promise((resolve, reject) => {
  62. connect.call(this, opts, (err, data) => {
  63. return err ? reject(err) : resolve(data)
  64. })
  65. })
  66. }
  67. try {
  68. const connectHandler = new ConnectHandler(opts, callback)
  69. this.dispatch({ ...opts, method: 'CONNECT' }, connectHandler)
  70. } catch (err) {
  71. if (typeof callback !== 'function') {
  72. throw err
  73. }
  74. const opaque = opts && opts.opaque
  75. queueMicrotask(() => callback(err, { opaque }))
  76. }
  77. }
  78. module.exports = connect