Skip to content

Commit e8c3aba

Browse files
authored
http2: extract listenHandlers and one bugfix (#3722)
* fix: restructure client-h2 * extract onHttp2SessionClose and rename onHTTP2GoAway to onHttp2SesssionGoAway * fix function header * extract functions * extract onSocketClose
1 parent 1bc83ea commit e8c3aba

File tree

1 file changed

+75
-60
lines changed

1 file changed

+75
-60
lines changed

lib/dispatcher/client-h2.js

+75-60
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ const {
2626
kHTTP2Session,
2727
kResume,
2828
kSize,
29-
kHTTPContext
29+
kHTTPContext,
30+
kClosed
3031
} = require('../core/symbols.js')
3132

3233
const kOpenStreams = Symbol('open streams')
@@ -93,82 +94,37 @@ async function connectH2 (client, socket) {
9394
session[kOpenStreams] = 0
9495
session[kClient] = client
9596
session[kSocket] = socket
97+
session[kHTTP2Session] = null
9698

9799
util.addListener(session, 'error', onHttp2SessionError)
98100
util.addListener(session, 'frameError', onHttp2FrameError)
99101
util.addListener(session, 'end', onHttp2SessionEnd)
100-
util.addListener(session, 'goaway', onHTTP2GoAway)
101-
util.addListener(session, 'close', function () {
102-
const { [kClient]: client } = this
103-
const { [kSocket]: socket } = client
104-
105-
const err = this[kSocket][kError] || this[kError] || new SocketError('closed', util.getSocketInfo(socket))
106-
107-
client[kHTTP2Session] = null
108-
109-
if (client.destroyed) {
110-
assert(client[kPending] === 0)
111-
112-
// Fail entire queue.
113-
const requests = client[kQueue].splice(client[kRunningIdx])
114-
for (let i = 0; i < requests.length; i++) {
115-
const request = requests[i]
116-
util.errorRequest(client, request, err)
117-
}
118-
}
119-
})
102+
util.addListener(session, 'goaway', onHttp2SessionGoAway)
103+
util.addListener(session, 'close', onHttp2SessionClose)
120104

121105
session.unref()
122106

123107
client[kHTTP2Session] = session
124108
socket[kHTTP2Session] = session
125109

126-
util.addListener(socket, 'error', function (err) {
127-
assert(err.code !== 'ERR_TLS_CERT_ALTNAME_INVALID')
128-
129-
this[kError] = err
130-
131-
this[kClient][kOnError](err)
132-
})
133-
134-
util.addListener(socket, 'end', function () {
135-
util.destroy(this, new SocketError('other side closed', util.getSocketInfo(this)))
136-
})
137-
138-
util.addListener(socket, 'close', function () {
139-
const err = this[kError] || new SocketError('closed', util.getSocketInfo(this))
140-
141-
client[kSocket] = null
110+
util.addListener(socket, 'error', onHttp2SocketError)
111+
util.addListener(socket, 'end', onHttp2SocketEnd)
112+
util.addListener(socket, 'close', onHttp2SocketClose)
142113

143-
if (this[kHTTP2Session] != null) {
144-
this[kHTTP2Session].destroy(err)
145-
}
146-
147-
client[kPendingIdx] = client[kRunningIdx]
148-
149-
assert(client[kRunning] === 0)
150-
151-
client.emit('disconnect', client[kUrl], [client], err)
152-
153-
client[kResume]()
154-
})
155-
156-
let closed = false
157-
socket.on('close', () => {
158-
closed = true
159-
})
114+
socket[kClosed] = false
115+
socket.on('close', onSocketClose)
160116

161117
return {
162118
version: 'h2',
163119
defaultPipelining: Infinity,
164-
write (...args) {
165-
return writeH2(client, ...args)
120+
write (request) {
121+
return writeH2(client, request)
166122
},
167123
resume () {
168124
resumeH2(client)
169125
},
170126
destroy (err, callback) {
171-
if (closed) {
127+
if (socket[kClosed]) {
172128
queueMicrotask(callback)
173129
} else {
174130
// Destroying the socket will trigger the session close
@@ -223,16 +179,19 @@ function onHttp2SessionEnd () {
223179
* This is the root cause of #3011
224180
* We need to handle GOAWAY frames properly, and trigger the session close
225181
* along with the socket right away
182+
*
183+
* @this {import('http2').ClientHttp2Session}
184+
* @param {number} errorCode
226185
*/
227-
function onHTTP2GoAway (code) {
186+
function onHttp2SessionGoAway (errorCode) {
228187
// We cannot recover, so best to close the session and the socket
229-
const err = this[kError] || new SocketError(`HTTP/2: "GOAWAY" frame received with code ${code}`, util.getSocketInfo(this))
188+
const err = this[kError] || new SocketError(`HTTP/2: "GOAWAY" frame received with code ${errorCode}`, util.getSocketInfo(this[kSocket]))
230189
const client = this[kClient]
231190

232191
client[kSocket] = null
233192
client[kHTTPContext] = null
234193

235-
if (this[kHTTP2Session] != null) {
194+
if (this[kHTTP2Session] !== null) {
236195
this[kHTTP2Session].destroy(err)
237196
this[kHTTP2Session] = null
238197
}
@@ -253,6 +212,62 @@ function onHTTP2GoAway (code) {
253212
client[kResume]()
254213
}
255214

215+
function onHttp2SessionClose () {
216+
const { [kClient]: client } = this
217+
const { [kSocket]: socket } = client
218+
219+
const err = this[kSocket][kError] || this[kError] || new SocketError('closed', util.getSocketInfo(socket))
220+
221+
client[kHTTP2Session] = null
222+
223+
if (client.destroyed) {
224+
assert(client[kPending] === 0)
225+
226+
// Fail entire queue.
227+
const requests = client[kQueue].splice(client[kRunningIdx])
228+
for (let i = 0; i < requests.length; i++) {
229+
const request = requests[i]
230+
util.errorRequest(client, request, err)
231+
}
232+
}
233+
}
234+
235+
function onHttp2SocketClose () {
236+
const err = this[kError] || new SocketError('closed', util.getSocketInfo(this))
237+
238+
const client = this[kHTTP2Session][kClient]
239+
240+
client[kSocket] = null
241+
242+
if (this[kHTTP2Session] !== null) {
243+
this[kHTTP2Session].destroy(err)
244+
}
245+
246+
client[kPendingIdx] = client[kRunningIdx]
247+
248+
assert(client[kRunning] === 0)
249+
250+
client.emit('disconnect', client[kUrl], [client], err)
251+
252+
client[kResume]()
253+
}
254+
255+
function onHttp2SocketError (err) {
256+
assert(err.code !== 'ERR_TLS_CERT_ALTNAME_INVALID')
257+
258+
this[kError] = err
259+
260+
this[kClient][kOnError](err)
261+
}
262+
263+
function onHttp2SocketEnd () {
264+
util.destroy(this, new SocketError('other side closed', util.getSocketInfo(this)))
265+
}
266+
267+
function onSocketClose () {
268+
this[kClosed] = true
269+
}
270+
256271
// https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2
257272
function shouldSendContentLength (method) {
258273
return method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS' && method !== 'TRACE' && method !== 'CONNECT'

0 commit comments

Comments
 (0)