Skip to content

Commit f41a62f

Browse files
committedJun 13, 2020
Fix "close" event on Node v12.16.3.
1 parent 4a298fc commit f41a62f

File tree

4 files changed

+42
-5
lines changed

4 files changed

+42
-5
lines changed
 

‎.travis.yml

+6
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ node_js:
6060
# returning a string with 2 little-endian bytes in a String.
6161
# Then again, this could be https://github.com/nodejs/node/pull/27936.
6262
- "12.4"
63+
- "12.16.2"
64+
65+
# v12.16.3 changed something in InternalSocket.prototype.shutdown or possibly
66+
# WritableStream.prototype.end causing the "close" event to not be emitted.
67+
# https://github.com/moll/node-mitm/issues/66
68+
- "12.16.3"
6369
- "12"
6470
- "13"
6571
- "14"

‎CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
## Unreleased
22
- Fixes one test for Node v12.4.
3+
- Fixes the socket "close" event on Node v12.16.3.
34

45
## 1.7.0 (Jan 30, 2019)
56
- Adds compatibility with Node v10.15.1.

‎lib/internal_socket.js

+17-5
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,14 @@ function InternalSocket(remote) {
3434
if (remote) this.remote = remote
3535
this.id = ++uniqueId
3636

37-
// End is for ReadableStream.prototype.push(null).
38-
// Finish is for WritableStream.prototype.end.
37+
// The "end" event follows ReadableStream.prototype.push(null).
3938
this.on("data", readData.bind(this))
4039
this.on("end", readEof.bind(this))
40+
41+
// The "finish" event follows WritableStream.prototype.end.
42+
//
43+
// There's WritableStream.prototype._final for processing before "finish" is
44+
// emitted, but that's only available in Node v8 and later.
4145
this.on("finish", this._write.bind(this, null, null, noop))
4246

4347
return this.pause(), this
@@ -55,7 +59,6 @@ InternalSocket.prototype = Object.create(DuplexStream.prototype, {
5559
// v0.11.14 does it in the next tick. For easier sync use, call it here.
5660
InternalSocket.prototype.readStart = function() { this.resume() }
5761
InternalSocket.prototype.readStop = function() { this.pause() }
58-
InternalSocket.prototype.close = InternalSocket.prototype.end
5962

6063
InternalSocket.prototype._read = noop
6164
InternalSocket.prototype.ref = noop
@@ -122,12 +125,14 @@ InternalSocket.prototype.writeUcs2String = function(req, data) {
122125
}
123126

124127
// While it seems to have existed since Node v0.10, Node v11.2 requires
125-
// "shutdown".
128+
// "shutdown". AFAICT, "shutdown" is for shutting the writable side down and
129+
// hence the use of WritableStream.prototype.end and waiting for the "finish"
130+
// event.
126131
if (
127132
NODE_11_2_AND_LATER ||
128133
NODE_10_15_1_AND_MAJOR
129134
) InternalSocket.prototype.shutdown = function(req) {
130-
this.once("end", req.oncomplete.bind(req, NO_ERROR, req.handle))
135+
this.once("finish", req.oncomplete.bind(req, NO_ERROR, req.handle))
131136
this.end()
132137

133138
// Note v11.8 requires "shutdown" to return an error value, with "1"
@@ -136,6 +141,13 @@ if (
136141
return 0
137142
}
138143

144+
// I'm unsure of the relationship between InternalSocket.prototype.shutdown and
145+
// InternalSocket.prototype.close.
146+
InternalSocket.prototype.close = function(done) {
147+
if (!this._writableState.finished) this.end(done)
148+
else if (done) done()
149+
}
150+
139151
// Node v0.10 will use writeQueueSize to see if it should set write request's
140152
// "cb" property or write more immediately.
141153
if (NODE_0_10) InternalSocket.prototype.writeQueueSize = 0

‎test/index_test.js

+18
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,24 @@ describe("Mitm", function() {
9494
module.connect(80, "localhost", done.bind(null, null))
9595
})
9696

97+
// The "close" event broke on Node v12.16.3 as the
98+
// InternalSocket.prototype.close method didn't call back if
99+
// the WritableStream had already been closed.
100+
it("must emit close on socket if ended immediately", function(done) {
101+
this.mitm.on("connection", function(socket) { socket.end() })
102+
var socket = module.connect({host: "foo"})
103+
socket.on("close", done.bind(null, null))
104+
})
105+
106+
it("must emit close on socket if ended in next tick", function(done) {
107+
this.mitm.on("connection", function(socket) {
108+
process.nextTick(socket.end.bind(socket))
109+
})
110+
111+
var socket = module.connect({host: "foo"})
112+
socket.on("close", done.bind(null, null))
113+
})
114+
97115
it("must intercept 127.0.0.1", function(done) {
98116
var server; this.mitm.on("connection", function(s) { server = s })
99117
var client = module.connect({host: "127.0.0.1"})

7 commit comments

Comments
 (7)

papandreou commented on Jun 13, 2020

@papandreou
Contributor

This does fix the problem we saw in unexpected-mitm mentioned by Alex in #66 (comment) 😌

moll commented on Jun 13, 2020

@moll
OwnerAuthor

Yeah, I know. :P I've yet to merge it to master and announce it as I'm trying to fix Travis CI to test on Node >= v5 to <= 6.4. For some reason NPM itself started to fail on those versions.

papandreou commented on Jun 13, 2020

@papandreou
Contributor

Cool, just wanted to provide some extra validation :)

That npm thing sucks. Everyone seems to be really eager to stop maintaining old node versions. I've found that the easiest thing is to just go with the flow and do a new major release here and there that cuts down support to the active LTS versions.

moll commented on Jun 13, 2020

@moll
OwnerAuthor

Of course, thanks for your keen eye! ;)

That npm thing sucks. Everyone seems to be really eager to stop maintaining old node versions. I've found that the easiest thing is to just go with the flow and do a new major release here and there that cuts down support to the active LTS versions.

Haa, only dead fish go with the flow. :P I'm sticking in there with support for old versions, as I think people have, or should have, better things to do than constantly upgrade their environments for possibly little gain. I personally use ancient Node.js versions for as long as I can. Fortunately few security issues affect my run of the mill usage, so so far I've managed to save quite a lot of time. :P

papandreou commented on Jun 13, 2020

@papandreou
Contributor

That's really admirable. In a less imperfect world, these testing tools should be the last man standing and only abandon those old versions when nobody else needs to test anything with them. But even mocha is node.js 10+ now.

moll commented on Jun 13, 2020

@moll
OwnerAuthor

Here-here! I don't intend to drop support for any Node.js version on any of my own libraries. :)

Ah, I didn't know Mocha's v10+. I'm still using the same old version I used years ago. :P Fortunately the feature set of Mocha, last I checked, is fairly minimal, so it should be simple to implement from scratch. :)

papandreou commented on Jun 14, 2020

@papandreou
Contributor

Or just keep using that old version. (I’ve been trying hard and so far resisted the temptation to write a test runner, haha)

Please sign in to comment.