Skip to content

Commit 8dc6a7e

Browse files
authored
fix: remove abort handler on close (nodejs#3211)
1 parent 9f26aff commit 8dc6a7e

File tree

2 files changed

+21
-22
lines changed

2 files changed

+21
-22
lines changed

lib/api/api-request.js

+19-20
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,18 @@ class RequestHandler extends AsyncResource {
7070
this.reason = this.signal.reason ?? new RequestAbortedError()
7171
} else {
7272
this.removeAbortListener = util.addAbortListener(this.signal, () => {
73-
this.removeAbortListener?.()
74-
this.removeAbortListener = null
75-
7673
this.reason = this.signal.reason ?? new RequestAbortedError()
7774
if (this.res) {
7875
util.destroy(this.res, this.reason)
7976
} else if (this.abort) {
8077
this.abort(this.reason)
8178
}
79+
80+
if (this.removeAbortListener) {
81+
this.res?.off('close', this.removeAbortListener)
82+
this.removeAbortListener()
83+
this.removeAbortListener = null
84+
}
8285
})
8386
}
8487
}
@@ -111,54 +114,44 @@ class RequestHandler extends AsyncResource {
111114
const parsedHeaders = responseHeaders === 'raw' ? util.parseHeaders(rawHeaders) : headers
112115
const contentType = parsedHeaders['content-type']
113116
const contentLength = parsedHeaders['content-length']
114-
const body = new Readable({ resume, abort, contentType, contentLength, highWaterMark })
117+
const res = new Readable({ resume, abort, contentType, contentLength, highWaterMark })
115118

116119
if (this.removeAbortListener) {
117-
// TODO (fix): 'close' is sufficient but breaks tests.
118-
body
119-
.on('end', this.removeAbortListener)
120-
.on('error', this.removeAbortListener)
120+
res.on('close', this.removeAbortListener)
121121
}
122122

123123
this.callback = null
124-
this.res = body
124+
this.res = res
125125
if (callback !== null) {
126126
if (this.throwOnError && statusCode >= 400) {
127127
this.runInAsyncScope(getResolveErrorBodyCallback, null,
128-
{ callback, body, contentType, statusCode, statusMessage, headers }
128+
{ callback, body: res, contentType, statusCode, statusMessage, headers }
129129
)
130130
} else {
131131
this.runInAsyncScope(callback, null, null, {
132132
statusCode,
133133
headers,
134134
trailers: this.trailers,
135135
opaque,
136-
body,
136+
body: res,
137137
context
138138
})
139139
}
140140
}
141141
}
142142

143143
onData (chunk) {
144-
const { res } = this
145-
return res.push(chunk)
144+
return this.res.push(chunk)
146145
}
147146

148147
onComplete (trailers) {
149-
const { res } = this
150-
151148
util.parseHeaders(trailers, this.trailers)
152-
153-
res.push(null)
149+
this.res.push(null)
154150
}
155151

156152
onError (err) {
157153
const { res, callback, body, opaque } = this
158154

159-
this.removeAbortListener?.()
160-
this.removeAbortListener = null
161-
162155
if (callback) {
163156
// TODO: Does this need queueMicrotask?
164157
this.callback = null
@@ -179,6 +172,12 @@ class RequestHandler extends AsyncResource {
179172
this.body = null
180173
util.destroy(body, err)
181174
}
175+
176+
if (this.removeAbortListener) {
177+
res?.off('close', this.removeAbortListener)
178+
this.removeAbortListener()
179+
this.removeAbortListener = null
180+
}
182181
}
183182
}
184183

test/client.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ test('basic get', async (t) => {
6363
body.on('data', (buf) => {
6464
bufs.push(buf)
6565
})
66-
body.on('end', () => {
66+
body.on('close', () => {
6767
t.strictEqual(signal.listenerCount('abort'), 0)
6868
t.strictEqual('hello', Buffer.concat(bufs).toString('utf8'))
6969
})
@@ -135,7 +135,7 @@ test('basic get with custom request.reset=true', async (t) => {
135135
body.on('data', (buf) => {
136136
bufs.push(buf)
137137
})
138-
body.on('end', () => {
138+
body.on('close', () => {
139139
t.strictEqual(signal.listenerCount('abort'), 0)
140140
t.strictEqual('hello', Buffer.concat(bufs).toString('utf8'))
141141
})

0 commit comments

Comments
 (0)