codekingpro/portable-devtools
114k
1'use strict'
2
3const assert = require('node:assert')
4const { AsyncResource } = require('node:async_hooks')
5const { InvalidArgumentError, SocketError } = require('../core/errors')
6const util = require('../core/util')
7const { addSignal, removeSignal } = require('./abort-signal')
8
9class ConnectHandler extends AsyncResource {
10 constructor (opts, callback) {
11 if (!opts || typeof opts !== 'object') {
12 throw new InvalidArgumentError('invalid opts')
13 }
14
15 if (typeof callback !== 'function') {
16 throw new InvalidArgumentError('invalid callback')
17 }
18
19 const { signal, opaque, responseHeaders } = opts
20
21 if (signal && typeof signal.on !== 'function' && typeof signal.addEventListener !== 'function') {
22 throw new InvalidArgumentError('signal must be an EventEmitter or EventTarget')
23 }
24
25 super('UNDICI_CONNECT')
26
27 this.opaque = opaque || null
28 this.responseHeaders = responseHeaders || null
29 this.callback = callback
30 this.abort = null
31
32 addSignal(this, signal)
33 }
34
35 onConnect (abort, context) {
36 if (this.reason) {
37 abort(this.reason)
38 return
39 }
40
41 assert(this.callback)
42
43 this.abort = abort
44 this.context = context
45 }
46
47 onHeaders () {
48 throw new SocketError('bad connect', null)
49 }
50
51 onUpgrade (statusCode, rawHeaders, socket) {
52 const { callback, opaque, context } = this
53
54 removeSignal(this)
55
56 this.callback = null
57
58 let headers = rawHeaders
59 // Indicates is an HTTP2Session
60 if (headers != null) {
61 headers = this.responseHeaders === 'raw' ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders)
62 }
63
64 this.runInAsyncScope(callback, null, null, {
65 statusCode,
66 headers,
67 socket,
68 opaque,
69 context
70 })
71 }
72
73 onError (err) {
74 const { callback, opaque } = this
75
76 removeSignal(this)
77
78 if (callback) {
79 this.callback = null
80 queueMicrotask(() => {
81 this.runInAsyncScope(callback, null, err, { opaque })
82 })
83 }
84 }
85}
86
87function connect (opts, callback) {
88 if (callback === undefined) {
89 return new Promise((resolve, reject) => {
90 connect.call(this, opts, (err, data) => {
91 return err ? reject(err) : resolve(data)
92 })
93 })
94 }
95
96 try {
97 const connectHandler = new ConnectHandler(opts, callback)
98 this.dispatch({ ...opts, method: 'CONNECT' }, connectHandler)
99 } catch (err) {
100 if (typeof callback !== 'function') {
101 throw err
102 }
103 const opaque = opts?.opaque
104 queueMicrotask(() => callback(err, { opaque }))
105 }
106}
107
108module.exports = connect
109 